Added storage area standalone rtl
diff --git a/verilog/dv/wb_utests/storage_wb/Makefile b/verilog/dv/wb_utests/storage_wb/Makefile new file mode 100644 index 0000000..4ff890f --- /dev/null +++ b/verilog/dv/wb_utests/storage_wb/Makefile
@@ -0,0 +1,17 @@ +.SUFFIXES: + +PATTERN = storage_wb + +all: ${PATTERN:=.vcd} + +%.vvp: %_tb.v + iverilog -I ../../../rtl \ + $< -o $@ + +%.vcd: %.vvp + vvp $< + +clean: + rm -f *.vvp *.vcd *.log + +.PHONY: clean all \ No newline at end of file
diff --git a/verilog/dv/wb_utests/storage_wb/storage_wb_tb.v b/verilog/dv/wb_utests/storage_wb/storage_wb_tb.v new file mode 100644 index 0000000..ccfdf95 --- /dev/null +++ b/verilog/dv/wb_utests/storage_wb/storage_wb_tb.v
@@ -0,0 +1,330 @@ + +`define MGMT_BLOCKS 2 +`define USER_BLOCKS 4 + +`define BASE_ADR { \ + {8'h07, {24{1'b0}} }, \ + {8'h06, {24{1'b0}} }, \ + {8'h05, {24{1'b0}} }, \ + {8'h04, {24{1'b0}} }, \ + {8'h03, {24{1'b0}} }, \ + {8'h02, {24{1'b0}} }, \ + {8'h01, {24{1'b0}} } \ +}\ + + +// `define DBG +`include "sram_1rw1r_32_256_8_sky130.v" +`include "storage.v" +`include "storage_bridge_wb.v" + +module storage_tb; + + reg wb_clk_i; + reg wb_rst_i; + + reg [31:0] wb_adr_i; + reg [31:0] wb_dat_i; + reg [3:0] wb_sel_i; + reg wb_we_i; + reg wb_cyc_i; + reg [1:0] wb_stb_i; + wire [1:0] wb_ack_o; + wire [31:0] wb_mgmt_dat_o; + + // MGMT_AREA RO WB Interface (USER_BLOCKS) + wire [31:0] wb_user_dat_o; + + wire [`MGMT_BLOCKS-1:0] mgmt_ena; + wire [(`MGMT_BLOCKS*4)-1:0] mgmt_wen_mask; + wire [`MGMT_BLOCKS-1:0] mgmt_wen; + wire [31:0] mgmt_wdata; + wire [7:0] mgmt_addr; + wire [(`MGMT_BLOCKS*32)-1:0] mgmt_rdata; + wire [`USER_BLOCKS-1:0] mgmt_user_ena; + wire [7:0] mgmt_user_addr; + wire [(`USER_BLOCKS*32)-1:0] mgmt_user_rdata; + + // USER_AREA R/W Interface (USER_BLOCKS) + reg user_clk; + reg [`USER_BLOCKS-1:0] user_ena; + reg [`USER_BLOCKS-1:0] user_wen; + reg [(`USER_BLOCKS*4)-1:0] user_wen_mask; + reg [7:0] user_addr; + reg [31:0] user_wdata; + wire [(`USER_BLOCKS*32)-1:0] user_rdata; + + // USER_AREA RO Interface (MGMT_BLOCS) + reg [`MGMT_BLOCKS-1:0] user_mgmt_ena; + reg [7:0] user_mgmt_addr; + wire [(`MGMT_BLOCKS*32)-1:0] user_mgmt_rdata; + + initial begin + // MGMT Ports + wb_clk_i = 0; + wb_rst_i = 0; + wb_stb_i = 0; + wb_cyc_i = 0; + wb_sel_i = 0; + wb_we_i = 0; + wb_dat_i = 0; + wb_adr_i = 0; + // User Ports + user_clk = 0; + user_ena = {`USER_BLOCKS{1'b1}}; + user_wen = {`USER_BLOCKS{1'b1}}; + user_addr = 0; + user_wdata = 0; + user_mgmt_ena = {`MGMT_BLOCKS{1'b1}}; + user_mgmt_addr = 0; + end + + always #1 wb_clk_i = ~wb_clk_i; + always #1 user_clk = ~user_clk; + + initial begin + $dumpfile("storage_tb.vcd"); + $dumpvars(0, storage_tb); + repeat (100) begin + repeat (1000) @(posedge wb_clk_i); + end + $display("%c[1;31m",27); + $display ("Monitor: Timeout, Test Storage Area Failed"); + $display("%c[0m",27); + $finish; + end + + reg [31:0] ref_data [255: 0]; + reg [32*(`MGMT_BLOCKS+`USER_BLOCKS)-1:0] base_adr = `BASE_ADR; + reg [31:0] block_adr; + integer i,j; + + initial begin + // Reset Operation + wb_rst_i = 1; + #2; + wb_rst_i = 0; + #2; + + // Test MGMT R/W port and user RO port + for (i = 0; i< `MGMT_BLOCKS; i = i +1) begin + for ( j = 0; j < 100; j = j + 1) begin + if (i == 0) begin + ref_data[j] = $urandom_range(0, 2**30); + end + block_adr = base_adr[32*i+:32] + j; + mgmt_write(block_adr, ref_data[j]); + #2; + end + end + + for (i = 0; i< `MGMT_BLOCKS; i = i +1) begin + for ( j = 0; j < 100; j = j + 1) begin + block_adr = base_adr[32*i+:32] + j; + mgmt_read(block_adr, 0); + if (wb_mgmt_dat_o !== ref_data[j]) begin + $display("Monitor: MGMT R/W Operation Failed"); + $finish; + end + + user_mgmt_read(j,i); + if (user_mgmt_rdata[32*i+:32] !== ref_data[j]) begin + $display("Monitor: User RO Operation Failed"); + $finish; + end + #2; + end + end + + // Test user R/W port & MGMT RO port + for (i = 0; i<`USER_BLOCKS; i = i +1) begin + for ( j = 0; j < 100; j = j + 1) begin + if (i == 0) begin + ref_data[j] = $urandom_range(0, 2**30); + end + user_write(j, ref_data[j], i); + #2; + end + end + + for (i = 0; i< `USER_BLOCKS; i = i +1) begin + for ( j = 0; j < 100; j = j + 1) begin + user_read(j,i); + if (user_rdata[32*i+:32] !== ref_data[j]) begin + $display("Monitor: User R/W Operation Failed"); + $finish; + end + + block_adr = base_adr[32*(i+`MGMT_BLOCKS)+:32] + j; + mgmt_read(block_adr,1); + if(wb_user_dat_o !== ref_data[j])begin + $display("Monitor: MGMT RO Operation Failed"); + $finish; + end + #2; + end + end + + $display("Success"); + $finish; + end + + task user_write; + input [32:0] addr; + input [32:0] data; + input integer block; + begin + @(posedge user_clk) begin + user_ena[block] = 0; + user_wen[block] = 0; + user_wen_mask[(block*4)+:4] = 4'b1111; + user_wdata = data; + user_addr = addr[7:0]; + $display("Write Cycle Started."); + end + #4; + user_ena[block] = 1; + user_wen_mask[(block*4)+:4] = 4'b0000; + user_wen[block] = 1; + $display("Write Cycle Ended."); + end + endtask + + task user_read; + input [32:0] addr; + input integer block; + begin + @(posedge user_clk) begin + user_ena[block] = 0; + user_addr = addr[7:0]; + $display("Read Cycle Started."); + end + #8; + user_ena[block] = 1; + $display("Read Cycle Ended."); + end + endtask + + task user_mgmt_read; + input [32:0] addr; + input integer block; + begin + @(posedge user_clk) begin + user_mgmt_ena[block] = 0; + user_mgmt_addr = addr[7:0]; + $display("Read Cycle Started."); + end + #8; + $display("Read Cycle Ended."); + end + endtask + + task mgmt_write; + input [32:0] addr; + input [32:0] data; + begin + @(posedge wb_clk_i) begin + wb_stb_i[0] = 1; + wb_cyc_i = 1; + wb_sel_i = 4'hF; + wb_we_i = 1; + wb_adr_i = addr; + wb_dat_i = data; + $display("Write Cycle Started."); + end + // Wait for an ACK + wait(wb_ack_o[0] == 1); + wait(wb_ack_o[0] == 0); + wb_cyc_i = 0; + wb_stb_i[0] = 0; + $display("Write Cycle Ended."); + end + endtask + + task mgmt_read; + input [32:0] addr; + input integer block; + begin + @(posedge wb_clk_i) begin + wb_stb_i[block] = 1; + wb_cyc_i = 1; + wb_we_i = 0; + wb_adr_i = addr; + $display("Read Cycle Started."); + end + // Wait for an ACK + wait(wb_ack_o[block] == 1); + wait(wb_ack_o[block] == 0); + wb_cyc_i = 0; + wb_stb_i[block] = 0; + $display("Read Cycle Ended."); + end + endtask + + storage_bridge_wb #( + .USER_BLOCKS(`USER_BLOCKS), + .MGMT_BLOCKS(`MGMT_BLOCKS), + .BASE_ADDR(`BASE_ADR) + ) wb_bridge ( + .wb_clk_i(wb_clk_i), + .wb_rst_i(wb_rst_i), + + .wb_adr_i(wb_adr_i), + .wb_dat_i(wb_dat_i), + .wb_sel_i(wb_sel_i), + .wb_we_i(wb_we_i), + .wb_cyc_i(wb_cyc_i), + .wb_stb_i(wb_stb_i), + .wb_ack_o(wb_ack_o), + .wb_mgmt_dat_o(wb_mgmt_dat_o), + + // MGMT_AREA RO WB Interface (USER_BLOCKS) + .wb_user_dat_o(wb_user_dat_o), + + // MGMT Area native memory interface + .mgmt_ena(mgmt_ena), + .mgmt_wen_mask(mgmt_wen_mask), + .mgmt_wen(mgmt_wen), + .mgmt_addr(mgmt_addr), + .mgmt_wdata(mgmt_wdata), + .mgmt_rdata(mgmt_rdata), + + // MGMT_AREA RO Interface (USER_BLOCKS) + .mgmt_user_ena(mgmt_user_ena), + .mgmt_user_addr(mgmt_user_addr), + .mgmt_user_rdata(mgmt_user_rdata) + ); + + + storage #( + .MGMT_BLOCKS(`MGMT_BLOCKS), + .USER_BLOCKS(`USER_BLOCKS) + ) uut ( + // Management R/W WB interface + .mgmt_clk(wb_clk_i), + .mgmt_ena(mgmt_ena), + .mgmt_wen(mgmt_wen), + .mgmt_wen_mask(mgmt_wen_mask), + .mgmt_addr(mgmt_addr), + .mgmt_wdata(mgmt_wdata), + .mgmt_rdata(mgmt_rdata), + // Management RO interface + .mgmt_user_ena(mgmt_user_ena), + .mgmt_user_addr(mgmt_user_addr), + .mgmt_user_rdata(mgmt_user_rdata), + // User R/W interface + .user_clk(user_clk), + .user_ena(user_ena), + .user_wen(user_wen), + .user_wen_mask(user_wen_mask), + .user_addr(user_addr), + .user_wdata(user_wdata), + .user_rdata(user_rdata), + // User RO interface + .user_mgmt_ena(user_mgmt_ena), + .user_mgmt_addr(user_mgmt_addr), + .user_mgmt_rdata(user_mgmt_rdata) + ); + + +endmodule \ No newline at end of file
diff --git a/verilog/rtl/storage.v b/verilog/rtl/storage.v new file mode 100644 index 0000000..b773158 --- /dev/null +++ b/verilog/rtl/storage.v
@@ -0,0 +1,70 @@ + +/* User area has R/W access for USER_BLOCKS and RO access for MGMT_BLOCKS + Management area has R/W access for MGMT_BLOCKS and RO access for USER_BLOCKS */ + +module storage #( + parameter USER_BLOCKS = 4, // R/W access + parameter MGMT_BLOCKS = 2 // R/W access +) ( + // MGMT_AREA R/W Interface (MGMT_BLOCKS) + input mgmt_clk, + input [MGMT_BLOCKS-1:0] mgmt_ena, + input [MGMT_BLOCKS-1:0] mgmt_wen, // not shared + input [(MGMT_BLOCKS*4)-1:0] mgmt_wen_mask, // not shared + input [7:0] mgmt_addr, + input [31:0] mgmt_wdata, + output [(MGMT_BLOCKS*32)-1:0] mgmt_rdata, + + // MGMT_AREA RO Interface (USER_BLOCKS) + input [USER_BLOCKS-1:0] mgmt_user_ena, + input [7:0] mgmt_user_addr, + output [(USER_BLOCKS*32)-1:0] mgmt_user_rdata, + + // USER_AREA R/W Interface (USER_BLOCKS) + input user_clk, + input [USER_BLOCKS-1:0] user_ena, + input [USER_BLOCKS-1:0] user_wen, + input [(USER_BLOCKS*4)-1:0] user_wen_mask, + input [7:0] user_addr, + input [31:0] user_wdata, + output [(USER_BLOCKS*32)-1:0] user_rdata, + + // USER_AREA RO Interface (MGMT_BLOCS) + input [MGMT_BLOCKS-1:0] user_mgmt_ena, + input [7:0] user_mgmt_addr, + output [(MGMT_BLOCKS*32)-1:0] user_mgmt_rdata +); + + sram_1rw1r_32_256_8_sky130 SRAM_0 [MGMT_BLOCKS-1:0] ( + // MGMT R/W port + .clk0(mgmt_clk), + .csb0(mgmt_ena), + .web0(mgmt_wen), + .wmask0(mgmt_wen_mask), + .addr0(mgmt_addr[7:0]), + .din0(mgmt_wdata), + .dout0(mgmt_rdata), + // User RO port + .clk1(user_clk), + .csb1(user_mgmt_ena), + .addr1(user_mgmt_addr), + .dout1(user_mgmt_rdata) + ); + + sram_1rw1r_32_256_8_sky130 SRAM_1 [USER_BLOCKS-1:0]( + // User R/W port + .clk0(user_clk), + .csb0(user_ena), + .web0(user_wen), + .wmask0(user_wen_mask), + .addr0(user_addr), + .din0(user_wdata), + .dout0(user_rdata), + // MGMT RO port + .clk1(mgmt_clk), + .csb1(mgmt_user_ena), + .addr1(mgmt_user_addr), + .dout1(mgmt_user_rdata) + ); + +endmodule \ No newline at end of file
diff --git a/verilog/rtl/storage_bridge_wb.v b/verilog/rtl/storage_bridge_wb.v new file mode 100644 index 0000000..1c89ca5 --- /dev/null +++ b/verilog/rtl/storage_bridge_wb.v
@@ -0,0 +1,109 @@ +module storage_bridge_wb #( + parameter USER_BLOCKS = 4, + parameter MGMT_BLOCKS = 2 +) ( + // MGMT_AREA R/W WB Interface (#of WB Slaves = MGMT_BLOCKS ) + input wb_clk_i, + input wb_rst_i, + + input [31:0] wb_adr_i, + input [31:0] wb_dat_i, + input [3:0] wb_sel_i, + input wb_we_i, + input wb_cyc_i, + input [1:0] wb_stb_i, + output reg [1:0] wb_ack_o, + output reg [31:0] wb_mgmt_dat_o, + + // MGMT_AREA RO WB Interface (USER_BLOCKS) + output reg [31:0] wb_user_dat_o, + + // MGMT Area native memory interface + output [MGMT_BLOCKS-1:0] mgmt_ena, + output [(MGMT_BLOCKS*4)-1:0] mgmt_wen_mask, + output [MGMT_BLOCKS-1:0] mgmt_wen, + output [7:0] mgmt_addr, + output [31:0] mgmt_wdata, + input [(MGMT_BLOCKS*32)-1:0] mgmt_rdata, + + // MGMT_AREA RO Interface (USER_BLOCKS) + output [USER_BLOCKS-1:0] mgmt_user_ena, + output [7:0] mgmt_user_addr, + input [(USER_BLOCKS*32)-1:0] mgmt_user_rdata +); + + localparam RAM_BLOCKS = USER_BLOCKS + MGMT_BLOCKS; + parameter [(RAM_BLOCKS*32)-1:0] BASE_ADDR = { + // User partition + {32'h 0700_0000}, + {32'h 0600_0000}, + {32'h 0500_0000}, + {32'h 0400_0000}, + {32'h 0300_0000}, + // MGMT partition + {32'h 0200_0000}, + {32'h 0100_0000} + }; + parameter ADR_MASK = 32'h FF00_0000; + + wire [1:0] valid; + wire [1:0] wen; + wire [7:0] wen_mask; + + assign valid = {2{wb_cyc_i}} & wb_stb_i; + assign wen = wb_we_i & valid; + assign wen_mask = wb_sel_i & {{4{wen[1]}}, {4{wen[0]}}}; + + // Ack generation + reg [1:0] wb_ack_read; + + always @(posedge wb_clk_i) begin + if (wb_rst_i == 1'b 1) begin + wb_ack_read <= 2'b0; + wb_ack_o <= 2'b0; + end else begin + wb_ack_o <= wb_we_i? (valid & ~wb_ack_o): wb_ack_read; + wb_ack_read <= (valid & ~wb_ack_o) & ~wb_ack_read; + end + end + + // Address decoding + wire [RAM_BLOCKS-1: 0] ram_sel; + genvar iS; + generate + for (iS = 0; iS < RAM_BLOCKS; iS = iS + 1) begin + assign ram_sel[iS] = + ((wb_adr_i & ADR_MASK) == BASE_ADDR[(iS+1)*32-1:iS*32]); + end + endgenerate + + // Management SoC interface + assign mgmt_ena = valid[0] ? ~ram_sel[1:0] : {MGMT_BLOCKS{1'b1}}; + assign mgmt_wen = ~{MGMT_BLOCKS{wen[0]}}; + assign mgmt_wen_mask = {MGMT_BLOCKS{wen_mask[3:0]}}; + assign mgmt_addr = wb_adr_i[7:0]; + assign mgmt_wdata = wb_dat_i[31:0]; + + wire [1:0] mgmt_sel = ram_sel[1:0]; + + integer i; + always @(*) begin + wb_mgmt_dat_o = {32{1'b0}}; + for (i=0; i<(MGMT_BLOCKS*32); i=i+1) + wb_mgmt_dat_o[i%32] = wb_mgmt_dat_o[i%32] | (mgmt_sel[i/32] & mgmt_rdata[i]); + end + + // User Interface + assign mgmt_user_ena = valid[1] ? ~ram_sel[5:2] : {USER_BLOCKS{1'b1}}; + assign mgmt_user_addr = wb_adr_i[7:0]; + + wire [3:0] user_sel = ram_sel [5:2]; + + integer j; + always @(*) begin + wb_user_dat_o = {32{1'b0}}; + for (j=0; j<(USER_BLOCKS*32); j=j+1) + wb_user_dat_o[j%32] = wb_user_dat_o[j%32] | (user_sel[j/32] & mgmt_user_rdata[j]); + end + +endmodule \ No newline at end of file