diff options
49 files changed, 2050 insertions, 66 deletions
@@ -2,9 +2,23 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.26 .. Yosys 0.26-dev +Yosys 0.27 .. Yosys 0.27-dev -------------------------- +Yosys 0.26 .. Yosys 0.27 +-------------------------- + * New commands and options + - Added option "-make_assert" to "equiv_make" pass. + - Added option "-coverenable" to "chformal" pass. + + * Verilog + - Resolve package types in interfaces. + - Handle range offsets in packed arrays within packed structs. + - Support for data and array queries on struct/union item expressions. + + * GateMate support + - Enable register initialization. + Yosys 0.25 .. Yosys 0.26 -------------------------- * New commands and options @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.26+39 +YOSYS_VER := 0.27+3 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -149,7 +149,7 @@ YOSYS_VER := 0.26+39 # back to calling git directly. TARBALL_GIT_REV := $(shell cat $(YOSYS_SRC)/.gitcommit) ifeq ($(TARBALL_GIT_REV),$$Format:%h$$) -GIT_REV := $(shell git ls-remote $(YOSYS_SRC) HEAD -q | $(AWK) 'BEGIN {R = "UNKNOWN"}; ($$2 == "HEAD") {R = substr($$1, 1, 9); exit} END {print R}') +GIT_REV := $(shell GIT_DIR=$(YOSYS_SRC)/.git git rev-parse --short=9 HEAD || echo UNKNOWN) else GIT_REV := $(TARBALL_GIT_REV) endif @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 7e58866.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 5f88c21.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # @@ -165,7 +165,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = a8f0ef2 +ABCREV = 2c1c83f ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -837,6 +837,9 @@ ABCOPT="" endif test: $(TARGETS) $(EXTRA_TARGETS) +ifeq ($(ENABLE_VERIFIC),1) + +cd tests/verific && bash run-test.sh $(SEEDOPT) +endif +cd tests/simple && bash run-test.sh $(SEEDOPT) +cd tests/simple_abc9 && bash run-test.sh $(SEEDOPT) +cd tests/hana && bash run-test.sh $(SEEDOPT) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index cb21eb3aa..6b81740a2 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -59,9 +59,12 @@ detect_loops = False so = SmtOpts() -def usage(): +def help(): print(os.path.basename(sys.argv[0]) + """ [options] <yosys_smt2_output> + -h, --help + show this message + -t <num_steps> -t <skip_steps>:<num_steps> -t <skip_steps>:<step_size>:<num_steps> @@ -181,19 +184,25 @@ def usage(): (this feature is experimental and incomplete) """ + so.helpmsg()) + +def usage(): + help() sys.exit(1) try: - opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts + - ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "yw=", "btorwit=", "presat", + opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:higcm:", so.longopts + + ["help", "final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "yw=", "btorwit=", "presat", "dump-vcd=", "dump-yw=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=", "smtc-init", "smtc-top=", "noinit", "binary", "keep-going", "check-witness", "detect-loops"]) except: usage() for o, a in opts: - if o == "-t": + if o in ("-h", "--help"): + help() + sys.exit(0) + elif o == "-t": got_topt = True a = a.split(":") if len(a) == 1: diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index c1e9fc7d0..ab3e55427 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1043,21 +1043,49 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr sw->signal = sig_select; current_case->switches.push_back(sw); - int select_width = inst->InputSize(); - int data_width = inst->OutputSize(); - int select_num = inst->Input1Size() / inst->InputSize(); - - int offset_select = 0; - int offset_data = 0; - - for (int i = 0; i < select_num; i++) { - RTLIL::CaseRule *cs = new RTLIL::CaseRule; - cs->compare.push_back(sig_select_values.extract(offset_select, select_width)); - cs->actions.push_back(SigSig(sig_out_val, sig_data_values.extract(offset_data, data_width))); - sw->cases.push_back(cs); - - offset_select += select_width; + unsigned select_width = inst->InputSize(); + unsigned data_width = inst->OutputSize(); + unsigned offset_data = 0; + unsigned offset_select = 0; + + OperWideCaseSelector* selector = (OperWideCaseSelector*) inst->View(); + + for (unsigned i = 0 ; i < selector->GetNumBranches() ; ++i) { + + SigSig action(sig_out_val, sig_data_values.extract(offset_data, data_width)); offset_data += data_width; + + for (unsigned j = 0 ; j < selector->GetNumConditions(i) ; ++j) { + Array left_bound, right_bound ; + selector->GetCondition(i, j, &left_bound, &right_bound); + + SigSpec sel_left = sig_select_values.extract(offset_select, select_width); + offset_select += select_width; + + if (right_bound.Size()) { + SigSpec sel_right = sig_select_values.extract(offset_select, select_width); + offset_select += select_width; + + log_assert(sel_right.is_fully_const() && sel_right.is_fully_def()); + log_assert(sel_left.is_fully_const() && sel_right.is_fully_def()); + + int32_t left = sel_left.as_int(); + int32_t right = sel_right.as_int(); + int width = sel_left.size(); + + for (int32_t i = right; i<left; i++) { + RTLIL::CaseRule *cs = new RTLIL::CaseRule; + cs->compare.push_back(RTLIL::Const(i,width)); + cs->actions.push_back(action); + sw->cases.push_back(cs); + } + } + + RTLIL::CaseRule *cs = new RTLIL::CaseRule; + cs->compare.push_back(sel_left); + cs->actions.push_back(action); + sw->cases.push_back(cs); + } } RTLIL::CaseRule *cs_default = new RTLIL::CaseRule; cs_default->actions.push_back(SigSig(sig_out_val, sig_data_default)); diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 522957f39..f0021cf87 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -316,7 +316,7 @@ statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTL if (mod_stat.count(it.first) > 0) { if (!quiet) log(" %*s%-*s %6u\n", 2*level, "", 26-2*level, log_id(it.first), it.second); - mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second; + mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1, quiet) * it.second; mod_data.num_cells -= it.second; } else { mod_data.num_cells_by_type[it.first] += it.second; diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index a90d81985..2656f30ce 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -179,7 +179,7 @@ struct MuxcoverWorker int prepare_decode_mux(SigBit &A, SigBit B, SigBit sel, SigBit bit) { - if (A == B || sel == State::Sx) + if (A == B || A == State::Sx || B == State::Sx || sel == State::Sx) return 0; tuple<SigBit, SigBit, SigBit> key(A, B, sel); @@ -197,9 +197,6 @@ struct MuxcoverWorker if (std::get<2>(entry)) return 0; - if (A == State::Sx || B == State::Sx) - return 0; - return cost_dmux / GetSize(std::get<1>(entry)); } diff --git a/techlibs/fabulous/Makefile.inc b/techlibs/fabulous/Makefile.inc index 44d57542b..28b0d5ef0 100644 --- a/techlibs/fabulous/Makefile.inc +++ b/techlibs/fabulous/Makefile.inc @@ -8,3 +8,4 @@ $(eval $(call add_share_file,share/fabulous,techlibs/fabulous/ff_map.v)) $(eval $(call add_share_file,share/fabulous,techlibs/fabulous/ram_regfile.txt)) $(eval $(call add_share_file,share/fabulous,techlibs/fabulous/regfile_map.v)) $(eval $(call add_share_file,share/fabulous,techlibs/fabulous/io_map.v)) +$(eval $(call add_share_file,share/fabulous,techlibs/fabulous/arith_map.v)) diff --git a/techlibs/fabulous/arith_map.v b/techlibs/fabulous/arith_map.v new file mode 100644 index 000000000..eca968556 --- /dev/null +++ b/techlibs/fabulous/arith_map.v @@ -0,0 +1,65 @@ +`default_nettype none + +`ifdef ARITH_ha +(* techmap_celltype = "$alu" *) +module _80_fabulous_ha_alu (A, B, CI, BI, X, Y, CO); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 1; +parameter B_WIDTH = 1; +parameter Y_WIDTH = 1; + +parameter _TECHMAP_CONSTMSK_CI_ = 0; +parameter _TECHMAP_CONSTVAL_CI_ = 0; + +(* force_downto *) +input [A_WIDTH-1:0] A; +(* force_downto *) +input [B_WIDTH-1:0] B; +input CI, BI; +(* force_downto *) +output [Y_WIDTH-1:0] X, Y, CO; + +(* force_downto *) +wire [Y_WIDTH-1:0] A_buf, B_buf; +\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); +\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + +(* force_downto *) +wire [Y_WIDTH-1:0] AA = A_buf; +(* force_downto *) +wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; +wire [Y_WIDTH:0] CARRY; + + +LUT4_HA #( + .INIT(16'b0), + .I0MUX(1'b1) +) carry_statrt ( + .I0(), .I1(CI), .I2(CI), .I3(), + .Ci(), + .Co(CARRY[0]) +); + +// Carry chain +genvar i; +generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice + LUT4_HA #( + .INIT(16'b1001_0110_1001_0110), // full adder sum over (I2, I1, I0) + .I0MUX(1'b1) + ) lut_i ( + .I0(), .I1(AA[i]), .I2(BB[i]), .I3(), + .Ci(CARRY[i]), + .O(Y[i]), + .Co(CARRY[i+1]) + ); + + assign CO[i] = (AA[i] && BB[i]) || ((Y[i] ^ AA[i] ^ BB[i]) && (AA[i] || BB[i])); +end endgenerate + +assign X = AA ^ BB; + +endmodule +`endif + diff --git a/techlibs/fabulous/prims.v b/techlibs/fabulous/prims.v index bd0af906a..fe3e8536a 100644 --- a/techlibs/fabulous/prims.v +++ b/techlibs/fabulous/prims.v @@ -24,6 +24,20 @@ module LUT4(output O, input I0, I1, I2, I3); assign O = I0 ? s1[1] : s1[0]; endmodule +module LUT4_HA(output O, Co, input I0, I1, I2, I3, Ci); + parameter [15:0] INIT = 0; + parameter I0MUX = 1'b1; + + wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0]; + wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; + wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + + wire I0_sel = I0MUX ? Ci : I0; + assign O = I0_sel ? s1[1] : s1[0]; + + assign Co = (Ci & I1) | (Ci & I2) | (I1 & I2); +endmodule + module LUTFF(input CLK, D, output reg O); initial O = 1'b0; always @ (posedge CLK) begin diff --git a/techlibs/fabulous/synth_fabulous.cc b/techlibs/fabulous/synth_fabulous.cc index d7c45e094..b4a7ab2dc 100644 --- a/techlibs/fabulous/synth_fabulous.cc +++ b/techlibs/fabulous/synth_fabulous.cc @@ -83,6 +83,9 @@ struct SynthPass : public ScriptPass log(" do not run 'alumacc' pass. i.e. keep arithmetic operators in\n"); log(" their direct form ($add, $sub, etc.).\n"); log("\n"); + log(" -carry <none|ha>\n"); + log(" carry mapping style (none, half-adders, ...) default=none\n"); + log("\n"); log(" -noregfile\n"); log(" do not map register files\n"); log("\n"); @@ -119,7 +122,7 @@ struct SynthPass : public ScriptPass log("\n"); } - string top_module, json_file, blif_file, plib, fsm_opts, memory_opts; + string top_module, json_file, blif_file, plib, fsm_opts, memory_opts, carry_mode; std::vector<string> extra_plib, extra_map; bool autotop, forvpr, noalumacc, nofsm, noshare, noregfile, iopad, complexdff, flatten; @@ -137,6 +140,7 @@ struct SynthPass : public ScriptPass noshare = false; iopad = false; complexdff = false; + carry_mode = "none"; flatten = true; json_file = ""; blif_file = ""; @@ -229,6 +233,12 @@ struct SynthPass : public ScriptPass complexdff = true; continue; } + if (args[argidx] == "-carry") { + carry_mode = args[++argidx]; + if (carry_mode != "none" && carry_mode != "ha") + log_cmd_error("Unsupported carry style: %s\n", carry_mode.c_str()); + continue; + } if (args[argidx] == "-noflatten") { flatten = false; continue; @@ -326,7 +336,8 @@ struct SynthPass : public ScriptPass if (check_label("map_gates")) { run("opt -full"); - run("techmap -map +/techmap.v"); + run(stringf("techmap -map +/techmap.v -map +/fabulous/arith_map.v -D ARITH_%s", + help_mode ? "<carry>" : carry_mode.c_str())); run("opt -fast"); } diff --git a/techlibs/gatemate/cells_sim.v b/techlibs/gatemate/cells_sim.v index 7ed6d83ff..12e01d2df 100644 --- a/techlibs/gatemate/cells_sim.v +++ b/techlibs/gatemate/cells_sim.v @@ -242,7 +242,8 @@ module CC_DFF #( parameter [0:0] CLK_INV = 1'b0,
parameter [0:0] EN_INV = 1'b0,
parameter [0:0] SR_INV = 1'b0,
- parameter [0:0] SR_VAL = 1'b0
+ parameter [0:0] SR_VAL = 1'b0,
+ parameter [0:0] INIT = 1'bx
)(
input D,
(* clkbuf_sink *)
@@ -256,7 +257,7 @@ module CC_DFF #( assign en = (EN_INV) ? ~EN : EN;
assign sr = (SR_INV) ? ~SR : SR;
- initial Q = 1'bX;
+ initial Q = INIT;
always @(posedge clk or posedge sr)
begin
@@ -272,9 +273,10 @@ endmodule module CC_DLT #(
- parameter [0:0] G_INV = 1'b0,
+ parameter [0:0] G_INV = 1'b0,
parameter [0:0] SR_INV = 1'b0,
- parameter [0:0] SR_VAL = 1'b0
+ parameter [0:0] SR_VAL = 1'b0,
+ parameter [0:0] INIT = 1'bx
)(
input D,
input G,
@@ -285,7 +287,7 @@ module CC_DLT #( assign en = (G_INV) ? ~G : G;
assign sr = (SR_INV) ? ~SR : SR;
- initial Q = 1'bX;
+ initial Q = INIT;
always @(*)
begin
diff --git a/techlibs/gatemate/reg_map.v b/techlibs/gatemate/reg_map.v index 6a2c7fb91..6ec170a9d 100644 --- a/techlibs/gatemate/reg_map.v +++ b/techlibs/gatemate/reg_map.v @@ -21,25 +21,31 @@ module \$_DFFE_xxxx_ (input D, C, R, E, output Q);
parameter _TECHMAP_CELLTYPE_ = "";
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
CC_DFF #(
.CLK_INV(_TECHMAP_CELLTYPE_[39:32] == "N"),
.EN_INV(_TECHMAP_CELLTYPE_[15:8] == "N"),
.SR_INV(_TECHMAP_CELLTYPE_[31:24] == "N"),
- .SR_VAL(_TECHMAP_CELLTYPE_[23:16] == "1")
+ .SR_VAL(_TECHMAP_CELLTYPE_[23:16] == "1"),
+ .INIT(_TECHMAP_WIREINIT_Q_)
) _TECHMAP_REPLACE_ (.D(D), .EN(E), .CLK(C), .SR(R), .Q(Q));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
(* techmap_celltype = "$_DLATCH_[NP][NP][01]_" *)
module \$_DLATCH_xxx_ (input E, R, D, output Q);
parameter _TECHMAP_CELLTYPE_ = "";
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
CC_DLT #(
.G_INV(_TECHMAP_CELLTYPE_[31:24] == "N"),
.SR_INV(_TECHMAP_CELLTYPE_[23:16] == "N"),
- .SR_VAL(_TECHMAP_CELLTYPE_[15:8] == "1")
+ .SR_VAL(_TECHMAP_CELLTYPE_[15:8] == "1"),
+ .INIT(_TECHMAP_WIREINIT_Q_)
) _TECHMAP_REPLACE_ (.D(D), .G(E), .SR(R), .Q(Q));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
diff --git a/techlibs/gatemate/synth_gatemate.cc b/techlibs/gatemate/synth_gatemate.cc index dd4fde643..1d46d7929 100644 --- a/techlibs/gatemate/synth_gatemate.cc +++ b/techlibs/gatemate/synth_gatemate.cc @@ -283,7 +283,7 @@ struct SynthGateMatePass : public ScriptPass if (check_label("map_regs"))
{
run("opt_clean");
- run("dfflegalize -cell $_DFFE_????_ x -cell $_DLATCH_???_ x");
+ run("dfflegalize -cell $_DFFE_????_ 01 -cell $_DLATCH_???_ 01");
run("techmap -map +/gatemate/reg_map.v");
run("opt_expr -mux_undef");
run("simplemap");
diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index ab8207ef1..535fd05ed 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -582,6 +582,14 @@ module IOBUF (O, IO, I, OEN); assign I = IO; endmodule +module ELVDS_OBUF (I, O, OB); + input I; + output O; + output OB; + assign O = I; + assign OB = ~I; +endmodule + module TLVDS_OBUF (I, O, OB); input I; output O; @@ -1632,3 +1640,20 @@ output OSCOUT; parameter FREQ_DIV = 96; endmodule + +(* blackbox *) +module OSCW(OSCOUT); +output OSCOUT; + +parameter FREQ_DIV = 80; +endmodule + +(* blackbox *) +module OSCO(OSCOUT, OSCEN); +input OSCEN; + +output OSCOUT; + +parameter FREQ_DIV = 100; +parameter REGULATOR_EN = 1'b0; +endmodule diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 52e8e2e3a..8943815bf 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -1674,7 +1674,7 @@ module SB_RAM40_4K ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L400 $setup(WE, posedge WCLK, 133); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 - (posedge RCLK => (RDATA : 16'bx)) = 2146; + (posedge RCLK *> (RDATA : 16'bx)) = 2146; endspecify `endif `ifdef ICE40_LP @@ -1696,7 +1696,7 @@ module SB_RAM40_4K ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L400 $setup(WE, posedge WCLK, 196); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 - (posedge RCLK => (RDATA : 16'bx)) = 3163; + (posedge RCLK *> (RDATA : 16'bx)) = 3163; endspecify `endif `ifdef ICE40_U @@ -1718,7 +1718,7 @@ module SB_RAM40_4K ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13025 $setup(WE, posedge WCLK, 252); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 - (posedge RCLK => (RDATA : 16'bx)) = 1179; + (posedge RCLK *> (RDATA : 16'bx)) = 1179; endspecify `endif endmodule @@ -1810,7 +1810,7 @@ module SB_RAM40_4KNR ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L400 $setup(WE, posedge WCLK, 133); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 - (posedge RCLKN => (RDATA : 16'bx)) = 2146; + (posedge RCLKN *> (RDATA : 16'bx)) = 2146; endspecify `endif `ifdef ICE40_LP @@ -1832,7 +1832,7 @@ module SB_RAM40_4KNR ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L400 $setup(WE, posedge WCLK, 196); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 - (posedge RCLKN => (RDATA : 16'bx)) = 3163; + (posedge RCLKN *> (RDATA : 16'bx)) = 3163; endspecify `endif `ifdef ICE40_U @@ -1854,7 +1854,7 @@ module SB_RAM40_4KNR ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13025 $setup(WE, posedge WCLK, 252); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 - (posedge RCLKN => (RDATA : 16'bx)) = 1179; + (posedge RCLKN *> (RDATA : 16'bx)) = 1179; endspecify `endif endmodule @@ -1946,7 +1946,7 @@ module SB_RAM40_4KNW ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L400 $setup(WE, posedge WCLKN, 133); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 - (posedge RCLK => (RDATA : 16'bx)) = 2146; + (posedge RCLK *> (RDATA : 16'bx)) = 2146; endspecify `endif `ifdef ICE40_LP @@ -1968,7 +1968,7 @@ module SB_RAM40_4KNW ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L400 $setup(WE, posedge WCLKN, 196); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 - (posedge RCLK => (RDATA : 16'bx)) = 3163; + (posedge RCLK *> (RDATA : 16'bx)) = 3163; endspecify `endif `ifdef ICE40_U @@ -1990,7 +1990,7 @@ module SB_RAM40_4KNW ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13025 $setup(WE, posedge WCLKN, 252); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 - (posedge RCLK => (RDATA : 16'bx)) = 1179; + (posedge RCLK *> (RDATA : 16'bx)) = 1179; endspecify `endif endmodule @@ -2082,7 +2082,7 @@ module SB_RAM40_4KNRNW ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L400 $setup(WE, posedge WCLKN, 133); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 - (posedge RCLKN => (RDATA : 16'bx)) = 2146; + (posedge RCLKN *> (RDATA : 16'bx)) = 2146; endspecify `endif `ifdef ICE40_LP @@ -2104,7 +2104,7 @@ module SB_RAM40_4KNRNW ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L400 $setup(WE, posedge WCLKN, 196); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 - (posedge RCLKN => (RDATA : 16'bx)) = 3163; + (posedge RCLKN *> (RDATA : 16'bx)) = 3163; endspecify `endif `ifdef ICE40_U @@ -2126,7 +2126,7 @@ module SB_RAM40_4KNRNW ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13025 $setup(WE, posedge WCLKN, 252); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 - (posedge RCLKN => (RDATA : 16'bx)) = 1179; + (posedge RCLKN *> (RDATA : 16'bx)) = 1179; endspecify `endif endmodule @@ -2653,9 +2653,9 @@ module SB_SPRAM256KA ( // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13206 $setup(WREN, posedge CLOCK, 289); // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13207-L13222 - (posedge CLOCK => (DATAOUT : 16'bx)) = 1821; + (posedge CLOCK *> (DATAOUT : 16'bx)) = 1821; // https://github.com/YosysHQ/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13223-L13238 - (posedge SLEEP => (DATAOUT : 16'b0)) = 1099; + (posedge SLEEP *> (DATAOUT : 16'b0)) = 1099; endspecify `endif endmodule diff --git a/tests/arch/common/blockram.v b/tests/arch/common/blockram.v index 5ed0736d0..c06ac96d5 100644 --- a/tests/arch/common/blockram.v +++ b/tests/arch/common/blockram.v @@ -22,7 +22,6 @@ module sync_ram_sp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10) endmodule // sync_ram_sp -`default_nettype none module sync_ram_sdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10) (input wire clk, write_enable, input wire [DATA_WIDTH-1:0] data_in, @@ -45,3 +44,33 @@ module sync_ram_sdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10) endmodule // sync_ram_sdp + +module sync_ram_tdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10) + (input wire clk_a, clk_b, + input wire write_enable_a, write_enable_b, + input wire read_enable_a, read_enable_b, + input wire [DATA_WIDTH-1:0] write_data_a, write_data_b, + input wire [ADDRESS_WIDTH-1:0] addr_a, addr_b, + output reg [DATA_WIDTH-1:0] read_data_a, read_data_b); + + localparam WORD = (DATA_WIDTH-1); + localparam DEPTH = (2**ADDRESS_WIDTH-1); + + reg [WORD:0] mem [0:DEPTH]; + + always @(posedge clk_a) begin + if (write_enable_a) + mem[addr_a] <= write_data_a; + else + read_data_a <= mem[addr_a]; + end + + always @(posedge clk_b) begin + if (write_enable_b) + mem[addr_b] <= write_data_b; + else + read_data_b <= mem[addr_b]; + end + +endmodule // sync_ram_tdp + diff --git a/tests/arch/ecp5/bug1836.mem b/tests/arch/ecp5/bug1836.mem new file mode 100644 index 000000000..1e904d87c --- /dev/null +++ b/tests/arch/ecp5/bug1836.mem @@ -0,0 +1,32 @@ +0x8000,0x8324,0x8647,0x896a,0x8c8b,0x8fab,0x92c7,0x95e1,
+0x98f8,0x9c0b,0x9f19,0xa223,0xa527,0xa826,0xab1f,0xae10,
+0xb0fb,0xb3de,0xb6b9,0xb98c,0xbc56,0xbf17,0xc1cd,0xc47a,
+0xc71c,0xc9b3,0xcc3f,0xcebf,0xd133,0xd39a,0xd5f5,0xd842,
+0xda82,0xdcb3,0xded7,0xe0eb,0xe2f1,0xe4e8,0xe6cf,0xe8a6,
+0xea6d,0xec23,0xedc9,0xef5e,0xf0e2,0xf254,0xf3b5,0xf504,
+0xf641,0xf76b,0xf884,0xf989,0xfa7c,0xfb5c,0xfc29,0xfce3,
+0xfd89,0xfe1d,0xfe9c,0xff09,0xff61,0xffa6,0xffd8,0xfff5,
+0xffff,0xfff5,0xffd8,0xffa6,0xff61,0xff09,0xfe9c,0xfe1d,
+0xfd89,0xfce3,0xfc29,0xfb5c,0xfa7c,0xf989,0xf884,0xf76b,
+0xf641,0xf504,0xf3b5,0xf254,0xf0e2,0xef5e,0xedc9,0xec23,
+0xea6d,0xe8a6,0xe6cf,0xe4e8,0xe2f1,0xe0eb,0xded7,0xdcb3,
+0xda82,0xd842,0xd5f5,0xd39a,0xd133,0xcebf,0xcc3f,0xc9b3,
+0xc71c,0xc47a,0xc1cd,0xbf17,0xbc56,0xb98c,0xb6b9,0xb3de,
+0xb0fb,0xae10,0xab1f,0xa826,0xa527,0xa223,0x9f19,0x9c0b,
+0x98f8,0x95e1,0x92c7,0x8fab,0x8c8b,0x896a,0x8647,0x8324,
+0x8000,0x7cdb,0x79b8,0x7695,0x7374,0x7054,0x6d38,0x6a1e,
+0x6707,0x63f4,0x60e6,0x5ddc,0x5ad8,0x57d9,0x54e0,0x51ef,
+0x4f04,0x4c21,0x4946,0x4673,0x43a9,0x40e8,0x3e32,0x3b85,
+0x38e3,0x364c,0x33c0,0x3140,0x2ecc,0x2c65,0x2a0a,0x27bd,
+0x257d,0x234c,0x2128,0x1f14,0x1d0e,0x1b17,0x1930,0x1759,
+0x1592,0x13dc,0x1236,0x10a1,0xf1d,0xdab,0xc4a,0xafb,
+0x9be,0x894,0x77b,0x676,0x583,0x4a3,0x3d6,0x31c,
+0x276,0x1e2,0x163,0xf6,0x9e,0x59,0x27,0xa,
+0x0,0xa,0x27,0x59,0x9e,0xf6,0x163,0x1e2,
+0x276,0x31c,0x3d6,0x4a3,0x583,0x676,0x77b,0x894,
+0x9be,0xafb,0xc4a,0xdab,0xf1d,0x10a1,0x1236,0x13dc,
+0x1592,0x1759,0x1930,0x1b17,0x1d0e,0x1f14,0x2128,0x234c,
+0x257d,0x27bd,0x2a0a,0x2c65,0x2ecc,0x3140,0x33c0,0x364c,
+0x38e3,0x3b85,0x3e32,0x40e8,0x43a9,0x4673,0x4946,0x4c21,
+0x4f04,0x51ef,0x54e0,0x57d9,0x5ad8,0x5ddc,0x60e6,0x63f4,
+0x6707,0x6a1e,0x6d38,0x7054,0x7374,0x7695,0x79b8,0x7cdb,
\ No newline at end of file diff --git a/tests/arch/ecp5/bug1836.ys b/tests/arch/ecp5/bug1836.ys new file mode 100644 index 000000000..15cdf4228 --- /dev/null +++ b/tests/arch/ecp5/bug1836.ys @@ -0,0 +1,23 @@ +read_verilog <<EOT +module top( + input clk, + output reg [15:0] sig1, sig2 +); + reg [7:0] ptr1, ptr2; + reg [15:0] mem [0:255]; + + initial begin + $readmemh("bug1836.mem", mem); + end + + always @(posedge clk) begin + sig1 <= mem[ptr1]; + ptr1 <= ptr1 + 3; + sig2 <= mem[ptr2]; + ptr2 <= ptr2 + 7; + end +endmodule +EOT + +synth_ecp5 -top top +select -assert-count 1 t:DP16KD diff --git a/tests/arch/ecp5/memories.ys b/tests/arch/ecp5/memories.ys index 5cddcb952..f075182c8 100644 --- a/tests/arch/ecp5/memories.ys +++ b/tests/arch/ecp5/memories.ys @@ -260,3 +260,13 @@ setattr -set logic_block 1 m:memory synth_ecp5 -top sync_rom; cd sync_rom select -assert-count 0 t:DP16KD # requested LUTROM explicitly select -assert-min 9 t:LUT4 + +# ============================== TDP RAM ============================== +# RAM bits <= 18K; Data width <= 18x2; Address width <= 9: -> DP16KD + +design -reset; read_verilog -defer ../common/blockram.v +chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 18 sync_ram_tdp +hierarchy -top sync_ram_tdp +synth_ecp5 -top sync_ram_tdp; cd sync_ram_tdp +select -assert-count 1 t:DP16KD +select -assert-none t:LUT4 diff --git a/tests/arch/fabulous/carry.ys b/tests/arch/fabulous/carry.ys new file mode 100644 index 000000000..bba969d37 --- /dev/null +++ b/tests/arch/fabulous/carry.ys @@ -0,0 +1,9 @@ +read_verilog ../common/add_sub.v +hierarchy -top top +proc +equiv_opt -assert -map +/fabulous/prims.v synth_fabulous -carry ha # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-max 10 t:LUT4_HA +select -assert-max 4 t:LUT1 +select -assert-none t:LUT1 t:LUT4_HA %% t:* %D diff --git a/tests/arch/gatemate/memory.ys b/tests/arch/gatemate/memory.ys index e919920f8..c4bf11cd3 100644 --- a/tests/arch/gatemate/memory.ys +++ b/tests/arch/gatemate/memory.ys @@ -6,6 +6,14 @@ cd sync_ram_sdp select -assert-count 1 t:CC_BUFG select -assert-count 1 t:CC_BRAM_20K +# 512 x 20 bit x 2 -> CC_BRAM_20K TDP RAM +design -reset +read_verilog ../common/blockram.v +chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 20 sync_ram_tdp +synth_gatemate -top sync_ram_tdp -noiopad +select -assert-count 2 t:CC_BUFG +select -assert-count 1 t:CC_BRAM_20K + # 512 x 80 bit -> CC_BRAM_40K SDP RAM design -reset read_verilog ../common/blockram.v diff --git a/tests/arch/ice40/spram.v b/tests/arch/ice40/spram.v new file mode 100644 index 000000000..4e1aef2c6 --- /dev/null +++ b/tests/arch/ice40/spram.v @@ -0,0 +1,22 @@ +module top (clk, write_enable, read_enable, write_data, addr, read_data); +parameter DATA_WIDTH = 8; +parameter ADDR_WIDTH = 8; +parameter SKIP_RDEN = 1; + +input clk; +input write_enable, read_enable; +input [DATA_WIDTH - 1 : 0] write_data; +input [ADDR_WIDTH - 1 : 0] addr; +output [DATA_WIDTH - 1 : 0] read_data; + +(* ram_style = "huge" *) +reg [DATA_WIDTH - 1 : 0] mem [2**ADDR_WIDTH - 1 : 0]; + +always @(posedge clk) begin + if (write_enable) + mem[addr] <= write_data; + else if (SKIP_RDEN || read_enable) + read_data <= mem[addr]; +end + +endmodule diff --git a/tests/arch/ice40/spram.ys b/tests/arch/ice40/spram.ys new file mode 100644 index 000000000..709c21862 --- /dev/null +++ b/tests/arch/ice40/spram.ys @@ -0,0 +1,15 @@ +read_verilog spram.v +hierarchy -top top +synth_ice40 +select -assert-count 1 t:SB_SPRAM256KA +select -assert-none t:SB_SPRAM256KA %% t:* %D + +# Testing with pattern as described in pattern document +design -reset +read_verilog spram.v +chparam -set SKIP_RDEN 0 +hierarchy -top top +synth_ice40 +select -assert-count 1 t:SB_SPRAM256KA +# Below fails due to extra SB_LUT4 +# select -assert-none t:SB_SPRAM256KA %% t:* %D diff --git a/tests/arch/intel_alm/blockram.ys b/tests/arch/intel_alm/blockram.ys index 3b61b9339..21b5ecbfb 100644 --- a/tests/arch/intel_alm/blockram.ys +++ b/tests/arch/intel_alm/blockram.ys @@ -1,6 +1,6 @@ read_verilog ../common/blockram.v chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 10 sync_ram_sdp -synth_intel_alm -family cyclonev -noiopad -noclkbuf +synth_intel_alm -top sync_ram_sdp -family cyclonev -noiopad -noclkbuf cd sync_ram_sdp select -assert-count 1 t:MISTRAL_NOT select -assert-count 1 t:MISTRAL_M10K diff --git a/tests/arch/xilinx/asym_ram_sdp.ys b/tests/arch/xilinx/asym_ram_sdp.ys new file mode 100644 index 000000000..37f6f314d --- /dev/null +++ b/tests/arch/xilinx/asym_ram_sdp.ys @@ -0,0 +1,50 @@ +# Memory bits <= 18K; Data width <= 36; Address width <= 14: -> RAMB18E1 + +# w4b | r16b +design -reset +read_verilog asym_ram_sdp_read_wider.v +synth_xilinx -top asym_ram_sdp_read_wider -noiopad +select -assert-count 1 t:RAMB18E1 + +# w8b | r16b +design -reset +read_verilog asym_ram_sdp_read_wider.v +chparam -set WIDTHA 8 -set SIZEA 512 -set ADDRWIDTHA 9 asym_ram_sdp_read_wider +synth_xilinx -top asym_ram_sdp_read_wider -noiopad +select -assert-count 1 t:RAMB18E1 + +# w4b | r32b +design -reset +read_verilog asym_ram_sdp_read_wider.v +chparam -set WIDTHB 32 -set SIZEB 128 -set ADDRWIDTHB 7 asym_ram_sdp_read_wider +synth_xilinx -top asym_ram_sdp_read_wider -noiopad +select -assert-count 1 t:RAMB18E1 + +# w16b | r4b +design -reset +read_verilog asym_ram_sdp_write_wider.v +synth_xilinx -top asym_ram_sdp_write_wider -noiopad +select -assert-count 1 t:RAMB18E1 + +# w16b | r8b +design -reset +read_verilog asym_ram_sdp_write_wider.v +chparam -set WIDTHB 8 -set SIZEB 512 -set ADDRWIDTHB 9 asym_ram_sdp_read_wider +synth_xilinx -top asym_ram_sdp_write_wider -noiopad +select -assert-count 1 t:RAMB18E1 + +# w32b | r4b +design -reset +read_verilog asym_ram_sdp_write_wider.v +chparam -set WIDTHA 32 -set SIZEA 128 -set ADDRWIDTHA 7 asym_ram_sdp_read_wider +synth_xilinx -top asym_ram_sdp_write_wider -noiopad +select -assert-count 1 t:RAMB18E1 + +# w4b | r24b +design -reset +read_verilog asym_ram_sdp_read_wider.v +chparam -set SIZEA 768 +chparam -set WIDTHB 24 -set SIZEB 128 -set ADDRWIDTHB 7 asym_ram_sdp_read_wider +synth_xilinx -top asym_ram_sdp_read_wider -noiopad +select -assert-count 1 t:RAMB18E1 + diff --git a/tests/arch/xilinx/asym_ram_sdp_read_wider.v b/tests/arch/xilinx/asym_ram_sdp_read_wider.v new file mode 100644 index 000000000..8743209e3 --- /dev/null +++ b/tests/arch/xilinx/asym_ram_sdp_read_wider.v @@ -0,0 +1,72 @@ +// Asymmetric port RAM +// Read Wider than Write. Read Statement in loop +//asym_ram_sdp_read_wider.v +module asym_ram_sdp_read_wider (clkA, clkB, enaA, weA, enaB, addrA, addrB, diA, doB); + parameter WIDTHA = 4; + parameter SIZEA = 1024; + parameter ADDRWIDTHA = 10; + + parameter WIDTHB = 16; + parameter SIZEB = 256; + parameter ADDRWIDTHB = 8; + + input clkA; + input clkB; + input weA; + input enaA, enaB; + input [ADDRWIDTHA-1:0] addrA; + input [ADDRWIDTHB-1:0] addrB; + input [WIDTHA-1:0] diA; + output [WIDTHB-1:0] doB; + + `define max(a,b) {(a) > (b) ? (a) : (b)} + `define min(a,b) {(a) < (b) ? (a) : (b)} + + function integer log2; + input integer value; + reg [31:0] shifted; + integer res; + begin + if (value < 2) + log2 = value; + else + begin + shifted = value-1; + for (res=0; shifted>0; res=res+1) + shifted = shifted>>1; + log2 = res; + end + end + endfunction + + localparam maxSIZE = `max(SIZEA, SIZEB); + localparam maxWIDTH = `max(WIDTHA, WIDTHB); + localparam minWIDTH = `min(WIDTHA, WIDTHB); + + localparam RATIO = maxWIDTH / minWIDTH; + localparam log2RATIO = log2(RATIO); + + reg [minWIDTH-1:0] RAM [0:maxSIZE-1]; + reg [WIDTHB-1:0] readB; + + always @(posedge clkA) + begin + if (enaA) begin + if (weA) + RAM[addrA] <= diA; + end + end + + always @(posedge clkB) + begin : ramread + integer i; + reg [log2RATIO-1:0] lsbaddr; + if (enaB) begin + for (i = 0; i < RATIO; i = i+1) begin + lsbaddr = i; + readB[(i+1)*minWIDTH-1 -: minWIDTH] <= RAM[{addrB, lsbaddr}]; + end + end + end + assign doB = readB; +endmodule
\ No newline at end of file diff --git a/tests/arch/xilinx/asym_ram_sdp_write_wider.v b/tests/arch/xilinx/asym_ram_sdp_write_wider.v new file mode 100644 index 000000000..cd61a3ccc --- /dev/null +++ b/tests/arch/xilinx/asym_ram_sdp_write_wider.v @@ -0,0 +1,71 @@ +// Asymmetric port RAM +// Write wider than Read. Write Statement in a loop. +// asym_ram_sdp_write_wider.v +module asym_ram_sdp_write_wider (clkA, clkB, weA, enaA, enaB, addrA, addrB, diA, doB); + parameter WIDTHB = 4; + parameter SIZEB = 1024; + parameter ADDRWIDTHB = 10; + + parameter WIDTHA = 16; + parameter SIZEA = 256; + parameter ADDRWIDTHA = 8; + + input clkA; + input clkB; + input weA; + input enaA, enaB; + input [ADDRWIDTHA-1:0] addrA; + input [ADDRWIDTHB-1:0] addrB; + input [WIDTHA-1:0] diA; + output [WIDTHB-1:0] doB; + + `define max(a,b) {(a) > (b) ? (a) : (b)} + `define min(a,b) {(a) < (b) ? (a) : (b)} + + function integer log2; + input integer value; + reg [31:0] shifted; + integer res; + begin + if (value < 2) + log2 = value; + else + begin + shifted = value-1; + for (res=0; shifted>0; res=res+1) + shifted = shifted>>1; + log2 = res; + end + end + endfunction + + localparam maxSIZE = `max(SIZEA, SIZEB); + localparam maxWIDTH = `max(WIDTHA, WIDTHB); + localparam minWIDTH = `min(WIDTHA, WIDTHB); + + localparam RATIO = maxWIDTH / minWIDTH; + localparam log2RATIO = log2(RATIO); + + reg [minWIDTH-1:0] RAM [0:maxSIZE-1]; + reg [WIDTHB-1:0] readB; + + always @(posedge clkB) begin + if (enaB) begin + readB <= RAM[addrB]; + end + end + assign doB = readB; + + always @(posedge clkA) + begin : ramwrite + integer i; + reg [log2RATIO-1:0] lsbaddr; + for (i=0; i< RATIO; i= i+ 1) begin : write1 + lsbaddr = i; + if (enaA) begin + if (weA) + RAM[{addrA, lsbaddr}] <= diA[(i+1)*minWIDTH-1 -: minWIDTH]; + end + end + end +endmodule
\ No newline at end of file diff --git a/tests/arch/xilinx/priority_memory.v b/tests/arch/xilinx/priority_memory.v new file mode 100644 index 000000000..fc943e209 --- /dev/null +++ b/tests/arch/xilinx/priority_memory.v @@ -0,0 +1,122 @@ +module priority_memory ( + clk, wren_a, rden_a, addr_a, wdata_a, rdata_a, + wren_b, rden_b, addr_b, wdata_b, rdata_b + ); + + parameter ABITS = 12; + parameter WIDTH = 72; + + input clk; + input wren_a, rden_a, wren_b, rden_b; + input [ABITS-1:0] addr_a, addr_b; + input [WIDTH-1:0] wdata_a, wdata_b; + output reg [WIDTH-1:0] rdata_a, rdata_b; + + `ifdef USE_HUGE + (* ram_style = "huge" *) + `endif + reg [WIDTH-1:0] mem [0:2**ABITS-1]; + + integer i; + initial begin + rdata_a <= 'h0; + rdata_b <= 'h0; + end + + `ifndef FLIP_PORTS + always @(posedge clk) begin + // A port + if (wren_a) + mem[addr_a] <= wdata_a; + else if (rden_a) + rdata_a <= mem[addr_a]; + + // B port + if (wren_b) + mem[addr_b] <= wdata_b; + else if (rden_b) + if (wren_a && addr_a == addr_b) + rdata_b <= wdata_a; + else + rdata_b <= mem[addr_b]; + end + `else // FLIP PORTS + always @(posedge clk) begin + // A port + if (wren_b) + mem[addr_b] <= wdata_b; + else if (rden_b) + rdata_b <= mem[addr_b]; + + // B port + if (wren_a) + mem[addr_a] <= wdata_a; + else if (rden_a) + if (wren_b && addr_a == addr_b) + rdata_a <= wdata_b; + else + rdata_a <= mem[addr_a]; + end + `endif +endmodule + +module sp_write_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a); + + parameter ABITS = 12; + parameter WIDTH = 72; + + input clk; + input wren_a, rden_a; + input [ABITS-1:0] addr_a; + input [WIDTH-1:0] wdata_a; + output reg [WIDTH-1:0] rdata_a; + + (* ram_style = "huge" *) + reg [WIDTH-1:0] mem [0:2**ABITS-1]; + + integer i; + initial begin + rdata_a <= 'h0; + end + + + always @(posedge clk) begin + // A port + if (wren_a) + mem[addr_a] <= wdata_a; + if (rden_a) + if (wren_a) + rdata_a <= wdata_a; + else + rdata_a <= mem[addr_a]; + end +endmodule + +module sp_read_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a); + + parameter ABITS = 12; + parameter WIDTH = 72; + + input clk; + input wren_a, rden_a; + input [ABITS-1:0] addr_a; + input [WIDTH-1:0] wdata_a; + output reg [WIDTH-1:0] rdata_a; + + (* ram_style = "huge" *) + reg [WIDTH-1:0] mem [0:2**ABITS-1]; + + integer i; + initial begin + rdata_a <= 'h0; + end + + + always @(posedge clk) begin + // A port + if (wren_a) + mem[addr_a] <= wdata_a; + if (rden_a) + rdata_a <= mem[addr_a]; + end +endmodule diff --git a/tests/arch/xilinx/priority_memory.ys b/tests/arch/xilinx/priority_memory.ys new file mode 100644 index 000000000..d0b2a16ad --- /dev/null +++ b/tests/arch/xilinx/priority_memory.ys @@ -0,0 +1,60 @@ + +# no uram by default +design -reset +read_verilog priority_memory.v +synth_xilinx -family xcup -top priority_memory +select -assert-none t:URAM288 + +# uram parameter +design -reset +read -define USE_HUGE +read_verilog priority_memory.v +synth_xilinx -family xcup -top priority_memory -noiopad +select -assert-count 1 t:URAM288 + +# uram option +design -reset +read_verilog priority_memory.v +synth_xilinx -family xcup -top priority_memory -noiopad -uram +# check for URAM block +select -assert-count 1 t:URAM288 +# check port A in code maps to port A in hardware: +# %co:+[DOUT_A] selects everything connected to a URAM288.DOUT_A port +# w:rdata_a selects the wire rdata_a +# %i finds the intersection of the two above selections +# if the result is 1 then the wire rdata_a is connected to Port A correctly +select -assert-count 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i +# we expect no more than 2 LUT2s to control the hardware priority +# if there are extra LUTs, then it is likely emulating logic it shouldn't +# ignore anything using blif, since that doesn't seem to support priority logic +# and is indicative of using verific/tabby +select -assert-max 2 t:LUT* n:*blif* %d + +# reverse priority +design -reset +read -define FLIP_PORTS +read_verilog priority_memory.v +synth_xilinx -family xcup -top priority_memory -noiopad -uram +# test priority is mapped correctly, rdata_a should now be connected to Port B +# see above for details +select -assert-count 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i + +# sp write first +design -reset +read_verilog priority_memory.v +synth_xilinx -family xcup -top sp_write_first -noiopad +select -assert-count 1 t:URAM288 +# write first connects rdata_a to port B +# similar to above, but also tests that rdata_a *isn't* connected to port A +select -assert-none 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i +select -assert-count 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i + +# sp read first +design -reset +read_verilog priority_memory.v +synth_xilinx -family xcup -top sp_read_first -noiopad +select -assert-count 1 t:URAM288 +# read first connects rdata_a to port A +# see above for details +select -assert-count 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i +select -assert-none 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i 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 diff --git a/tests/various/muxcover.ys b/tests/various/muxcover.ys index 67e9625e6..37a90dcb0 100644 --- a/tests/various/muxcover.ys +++ b/tests/various/muxcover.ys @@ -508,3 +508,43 @@ design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter sat -verify -prove-asserts -show-ports miter + +## implement a mux6 as a mux8 :: https://github.com/YosysHQ/yosys/issues/3591 + +design -reset +read_verilog << EOF +module test (A, S, Y); + parameter INPUTS = 6; + + input [INPUTS-1:0] A; + input [$clog2(INPUTS)-1:0] S; + + wire [15:0] AA = {{(16-INPUTS){1'b0}}, A}; + wire [3:0] SS = {{(4-$clog2(INPUTS)){1'b0}}, S}; + + output Y = SS[3] ? (SS[2] ? SS[1] ? (SS[0] ? AA[15] : AA[14]) + : (SS[0] ? AA[13] : AA[12]) + : SS[1] ? (SS[0] ? AA[11] : AA[10]) + : (SS[0] ? AA[9] : AA[8])) + : (SS[2] ? SS[1] ? (SS[0] ? AA[7] : AA[6]) + : (SS[0] ? AA[5] : AA[4]) + : SS[1] ? (SS[0] ? AA[3] : AA[2]) + : (SS[0] ? AA[1] : AA[0])); +endmodule +EOF + +prep +design -save gold +simplemap t:\$mux +muxcover +opt_clean -purge +select -assert-count 1 t:$_MUX8_ +select -assert-none t:$_MUX8_ %% t:* %D +techmap -map +/simcells.v t:$_MUX8_ +design -stash gate + +design -import gold -as gold +design -import gate -as gate + +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter +sat -verify -prove-asserts -show-ports miter diff --git a/tests/verific/.gitignore b/tests/verific/.gitignore new file mode 100644 index 000000000..b48f808a1 --- /dev/null +++ b/tests/verific/.gitignore @@ -0,0 +1,3 @@ +/*.log +/*.out +/run-test.mk diff --git a/tests/verific/case.sv b/tests/verific/case.sv new file mode 100644 index 000000000..ed8529b91 --- /dev/null +++ b/tests/verific/case.sv @@ -0,0 +1,28 @@ +module top ( + input clk, + input [5:0] currentstate, + output reg [1:0] o + ); + always @ (posedge clk) + begin + case (currentstate) + 5'd1,5'd2, 5'd3: + begin + o <= 2'b01; + end + 5'd4: + begin + o <= 2'b10; + end + 5'd5,5'd6,5'd7: + begin + o <= 2'b11; + end + default : + begin + o <= 2'b00; + end + endcase + end +endmodule + diff --git a/tests/verific/case.ys b/tests/verific/case.ys new file mode 100644 index 000000000..a181b39cf --- /dev/null +++ b/tests/verific/case.ys @@ -0,0 +1,16 @@ +verific -cfg db_abstract_case_statement_synthesis 0 +read -sv case.sv +verific -import top +prep +rename top gold + +verific -cfg db_abstract_case_statement_synthesis 1 +read -sv case.sv +verific -import top +prep +rename top gate + +miter -equiv -flatten -make_assert gold gate miter +prep -top miter +clk2fflogic +sat -set-init-zero -tempinduct -prove-asserts -verify diff --git a/tests/verific/range_case.sv b/tests/verific/range_case.sv new file mode 100644 index 000000000..9843feafe --- /dev/null +++ b/tests/verific/range_case.sv @@ -0,0 +1,11 @@ +module top(input clk, input signed [3:0] sel_w , output reg out); + +always @ (posedge clk) +begin + case (sel_w) inside + [-4:3] : out <= 1'b1; + [4:5] : out <= 1'b0; + endcase +end + +endmodule diff --git a/tests/verific/range_case.ys b/tests/verific/range_case.ys new file mode 100644 index 000000000..27afbbc17 --- /dev/null +++ b/tests/verific/range_case.ys @@ -0,0 +1,16 @@ +verific -cfg db_abstract_case_statement_synthesis 0 +read -sv range_case.sv +verific -import top +proc +rename top gold + +verific -cfg db_abstract_case_statement_synthesis 1 +read -sv range_case.sv +verific -import top +proc +rename top gate + +miter -equiv -flatten -make_assert gold gate miter +prep -top miter +clk2fflogic +sat -set-init-zero -tempinduct -prove-asserts -verify diff --git a/tests/verific/run-test.sh b/tests/verific/run-test.sh new file mode 100755 index 000000000..2f91cf0fd --- /dev/null +++ b/tests/verific/run-test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -eu +source ../gen-tests-makefile.sh +run_tests --yosys-scripts --bash |