`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 21.10.2025 12:14:25
// Design Name:
// Module Name: memory
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module s_ram_controller(input clk,
input rst,
input start, // chip select
input write_enable,
input [1:0] bank_select,
input [7:0] address,
input [31:0] write_data,
output reg done,
output reg [31:0] read_data,
// Interface to SRAM bank
output reg in_CS,
output reg in_write_en,
output reg [1:0] in_bank_select,
output reg [7:0] in_bram_add,
//output reg [7:0] in_sram_col,
output reg [31:0] in_sram_write_data,
input [31:0] out_sram_read_data
);
localparam IDLE = 3'b000,
WRITE = 3'b001,
READ = 3'b010,
WAIT = 3'b011,
DONE = 3'b100;
reg [2:0] current_state, next_state;
always @(posedge clk or posedge rst) begin
if (rst)
current_state <= IDLE;
else
current_state <= next_state;
end
always @(*) begin
case (current_state)
IDLE: begin
if (start) begin
if (write_enable)
next_state = WRITE;
else
next_state = READ;
end else
next_state = IDLE;
end
WRITE: next_state = WAIT;
READ: next_state = WAIT;
WAIT: next_state = DONE;
DONE: next_state = IDLE;
default: next_state = IDLE;
endcase
end
// Output Control
always @(posedge clk or posedge rst) begin
if (rst) begin
in_CS <= 1'b1;
in_write_en <= 1'b0;
in_bank_select <= 2'b00;
in_bram_add <= 14'b0;
// in_sram_col <= 9'b0;
in_sram_write_data <= 32'b0;
read_data <= 32'b0;
done <= 1'b0;
end else begin
case (current_state)
IDLE: begin
in_CS <= 1'b1;
done <= 1'b0;
end
WRITE: begin
in_CS <= 1'b0;
in_write_en <= 1'b1;
in_bank_select <= bank_select;
in_bram_add <= address;
// in_sram_col <= col_address;
in_sram_write_data <= write_data;
end
READ: begin
in_CS <= 1'b0;
in_write_en <= 1'b0;
in_bank_select <= bank_select;
in_bram_add <= address;
//in_sram_col <= col_address;
end
WAIT: begin
in_CS <= 1'b1; // deactivate chip select
if (!write_enable)
read_data <= out_sram_read_data;
end
DONE: begin
done <= 1'b1;
end
endcase
end
end
endmodule
module s_ram_bank(
// SRAM MODEL INTERFACE
input in_CLK,
input in_CS, // CHIP SELECT
input in_write_en, // Write Enable
input [1:0] in_bank_select, // Bank Selection
input [7:0] in_sram_row, // Row Address
input [31:0] in_sram_write_data,
output reg [31:0] out_sram_read_data // Read Data Output
);
reg [3:0] we;
always @(*) begin
we = 4'b0000; // Initialize all write enables to 0
if (in_bank_select == 2'b00) begin
we[0] = 1;
end
else if (in_bank_select == 2'b01) begin
we[1] = 1;
end
else if (in_bank_select == 2'b10) begin
we[2] = 1;
end
else if (in_bank_select == 2'b11) begin
we[3] = 1;
end
end
wire [31:0] bank_read_data [0:3];
genvar i;
generate
for (i = 0; i < 4; i = i + 1) begin : bank_gen
b_ram bank_inst (
.in_CLK(in_CLK),
.in_CS(in_CS & we[i]), // Combine chip select with bank write enable
.in_write_en(in_write_en),
.in_bram_add(in_sram_row), // Using row address as BRAM address
.in_sram_write_data(in_sram_write_data),
.out_sram_read_data(bank_read_data[i])
);
end
endgenerate
// Output multiplexer based on bank selection
always @(*) begin
case (in_bank_select)
2'b00: out_sram_read_data = bank_read_data[0];
2'b01: out_sram_read_data = bank_read_data[1];
2'b10: out_sram_read_data = bank_read_data[2];
2'b11: out_sram_read_data = bank_read_data[3];
default: out_sram_read_data = 32'b0;
endcase
end
endmodule
module b_ram(
// SRAM MODEL INTERFACE
input in_CLK,
input in_CS, // CHIP SELECT
input in_write_en, // Write Enable
input [7:0] in_bram_add, // Row Address
input [31:0] in_sram_write_data,
output reg [31:0] out_sram_read_data // Read Data Output
);
parameter DATA = 32;
parameter addr = 8;
(* ram_style = "block" *) reg [DATA-1:0] mem [(2**addr)-1:0];
always @(posedge in_CLK) begin
if (!in_CS) begin
if (in_write_en) begin
mem[in_bram_add] <= in_sram_write_data;
end
end else begin
out_sram_read_data <= mem[in_bram_add];
end
end
endmodule
`timescale 1ns / 1ps
module top_memory(
input clk,
input rst,
input start, // chip select
input write_enable,
input [1:0] bank_select,
input [7:0] address,
input [31:0] write_data,
output done,
output [31:0] read_data
);
// Internal wires between controller and SRAM bank
wire in_CS;
wire in_write_en;
wire [1:0] in_bank_select;
wire [7:0] in_bram_add;
wire [31:0] in_sram_write_data;
wire [31:0] out_sram_read_data;
// Instantiate SRAM Controller
s_ram_controller controller_inst (
.clk(clk),
.rst(rst),
.start(start),
.write_enable(write_enable),
.bank_select(bank_select),
.address(address),
.write_data(write_data),
.done(done),
.read_data(read_data),
// Interface to SRAM bank
.in_CS(in_CS),
.in_write_en(in_write_en),
.in_bank_select(in_bank_select),
.in_bram_add(in_bram_add),
.in_sram_write_data(in_sram_write_data),
.out_sram_read_data(out_sram_read_data)
);
// Instantiate SRAM Bank
s_ram_bank sram_bank_inst (
.in_CLK(clk),
.in_CS(in_CS),
.in_write_en(in_write_en),
.in_bank_select(in_bank_select),
.in_sram_row(in_bram_add), // Connect row address
.in_sram_write_data(in_sram_write_data),
.out_sram_read_data(out_sram_read_data)
);
endmodule
TEST BENCH
timescale 1ns / 1ps
module tb_top_memory();
reg clk;
reg rst;
reg start;
reg write_enable;
reg [1:0] bank_select;
reg [7:0] address;
reg [31:0] write_data;
wire done;
wire [31:0] read_data;
// Instantiate the top module
top_memory uut (
.clk(clk),
.rst(rst),
.start(start),
.write_enable(write_enable),
.bank_select(bank_select),
.address(address),
.write_data(write_data),
.done(done),
.read_data(read_data)
);
// Clock generation
always #5 clk = ~clk;
// Test data patterns
reg [31:0] test_data [0:15];
integer i;
initial begin
// Initialize test data
for (i = 0; i < 16; i = i + 1) begin
test_data[i] = 32'h12345678 + i * 32'h11111111;
end
// Initialize signals
clk = 0;
rst = 1;
start = 0;
write_enable = 0;
bank_select = 2'b00;
address = 8'h00;
write_data = 32'h00000000;
// Apply reset
#20;
rst = 0;
#20;
$display("=== Starting Memory System Testbench ===");
$display("Time\tOperation\tBank\tAddress\tData");
$display("------------------------------------------------");
// Test 1: Write to all banks
$display("\n=== Test 1: Writing to all banks ===");
for (i = 0; i < 4; i = i + 1) begin
write_to_memory(i, i * 16, test_data[i]);
#50;
end
// Test 2: Read from all banks
$display("\n=== Test 2: Reading from all banks ===");
for (i = 0; i < 4; i = i + 1) begin
read_from_memory(i, i * 16);
#50;
end
// Test 3: Write multiple addresses in same bank
$display("\n=== Test 3: Multiple writes to Bank 0 ===");
for (i = 0; i < 4; i = i + 1) begin
write_to_memory(2'b00, i, test_data[i + 4]);
#50;
end
// Test 4: Read multiple addresses from same bank
$display("\n=== Test 4: Multiple reads from Bank 0 ===");
for (i = 0; i < 4; i = i + 1) begin
read_from_memory(2'b00, i);
#50;
end
// Test 5: Write to high addresses
$display("\n=== Test 5: Writing to high addresses ===");
write_to_memory(2'b11, 8'hFF, 32'hDEADBEEF);
#50;
read_from_memory(2'b11, 8'hFF);
#50;
// Test 6: Back-to-back operations
$display("\n=== Test 6: Back-to-back operations ===");
write_to_memory(2'b01, 8'h10, 32'hCAFEBABE);
wait_for_done();
read_from_memory(2'b01, 8'h10);
wait_for_done();
write_to_memory(2'b10, 8'h20, 32'hFACEB00C);
wait_for_done();
// Test 7: Verify data integrity across banks
$display("\n=== Test 7: Data integrity check ===");
for (i = 0; i < 4; i = i + 1) begin
read_from_memory(i, i * 16);
#50;
if (read_data === test_data[i]) begin
$display("✓ Bank %0d data verified correctly", i);
end else begin
$display("✗ Bank %0d data mismatch! Expected: %h, Got: %h",
i, test_data[i], read_data);
end
end
#100;
$display("\n=== Testbench Complete ===");
$finish;
end
// Task for write operation
task write_to_memory;
input [1:0] bank;
input [7:0] addr;
input [31:0] data;
begin
@(posedge clk);
write_enable = 1;
bank_select = bank;
address = addr;
write_data = data;
start = 1;
@(posedge clk);
start = 0;
wait_for_done();
$display("%0t\tWRITE\t\t%0d\t%h\t%h", $time, bank, addr, data);
end
endtask
// Task for read operation
task read_from_memory;
input [1:0] bank;
input [7:0] addr;
begin
@(posedge clk);
write_enable = 0;
bank_select = bank;
address = addr;
start = 1;
@(posedge clk);
start = 0;
wait_for_done();
$display("%0t\tREAD\t\t%0d\t%h\t%h", $time, bank, addr, read_data);
end
endtask
// Task to wait for done signal
task wait_for_done;
begin
wait(done == 1);
@(posedge clk);
#1; // Small delay for signal stabilization
end
endtask
// Monitor to track all operations
always @(posedge clk) begin
if (done) begin
if (write_enable) begin
$display("%0t\tWRITE DONE\t%0d\t%h\t%h",
$time, bank_select, address, write_data);
end else begin
$display("%0t\tREAD DONE\t%0d\t%h\t%h",
$time, bank_select, address, read_data);
end
end
end
endmodule