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 | 
