From: Marcelina Koƛcielnicka Date: Fri, 6 May 2022 14:30:56 +0000 (+0200) Subject: Add memory_libmap tests. X-Git-Tag: divfloor-in-write_smt2-old-test~11 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=982a11c709b4b363f85ae52a127f8a98bda30a3f;p=yosys.git Add memory_libmap tests. --- diff --git a/Makefile b/Makefile index 0c542aae0..7c3cc380d 100644 --- a/Makefile +++ b/Makefile @@ -808,6 +808,7 @@ test: $(TARGETS) $(EXTRA_TARGETS) +cd tests/fsm && bash run-test.sh $(SEEDOPT) +cd tests/techmap && bash run-test.sh +cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT) + +cd tests/memlib && bash run-test.sh $(SEEDOPT) +cd tests/bram && bash run-test.sh $(SEEDOPT) +cd tests/various && bash run-test.sh +cd tests/select && bash run-test.sh diff --git a/tests/memlib/.gitignore b/tests/memlib/.gitignore new file mode 100644 index 000000000..03dbe82ae --- /dev/null +++ b/tests/memlib/.gitignore @@ -0,0 +1,5 @@ +t_*.log +t_*.out +t_*.v +t_*.ys +run-test.mk diff --git a/tests/memlib/generate.py b/tests/memlib/generate.py new file mode 100644 index 000000000..341486584 --- /dev/null +++ b/tests/memlib/generate.py @@ -0,0 +1,900 @@ +# TODO: + +# - memory initialization +# - clock polarity combinations +# - CE/srst/rdwr/be interactions +# - priority logic +# - byte enables, wrbe_separate +# - duplication for read ports +# - abits/dbits determination +# - mixed width +# - swizzles for weird width progressions + + +class Test: + def __init__(self, name, src, libs, defs, cells): + self.name = name + self.src = src + self.libs = libs + self.defs = defs + self.cells = cells + +TESTS = [] + +### basic sanity tests + +ASYNC = """ +module top(clk, ra, wa, rd, wd, we); + +localparam ABITS = {abits}; +localparam DBITS = {dbits}; + +input wire clk; +input wire we; +input wire [ABITS-1:0] ra, wa; +input wire [DBITS-1:0] wd; +output wire [DBITS-1:0] rd; + +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +always @(posedge clk) + if (we) + mem[wa] <= wd; + +assign rd = mem[ra]; + +endmodule +""" + +ASYNC_SMALL = ASYNC.format(abits=6, dbits=6) +ASYNC_BIG = ASYNC.format(abits=11, dbits=10) + +TESTS += [ + Test("async_big", ASYNC_BIG, ["lut", "block_tdp"], [], {"RAM_LUT": 384}), + Test("async_big_block", ASYNC_BIG, ["block_tdp"], [], {"RAM_BLOCK_TDP": 0}), + Test("async_small", ASYNC_SMALL, ["lut", "block_tdp"], [], {"RAM_LUT": 8}), + Test("async_small_block", ASYNC_SMALL, ["block_tdp"], [], {"RAM_BLOCK_TDP": 0}), +] + +SYNC = """ +module top(clk, ra, wa, rd, wd, we); + +localparam ABITS = {abits}; +localparam DBITS = {dbits}; + +input wire clk; +input wire we; +input wire [ABITS-1:0] ra, wa; +input wire [DBITS-1:0] wd; +output reg [DBITS-1:0] rd; + +{attr} +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +always @(posedge clk) + if (we) + mem[wa] <= wd; + +always @(posedge clk) + rd <= mem[ra]; + +endmodule +""" + +SYNC_SMALL = SYNC.format(abits=6, dbits=6, attr="") +SYNC_SMALL_BLOCK = SYNC.format(abits=6, dbits=6, attr='(* ram_style="block" *)') +SYNC_BIG = SYNC.format(abits=11, dbits=10, attr="") +SYNC_MID = SYNC.format(abits=6, dbits=16, attr="") + +TESTS += [ + Test("sync_big", SYNC_BIG, ["lut", "block_tdp"], [], {"RAM_BLOCK_TDP": 20}), + Test("sync_big_sdp", SYNC_BIG, ["lut", "block_sdp"], [], {"RAM_BLOCK_SDP": 20}), + Test("sync_big_lut", SYNC_BIG, ["lut"], [], {"RAM_LUT": 384}), + Test("sync_small", SYNC_SMALL, ["lut", "block_tdp"], [], {"RAM_LUT": 8}), + Test("sync_small_block", SYNC_SMALL, ["block_tdp"], [], {"RAM_BLOCK_TDP": 1}), + Test("sync_small_block_attr", SYNC_SMALL_BLOCK, ["lut", "block_tdp"], [], {"RAM_BLOCK_TDP": 1}), +] + +### basic TDP test + +TDP = """ +module top(clka, clkb, addra, addrb, rda, rdb, wda, wdb, wea, web); + +localparam ABITS = 6; +localparam DBITS = 6; + +input wire clka, clkb; +input wire wea, web; +input wire [ABITS-1:0] addra, addrb; +input wire [DBITS-1:0] wda, wdb; +output reg [DBITS-1:0] rda, rdb; + +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +always @(posedge clka) + if (wea) + mem[addra] <= wda; + else + rda <= mem[addra]; + +always @(posedge clkb) + if (web) + mem[addrb] <= wdb; + else + rdb <= mem[addrb]; + +endmodule +""" + +TESTS += [ + Test("tdp", TDP, ["block_tdp", "block_sdp"], [], {"RAM_BLOCK_TDP": 1}), +] + +# shared clock + +SYNC_2CLK = """ +module top(rclk, wclk, ra, wa, rd, wd, we); + +localparam ABITS = 6; +localparam DBITS = 16; + +input wire rclk, wclk; +input wire we; +input wire [ABITS-1:0] ra, wa; +input wire [DBITS-1:0] wd; +output reg [DBITS-1:0] rd; + +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +always @(posedge wclk) + if (we) + mem[wa] <= wd; + +always @(posedge rclk) + rd <= mem[ra]; + +endmodule +""" + +TESTS += [ + Test("sync_2clk", SYNC_2CLK, ["block_sdp"], [], {"RAM_BLOCK_SDP": 1}), + Test("sync_shared", SYNC_MID, ["block_sdp_1clk"], [], {"RAM_BLOCK_SDP_1CLK": 1}), + Test("sync_2clk_shared", SYNC_2CLK, ["block_sdp_1clk"], [], {"RAM_BLOCK_SDP_1CLK": 0}), +] + +# inter-port transparency + +SYNC_TRANS = """ +module top(clk, ra, wa, rd, wd, we); + +localparam ABITS = 6; +localparam DBITS = 16; + +input wire clk; +input wire we; +input wire [ABITS-1:0] ra, wa; +input wire [DBITS-1:0] wd; +output reg [DBITS-1:0] rd; + +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +always @(negedge clk) + if (we) + mem[wa] <= wd; + +always @(negedge clk) begin + rd <= mem[ra]; + if (we && ra == wa) + rd <= wd; +end + +endmodule +""" + +TESTS += [ + Test("sync_trans_old_old", SYNC_MID, ["block_sdp_1clk"], ["TRANS_OLD"], {"RAM_BLOCK_SDP_1CLK": (1, {"OPTION_TRANS": 0})}), + Test("sync_trans_old_new", SYNC_MID, ["block_sdp_1clk"], ["TRANS_NEW"], {"RAM_BLOCK_SDP_1CLK": 1}), + Test("sync_trans_old_none", SYNC_MID, ["block_sdp_1clk"], [], {"RAM_BLOCK_SDP_1CLK": 1}), + Test("sync_trans_new_old", SYNC_TRANS, ["block_sdp_1clk"], ["TRANS_OLD"], {"RAM_BLOCK_SDP_1CLK": 1}), + Test("sync_trans_new_new", SYNC_TRANS, ["block_sdp_1clk"], ["TRANS_NEW"], {"RAM_BLOCK_SDP_1CLK": (1, {"OPTION_TRANS": 1})}), + Test("sync_trans_new_none", SYNC_TRANS, ["block_sdp_1clk"], [], {"RAM_BLOCK_SDP_1CLK": 1}), +] + +# rdwr checks + +SP_NO_CHANGE = """ +module top(clk, addr, rd, wd, we); + +input wire clk; +input wire we; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +always @(negedge clk) begin + if (we) + mem[addr] <= wd; + else + rd <= mem[addr]; +end + +endmodule +""" + +SP_NO_CHANGE_BE = """ +module top(clk, addr, rd, wd, we); + +input wire clk; +input wire [1:0] we; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +always @(negedge clk) begin + if (we) begin + if (we[0]) + mem[addr][7:0] <= wd[7:0]; + if (we[1]) + mem[addr][15:8] <= wd[15:8]; + end else + rd <= mem[addr]; +end + +endmodule +""" + +SP_NEW = """ +module top(clk, addr, rd, wd, we); + +input wire clk; +input wire we; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +always @(negedge clk) begin + if (we) begin + mem[addr] <= wd; + rd <= wd; + end else + rd <= mem[addr]; +end + +endmodule +""" + +SP_NEW_BE = """ +module top(clk, addr, rd, wd, we); + +input wire clk; +input wire [1:0] we; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +always @(negedge clk) begin + rd <= mem[addr]; + if (we[0]) begin + mem[addr][7:0] <= wd[7:0]; + rd[7:0] <= wd[7:0]; + end + if (we[1]) begin + mem[addr][15:8] <= wd[15:8]; + rd[15:8] <= wd[15:8]; + end +end + +endmodule +""" + +SP_OLD = """ +module top(clk, addr, rd, wd, we); + +input wire clk; +input wire we; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +always @(negedge clk) begin + if (we) + mem[addr] <= wd; + rd <= mem[addr]; +end + +endmodule +""" + +SP_OLD_BE = """ +module top(clk, addr, rd, wd, we); + +input wire clk; +input wire [1:0] we; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +always @(negedge clk) begin + if (we[0]) + mem[addr][7:0] <= wd[7:0]; + if (we[1]) + mem[addr][15:8] <= wd[15:8]; + rd <= mem[addr]; +end + +endmodule +""" + +TESTS += [ + Test("sp_nc_none", SP_NO_CHANGE, ["block_sp"], [], {"RAM_BLOCK_SP": 1}), + Test("sp_new_none", SP_NEW, ["block_sp"], [], {"RAM_BLOCK_SP": 1}), + Test("sp_old_none", SP_OLD, ["block_sp"], [], {"RAM_BLOCK_SP": 0}), + Test("sp_nc_nc", SP_NO_CHANGE, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_nc", SP_NEW, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 1}), + Test("sp_old_nc", SP_OLD, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 0}), + Test("sp_nc_new", SP_NO_CHANGE, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_new", SP_NEW, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 1}), + Test("sp_old_new", SP_OLD, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 0}), + Test("sp_nc_old", SP_NO_CHANGE, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_old", SP_NEW, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_old_old", SP_OLD, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_nc_new_only", SP_NO_CHANGE, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_new_only", SP_NEW, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 1}), + Test("sp_old_new_only", SP_OLD, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 0}), + Test("sp_nc_new_only_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_new_only_be", SP_NEW_BE, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 2}), + Test("sp_old_new_only_be", SP_OLD_BE, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 0}), + Test("sp_nc_new_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_new_be", SP_NEW_BE, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 1}), + Test("sp_old_new_be", SP_OLD_BE, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 0}), + Test("sp_nc_old_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_old_be", SP_NEW_BE, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_old_old_be", SP_OLD_BE, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_nc_nc_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_nc_be", SP_NEW_BE, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 2}), + Test("sp_old_nc_be", SP_OLD_BE, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 0}), + Test("sp_nc_auto", SP_NO_CHANGE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_auto", SP_NEW, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "NEW"})}), + Test("sp_old_auto", SP_OLD, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "OLD"})}), + Test("sp_nc_auto_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": 1}), + Test("sp_new_auto_be", SP_NEW_BE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "NEW"})}), + Test("sp_old_auto_be", SP_OLD_BE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "OLD"})}), +] + +SP_INIT = """ +module top(clk, addr, rd, wd, we, re); + +input wire clk; +input wire we, re; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +initial rd = {ival}; + +always @(posedge clk) begin + if (we) + mem[addr] <= wd; + if (re) + rd <= mem[addr]; +end + +endmodule +""" + +SP_INIT_X = SP_INIT.format(ival="16'hxxxx") +SP_INIT_0 = SP_INIT.format(ival="16'h0000") +SP_INIT_V = SP_INIT.format(ival="16'h55aa") + +TESTS += [ + Test("sp_init_x_x", SP_INIT_X, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_x_x_re", SP_INIT_X, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_x_x_ce", SP_INIT_X, ["block_sp"], ["CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_0_x", SP_INIT_0, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_0_x_re", SP_INIT_0, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_0_0", SP_INIT_0, ["block_sp"], ["RDINIT_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_0_0_re", SP_INIT_0, ["block_sp"], ["RDINIT_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_0_any", SP_INIT_0, ["block_sp"], ["RDINIT_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_0_any_re", SP_INIT_0, ["block_sp"], ["RDINIT_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_v_x", SP_INIT_V, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_v_x_re", SP_INIT_V, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_v_0", SP_INIT_V, ["block_sp"], ["RDINIT_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_v_0_re", SP_INIT_V, ["block_sp"], ["RDINIT_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_v_any", SP_INIT_V, ["block_sp"], ["RDINIT_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_init_v_any_re", SP_INIT_V, ["block_sp"], ["RDINIT_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), +] + +SP_ARST = """ +module top(clk, addr, rd, wd, we, re, ar); + +input wire clk; +input wire we, re, ar; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +initial rd = {ival}; + +always @(posedge clk) begin + if (we) + mem[addr] <= wd; +end +always @(posedge clk, posedge ar) begin + if (ar) + rd <= {aval}; + else if (re) + rd <= mem[addr]; +end + +endmodule +""" + +SP_ARST_X = SP_ARST.format(ival="16'hxxxx", aval="16'hxxxx") +SP_ARST_0 = SP_ARST.format(ival="16'hxxxx", aval="16'h0000") +SP_ARST_V = SP_ARST.format(ival="16'hxxxx", aval="16'h55aa") +SP_ARST_E = SP_ARST.format(ival="16'h55aa", aval="16'h55aa") +SP_ARST_N = SP_ARST.format(ival="16'h1234", aval="16'h55aa") + +TESTS += [ + Test("sp_arst_x_x", SP_ARST_X, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_x_x_re", SP_ARST_X, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_0_x", SP_ARST_0, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_0_x_re", SP_ARST_0, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_0_0", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_0_0_re", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_0_any", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_0_any_re", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_0_init", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_0_init_re", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_v_x", SP_ARST_V, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_v_x_re", SP_ARST_V, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_v_0", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_v_0_re", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_v_any", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_v_any_re", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_v_init", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_v_init_re", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_e_x", SP_ARST_E, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_e_x_re", SP_ARST_E, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_e_0", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_e_0_re", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_e_any", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_e_any_re", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_e_init", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_e_init_re", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_n_x", SP_ARST_N, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_n_x_re", SP_ARST_N, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_n_0", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_n_0_re", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_n_any", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_n_any_re", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_n_init", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_arst_n_init_re", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), +] + +SP_SRST = """ +module top(clk, addr, rd, wd, we, re, sr); + +input wire clk; +input wire we, re, sr; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +initial rd = {ival}; + +always @(posedge clk) begin + if (we) + mem[addr] <= wd; +end +always @(posedge clk) begin + if (sr) + rd <= {sval}; + else if (re) + rd <= mem[addr]; +end + +endmodule +""" + +SP_SRST_G = """ +module top(clk, addr, rd, wd, we, re, sr); + +input wire clk; +input wire we, re, sr; +input wire [3:0] addr; +input wire [15:0] wd; +output reg [15:0] rd; + +reg [15:0] mem [0:15]; + +initial rd = {ival}; + +always @(posedge clk) begin + if (we) + mem[addr] <= wd; +end +always @(posedge clk) begin + if (re) begin + if (sr) + rd <= {sval}; + else + rd <= mem[addr]; + end +end + +endmodule +""" + +SP_SRST_X = SP_SRST.format(ival="16'hxxxx", sval="16'hxxxx") +SP_SRST_0 = SP_SRST.format(ival="16'hxxxx", sval="16'h0000") +SP_SRST_V = SP_SRST.format(ival="16'hxxxx", sval="16'h55aa") +SP_SRST_E = SP_SRST.format(ival="16'h55aa", sval="16'h55aa") +SP_SRST_N = SP_SRST.format(ival="16'h1234", sval="16'h55aa") +SP_SRST_GV = SP_SRST_G.format(ival="16'hxxxx", sval="16'h55aa") + +TESTS += [ + Test("sp_srst_x_x", SP_SRST_X, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_x_x_re", SP_SRST_X, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_0_x", SP_SRST_0, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_0_x_re", SP_SRST_0, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_0_0", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_0_0_re", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_0_any", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_0_any_re", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_0_init", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_0_init_re", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_x", SP_SRST_V, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_x_re", SP_SRST_V, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_0", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_0_re", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_any", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_any_re", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_any_re_gated", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY_RE", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_any_ce", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_any_ce_gated", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY_CE", "CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_init", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_v_init_re", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_e_x", SP_SRST_E, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_e_x_re", SP_SRST_E, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_e_0", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_e_0_re", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_e_any", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_e_any_re", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_e_init", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_e_init_re", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_n_x", SP_SRST_N, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_n_x_re", SP_SRST_N, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_n_0", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_n_0_re", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_n_any", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_n_any_re", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_n_init", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_n_init_re", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_x", SP_SRST_GV, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_x_re", SP_SRST_GV, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_0", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_0_re", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_any", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_any_re", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_any_re_gated", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY_RE", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_any_ce", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_any_ce_gated", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY_CE", "CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_init", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), + Test("sp_srst_gv_init_re", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), +] + +WIDE_SDP = """ +module top(rclk, ra, rd, re, rr, wclk, wa, wd, we); + +input wire rclk, wclk, re, rr; +input wire [2**({ww}-{bw})-1:0] we; +input wire [{aw}-{rw}+{xw}-1:0] ra; +input wire [{aw}-{ww}+{xw}-1:0] wa; +input wire [2**{ww}-1:0] wd; +output reg [2**{rw}-1:0] rd; + +reg mem [0:2**{aw}-1]; + +initial mem[3] = 0; +initial mem[17] = 1; +initial mem[23] = 0; +initial mem[24] = 1; + +integer i, j; +always @(posedge wclk) + for (i = 0; i < 2**{ww}; i = i + 2**{bw}) + if (we[i >> {bw}]) + for (j = 0; j < 2**{bw}; j = j + 1) + mem[wa << {ww} | i | j] <= wd[i | j]; + +always @(posedge rclk) + if (rr) + rd <= {sval}; + else if (re) + for (i = 0; i < 2**{rw}; i = i + 1) + rd[i] <= mem[ra << {rw} | i]; + +endmodule +""" + +for (aw, rw, ww, bw, xw, sval, cnt) in [ + (6, 1, 1, 1, 1, "2'h1", 1), + (7, 1, 1, 1, 1, "2'h2", 2), + (8, 1, 1, 1, 1, "2'h3", 4), + (6, 0, 0, 0, 0, "2'h0", 1), + (6, 1, 0, 0, 0, "2'h0", 1), + (6, 2, 0, 0, 0, "2'h0", 1), + (6, 3, 0, 0, 0, "2'h0", 1), + (6, 4, 0, 0, 0, "2'h0", 1), + (6, 5, 0, 0, 0, "2'h0", 2), + (6, 0, 1, 0, 0, "2'h0", 2), + (6, 0, 1, 1, 0, "2'h0", 1), + (6, 0, 2, 0, 0, "2'h0", 4), + (6, 0, 2, 2, 0, "2'h0", 1), + (6, 0, 3, 2, 0, "2'h0", 1), + (6, 0, 4, 2, 0, "2'h0", 1), + (6, 0, 5, 2, 0, "2'h0", 2), + (7, 0, 0, 0, 0, "2'h0", 2), + (7, 1, 0, 0, 0, "2'h0", 2), + (7, 2, 0, 0, 0, "2'h0", 2), + (7, 3, 0, 0, 0, "2'h0", 2), + (7, 4, 0, 0, 0, "2'h0", 2), + (7, 5, 0, 0, 0, "2'h0", 2), + (7, 0, 1, 0, 0, "2'h0", 2), + (7, 0, 1, 1, 0, "2'h0", 2), + (7, 0, 2, 0, 0, "2'h0", 4), + (7, 0, 2, 2, 0, "2'h0", 2), + (7, 0, 3, 2, 0, "2'h0", 2), + (7, 0, 4, 2, 0, "2'h0", 2), + (7, 0, 5, 2, 0, "2'h0", 2), +]: + TESTS.append(Test( + f"wide_sdp_a{aw}r{rw}w{ww}b{bw}x{xw}", + WIDE_SDP.format(aw=aw, rw=rw, ww=ww, bw=bw, xw=xw, sval=sval), + ["wide_sdp"], [], + {"RAM_WIDE_SDP": cnt} + )) + +WIDE_SP = """ +module top(clk, a, rd, re, rr, wd, we); + +input wire clk, re, rr; +input wire [2**({ww}-{bw})-1:0] we; +input wire [{aw}-1:0] a; +input wire [2**{ww}-1:0] wd; +output reg [2**{rw}-1:0] rd; + +reg mem [0:2**{aw}-1]; + +initial mem[3] = 0; +initial mem[17] = 1; +initial mem[23] = 0; +initial mem[24] = 1; + +integer i, j; +always @(posedge clk) begin + for (i = 0; i < 2**{ww}; i = i + 2**{bw}) + if (we[i >> {bw}]) + for (j = 0; j < 2**{bw}; j = j + 1) + mem[a & ~((1 << {ww}) - 1) | i | j] <= wd[i | j]; + if (rr) + rd <= {sval}; + else if (re) + for (i = 0; i < 2**{rw}; i = i + 1) + rd[i] <= mem[a & ~((1 << {rw}) - 1) | i]; +end + +endmodule +""" + +for (aw, rw, ww, bw, sval, cnt) in [ + (6, 1, 1, 1, "2'h1", 1), + (7, 1, 1, 1, "2'h2", 2), + (8, 1, 1, 1, "2'h3", 4), + (6, 0, 0, 0, "2'h0", 1), + (6, 1, 0, 0, "2'h0", 1), + (6, 2, 0, 0, "2'h0", 1), + (6, 3, 0, 0, "2'h0", 1), + (6, 4, 0, 0, "2'h0", 1), + (6, 5, 0, 0, "2'h0", 2), + (6, 0, 1, 0, "2'h0", 2), + (6, 0, 1, 1, "2'h0", 1), + (6, 0, 2, 0, "2'h0", 4), + (6, 0, 2, 2, "2'h0", 1), + (6, 0, 3, 2, "2'h0", 1), + (6, 0, 4, 2, "2'h0", 1), + (6, 0, 5, 2, "2'h0", 2), + (7, 0, 0, 0, "2'h0", 2), + (7, 1, 0, 0, "2'h0", 2), + (7, 2, 0, 0, "2'h0", 2), + (7, 3, 0, 0, "2'h0", 2), + (7, 4, 0, 0, "2'h0", 2), + (7, 5, 0, 0, "2'h0", 2), + (7, 0, 1, 0, "2'h0", 2), + (7, 0, 1, 1, "2'h0", 2), + (7, 0, 2, 0, "2'h0", 4), + (7, 0, 2, 2, "2'h0", 2), + (7, 0, 3, 2, "2'h0", 2), + (7, 0, 4, 2, "2'h0", 2), + (7, 0, 5, 2, "2'h0", 2), +]: + TESTS.append(Test( + f"wide_sp_mix_a{aw}r{rw}w{ww}b{bw}", + WIDE_SP.format(aw=aw, rw=rw, ww=ww, bw=bw, sval=sval), + ["wide_sp"], ["WIDTH_MIX"], + {"RAM_WIDE_SP": cnt} + )) + +for (aw, rw, ww, bw, sval, cnt) in [ + (6, 1, 1, 1, "2'h1", 1), + (7, 1, 1, 1, "2'h2", 2), + (8, 1, 1, 1, "2'h3", 4), + (6, 0, 0, 0, "2'h0", 1), + (6, 1, 0, 0, "2'h0", 2), + (6, 2, 0, 0, "2'h0", 4), + (6, 3, 0, 0, "2'h0", 4), + (6, 4, 0, 0, "2'h0", 4), + (6, 5, 0, 0, "2'h0", 8), + (6, 0, 1, 0, "2'h0", 2), + (6, 0, 1, 1, "2'h0", 1), + (6, 0, 2, 0, "2'h0", 4), + (6, 0, 2, 2, "2'h0", 1), + (6, 0, 3, 2, "2'h0", 1), + (6, 0, 4, 2, "2'h0", 1), + (6, 0, 5, 2, "2'h0", 2), + (7, 0, 0, 0, "2'h0", 2), + (7, 1, 0, 0, "2'h0", 2), + (7, 2, 0, 0, "2'h0", 4), + (7, 3, 0, 0, "2'h0", 8), + (7, 4, 0, 0, "2'h0", 8), + (7, 5, 0, 0, "2'h0", 8), + (7, 0, 1, 0, "2'h0", 2), + (7, 0, 1, 1, "2'h0", 2), + (7, 0, 2, 0, "2'h0", 4), + (7, 0, 2, 2, "2'h0", 2), + (7, 0, 3, 2, "2'h0", 2), + (7, 0, 4, 2, "2'h0", 2), + (7, 0, 5, 2, "2'h0", 2), +]: + TESTS.append(Test( + f"wide_sp_tied_a{aw}r{rw}w{ww}b{bw}", + WIDE_SP.format(aw=aw, rw=rw, ww=ww, bw=bw, sval=sval), + ["wide_sp"], [], + {"RAM_WIDE_SP": cnt} + )) + +WIDE_RW = """ +module top(clk, a, rd, re, wd, we); + +input wire clk, re; +input wire [2**({ww}-{bw})-1:0] we; +input wire [{aw}-1:0] a; +input wire [2**{ww}-1:0] wd; +output reg [2**{rw}-1:0] rd; + +(* ram_block *) +reg mem [0:2**{aw}-1]; + +initial mem[3] = 0; +initial mem[17] = 1; +initial mem[23] = 0; +initial mem[24] = 1; + +integer i, j; +always @(posedge clk) begin + for (i = 0; i < 2**{ww}; i = i + 2**{bw}) + if (we[i >> {bw}]) + for (j = 0; j < 2**{bw}; j = j + 1) + mem[a & ~((1 << {ww}) - 1) | i | j] <= wd[i | j]; + if (re) + for (i = 0; i < 2**{rw}; i = i + 1) + rd[i] <= mem[a & ~((1 << {rw}) - 1) | i]; +end + +endmodule +""" + +for (aw, rw, ww, bw, cntww, cntwr) in [ + (6, 1, 1, 1, 2, 1), + (7, 1, 1, 1, 4, 2), + (8, 1, 1, 1, 8, 4), + (6, 0, 0, 0, 4, 2), + (6, 1, 0, 0, 4, 2), + (6, 2, 0, 0, 4, 2), + (6, 3, 0, 0, 8, 2), + (6, 4, 0, 0, 16, 4), + (6, 5, 0, 0, 32, 8), + (6, 0, 1, 0, 4, 2), + (6, 0, 1, 1, 2, 1), + (6, 0, 2, 0, 4, 4), + (6, 0, 2, 2, 1, 2), + (6, 0, 3, 2, 1, 4), + (6, 0, 4, 2, 2, 8), + (6, 0, 5, 2, 4, 16), + (7, 0, 0, 0, 8, 4), + (7, 1, 0, 0, 8, 4), + (7, 2, 0, 0, 8, 4), + (7, 3, 0, 0, 8, 4), + (7, 4, 0, 0, 16, 4), + (7, 5, 0, 0, 32, 8), + (7, 0, 1, 0, 8, 4), + (7, 0, 1, 1, 4, 2), + (7, 0, 2, 0, 8, 4), + (7, 0, 2, 2, 2, 2), + (7, 0, 3, 2, 2, 4), + (7, 0, 4, 2, 2, 8), + (7, 0, 5, 2, 4, 16), +]: + TESTS.append(Test( + f"wide_read_a{aw}r{rw}w{ww}b{bw}", + WIDE_RW.format(aw=aw, rw=rw, ww=ww, bw=bw), + ["wide_read"], [], + {"RAM_WIDE_READ": cntwr} + )) + TESTS.append(Test( + f"wide_write_a{aw}r{rw}w{ww}b{bw}", + WIDE_RW.format(aw=aw, rw=rw, ww=ww, bw=bw), + ["wide_write"], [], + {"RAM_WIDE_WRITE": cntww} + )) + +with open("run-test.mk", "w") as mf: + mf.write("ifneq ($(strip $(SEED)),)\n") + mf.write("SEEDOPT=-S$(SEED)\n") + mf.write("endif\n") + mf.write("all:") + for t in TESTS: + mf.write(" " + t.name) + mf.write("\n") + mf.write(".PHONY: all\n") + + + for t in TESTS: + with open("t_{}.v".format(t.name), "w") as tf: + tf.write(t.src) + with open("t_{}.ys".format(t.name), "w") as sf: + sf.write("proc\n") + sf.write("opt\n") + sf.write("opt -full\n") + sf.write("memory -nomap\n") + sf.write("dump\n") + sf.write("memory_libmap") + for lib in t.libs: + sf.write(" -lib ../memlib_{}.txt".format(lib)) + for d in t.defs: + sf.write(" -D {}".format(d)) + sf.write("\n") + sf.write("memory_map\n") + for k, v in t.cells.items(): + if isinstance(v, tuple): + (cc, ca) = v + sf.write("select -assert-count {} t:{}\n".format(cc, k)) + for kk, vv in ca.items(): + sf.write("select -assert-count {} t:{} r:{}={} %i\n".format(cc, k, kk, vv)) + else: + sf.write("select -assert-count {} t:{}\n".format(v, k)) + mf.write("{}:\n".format(t.name)) + mf.write("\t@../tools/autotest.sh -G -j $(SEEDOPT) $(EXTRA_FLAGS) -p 'script ../t_{}.ys'".format(t.name)) + for lib in t.libs: + mf.write(" -l memlib_{}.v".format(lib)) + mf.write(" t_{}.v || (cat t_{}.err; exit 1)\n".format(t.name, t.name)) + mf.write(".PHONY: {}\n".format(t.name)) diff --git a/tests/memlib/memlib_block_sdp.txt b/tests/memlib/memlib_block_sdp.txt new file mode 100644 index 000000000..6c34c5a96 --- /dev/null +++ b/tests/memlib/memlib_block_sdp.txt @@ -0,0 +1,12 @@ +ram block \RAM_BLOCK_SDP { + cost 64; + abits 10; + widths 1 2 4 8 16 per_port; + init any; + port sw "W" { + clock anyedge; + } + port sr "R" { + clock anyedge; + } +} diff --git a/tests/memlib/memlib_block_sdp.v b/tests/memlib/memlib_block_sdp.v new file mode 100644 index 000000000..d8dac68e3 --- /dev/null +++ b/tests/memlib/memlib_block_sdp.v @@ -0,0 +1,26 @@ +module RAM_BLOCK_SDP( + input PORT_R_CLK, + input [9:0] PORT_R_ADDR, + output reg [15:0] PORT_R_RD_DATA, + input PORT_W_CLK, + input PORT_W_WR_EN, + input [9:0] PORT_W_ADDR, + input [15:0] PORT_W_WR_DATA +); + +parameter INIT = 0; +parameter PORT_R_WIDTH = 1; +parameter PORT_W_WIDTH = 1; +parameter PORT_R_CLK_POL = 0; +parameter PORT_W_CLK_POL = 0; + +reg [2**10-1:0] mem = INIT; + +always @(negedge (PORT_R_CLK ^ PORT_R_CLK_POL)) + PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH]; + +always @(negedge (PORT_W_CLK ^ PORT_W_CLK_POL)) + if (PORT_W_WR_EN) + mem[PORT_W_ADDR+:PORT_W_WIDTH] <= PORT_W_WR_DATA; + +endmodule diff --git a/tests/memlib/memlib_block_sdp_1clk.txt b/tests/memlib/memlib_block_sdp_1clk.txt new file mode 100644 index 000000000..07c76c2a2 --- /dev/null +++ b/tests/memlib/memlib_block_sdp_1clk.txt @@ -0,0 +1,22 @@ +ram block \RAM_BLOCK_SDP_1CLK { + cost 64; + abits 10; + widths 1 2 4 8 16 per_port; + init any; + port sw "W" { + clock anyedge "C"; + ifdef TRANS_OLD { + option "TRANS" 0 { + wrtrans "R" old; + } + } + ifdef TRANS_NEW { + option "TRANS" 1 { + wrtrans "R" new; + } + } + } + port sr "R" { + clock anyedge "C"; + } +} diff --git a/tests/memlib/memlib_block_sdp_1clk.v b/tests/memlib/memlib_block_sdp_1clk.v new file mode 100644 index 000000000..5e8159f9d --- /dev/null +++ b/tests/memlib/memlib_block_sdp_1clk.v @@ -0,0 +1,36 @@ +module RAM_BLOCK_SDP_1CLK( + input CLK_C, + input PORT_R_CLK, + input [9:0] PORT_R_ADDR, + output reg [15:0] PORT_R_RD_DATA, + input PORT_W_CLK, + input PORT_W_WR_EN, + input [9:0] PORT_W_ADDR, + input [15:0] PORT_W_WR_DATA +); + +parameter PORT_R_CLK_POL = 0; +parameter PORT_W_CLK_POL = 0; +parameter CLK_C_POL = 0; +parameter INIT = 0; +parameter OPTION_TRANS = 2; +parameter PORT_R_WIDTH = 1; +parameter PORT_W_WIDTH = 1; + +reg [2**10-1:0] mem = INIT; + +always @(negedge (CLK_C ^ CLK_C_POL)) begin + if (OPTION_TRANS == 0) + PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH]; + if (PORT_W_WR_EN) + mem[PORT_W_ADDR+:PORT_W_WIDTH] = 16'hx; + if (OPTION_TRANS == 2) + PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH]; + if (PORT_W_WR_EN) + mem[PORT_W_ADDR+:PORT_W_WIDTH] = PORT_W_WR_DATA; + if (OPTION_TRANS == 1) + PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH]; +end + + +endmodule diff --git a/tests/memlib/memlib_block_sp.txt b/tests/memlib/memlib_block_sp.txt new file mode 100644 index 000000000..f99320d73 --- /dev/null +++ b/tests/memlib/memlib_block_sp.txt @@ -0,0 +1,95 @@ +ram block \RAM_BLOCK_SP { + cost 2; + abits 4; + width 16; + byte 8; + port srsw "A" { + clock posedge; + ifdef CLKEN { + clken; + } + ifdef RDEN { + rden; + } + ifdef RDWR_NO_CHANGE { + option "RDWR" "NO_CHANGE" { + rdwr no_change; + } + } + ifdef RDWR_OLD { + option "RDWR" "OLD" { + rdwr old; + } + } + ifdef RDWR_NEW { + option "RDWR" "NEW" { + rdwr new; + } + } + ifdef RDWR_NEW_ONLY { + option "RDWR" "NEW_ONLY" { + rdwr new_only; + } + } + ifdef RDINIT_0 { + option "RDINIT" "ZERO" { + rdinit zero; + } + } + ifdef RDINIT_ANY { + option "RDINIT" "ANY" { + rdinit any; + } + } + ifdef RDARST_0 { + option "RDARST" "ZERO" { + rdarst zero; + } + } + ifdef RDARST_ANY { + option "RDARST" "ANY" { + rdarst any; + } + } + ifdef RDARST_INIT { + option "RDARST" "INIT" { + rdarst init; + } + } + ifdef RDSRST_0 { + option "SRST_GATE" 0 { + option "RDSRST" "ZERO" { + rdsrst zero ungated; + } + } + } + ifdef RDSRST_ANY { + option "SRST_GATE" 0 { + option "RDSRST" "ANY" { + rdsrst any ungated; + } + } + } + ifdef RDSRST_INIT { + option "SRST_GATE" 0 { + option "RDSRST" "INIT" { + rdsrst init ungated; + } + } + } + ifdef RDSRST_ANY_CE { + option "SRST_GATE" 1 { + option "RDSRST" "ANY" { + rdsrst any gated_clken; + } + } + } + ifdef RDSRST_ANY_RE { + option "SRST_GATE" 2 { + option "RDSRST" "ANY" { + rdsrst any gated_rden; + } + } + } + } +} diff --git a/tests/memlib/memlib_block_sp.v b/tests/memlib/memlib_block_sp.v new file mode 100644 index 000000000..1f7830137 --- /dev/null +++ b/tests/memlib/memlib_block_sp.v @@ -0,0 +1,81 @@ +module RAM_BLOCK_SP( + input PORT_A_CLK, + input PORT_A_CLK_EN, + input PORT_A_RD_EN, + input PORT_A_RD_ARST, + input PORT_A_RD_SRST, + input [1:0] PORT_A_WR_EN, + input [3:0] PORT_A_ADDR, + output reg [15:0] PORT_A_RD_DATA, + input [15:0] PORT_A_WR_DATA +); + +parameter OPTION_RDWR = "UNDEFINED"; +parameter OPTION_RDINIT = "UNDEFINED"; +parameter OPTION_RDARST = "UNDEFINED"; +parameter OPTION_RDSRST = "UNDEFINED"; +parameter OPTION_SRST_GATE = 0; +parameter PORT_A_RD_INIT_VALUE = 16'hxxxx; +parameter PORT_A_RD_ARST_VALUE = 16'hxxxx; +parameter PORT_A_RD_SRST_VALUE = 16'hxxxx; + +reg [15:0] mem [0:15]; + +initial + if (OPTION_RDINIT == "ZERO") + PORT_A_RD_DATA = 0; + else if (OPTION_RDINIT == "ANY") + PORT_A_RD_DATA = PORT_A_RD_INIT_VALUE; + +localparam ARST_VALUE = + (OPTION_RDARST == "ZERO") ? 16'h0000 : + (OPTION_RDARST == "INIT") ? PORT_A_RD_INIT_VALUE : + (OPTION_RDARST == "ANY") ? PORT_A_RD_ARST_VALUE : + 16'hxxxx; + +localparam SRST_VALUE = + (OPTION_RDSRST == "ZERO") ? 16'h0000 : + (OPTION_RDSRST == "INIT") ? PORT_A_RD_INIT_VALUE : + (OPTION_RDSRST == "ANY") ? PORT_A_RD_SRST_VALUE : + 16'hxxxx; + +pullup (PORT_A_CLK_EN); +pullup (PORT_A_RD_EN); +pulldown (PORT_A_RD_ARST); +pulldown (PORT_A_RD_SRST); + +always @(posedge PORT_A_CLK) begin + if (PORT_A_CLK_EN) begin + if (PORT_A_WR_EN[0]) + mem[PORT_A_ADDR][7:0] <= PORT_A_WR_DATA[7:0]; + if (PORT_A_WR_EN[1]) + mem[PORT_A_ADDR][15:8] <= PORT_A_WR_DATA[15:8]; + if (PORT_A_RD_EN && (!PORT_A_WR_EN || OPTION_RDWR != "NO_CHANGE")) begin + PORT_A_RD_DATA <= mem[PORT_A_ADDR]; + if (PORT_A_WR_EN && OPTION_RDWR == "NEW_ONLY") + PORT_A_RD_DATA <= 16'hx; + if (PORT_A_WR_EN[0]) + case (OPTION_RDWR) + "NEW": PORT_A_RD_DATA[7:0] <= PORT_A_WR_DATA[7:0]; + "NEW_ONLY": PORT_A_RD_DATA[7:0] <= PORT_A_WR_DATA[7:0]; + "UNDEFINED": PORT_A_RD_DATA[7:0] <= 8'hx; + endcase + if (PORT_A_WR_EN[1]) + case (OPTION_RDWR) + "NEW": PORT_A_RD_DATA[15:8] <= PORT_A_WR_DATA[15:8]; + "NEW_ONLY": PORT_A_RD_DATA[15:8] <= PORT_A_WR_DATA[15:8]; + "UNDEFINED": PORT_A_RD_DATA[15:8] <= 8'hx; + endcase + end + end + if (PORT_A_RD_SRST && (!OPTION_SRST_GATE || (OPTION_SRST_GATE == 2 && PORT_A_RD_EN) || (OPTION_SRST_GATE == 1 && PORT_A_CLK_EN))) + PORT_A_RD_DATA <= SRST_VALUE; +end + +always @(PORT_A_RD_ARST) + if (PORT_A_RD_ARST) + force PORT_A_RD_DATA = ARST_VALUE; + else + release PORT_A_RD_DATA; + +endmodule diff --git a/tests/memlib/memlib_block_tdp.txt b/tests/memlib/memlib_block_tdp.txt new file mode 100644 index 000000000..80cc7e504 --- /dev/null +++ b/tests/memlib/memlib_block_tdp.txt @@ -0,0 +1,10 @@ +ram block \RAM_BLOCK_TDP { + cost 64; + abits 10; + widths 1 2 4 8 16 per_port; + init any; + port srsw "A" "B" { + clock anyedge; + rdwr no_change; + } +} diff --git a/tests/memlib/memlib_block_tdp.v b/tests/memlib/memlib_block_tdp.v new file mode 100644 index 000000000..c6b876360 --- /dev/null +++ b/tests/memlib/memlib_block_tdp.v @@ -0,0 +1,38 @@ +module RAM_BLOCK_TDP( + input PORT_A_CLK, + input PORT_A_WR_EN, + input [9:0] PORT_A_ADDR, + input [15:0] PORT_A_WR_DATA, + output reg [15:0] PORT_A_RD_DATA, + input PORT_B_CLK, + input PORT_B_WR_EN, + input [9:0] PORT_B_ADDR, + input [15:0] PORT_B_WR_DATA, + output reg [15:0] PORT_B_RD_DATA +); + +parameter INIT = 0; +parameter PORT_A_WIDTH = 1; +parameter PORT_B_WIDTH = 1; +parameter PORT_A_CLK_POL = 0; +parameter PORT_B_CLK_POL = 0; + +reg [2**10-1:0] mem = INIT; + +always @(negedge (PORT_A_CLK ^ PORT_A_CLK_POL)) begin + if (PORT_A_WR_EN) begin + mem[PORT_A_ADDR+:PORT_A_WIDTH] <= PORT_A_WR_DATA; + end else begin + PORT_A_RD_DATA <= mem[PORT_A_ADDR+:PORT_A_WIDTH]; + end +end + +always @(negedge (PORT_B_CLK ^ PORT_B_CLK_POL)) begin + if (PORT_B_WR_EN) begin + mem[PORT_B_ADDR+:PORT_B_WIDTH] <= PORT_B_WR_DATA; + end else begin + PORT_B_RD_DATA <= mem[PORT_B_ADDR+:PORT_B_WIDTH]; + end +end + +endmodule diff --git a/tests/memlib/memlib_lut.txt b/tests/memlib/memlib_lut.txt new file mode 100644 index 000000000..0cc8fda15 --- /dev/null +++ b/tests/memlib/memlib_lut.txt @@ -0,0 +1,12 @@ +ram distributed \RAM_LUT { + abits 4; + width 4; + init any; + cost 4; + port ar "R" { + } + port arsw "RW" { + clock anyedge; + } +} + diff --git a/tests/memlib/memlib_lut.v b/tests/memlib/memlib_lut.v new file mode 100644 index 000000000..1f20a110a --- /dev/null +++ b/tests/memlib/memlib_lut.v @@ -0,0 +1,30 @@ +module RAM_LUT( + input [3:0] PORT_R_ADDR, + input [3:0] PORT_RW_ADDR, + input PORT_RW_CLK, + input PORT_RW_WR_EN, + input [3:0] PORT_RW_WR_DATA, + output [3:0] PORT_R_RD_DATA, + output [3:0] PORT_RW_RD_DATA +); + +parameter INIT = 0; +parameter PORT_RW_CLK_POL = 1; + +reg [3:0] mem [0:15]; + +integer i; +initial + for (i = 0; i < 16; i += 1) + mem[i] = INIT[i*4+:4]; + +assign PORT_R_RD_DATA = mem[PORT_R_ADDR]; +assign PORT_RW_RD_DATA = mem[PORT_RW_ADDR]; + +wire CLK = PORT_RW_CLK ~^ PORT_RW_CLK_POL; + +always @(posedge CLK) + if (PORT_RW_WR_EN) + mem[PORT_RW_ADDR] <= PORT_RW_WR_DATA; + +endmodule diff --git a/tests/memlib/memlib_wide_read.txt b/tests/memlib/memlib_wide_read.txt new file mode 100644 index 000000000..c11021045 --- /dev/null +++ b/tests/memlib/memlib_wide_read.txt @@ -0,0 +1,12 @@ +ram block \RAM_WIDE_READ { + cost 2; + abits 6; + widths 1 2 4 8 per_port; + init any; + port srsw "A" { + width rd 8 wr 2; + clock posedge; + rden; + rdwr old; + } +} diff --git a/tests/memlib/memlib_wide_read.v b/tests/memlib/memlib_wide_read.v new file mode 100644 index 000000000..e45f64376 --- /dev/null +++ b/tests/memlib/memlib_wide_read.v @@ -0,0 +1,25 @@ +module RAM_WIDE_READ #( + parameter [63:0] INIT = 64'hx, + parameter PORT_A_RD_WIDTH = 8, + parameter PORT_A_WR_WIDTH = 2 +) ( + input PORT_A_CLK, + input PORT_A_RD_EN, + input [5:0] PORT_A_ADDR, + output reg [7:0] PORT_A_RD_DATA, + input PORT_A_WR_EN, + input [1:0] PORT_A_WR_DATA +); + +reg [63:0] mem; + +initial mem = INIT; + +always @(posedge PORT_A_CLK) begin + if (PORT_A_RD_EN) + PORT_A_RD_DATA <= mem[{PORT_A_ADDR[5:3], 3'b000}+:8]; + if (PORT_A_WR_EN) + mem[{PORT_A_ADDR[5:1],1'b0}+:2] <= PORT_A_WR_DATA; +end + +endmodule diff --git a/tests/memlib/memlib_wide_sdp.txt b/tests/memlib/memlib_wide_sdp.txt new file mode 100644 index 000000000..ec90c45bd --- /dev/null +++ b/tests/memlib/memlib_wide_sdp.txt @@ -0,0 +1,17 @@ +ram block \RAM_WIDE_SDP { + cost 2; + abits 6; + widths 1 2 5 10 20 per_port; + byte 5; + init any; + port sr "R" { + clock posedge; + rden; + rdsrst any ungated; + } + port sw "W" { + clock posedge; + wrtrans "R" old; + wrbe_separate; + } +} diff --git a/tests/memlib/memlib_wide_sdp.v b/tests/memlib/memlib_wide_sdp.v new file mode 100644 index 000000000..456853177 --- /dev/null +++ b/tests/memlib/memlib_wide_sdp.v @@ -0,0 +1,45 @@ +module RAM_WIDE_SDP #( + parameter [79:0] INIT = 80'hx, + parameter PORT_R_WIDTH = 1, + parameter PORT_W_WIDTH = 1, + parameter PORT_W_WR_BE_WIDTH = 1, + parameter PORT_R_RD_SRST_VALUE = 16'hx +) ( + input PORT_R_CLK, + input PORT_R_RD_EN, + input PORT_R_RD_SRST, + input [5:0] PORT_R_ADDR, + output reg [PORT_R_WIDTH-1:0] PORT_R_RD_DATA, + input PORT_W_CLK, + input PORT_W_WR_EN, + input [PORT_W_WR_BE_WIDTH-1:0] PORT_W_WR_BE, + input [5:0] PORT_W_ADDR, + input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA +); + +reg [79:0] mem; + +initial mem = INIT; + +always @(posedge PORT_R_CLK) + if (PORT_R_RD_SRST) + PORT_R_RD_DATA <= PORT_R_RD_SRST_VALUE; + else if (PORT_R_RD_EN) + PORT_R_RD_DATA <= mem[PORT_R_ADDR[5:2] * 5 + PORT_R_ADDR[1:0]+:PORT_R_WIDTH]; + +generate + if (PORT_W_WIDTH < 5) begin + always @(posedge PORT_W_CLK) + if (PORT_W_WR_EN && PORT_W_WR_BE[0]) + mem[PORT_W_ADDR[5:2] * 5 + PORT_W_ADDR[1:0]+:PORT_W_WIDTH] <= PORT_W_WR_DATA; + end else begin + integer i; + always @(posedge PORT_W_CLK) + if (PORT_W_WR_EN) + for (i = 0; i < PORT_W_WR_BE_WIDTH; i = i + 1) + if (PORT_W_WR_BE[i]) + mem[(PORT_W_ADDR[5:2] + i) * 5+:5] <= PORT_W_WR_DATA[i * 5+:5]; + end +endgenerate + +endmodule diff --git a/tests/memlib/memlib_wide_sp.txt b/tests/memlib/memlib_wide_sp.txt new file mode 100644 index 000000000..7780e4f9d --- /dev/null +++ b/tests/memlib/memlib_wide_sp.txt @@ -0,0 +1,22 @@ +ram block \RAM_WIDE_SP { + cost 2; + abits 6; + widths 1 2 5 10 20 per_port; + byte 5; + init any; + port srsw "A" { + ifdef WIDTH_MIX { + option "WIDTH_MIX" 1 { + width mix; + } + } else { + option "WIDTH_MIX" 0 { + width tied; + } + } + clock posedge; + rden; + rdwr old; + rdsrst any ungated; + } +} diff --git a/tests/memlib/memlib_wide_sp.v b/tests/memlib/memlib_wide_sp.v new file mode 100644 index 000000000..920a3339a --- /dev/null +++ b/tests/memlib/memlib_wide_sp.v @@ -0,0 +1,54 @@ +module RAM_WIDE_SP #( + parameter [79:0] INIT = 80'hx, + parameter PORT_A_RD_WIDTH = 1, + parameter PORT_A_WR_WIDTH = 1, + parameter PORT_A_WIDTH = 1, + parameter OPTION_WIDTH_MIX = 0, + parameter PORT_A_WR_EN_WIDTH = 1, + parameter PORT_A_RD_SRST_VALUE = 16'hx, + parameter RD_WIDTH = OPTION_WIDTH_MIX ? PORT_A_RD_WIDTH : PORT_A_WIDTH, + parameter WR_WIDTH = OPTION_WIDTH_MIX ? PORT_A_WR_WIDTH : PORT_A_WIDTH +) ( + input PORT_A_CLK, + input PORT_A_RD_EN, + input PORT_A_RD_SRST, + input [5:0] PORT_A_ADDR, + output reg [RD_WIDTH-1:0] PORT_A_RD_DATA, + input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN, + input [WR_WIDTH-1:0] PORT_A_WR_DATA +); + +reg [79:0] mem; + +initial mem = INIT; + +always @(posedge PORT_A_CLK) + if (PORT_A_RD_SRST) + PORT_A_RD_DATA <= PORT_A_RD_SRST_VALUE; + else if (PORT_A_RD_EN) + case (RD_WIDTH) + 1: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:2] * 5 + PORT_A_ADDR[1:0]+:1]; + 2: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:2] * 5 + PORT_A_ADDR[1] * 2+:2]; + 5: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:2] * 5+:5]; + 10: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:3] * 10+:10]; + 20: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:4] * 20+:20]; + endcase + +always @(posedge PORT_A_CLK) + case (WR_WIDTH) + 1: if (PORT_A_WR_EN) mem[PORT_A_ADDR[5:2] * 5 + PORT_A_ADDR[1:0]+:1] <= PORT_A_WR_DATA; + 2: if (PORT_A_WR_EN) mem[PORT_A_ADDR[5:2] * 5 + PORT_A_ADDR[1] * 2+:2] <= PORT_A_WR_DATA; + 5: if (PORT_A_WR_EN) mem[PORT_A_ADDR[5:2] * 5+:5] <= PORT_A_WR_DATA; + 10: begin + if (PORT_A_WR_EN[0]) mem[PORT_A_ADDR[5:3] * 10+:5] <= PORT_A_WR_DATA[4:0]; + if (PORT_A_WR_EN[1]) mem[PORT_A_ADDR[5:3] * 10 + 5+:5] <= PORT_A_WR_DATA[9:5]; + end + 20: begin + if (PORT_A_WR_EN[0]) mem[PORT_A_ADDR[5:4] * 20+:5] <= PORT_A_WR_DATA[4:0]; + if (PORT_A_WR_EN[1]) mem[PORT_A_ADDR[5:4] * 20 + 5+:5] <= PORT_A_WR_DATA[9:5]; + if (PORT_A_WR_EN[2]) mem[PORT_A_ADDR[5:4] * 20 + 10+:5] <= PORT_A_WR_DATA[14:10]; + if (PORT_A_WR_EN[3]) mem[PORT_A_ADDR[5:4] * 20 + 15+:5] <= PORT_A_WR_DATA[19:15]; + end + endcase + +endmodule diff --git a/tests/memlib/memlib_wide_write.txt b/tests/memlib/memlib_wide_write.txt new file mode 100644 index 000000000..59222b7fb --- /dev/null +++ b/tests/memlib/memlib_wide_write.txt @@ -0,0 +1,13 @@ +ram block \RAM_WIDE_WRITE { + cost 2; + abits 6; + widths 1 2 4 8 per_port; + byte 4; + init any; + port srsw "A" { + width rd 2 wr 8; + clock posedge; + rden; + rdwr old; + } +} diff --git a/tests/memlib/memlib_wide_write.v b/tests/memlib/memlib_wide_write.v new file mode 100644 index 000000000..afed6d00c --- /dev/null +++ b/tests/memlib/memlib_wide_write.v @@ -0,0 +1,29 @@ +module RAM_WIDE_WRITE #( + parameter [63:0] INIT = 64'hx, + parameter PORT_A_RD_WIDTH = 2, + parameter PORT_A_WR_WIDTH = 8, + parameter PORT_A_WR_EN_WIDTH = 2 +) ( + input PORT_A_CLK, + input PORT_A_RD_EN, + input [5:0] PORT_A_ADDR, + output reg [1:0] PORT_A_RD_DATA, + input [1:0] PORT_A_WR_EN, + input [7:0] PORT_A_WR_DATA +); + +reg [63:0] mem; + +initial mem = INIT; + +always @(posedge PORT_A_CLK) begin + if (PORT_A_RD_EN) + PORT_A_RD_DATA <= mem[{PORT_A_ADDR[5:1],1'b0}+:2]; + if (PORT_A_WR_EN[0]) + mem[{PORT_A_ADDR[5:3],3'b000}+:4] <= PORT_A_WR_DATA[3:0]; + if (PORT_A_WR_EN[1]) + mem[{PORT_A_ADDR[5:3],3'b100}+:4] <= PORT_A_WR_DATA[7:4]; +end + +endmodule + diff --git a/tests/memlib/run-test.sh b/tests/memlib/run-test.sh new file mode 100755 index 000000000..abe88a6cb --- /dev/null +++ b/tests/memlib/run-test.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -eu + +OPTIND=1 +seed="" # default to no seed specified +while getopts "S:" opt +do + case "$opt" in + S) seed="$OPTARG" ;; + esac +done +shift "$((OPTIND-1))" + +python3 generate.py +exec ${MAKE:-make} -f run-test.mk SEED="$seed"