From af744097496702926f4fbff5d6eb889ad82fa6cf Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 28 Jun 2019 10:21:16 +0200 Subject: [PATCH 01/63] Improve specify dummy parser, fixes #1144 Signed-off-by: Clifford Wolf --- frontends/verilog/verilog_parser.y | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index d89b2dc88..dab5b5919 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1068,11 +1068,18 @@ list_of_path_delay_extra_expressions : path_delay_expression ',' path_delay_expression ',' path_delay_expression ; +specify_edge_identifier : + TOK_POSEDGE | TOK_NEGEDGE ; + parallel_path_description : - '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ; + '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' | + '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor opt_polarity_operator ':' ignspec_expr ')' ')' | + '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr ')' ')' ; full_path_description : - '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' ; + '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' | + '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs opt_polarity_operator ':' ignspec_expr ')' ')' | + '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs TOK_POS_INDEXED ignspec_expr ')' ')' ; // This was broken into 2 rules to solve shift/reduce conflicts list_of_path_inputs : From dc677c791de438a493ad5e0101987da29c6a6d0f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 28 Jun 2019 10:12:48 -0700 Subject: [PATCH 02/63] Add test from #1144, and try reading without '-specify' flag --- tests/various/specify.v | 14 ++++++++++++++ tests/various/specify.ys | 2 ++ 2 files changed, 16 insertions(+) diff --git a/tests/various/specify.v b/tests/various/specify.v index afc421da8..b1f399267 100644 --- a/tests/various/specify.v +++ b/tests/various/specify.v @@ -28,3 +28,17 @@ module test2 ( (B => Q) = 1.5; endspecify endmodule + +module issue01144(input clk, d, output q); +specify + // Fails: + (posedge clk => (q +: d)) = (3,1); + (/*posedge*/ clk => (q +: d)) = (3,1); + (posedge clk *> (q +: d)) = (3,1); + (/*posedge*/ clk *> (q +: d)) = (3,1); + + // Works: + (/*posedge*/ clk => q) = (3,1); + (/*posedge*/ clk *> q) = (3,1); +endspecify +endmodule diff --git a/tests/various/specify.ys b/tests/various/specify.ys index a5ca07219..a2b6038e4 100644 --- a/tests/various/specify.ys +++ b/tests/various/specify.ys @@ -54,3 +54,5 @@ equiv_struct equiv_induct -seq 5 equiv_status -assert design -reset + +read_verilog specify.v From 85f1c2dcbe1ebd3fa609f2a9a558810dfcc8484c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 29 Jun 2019 21:42:20 -0700 Subject: [PATCH 03/63] Cleanup SRL inference/make more consistent --- techlibs/xilinx/cells_map.v | 44 +++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 9a316fc96..89671c0fc 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -56,7 +56,6 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o localparam [DEPTH-1:0] INIT_R = brev(INIT); parameter _TECHMAP_CONSTMSK_L_ = 0; - parameter _TECHMAP_CONSTVAL_L_ = 0; wire CE; generate @@ -129,26 +128,33 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); end end - else if (DEPTH <= 129 && ~&_TECHMAP_CONSTMSK_L_) begin - // Handle cases where fixed-length depth is - // just 1 over a convenient value - \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); + // For fixed length, if just 1 over a convenient value, decompose + else if (DEPTH <= 129 && &_TECHMAP_CONSTMSK_L_) begin + wire T; + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-1:1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl (.C(C), .D(D), .L({32{1'b1}}), .E(E), .Q(T)); + \$__XILINX_SHREG_ #(.DEPTH(1), .INIT(INIT[0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_last (.C(C), .D(T), .L(L), .E(E), .Q(Q)); end + // For variable length, if just 1 over a convenient value, then bump up one more + else if (DEPTH < 129 && ~&_TECHMAP_CONSTMSK_L_) + \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); else begin - localparam lower_clog2 = $clog2((DEPTH+1)/2); - localparam lower_depth = 2 ** lower_clog2; - wire T0, T1, T2, T3; - if (&_TECHMAP_CONSTMSK_L_) begin - \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(lower_depth-1), .E(E), .Q(T0)); - \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-lower_depth-1), .E(E), .Q(Q), .SO(T3)); - end - else begin - \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1)); - \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3)); - assign Q = L[lower_clog2] ? T2 : T0; - end - if (DEPTH == 2 * lower_depth) - assign SO = T3; + localparam depth0 = 128; + localparam num_srl128 = DEPTH / depth0; + localparam depthN = DEPTH % depth0; + wire [num_srl128 + (depthN > 0 ? 1 : 0) - 1:0] T; + wire [num_srl128 + (depthN > 0 ? 1 : 0) :0] S; + assign S[0] = D; + genvar i; + for (i = 0; i < num_srl128; i++) + \$__XILINX_SHREG_ #(.DEPTH(depth0), .INIT(INIT[DEPTH-1-i*depth0-:depth0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl (.C(C), .D(S[i]), .L(L[$clog2(depth0)-1:0]), .E(E), .Q(T[i]), .SO(S[i+1])); + + if (depthN > 0) + \$__XILINX_SHREG_ #(.DEPTH(depthN), .INIT(INIT[depthN-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_last (.C(C), .D(S[num_srl128]), .L(L[$clog2(depth0)-1:0]), .E(E), .Q(T[num_srl128])); + + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T[num_srl128 + (depthN > 0 ? 1 : 0) - 1]; + else + assign Q = T[L[DEPTH-1:$clog2(depth0)]]; end endgenerate endmodule From 04459cb30aff2341d6de43f7eefe5acaa4bb1db1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 30 Jun 2019 11:48:01 -0700 Subject: [PATCH 04/63] Comment out invalid syntax --- tests/various/specify.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/various/specify.v b/tests/various/specify.v index b1f399267..985879f85 100644 --- a/tests/various/specify.v +++ b/tests/various/specify.v @@ -33,9 +33,9 @@ module issue01144(input clk, d, output q); specify // Fails: (posedge clk => (q +: d)) = (3,1); - (/*posedge*/ clk => (q +: d)) = (3,1); + //(/*posedge*/ clk => (q +: d)) = (3,1); // Invalid syntax (posedge clk *> (q +: d)) = (3,1); - (/*posedge*/ clk *> (q +: d)) = (3,1); + //(/*posedge*/ clk *> (q +: d)) = (3,1); // Invalid syntax // Works: (/*posedge*/ clk => q) = (3,1); From 9251c000e86c1d7e757c89720f729ac984aaf901 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 2 Jul 2019 17:10:13 +0000 Subject: [PATCH 05/63] manual: explain the purpose of `sync always`. --- manual/CHAPTER_Overview.tex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex index 1a25c477f..3009bf2c0 100644 --- a/manual/CHAPTER_Overview.tex +++ b/manual/CHAPTER_Overview.tex @@ -331,8 +331,9 @@ to update {\tt \textbackslash{}q}. An RTLIL::Process is a container for zero or more RTLIL::SyncRule objects and exactly one RTLIL::CaseRule object, which is called the {\it root case}. -An RTLIL::SyncRule object contains an (optional) synchronization condition -(signal and edge-type) and zero or more assignments (RTLIL::SigSig). +An RTLIL::SyncRule object contains an (optional) synchronization condition (signal and edge-type) and zero or +more assignments (RTLIL::SigSig). The {\tt always} synchronization condition is used to break combinatorial +loops when a latch should be inferred instead. An RTLIL::CaseRule is a container for zero or more assignments (RTLIL::SigSig) and zero or more RTLIL::SwitchRule objects. An RTLIL::SwitchRule objects is a From 9c556e3c02a8b25fbcd764e019e3870d021684ec Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 2 Jul 2019 19:13:40 -0700 Subject: [PATCH 06/63] Add test --- tests/various/abc9.v | 4 ++++ tests/various/abc9.ys | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/tests/various/abc9.v b/tests/various/abc9.v index 8271cd249..a08b613a8 100644 --- a/tests/various/abc9.v +++ b/tests/various/abc9.v @@ -3,3 +3,7 @@ initial o = 1'b0; always @* o <= ~o; endmodule + +module abc9_test028(input i, output o); +unknown u(~i, o); +endmodule diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys index 922f7005d..a84b637d9 100644 --- a/tests/various/abc9.ys +++ b/tests/various/abc9.ys @@ -1,4 +1,6 @@ read_verilog abc9.v +design -save read +hierarchy -top abc9_test027 proc design -save gold @@ -12,3 +14,11 @@ design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter +design -load read +hierarchy -top abc9_test028 +proc + +abc9 -lut 4 +select -assert-count 1 t:$lut r:LUT=1 r:WIDTH=1 %i %i +select -assert-count 1 t:unknown +select -assert-none t:$lut t:unknown %% t: %D From 10524064e94b9fe21483092e2733b1b71ae60b4e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 2 Jul 2019 19:14:30 -0700 Subject: [PATCH 07/63] write_xaiger to treat unknown cell connections as keep-s --- backends/aiger/xaiger.cc | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index eb3d47569..869b741a6 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -138,6 +138,7 @@ struct XAigerWriter { pool undriven_bits; pool unused_bits; + pool keep_bits; // promote public wires for (auto wire : module->wires()) @@ -168,6 +169,9 @@ struct XAigerWriter unused_bits.insert(bit); } + if (keep) + keep_bits.insert(bit); + if (wire->port_input || keep) { if (bit != wirebit) alias_map[bit] = wirebit; @@ -235,7 +239,7 @@ struct XAigerWriter log_assert(!holes_mode); RTLIL::Module* inst_module = module->design->module(cell->type); - if (inst_module && inst_module->attributes.count("\\abc_box_id")) { + if (inst_module && inst_module->attributes.count("\\abc_box_id")) { abc_box_seen = true; if (!holes_mode) { @@ -255,10 +259,11 @@ struct XAigerWriter } } else { + bool cell_known = cell->known(); for (const auto &c : cell->connections()) { if (c.second.is_fully_const()) continue; - auto is_input = cell->input(c.first); - auto is_output = cell->output(c.first); + auto is_input = !cell_known || cell->input(c.first); + auto is_output = !cell_known || cell->output(c.first); if (!is_input && !is_output) log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type)); @@ -266,12 +271,15 @@ struct XAigerWriter for (auto b : c.second.bits()) { Wire *w = b.wire; if (!w) continue; - if (!w->port_output) { + if (!w->port_output || !cell_known) { SigBit I = sigmap(b); if (I != b) alias_map[b] = I; output_bits.insert(b); unused_bits.erase(b); + + if (!cell_known) + keep_bits.insert(b); } } } @@ -424,7 +432,7 @@ struct XAigerWriter auto jt = input_bits.find(b); if (jt != input_bits.end()) { - log_assert(b.wire->attributes.count("\\keep")); + log_assert(keep_bits.count(O)); input_bits.erase(b); } } @@ -444,7 +452,7 @@ struct XAigerWriter // with $inout.out suffix, make it a PO driven by the existing inout, and // inherit existing inout's drivers if ((wire->port_input && wire->port_output && !undriven_bits.count(bit)) - || wire->attributes.count("\\keep")) { + || keep_bits.count(bit)) { RTLIL::IdString wire_name = wire->name.str() + "$inout.out"; RTLIL::Wire *new_wire = module->wire(wire_name); if (!new_wire) From ba365679082cff2b9879eef5349bfdf2b5291449 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 3 Jul 2019 11:22:10 +0200 Subject: [PATCH 08/63] Some cleanups in "ignore specify parser" Signed-off-by: Clifford Wolf --- frontends/verilog/verilog_parser.y | 84 ++---------------------------- tests/various/specify.v | 2 +- 2 files changed, 6 insertions(+), 80 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index dab5b5919..0fec445fa 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1021,13 +1021,8 @@ list_of_specparam_assignments: specparam_assignment: ignspec_id '=' constant_mintypmax_expression ; -/* -pulsestyle_declaration : - ; - -showcancelled_declaration : - ; -*/ +ignspec_opt_cond: + TOK_IF '(' ignspec_expr ')' | /* empty */; path_declaration : simple_path_declaration ';' @@ -1036,8 +1031,8 @@ path_declaration : ; simple_path_declaration : - parallel_path_description '=' path_delay_value | - full_path_description '=' path_delay_value + ignspec_opt_cond parallel_path_description '=' path_delay_value | + ignspec_opt_cond full_path_description '=' path_delay_value ; path_delay_value : @@ -1047,26 +1042,7 @@ path_delay_value : ; list_of_path_delay_extra_expressions : -/* - t_path_delay_expression - | trise_path_delay_expression ',' tfall_path_delay_expression - | trise_path_delay_expression ',' tfall_path_delay_expression ',' tz_path_delay_expression - | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ',' - tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression - | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ',' - tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression ',' - t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ',' - tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression -*/ - ',' path_delay_expression - | ',' path_delay_expression ',' path_delay_expression - | ',' path_delay_expression ',' path_delay_expression ',' - path_delay_expression ',' path_delay_expression ',' path_delay_expression - | ',' path_delay_expression ',' path_delay_expression ',' - path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' - path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' - path_delay_expression ',' path_delay_expression ',' path_delay_expression - ; + ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions; specify_edge_identifier : TOK_POSEDGE | TOK_NEGEDGE ; @@ -1119,56 +1095,6 @@ system_timing_args : system_timing_arg | system_timing_args ',' system_timing_arg ; -/* -t_path_delay_expression : - path_delay_expression; - -trise_path_delay_expression : - path_delay_expression; - -tfall_path_delay_expression : - path_delay_expression; - -tz_path_delay_expression : - path_delay_expression; - -t01_path_delay_expression : - path_delay_expression; - -t10_path_delay_expression : - path_delay_expression; - -t0z_path_delay_expression : - path_delay_expression; - -tz1_path_delay_expression : - path_delay_expression; - -t1z_path_delay_expression : - path_delay_expression; - -tz0_path_delay_expression : - path_delay_expression; - -t0x_path_delay_expression : - path_delay_expression; - -tx1_path_delay_expression : - path_delay_expression; - -t1x_path_delay_expression : - path_delay_expression; - -tx0_path_delay_expression : - path_delay_expression; - -txz_path_delay_expression : - path_delay_expression; - -tzx_path_delay_expression : - path_delay_expression; -*/ - path_delay_expression : ignspec_constant_expression; diff --git a/tests/various/specify.v b/tests/various/specify.v index 985879f85..73a59eb7a 100644 --- a/tests/various/specify.v +++ b/tests/various/specify.v @@ -7,7 +7,7 @@ module test ( if (EN) Q <= D; specify - if (EN) (CLK *> (Q : D)) = (1, 2:3:4); + if (EN) (posedge CLK *> (Q : D)) = (1, 2:3:4); $setup(D, posedge CLK &&& EN, 5); $hold(posedge CLK, D &&& EN, 6); endspecify From 1f173210ebbf2cd5b5714e351ed40b6141d90b14 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 3 Jul 2019 11:25:05 +0200 Subject: [PATCH 09/63] Fix tests/various/specify.v Signed-off-by: Clifford Wolf --- tests/various/specify.v | 9 ++------- tests/various/specify.ys | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/various/specify.v b/tests/various/specify.v index 73a59eb7a..5d44d78f7 100644 --- a/tests/various/specify.v +++ b/tests/various/specify.v @@ -7,9 +7,11 @@ module test ( if (EN) Q <= D; specify +`ifndef SKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS if (EN) (posedge CLK *> (Q : D)) = (1, 2:3:4); $setup(D, posedge CLK &&& EN, 5); $hold(posedge CLK, D &&& EN, 6); +`endif endspecify endmodule @@ -31,14 +33,7 @@ endmodule module issue01144(input clk, d, output q); specify - // Fails: (posedge clk => (q +: d)) = (3,1); - //(/*posedge*/ clk => (q +: d)) = (3,1); // Invalid syntax (posedge clk *> (q +: d)) = (3,1); - //(/*posedge*/ clk *> (q +: d)) = (3,1); // Invalid syntax - - // Works: - (/*posedge*/ clk => q) = (3,1); - (/*posedge*/ clk *> q) = (3,1); endspecify endmodule diff --git a/tests/various/specify.ys b/tests/various/specify.ys index a2b6038e4..00597e1e2 100644 --- a/tests/various/specify.ys +++ b/tests/various/specify.ys @@ -55,4 +55,4 @@ equiv_induct -seq 5 equiv_status -assert design -reset -read_verilog specify.v +read_verilog -DSKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS specify.v From 3a1a41bdb16c9cdf587147f8fb9dc910bcddfd26 Mon Sep 17 00:00:00 2001 From: Benedikt Tutzer Date: Thu, 4 Jul 2019 14:20:13 +0200 Subject: [PATCH 10/63] Throw runtime exception when trying to convert a c++-pointer to a python-object in case the pointer is a nullptr to avoid a segfault. Fixes #1090 --- misc/py_wrap_generator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py index 9e5727499..66d661fa1 100644 --- a/misc/py_wrap_generator.py +++ b/misc/py_wrap_generator.py @@ -779,6 +779,9 @@ class WClass: #if self.link_type != link_types.pointer: text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{" + text += "\n\t\t\tif(ref == nullptr){" + text += "\n\t\t\t\tthrow std::runtime_error(\"" + self.name + " does not exist.\");" + text += "\n\t\t\t}" text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));" if self.link_type == link_types.pointer: text += "\n\t\t\tret->ref_obj = ref;" From 4f798cda9d1b05d141e16a21b9e357de364021de Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Sun, 7 Jul 2019 16:00:38 +0100 Subject: [PATCH 11/63] synth_intel: Warn about untested Quartus backend --- techlibs/intel/synth_intel.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc index 639cba2c2..09c9ba3af 100644 --- a/techlibs/intel/synth_intel.cc +++ b/techlibs/intel/synth_intel.cc @@ -48,6 +48,8 @@ struct SynthIntelPass : public ScriptPass { log(" -vqm \n"); log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); log(" output file is omitted if this parameter is not specified.\n"); + log(" Note that this backend has not been tested and is likely incompatible\n"); + log(" with recent versions of Quartus.\n"); log("\n"); log(" -vpr \n"); log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n"); @@ -108,6 +110,7 @@ struct SynthIntelPass : public ScriptPass { } if (args[argidx] == "-vqm" && argidx + 1 < args.size()) { vout_file = args[++argidx]; + log_warning("The Quartus backend has not been tested recently and is likely incompatible with modern versions of Quartus.\n"); continue; } if (args[argidx] == "-vpr" && argidx + 1 < args.size()) { From 93bc5affd3fc635dafec3a37bf4c5b94c252036f Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jul 2019 11:34:58 +0000 Subject: [PATCH 12/63] Allow attributes on individual switch cases in RTLIL. The parser changes are slightly awkward. Consider the following IL: process $0 switch \foo case 1'1 assign \bar \baz ... case end end Before this commit, attributes are valid in , and iff it is immediately followed by a `switch`. (They are essentially attached to the switch.) But, after this commit, and because switch cases do not have an ending delimiter, becomes ambiguous: the attribute could attach to either the following `case`, or to the following `switch`. This isn't expressible in LALR(1) and results in a reduce/reduce conflict. To address this, attributes inside processes are now valid anywhere inside the process: in and a part of case body, and in as a separate rule. As a consequence, attributes can now precede `assign`s, which is made illegal in the same way it is illegal to attach attributes to `connect`. Attributes are tracked separately from the parser state, so this does not affect collection of attributes at all, other than allowing them on `case`s. The grammar change serves purely to allow attributes in more syntactic places. --- backends/ilang/ilang_backend.cc | 5 +++++ frontends/ilang/ilang_parser.y | 13 +++++++++---- kernel/rtlil.h | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc index b4ba2b03f..313af7d5c 100644 --- a/backends/ilang/ilang_backend.cc +++ b/backends/ilang/ilang_backend.cc @@ -204,6 +204,11 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { + for (auto ait = (*it)->attributes.begin(); ait != (*it)->attributes.end(); ++ait) { + f << stringf("%s attribute %s ", indent.c_str(), ait->first.c_str()); + dump_const(f, ait->second); + f << stringf("\n"); + } f << stringf("%s case ", indent.c_str()); for (size_t i = 0; i < (*it)->compare.size(); i++) { if (i > 0) diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index 44c99906a..b4b9693da 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -282,14 +282,14 @@ proc_stmt: } case_body sync_list TOK_END EOL; switch_stmt: - attr_list TOK_SWITCH sigspec EOL { + TOK_SWITCH sigspec EOL { RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; - rule->signal = *$3; + rule->signal = *$2; rule->attributes = attrbuf; switch_stack.back()->push_back(rule); attrbuf.clear(); - delete $3; - } switch_body TOK_END EOL; + delete $2; + } attr_list switch_body TOK_END EOL; attr_list: /* empty */ | @@ -298,9 +298,11 @@ attr_list: switch_body: switch_body TOK_CASE { RTLIL::CaseRule *rule = new RTLIL::CaseRule; + rule->attributes = attrbuf; switch_stack.back()->back()->cases.push_back(rule); switch_stack.push_back(&rule->switches); case_stack.push_back(rule); + attrbuf.clear(); } compare_list EOL case_body { switch_stack.pop_back(); case_stack.pop_back(); @@ -319,12 +321,15 @@ compare_list: /* empty */; case_body: + case_body attr_stmt | case_body switch_stmt | case_body assign_stmt | /* empty */; assign_stmt: TOK_ASSIGN sigspec sigspec EOL { + if (attrbuf.size() != 0) + rtlil_frontend_ilang_yyerror("dangling attribute"); case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3)); delete $2; delete $3; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f4fcf5dcf..82cbfaf28 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1327,7 +1327,7 @@ public: #endif }; -struct RTLIL::CaseRule +struct RTLIL::CaseRule : public RTLIL::AttrObject { std::vector compare; std::vector actions; From b1f400aeb8de657d5fa28c153df14246378df2b1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jul 2019 12:29:08 +0000 Subject: [PATCH 13/63] genrtlil: emit \src attribute on CaseRule. --- frontends/ast/genrtlil.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 079fc11e5..571ddd988 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -504,6 +504,7 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::CaseRule *backup_case = current_case; current_case = new RTLIL::CaseRule; + current_case->attributes["\\src"] = stringf("%s:%d", child->filename.c_str(), child->linenum); last_generated_case = current_case; addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); for (auto node : child->children) { From 55c1f4027794a89971055b705254832b189a1c83 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jul 2019 12:48:50 +0000 Subject: [PATCH 14/63] verilog_backend: dump attributes on CaseRule, as comments. Attributes are not permitted in that position by Verilog grammar. --- backends/verilog/verilog_backend.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 827af5d85..18c92521f 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -364,20 +364,22 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) } } -void dump_attributes(std::ostream &f, std::string indent, dict &attributes, char term = '\n', bool modattr = false) +void dump_attributes(std::ostream &f, std::string indent, dict &attributes, char term = '\n', bool modattr = false, bool as_comment = false) { if (noattr) return; + if (attr2comment) + as_comment = true; for (auto it = attributes.begin(); it != attributes.end(); ++it) { - f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str()); + f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str()); f << stringf(" = "); if (modattr && (it->second == Const(0, 1) || it->second == Const(0))) f << stringf(" 0 "); else if (modattr && (it->second == Const(1, 1) || it->second == Const(1))) f << stringf(" 1 "); else - dump_const(f, it->second, -1, 0, false, attr2comment); - f << stringf(" %s%c", attr2comment ? "*/" : "*)", term); + dump_const(f, it->second, -1, 0, false, as_comment); + f << stringf(" %s%c", as_comment ? "*/" : "*)", term); } } @@ -1511,7 +1513,9 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw dump_sigspec(f, (*it)->compare[i]); } } - f << stringf(":\n"); + f << stringf(":"); + dump_attributes(f, indent, (*it)->attributes, ' ', /*modattr=*/false, /*as_comment=*/true); + f << stringf("\n"); dump_case_body(f, indent + " ", *it); } @@ -1662,7 +1666,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) } } - dump_attributes(f, indent, module->attributes, '\n', true); + dump_attributes(f, indent, module->attributes, '\n', /*attr2comment=*/true); f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str()); bool keep_running = true; for (int port_id = 1; keep_running; port_id++) { From 48655dfb8b4dda7607ed7a790eb5f6bce5c27d38 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jul 2019 13:18:18 +0000 Subject: [PATCH 15/63] proc_mux: consider \src attribute on CaseRule. --- passes/proc/proc_mux.cc | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index aac0b121c..d029282fd 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -144,7 +144,13 @@ struct SnippetSwCache } }; -RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SwitchRule *sw, bool ifxmode) +void apply_attrs(RTLIL::Cell *cell, const RTLIL::SwitchRule *sw, const RTLIL::CaseRule *cs) +{ + cell->attributes = sw->attributes; + cell->add_strpool_attribute("\\src", cs->get_strpool_attribute("\\src")); +} + +RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode) { std::stringstream sstr; sstr << "$procmux$" << (autoidx++); @@ -173,7 +179,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s { // create compare cell RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), ifxmode ? "$eqx" : "$eq"); - eq_cell->attributes = sw->attributes; + apply_attrs(eq_cell, sw, cs); eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0); eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(0); @@ -199,7 +205,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s // reduce cmp vector to one logic signal RTLIL::Cell *any_cell = mod->addCell(sstr.str() + "_ANY", "$reduce_or"); - any_cell->attributes = sw->attributes; + apply_attrs(any_cell, sw, cs); any_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0); any_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cmp_wire->width); @@ -212,7 +218,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s return RTLIL::SigSpec(ctrl_wire); } -RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode) +RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode) { log_assert(when_signal.size() == else_signal.size()); @@ -224,7 +230,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s return when_signal; // compare results - RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode); + RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode); if (ctrl_sig.size() == 0) return when_signal; log_assert(ctrl_sig.size() == 1); @@ -234,7 +240,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s // create the multiplexer itself RTLIL::Cell *mux_cell = mod->addCell(sstr.str(), "$mux"); - mux_cell->attributes = sw->attributes; + apply_attrs(mux_cell, sw, cs); mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.size()); mux_cell->setPort("\\A", else_signal); @@ -246,7 +252,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s return RTLIL::SigSpec(result_wire); } -void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode) +void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode) { log_assert(last_mux_cell != NULL); log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size()); @@ -254,7 +260,7 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve if (when_signal == last_mux_cell->getPort("\\A")) return; - RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode); + RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode); log_assert(ctrl_sig.size() == 1); last_mux_cell->type = "$pmux"; @@ -395,9 +401,9 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d RTLIL::CaseRule *cs2 = sw->cases[case_idx]; RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val, ifxmode); if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1]) - append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode); + append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, cs2, ifxmode); else - result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode); + result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, cs2, ifxmode); } } From 628437b01cd37b95c020b2f4c4e2f2d8f0e9bf8b Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jul 2019 15:11:29 +0000 Subject: [PATCH 16/63] verilog_backend: dump attributes on SwitchRule. This appears to be an omission. --- backends/verilog/verilog_backend.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 18c92521f..6288502a5 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1494,6 +1494,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw return; } + dump_attributes(f, indent, sw->attributes); f << stringf("%s" "casez (", indent.c_str()); dump_sigspec(f, sw->signal); f << stringf(")\n"); From c58998a7d2c1066ea28cabe9bc6e1e52bb6668f0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 10:48:10 -0700 Subject: [PATCH 17/63] atoi -> stoi as per @daveshah1 --- techlibs/xilinx/synth_xilinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 0a30848aa..c18c3918f 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -194,7 +194,7 @@ struct SynthXilinxPass : public ScriptPass continue; } if (args[argidx] == "-widemux" && argidx+1 < args.size()) { - widemux = atoi(args[++argidx].c_str()); + widemux = std::stoi(args[++argidx]); continue; } if (args[argidx] == "-abc9") { From a34c5612e702d481798fa7fc27cf2fef06a2b544 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 10:59:12 -0700 Subject: [PATCH 18/63] Add muxcover -mux2=cost option --- passes/techmap/muxcover.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index c84cfc39a..4d9c111e7 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -631,7 +631,7 @@ struct MuxcoverPass : public Pass { log("\n"); log("Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells\n"); log("\n"); - log(" -mux4[=cost], -mux8[=cost], -mux16[=cost]\n"); + log(" -mux2=cost, -mux4[=cost], -mux8[=cost], -mux16[=cost]\n"); log(" Use the specified types of MUXes (with optional integer costs). If none\n"); log(" of these options are given, the effect is the same as if all of them are.\n"); log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4); @@ -661,6 +661,7 @@ struct MuxcoverPass : public Pass { bool nodecode = false; bool nopartial = false; int cost_dmux = COST_DMUX; + int cost_mux2 = COST_MUX2; int cost_mux4 = COST_MUX4; int cost_mux8 = COST_MUX8; int cost_mux16 = COST_MUX16; @@ -669,6 +670,10 @@ struct MuxcoverPass : public Pass { for (argidx = 1; argidx < args.size(); argidx++) { const auto &arg = args[argidx]; + if (arg.size() >= 6 && arg.substr(0,6) == "-mux2=") { + cost_mux2 = atoi(arg.substr(6).c_str()); + continue; + } if (arg.size() >= 5 && arg.substr(0,5) == "-mux4") { use_mux4 = true; if (arg.size() > 5) { @@ -722,6 +727,7 @@ struct MuxcoverPass : public Pass { worker.use_mux8 = use_mux8; worker.use_mux16 = use_mux16; worker.cost_dmux = cost_dmux; + worker.cost_mux2 = cost_mux2; worker.cost_mux4 = cost_mux4; worker.cost_mux8 = cost_mux8; worker.cost_mux16 = cost_mux16; From 3681162c8d6826cf5ccf5de485ba14b4200a5221 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 11:00:06 -0700 Subject: [PATCH 19/63] atoi -> stoi --- passes/techmap/muxcover.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index 4d9c111e7..fa97239f5 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -671,14 +671,14 @@ struct MuxcoverPass : public Pass { { const auto &arg = args[argidx]; if (arg.size() >= 6 && arg.substr(0,6) == "-mux2=") { - cost_mux2 = atoi(arg.substr(6).c_str()); + cost_mux2 = std::stoi(arg.substr(6)); continue; } if (arg.size() >= 5 && arg.substr(0,5) == "-mux4") { use_mux4 = true; if (arg.size() > 5) { if (arg[5] != '=') break; - cost_mux4 = atoi(arg.substr(6).c_str()); + cost_mux4 = std::stoi(arg.substr(6)); } continue; } @@ -686,7 +686,7 @@ struct MuxcoverPass : public Pass { use_mux8 = true; if (arg.size() > 5) { if (arg[5] != '=') break; - cost_mux8 = atoi(arg.substr(6).c_str()); + cost_mux8 = std::stoi(arg.substr(6)); } continue; } @@ -694,12 +694,12 @@ struct MuxcoverPass : public Pass { use_mux16 = true; if (arg.size() > 6) { if (arg[6] != '=') break; - cost_mux16 = atoi(arg.substr(7).c_str()); + cost_mux16 = std::stoi(arg.substr(7)); } continue; } if (arg.size() >= 6 && arg.substr(0,6) == "-dmux=") { - cost_dmux = atoi(arg.substr(6).c_str()); + cost_dmux = std::stoi(arg.substr(6)); continue; } if (arg == "-nodecode") { From dbe1326573e878f4f9d4fc80ce1afcd0f7d84ec6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 11:08:20 -0700 Subject: [PATCH 20/63] Parametric muxcover costs as per @daveshah1 --- techlibs/xilinx/synth_xilinx.cc | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index c18c3918f..f43923afb 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -280,23 +280,21 @@ struct SynthXilinxPass : public ScriptPass } else if (widemux > 0) { run("simplemap t:$mux"); - std::string muxcover_args = " -nodecode"; + constexpr int cost_mux2 = 100; + std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2); switch (widemux) { - // NB: Cost of mux2 is 100; mux8 should cost between 3 and 4 - // of those so that 4:1 muxes and below are implemented - // out of mux2s - case 5: muxcover_args += " -mux8=350 -mux16=400"; break; - case 6: muxcover_args += " -mux8=450 -mux16=500"; break; - case 7: muxcover_args += " -mux8=550 -mux16=600"; break; - case 8: muxcover_args += " -mux8=650 -mux16=700"; break; - case 9: muxcover_args += " -mux16=750"; break; - case 10: muxcover_args += " -mux16=850"; break; - case 11: muxcover_args += " -mux16=950"; break; - case 12: muxcover_args += " -mux16=1050"; break; - case 13: muxcover_args += " -mux16=1150"; break; - case 14: muxcover_args += " -mux16=1250"; break; - case 15: muxcover_args += " -mux16=1350"; break; - default: muxcover_args += " -mux16=1450"; break; + case 5: + case 6: + case 7: + case 8: muxcover_args += stringf(" -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break; + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + default: muxcover_args += stringf(" -mux16=%d", cost_mux2*(widemux-1)-1); break; } run("muxcover " + muxcover_args); } From 0944acf3affd8c6b161a2381b37eed3931c801a5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 11:29:21 -0700 Subject: [PATCH 21/63] synth_xilinx -widemux=2 is minimum now --- techlibs/xilinx/synth_xilinx.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index f43923afb..4f597de4d 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -79,7 +79,7 @@ struct SynthXilinxPass : public ScriptPass log("\n"); log(" -widemux \n"); log(" enable inference of hard multiplexer resources (MuxFx) for muxes at or\n"); - log(" above this number of inputs (minimum value 5).\n"); + log(" above this number of inputs (minimum value 2).\n"); log(" default: 0 (no inference)\n"); log("\n"); log(" -run :\n"); @@ -208,8 +208,8 @@ struct SynthXilinxPass : public ScriptPass if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6s") log_cmd_error("Invalid Xilinx -family setting: %s\n", family.c_str()); - if (widemux != 0 && widemux < 5) - log_cmd_error("-widemux value must be 0 or >= 5.\n"); + if (widemux != 0 && widemux < 2) + log_cmd_error("-widemux value must be 0 or >= 2.\n"); if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); @@ -252,7 +252,7 @@ struct SynthXilinxPass : public ScriptPass // so attempt to convert $pmux-es to the former // Also: wide multiplexer inference benefits from this too if (!(nosrl && widemux == 0) || help_mode) - run("pmux2shiftx", "(skip if '-nosrl' and '-widemux' < 5)"); + run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')"); } if (check_label("bram", "(skip if '-nobram')")) { @@ -283,6 +283,9 @@ struct SynthXilinxPass : public ScriptPass constexpr int cost_mux2 = 100; std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2); switch (widemux) { + case 2: + case 3: + case 4: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-2, cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break; case 5: case 6: case 7: From 895ca501734d2f33b61f118a288832b55a366bd2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 12:03:38 -0700 Subject: [PATCH 22/63] Fixes for 2:1 muxes --- techlibs/xilinx/cells_map.v | 33 +++++++++++++++++++++++++++++---- techlibs/xilinx/synth_xilinx.cc | 2 +- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 27e860801..e12dd2833 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -193,6 +193,14 @@ module \$__XILINX_SHIFTX (A, B, Y); else if (A_WIDTH < `MIN_MUX_INPUTS) begin wire _TECHMAP_FAIL_ = 1; end + else if (A_WIDTH == 2) begin + MUXF7 fpga_hard_mux (.I0(A[0]), .I1(A[1]), .S(B[0]), .O(Y)); + end + else if (A_WIDTH <= 2 ** 2) begin + wire [4-1:0] T; + assign T = {{(4-A_WIDTH){1'bx}}, A}; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T[0]), .I1(T[1]), .I2(T[2]), .I3(T[3]), .S0(B[0]), .S1(B[1]), .O(Y)); + end else if (A_WIDTH <= 2 ** 3) begin localparam a_width0 = 2 ** 2; localparam a_widthN = A_WIDTH - a_width0; @@ -251,15 +259,32 @@ module _90__XILINX_SHIFTX (A, B, Y); \$shiftx #(.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)); endmodule +module \$_MUX_ (A, B, S, Y); + input A, B, S; + output Y; + generate + if (`MIN_MUX_INPUTS == 2) + \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(2), .B_WIDTH(1), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({B,A}), .B(S), .Y(Y)); + else + wire _TECHMAP_FAIL_ = 1; + endgenerate +endmodule + +module \$_MUX4_ (A, B, C, D, S, T, Y); + input A, B, C, D, S, T; + output Y; + \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({D,C,B,A}), .B({T,S}), .Y(Y)); +endmodule + module \$_MUX8_ (A, B, C, D, E, F, G, H, S, T, U, Y); -input A, B, C, D, E, F, G, H, S, T, U; -output Y; + input A, B, C, D, E, F, G, H, S, T, U; + output Y; \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(3), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({H,G,F,E,D,C,B,A}), .B({U,T,S}), .Y(Y)); endmodule module \$_MUX16_ (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V, Y); -input A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V; -output Y; + input A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V; + output Y; \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(16), .B_WIDTH(4), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A}), .B({V,U,T,S}), .Y(Y)); endmodule `endif diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 4f597de4d..62bfaaaf1 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -283,7 +283,7 @@ struct SynthXilinxPass : public ScriptPass constexpr int cost_mux2 = 100; std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2); switch (widemux) { - case 2: + case 2: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2+1, cost_mux2+2, cost_mux2+3); break; case 3: case 4: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-2, cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break; case 5: From b5072256f2c6b94423adb0ac1e2aec965230afe3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 12:50:59 -0700 Subject: [PATCH 23/63] Update muxcover doc as per @ZirconiumX --- passes/techmap/muxcover.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index fa97239f5..d53378a29 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -631,11 +631,16 @@ struct MuxcoverPass : public Pass { log("\n"); log("Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells\n"); log("\n"); - log(" -mux2=cost, -mux4[=cost], -mux8[=cost], -mux16[=cost]\n"); - log(" Use the specified types of MUXes (with optional integer costs). If none\n"); - log(" of these options are given, the effect is the same as if all of them are.\n"); - log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4); - log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16); + log(" -mux4[=cost], -mux8[=cost], -mux16[=cost]\n"); + log(" Cover $_MUX_ trees using the specified types of MUXes (with optional\n"); + log(" integer costs). If none of these options are given, the effect is the\n"); + log(" same as if all of them are.\n"); + log(" Default costs: $_MUX4_ = %d, $_MUX8_ = %d, \n", COST_MUX4, COST_MUX8); + log(" $_MUX16_ = %d\n", COST_MUX16); + log("\n"); + log(" -mux2=cost\n"); + log(" Use the specified cost for $_MUX_ cells when making covering decisions.\n"); + log(" Default cost: $_MUX_ = %d\n", COST_MUX2); log("\n"); log(" -dmux=cost\n"); log(" Use the specified cost for $_MUX_ cells used in decoders.\n"); From baf47e496f35cb90e5c7181079d38c04907c42da Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 17:04:39 -0700 Subject: [PATCH 24/63] Add synth_xilinx -widemux recommended value --- techlibs/xilinx/synth_xilinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 62bfaaaf1..7836f9f3e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -79,7 +79,7 @@ struct SynthXilinxPass : public ScriptPass log("\n"); log(" -widemux \n"); log(" enable inference of hard multiplexer resources (MuxFx) for muxes at or\n"); - log(" above this number of inputs (minimum value 2).\n"); + log(" above this number of inputs (minimum value 2, recommended value >= 5).\n"); log(" default: 0 (no inference)\n"); log("\n"); log(" -run :\n"); From 78914e2e0e0a92e65cb1594c4858bc2225322ade Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 17:06:22 -0700 Subject: [PATCH 25/63] Capitalisation --- techlibs/xilinx/synth_xilinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 7836f9f3e..b404dc8e7 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -78,7 +78,7 @@ struct SynthXilinxPass : public ScriptPass log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n"); log("\n"); log(" -widemux \n"); - log(" enable inference of hard multiplexer resources (MuxFx) for muxes at or\n"); + log(" enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n"); log(" above this number of inputs (minimum value 2, recommended value >= 5).\n"); log(" default: 0 (no inference)\n"); log("\n"); From 3f86407cc32e20a8885c73f959082c5c0449bf9a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 17:06:35 -0700 Subject: [PATCH 26/63] Map $__XILINX_SHIFTX in a more balanced manner --- techlibs/xilinx/cells_map.v | 85 +++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index e12dd2833..d48a3f15c 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -197,49 +197,62 @@ module \$__XILINX_SHIFTX (A, B, Y); MUXF7 fpga_hard_mux (.I0(A[0]), .I1(A[1]), .S(B[0]), .O(Y)); end else if (A_WIDTH <= 2 ** 2) begin - wire [4-1:0] T; - assign T = {{(4-A_WIDTH){1'bx}}, A}; - \$__XILINX_MUXF78 fpga_hard_mux (.I0(T[0]), .I1(T[1]), .I2(T[2]), .I3(T[3]), .S0(B[0]), .S1(B[1]), .O(Y)); + wire [4-1:0] Ax = {{(4-A_WIDTH){A[A_WIDTH-1]}}, A}; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[1]), .I2(Ax[2]), .I3(Ax[3]), .S0(B[0]), .S1(B[1]), .O(Y)); end else if (A_WIDTH <= 2 ** 3) begin - localparam a_width0 = 2 ** 2; - localparam a_widthN = A_WIDTH - a_width0; - wire T0, T1; - \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux (.A(A[a_width0-1:0]), .B(B[2-1:0]), .Y(T0)); - if (a_widthN > 1) - \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T1)); - else - assign T1 = A[A_WIDTH-1]; - MUXF7 fpga_hard_mux (.I0(T0), .I1(T1), .S(B[2]), .O(Y)); + // Rather than extend with 1'bx which gets flattened to 1'b0 + // causing the "don't care" state to get lost, extend with MSB + // so that we can recognise again later when mapping MUXF78 + wire [8-1:0] Ax = {{(8-A_WIDTH){A[A_WIDTH-1]}}, A}; + wire T0 = B[0] ? Ax[1] : Ax[0]; + wire T1 = B[0] ? Ax[3] : Ax[2]; + wire T2 = B[0] ? Ax[5] : Ax[4]; + wire T3 = B[0] ? Ax[7] : Ax[6]; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T1), .I2(T2), .I3(T3), .S0(B[1]), .S1(B[2]), .O(Y)); end else if (A_WIDTH <= 2 ** 4) begin - localparam a_width0 = 2 ** 2; - localparam num_mux8 = A_WIDTH / a_width0; - localparam a_widthN = A_WIDTH % a_width0; - wire [a_width0-1:0] T; - for (i = 0; i < a_width0; i++) - if (i < num_mux8) - \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_mux (.A(A[i*a_width0+:a_width0]), .B(B[2-1:0]), .Y(T[i])); - else if (i == num_mux8 && a_widthN > 1) - \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_mux_last (.A(A[A_WIDTH-1-:a_widthN]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i])); - else - assign T[i] = A[A_WIDTH-1]; - \$__XILINX_MUXF78 fpga_hard_mux (.I0(T[0]), .I1(T[1]), .I2(T[2]), .I3(T[3]), .S0(B[2]), .S1(B[3]), .O(Y)); + // Rather than extend with 1'bx which gets flattened to 1'b0 + // causing the "don't care" state to get lost, extend with MSB + // so that we can recognise again later when mapping MUXF78 + wire [16-1:0] Ax = {{(16-A_WIDTH){A[A_WIDTH-1]}}, A}; + wire T0 = B[1] ? B[0] ? Ax[ 3] : Ax[ 2] + : B[0] ? Ax[ 1] : Ax[ 0]; + wire T1 = B[1] ? B[0] ? Ax[ 7] : Ax[ 6] + : B[0] ? Ax[ 5] : Ax[ 4]; + wire T2 = B[1] ? B[0] ? Ax[11] : Ax[10] + : B[0] ? Ax[ 9] : Ax[ 8]; + wire T3 = B[1] ? B[0] ? Ax[15] : Ax[14] + : B[0] ? Ax[13] : Ax[12]; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T1), .I2(T2), .I3(T3), .S0(B[2]), .S1(B[3]), .O(Y)); end else begin - localparam a_width0 = 2 ** 4; - localparam num_mux16 = A_WIDTH / a_width0; - localparam a_widthN = A_WIDTH % a_width0; - wire [num_mux16 + (a_widthN > 0 ? 1 : 0) - 1:0] T; + localparam num_mux16 = (A_WIDTH+15) / 16; + localparam clog2_num_mux16 = $clog2(num_mux16); + wire [num_mux16-1:0] T; + wire [num_mux16*16-1:0] Ax = {{(num_mux16*16-A_WIDTH){1'bx}}, A}; for (i = 0; i < num_mux16; i++) - \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(4), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux (.A(A[i*a_width0+:a_width0]), .B(B[4-1:0]), .Y(T[i])); - if (a_widthN > 0) begin - if (a_widthN > 1) - \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1-:a_widthN]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[num_mux16])); - else - assign T[num_mux16] = A[A_WIDTH-1]; - end - \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(num_mux16 + (a_widthN > 0 ? 1 : 0)), .B_WIDTH(B_WIDTH-4), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(T), .B(B[B_WIDTH-1:4]), .Y(Y)); + \$__XILINX_SHIFTX #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(16), + .B_WIDTH(4), + .Y_WIDTH(Y_WIDTH) + ) fpga_mux ( + .A(Ax[i*16+:16]), + .B(B[3:0]), + .Y(T[i]) + ); + \$__XILINX_SHIFTX #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(num_mux16), + .B_WIDTH(clog2_num_mux16), + .Y_WIDTH(Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A(T), + .B(B[B_WIDTH-1-:clog2_num_mux16]), + .Y(Y)); end endgenerate endmodule From dd9771cbcdc14366c6acc501833c6050c39251de Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 19:14:54 -0700 Subject: [PATCH 27/63] Add synth -keepdc option --- techlibs/common/synth.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 555de9fba..af70cc498 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -78,6 +78,9 @@ struct SynthPass : public ScriptPass log(" -abc9\n"); log(" use new ABC9 flow (EXPERIMENTAL)\n"); log("\n"); + log(" -keepdc\n"); + log(" do not optimize explicit don't-care values on $mux cells.\n"); + log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); @@ -85,7 +88,7 @@ struct SynthPass : public ScriptPass } string top_module, fsm_opts, memory_opts, abc; - bool autotop, flatten, noalumacc, nofsm, noabc, noshare; + bool autotop, flatten, noalumacc, nofsm, noabc, noshare, keepdc; int lut; void clear_flags() YS_OVERRIDE @@ -102,6 +105,7 @@ struct SynthPass : public ScriptPass noabc = false; noshare = false; abc = "abc"; + keepdc = false; } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -167,6 +171,10 @@ struct SynthPass : public ScriptPass abc = "abc9"; continue; } + if (args[argidx] == "-keepdc") { + keepdc = true; + continue; + } break; } extra_args(args, argidx, design); @@ -211,7 +219,10 @@ struct SynthPass : public ScriptPass run("opt_clean"); run("check"); run("opt"); - run("wreduce"); + if (help_mode) + run("wreduce [-keepdc]"); + else + run("wreduce" + std::string(keepdc ? " -keepdc" : "")); run("peepopt"); run("opt_clean"); if (help_mode) From 37b58f43242086de13fb2966d11b71efa29e7bfd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 19:15:07 -0700 Subject: [PATCH 28/63] Clarify 'wreduce -keepdc' doc --- passes/opt/wreduce.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 1fbc41082..f749c8249 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -497,7 +497,7 @@ struct WreducePass : public Pass { log(" flows that use the 'memory_memx' pass.\n"); log("\n"); log(" -keepdc\n"); - log(" Do not optimize explicit don't-care values.\n"); + log(" Do not optimize explicit don't-care values on $mux cells.\n"); log("\n"); } void execute(std::vector args, Design *design) YS_OVERRIDE From fccabd09436aae780875fae2d833f58549f38418 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 19:15:37 -0700 Subject: [PATCH 29/63] Add synth -keepdc to CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index ae7d28236..646d63a63 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ Yosys 0.9 .. Yosys 0.9-dev - Added "synth_xilinx -abc9" (experimental) - Added "synth_ice40 -abc9" (experimental) - Added "synth -abc9" (experimental) + - Added "synth -keepdc" - Added "script -scriptwire From 41d7d9d24b8ba7fd84dd72b27eb9aede10b8ef15 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 19:21:21 -0700 Subject: [PATCH 30/63] Clarify script -scriptwire doc --- kernel/yosys.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index f95c0127b..a42a7c0b8 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -1273,6 +1273,10 @@ struct ScriptCmdPass : public Pass { log("If only one label is specified (without ':') then only the block\n"); log("marked with that label (until the next label) is executed.\n"); log("\n"); + log("In \"-scriptwire\" mode, the commands on the selected wire(s) will be executed\n"); + log("in the scope of (and thus, relative to) the wires' owning module(s). This\n"); + log("'-module' mode can be exited by using the 'cd' command.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { From 7f964859ec99500e471853f5914b6e5b7c35a031 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 19:23:24 -0700 Subject: [PATCH 31/63] synth_xilinx to call "synth -run coarse" with "-keepdc" --- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index b404dc8e7..15a37a439 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -240,9 +240,9 @@ struct SynthXilinxPass : public ScriptPass if (check_label("coarse")) { if (help_mode) - run("synth -run coarse [-flatten]", "(with '-flatten')"); + run("synth -keepdc -run coarse [-flatten]", "(with '-flatten')"); else - run("synth -run coarse" + std::string(flatten ? "" : " -flatten"), "(with '-flatten')"); + run("synth -keepdc -run coarse" + std::string(flatten ? "" : " -flatten"), "(with '-flatten')"); if (widemux > 0 || help_mode) run("muxpack", " ('-widemux' only)"); From de404535538fe4d2548be82724515961e6e92519 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 22:56:19 -0700 Subject: [PATCH 32/63] Reword --- techlibs/xilinx/cells_map.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index d48a3f15c..63095880e 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -202,7 +202,7 @@ module \$__XILINX_SHIFTX (A, B, Y); end else if (A_WIDTH <= 2 ** 3) begin // Rather than extend with 1'bx which gets flattened to 1'b0 - // causing the "don't care" state to get lost, extend with MSB + // causing the "don't care" status to get lost, extend with MSB // so that we can recognise again later when mapping MUXF78 wire [8-1:0] Ax = {{(8-A_WIDTH){A[A_WIDTH-1]}}, A}; wire T0 = B[0] ? Ax[1] : Ax[0]; @@ -213,7 +213,7 @@ module \$__XILINX_SHIFTX (A, B, Y); end else if (A_WIDTH <= 2 ** 4) begin // Rather than extend with 1'bx which gets flattened to 1'b0 - // causing the "don't care" state to get lost, extend with MSB + // causing the "don't care" status to get lost, extend with MSB // so that we can recognise again later when mapping MUXF78 wire [16-1:0] Ax = {{(16-A_WIDTH){A[A_WIDTH-1]}}, A}; wire T0 = B[1] ? B[0] ? Ax[ 3] : Ax[ 2] From 939a225f921efc4276121fe957f545a98d252fa0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 23:02:57 -0700 Subject: [PATCH 33/63] Less thinking --- techlibs/xilinx/cells_map.v | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 63095880e..7c67c7a79 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -196,11 +196,11 @@ module \$__XILINX_SHIFTX (A, B, Y); else if (A_WIDTH == 2) begin MUXF7 fpga_hard_mux (.I0(A[0]), .I1(A[1]), .S(B[0]), .O(Y)); end - else if (A_WIDTH <= 2 ** 2) begin + else if (A_WIDTH <= 4) begin wire [4-1:0] Ax = {{(4-A_WIDTH){A[A_WIDTH-1]}}, A}; \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[1]), .I2(Ax[2]), .I3(Ax[3]), .S0(B[0]), .S1(B[1]), .O(Y)); end - else if (A_WIDTH <= 2 ** 3) begin + else if (A_WIDTH <= 8) begin // Rather than extend with 1'bx which gets flattened to 1'b0 // causing the "don't care" status to get lost, extend with MSB // so that we can recognise again later when mapping MUXF78 @@ -211,7 +211,7 @@ module \$__XILINX_SHIFTX (A, B, Y); wire T3 = B[0] ? Ax[7] : Ax[6]; \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T1), .I2(T2), .I3(T3), .S0(B[1]), .S1(B[2]), .O(Y)); end - else if (A_WIDTH <= 2 ** 4) begin + else if (A_WIDTH <= 16) begin // Rather than extend with 1'bx which gets flattened to 1'b0 // causing the "don't care" status to get lost, extend with MSB // so that we can recognise again later when mapping MUXF78 From d4ab43d9403899dcae74a24e71385fd959de98f8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 23:05:48 -0700 Subject: [PATCH 34/63] Add one more comment --- techlibs/xilinx/cells_map.v | 3 +++ 1 file changed, 3 insertions(+) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 7c67c7a79..39427cc90 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -197,6 +197,9 @@ module \$__XILINX_SHIFTX (A, B, Y); MUXF7 fpga_hard_mux (.I0(A[0]), .I1(A[1]), .S(B[0]), .O(Y)); end else if (A_WIDTH <= 4) begin + // Rather than extend with 1'bx which gets flattened to 1'b0 + // causing the "don't care" status to get lost, extend with MSB + // so that we can recognise again later when mapping MUXF78 wire [4-1:0] Ax = {{(4-A_WIDTH){A[A_WIDTH-1]}}, A}; \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[1]), .I2(Ax[2]), .I3(Ax[3]), .S0(B[0]), .S1(B[1]), .O(Y)); end From 45da3ada7babc8f2b23a8b23ce25430a98e2e58e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 23:49:16 -0700 Subject: [PATCH 35/63] Do not call opt -mux_undef (part of -full) before muxcover --- techlibs/xilinx/synth_xilinx.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 15a37a439..6eab74a21 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -270,7 +270,11 @@ struct SynthXilinxPass : public ScriptPass } if (check_label("fine")) { - run("opt -fast -full"); + if (widemux > 0) + run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover + // performs less efficiently + else + run("opt -fast -full"); run("memory_map"); run("dffsr2dff"); run("dff2dffe"); From 6951e3207063f66814e765d7d72e553b8b8eace1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Jul 2019 23:51:13 -0700 Subject: [PATCH 36/63] Decompose mux inputs in delay-orientated (rather than area) fashion --- techlibs/xilinx/cells_map.v | 48 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 39427cc90..35eea9858 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -200,34 +200,46 @@ module \$__XILINX_SHIFTX (A, B, Y); // Rather than extend with 1'bx which gets flattened to 1'b0 // causing the "don't care" status to get lost, extend with MSB // so that we can recognise again later when mapping MUXF78 - wire [4-1:0] Ax = {{(4-A_WIDTH){A[A_WIDTH-1]}}, A}; - \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[1]), .I2(Ax[2]), .I3(Ax[3]), .S0(B[0]), .S1(B[1]), .O(Y)); + wire [4-1:0] Ax; + if (A_WIDTH == 4) + assign Ax = A; + else + assign Ax = {A[1-:4-A_WIDTH], A}; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[2]), .I2(Ax[1]), .I3(Ax[3]), .S0(B[1]), .S1(B[0]), .O(Y)); end else if (A_WIDTH <= 8) begin // Rather than extend with 1'bx which gets flattened to 1'b0 // causing the "don't care" status to get lost, extend with MSB // so that we can recognise again later when mapping MUXF78 - wire [8-1:0] Ax = {{(8-A_WIDTH){A[A_WIDTH-1]}}, A}; - wire T0 = B[0] ? Ax[1] : Ax[0]; - wire T1 = B[0] ? Ax[3] : Ax[2]; - wire T2 = B[0] ? Ax[5] : Ax[4]; - wire T3 = B[0] ? Ax[7] : Ax[6]; - \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T1), .I2(T2), .I3(T3), .S0(B[1]), .S1(B[2]), .O(Y)); + wire [8-1:0] Ax; + if (A_WIDTH == 8) + assign Ax = A; + else + assign Ax = {A[3-:8-A_WIDTH], A}; + wire T0 = B[2] ? Ax[4] : Ax[0]; + wire T1 = B[2] ? Ax[5] : Ax[1]; + wire T2 = B[2] ? Ax[6] : Ax[2]; + wire T3 = B[2] ? Ax[7] : Ax[3]; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T1), .I3(T3), .S0(B[1]), .S1(B[0]), .O(Y)); end else if (A_WIDTH <= 16) begin // Rather than extend with 1'bx which gets flattened to 1'b0 // causing the "don't care" status to get lost, extend with MSB // so that we can recognise again later when mapping MUXF78 - wire [16-1:0] Ax = {{(16-A_WIDTH){A[A_WIDTH-1]}}, A}; - wire T0 = B[1] ? B[0] ? Ax[ 3] : Ax[ 2] - : B[0] ? Ax[ 1] : Ax[ 0]; - wire T1 = B[1] ? B[0] ? Ax[ 7] : Ax[ 6] - : B[0] ? Ax[ 5] : Ax[ 4]; - wire T2 = B[1] ? B[0] ? Ax[11] : Ax[10] - : B[0] ? Ax[ 9] : Ax[ 8]; - wire T3 = B[1] ? B[0] ? Ax[15] : Ax[14] - : B[0] ? Ax[13] : Ax[12]; - \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T1), .I2(T2), .I3(T3), .S0(B[2]), .S1(B[3]), .O(Y)); + wire [16-1:0] Ax; + if (A_WIDTH == 16) + assign Ax = A; + else + assign Ax = {A[7-:8-A_WIDTH], A}; + wire T0 = B[2] ? B[3] ? Ax[12] : Ax[4] + : B[3] ? Ax[ 8] : Ax[0]; + wire T1 = B[2] ? B[3] ? Ax[13] : Ax[5] + : B[3] ? Ax[ 9] : Ax[1]; + wire T2 = B[2] ? B[3] ? Ax[14] : Ax[6] + : B[3] ? Ax[10] : Ax[2]; + wire T3 = B[2] ? B[3] ? Ax[15] : Ax[7] + : B[3] ? Ax[11] : Ax[3]; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T1), .I3(T3), .S0(B[1]), .S1(B[0]), .O(Y)); end else begin localparam num_mux16 = (A_WIDTH+15) / 16; From f7a14a56780fedfc38a104f46b801b84fa357d01 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 9 Jul 2019 08:57:57 +0000 Subject: [PATCH 37/63] proc_clean: add -quiet option. This is useful for other passes that call it often, like bugpoint. --- passes/proc/proc_clean.cc | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc index 52141a8ec..97f4c6573 100644 --- a/passes/proc/proc_clean.cc +++ b/passes/proc/proc_clean.cc @@ -143,7 +143,7 @@ void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int m YOSYS_NAMESPACE_END PRIVATE_NAMESPACE_BEGIN -void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count) +void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count, bool quiet) { int count = 0; bool did_something = true; @@ -160,7 +160,7 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count) did_something = false; proc_clean_case(&proc->root_case, did_something, count, -1); } - if (count > 0) + if (count > 0 && !quiet) log("Found and cleaned up %d empty switch%s in `%s.%s'.\n", count, count == 1 ? "" : "es", mod->name.c_str(), proc->name.c_str()); total_count += count; } @@ -171,7 +171,10 @@ struct ProcCleanPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" proc_clean [selection]\n"); + log(" proc_clean [options] [selection]\n"); + log("\n"); + log(" -quiet\n"); + log(" do not print any messages.\n"); log("\n"); log("This pass removes empty parts of processes and ultimately removes a process\n"); log("if it contains only empty structures.\n"); @@ -180,9 +183,20 @@ struct ProcCleanPass : public Pass { void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { int total_count = 0; - log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n"); + bool quiet = false; - extra_args(args, 1, design); + if (find(args.begin(), args.end(), "-quiet") == args.end()) + log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-quiet") { + quiet = true; + continue; + } + } + extra_args(args, argidx, design); for (auto mod : design->modules()) { std::vector delme; @@ -191,10 +205,11 @@ struct ProcCleanPass : public Pass { for (auto &proc_it : mod->processes) { if (!design->selected(mod, proc_it.second)) continue; - proc_clean(mod, proc_it.second, total_count); + proc_clean(mod, proc_it.second, total_count, quiet); if (proc_it.second->syncs.size() == 0 && proc_it.second->root_case.switches.size() == 0 && proc_it.second->root_case.actions.size() == 0) { - log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str()); + if (!quiet) + log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str()); delme.push_back(proc_it.first); } } @@ -204,7 +219,8 @@ struct ProcCleanPass : public Pass { } } - log("Cleaned up %d empty switch%s.\n", total_count, total_count == 1 ? "" : "es"); + if (!quiet) + log("Cleaned up %d empty switch%s.\n", total_count, total_count == 1 ? "" : "es"); } } ProcCleanPass; From f2fb958d44bada70859ef2c4db9076e27da643e7 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 9 Jul 2019 09:08:38 +0000 Subject: [PATCH 38/63] bugpoint: add -assigns and -updates options. --- passes/cmds/bugpoint.cc | 90 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 9 deletions(-) diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc index 038ab7c7c..5a47988ec 100644 --- a/passes/cmds/bugpoint.cc +++ b/passes/cmds/bugpoint.cc @@ -51,14 +51,14 @@ struct BugpointPass : public Pass { log(" only consider crashes that place this string in the log file.\n"); log("\n"); log(" -fast\n"); - log(" run `clean -purge` after each minimization step. converges faster, but\n"); - log(" produces larger testcases, and may fail to produce any testcase at all if\n"); - log(" the crash is related to dangling wires.\n"); + log(" run `proc_clean; clean -purge` after each minimization step. converges\n"); + log(" faster, but produces larger testcases, and may fail to produce any\n"); + log(" testcase at all if the crash is related to dangling wires.\n"); log("\n"); log(" -clean\n"); - log(" run `clean -purge` before checking testcase and after finishing. produces\n"); - log(" smaller and more useful testcases, but may fail to produce any testcase\n"); - log(" at all if the crash is related to dangling wires.\n"); + log(" run `proc_clean; clean -purge` before checking testcase and after\n"); + log(" finishing. produces smaller and more useful testcases, but may fail to\n"); + log(" produce any testcase at all if the crash is related to dangling wires.\n"); log("\n"); log(" -modules\n"); log(" try to remove modules.\n"); @@ -72,6 +72,12 @@ struct BugpointPass : public Pass { log(" -connections\n"); log(" try to reconnect ports to 'x.\n"); log("\n"); + log(" -assigns\n"); + log(" try to remove process assigns from cases.\n"); + log("\n"); + log(" -updates\n"); + log(" try to remove process updates from syncs.\n"); + log("\n"); } bool run_yosys(RTLIL::Design *design, string yosys_cmd, string script) @@ -110,6 +116,7 @@ struct BugpointPass : public Pass { RTLIL::Design *design_copy = new RTLIL::Design; for (auto &it : design->modules_) design_copy->add(it.second->clone()); + Pass::call(design_copy, "proc_clean -quiet"); Pass::call(design_copy, "clean -purge"); if (do_delete) @@ -117,7 +124,7 @@ struct BugpointPass : public Pass { return design_copy; } - RTLIL::Design *simplify_something(RTLIL::Design *design, int &seed, bool stage2, bool modules, bool ports, bool cells, bool connections) + RTLIL::Design *simplify_something(RTLIL::Design *design, int &seed, bool stage2, bool modules, bool ports, bool cells, bool connections, bool assigns, bool updates) { RTLIL::Design *design_copy = new RTLIL::Design; for (auto &it : design->modules_) @@ -225,6 +232,59 @@ struct BugpointPass : public Pass { } } } + if (assigns) + { + for (auto mod : design_copy->modules()) + { + if (mod->get_blackbox_attribute()) + continue; + + for (auto &pr : mod->processes) + { + vector cases = {&pr.second->root_case}; + while (!cases.empty()) + { + RTLIL::CaseRule *cs = cases[0]; + cases.erase(cases.begin()); + for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) + { + if (index++ == seed) + { + log("Trying to remove assign %s %s in %s.%s.\n", log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str()); + cs->actions.erase(it); + return design_copy; + } + } + for (auto &sw : cs->switches) + cases.insert(cases.end(), sw->cases.begin(), sw->cases.end()); + } + } + } + } + if (updates) + { + for (auto mod : design_copy->modules()) + { + if (mod->get_blackbox_attribute()) + continue; + + for (auto &pr : mod->processes) + { + for (auto &sy : pr.second->syncs) + { + for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) + { + if (index++ == seed) + { + log("Trying to remove sync %s update %s %s in %s.%s.\n", log_signal(sy->signal), log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str()); + sy->actions.erase(it); + return design_copy; + } + } + } + } + } + } return NULL; } @@ -232,7 +292,7 @@ struct BugpointPass : public Pass { { string yosys_cmd = "yosys", script, grep; bool fast = false, clean = false; - bool modules = false, ports = false, cells = false, connections = false, has_part = false; + bool modules = false, ports = false, cells = false, connections = false, assigns = false, updates = false, has_part = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -277,6 +337,16 @@ struct BugpointPass : public Pass { has_part = true; continue; } + if (args[argidx] == "-assigns") { + assigns = true; + has_part = true; + continue; + } + if (args[argidx] == "-updates") { + updates = true; + has_part = true; + continue; + } break; } extra_args(args, argidx, design); @@ -290,6 +360,8 @@ struct BugpointPass : public Pass { ports = true; cells = true; connections = true; + assigns = true; + updates = true; } if (!design->full_selection()) @@ -305,7 +377,7 @@ struct BugpointPass : public Pass { bool found_something = false, stage2 = false; while (true) { - if (RTLIL::Design *simplified = simplify_something(crashing_design, seed, stage2, modules, ports, cells, connections)) + if (RTLIL::Design *simplified = simplify_something(crashing_design, seed, stage2, modules, ports, cells, connections, assigns, updates)) { simplified = clean_design(simplified, fast, /*do_delete=*/true); From 5fe0ffe30f315d50b2405c2d436ad8e7ca9ba2f6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jul 2019 15:19:01 +0000 Subject: [PATCH 39/63] proc_prune: new pass. The proc_prune pass is similar in nature to proc_rmdead pass: while proc_rmdead removes branches that never become active because another branch preempts it, proc_prune removes assignments that never become active because another assignment preempts them. Genrtlil contains logic similar to the proc_prune pass, but their purpose is different: genrtlil has to prune assignments to adapt the semantics of blocking assignments in HDLs (latest assignment wins) to semantics of assignments in RTLIL processes (assignment in the most specific case wins). On the other hand proc_prune is a general purpose RTLIL simplification that benefits all frontends, even those not using the Yosys AST library. The proc_prune pass is added to the proc script after proc_rmdead, since it gives better results with fewer branches. --- passes/proc/Makefile.inc | 2 +- passes/proc/proc.cc | 2 + passes/proc/proc_prune.cc | 135 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 passes/proc/proc_prune.cc diff --git a/passes/proc/Makefile.inc b/passes/proc/Makefile.inc index 397fe46a1..4b56979f8 100644 --- a/passes/proc/Makefile.inc +++ b/passes/proc/Makefile.inc @@ -1,5 +1,6 @@ OBJS += passes/proc/proc.o +OBJS += passes/proc/proc_prune.o OBJS += passes/proc/proc_clean.o OBJS += passes/proc/proc_rmdead.o OBJS += passes/proc/proc_init.o @@ -7,4 +8,3 @@ OBJS += passes/proc/proc_arst.o OBJS += passes/proc/proc_mux.o OBJS += passes/proc/proc_dlatch.o OBJS += passes/proc/proc_dff.o - diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc index ef7cb0f71..a5b4a3112 100644 --- a/passes/proc/proc.cc +++ b/passes/proc/proc.cc @@ -37,6 +37,7 @@ struct ProcPass : public Pass { log("\n"); log(" proc_clean\n"); log(" proc_rmdead\n"); + log(" proc_prune\n"); log(" proc_init\n"); log(" proc_arst\n"); log(" proc_mux\n"); @@ -83,6 +84,7 @@ struct ProcPass : public Pass { Pass::call(design, "proc_clean"); if (!ifxmode) Pass::call(design, "proc_rmdead"); + Pass::call(design, "proc_prune"); Pass::call(design, "proc_init"); if (global_arst.empty()) Pass::call(design, "proc_arst"); diff --git a/passes/proc/proc_prune.cc b/passes/proc/proc_prune.cc new file mode 100644 index 000000000..7222d414d --- /dev/null +++ b/passes/proc/proc_prune.cc @@ -0,0 +1,135 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2019 whitequark + * + * 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. + * + */ + +#include "kernel/register.h" +#include "kernel/sigtools.h" +#include "kernel/log.h" +#include +#include + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct PruneWorker +{ + RTLIL::Module *module; + SigMap sigmap; + + int count = 0; + + PruneWorker(RTLIL::Module *mod) : module(mod), sigmap(mod) {} + + pool do_switch(RTLIL::SwitchRule *sw, pool assigned) + { + pool all_assigned; + bool full_case = sw->get_bool_attribute("\\full_case"); + bool first = true; + for (auto it : sw->cases) { + if (it->compare.empty()) + full_case = true; + pool case_assigned = do_case(it, assigned); + if (first) { + first = false; + all_assigned = case_assigned; + } else { + for (auto &bit : all_assigned) + if (!case_assigned[bit]) + all_assigned.erase(bit); + } + } + if (full_case) + assigned.insert(all_assigned.begin(), all_assigned.end()); + return assigned; + } + + pool do_case(RTLIL::CaseRule *cs, pool assigned) + { + for (auto it = cs->switches.rbegin(); it != cs->switches.rend(); ++it) { + pool sw_assigned = do_switch((*it), assigned); + assigned.insert(sw_assigned.begin(), sw_assigned.end()); + } + pool remove; + for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ++it) { + RTLIL::SigSpec lhs = sigmap(it->first); + bool redundant = true; + for (auto &bit : lhs) { + if (bit.wire && !assigned[bit]) { + redundant = false; + break; + } + } + if (redundant) + remove.insert(*it); + else { + for (auto &bit : lhs) + if (bit.wire) + assigned.insert(bit); + } + } + for (auto it = cs->actions.begin(); it != cs->actions.end(); ) { + if (remove[*it]) { + it = cs->actions.erase(it); + count++; + } else it++; + } + return assigned; + } + + void do_process(RTLIL::Process *pr) + { + do_case(&pr->root_case, {}); + } +}; + +struct ProcPrunePass : public Pass { + ProcPrunePass() : Pass("proc_prune", "remove redundant assignments") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" proc_prune [selection]\n"); + log("\n"); + log("This pass identifies assignments in processes that are always overwritten by\n"); + log("a later assignment to the same signal and removes them.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + int total_count = 0; + log_header(design, "Executing PROC_PRUNE pass (remove redundant assignments in processes).\n"); + + extra_args(args, 1, design); + + for (auto mod : design->modules()) { + if (!design->selected(mod)) + continue; + PruneWorker worker(mod); + for (auto &proc_it : mod->processes) { + if (!design->selected(mod, proc_it.second)) + continue; + worker.do_process(proc_it.second); + } + total_count += worker.count; + } + + log("Removed %d redundant assignment%s.\n", total_count, total_count == 1 ? "" : "s"); + } +} ProcPrunePass; + +PRIVATE_NAMESPACE_END From 44bcb7a187ffa00921cb14fa50428ce272ce3b6b Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 9 Jul 2019 08:14:52 +0000 Subject: [PATCH 40/63] proc_prune: promote assigns to module connections when legal. This can pave the way for further transformations by exposing identities that were previously hidden in a process to any pass that uses SigMap. Indeed, this commit removes some ad-hoc logic from proc_init that appears to have been tailored to the output of genrtlil in favor of using `SigMap.apply()`. (This removal is not optional, as the ad-hoc logic cannot cope with the result of running proc_prune; a similar issue was fixed in proc_arst.) --- passes/proc/proc_arst.cc | 2 +- passes/proc/proc_init.cc | 26 +++++----------------- passes/proc/proc_prune.cc | 47 +++++++++++++++++++++++++++++---------- 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc index b69eba3f9..d069f152a 100644 --- a/passes/proc/proc_arst.cc +++ b/passes/proc/proc_arst.cc @@ -172,7 +172,7 @@ restart_proc_arst: sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0; } for (auto &action : sync->actions) { - RTLIL::SigSpec rspec = action.second; + RTLIL::SigSpec rspec = assign_map(action.second); RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size()); for (int i = 0; i < GetSize(rspec); i++) if (rspec[i].wire == NULL) diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc index e2dc07e53..462a384b7 100644 --- a/passes/proc/proc_init.cc +++ b/passes/proc/proc_init.cc @@ -26,21 +26,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule) -{ - log_assert(rule.compare.size() == 0); - - while (1) { - RTLIL::SigSpec tmp = sig; - for (auto &it : rule.actions) - tmp.replace(it.first, it.second); - if (tmp == sig) - break; - sig = tmp; - } -} - -void proc_init(RTLIL::Module *mod, RTLIL::Process *proc) +void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc) { bool found_init = false; @@ -53,9 +39,7 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc) for (auto &action : sync->actions) { RTLIL::SigSpec lhs = action.first; - RTLIL::SigSpec rhs = action.second; - - proc_get_const(rhs, proc->root_case); + RTLIL::SigSpec rhs = sigmap(action.second); if (!rhs.is_fully_const()) log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs)); @@ -120,10 +104,12 @@ struct ProcInitPass : public Pass { extra_args(args, 1, design); for (auto mod : design->modules()) - if (design->selected(mod)) + if (design->selected(mod)) { + SigMap sigmap(mod); for (auto &proc_it : mod->processes) if (design->selected(mod, proc_it.second)) - proc_init(mod, proc_it.second); + proc_init(mod, sigmap, proc_it.second); + } } } ProcInitPass; diff --git a/passes/proc/proc_prune.cc b/passes/proc/proc_prune.cc index 7222d414d..9e00b0a8a 100644 --- a/passes/proc/proc_prune.cc +++ b/passes/proc/proc_prune.cc @@ -31,11 +31,11 @@ struct PruneWorker RTLIL::Module *module; SigMap sigmap; - int count = 0; + int removed_count = 0, promoted_count = 0; PruneWorker(RTLIL::Module *mod) : module(mod), sigmap(mod) {} - pool do_switch(RTLIL::SwitchRule *sw, pool assigned) + pool do_switch(RTLIL::SwitchRule *sw, pool assigned, pool &affected) { pool all_assigned; bool full_case = sw->get_bool_attribute("\\full_case"); @@ -43,7 +43,7 @@ struct PruneWorker for (auto it : sw->cases) { if (it->compare.empty()) full_case = true; - pool case_assigned = do_case(it, assigned); + pool case_assigned = do_case(it, assigned, affected); if (first) { first = false; all_assigned = case_assigned; @@ -58,10 +58,11 @@ struct PruneWorker return assigned; } - pool do_case(RTLIL::CaseRule *cs, pool assigned) + pool do_case(RTLIL::CaseRule *cs, pool assigned, pool &affected, + bool root = false) { for (auto it = cs->switches.rbegin(); it != cs->switches.rend(); ++it) { - pool sw_assigned = do_switch((*it), assigned); + pool sw_assigned = do_switch((*it), assigned, affected); assigned.insert(sw_assigned.begin(), sw_assigned.end()); } pool remove; @@ -74,18 +75,35 @@ struct PruneWorker break; } } - if (redundant) + if (redundant) { + removed_count++; remove.insert(*it); - else { + } else { + if (root) { + bool promotable = true; + for (auto &bit : lhs) { + if (bit.wire && affected[bit]) { + promotable = false; + break; + } + } + if (promotable) { + promoted_count++; + module->connect(*it); + remove.insert(*it); + } + } for (auto &bit : lhs) if (bit.wire) assigned.insert(bit); + for (auto &bit : lhs) + if (bit.wire) + affected.insert(bit); } } for (auto it = cs->actions.begin(); it != cs->actions.end(); ) { if (remove[*it]) { it = cs->actions.erase(it); - count++; } else it++; } return assigned; @@ -93,7 +111,8 @@ struct PruneWorker void do_process(RTLIL::Process *pr) { - do_case(&pr->root_case, {}); + pool affected; + do_case(&pr->root_case, {}, affected, /*root=*/true); } }; @@ -111,7 +130,7 @@ struct ProcPrunePass : public Pass { } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - int total_count = 0; + int total_removed_count = 0, total_promoted_count = 0; log_header(design, "Executing PROC_PRUNE pass (remove redundant assignments in processes).\n"); extra_args(args, 1, design); @@ -125,10 +144,14 @@ struct ProcPrunePass : public Pass { continue; worker.do_process(proc_it.second); } - total_count += worker.count; + total_removed_count += worker.removed_count; + total_promoted_count += worker.promoted_count; } - log("Removed %d redundant assignment%s.\n", total_count, total_count == 1 ? "" : "s"); + log("Removed %d redundant assignment%s.\n", + total_removed_count, total_removed_count == 1 ? "" : "s"); + log("Promoted %d assignment%s to connection%s.\n", + total_promoted_count, total_promoted_count == 1 ? "" : "s", total_promoted_count == 1 ? "" : "s"); } } ProcPrunePass; From 667199d46013d116bdbeb9be8592a77503a470e2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 09:16:00 -0700 Subject: [PATCH 41/63] Fix spacing --- techlibs/xilinx/synth_xilinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 6eab74a21..abdf7f9cc 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -287,7 +287,7 @@ struct SynthXilinxPass : public ScriptPass constexpr int cost_mux2 = 100; std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2); switch (widemux) { - case 2: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2+1, cost_mux2+2, cost_mux2+3); break; + case 2: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2+1, cost_mux2+2, cost_mux2+3); break; case 3: case 4: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-2, cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break; case 5: From bc84f7dd10ad44118fd6d800cb7a896069fd223d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 09:22:12 -0700 Subject: [PATCH 42/63] Fix spacing --- techlibs/xilinx/synth_xilinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index abdf7f9cc..2a77ce397 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -270,7 +270,7 @@ struct SynthXilinxPass : public ScriptPass } if (check_label("fine")) { - if (widemux > 0) + if (widemux > 0) run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover // performs less efficiently else From 5a0f2e43c796ed91693d60261bd75a489f778a3a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 09:35:09 -0700 Subject: [PATCH 43/63] Rename __builtin_bswap32 -> bswap32 --- backends/aiger/xaiger.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 869b741a6..69f63486c 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -21,13 +21,15 @@ // https://stackoverflow.com/a/46137633 #ifdef _MSC_VER #include -#define __builtin_bswap32 _byteswap_ulong +#define bswap32 _byteswap_ulong #elif defined(__APPLE__) #include -#define __builtin_bswap32 OSSwapInt32 -#elif !defined(__GNUC__) +#define bswap32 OSSwapInt32 +#elif defined(__GNUC__) +#define bswap32 __builtin_bswap32 +#else #include -inline uint32_t __builtin_bswap32(uint32_t x) +inline static uint32_t bswap32(uint32_t x) { // https://stackoverflow.com/a/27796212 register uint32_t value = number_to_be_reversed; From 713337255e6ab57b0679d64539d5c87d036c067f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 10:14:23 -0700 Subject: [PATCH 44/63] Revert "Add "synth -keepdc" option" --- CHANGELOG | 1 - passes/opt/wreduce.cc | 2 +- techlibs/common/synth.cc | 15 ++------------- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 646d63a63..ae7d28236 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,7 +12,6 @@ Yosys 0.9 .. Yosys 0.9-dev - Added "synth_xilinx -abc9" (experimental) - Added "synth_ice40 -abc9" (experimental) - Added "synth -abc9" (experimental) - - Added "synth -keepdc" - Added "script -scriptwire diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index f749c8249..1fbc41082 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -497,7 +497,7 @@ struct WreducePass : public Pass { log(" flows that use the 'memory_memx' pass.\n"); log("\n"); log(" -keepdc\n"); - log(" Do not optimize explicit don't-care values on $mux cells.\n"); + log(" Do not optimize explicit don't-care values.\n"); log("\n"); } void execute(std::vector args, Design *design) YS_OVERRIDE diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index af70cc498..555de9fba 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -78,9 +78,6 @@ struct SynthPass : public ScriptPass log(" -abc9\n"); log(" use new ABC9 flow (EXPERIMENTAL)\n"); log("\n"); - log(" -keepdc\n"); - log(" do not optimize explicit don't-care values on $mux cells.\n"); - log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); @@ -88,7 +85,7 @@ struct SynthPass : public ScriptPass } string top_module, fsm_opts, memory_opts, abc; - bool autotop, flatten, noalumacc, nofsm, noabc, noshare, keepdc; + bool autotop, flatten, noalumacc, nofsm, noabc, noshare; int lut; void clear_flags() YS_OVERRIDE @@ -105,7 +102,6 @@ struct SynthPass : public ScriptPass noabc = false; noshare = false; abc = "abc"; - keepdc = false; } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -171,10 +167,6 @@ struct SynthPass : public ScriptPass abc = "abc9"; continue; } - if (args[argidx] == "-keepdc") { - keepdc = true; - continue; - } break; } extra_args(args, argidx, design); @@ -219,10 +211,7 @@ struct SynthPass : public ScriptPass run("opt_clean"); run("check"); run("opt"); - if (help_mode) - run("wreduce [-keepdc]"); - else - run("wreduce" + std::string(keepdc ? " -keepdc" : "")); + run("wreduce"); run("peepopt"); run("opt_clean"); if (help_mode) From 737340327fd8bae4a3b958d85cb14eecb767ed67 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 10:15:02 -0700 Subject: [PATCH 45/63] Revert "synth_xilinx to call "synth -run coarse" with "-keepdc"" This reverts commit 7f964859ec99500e471853f5914b6e5b7c35a031. --- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 2a77ce397..8da6df57e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -240,9 +240,9 @@ struct SynthXilinxPass : public ScriptPass if (check_label("coarse")) { if (help_mode) - run("synth -keepdc -run coarse [-flatten]", "(with '-flatten')"); + run("synth -run coarse [-flatten]", "(with '-flatten')"); else - run("synth -keepdc -run coarse" + std::string(flatten ? "" : " -flatten"), "(with '-flatten')"); + run("synth -run coarse" + std::string(flatten ? "" : " -flatten"), "(with '-flatten')"); if (widemux > 0 || help_mode) run("muxpack", " ('-widemux' only)"); From c68b9092100280dbc059526a88f9d8e2902ff6a3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 10:21:54 -0700 Subject: [PATCH 46/63] synth_xilinx to call commands of synth -coarse directly --- techlibs/xilinx/synth_xilinx.cc | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 8da6df57e..0152af481 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -239,10 +239,25 @@ struct SynthXilinxPass : public ScriptPass } if (check_label("coarse")) { + run("proc"); + if (help_mode || flatten) + run("flatten", "(if -flatten)"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); if (help_mode) - run("synth -run coarse [-flatten]", "(with '-flatten')"); + run("wreduce [-keepdc]", "(option for '-widemux')"); else - run("synth -run coarse" + std::string(flatten ? "" : " -flatten"), "(with '-flatten')"); + run("wreduce" + std::string(widemux > 0 ? " -keepdc" : "")); + run("peepopt"); + run("opt_clean"); + run("alumacc"); + run("share"); + run("opt"); + run("fsm"); + run("opt -fast"); + run("memory -nomap"); if (widemux > 0 || help_mode) run("muxpack", " ('-widemux' only)"); @@ -253,6 +268,8 @@ struct SynthXilinxPass : public ScriptPass // Also: wide multiplexer inference benefits from this too if (!(nosrl && widemux == 0) || help_mode) run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')"); + + run("opt_clean"); } if (check_label("bram", "(skip if '-nobram')")) { @@ -344,7 +361,7 @@ struct SynthXilinxPass : public ScriptPass if (check_label("map_luts")) { run("opt_expr -mux_undef"); if (help_mode) - run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(skip if 'nowidelut', only for '-retime')"); + run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut', option for '-retime')"); else if (abc9) { if (family != "xc7") log_warning("'synth_xilinx -abc9' currently supports '-family xc7' only.\n"); From c8649953431d3789296c4a7c1bd559ec136af6e3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 10:38:07 -0700 Subject: [PATCH 47/63] Fix typo and comments --- techlibs/xilinx/cells_map.v | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index d3f6a60cc..233a56003 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -204,7 +204,7 @@ module \$__XILINX_SHIFTX (A, B, Y); end else if (A_WIDTH <= 4) begin // Rather than extend with 1'bx which gets flattened to 1'b0 - // causing the "don't care" status to get lost, extend with MSB + // causing the "don't care" status to get lost, extend with MSBs // so that we can recognise again later when mapping MUXF78 wire [4-1:0] Ax; if (A_WIDTH == 4) @@ -215,7 +215,7 @@ module \$__XILINX_SHIFTX (A, B, Y); end else if (A_WIDTH <= 8) begin // Rather than extend with 1'bx which gets flattened to 1'b0 - // causing the "don't care" status to get lost, extend with MSB + // causing the "don't care" status to get lost, extend with MSBs // so that we can recognise again later when mapping MUXF78 wire [8-1:0] Ax; if (A_WIDTH == 8) @@ -230,13 +230,13 @@ module \$__XILINX_SHIFTX (A, B, Y); end else if (A_WIDTH <= 16) begin // Rather than extend with 1'bx which gets flattened to 1'b0 - // causing the "don't care" status to get lost, extend with MSB + // causing the "don't care" status to get lost, extend with MSBs // so that we can recognise again later when mapping MUXF78 wire [16-1:0] Ax; if (A_WIDTH == 16) assign Ax = A; else - assign Ax = {A[7-:8-A_WIDTH], A}; + assign Ax = {A[7-:16-A_WIDTH], A}; wire T0 = B[2] ? B[3] ? Ax[12] : Ax[4] : B[3] ? Ax[ 8] : Ax[0]; wire T1 = B[2] ? B[3] ? Ax[13] : Ax[5] From 93522b0ae15466297e45edecf55f7e33c4ebcc1c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 10:59:37 -0700 Subject: [PATCH 48/63] Extend during mux decomposition with 1'bx --- techlibs/xilinx/cells_map.v | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 233a56003..e81ff8f53 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -203,25 +203,11 @@ module \$__XILINX_SHIFTX (A, B, Y); MUXF7 fpga_hard_mux (.I0(A[0]), .I1(A[1]), .S(B[0]), .O(Y)); end else if (A_WIDTH <= 4) begin - // Rather than extend with 1'bx which gets flattened to 1'b0 - // causing the "don't care" status to get lost, extend with MSBs - // so that we can recognise again later when mapping MUXF78 - wire [4-1:0] Ax; - if (A_WIDTH == 4) - assign Ax = A; - else - assign Ax = {A[1-:4-A_WIDTH], A}; + wire [4-1:0] Ax = {{{4-A_WIDTH}{1'bx}}, A}; \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[2]), .I2(Ax[1]), .I3(Ax[3]), .S0(B[1]), .S1(B[0]), .O(Y)); end else if (A_WIDTH <= 8) begin - // Rather than extend with 1'bx which gets flattened to 1'b0 - // causing the "don't care" status to get lost, extend with MSBs - // so that we can recognise again later when mapping MUXF78 - wire [8-1:0] Ax; - if (A_WIDTH == 8) - assign Ax = A; - else - assign Ax = {A[3-:8-A_WIDTH], A}; + wire [8-1:0] Ax = {{{8-A_WIDTH}{1'bx}}, A}; wire T0 = B[2] ? Ax[4] : Ax[0]; wire T1 = B[2] ? Ax[5] : Ax[1]; wire T2 = B[2] ? Ax[6] : Ax[2]; @@ -229,14 +215,7 @@ module \$__XILINX_SHIFTX (A, B, Y); \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T1), .I3(T3), .S0(B[1]), .S1(B[0]), .O(Y)); end else if (A_WIDTH <= 16) begin - // Rather than extend with 1'bx which gets flattened to 1'b0 - // causing the "don't care" status to get lost, extend with MSBs - // so that we can recognise again later when mapping MUXF78 - wire [16-1:0] Ax; - if (A_WIDTH == 16) - assign Ax = A; - else - assign Ax = {A[7-:16-A_WIDTH], A}; + wire [16-1:0] Ax = {{{16-A_WIDTH}{1'bx}}, A}; wire T0 = B[2] ? B[3] ? Ax[12] : Ax[4] : B[3] ? Ax[ 8] : Ax[0]; wire T1 = B[2] ? B[3] ? Ax[13] : Ax[5] From f8512864cd2b9c0c17d71d4196dbf3f25ec554d1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 9 Jul 2019 20:58:01 +0200 Subject: [PATCH 49/63] Add tests/simple_abc9/.gitignore Signed-off-by: Clifford Wolf --- tests/simple_abc9/.gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/simple_abc9/.gitignore diff --git a/tests/simple_abc9/.gitignore b/tests/simple_abc9/.gitignore new file mode 100644 index 000000000..598951333 --- /dev/null +++ b/tests/simple_abc9/.gitignore @@ -0,0 +1,3 @@ +*.v +*.log +*.out From 3dd92fcd15bc3f1448a97e6bb7c997d36781b55c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 9 Jul 2019 20:58:28 +0200 Subject: [PATCH 50/63] Improve tests/various/run-test.sh Signed-off-by: Clifford Wolf --- tests/various/run-test.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh index d49553ede..92b905765 100755 --- a/tests/various/run-test.sh +++ b/tests/various/run-test.sh @@ -4,11 +4,9 @@ for x in *.ys; do echo "Running $x.." ../../yosys -ql ${x%.ys}.log $x done -# Run any .sh files in this directory (with the exception of the file - run-test.sh -shell_tests=$(echo *.sh | sed -e 's/run-test.sh//') -if [ "$shell_tests" ]; then - for s in $shell_tests; do - echo "Running $s.." - bash $s - done -fi +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "Running $s.." + bash $s + fi +done From c18b23f0559f2232186ce3b97b4ffb64877abd5c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 9 Jul 2019 20:58:59 +0200 Subject: [PATCH 51/63] Add tests/various/async.{sh,v} Signed-off-by: Clifford Wolf --- tests/various/async.sh | 6 ++++ tests/various/async.v | 82 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 tests/various/async.sh create mode 100644 tests/various/async.v diff --git a/tests/various/async.sh b/tests/various/async.sh new file mode 100644 index 000000000..423034eb8 --- /dev/null +++ b/tests/various/async.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -ex +../../yosys -q -o async_syn.v -p 'synth; rename uut syn' async.v +iverilog -o async_sim -DTESTBENCH async.v async_syn.v +vvp -N async_sim > async.out +rm -f async_syn.v async_sim async.out async.vcd diff --git a/tests/various/async.v b/tests/various/async.v new file mode 100644 index 000000000..229b5b939 --- /dev/null +++ b/tests/various/async.v @@ -0,0 +1,82 @@ +`define MAXQ 2 +module uut ( + input clk, + input d, r, e, + output [`MAXQ:0] q +); + reg q0; + always @(posedge clk) begin + if (r) + q0 <= 0; + else if (e) + q0 <= d; + end + + reg q1; + always @(posedge clk, posedge r) begin + if (r) + q1 <= 0; + else if (e) + q1 <= d; + end + + reg q2; + always @(posedge clk, negedge r) begin + if (!r) + q2 <= 0; + else if (!e) + q2 <= d; + end + + assign q = {q2, q1, q0}; +endmodule + +`ifdef TESTBENCH +module testbench; + reg clk; + always #5 clk = (clk === 1'b0); + + reg d, r, e; + + wire [`MAXQ:0] q_uut; + uut uut (.clk(clk), .d(d), .r(r), .e(e), .q(q_uut)); + + wire [`MAXQ:0] q_syn; + syn syn (.clk(clk), .d(d), .r(r), .e(e), .q(q_syn)); + + task printq; + reg [5*8-1:0] msg; + begin + msg = "OK"; + if (q_uut != q_syn) msg = "SYN"; + $display("%6t %b %b %s", $time, q_uut, q_syn, msg); + if (msg != "OK") $stop; + end + endtask + + initial if(0) begin + $dumpfile("async.vcd"); + $dumpvars(0, testbench); + end + + initial begin + @(posedge clk); + d <= 0; + r <= 0; + e <= 0; + @(posedge clk); + e <= 1; + @(posedge clk); + e <= 0; + repeat (10000) begin + @(posedge clk); + printq; + d <= $random; + r <= $random; + e <= $random; + end + $display("OK"); + $finish; + end +endmodule +`endif From c2db70f41e2697d141439c093813ae48f3b7a5d4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 12:14:00 -0700 Subject: [PATCH 52/63] Increment _TECHMAP_BITS_CONNMAP_ by one since counting from zero --- passes/techmap/techmap.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index ab0bd3b54..ceb053825 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -649,10 +649,13 @@ struct TechmapWorker unique_bit_id[bit] = unique_bit_id_counter++; } + // Find highest bit set int bits = 0; for (int i = 0; i < 32; i++) if (((unique_bit_id_counter-1) & (1 << i)) != 0) bits = i; + // Increment index by one to get number of bits + bits++; if (tpl->avail_parameters.count("\\_TECHMAP_BITS_CONNMAP_")) parameters["\\_TECHMAP_BITS_CONNMAP_"] = bits; From 37bb6b5e96fcedc1126c31aac84b8c029e192f5f Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 9 Jul 2019 19:14:03 +0000 Subject: [PATCH 53/63] write_verilog: fix placement of case attributes. NFC. --- backends/verilog/verilog_backend.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 6288502a5..087c6fec6 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1501,6 +1501,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw bool got_default = false; for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { + dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*as_comment=*/true); if ((*it)->compare.size() == 0) { if (got_default) continue; @@ -1514,9 +1515,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw dump_sigspec(f, (*it)->compare[i]); } } - f << stringf(":"); - dump_attributes(f, indent, (*it)->attributes, ' ', /*modattr=*/false, /*as_comment=*/true); - f << stringf("\n"); + f << stringf(":\n"); dump_case_body(f, indent + " ", *it); } From b1a048a703b12bc02433d8c2c98b4b35cc799979 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 12:35:41 -0700 Subject: [PATCH 54/63] Extend using A[1] to preserve don't care --- techlibs/xilinx/cells_map.v | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index e81ff8f53..f20fe253e 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -203,7 +203,15 @@ module \$__XILINX_SHIFTX (A, B, Y); MUXF7 fpga_hard_mux (.I0(A[0]), .I1(A[1]), .S(B[0]), .O(Y)); end else if (A_WIDTH <= 4) begin - wire [4-1:0] Ax = {{{4-A_WIDTH}{1'bx}}, A}; + wire [4-1:0] Ax; + if (A_WIDTH == 4) + assign Ax = A; + else + // Rather than extend with 1'bx which gets flattened to 1'b0 + // causing the "don't care" status to get lost, extend with + // the same driver of F7B.I0 so that we can optimise F7B away + // later + assign Ax = {A[1], A}; \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[2]), .I2(Ax[1]), .I3(Ax[3]), .S0(B[1]), .S1(B[0]), .O(Y)); end else if (A_WIDTH <= 8) begin From 513862148211401fe71fb7966c81773042665acd Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 9 Jul 2019 22:21:25 +0200 Subject: [PATCH 55/63] Improve tests/various/async, disable failing ffl test Signed-off-by: Clifford Wolf --- tests/various/async.sh | 9 +++++++-- tests/various/async.v | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/tests/various/async.sh b/tests/various/async.sh index 423034eb8..7c41d6d94 100644 --- a/tests/various/async.sh +++ b/tests/various/async.sh @@ -1,6 +1,11 @@ #!/bin/bash set -ex ../../yosys -q -o async_syn.v -p 'synth; rename uut syn' async.v -iverilog -o async_sim -DTESTBENCH async.v async_syn.v +../../yosys -q -o async_prp.v -p 'prep; rename uut prp' async.v +../../yosys -q -o async_a2s.v -p 'prep; async2sync; rename uut a2s' async.v +../../yosys -q -o async_ffl.v -p 'prep; clk2fflogic; rename uut ffl' async.v +iverilog -o async_sim -DTESTBENCH async.v async_???.v vvp -N async_sim > async.out -rm -f async_syn.v async_sim async.out async.vcd +tail async.out +grep PASS async.out +rm -f async_???.v async_sim async.out async.vcd diff --git a/tests/various/async.v b/tests/various/async.v index 229b5b939..1e32a06b5 100644 --- a/tests/various/async.v +++ b/tests/various/async.v @@ -32,9 +32,23 @@ module uut ( endmodule `ifdef TESTBENCH +module \$ff #( + parameter integer WIDTH = 1 +) ( + input [WIDTH-1:0] D, + output reg [WIDTH-1:0] Q +); + wire sysclk = testbench.sysclk; + always @(posedge sysclk) + Q <= D; +endmodule + module testbench; + reg sysclk; + always #5 sysclk = (sysclk === 1'b0); + reg clk; - always #5 clk = (clk === 1'b0); + always @(posedge sysclk) clk = (clk === 1'b0); reg d, r, e; @@ -44,13 +58,25 @@ module testbench; wire [`MAXQ:0] q_syn; syn syn (.clk(clk), .d(d), .r(r), .e(e), .q(q_syn)); + wire [`MAXQ:0] q_prp; + prp prp (.clk(clk), .d(d), .r(r), .e(e), .q(q_prp)); + + wire [`MAXQ:0] q_a2s; + a2s a2s (.clk(clk), .d(d), .r(r), .e(e), .q(q_a2s)); + + wire [`MAXQ:0] q_ffl; + ffl ffl (.clk(clk), .d(d), .r(r), .e(e), .q(q_ffl)); + task printq; reg [5*8-1:0] msg; begin msg = "OK"; - if (q_uut != q_syn) msg = "SYN"; - $display("%6t %b %b %s", $time, q_uut, q_syn, msg); - if (msg != "OK") $stop; + if (q_uut !== q_syn) msg = "SYN"; + if (q_uut !== q_prp) msg = "PRP"; + if (q_uut !== q_a2s) msg = "A2S"; + // if (q_uut !== q_ffl) msg = "FFL"; + $display("%6t %b %b %b %b %b %s", $time, q_uut, q_syn, q_prp, q_a2s, q_ffl, msg); + if (msg != "OK") $finish; end endtask @@ -75,7 +101,7 @@ module testbench; r <= $random; e <= $random; end - $display("OK"); + $display("PASS"); $finish; end endmodule From 9546ccdbd348b1dc056884a536246801cdf1c4f1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 9 Jul 2019 22:44:39 +0200 Subject: [PATCH 56/63] Fix tests/various/async FFL test Signed-off-by: Clifford Wolf --- passes/sat/clk2fflogic.cc | 7 +++++++ tests/various/async.v | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc index 49ec795d3..4bb4aa047 100644 --- a/passes/sat/clk2fflogic.cc +++ b/passes/sat/clk2fflogic.cc @@ -253,6 +253,13 @@ struct Clk2fflogicPass : public Pass { SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge); Const rstval = cell->parameters["\\ARST_VALUE"]; + Wire *past_arst = module->addWire(NEW_ID); + module->addFf(NEW_ID, arst, past_arst); + if (cell->parameters["\\ARST_POLARITY"].as_bool()) + arst = module->LogicOr(NEW_ID, arst, past_arst); + else + arst = module->LogicAnd(NEW_ID, arst, past_arst); + if (cell->parameters["\\ARST_POLARITY"].as_bool()) module->addMux(NEW_ID, qval, rstval, arst, sig_q); else diff --git a/tests/various/async.v b/tests/various/async.v index 1e32a06b5..c27e30c4b 100644 --- a/tests/various/async.v +++ b/tests/various/async.v @@ -74,7 +74,7 @@ module testbench; if (q_uut !== q_syn) msg = "SYN"; if (q_uut !== q_prp) msg = "PRP"; if (q_uut !== q_a2s) msg = "A2S"; - // if (q_uut !== q_ffl) msg = "FFL"; + if (q_uut !== q_ffl) msg = "FFL"; $display("%6t %b %b %b %b %b %s", $time, q_uut, q_syn, q_prp, q_a2s, q_ffl, msg); if (msg != "OK") $finish; end From 27b27b8781ab8d57aa85a432aba7e914570feffb Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 9 Jul 2019 22:26:10 +0100 Subject: [PATCH 57/63] synth_ecp5: Fix typo in copyright header Signed-off-by: David Shah --- techlibs/ecp5/synth_ecp5.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index f16a47f01..3b0c2ea9e 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -2,7 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf - * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above From 5b48b18d29dabfaa3aa51fc4946f14b0ea8954e2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 14:28:54 -0700 Subject: [PATCH 58/63] Restore missing techmap -map +/cmp2lut.v with LUT_WIDTH=6 --- techlibs/xilinx/synth_xilinx.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 0152af481..7e10a392a 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -2,6 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf + * (C) 2019 Eddie Hung * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -252,6 +253,7 @@ struct SynthXilinxPass : public ScriptPass run("wreduce" + std::string(widemux > 0 ? " -keepdc" : "")); run("peepopt"); run("opt_clean"); + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6"); run("alumacc"); run("share"); run("opt"); From c55530b90197302e7c27eb106094fa74a178fc67 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 14:29:58 -0700 Subject: [PATCH 59/63] Restore opt_clean back to original place --- techlibs/xilinx/synth_xilinx.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 7e10a392a..c4877c8af 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -260,6 +260,7 @@ struct SynthXilinxPass : public ScriptPass run("fsm"); run("opt -fast"); run("memory -nomap"); + run("opt_clean"); if (widemux > 0 || help_mode) run("muxpack", " ('-widemux' only)"); @@ -270,8 +271,6 @@ struct SynthXilinxPass : public ScriptPass // Also: wide multiplexer inference benefits from this too if (!(nosrl && widemux == 0) || help_mode) run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')"); - - run("opt_clean"); } if (check_label("bram", "(skip if '-nobram')")) { From e573d024a257a6cf8925784f6f22d192a1f24693 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 9 Jul 2019 21:26:38 -0700 Subject: [PATCH 60/63] Call muxpack and pmux2shiftx before cmp2lut --- techlibs/xilinx/synth_xilinx.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index c4877c8af..ef7660288 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -253,14 +253,6 @@ struct SynthXilinxPass : public ScriptPass run("wreduce" + std::string(widemux > 0 ? " -keepdc" : "")); run("peepopt"); run("opt_clean"); - run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6"); - run("alumacc"); - run("share"); - run("opt"); - run("fsm"); - run("opt -fast"); - run("memory -nomap"); - run("opt_clean"); if (widemux > 0 || help_mode) run("muxpack", " ('-widemux' only)"); @@ -269,8 +261,19 @@ struct SynthXilinxPass : public ScriptPass // cells for identifying variable-length shift registers, // so attempt to convert $pmux-es to the former // Also: wide multiplexer inference benefits from this too - if (!(nosrl && widemux == 0) || help_mode) + if (!(nosrl && widemux == 0) || help_mode) { run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')"); + run("clean", " (skip if '-nosrl' and '-widemux=0')"); + } + + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6"); + run("alumacc"); + run("share"); + run("opt"); + run("fsm"); + run("opt -fast"); + run("memory -nomap"); + run("opt_clean"); } if (check_label("bram", "(skip if '-nobram')")) { From 521971e32ef54fa64474a8ed1c2748572901aaf5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Jul 2019 12:20:04 -0700 Subject: [PATCH 61/63] Add some ASCII art explaining mux decomposition --- techlibs/xilinx/cells_map.v | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index f20fe253e..82399be08 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -214,6 +214,27 @@ module \$__XILINX_SHIFTX (A, B, Y); assign Ax = {A[1], A}; \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[2]), .I2(Ax[1]), .I3(Ax[3]), .S0(B[1]), .S1(B[0]), .O(Y)); end + // Note that the following decompositions are 'backwards' in that + // the LSBs are placed on the hard resources, and the soft resources + // are used for MSBs. + // This has the effect of more effectively utilising the hard mux; + // take for example a 5:1 multiplexer, currently this would map as: + // + // A[0] \___ __ A[0] \__ __ + // A[4] / \| \ whereas the more A[1] / \| \ + // A[1] _____| | obvious mapping A[2] \___| | + // A[2] _____| |-- of MSBs to hard A[3] / | |__ + // A[3]______| | resources would A[4] ____| | + // |__/ lead to: 1'bx ____| | + // || |__/ + // || || + // B[1:0] B[1:2] + // + // Expectation would be that the 'forward' mapping (right) is more + // area efficient (consider a 9:1 multiplexer using 2x4:1 multiplexers + // on its I0 and I1 inputs, and A[8] and 1'bx on its I2 and I3 inputs) + // but that the 'backwards' mapping (left) is more delay efficient + // since smaller LUTs are faster than wider ones. else if (A_WIDTH <= 8) begin wire [8-1:0] Ax = {{{8-A_WIDTH}{1'bx}}, A}; wire T0 = B[2] ? Ax[4] : Ax[0]; From 58bb84e5b22ba66310fd54fecdbf5817138a5fd1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Jul 2019 12:32:33 -0700 Subject: [PATCH 62/63] Add some spacing --- techlibs/xilinx/cells_map.v | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 82399be08..2eb9fa2c1 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -220,15 +220,15 @@ module \$__XILINX_SHIFTX (A, B, Y); // This has the effect of more effectively utilising the hard mux; // take for example a 5:1 multiplexer, currently this would map as: // - // A[0] \___ __ A[0] \__ __ - // A[4] / \| \ whereas the more A[1] / \| \ - // A[1] _____| | obvious mapping A[2] \___| | - // A[2] _____| |-- of MSBs to hard A[3] / | |__ - // A[3]______| | resources would A[4] ____| | - // |__/ lead to: 1'bx ____| | - // || |__/ - // || || - // B[1:0] B[1:2] + // A[0] \___ __ A[0] \__ __ + // A[4] / \| \ whereas the more A[1] / \| \ + // A[1] _____| | obvious mapping A[2] \___| | + // A[2] _____| |-- of MSBs to hard A[3] / | |__ + // A[3]______| | resources would A[4] ____| | + // |__/ lead to: 1'bx ____| | + // || |__/ + // || || + // B[1:0] B[1:2] // // Expectation would be that the 'forward' mapping (right) is more // area efficient (consider a 9:1 multiplexer using 2x4:1 multiplexers From 6bbd286e033ed25bb49684316a86d6227dec4cd7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Jul 2019 12:47:48 -0700 Subject: [PATCH 63/63] Error out if -abc9 and -retime specified --- techlibs/ecp5/synth_ecp5.cc | 3 +++ techlibs/ice40/synth_ice40.cc | 5 ++++- techlibs/xilinx/synth_xilinx.cc | 13 ++++++++----- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 3b0c2ea9e..9f409ca51 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -199,6 +199,9 @@ struct SynthEcp5Pass : public ScriptPass if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); + if (abc9 && retime) + log_cmd_error("-retime option not currently compatible with -abc9!\n"); + log_header(design, "Executing SYNTH_ECP5 pass.\n"); log_push(); diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 9dd5d81f7..2c75215cb 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -227,6 +227,9 @@ struct SynthIce40Pass : public ScriptPass if (device_opt != "hx" && device_opt != "lp" && device_opt !="u") log_cmd_error("Invalid or no device specified: '%s'\n", device_opt.c_str()); + if (abc == "abc9" && retime) + log_cmd_error("-retime option not currently compatible with -abc9!\n"); + log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); @@ -296,7 +299,7 @@ struct SynthIce40Pass : public ScriptPass run("techmap"); else run("techmap -map +/techmap.v -map +/ice40/arith_map.v"); - if ((retime || help_mode) && abc != "abc9") + if (retime || help_mode) run(abc + " -dff", "(only if -retime)"); run("ice40_opt"); } diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index b7c32d2e0..22c4a1a1b 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -25,8 +25,8 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -#define XC7_WIRE_DELAY "300" // Number with which ABC will map a 6-input gate - // to one LUT6 (instead of a LUT5 + LUT2) +#define XC7_WIRE_DELAY 300 // Number with which ABC will map a 6-input gate + // to one LUT6 (instead of a LUT5 + LUT2) struct SynthXilinxPass : public ScriptPass { @@ -195,11 +195,14 @@ struct SynthXilinxPass : public ScriptPass extra_args(args, argidx, design); if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6s") - log_cmd_error("Invalid Xilinx -family setting: %s\n", family.c_str()); + log_cmd_error("Invalid Xilinx -family setting: '%s'.\n", family.c_str()); if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); + if (abc9 && retime) + log_cmd_error("-retime option not currently compatible with -abc9!\n"); + log_header(design, "Executing SYNTH_XILINX pass.\n"); log_push(); @@ -297,9 +300,9 @@ struct SynthXilinxPass : public ScriptPass if (family != "xc7") log_warning("'synth_xilinx -abc9' currently supports '-family xc7' only.\n"); if (nowidelut) - run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::string(XC7_WIRE_DELAY) + string(retime ? " -dff" : "")); + run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY)); else - run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::string(XC7_WIRE_DELAY) + string(retime ? " -dff" : "")); + run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY)); } else { if (nowidelut)