diff --git a/tests/arch/quicklogic/qlf_k6n10f/gen_memories.py b/tests/arch/quicklogic/qlf_k6n10f/gen_memories.py index 353843b78..ea750b8ed 100644 --- a/tests/arch/quicklogic/qlf_k6n10f/gen_memories.py +++ b/tests/arch/quicklogic/qlf_k6n10f/gen_memories.py @@ -1,3 +1,8 @@ +from __future__ import annotations + +from dataclasses import dataclass + + blockram_template = """# ====================================== design -reset; read_verilog -defer ../../common/blockram.v chparam{param_str} {top} @@ -97,23 +102,152 @@ blockram_tests: "list[tuple[list[tuple[str, int]], str, list[str]]]" = [ "-assert-count 1 t:TDP36K"]), ] -with open("t_mem.ys", mode="w") as f: - for (params, top, assertions) in blockram_tests: - param_str = "" - for (key, val) in params: - param_str += f" -set {key} {val}" - dp_subs = [""] - if "*dp" in top: - dp_subs = ["sdp", "tdp"] - wr_subs = [""] - if "w*r" in top: - wr_subs = ["wwr", "wrr"] - for db_sub in dp_subs: - for wr_sub in wr_subs: - print( - blockram_template.format(param_str=param_str, top=top.replace("*dp", db_sub).replace("w*r", wr_sub)), - file=f - ) - for assertion in assertions: - print("select {}".format(assertion), file=f) - print("", file=f) +sim_template = """\ +cd +read_verilog +/quicklogic/qlf_k6n10f/brams_sim.v +/quicklogic/qlf_k6n10f/sram1024x18_mem.v +/quicklogic/qlf_k6n10f/ufifo_ctl.v +/quicklogic/qlf_k6n10f/TDP18K_FIFO.v +read_verilog <<EOF +`define MEM_TEST_VECTOR {mem_test_vector} + +`define UUT_SUBMODULE \\ +{uut_submodule} +EOF +read_verilog -defer -formal mem_tb.v +chparam{param_str} -set VECTORLEN {vectorlen} TB +hierarchy -top TB -check +proc +sim -clock clk -n {vectorlen} -assert +""" + +sync_ram_sdp_submodule = """\ +sync_ram_sdp #(\\ + .ADDRESS_WIDTH(ADDRESS_WIDTH),\\ + .DATA_WIDTH(DATA_WIDTH)\\ +) uut (\\ + .clk(clk),\\ + .address_in_r(ra_a),\\ + .data_out(rq_a),\\ + .write_enable(wce_a),\\ + .address_in_w(wa_a),\\ + .data_in(wd_a)\\ +);\ +""" + +@dataclass +class TestClass: + params: dict[str, int] + top: str + assertions: list[str] + test_steps: None | list[dict[str, int]] + +test_val_map = { + "rce_a": "rce_a_testvector", + "ra_a": "ra_a_testvector", + "rq_a": "rq_a_expected", + "wce_a": "wce_a_testvector", + "wa_a": "wa_a_testvector", + "wd_a": "wd_a_testvector", + "rce_b": "rce_b_testvector", + "ra_b": "ra_b_testvector", + "rq_b": "rq_b_expected", + "wce_b": "wce_b_testvector", + "wa_b": "wa_b_testvector", + "wd_b": "wd_b_testvector", +} + +sim_tests: list[TestClass] = [ + TestClass( + params={"ADDRESS_WIDTH": 10, "DATA_WIDTH": 36}, + top="sync_ram_sdp", + assertions=["-assert-count 1 t:TDP36K"], + test_steps=[ + {"wce_a": 1, "wa_a": 0x0A, "wd_a": 0xdeadbeef}, + {"wce_a": 1, "wa_a": 0xBA, "wd_a": 0x5a5a5a5a}, + {"wce_a": 1, "wa_a": 0xFF, "wd_a": 0}, + {"rce_a": 1, "ra_a": 0xA}, + {"rq_a": 0xdeadbeef}, + {"rce_a": 1, "ra_a": 0xFF}, + {"rq_a": 0}, + ] + ), +] + +for (params, top, assertions) in blockram_tests: + sim_test = TestClass( + params=dict(params), + top=top, + assertions=assertions, + test_steps=None + ) + sim_tests.append(sim_test) + +i = 0 +j = 0 +max_j = 16 +f = None +for sim_test in sim_tests: + # format params + param_str = "" + for (key, val) in sim_test.params.items(): + param_str += f" -set {key} {val}" + + # resolve top module wildcards + top_list = [sim_test.top] + if "*dp" in sim_test.top: + top_list += [ + sim_test.top.replace("*dp", dp_sub) for dp_sub in ["sdp", "tdp"] + ] + if "w*r" in sim_test.top: + top_list += [ + sim_test.top.replace("w*r", wr_sub) for wr_sub in ["wwr", "wrr"] + ] + if len(top_list) > 1: + top_list.pop(0) + + # iterate over string substitutions + for top in top_list: + # limit number of tests per file to allow parallel make + if not f: + fn = f"t_mem{i}.ys" + f = open(fn, mode="w") + j = 0 + + # output yosys script test file + print( + blockram_template.format(param_str=param_str, top=top), + file=f + ) + for assertion in sim_test.assertions: + print("select {}".format(assertion), file=f) + print("", file=f) + + # prepare simulation tests + test_steps = sim_test.test_steps + if test_steps: + if top == "sync_ram_sdp": + uut_submodule = sync_ram_sdp_submodule + else: + raise NotImplementedError(f"missing submodule header for {top}") + mem_test_vector = "" + for step, test in enumerate(test_steps): + for key, val in test.items(): + key = test_val_map[key] + mem_test_vector += f"\\\n{key}[{step}] = 'h{val:x};" + print( + sim_template.format( + mem_test_vector=mem_test_vector, + uut_submodule=uut_submodule, + param_str=param_str, + vectorlen=len(test_steps) + 2 + ), file=f + ) + # simulation counts for 2 tests + j += 1 + + # increment test counter + j += 1 + if j >= max_j: + f = f.close() + i += 1 + +if f: + f.close() diff --git a/tests/arch/quicklogic/qlf_k6n10f/mem_tb.v b/tests/arch/quicklogic/qlf_k6n10f/mem_tb.v new file mode 100644 index 000000000..93ba2a31a --- /dev/null +++ b/tests/arch/quicklogic/qlf_k6n10f/mem_tb.v @@ -0,0 +1,73 @@ +module TB(input clk); + +parameter ADDRESS_WIDTH = 10; +parameter DATA_WIDTH = 36; +parameter VECTORLEN = 16; + +reg rce_a_testvector [VECTORLEN-1:0]; +reg [ADDRESS_WIDTH-1:0] ra_a_testvector [VECTORLEN-1:0]; +reg [DATA_WIDTH-1:0] rq_a_expected [VECTORLEN-1:0]; + +reg wce_a_testvector [VECTORLEN-1:0]; +reg [ADDRESS_WIDTH-1:0] wa_a_testvector [VECTORLEN-1:0]; +reg [DATA_WIDTH-1:0] wd_a_testvector [VECTORLEN-1:0]; + +reg rce_b_testvector [VECTORLEN-1:0]; +reg [ADDRESS_WIDTH-1:0] ra_b_testvector [VECTORLEN-1:0]; +reg [DATA_WIDTH-1:0] rq_b_expected [VECTORLEN-1:0]; + +reg wce_b_testvector [VECTORLEN-1:0]; +reg [ADDRESS_WIDTH-1:0] wa_b_testvector [VECTORLEN-1:0]; +reg [DATA_WIDTH-1:0] wd_b_testvector [VECTORLEN-1:0]; + +reg [$clog2(VECTORLEN)-1:0] i = 0; + +integer j; +initial begin + for (j = 0; j < VECTORLEN; j = j + 1) begin + rce_a_testvector[j] = 1'b0; + ra_a_testvector[j] = 10'h0; + wce_a_testvector[j] = 1'b0; + wa_a_testvector[j] = 10'h0; + rce_b_testvector[j] = 1'b0; + ra_b_testvector[j] = 10'h0; + wce_b_testvector[j] = 1'b0; + wa_b_testvector[j] = 10'h0; + + end + + `MEM_TEST_VECTOR + +end + + +wire rce_a = rce_a_testvector[i]; +wire [ADDRESS_WIDTH-1:0] ra_a = ra_a_testvector[i]; +wire [DATA_WIDTH-1:0] rq_a; + +wire wce_a = wce_a_testvector[i]; +wire [ADDRESS_WIDTH-1:0] wa_a = wa_a_testvector[i]; +wire [DATA_WIDTH-1:0] wd_a = wd_a_testvector[i]; + +wire rce_b = rce_b_testvector[i]; +wire [ADDRESS_WIDTH-1:0] ra_b = ra_b_testvector[i]; +wire [DATA_WIDTH-1:0] rq_b; + +wire wce_b = wce_b_testvector[i]; +wire [ADDRESS_WIDTH-1:0] wa_b = wa_b_testvector[i]; +wire [DATA_WIDTH-1:0] wd_b = wd_b_testvector[i]; + +`UUT_SUBMODULE + +always @(posedge clk) begin + if (i < VECTORLEN-1) begin + if (i > 0) begin + if($past(rce_a)) + assert(rq_a == rq_a_expected[i]); + if($past(rce_b)) + assert(rq_b == rq_b_expected[i]); + end + i <= i + 1; + end +end +endmodule