aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG16
-rw-r--r--Makefile11
-rw-r--r--backends/smt2/smtbmc.py17
-rw-r--r--frontends/verific/verific.cc56
-rw-r--r--passes/cmds/stat.cc2
-rw-r--r--passes/techmap/muxcover.cc5
-rw-r--r--techlibs/fabulous/Makefile.inc1
-rw-r--r--techlibs/fabulous/arith_map.v65
-rw-r--r--techlibs/fabulous/prims.v14
-rw-r--r--techlibs/fabulous/synth_fabulous.cc15
-rw-r--r--techlibs/gatemate/cells_sim.v12
-rw-r--r--techlibs/gatemate/reg_map.v10
-rw-r--r--techlibs/gatemate/synth_gatemate.cc2
-rw-r--r--techlibs/gowin/cells_sim.v25
-rw-r--r--techlibs/ice40/cells_sim.v28
-rw-r--r--tests/arch/common/blockram.v31
-rw-r--r--tests/arch/ecp5/bug1836.mem32
-rw-r--r--tests/arch/ecp5/bug1836.ys23
-rw-r--r--tests/arch/ecp5/memories.ys10
-rw-r--r--tests/arch/fabulous/carry.ys9
-rw-r--r--tests/arch/gatemate/memory.ys8
-rw-r--r--tests/arch/ice40/spram.v22
-rw-r--r--tests/arch/ice40/spram.ys15
-rw-r--r--tests/arch/intel_alm/blockram.ys2
-rw-r--r--tests/arch/xilinx/asym_ram_sdp.ys50
-rw-r--r--tests/arch/xilinx/asym_ram_sdp_read_wider.v72
-rw-r--r--tests/arch/xilinx/asym_ram_sdp_write_wider.v71
-rw-r--r--tests/arch/xilinx/priority_memory.v122
-rw-r--r--tests/arch/xilinx/priority_memory.ys60
-rw-r--r--tests/memlib/generate.py677
-rw-r--r--tests/memlib/memlib_9b1B.txt31
-rw-r--r--tests/memlib/memlib_9b1B.v68
-rw-r--r--tests/memlib/memlib_block_sp_full.txt61
-rw-r--r--tests/memlib/memlib_block_sp_full.v82
-rw-r--r--tests/memlib/memlib_clock_sdp.txt76
-rw-r--r--tests/memlib/memlib_clock_sdp.v36
-rw-r--r--tests/memlib/memlib_lut.txt18
-rw-r--r--tests/memlib/memlib_lut.v9
-rw-r--r--tests/memlib/memlib_multilut.txt19
-rw-r--r--tests/memlib/memlib_multilut.v45
-rw-r--r--tests/memlib/memlib_wren.txt37
-rw-r--r--tests/memlib/memlib_wren.v33
-rw-r--r--tests/various/muxcover.ys40
-rw-r--r--tests/verific/.gitignore3
-rw-r--r--tests/verific/case.sv28
-rw-r--r--tests/verific/case.ys16
-rw-r--r--tests/verific/range_case.sv11
-rw-r--r--tests/verific/range_case.ys16
-rwxr-xr-xtests/verific/run-test.sh4
49 files changed, 2050 insertions, 66 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 18874a04e..80672a8cc 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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
diff --git a/Makefile b/Makefile
index 396aeb927..0581cba83 100644
--- a/Makefile
+++ b/Makefile
@@ -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