aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/common
diff options
context:
space:
mode:
Diffstat (limited to 'techlibs/common')
-rw-r--r--techlibs/common/Makefile.inc9
-rw-r--r--techlibs/common/cmp2lut.v105
-rw-r--r--techlibs/common/dummy.box1
-rw-r--r--techlibs/common/gate2lut.v87
-rw-r--r--techlibs/common/mul2dsp.v296
-rw-r--r--techlibs/common/prep.cc40
-rw-r--r--techlibs/common/simcells.v23
-rw-r--r--techlibs/common/simlib.v244
-rw-r--r--techlibs/common/synth.cc82
9 files changed, 844 insertions, 43 deletions
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc
index ab961ac0b..a42f63128 100644
--- a/techlibs/common/Makefile.inc
+++ b/techlibs/common/Makefile.inc
@@ -9,12 +9,12 @@ GENFILES += techlibs/common/simcells_help.inc
techlibs/common/simlib_help.inc: techlibs/common/cellhelp.py techlibs/common/simlib.v
$(Q) mkdir -p techlibs/common
- $(P) python3 $^ > $@.new
+ $(P) $(PYTHON_EXECUTABLE) $^ > $@.new
$(Q) mv $@.new $@
techlibs/common/simcells_help.inc: techlibs/common/cellhelp.py techlibs/common/simcells.v
$(Q) mkdir -p techlibs/common
- $(P) python3 $^ > $@.new
+ $(P) $(PYTHON_EXECUTABLE) $^ > $@.new
$(Q) mv $@.new $@
kernel/register.o: techlibs/common/simlib_help.inc techlibs/common/simcells_help.inc
@@ -25,5 +25,8 @@ $(eval $(call add_share_file,share,techlibs/common/techmap.v))
$(eval $(call add_share_file,share,techlibs/common/pmux2mux.v))
$(eval $(call add_share_file,share,techlibs/common/adff2dff.v))
$(eval $(call add_share_file,share,techlibs/common/dff2ff.v))
+$(eval $(call add_share_file,share,techlibs/common/gate2lut.v))
+$(eval $(call add_share_file,share,techlibs/common/cmp2lut.v))
$(eval $(call add_share_file,share,techlibs/common/cells.lib))
-
+$(eval $(call add_share_file,share,techlibs/common/mul2dsp.v))
+$(eval $(call add_share_file,share,techlibs/common/dummy.box))
diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v
new file mode 100644
index 000000000..1c8192b85
--- /dev/null
+++ b/techlibs/common/cmp2lut.v
@@ -0,0 +1,105 @@
+// Certain arithmetic operations between a signal of width n and a constant can be directly mapped
+// to a single k-LUT (where n <= k). This is preferable to normal alumacc techmapping process
+// because for many targets, arithmetic techmapping creates hard logic (such as carry cells) which often
+// cannot be optimized further.
+//
+// TODO: Currently, only comparisons with 1-bit output are mapped. Potentially, all arithmetic cells
+// with n <= k inputs should be techmapped in this way, because this shortens the critical path
+// from n to 1 by avoiding carry chains.
+
+(* techmap_celltype = "$lt $le $gt $ge" *)
+module _90_lut_cmp_ (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+parameter _TECHMAP_CELLTYPE_ = "";
+
+parameter _TECHMAP_CONSTMSK_A_ = 0;
+parameter _TECHMAP_CONSTVAL_A_ = 0;
+parameter _TECHMAP_CONSTMSK_B_ = 0;
+parameter _TECHMAP_CONSTVAL_B_ = 0;
+
+function automatic [(1 << `LUT_WIDTH)-1:0] gen_lut;
+ input integer width;
+ input integer operation;
+ input integer swap;
+ input integer sign;
+ input integer operand;
+ integer n, i_var, i_cst, lhs, rhs, o_bit;
+ begin
+ gen_lut = width'b0;
+ for (n = 0; n < (1 << width); n++) begin
+ if (sign)
+ i_var = n[width-1:0];
+ else
+ i_var = n;
+ i_cst = operand;
+ if (swap) begin
+ lhs = i_cst;
+ rhs = i_var;
+ end else begin
+ lhs = i_var;
+ rhs = i_cst;
+ end
+ if (operation == 0)
+ o_bit = (lhs < rhs);
+ if (operation == 1)
+ o_bit = (lhs <= rhs);
+ if (operation == 2)
+ o_bit = (lhs > rhs);
+ if (operation == 3)
+ o_bit = (lhs >= rhs);
+ if (operation == 4)
+ o_bit = (lhs == rhs);
+ if (operation == 5)
+ o_bit = (lhs != rhs);
+ gen_lut = gen_lut | (o_bit << n);
+ end
+ end
+endfunction
+
+generate
+ if (_TECHMAP_CELLTYPE_ == "$lt")
+ localparam operation = 0;
+ if (_TECHMAP_CELLTYPE_ == "$le")
+ localparam operation = 1;
+ if (_TECHMAP_CELLTYPE_ == "$gt")
+ localparam operation = 2;
+ if (_TECHMAP_CELLTYPE_ == "$ge")
+ localparam operation = 3;
+ if (_TECHMAP_CELLTYPE_ == "$eq")
+ localparam operation = 4;
+ if (_TECHMAP_CELLTYPE_ == "$ne")
+ localparam operation = 5;
+
+ if (A_WIDTH > `LUT_WIDTH || B_WIDTH > `LUT_WIDTH || Y_WIDTH != 1)
+ wire _TECHMAP_FAIL_ = 1;
+ else if (&_TECHMAP_CONSTMSK_B_)
+ \$lut #(
+ .WIDTH(A_WIDTH),
+ .LUT({ gen_lut(A_WIDTH, operation, 0, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_B_) })
+ ) _TECHMAP_REPLACE_ (
+ .A(A),
+ .Y(Y)
+ );
+ else if (&_TECHMAP_CONSTMSK_A_)
+ \$lut #(
+ .WIDTH(B_WIDTH),
+ .LUT({ gen_lut(B_WIDTH, operation, 1, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_A_) })
+ ) _TECHMAP_REPLACE_ (
+ .A(B),
+ .Y(Y)
+ );
+ else
+ wire _TECHMAP_FAIL_ = 1;
+endgenerate
+
+endmodule
diff --git a/techlibs/common/dummy.box b/techlibs/common/dummy.box
new file mode 100644
index 000000000..0c18070a0
--- /dev/null
+++ b/techlibs/common/dummy.box
@@ -0,0 +1 @@
+(dummy) 1 0 0 0
diff --git a/techlibs/common/gate2lut.v b/techlibs/common/gate2lut.v
new file mode 100644
index 000000000..99c123f4a
--- /dev/null
+++ b/techlibs/common/gate2lut.v
@@ -0,0 +1,87 @@
+(* techmap_celltype = "$_NOT_" *)
+module _90_lut_not (A, Y);
+ input A;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ .LUT(4'b01)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
+
+(* techmap_celltype = "$_OR_" *)
+module _90_lut_or (A, B, Y);
+ input A, B;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {B, A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ .LUT(4'b1110)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
+
+(* techmap_celltype = "$_AND_" *)
+module _90_lut_and (A, B, Y);
+ input A, B;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {B, A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ .LUT(4'b1000)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
+
+(* techmap_celltype = "$_XOR_" *)
+module _90_lut_xor (A, B, Y);
+ input A, B;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {B, A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ .LUT(4'b0110)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
+
+(* techmap_celltype = "$_MUX_" *)
+module _90_lut_mux (A, B, S, Y);
+ input A, B, S;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {S, B, A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ // A 1010 1010
+ // B 1100 1100
+ // S 1111 0000
+ .LUT(8'b_1100_1010)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v
new file mode 100644
index 000000000..4cabb4453
--- /dev/null
+++ b/techlibs/common/mul2dsp.v
@@ -0,0 +1,296 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ * 2019 David Shah <dave@ds0.me>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ---
+ *
+ * Tech-mapping rules for decomposing arbitrarily-sized $mul cells
+ * into an equivalent collection of smaller `DSP_NAME cells (with the
+ * same interface as $mul) no larger than `DSP_[AB]_MAXWIDTH, attached
+ * to $shl and $add cells.
+ *
+ */
+
+`ifndef DSP_A_MAXWIDTH
+$fatal(1, "Macro DSP_A_MAXWIDTH must be defined");
+`endif
+`ifndef DSP_B_MAXWIDTH
+$fatal(1, "Macro DSP_B_MAXWIDTH must be defined");
+`endif
+`ifndef DSP_B_MAXWIDTH
+$fatal(1, "Macro DSP_B_MAXWIDTH must be defined");
+`endif
+`ifndef DSP_A_MAXWIDTH_PARTIAL
+`define DSP_A_MAXWIDTH_PARTIAL `DSP_A_MAXWIDTH
+`endif
+`ifndef DSP_B_MAXWIDTH_PARTIAL
+`define DSP_B_MAXWIDTH_PARTIAL `DSP_B_MAXWIDTH
+`endif
+
+`ifndef DSP_NAME
+$fatal(1, "Macro DSP_NAME must be defined");
+`endif
+
+`define MAX(a,b) (a > b ? a : b)
+`define MIN(a,b) (a < b ? a : b)
+
+(* techmap_celltype = "$mul $__mul" *)
+module _80_mul (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ parameter _TECHMAP_CELLTYPE_ = "";
+
+ generate
+ if (0) begin end
+`ifdef DSP_A_MINWIDTH
+ else if (A_WIDTH < `DSP_A_MINWIDTH)
+ wire _TECHMAP_FAIL_ = 1;
+`endif
+`ifdef DSP_B_MINWIDTH
+ else if (B_WIDTH < `DSP_B_MINWIDTH)
+ wire _TECHMAP_FAIL_ = 1;
+`endif
+`ifdef DSP_Y_MINWIDTH
+ else if (Y_WIDTH < `DSP_Y_MINWIDTH)
+ wire _TECHMAP_FAIL_ = 1;
+`endif
+`ifdef DSP_SIGNEDONLY
+ else if (_TECHMAP_CELLTYPE_ == "$mul" && !A_SIGNED && !B_SIGNED)
+ \$mul #(
+ .A_SIGNED(1),
+ .B_SIGNED(1),
+ .A_WIDTH(A_WIDTH + 1),
+ .B_WIDTH(B_WIDTH + 1),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A({1'b0, A}),
+ .B({1'b0, B}),
+ .Y(Y)
+ );
+`endif
+ else if (_TECHMAP_CELLTYPE_ == "$mul" && A_WIDTH < B_WIDTH)
+ \$mul #(
+ .A_SIGNED(B_SIGNED),
+ .B_SIGNED(A_SIGNED),
+ .A_WIDTH(B_WIDTH),
+ .B_WIDTH(A_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(B),
+ .B(A),
+ .Y(Y)
+ );
+ else begin
+ wire [1023:0] _TECHMAP_DO_ = "proc; clean";
+
+`ifdef DSP_SIGNEDONLY
+ localparam sign_headroom = 1;
+`else
+ localparam sign_headroom = 0;
+`endif
+
+ genvar i;
+ if (A_WIDTH > `DSP_A_MAXWIDTH) begin
+ localparam n = (A_WIDTH-`DSP_A_MAXWIDTH+`DSP_A_MAXWIDTH_PARTIAL-sign_headroom-1) / (`DSP_A_MAXWIDTH_PARTIAL-sign_headroom);
+ localparam partial_Y_WIDTH = `MIN(Y_WIDTH, B_WIDTH+`DSP_A_MAXWIDTH_PARTIAL);
+ localparam last_A_WIDTH = A_WIDTH-n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom);
+ localparam last_Y_WIDTH = B_WIDTH+last_A_WIDTH;
+ if (A_SIGNED && B_SIGNED) begin
+ wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ wire signed [last_Y_WIDTH-1:0] last_partial;
+ wire signed [Y_WIDTH-1:0] partial_sum [n:0];
+ end
+ else begin
+ wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ wire [last_Y_WIDTH-1:0] last_partial;
+ wire [Y_WIDTH-1:0] partial_sum [n:0];
+ end
+
+ for (i = 0; i < n; i=i+1) begin:sliceA
+ \$__mul #(
+ .A_SIGNED(sign_headroom),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(`DSP_A_MAXWIDTH_PARTIAL),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(partial_Y_WIDTH)
+ ) mul (
+ .A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_A_MAXWIDTH_PARTIAL-sign_headroom]}),
+ .B(B),
+ .Y(partial[i])
+ );
+ // TODO: Currently a 'cascade' approach to summing the partial
+ // products is taken here, but a more efficient 'binary
+ // reduction' approach also exists...
+ if (i == 0)
+ assign partial_sum[i] = partial[i];
+ else
+ assign partial_sum[i] = (partial[i] << (* mul2dsp *) i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) partial_sum[i-1];
+ end
+
+ \$__mul #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(last_A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(last_Y_WIDTH)
+ ) sliceA.last (
+ .A(A[A_WIDTH-1 -: last_A_WIDTH]),
+ .B(B),
+ .Y(last_partial)
+ );
+ assign partial_sum[n] = (last_partial << (* mul2dsp *) n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) partial_sum[n-1];
+ assign Y = partial_sum[n];
+ end
+ else if (B_WIDTH > `DSP_B_MAXWIDTH) begin
+ localparam n = (B_WIDTH-`DSP_B_MAXWIDTH+`DSP_B_MAXWIDTH_PARTIAL-sign_headroom-1) / (`DSP_B_MAXWIDTH_PARTIAL-sign_headroom);
+ localparam partial_Y_WIDTH = `MIN(Y_WIDTH, A_WIDTH+`DSP_B_MAXWIDTH_PARTIAL);
+ localparam last_B_WIDTH = B_WIDTH-n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom);
+ localparam last_Y_WIDTH = A_WIDTH+last_B_WIDTH;
+ if (A_SIGNED && B_SIGNED) begin
+ wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ wire signed [last_Y_WIDTH-1:0] last_partial;
+ wire signed [Y_WIDTH-1:0] partial_sum [n:0];
+ end
+ else begin
+ wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ wire [last_Y_WIDTH-1:0] last_partial;
+ wire [Y_WIDTH-1:0] partial_sum [n:0];
+ end
+
+ for (i = 0; i < n; i=i+1) begin:sliceB
+ \$__mul #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(sign_headroom),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(`DSP_B_MAXWIDTH_PARTIAL),
+ .Y_WIDTH(partial_Y_WIDTH)
+ ) mul (
+ .A(A),
+ .B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_B_MAXWIDTH_PARTIAL-sign_headroom]}),
+ .Y(partial[i])
+ );
+ // TODO: Currently a 'cascade' approach to summing the partial
+ // products is taken here, but a more efficient 'binary
+ // reduction' approach also exists...
+ if (i == 0)
+ assign partial_sum[i] = partial[i];
+ else
+ assign partial_sum[i] = (partial[i] << (* mul2dsp *) i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) partial_sum[i-1];
+ end
+
+ \$__mul #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(last_B_WIDTH),
+ .Y_WIDTH(last_Y_WIDTH)
+ ) mul_sliceB_last (
+ .A(A),
+ .B(B[B_WIDTH-1 -: last_B_WIDTH]),
+ .Y(last_partial)
+ );
+ assign partial_sum[n] = (last_partial << (* mul2dsp *) n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) partial_sum[n-1];
+ assign Y = partial_sum[n];
+ end
+ else begin
+ if (A_SIGNED)
+ wire signed [`DSP_A_MAXWIDTH-1:0] Aext = $signed(A);
+ else
+ wire [`DSP_A_MAXWIDTH-1:0] Aext = A;
+ if (B_SIGNED)
+ wire signed [`DSP_B_MAXWIDTH-1:0] Bext = $signed(B);
+ else
+ wire [`DSP_B_MAXWIDTH-1:0] Bext = B;
+
+ `DSP_NAME #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(`DSP_A_MAXWIDTH),
+ .B_WIDTH(`DSP_B_MAXWIDTH),
+ .Y_WIDTH(`MIN(Y_WIDTH,`DSP_A_MAXWIDTH+`DSP_B_MAXWIDTH)),
+ ) _TECHMAP_REPLACE_ (
+ .A(Aext),
+ .B(Bext),
+ .Y(Y)
+ );
+ end
+ end
+ endgenerate
+endmodule
+
+(* techmap_celltype = "$mul $__mul" *)
+module _90_soft_mul (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ // Indirection necessary since mapping
+ // back to $mul will cause recursion
+ generate
+ if (A_SIGNED && !B_SIGNED)
+ \$__soft_mul #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(1),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH+1),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(A),
+ .B({1'b0,B}),
+ .Y(Y)
+ );
+ else if (!A_SIGNED && B_SIGNED)
+ \$__soft_mul #(
+ .A_SIGNED(1),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH+1),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A({1'b0,A}),
+ .B(B),
+ .Y(Y)
+ );
+ else
+ \$__soft_mul #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(A),
+ .B(B),
+ .Y(Y)
+ );
+ endgenerate
+endmodule
diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc
index 71534983d..cdd21c3b3 100644
--- a/techlibs/common/prep.cc
+++ b/techlibs/common/prep.cc
@@ -29,7 +29,7 @@ struct PrepPass : public ScriptPass
{
PrepPass() : ScriptPass("prep", "generic synthesis script") { }
- virtual void help() YS_OVERRIDE
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -55,15 +55,16 @@ struct PrepPass : public ScriptPass
log("\n");
log(" -memx\n");
log(" simulate verilog simulation behavior for out-of-bounds memory accesses\n");
- log(" using the 'memory_memx' pass. This option implies -nordff.\n");
+ log(" using the 'memory_memx' pass.\n");
log("\n");
log(" -nomem\n");
log(" do not run any of the memory_* passes\n");
log("\n");
- log(" -nordff\n");
- log(" passed to 'memory_dff'. prohibits merging of FFs into memory read ports\n");
+ log(" -rdff\n");
+ log(" do not pass -nordff to 'memory_dff'. This enables merging of FFs into\n");
+ log(" memory read ports.\n");
log("\n");
- log(" -nokeepdc\n");
+ log(" -nokeepdc\n");
log(" do not call opt_* with -keepdc\n");
log("\n");
log(" -run <from_label>[:<to_label>]\n");
@@ -77,13 +78,12 @@ struct PrepPass : public ScriptPass
log("\n");
}
- string top_module, fsm_opts, memory_opts;
- bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc;
+ string top_module, fsm_opts;
+ bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc, nordff;
- virtual void clear_flags() YS_OVERRIDE
+ void clear_flags() YS_OVERRIDE
{
top_module.clear();
- memory_opts.clear();
autotop = false;
flatten = false;
@@ -91,9 +91,10 @@ struct PrepPass : public ScriptPass
memxmode = false;
nomemmode = false;
nokeepdc = false;
+ nordff = true;
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
@@ -129,7 +130,6 @@ struct PrepPass : public ScriptPass
}
if (args[argidx] == "-memx") {
memxmode = true;
- memory_opts += " -nordff";
continue;
}
if (args[argidx] == "-nomem") {
@@ -137,7 +137,11 @@ struct PrepPass : public ScriptPass
continue;
}
if (args[argidx] == "-nordff") {
- memory_opts += " -nordff";
+ nordff = true;
+ continue;
+ }
+ if (args[argidx] == "-rdff") {
+ nordff = false;
continue;
}
if (args[argidx] == "-nokeepdc") {
@@ -149,7 +153,7 @@ struct PrepPass : public ScriptPass
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing PREP pass.\n");
log_push();
@@ -159,7 +163,7 @@ struct PrepPass : public ScriptPass
log_pop();
}
- virtual void script() YS_OVERRIDE
+ void script() YS_OVERRIDE
{
if (check_label("begin"))
@@ -191,12 +195,14 @@ struct PrepPass : public ScriptPass
run(nokeepdc ? "opt" : "opt -keepdc");
if (!ifxmode) {
if (help_mode)
- run("wreduce [-memx]");
- else
+ run("wreduce -keepdc [-memx]");
+ else if (nokeepdc)
run(memxmode ? "wreduce -memx" : "wreduce");
+ else
+ run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc");
}
if (!nomemmode) {
- run("memory_dff" + (help_mode ? " [-nordff]" : memory_opts));
+ run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : ""));
if (help_mode || memxmode)
run("memory_memx", "(if -memx)");
run("opt_clean");
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index 937512e7c..64720e598 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -230,6 +230,25 @@ endmodule
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//-
+//- $_NMUX_ (A, B, S, Y)
+//-
+//- A 2-input inverting MUX gate.
+//-
+//- Truth table: A B S | Y
+//- -------+---
+//- 0 - 0 | 1
+//- 1 - 0 | 0
+//- - 0 1 | 1
+//- - 1 1 | 0
+//-
+module \$_NMUX_ (A, B, S, Y);
+input A, B, S;
+output Y;
+assign Y = S ? !B : !A;
+endmodule
+
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
//- $_MUX4_ (A, B, C, D, S, T, Y)
//-
//- A 4-input MUX gate.
@@ -465,7 +484,7 @@ endmodule
//-
//- $_SR_NP_ (S, R, Q)
//-
-//- A set-reset latch with negative polarity SET and positive polarioty RESET.
+//- A set-reset latch with negative polarity SET and positive polarity RESET.
//-
//- Truth table: S R | Q
//- -----+---
@@ -489,7 +508,7 @@ endmodule
//-
//- $_SR_PN_ (S, R, Q)
//-
-//- A set-reset latch with positive polarity SET and negative polarioty RESET.
+//- A set-reset latch with positive polarity SET and negative polarity RESET.
//-
//- Truth table: S R | Q
//- -----+---
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 276503fe8..7845a3fed 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -532,14 +532,26 @@ endmodule
// --------------------------------------------------------
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $lcu (P, G, CI, CO)
+//-
+//- Lookahead carry unit
+//- A building block dedicated to fast computation of carry-bits used in binary
+//- arithmetic operations. By replacing the ripple carry structure used in full-adder
+//- blocks, the more significant bits of the sum can be expected to be computed more
+//- quickly.
+//- Typically created during `techmap` of $alu cells (see the "_90_alu" rule in
+//- +/techmap.v).
module \$lcu (P, G, CI, CO);
parameter WIDTH = 1;
-input [WIDTH-1:0] P, G;
-input CI;
+input [WIDTH-1:0] P; // Propagate
+input [WIDTH-1:0] G; // Generate
+input CI; // Carry-in
-output reg [WIDTH-1:0] CO;
+output reg [WIDTH-1:0] CO; // Carry-out
integer i;
always @* begin
@@ -555,6 +567,17 @@ endmodule
// --------------------------------------------------------
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $alu (A, B, CI, BI, X, Y, CO)
+//-
+//- Arithmetic logic unit.
+//- A building block supporting both binary addition/subtraction operations, and
+//- indirectly, comparison operations.
+//- Typically created by the `alumacc` pass, which transforms:
+//- $add, $sub, $lt, $le, $ge, $gt, $eq, $eqx, $ne, $nex
+//- cells into this $alu cell.
+//-
module \$alu (A, B, CI, BI, X, Y, CO);
parameter A_SIGNED = 0;
@@ -563,12 +586,16 @@ parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] X, Y;
+input [A_WIDTH-1:0] A; // Input operand
+input [B_WIDTH-1:0] B; // Input operand
+output [Y_WIDTH-1:0] X; // A xor B (sign-extended, optional B inversion,
+ // used in combination with
+ // reduction-AND for $eq/$ne ops)
+output [Y_WIDTH-1:0] Y; // Sum
-input CI, BI;
-output [Y_WIDTH-1:0] CO;
+input CI; // Carry-in (set for $sub)
+input BI; // Invert-B (set for $sub)
+output [Y_WIDTH-1:0] CO; // Carry-out
wire [Y_WIDTH-1:0] AA, BB;
@@ -584,6 +611,7 @@ endgenerate
wire y_co_undef = ^{A, A, B, B, CI, CI, BI, BI};
assign X = AA ^ BB;
+// Full adder
assign Y = (AA + BB + CI) ^ {Y_WIDTH{y_co_undef}};
function get_carry;
@@ -1271,6 +1299,181 @@ endmodule
// --------------------------------------------------------
+module \$specify2 (EN, SRC, DST);
+
+parameter FULL = 0;
+parameter SRC_WIDTH = 1;
+parameter DST_WIDTH = 1;
+
+parameter SRC_DST_PEN = 0;
+parameter SRC_DST_POL = 0;
+
+parameter T_RISE_MIN = 0;
+parameter T_RISE_TYP = 0;
+parameter T_RISE_MAX = 0;
+
+parameter T_FALL_MIN = 0;
+parameter T_FALL_TYP = 0;
+parameter T_FALL_MAX = 0;
+
+input EN;
+input [SRC_WIDTH-1:0] SRC;
+input [DST_WIDTH-1:0] DST;
+
+localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
+
+`ifdef SIMLIB_SPECIFY
+specify
+ if (EN && SD==0 && !FULL) (SRC => DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==0 && FULL) (SRC *> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==1 && !FULL) (SRC +=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==1 && FULL) (SRC +*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==2 && !FULL) (SRC -=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==2 && FULL) (SRC -*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+endspecify
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$specify3 (EN, SRC, DST, DAT);
+
+parameter FULL = 0;
+parameter SRC_WIDTH = 1;
+parameter DST_WIDTH = 1;
+
+parameter EDGE_EN = 0;
+parameter EDGE_POL = 0;
+
+parameter SRC_DST_PEN = 0;
+parameter SRC_DST_POL = 0;
+
+parameter DAT_DST_PEN = 0;
+parameter DAT_DST_POL = 0;
+
+parameter T_RISE_MIN = 0;
+parameter T_RISE_TYP = 0;
+parameter T_RISE_MAX = 0;
+
+parameter T_FALL_MIN = 0;
+parameter T_FALL_TYP = 0;
+parameter T_FALL_MAX = 0;
+
+input EN;
+input [SRC_WIDTH-1:0] SRC;
+input [DST_WIDTH-1:0] DST, DAT;
+
+localparam ED = EDGE_EN ? (EDGE_POL ? 1 : 2) : 0;
+localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
+localparam DD = DAT_DST_PEN ? (DAT_DST_POL ? 1 : 2) : 0;
+
+`ifdef SIMLIB_SPECIFY
+specify
+ // DD=0
+
+ if (EN && DD==0 && SD==0 && ED==0 && !FULL) ( SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==0 && FULL) ( SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==0 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==0 && FULL) ( SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==0 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==0 && FULL) ( SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ // DD=1
+
+ if (EN && DD==1 && SD==0 && ED==0 && !FULL) ( SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==0 && FULL) ( SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==1 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==0 && FULL) ( SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==1 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==0 && FULL) ( SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ // DD=2
+
+ if (EN && DD==2 && SD==0 && ED==0 && !FULL) ( SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==0 && FULL) ( SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==2 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==0 && FULL) ( SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==2 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==0 && FULL) ( SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+endspecify
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$specrule (EN_SRC, EN_DST, SRC, DST);
+
+parameter TYPE = "";
+parameter T_LIMIT = 0;
+parameter T_LIMIT2 = 0;
+
+parameter SRC_WIDTH = 1;
+parameter DST_WIDTH = 1;
+
+parameter SRC_PEN = 0;
+parameter SRC_POL = 0;
+
+parameter DST_PEN = 0;
+parameter DST_POL = 0;
+
+input EN_SRC, EN_DST;
+input [SRC_WIDTH-1:0] SRC;
+input [DST_WIDTH-1:0] DST;
+
+`ifdef SIMLIB_SPECIFY
+specify
+ // TBD
+endspecify
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
module \$assert (A, EN);
input A, EN;
@@ -1370,6 +1573,30 @@ endmodule
// --------------------------------------------------------
+module \$allconst (Y);
+
+parameter WIDTH = 0;
+
+output [WIDTH-1:0] Y;
+
+assign Y = 'bx;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$allseq (Y);
+
+parameter WIDTH = 0;
+
+output [WIDTH-1:0] Y;
+
+assign Y = 'bx;
+
+endmodule
+
+// --------------------------------------------------------
+
module \$equiv (A, B, Y);
input A, B;
@@ -1839,4 +2066,5 @@ end
endmodule
`endif
+
// --------------------------------------------------------
diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc
index 11ebe5339..a176357a7 100644
--- a/techlibs/common/synth.cc
+++ b/techlibs/common/synth.cc
@@ -29,7 +29,7 @@ struct SynthPass : public ScriptPass
{
SynthPass() : ScriptPass("synth", "generic synthesis script") { }
- virtual void help() YS_OVERRIDE
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -51,6 +51,9 @@ struct SynthPass : public ScriptPass
log(" -encfile <file>\n");
log(" passed to 'fsm_recode' via 'fsm'\n");
log("\n");
+ log(" -lut <k>\n");
+ log(" perform synthesis for a k-LUT architecture.\n");
+ log("\n");
log(" -nofsm\n");
log(" do not run FSM optimization\n");
log("\n");
@@ -64,21 +67,28 @@ struct SynthPass : public ScriptPass
log(" -nordff\n");
log(" passed to 'memory'. prohibits merging of FFs into memory read ports\n");
log("\n");
+ log(" -noshare\n");
+ log(" do not run SAT-based resource sharing\n");
+ log("\n");
log(" -run <from_label>[:<to_label>]\n");
log(" only run the commands between the labels (see below). an empty\n");
log(" from label is synonymous to 'begin', and empty to label is\n");
log(" synonymous to the end of the command list.\n");
log("\n");
+ log(" -abc9\n");
+ log(" use new ABC9 flow (EXPERIMENTAL)\n");
+ log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
- string top_module, fsm_opts, memory_opts;
- bool autotop, flatten, noalumacc, nofsm, noabc;
+ string top_module, fsm_opts, memory_opts, abc;
+ bool autotop, flatten, noalumacc, nofsm, noabc, noshare;
+ int lut;
- virtual void clear_flags() YS_OVERRIDE
+ void clear_flags() YS_OVERRIDE
{
top_module.clear();
fsm_opts.clear();
@@ -86,12 +96,15 @@ struct SynthPass : public ScriptPass
autotop = false;
flatten = false;
+ lut = 0;
noalumacc = false;
nofsm = false;
noabc = false;
+ noshare = false;
+ abc = "abc";
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
clear_flags();
@@ -126,6 +139,10 @@ struct SynthPass : public ScriptPass
flatten = true;
continue;
}
+ if (args[argidx] == "-lut") {
+ lut = atoi(args[++argidx].c_str());
+ continue;
+ }
if (args[argidx] == "-nofsm") {
nofsm = true;
continue;
@@ -142,12 +159,23 @@ struct SynthPass : public ScriptPass
memory_opts += " -nordff";
continue;
}
+ if (args[argidx] == "-noshare") {
+ noshare = true;
+ continue;
+ }
+ if (args[argidx] == "-abc9") {
+ abc = "abc9";
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
+
+ if (abc == "abc9" && !lut)
+ log_cmd_error("ABC9 flow only supported for FPGA synthesis (using '-lut' option)\n");
log_header(design, "Executing SYNTH pass.\n");
log_push();
@@ -157,7 +185,7 @@ struct SynthPass : public ScriptPass
log_pop();
}
- virtual void script() YS_OVERRIDE
+ void script() YS_OVERRIDE
{
if (check_label("begin"))
{
@@ -178,18 +206,25 @@ struct SynthPass : public ScriptPass
{
run("proc");
if (help_mode || flatten)
- run("flatten", "(if -flatten)");
+ run("flatten", " (if -flatten)");
run("opt_expr");
run("opt_clean");
run("check");
run("opt");
run("wreduce");
+ run("peepopt");
+ run("opt_clean");
+ if (help_mode)
+ run("techmap -map +/cmp2lut.v", " (if -lut)");
+ else
+ run(stringf("techmap -map +/cmp2lut.v -D LUT_WIDTH=%d", lut));
if (!noalumacc)
- run("alumacc");
- run("share");
+ run("alumacc", " (unless -noalumacc)");
+ if (!noshare)
+ run("share", " (unless -noshare)");
run("opt");
if (!nofsm)
- run("fsm" + fsm_opts);
+ run("fsm" + fsm_opts, " (unless -nofsm)");
run("opt -fast");
run("memory -nomap" + memory_opts);
run("opt_clean");
@@ -201,12 +236,33 @@ struct SynthPass : public ScriptPass
run("memory_map");
run("opt -full");
run("techmap");
+ if (help_mode)
+ {
+ run("techmap -map +/gate2lut.v", "(if -noabc and -lut)");
+ run("clean; opt_lut", " (if -noabc and -lut)");
+ }
+ else if (noabc && lut)
+ {
+ run(stringf("techmap -map +/gate2lut.v -D LUT_WIDTH=%d", lut));
+ run("clean; opt_lut");
+ }
run("opt -fast");
if (!noabc) {
#ifdef YOSYS_ENABLE_ABC
- run("abc -fast");
- run("opt -fast");
+ if (help_mode)
+ {
+ run(abc + " -fast", " (unless -noabc, unless -lut)");
+ run(abc + " -fast -lut k", "(unless -noabc, if -lut)");
+ }
+ else
+ {
+ if (lut)
+ run(stringf("%s -fast -lut %d", abc.c_str(), lut));
+ else
+ run(abc + " -fast");
+ }
+ run("opt -fast", " (unless -noabc)");
#endif
}
}