diff options
author | KrystalDelusion <krystinedawn@yosyshq.com> | 2022-07-07 11:10:33 +1200 |
---|---|---|
committer | KrystalDelusion <krystinedawn@yosyshq.com> | 2023-02-21 05:23:15 +1300 |
commit | 7f033d3c1f4604d303da237fbc7a38ee503416ad (patch) | |
tree | ab936013736da16465f74fe771dd08f5fbf261d6 /tests/memlib | |
parent | af1b9c9e070dd5873871c73c5762fbefd345a8c9 (diff) | |
download | yosys-7f033d3c1f4604d303da237fbc7a38ee503416ad.tar.gz yosys-7f033d3c1f4604d303da237fbc7a38ee503416ad.tar.bz2 yosys-7f033d3c1f4604d303da237fbc7a38ee503416ad.zip |
More tests in memlib/generate.py
Covers most of the todo list, at least functionally. Some minor issues with not always using hardware features.
Diffstat (limited to 'tests/memlib')
-rw-r--r-- | tests/memlib/generate.py | 677 | ||||
-rw-r--r-- | tests/memlib/memlib_9b1B.txt | 31 | ||||
-rw-r--r-- | tests/memlib/memlib_9b1B.v | 68 | ||||
-rw-r--r-- | tests/memlib/memlib_block_sp_full.txt | 61 | ||||
-rw-r--r-- | tests/memlib/memlib_block_sp_full.v | 82 | ||||
-rw-r--r-- | tests/memlib/memlib_clock_sdp.txt | 76 | ||||
-rw-r--r-- | tests/memlib/memlib_clock_sdp.v | 36 | ||||
-rw-r--r-- | tests/memlib/memlib_lut.txt | 18 | ||||
-rw-r--r-- | tests/memlib/memlib_lut.v | 9 | ||||
-rw-r--r-- | tests/memlib/memlib_multilut.txt | 19 | ||||
-rw-r--r-- | tests/memlib/memlib_multilut.v | 45 | ||||
-rw-r--r-- | tests/memlib/memlib_wren.txt | 37 | ||||
-rw-r--r-- | tests/memlib/memlib_wren.v | 33 |
13 files changed, 1180 insertions, 12 deletions
diff --git a/tests/memlib/generate.py b/tests/memlib/generate.py index 341486584..f40210501 100644 --- a/tests/memlib/generate.py +++ b/tests/memlib/generate.py @@ -1,13 +1,6 @@ # 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 @@ -22,6 +15,7 @@ class Test: TESTS = [] ### basic sanity tests +# Asynchronous-read RAM ASYNC = """ module top(clk, ra, wa, rd, wd, we); @@ -56,6 +50,7 @@ TESTS += [ Test("async_small_block", ASYNC_SMALL, ["block_tdp"], [], {"RAM_BLOCK_TDP": 0}), ] +# Synchronous SDP read first SYNC = """ module top(clk, ra, wa, rd, wd, we); @@ -95,6 +90,261 @@ TESTS += [ Test("sync_small_block_attr", SYNC_SMALL_BLOCK, ["lut", "block_tdp"], [], {"RAM_BLOCK_TDP": 1}), ] +### initialization values testing +LUT_INIT = """ +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]; + +integer i; +initial + for (i = 0; i < 2**ABITS-1; i = i + 1) + mem[i] = {ival}; + +always @(posedge clk) + if (we) + mem[wa] <= wd; + +assign rd = mem[ra]; + +endmodule +""" + +INIT_LUT_ZEROS = LUT_INIT.format(abits=4, dbits=4, ival=0); +INIT_LUT_VAL = LUT_INIT.format(abits=4, dbits=4, ival=5); +INIT_LUT_VAL2 = LUT_INIT.format(abits=6, dbits=6, ival="6'h12"); +INIT_LUT_X = LUT_INIT.format(abits=4, dbits=4, ival="4'hx") + +TESTS += [ + Test("init_lut_zeros_zero", INIT_LUT_ZEROS, ["lut"], ["INIT_ZERO"], {"RAM_LUT":1}), + Test("init_lut_zeros_any", INIT_LUT_ZEROS, ["lut"], ["INIT_ANY"], {"RAM_LUT":1}), + Test("init_lut_val_zero", INIT_LUT_VAL, ["lut"], ["INIT_ZERO"], {"RAM_LUT":0}), #CHECK: no emulation? + Test("init_lut_val_any", INIT_LUT_VAL, ["lut"], ["INIT_ANY"], {"RAM_LUT":1}), + Test("init_lut_val_no_undef", INIT_LUT_VAL, ["lut"], ["INIT_NO_UNDEF"], {"RAM_LUT":1}), + Test("init_lut_val2_any", INIT_LUT_VAL2, ["lut"], ["INIT_ANY"], {"RAM_LUT":8}), + Test("init_lut_val2_no_undef", INIT_LUT_VAL2, ["lut"], ["INIT_NO_UNDEF"], {"RAM_LUT":8}), + Test("init_lut_x_none", INIT_LUT_X, ["lut"], ["INIT_NONE"], {"RAM_LUT":1}), + Test("init_lut_x_zero", INIT_LUT_X, ["lut"], ["INIT_ZERO"], {"RAM_LUT":1}), + Test("init_lut_x_any", INIT_LUT_X, ["lut"], ["INIT_ANY"], {"RAM_LUT":1}), + Test("init_lut_x_no_undef", INIT_LUT_X, ["lut"], ["INIT_NO_UNDEF"], {"RAM_LUT":1}), +] + +### width testing 9-bit-per-byte +RAM_9b1B = """ +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; + +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +always @(posedge clk) + if (we) + mem[wa] <= wd; + +always @(posedge clk) + rd <= mem[ra]; + +endmodule +""" + +RAM_18b2B = RAM_9b1B.format(abits=3, dbits=18); +RAM_9b1B = RAM_9b1B.format(abits=4, dbits=9); +RAM_4b1B = RAM_9b1B.format(abits=5, dbits=4); +RAM_2b1B = RAM_9b1B.format(abits=6, dbits=2); +RAM_1b1B = RAM_9b1B.format(abits=7, dbits=1); + +TESTS += [ + Test("ram_18b2B", RAM_18b2B, ["9b1B"], [], {"RAM_9b1B":1}), + Test("ram_9b1B", RAM_9b1B, ["9b1B"], [], {"RAM_9b1B":1}), + Test("ram_4b1B", RAM_4b1B, ["9b1B"], [], {"RAM_9b1B":1}), + Test("ram_2b1B", RAM_2b1B, ["9b1B"], [], {"RAM_9b1B":1}), + Test("ram_1b1B", RAM_1b1B, ["9b1B"], [], {"RAM_9b1B":1}), +] + +### initializing 9-bits-per-byte +RAM_9b1B_init = """ +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; + +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +integer i; +initial + for (i = 0; i < 2**ABITS-1; i = i + 1) + mem[i] = {ival}; + +always @(posedge clk) + if (we) + mem[wa] <= wd; + +always @(posedge clk) + rd <= mem[ra]; + +endmodule +""" + +INIT_9b1B_ZEROS = RAM_9b1B_init.format(abits=4, dbits=9, ival=0); +INIT_9b1B_VAL = RAM_9b1B_init.format(abits=4, dbits=9, ival=275); +INIT_13b2B_VAL = RAM_9b1B_init.format(abits=3, dbits=13, ival="13'h01f3") +INIT_18b2B_VAL = RAM_9b1B_init.format(abits=4, dbits=18, ival="18'h1f39a"); +INIT_4b1B_X = RAM_9b1B_init.format(abits=5, dbits=4, ival="4'hx") + +TESTS += [ + Test("init_9b1B_zeros_zero", INIT_9b1B_ZEROS, ["9b1B"], ["INIT_ZERO"], {"RAM_9b1B":1}), + Test("init_9b1B_zeros_any", INIT_9b1B_ZEROS, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":1}), + Test("init_9b1B_val_zero", INIT_9b1B_VAL, ["9b1B"], ["INIT_ZERO"], {"RAM_9b1B":0}), #CHECK: no emulation? + Test("init_9b1B_val_any", INIT_9b1B_VAL, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":1}), + Test("init_9b1B_val_no_undef", INIT_9b1B_VAL, ["9b1B"], ["INIT_NO_UNDEF"], {"RAM_9b1B":1}), + Test("init_13b2B_val_any", INIT_13b2B_VAL, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":1}), + Test("init_18b2B_val_any", INIT_18b2B_VAL, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":2}), + Test("init_18b2B_val_no_undef", INIT_18b2B_VAL, ["9b1B"], ["INIT_NO_UNDEF"], {"RAM_9b1B":2}), + Test("init_4b1B_x_none", INIT_4b1B_X, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B":1}), + Test("init_4b1B_x_zero", INIT_4b1B_X, ["9b1B"], ["INIT_ZERO"], {"RAM_9b1B":1}), + Test("init_4b1B_x_any", INIT_4b1B_X, ["9b1B"], ["INIT_ANY"], {"RAM_9b1B":1}), + Test("init_4b1B_x_no_undef", INIT_4b1B_X, ["9b1B"], ["INIT_NO_UNDEF"], {"RAM_9b1B":1}), +] + +### Clock polarity combinations +# I'm not entirely convinced auto-test is correctly testing clock edging +# but they do at least all gen/synth +SYNCCLOCK = """ +module top(clk, ra, wa, rd, wd, we); + +localparam ABITS = {abits}; +localparam DBITS = 8; + +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 @(posedge clk) + if (we) + mem[wa] <= wd; + +always @(posedge clk) + rd <= mem[ra]; + +endmodule +""" +for (abits, cnt, wclk, rclk, shared) in [ + (4, 1, "ANY","ANY", False), + (4, 1, "ANY","NEG", False), + (4, 1, "ANY","POS", False), + (4, 1, "NEG","ANY", False), + (4, 1, "NEG","POS", False), + (4, 1, "NEG","NEG", False), + (4, 1, "POS","ANY", False), + (4, 1, "POS","NEG", False), + (4, 1, "POS","POS", False), + (4, 1, "ANY","ANY", True), + (4, 0, "NEG","POS", True), # FF mapping + (4, 1, "NEG","NEG", True), + (4, 0, "POS","NEG", True), # FF mapping + (4, 1, "POS","POS", True), + # cannot combine "ANY" with "POS|NEG" when using shared clock +]: + name = f"clock_a{abits}_w{wclk}r{rclk}s{shared}" + defs = ["WCLK_" + wclk, "RCLK_" + rclk] + if (shared): + defs.append("SHARED_CLK") + TESTS.append(Test( + name, SYNCCLOCK.format(abits=abits), + ["clock_sdp"], defs, {"RAM_CLOCK_SDP": cnt} + )) + +### mixed width testing +# Wide write port +MIXED_WRITE = """ +module top(clk, ra, wa, rd, wd, we); + +localparam WABITS = {wabits}; +localparam WDBITS = {wdbits}; + +localparam RABITS = {rabits}; +localparam RDBITS = {rdbits}; + +input wire clk; +input wire we; +input wire [WABITS-1:0] wa; +input wire [WDBITS-1:0] wd; +input wire [RABITS-1:0] ra; +output reg [RDBITS-1:0] rd; + +localparam DEPTH = (2**WABITS); + +localparam OFFSET = RABITS-WABITS; + +(* syn_ramstyle = "block_ram" *) +reg [WDBITS-1:0] mem [0:DEPTH-1]; + +always @(posedge clk) + if (we) + mem[wa] <= wd; + +if (OFFSET > 0) begin + reg [WDBITS-1:0] mem_read; + reg [OFFSET-1:0] subaddr_r; + always @(posedge clk) begin + mem_read <= mem[ra[RABITS-1:OFFSET]]; + subaddr_r <= ra[OFFSET-1:0]; + end + + always @(mem_read, subaddr_r) + rd <= mem_read[subaddr_r*RDBITS+:RDBITS]; +end +else +begin + always @(posedge clk) + case (OFFSET) + 0: rd <= mem[ra]; + -1: rd <= {{ mem[ra], mem[ra+1] }}; + endcase +end +endmodule +""" + +UNMIXED = MIXED_WRITE.format(wabits=4, wdbits=9, rabits=4, rdbits=9) +MIXED_9_18 = MIXED_WRITE.format(wabits=5, wdbits=9, rabits=4, rdbits=18) +MIXED_18_9 = MIXED_WRITE.format(wabits=3, wdbits=18, rabits=4, rdbits=9) +MIXED_36_9 = MIXED_WRITE.format(wabits=3, wdbits=36, rabits=5, rdbits=9) +MIXED_4_2 = MIXED_WRITE.format(wabits=5, wdbits=4, rabits=6, rdbits=2); + +TESTS += [ + Test("unmixed", UNMIXED, ["9b1B"], [], {"RAM_9b1B":1}), + Test("mixed_9_18", MIXED_9_18, ["9b1B"], [], {"RAM_9b1B":4}), #CHECK: only using half the memory + Test("mixed_18_9", MIXED_18_9, ["9b1B"], [], {"RAM_9b1B":1}), + Test("mixed_36_9", MIXED_36_9, ["9b1B"], [], {"RAM_9b1B":2}), + Test("mixed_4_2", MIXED_4_2, ["9b1B"], [], {"RAM_9b1B":1}), +] + ### basic TDP test TDP = """ @@ -131,7 +381,7 @@ TESTS += [ ] # shared clock - +# Synchronous SDP with clock domain crossing SYNC_2CLK = """ module top(rclk, wclk, ra, wa, rd, wd, we); @@ -163,7 +413,7 @@ TESTS += [ ] # inter-port transparency - +# Synchronous SDP with write-first behaviour SYNC_TRANS = """ module top(clk, ra, wa, rd, wd, we); @@ -201,7 +451,7 @@ TESTS += [ ] # rdwr checks - +# Synchronous single-port RAM with mutually exclusive read/write SP_NO_CHANGE = """ module top(clk, addr, rd, wd, we); @@ -247,6 +497,7 @@ end endmodule """ +# Synchronous single-port RAM with write-first behaviour SP_NEW = """ module top(clk, addr, rd, wd, we); @@ -295,6 +546,7 @@ end endmodule """ +# Synchronous single-port RAM with read-first behaviour SP_OLD = """ module top(clk, addr, rd, wd, we); @@ -373,6 +625,7 @@ TESTS += [ Test("sp_old_auto_be", SP_OLD_BE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "OLD"})}), ] +# Synchronous read port with initial value SP_INIT = """ module top(clk, addr, rd, wd, we, re); @@ -418,6 +671,7 @@ TESTS += [ Test("sp_init_v_any_re", SP_INIT_V, ["block_sp"], ["RDINIT_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), ] +# Synchronous read port with asynchronous reset SP_ARST = """ module top(clk, addr, rd, wd, we, re, ar); @@ -488,6 +742,7 @@ TESTS += [ Test("sp_arst_n_init_re", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), ] +# Synchronous read port with synchronous reset (reset priority over enable) SP_SRST = """ module top(clk, addr, rd, wd, we, re, sr); @@ -515,6 +770,7 @@ end endmodule """ +# Synchronous read port with synchronous reet (enable priority over reset) SP_SRST_G = """ module top(clk, addr, rd, wd, we, re, sr); @@ -602,6 +858,180 @@ TESTS += [ Test("sp_srst_gv_init_re", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}), ] +# Byte enables, wrbe_separate +SYNC_ENABLE = """ +module top(clk, rwa, rd, wd, we); + +localparam ABITS = {abits}; +localparam DBITS = {dbits}; + +input wire clk; +input wire we; +input wire [ABITS-1:0] rwa; +input wire [DBITS-1:0] wd; +output reg [DBITS-1:0] rd; + +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +always @(posedge clk) begin + if (we) + mem[rwa] <= wd; + else + rd <= mem[rwa]; +end + +endmodule +""" + +for (abits, dbits, sep, defs, cells) in [ + (4, 4, False, ["NO_BYTE"], {"RAM_WREN": 1}), + (5, 4, False, ["NO_BYTE"], {"RAM_WREN": 2}), + (6, 4, False, ["NO_BYTE"], {"RAM_WREN": 4}), + # (4, 4, True, ["NO_BYTE"], {"RAM_WREN": 1}), # should throw an error + (3, 8, False, ["NO_BYTE"], {"RAM_WREN": 2}), # needs two write ports + (4, 8, False, ["NO_BYTE"], {"RAM_WREN": 2}), + (4, 4, False, ["W4_B4"], {"RAM_WREN": 1}), + (4, 8, True, ["W4_B4"], {"RAM_WREN": 2}), + (4, 8, False, ["W8_B4"], {"RAM_WREN": 1}), + (4, 8, True, ["W8_B4"], {"RAM_WREN": 1}), + (4, 8, False, ["W8_B8"], {"RAM_WREN": 1}), + (4, 8, True, ["W8_B8"], {"RAM_WREN": 1}), + +]: + name = f"wren_a{abits}d{dbits}_{defs[0]}" + if (sep): + defs.append("WRBE_SEPARATE") + name += "_separate" + + TESTS.append(Test( + name, SYNC_ENABLE.format(abits=abits, dbits=dbits), + ["wren"], defs, cells + )) + +# Write port with byte enables +ENABLES = """ +module top(clk, we, be, rwa, wd, rd); + +localparam ABITS = {abits}; +localparam WBITS = {wbits}; +localparam WORDS = {words}; + +input wire clk; +input wire we; +input wire [WORDS-1:0] be; +input wire [ABITS-1:0] rwa; +input wire [(WBITS*WORDS)-1:0] wd; +output reg [(WBITS*WORDS)-1:0] rd; + +reg [(WBITS*WORDS)-1:0] mem [0:2**ABITS-1]; + +integer i; +always @(posedge clk) + for (i=0; i<WORDS; i=i+1) + if (we && be[i]) + mem[rwa][i*WBITS+:WBITS] <= wd[i*WBITS+:WBITS]; + +always @(posedge clk) + if (!we) + rd <= mem[rwa]; + +endmodule +""" + +for (abits, wbits, words, defs, cells) in [ + (4, 2, 8, ["W16_B4"], {"RAM_WREN": 2}), + (4, 4, 4, ["W16_B4"], {"RAM_WREN": 1}), + (5, 4, 2, ["W16_B4"], {"RAM_WREN": 1}), + (5, 4, 4, ["W16_B4"], {"RAM_WREN": 2}), + (4, 8, 2, ["W16_B4"], {"RAM_WREN": 1}), + (5, 8, 1, ["W16_B4"], {"RAM_WREN": 1}), + (5, 8, 2, ["W16_B4"], {"RAM_WREN": 2}), + (4,16, 1, ["W16_B4"], {"RAM_WREN": 1}), + (4, 4, 2, ["W8_B8"], {"RAM_WREN": 2}), + (4, 4, 1, ["W8_B8"], {"RAM_WREN": 1}), + (4, 8, 2, ["W8_B8"], {"RAM_WREN": 2}), + (3, 8, 2, ["W8_B8"], {"RAM_WREN": 2}), + (4, 4, 2, ["W8_B4"], {"RAM_WREN": 1}), + (4, 2, 4, ["W8_B4"], {"RAM_WREN": 2}), + (4, 4, 4, ["W8_B4"], {"RAM_WREN": 2}), + (4, 4, 4, ["W4_B4"], {"RAM_WREN": 4}), + (4, 4, 5, ["W4_B4"], {"RAM_WREN": 5}), + +]: + name = f"wren_a{abits}d{wbits}w{words}_{defs[0]}" + TESTS.append(Test( + name, ENABLES.format(abits=abits, wbits=wbits, words=words), + ["wren"], defs, cells + )) + + defs.append("WRBE_SEPARATE") + name += "_separate" + TESTS.append(Test( + name, ENABLES.format(abits=abits, wbits=wbits, words=words), + ["wren"], defs, cells + )) + +# abits/dbits determination (aka general geometry picking) +GEOMETRIC = """ +module top(clk, rwa, rd, wd, we); + +localparam ABITS = {abits}; +localparam DBITS = {dbits}; + +input wire clk; +input wire we; +input wire [ABITS-1:0] rwa; +input wire [DBITS-1:0] wd; +output reg [DBITS-1:0] rd; + +(* ram_style="block" *) +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +always @(posedge clk) + if (we) + mem[rwa] <= wd; + else + rd <= mem[rwa]; + +endmodule +""" + +for (abits,dbits, libs, defs, cells) in [ + # W64_B8 gives 16 * 64 = 1024 bits of memory with up to 8x8b rw ports + ( 4, 64, ["wren"], ["W64_B8"], {"RAM_WREN": 1}), + ( 5, 32, ["wren"], ["W64_B8"], {"RAM_WREN": 1}), + ( 5, 64, ["wren"], ["W64_B8"], {"RAM_WREN": 2}), + ( 6, 16, ["wren"], ["W64_B8"], {"RAM_WREN": 1}), + ( 6, 30, ["wren"], ["W64_B8"], {"RAM_WREN": 2}), + ( 6, 64, ["wren"], ["W64_B8"], {"RAM_WREN": 4}), + ( 7, 4, ["wren"], ["W64_B8"], {"RAM_WREN": 1}), + ( 7, 6, ["wren"], ["W64_B8"], {"RAM_WREN": 1}), + ( 7, 8, ["wren"], ["W64_B8"], {"RAM_WREN": 1}), + ( 7, 17, ["wren"], ["W64_B8"], {"RAM_WREN": 3}), + ( 8, 4, ["wren"], ["W64_B8"], {"RAM_WREN": 2}), + ( 8, 6, ["wren"], ["W64_B8"], {"RAM_WREN": 2}), + ( 9, 4, ["wren"], ["W64_B8"], {"RAM_WREN": 4}), + ( 9, 8, ["wren"], ["W64_B8"], {"RAM_WREN": 4}), + ( 9, 5, ["wren"], ["W64_B8"], {"RAM_WREN": 4}), + ( 9, 6, ["wren"], ["W64_B8"], {"RAM_WREN": 4}), + # 9b1B gives 128 bits of memory with 1 2 or 4 bit read and write ports + # or 144 bits with 9 or 18 bit read and write ports + ( 3, 18, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 1}), + ( 4, 4, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 1}), + ( 4, 18, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 2}), + ( 5, 32, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 8}), + ( 6, 4, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 2}), + ( 7, 11, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 11}), + ( 7, 18, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 16}), + ( 11, 1, ["9b1B"], ["INIT_NONE"], {"RAM_9b1B": 16}), +]: + name = f"geom_a{abits}d{dbits}_{libs[0]}" + TESTS.append(Test( + name, GEOMETRIC.format(abits=abits, dbits=dbits), + libs, defs, cells + )) + +# Mixed width testing WIDE_SDP = """ module top(rclk, ra, rd, re, rr, wclk, wa, wd, we); @@ -857,6 +1287,233 @@ for (aw, rw, ww, bw, cntww, cntwr) in [ {"RAM_WIDE_WRITE": cntww} )) +# Multiple read ports +# 1rw port plus 3 (or 7) r ports +QUAD_PORT = """ +module top(clk, rwa, r0a, r1a, r2a, rd, r0d, r1d, r2d, wd, we); + +localparam ABITS = {abits}; +localparam DBITS = {dbits}; + +input wire clk; +input wire we; +input wire [ABITS-1:0] rwa; +input wire [ABITS-1:0] r0a; +input wire [ABITS-1:0] r1a; +input wire [ABITS-1:0] r2a; +input wire [DBITS-1:0] wd; +output wire [DBITS-1:0] rd; +output wire [DBITS-1:0] r0d; +output wire [DBITS-1:0] r1d; +output wire [DBITS-1:0] r2d; + +reg [DBITS-1:0] mem [0:2**ABITS-1]; + +always @(posedge clk) + if (we) + mem[rwa] <= wd; + +assign rd = mem[rwa]; +assign r0d = mem[r0a]; +assign r1d = mem[r1a]; +assign r2d = mem[r2a]; + +endmodule +""" + +for (abits, dbits, cnt) in [ + (2, 2, 1), + (4, 2, 1), + (5, 2, 2), + (4, 4, 2), + (6, 2, 4), + (4, 8, 4), +]: + TESTS.append(Test( + f"quad_port_a{abits}d{dbits}", + QUAD_PORT.format(abits=abits, dbits=dbits), + ["multilut"], ["PORTS_QUAD"], + {"LUT_MULTI": cnt} + )) + +# Wide asynchronous read port +WIDE_READ = """ +module top(clk, we, rwa, wd, rd); + +localparam ABITS = {abits}; +localparam WBITS = {wbits}; +localparam RWORDS = {rwords}; + +input wire clk; +input wire we; +input wire [ABITS-1:0] rwa; +input wire [WBITS-1:0] wd; +output wire [(WBITS*RWORDS)-1:0] rd; + +reg [WBITS-1:0] mem [0:2**ABITS-1]; + +always @(posedge clk) + if (we) + mem[rwa] <= wd; + +genvar i; +generate + for (i = 0; i < RWORDS; i = i + 1) + assign rd[i*WBITS+:WBITS] = mem[rwa + i]; +endgenerate + +endmodule +""" + +for (abits, wbits, rwords, cntquad, cntoct) in [ + (4, 2, 1, 1, 1), + (4, 2, 2, 1, 1), + (4, 2, 3, 1, 1), + (4, 2, 4, 1, 1), + (4, 2, 5, 2, 1), + (4, 2, 6, 2, 1), + (4, 2, 7, 2, 1), # Write port needs to be duplicated, so only 3 extra read + (4, 2, 8, 3, 1), # ports per quad port LUT (i.e. 7 ports in 2, 8 ports in 3) + (4, 2, 9, 3, 2), + (4, 4, 1, 2, 2), + (4, 4, 4, 2, 2), + (4, 4, 6, 4, 2), + (4, 4, 9, 6, 4), + (5, 2, 1, 2, 2), + (5, 2, 4, 2, 2), + (5, 2, 9, 6, 4), +]: + TESTS.append(Test( + f"wide_quad_a{abits}w{wbits}r{rwords}", + WIDE_READ.format(abits=abits, wbits=wbits, rwords=rwords), + ["multilut"], ["PORTS_QUAD"], + {"LUT_MULTI": cntquad} + )) + TESTS.append(Test( + f"wide_oct_a{abits}w{wbits}r{rwords}", + WIDE_READ.format(abits=abits, wbits=wbits, rwords=rwords), + ["multilut"], ["PORTS_OCT"], + {"LUT_MULTI": cntoct} + )) + +# signal priorities & pattern testing +PRIORITY = """ +module top(clk, clken, wren, wben, rden, rst, addr, wdata, rdata); + +localparam ABITS = {abits}; +localparam WBITS = {wbits}; +localparam WORDS = {words}; + +localparam BITS = WBITS * WORDS; + +input wire clk, clken; +input wire wren, rden, rst; +input wire [WORDS-1:0] wben; +input wire [ABITS-1:0] addr; +input wire [BITS-1:0] wdata; +output reg [BITS-1:0] rdata; + +reg [BITS-1:0] mem [0:2**ABITS-1]; + +integer i; +always @(posedge clk) begin +{code} +end +endmodule +""" +#reset_gate in ["ungated", "rst", "rden && rst"] +#clk_en in [True, False] +#rdwr in ["nc", "old", "new", "undef", "newdef"] + +for (testname, reset_gate, rdwr, clk_en, add_logic) in [ + ("no_reset", "", "old", False, 0), + ("gclken", "rst", "old", False, 0), + ("ungated", "ungated", "old", False, 1), # muxes wren with rst + ("gclken_ce", "rst", "old", True, 3), # AND to simulate CLK_EN + ("grden", "rden && rst", "old", False, 1), # selects _clken, simulates _rden + ("grden_ce", "rden && rst", "old", True, 4), # both of the above + ("exclwr", "", "nc", False, 2), # selects new_only and simulates + ("excl_rst", "rst", "nc", False, 3), # as above, extra gate for rst + ("transwr", "", "new", False, 0), + ("trans_rst", "rst", "new", False, 0), +]: + write = "if (wren) \n\t\tmem[addr] <= wdata;" + + if rdwr == "new": + read = """if (rden) + if (wren) + rdata <= wdata; + else + rdata <= mem[addr];""" + else: + read = "if (rden) \n\t\trdata <= mem[addr];" + + if "rst" in reset_gate: + read = f"if ({reset_gate})\n\t\trdata <= 0; \n\telse {read}" + + if reset_gate == "ungated": + outer = "if (rst)\n\trdata <= 0;\nelse " + else: + outer = "" + + if clk_en: + outer = f"{outer}if (clken) " + + code = f"""{outer}begin + {write} + {"else " if rdwr == "nc" else ""}{read} +end""" + + TESTS.append(Test( + testname, PRIORITY.format(code=code, abits=4, wbits=8, words=2), + ["block_sp_full"], ["USE_SRST"], + {"RAM_BLOCK_SP": 1, "$*": add_logic} + )) + +for (testname, reset_gate, defs, rdwr, add_logic) in [ + ("wr_byte", "", ["USE_SRST_BLOCKING"], "old", 0), + ("trans_byte", "", ["USE_SRST_BLOCKING"], "new", 0), + ("wr_rst_byte", "rst", ["USE_SRST"], "old", 2), # expected mux to emulate blocking + ("rst_wr_byte", "rst", ["USE_SRST_BLOCKING"], "old", 2), # should use hardware blocking, doesn't + ("rdenrst_wr_byte", "rden && rst", ["USE_SRST"], "old", 3), +]: + wordsloop = "for (i=0; i<WORDS; i=i+1)" + if rdwr == "old": + read_write = f"""if (rden) + rdata = mem[addr]; + {wordsloop} + if (wben[i]) + mem[addr][i] <= wdata[i];""" + else: + read_write = f"""{wordsloop} + if (wben[i]) begin + mem[addr][i] <= wdata[i]; + rdata[i] <= wdata[i]; + end else + rdata[i] <= mem[addr][i];""" + + if "rst" in reset_gate: + reset_rw = f"""if ({reset_gate}) + rdata <= 0; +else begin + {read_write} +end""" + else: + reset_rw = read_write + + if reset_gate == "ungated": + outer = "if (rst)\n\trdata <= 0;\nelse " + else: + outer = "" + + code = f"{outer}\n{reset_rw}" + + TESTS.append(Test( + testname, PRIORITY.format(code=code, abits=4, wbits=1, words=2), + ["block_sp_full"], defs, + {"RAM_BLOCK_SP": 1, "$*": add_logic} + )) + with open("run-test.mk", "w") as mf: mf.write("ifneq ($(strip $(SEED)),)\n") mf.write("SEEDOPT=-S$(SEED)\n") diff --git a/tests/memlib/memlib_9b1B.txt b/tests/memlib/memlib_9b1B.txt new file mode 100644 index 000000000..4917aaf8b --- /dev/null +++ b/tests/memlib/memlib_9b1B.txt @@ -0,0 +1,31 @@ +ram block \RAM_9b1B { + cost 64; + abits 7; + widths 1 2 4 9 18 per_port; + byte 9; + + ifdef INIT_NONE { + option "INIT" "NONE" { + init none; + } + } else ifdef INIT_ZERO { + option "INIT" "ZERO" { + init zero; + } + } else ifdef INIT_NO_UNDEF { + option "INIT" "NO_UNDEF" { + init no_undef; + } + } else ifdef INIT_ANY { + option "INIT" "ANY" { + init any; + } + } + + port sw "W" { + clock anyedge; + } + port sr "R" { + clock anyedge; + } +} diff --git a/tests/memlib/memlib_9b1B.v b/tests/memlib/memlib_9b1B.v new file mode 100644 index 000000000..55545ebd4 --- /dev/null +++ b/tests/memlib/memlib_9b1B.v @@ -0,0 +1,68 @@ +module RAM_9b1B ( + input PORT_R_CLK, + input [6:0] PORT_R_ADDR, + output reg [PORT_R_WIDTH-1:0] PORT_R_RD_DATA, + input PORT_W_CLK, + input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN, + input [6:0] PORT_W_ADDR, + input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA +); + +parameter INIT = 0; +parameter OPTION_INIT = "UNDEFINED"; +parameter PORT_R_WIDTH = 9; +parameter PORT_W_WIDTH = 9; +parameter PORT_R_CLK_POL = 0; +parameter PORT_W_CLK_POL = 0; +parameter PORT_W_WR_EN_WIDTH = 1; + +reg [8:0] mem [0:15]; + +integer i; +initial + for (i = 0; i < 16; i += 1) + case (OPTION_INIT) + "NONE": mem[i] = mem[i]; //? + "ZERO": mem[i] = 9'h0; + "ANY": mem[i] = INIT[i*9+:9]; + "NO_UNDEF": mem[i] = INIT[i*9+:9]; + "UNDEFINED": mem[i] = 9'hx; + endcase + +wire [3:0] addr_r; +assign addr_r = PORT_R_ADDR[6:3]; +reg [17:0] mem_read; +reg [2:0] subaddr_r; +always @(negedge (PORT_R_CLK ^ PORT_R_CLK_POL)) begin + subaddr_r <= PORT_R_ADDR[2:0]; + mem_read[8:0] <= mem[addr_r]; + if (PORT_R_WIDTH == 18) + mem_read[17:9] <= mem[addr_r + 1]; +end + +always @(mem_read, subaddr_r) begin + case (PORT_R_WIDTH) + 18: PORT_R_RD_DATA <= mem_read; + 9: PORT_R_RD_DATA <= mem_read[8:0]; + 4: PORT_R_RD_DATA <= mem_read[subaddr_r[2]*4+:4]; + 2: PORT_R_RD_DATA <= mem_read[subaddr_r[2:1]*2+:2]; + 1: PORT_R_RD_DATA <= mem_read[subaddr_r]; + endcase +end + +wire [3:0] addr_w; +assign addr_w = PORT_W_ADDR[6:3]; +always @(negedge (PORT_W_CLK ^ PORT_W_CLK_POL)) begin + if (PORT_W_WR_EN[0]) + case (PORT_W_WIDTH) + 18, + 9: mem[addr_w] <= PORT_W_WR_DATA[8:0]; + 4: mem[addr_w][PORT_W_ADDR[2]*4+:4] <= PORT_W_WR_DATA; + 2: mem[addr_w][PORT_W_ADDR[2:1]*2+:2] <= PORT_W_WR_DATA; + 1: mem[addr_w][PORT_W_ADDR[2:0]] <= PORT_W_WR_DATA; + endcase + if (PORT_W_WR_EN[1]) + mem[addr_w + 1] <= PORT_W_WR_DATA[17:9]; +end + +endmodule diff --git a/tests/memlib/memlib_block_sp_full.txt b/tests/memlib/memlib_block_sp_full.txt new file mode 100644 index 000000000..000f91af3 --- /dev/null +++ b/tests/memlib/memlib_block_sp_full.txt @@ -0,0 +1,61 @@ +ram block \RAM_BLOCK_SP { + cost 2; + abits 4; + width 16; + byte 8; + port srsw "A" { + clock posedge; + clken; + rden; + + option "RDWR" "NO_CHANGE" { + rdwr no_change; + } + option "RDWR" "OLD" { + rdwr old; + } + option "RDWR" "NEW" { + rdwr new; + } + option "RDWR" "NEW_ONLY" { + rdwr new_only; + } + + ifdef USE_ARST { + option "RDARST" "ZERO" { + rdarst zero; + } + option "RDARST" "ANY" { + rdarst any; + } + } + + ifdef USE_SRST { + option "SRST_BLOCK" 0 { + option "SRST_GATE" 0 { + rdsrst zero ungated; + } + option "SRST_GATE" 1 { + rdsrst zero gated_clken; + } + option "SRST_GATE" 2 { + rdsrst zero gated_rden; + } + } + } + + ifdef USE_SRST_BLOCKING { + option "SRST_BLOCK" 1 { + option "SRST_GATE" 0 { + rdsrst zero ungated block_wr; + } + option "SRST_GATE" 1 { + rdsrst zero gated_clken block_wr; + } + option "SRST_GATE" 2 { + rdsrst zero gated_rden block_wr; + } + } + } + } +} diff --git a/tests/memlib/memlib_block_sp_full.v b/tests/memlib/memlib_block_sp_full.v new file mode 100644 index 000000000..8ba32b9ed --- /dev/null +++ b/tests/memlib/memlib_block_sp_full.v @@ -0,0 +1,82 @@ +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 = "ZERO"; +parameter OPTION_SRST_GATE = 0; +parameter OPTION_SRST_BLOCK = 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; + +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_RD_SRST && OPTION_SRST_BLOCK)) 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]; + end + 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_clock_sdp.txt b/tests/memlib/memlib_clock_sdp.txt new file mode 100644 index 000000000..00e911ef8 --- /dev/null +++ b/tests/memlib/memlib_clock_sdp.txt @@ -0,0 +1,76 @@ +ram block \RAM_CLOCK_SDP { + cost 64; + abits 10; + widths 1 2 4 8 16 per_port; + init any; + port sw "W" { + ifdef SHARED_CLK { + ifdef WCLK_ANY { + option "WCLK" "ANY" { + clock anyedge "CLK"; + } + } + ifdef WCLK_POS { + option "WCLK" "POS" { + clock posedge "CLK"; + } + } + ifdef WCLK_NEG { + option "WCLK" "NEG" { + clock negedge "CLK"; + } + } + } else { + ifdef WCLK_ANY { + option "WCLK" "ANY" { + clock anyedge; + } + } + ifdef WCLK_POS { + option "WCLK" "POS" { + clock posedge; + } + } + ifdef WCLK_NEG { + option "WCLK" "NEG" { + clock negedge; + } + } + } + } + port sr "R" { + ifdef SHARED_CLK { + ifdef RCLK_ANY { + option "RCLK" "ANY" { + clock anyedge "CLK"; + } + } + ifdef RCLK_POS { + option "RCLK" "POS" { + clock posedge "CLK"; + } + } + ifdef RCLK_NEG { + option "RCLK" "NEG" { + clock negedge "CLK"; + } + } + } else { + ifdef RCLK_ANY { + option "RCLK" "ANY" { + clock anyedge; + } + } + ifdef RCLK_POS { + option "RCLK" "POS" { + clock posedge; + } + } + ifdef RCLK_NEG { + option "RCLK" "NEG" { + clock negedge; + } + } + } + } +} diff --git a/tests/memlib/memlib_clock_sdp.v b/tests/memlib/memlib_clock_sdp.v new file mode 100644 index 000000000..e9036351e --- /dev/null +++ b/tests/memlib/memlib_clock_sdp.v @@ -0,0 +1,36 @@ +module RAM_CLOCK_SDP( + input CLK_CLK, + 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 CLK_CLK_POL = 0; +parameter PORT_R_CLK_POL = 0; +parameter PORT_W_CLK_POL = 0; +parameter OPTION_WCLK = "ANY"; +parameter OPTION_RCLK = "ANY"; + +reg [2**10-1:0] mem = INIT; + +wire RCLK; +case (OPTION_RCLK) +"ANY": assign RCLK = PORT_R_CLK == PORT_R_CLK_POL; +"POS": assign RCLK = PORT_R_CLK; +"NEG": assign RCLK = ~PORT_R_CLK; +endcase +always @(posedge RCLK) + PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH]; + +always @(negedge PORT_W_CLK ^ (PORT_W_CLK_POL || OPTION_WCLK == "POS")) + if (PORT_W_WR_EN) + mem[PORT_W_ADDR+:PORT_W_WIDTH] <= PORT_W_WR_DATA; + +endmodule diff --git a/tests/memlib/memlib_lut.txt b/tests/memlib/memlib_lut.txt index 0cc8fda15..9f6d84123 100644 --- a/tests/memlib/memlib_lut.txt +++ b/tests/memlib/memlib_lut.txt @@ -1,7 +1,23 @@ ram distributed \RAM_LUT { abits 4; width 4; - init any; + ifdef INIT_NONE { + option "INIT" "NONE" { + init none; + } + } else ifdef INIT_ZERO { + option "INIT" "ZERO" { + init zero; + } + } else ifdef INIT_NO_UNDEF { + option "INIT" "NO_UNDEF" { + init no_undef; + } + } else { + option "INIT" "ANY" { + init any; + } + } cost 4; port ar "R" { } diff --git a/tests/memlib/memlib_lut.v b/tests/memlib/memlib_lut.v index 1f20a110a..2685d2337 100644 --- a/tests/memlib/memlib_lut.v +++ b/tests/memlib/memlib_lut.v @@ -9,6 +9,7 @@ module RAM_LUT( ); parameter INIT = 0; +parameter OPTION_INIT = "UNDEFINED"; parameter PORT_RW_CLK_POL = 1; reg [3:0] mem [0:15]; @@ -16,7 +17,13 @@ reg [3:0] mem [0:15]; integer i; initial for (i = 0; i < 16; i += 1) - mem[i] = INIT[i*4+:4]; + case (OPTION_INIT) + "NONE": mem[i] = mem[i]; //? + "ZERO": mem[i] = 4'h0; + "ANY": mem[i] = INIT[i*4+:4]; + "NO_UNDEF": mem[i] = INIT[i*4+:4]; + "UNDEFINED": mem[i] = 4'hx; + endcase assign PORT_R_RD_DATA = mem[PORT_R_ADDR]; assign PORT_RW_RD_DATA = mem[PORT_RW_ADDR]; diff --git a/tests/memlib/memlib_multilut.txt b/tests/memlib/memlib_multilut.txt new file mode 100644 index 000000000..387f4f8e2 --- /dev/null +++ b/tests/memlib/memlib_multilut.txt @@ -0,0 +1,19 @@ +ram distributed \LUT_MULTI { + abits 4; + width 2; + init any; + port arsw "RW" { + clock posedge; + } + ifdef PORTS_QUAD { + option "PORTS" "QUAD" { + port ar "R0" "R1" "R2" { + } + } + } else ifdef PORTS_OCT { + option "PORTS" "OCT" { + port ar "R0" "R1" "R2" "R3" "R4" "R5" "R6" { + } + } + } +} diff --git a/tests/memlib/memlib_multilut.v b/tests/memlib/memlib_multilut.v new file mode 100644 index 000000000..a623d41fd --- /dev/null +++ b/tests/memlib/memlib_multilut.v @@ -0,0 +1,45 @@ +module LUT_MULTI( + input [3:0] PORT_R0_ADDR, + input [3:0] PORT_R1_ADDR, + input [3:0] PORT_R2_ADDR, + input [3:0] PORT_R3_ADDR, + input [3:0] PORT_R4_ADDR, + input [3:0] PORT_R5_ADDR, + input [3:0] PORT_R6_ADDR, + input [3:0] PORT_RW_ADDR, + input PORT_RW_CLK, + input PORT_RW_WR_EN, + input [1:0] PORT_RW_WR_DATA, + output [1:0] PORT_R0_RD_DATA, + output [1:0] PORT_R1_RD_DATA, + output [1:0] PORT_R2_RD_DATA, + output [1:0] PORT_R3_RD_DATA, + output [1:0] PORT_R4_RD_DATA, + output [1:0] PORT_R5_RD_DATA, + output [1:0] PORT_R6_RD_DATA, + output [1:0] PORT_RW_RD_DATA +); + +parameter INIT = 0; +parameter OPTION_PORTS = "UNDEFINED"; + +reg [1:0] mem [0:15]; +integer i; +initial + for (i = 0; i < 16; i += 1) + mem[i] = INIT[i*4+:4]; + +assign PORT_R0_RD_DATA = mem[PORT_R0_ADDR]; +assign PORT_R1_RD_DATA = mem[PORT_R1_ADDR]; +assign PORT_R2_RD_DATA = mem[PORT_R2_ADDR]; +assign PORT_R3_RD_DATA = mem[PORT_R3_ADDR]; +assign PORT_R4_RD_DATA = mem[PORT_R4_ADDR]; +assign PORT_R5_RD_DATA = mem[PORT_R5_ADDR]; +assign PORT_R6_RD_DATA = mem[PORT_R6_ADDR]; +assign PORT_RW_RD_DATA = mem[PORT_RW_ADDR]; + +always @(posedge PORT_RW_CLK) + if (PORT_RW_WR_EN) + mem[PORT_RW_ADDR] <= PORT_RW_WR_DATA; + +endmodule diff --git a/tests/memlib/memlib_wren.txt b/tests/memlib/memlib_wren.txt new file mode 100644 index 000000000..31ff3ff60 --- /dev/null +++ b/tests/memlib/memlib_wren.txt @@ -0,0 +1,37 @@ +ram block \RAM_WREN { + abits 4; + init none; + + ifdef NO_BYTE { + # single enable signal + widths 4 8 global; + } else ifdef W4_B4 { + widths 4 global; + byte 4; + } else ifdef W8_B4 { + widths 8 global; + option "BYTESIZE" 4 { + byte 4; + } + } else ifdef W8_B8 { + width 8; + byte 8; + } else ifdef W16_B4 { + widths 16 global; + option "BYTESIZE" 4 { + byte 4; + } + } else ifdef W64_B8 { + widths 64 global; + option "BYTESIZE" 8 { + byte 8; + } + } + + port srsw "A" { + clock posedge; + ifdef WRBE_SEPARATE { + wrbe_separate; + } + } +} diff --git a/tests/memlib/memlib_wren.v b/tests/memlib/memlib_wren.v new file mode 100644 index 000000000..b9433d42e --- /dev/null +++ b/tests/memlib/memlib_wren.v @@ -0,0 +1,33 @@ +module RAM_WREN ( + input PORT_A_CLK, + input [ABITS-1:0] PORT_A_ADDR, + input [WIDTH-1:0] PORT_A_WR_DATA, + output reg [WIDTH-1:0] PORT_A_RD_DATA, + input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN, + input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE +); + +parameter ABITS=4; +parameter WIDTH=8; +parameter PORT_A_WR_EN_WIDTH=1; +parameter PORT_A_WR_BE_WIDTH=0; +parameter OPTION_BYTESIZE=WIDTH; +parameter WB=OPTION_BYTESIZE; + +reg [WIDTH-1:0] mem [0:2**ABITS-1]; + +integer i; +always @(posedge PORT_A_CLK) begin + for (i=0; i<PORT_A_WR_EN_WIDTH; i=i+1) // use PORT_A_WR_EN + if (!PORT_A_WR_BE_WIDTH && PORT_A_WR_EN[i]) + mem[PORT_A_ADDR][i*WB+:WB] <= PORT_A_WR_DATA[i*WB+:WB]; + for (i=0; i<PORT_A_WR_BE_WIDTH; i=i+1) // use PORT_A_WR_BE + if (PORT_A_WR_EN[0] && PORT_A_WR_BE[i]) + mem[PORT_A_ADDR][i*WB+:WB] <= PORT_A_WR_DATA[i*WB+:WB]; +end + +always @(posedge PORT_A_CLK) + if (!PORT_A_WR_EN[0]) + PORT_A_RD_DATA <= mem[PORT_A_ADDR]; + +endmodule |