From d855683917b42555c1e3472e71c957335574655c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 26 Apr 2019 16:53:16 -0700 Subject: [PATCH 01/41] Revert synth_xilinx 'fine' label more to how it used to be... --- techlibs/xilinx/synth_xilinx.cc | 61 +++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 58dd928a0..45ad1c465 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -108,23 +108,23 @@ struct SynthXilinxPass : public Pass log(" techmap -map +/xilinx/drams_map.v\n"); log("\n"); log(" fine:\n"); - log(" opt -fast\n"); + log(" opt -fast -full\n"); log(" memory_map\n"); log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" techmap -map +/xilinx/arith_map.v\n"); + log(" pmux2shiftx (without '-nosrl' only)\n"); + log(" opt -full\n"); + log(" techmap\n"); + log(" opt -fast\n"); + log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); log(" opt -fast\n"); log("\n"); log(" map_cells:\n"); - log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n"); - log(" pmux2shiftx (without '-nosrl' only)\n"); - log(" opt_expr -mux_undef (without '-nosrl' only)\n"); - log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); log(" techmap -map +/xilinx/cells_map.v\n"); log(" clean\n"); log("\n"); log(" map_luts:\n"); - log(" opt -full\n"); log(" techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n"); log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); log(" clean\n"); @@ -262,9 +262,30 @@ struct SynthXilinxPass : public Pass } } + log(" fine:\n"); + log(" opt -fast -full\n"); + log(" memory_map\n"); + log(" dffsr2dff\n"); + log(" dff2dffe\n"); + log(" techmap -map +/xilinx/arith_map.v\n"); + log(" pmux2shiftx (without '-nosrl' only)\n"); + log(" opt -full\n"); + log(" techmap\n"); + log(" opt -fast\n"); + log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); + log(" opt -fast\n"); + log("\n"); + log(" map_cells:\n"); + log(" techmap -map +/xilinx/cells_map.v\n"); + log(" clean\n"); + log("\n"); + log(" map_luts:\n"); + log(" techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n"); + + if (check_label(active, run_from, run_to, "fine")) { - Pass::call(design, "opt -fast"); + Pass::call(design, "opt -fast -full"); Pass::call(design, "memory_map"); Pass::call(design, "dffsr2dff"); Pass::call(design, "dff2dffe"); @@ -275,25 +296,24 @@ struct SynthXilinxPass : public Pass Pass::call(design, "techmap -map +/xilinx/arith_map.v"); } + Pass::call(design, "opt -full"); + Pass::call(design, "techmap"); + Pass::call(design, "opt -fast"); + + // shregmap -tech xilinx can cope with $shiftx and $mux + // cells for identifiying variable-length shift registers, + // so attempt to convert $pmux-es to the former + if (!nosrl) + Pass::call(design, "pmux2shiftx"); + Pass::call(design, "opt -fast"); } if (check_label(active, run_from, run_to, "map_cells")) { - if (!nosrl) { - // shregmap operates on bit-level flops, not word-level, - // so break those down here - Pass::call(design, "simplemap t:$dff t:$dffe"); - // shregmap -tech xilinx can cope with $shiftx and $mux - // cells for identifiying variable-length shift registers, - // so attempt to convert $pmux-es to the former - Pass::call(design, "pmux2shiftx"); - // pmux2shiftx can leave behind a $pmux with a single entry - // -- need this to clean that up before shregmap - Pass::call(design, "opt_expr -mux_undef"); - // shregmap with '-tech xilinx' infers variable length shift regs + // shregmap with '-tech xilinx' infers variable length shift regs + if (!nosrl) Pass::call(design, "shregmap -tech xilinx -minlen 3"); - } Pass::call(design, "techmap -map +/xilinx/cells_map.v"); Pass::call(design, "clean"); @@ -301,7 +321,6 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "map_luts")) { - Pass::call(design, "opt -full"); Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v"); Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); From af840bbc63a9a82a9c4e2c24476c70659efee63f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 28 Apr 2019 12:36:04 -0700 Subject: [PATCH 02/41] Move neg-pol to pos-pol mapping from ff_map to cells_map.v --- techlibs/xilinx/cells_map.v | 8 ++++++++ techlibs/xilinx/ff_map.v | 13 ++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 704ab21b1..b29238a12 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -17,6 +17,14 @@ * */ +// Convert negative-polarity reset to positive-polarity +module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule + + module \$__SHREG_ (input C, input D, input E, output Q); parameter DEPTH = 0; parameter [DEPTH-1:0] INIT = 0; diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v index c61fd7070..13beaa6ae 100644 --- a/techlibs/xilinx/ff_map.v +++ b/techlibs/xilinx/ff_map.v @@ -22,26 +22,21 @@ `ifndef _NO_FFS -`ifndef _NO_POS_SR module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule +module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule -`endif - -module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule - -module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -`endif `endif From e97178a888cebc6acacb8f8f2c68d4f9743a9284 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 28 Apr 2019 12:51:00 -0700 Subject: [PATCH 03/41] WIP --- techlibs/xilinx/synth_xilinx.cc | 60 +++++++++++++-------------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 45ad1c465..ba9efc658 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -113,12 +113,14 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" techmap -map +/xilinx/arith_map.v\n"); - log(" pmux2shiftx (without '-nosrl' only)\n"); log(" opt -full\n"); - log(" techmap\n"); - log(" opt -fast\n"); + log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n"); + log(" pmux2shiftx (without '-nosrl' only)\n"); + log(" opt_expr -mux_undef (without '-nosrl' only)\n"); log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); log(" opt -fast\n"); + log(" techmap\n"); + log(" opt -fast\n"); log("\n"); log(" map_cells:\n"); log(" techmap -map +/xilinx/cells_map.v\n"); @@ -262,29 +264,15 @@ struct SynthXilinxPass : public Pass } } - log(" fine:\n"); - log(" opt -fast -full\n"); - log(" memory_map\n"); - log(" dffsr2dff\n"); - log(" dff2dffe\n"); - log(" techmap -map +/xilinx/arith_map.v\n"); - log(" pmux2shiftx (without '-nosrl' only)\n"); - log(" opt -full\n"); - log(" techmap\n"); - log(" opt -fast\n"); - log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); - log(" opt -fast\n"); - log("\n"); - log(" map_cells:\n"); - log(" techmap -map +/xilinx/cells_map.v\n"); - log(" clean\n"); - log("\n"); - log(" map_luts:\n"); - log(" techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n"); - - if (check_label(active, run_from, run_to, "fine")) { + if (!nosrl) { + // shregmap -tech xilinx can cope with $shiftx and $mux + // cells for identifiying variable-length shift registers, + // so attempt to convert $pmux-es to the former + Pass::call(design, "pmux2shiftx"); + } + Pass::call(design, "opt -fast -full"); Pass::call(design, "memory_map"); Pass::call(design, "dffsr2dff"); @@ -297,31 +285,29 @@ struct SynthXilinxPass : public Pass } Pass::call(design, "opt -full"); + + if (!nosrl) { + // shregmap operates on bit-level flops, not word-level, + // so break those down here + Pass::call(design, "simplemap t:$dff t:$dffe"); + Pass::call(design, "show -format pdf -prefix show *depth=3*"); + // shregmap with '-tech xilinx' infers variable length shift regs + Pass::call(design, "shregmap -tech xilinx -minlen 3"); + Pass::call(design, "opt -fast"); + } + Pass::call(design, "techmap"); Pass::call(design, "opt -fast"); - - // shregmap -tech xilinx can cope with $shiftx and $mux - // cells for identifiying variable-length shift registers, - // so attempt to convert $pmux-es to the former - if (!nosrl) - Pass::call(design, "pmux2shiftx"); - - Pass::call(design, "opt -fast"); } if (check_label(active, run_from, run_to, "map_cells")) { - // shregmap with '-tech xilinx' infers variable length shift regs - if (!nosrl) - Pass::call(design, "shregmap -tech xilinx -minlen 3"); - Pass::call(design, "techmap -map +/xilinx/cells_map.v"); Pass::call(design, "clean"); } if (check_label(active, run_from, run_to, "map_luts")) { - Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v"); Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); // This shregmap call infers fixed length shift registers after abc From acafcdc94dc148b2bf9c8faef173e5b2b54e1ac5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 28 Apr 2019 13:04:34 -0700 Subject: [PATCH 04/41] Copy with 1'bx padding in $shiftx --- passes/techmap/shregmap.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index a541b33be..75eedfbcc 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -178,7 +178,17 @@ struct ShregmapTechXilinx7 : ShregmapTech // Only map if $shiftx exclusively covers the shift register if (shiftx->type == "$shiftx") { - if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) + if (GetSize(taps) > shiftx->getParam("\\A_WIDTH").as_int()) + return false; + // Due to padding the most significant bits of A may be 1'bx, + // and if so, discount them + if (GetSize(taps) < shiftx->getParam("\\A_WIDTH").as_int()) { + const SigSpec A = shiftx->getPort("\\A"); + const int A_width = shiftx->getParam("\\A_WIDTH").as_int(); + for (int i = GetSize(taps); i < A_width; ++i) + if (A[i] != RTLIL::Sx) return false; + } + else if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) return false; } else if (shiftx->type == "$mux") { From 32881a989c2eb2cc73e224e6dc20dc3949f90e55 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 26 Apr 2019 16:38:36 +0200 Subject: [PATCH 05/41] Support multiple pmg files (right now just concatenated together) Signed-off-by: Clifford Wolf --- passes/pmgen/pmgen.py | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index d9747b065..edc1ad7fe 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -3,14 +3,34 @@ import re import sys import pprint +import getopt pp = pprint.PrettyPrinter(indent=4) -pmgfile = sys.argv[1] -assert pmgfile.endswith(".pmg") -prefix = pmgfile[0:-4] -prefix = prefix.split('/')[-1] -outfile = sys.argv[2] +prefix = None +pmgfiles = list() +outfile = None + +opts, args = getopt.getopt(sys.argv[1:], "p:o:") + +for o, a in opts: + if o == "-p": + prefix = o + elif o == "-o": + outfile = a + +if outfile is None: + outfile = args[-1] + args = args[0:-1] + +for a in args: + assert a.endswith(".pmg") + if prefix is None and len(args) == 1: + prefix = a[0:-4] + prefix = prefix.split('/')[-1] + pmgfiles.append(a) + +assert prefix is not None state_types = dict() udata_types = dict() @@ -77,7 +97,7 @@ def rewrite_cpp(s): return "".join(t) -with open(pmgfile, "r") as f: +def process_pmgfile(f): while True: line = f.readline() if line == "": break @@ -180,6 +200,10 @@ with open(pmgfile, "r") as f: blocks.append(block) +for fn in pmgfiles: + with open(fn, "r") as f: + process_pmgfile(f) + with open(outfile, "w") as f: print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) print("", file=f) From 9f792c599db0cc466444d58e3c675711deb6349b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 29 Apr 2019 13:02:05 +0200 Subject: [PATCH 06/41] Add pmgen support for multiple patterns in one matcher Signed-off-by: Clifford Wolf --- passes/pmgen/ice40_dsp.cc | 114 +++++++++++---------- passes/pmgen/ice40_dsp.pmg | 2 + passes/pmgen/pmgen.py | 202 +++++++++++++++++++++++-------------- 3 files changed, 188 insertions(+), 130 deletions(-) diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 3a054a463..36ba1dabe 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -26,40 +26,42 @@ PRIVATE_NAMESPACE_BEGIN void create_ice40_dsp(ice40_dsp_pm &pm) { + auto &st = pm.st_ice40_dsp; + #if 0 log("\n"); - log("ffA: %s\n", log_id(pm.st.ffA, "--")); - log("ffB: %s\n", log_id(pm.st.ffB, "--")); - log("mul: %s\n", log_id(pm.st.mul, "--")); - log("ffY: %s\n", log_id(pm.st.ffY, "--")); - log("addAB: %s\n", log_id(pm.st.addAB, "--")); - log("muxAB: %s\n", log_id(pm.st.muxAB, "--")); - log("ffS: %s\n", log_id(pm.st.ffS, "--")); + log("ffA: %s\n", log_id(st.ffA, "--")); + log("ffB: %s\n", log_id(st.ffB, "--")); + log("mul: %s\n", log_id(st.mul, "--")); + log("ffY: %s\n", log_id(st.ffY, "--")); + log("addAB: %s\n", log_id(st.addAB, "--")); + log("muxAB: %s\n", log_id(st.muxAB, "--")); + log("ffS: %s\n", log_id(st.ffS, "--")); #endif - log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(pm.st.mul)); + log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); - if (GetSize(pm.st.sigA) > 16) { - log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA)); + if (GetSize(st.sigA) > 16) { + log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA)); return; } - if (GetSize(pm.st.sigB) > 16) { - log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB)); + if (GetSize(st.sigB) > 16) { + log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB)); return; } - if (GetSize(pm.st.sigS) > 32) { - log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS)); + if (GetSize(st.sigS) > 32) { + log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS)); return; } - if (GetSize(pm.st.sigY) > 32) { - log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY)); + if (GetSize(st.sigY) > 32) { + log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY)); return; } - bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool(); + bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool(); if (mul_signed) { log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n"); @@ -69,21 +71,21 @@ void create_ice40_dsp(ice40_dsp_pm &pm) log(" replacing $mul with SB_MAC16 cell.\n"); Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); - pm.module->swap_names(cell, pm.st.mul); + pm.module->swap_names(cell, st.mul); // SB_MAC16 Input Interface - SigSpec A = pm.st.sigA; + SigSpec A = st.sigA; A.extend_u0(16, mul_signed); - SigSpec B = pm.st.sigB; + SigSpec B = st.sigB; B.extend_u0(16, mul_signed); SigSpec CD; - if (pm.st.muxA) - CD = pm.st.muxA->getPort("\\B"); - if (pm.st.muxB) - CD = pm.st.muxB->getPort("\\A"); + if (st.muxA) + CD = st.muxA->getPort("\\B"); + if (st.muxB) + CD = st.muxB->getPort("\\A"); CD.extend_u0(32, mul_signed); cell->setPort("\\A", A); @@ -91,8 +93,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\C", CD.extract(0, 16)); cell->setPort("\\D", CD.extract(16, 16)); - cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0); - cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0); + cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0); + cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0); cell->setPort("\\AHOLD", State::S0); cell->setPort("\\BHOLD", State::S0); @@ -102,25 +104,25 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\IRSTTOP", State::S0); cell->setPort("\\IRSTBOT", State::S0); - if (pm.st.clock_vld) + if (st.clock_vld) { - cell->setPort("\\CLK", pm.st.clock); + cell->setPort("\\CLK", st.clock); cell->setPort("\\CE", State::S1); - cell->setParam("\\NEG_TRIGGER", pm.st.clock_pol ? State::S0 : State::S1); + cell->setParam("\\NEG_TRIGGER", st.clock_pol ? State::S0 : State::S1); - log(" clock: %s (%s)", log_signal(pm.st.clock), pm.st.clock_pol ? "posedge" : "negedge"); + log(" clock: %s (%s)", log_signal(st.clock), st.clock_pol ? "posedge" : "negedge"); - if (pm.st.ffA) - log(" ffA:%s", log_id(pm.st.ffA)); + if (st.ffA) + log(" ffA:%s", log_id(st.ffA)); - if (pm.st.ffB) - log(" ffB:%s", log_id(pm.st.ffB)); + if (st.ffB) + log(" ffB:%s", log_id(st.ffB)); - if (pm.st.ffY) - log(" ffY:%s", log_id(pm.st.ffY)); + if (st.ffY) + log(" ffY:%s", log_id(st.ffY)); - if (pm.st.ffS) - log(" ffS:%s", log_id(pm.st.ffS)); + if (st.ffS) + log(" ffS:%s", log_id(st.ffS)); log("\n"); } @@ -144,16 +146,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Output Interface - SigSpec O = pm.st.ffS ? pm.st.sigS : pm.st.sigY; + SigSpec O = st.ffS ? st.sigS : st.sigY; if (GetSize(O) < 32) O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); cell->setPort("\\O", O); - if (pm.st.addAB) { - log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type)); - cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1); - cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1); + if (st.addAB) { + log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1); + cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1); } else { cell->setPort("\\ADDSUBTOP", State::S0); cell->setPort("\\ADDSUBBOT", State::S0); @@ -166,10 +168,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\OHOLDBOT", State::S0); SigSpec acc_reset = State::S0; - if (pm.st.muxA) - acc_reset = pm.st.muxA->getPort("\\S"); - if (pm.st.muxB) - acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S")); + if (st.muxA) + acc_reset = st.muxA->getPort("\\S"); + if (st.muxB) + acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S")); cell->setPort("\\OLOADTOP", acc_reset); cell->setPort("\\OLOADBOT", acc_reset); @@ -179,17 +181,17 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\C_REG", State::S0); cell->setParam("\\D_REG", State::S0); - cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); - cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); - cell->setParam("\\PIPELINE_16x16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0); + cell->setParam("\\TOP_8x8_MULT_REG", st.ffY ? State::S1 : State::S0); + cell->setParam("\\BOT_8x8_MULT_REG", st.ffY ? State::S1 : State::S0); + cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); - cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); + cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0); cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); - cell->setParam("\\BOTOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); + cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2)); cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0); cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); @@ -198,9 +200,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0); cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0); - pm.autoremove(pm.st.mul); - pm.autoremove(pm.st.ffY); - pm.autoremove(pm.st.ffS); + pm.autoremove(st.mul); + pm.autoremove(st.ffY); + pm.autoremove(st.ffS); } struct Ice40DspPass : public Pass { @@ -230,7 +232,7 @@ struct Ice40DspPass : public Pass { extra_args(args, argidx, design); for (auto module : design->selected_modules()) - ice40_dsp_pm(module, module->selected_cells()).run(create_ice40_dsp); + ice40_dsp_pm(module, module->selected_cells()).run_ice40_dsp(create_ice40_dsp); } } Ice40DspPass; diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 96c62e313..1f3590d4e 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,3 +1,5 @@ +pattern ice40_dsp + state clock state clock_pol clock_vld state sigA sigB sigY sigS diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index edc1ad7fe..bb4c9d66b 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -10,14 +10,17 @@ pp = pprint.PrettyPrinter(indent=4) prefix = None pmgfiles = list() outfile = None +debug = False -opts, args = getopt.getopt(sys.argv[1:], "p:o:") +opts, args = getopt.getopt(sys.argv[1:], "p:o:d") for o, a in opts: if o == "-p": - prefix = o + prefix = a elif o == "-o": outfile = a + elif o == "-d": + debug = True if outfile is None: outfile = args[-1] @@ -32,6 +35,8 @@ for a in args: assert prefix is not None +current_pattern = None +patterns = dict() state_types = dict() udata_types = dict() blocks = list() @@ -98,6 +103,7 @@ def rewrite_cpp(s): return "".join(t) def process_pmgfile(f): + global current_pattern while True: line = f.readline() if line == "": break @@ -107,14 +113,31 @@ def process_pmgfile(f): if len(cmd) == 0 or cmd[0].startswith("//"): continue cmd = cmd[0] + if cmd == "pattern": + if current_pattern is not None: + block = dict() + block["type"] = "final" + block["pattern"] = current_pattern + blocks.append(block) + line = line.split() + assert len(line) == 2 + assert line[1] not in patterns + current_pattern = line[1] + patterns[current_pattern] = len(blocks) + state_types[current_pattern] = dict() + udata_types[current_pattern] = dict() + continue + + assert current_pattern is not None + if cmd == "state": m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) assert m type_str = m.group(1) states_str = m.group(2) for s in re.split(r"\s+", states_str): - assert s not in state_types - state_types[s] = type_str + assert s not in state_types[current_pattern] + state_types[current_pattern][s] = type_str continue if cmd == "udata": @@ -123,19 +146,20 @@ def process_pmgfile(f): type_str = m.group(1) udatas_str = m.group(2) for s in re.split(r"\s+", udatas_str): - assert s not in udata_types - udata_types[s] = type_str + assert s not in udata_types[current_pattern] + udata_types[current_pattern][s] = type_str continue if cmd == "match": block = dict() block["type"] = "match" + block["pattern"] = current_pattern line = line.split() assert len(line) == 2 - assert line[1] not in state_types + assert line[1] not in state_types[current_pattern] block["cell"] = line[1] - state_types[line[1]] = "Cell*"; + state_types[current_pattern][line[1]] = "Cell*"; block["if"] = list() block["select"] = list() @@ -178,15 +202,18 @@ def process_pmgfile(f): assert False blocks.append(block) + continue if cmd == "code": block = dict() block["type"] = "code" + block["pattern"] = current_pattern + block["code"] = list() block["states"] = set() for s in line.split()[1:]: - assert s in state_types + assert s in state_types[current_pattern] block["states"].add(s) while True: @@ -199,11 +226,25 @@ def process_pmgfile(f): block["code"].append(rewrite_cpp(l.rstrip())) blocks.append(block) + continue + + assert False for fn in pmgfiles: with open(fn, "r") as f: process_pmgfile(f) +if current_pattern is not None: + block = dict() + block["type"] = "final" + block["pattern"] = current_pattern + blocks.append(block) + +current_pattern = None + +if debug: + pp.pprint(blocks) + with open(outfile, "w") as f: print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) print("", file=f) @@ -236,17 +277,19 @@ with open(outfile, "w") as f: print(" int rollback;", file=f) print("", file=f) - print(" struct state_t {", file=f) - for s, t in sorted(state_types.items()): - print(" {} {};".format(t, s), file=f) - print(" } st;", file=f) - print("", file=f) + for current_pattern in sorted(patterns.keys()): + print(" struct state_{}_t {{".format(current_pattern), file=f) + for s, t in sorted(state_types[current_pattern].items()): + print(" {} {};".format(t, s), file=f) + print(" }} st_{};".format(current_pattern), file=f) + print("", file=f) - print(" struct udata_t {", file=f) - for s, t in sorted(udata_types.items()): - print(" {} {};".format(t, s), file=f) - print(" } ud;", file=f) - print("", file=f) + print(" struct udata_{}_t {{".format(current_pattern), file=f) + for s, t in sorted(udata_types[current_pattern].items()): + print(" {} {};".format(t, s), file=f) + print(" }} ud_{};".format(current_pattern), file=f) + print("", file=f) + current_pattern = None for v, n in sorted(ids.items()): if n[0] == "\\": @@ -282,20 +325,22 @@ with open(outfile, "w") as f: print(" }", file=f) print("", file=f) - print(" void check_blacklist() {", file=f) - print(" if (!blacklist_dirty)", file=f) - print(" return;", file=f) - print(" blacklist_dirty = false;", file=f) - for index in range(len(blocks)): - block = blocks[index] - if block["type"] == "match": - print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f) - print(" rollback = {};".format(index+1), file=f) - print(" return;", file=f) - print(" }", file=f) - print(" rollback = 0;", file=f) - print(" }", file=f) - print("", file=f) + for current_pattern in sorted(patterns.keys()): + print(" void check_blacklist_{}() {{".format(current_pattern), file=f) + print(" if (!blacklist_dirty)", file=f) + print(" return;", file=f) + print(" blacklist_dirty = false;", file=f) + for index in range(len(blocks)): + block = blocks[index] + if block["type"] == "match": + print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f) + print(" rollback = {};".format(index+1), file=f) + print(" return;", file=f) + print(" }", file=f) + print(" rollback = 0;", file=f) + print(" }", file=f) + print("", file=f) + current_pattern = None print(" SigSpec port(Cell *cell, IdString portname) {", file=f) print(" return sigmap(cell->getPort(portname));", file=f) @@ -318,11 +363,13 @@ with open(outfile, "w") as f: print(" {}_pm(Module *module, const vector &cells) :".format(prefix), file=f) print(" module(module), sigmap(module) {", file=f) - for s, t in sorted(udata_types.items()): - if t.endswith("*"): - print(" ud.{} = nullptr;".format(s), file=f) - else: - print(" ud.{} = {}();".format(s, t), file=f) + for current_pattern in sorted(patterns.keys()): + for s, t in sorted(udata_types[current_pattern].items()): + if t.endswith("*"): + print(" ud_{}.{} = nullptr;".format(current_pattern,s), file=f) + else: + print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f) + current_pattern = None print(" for (auto cell : module->cells()) {", file=f) print(" for (auto &conn : cell->connections())", file=f) print(" add_siguser(conn.second, cell);", file=f) @@ -352,34 +399,48 @@ with open(outfile, "w") as f: print(" }", file=f) print("", file=f) - print(" void run(std::function on_accept_f) {", file=f) - print(" on_accept = on_accept_f;", file=f) - print(" rollback = 0;", file=f) - print(" blacklist_dirty = false;", file=f) - for s, t in sorted(state_types.items()): - if t.endswith("*"): - print(" st.{} = nullptr;".format(s), file=f) - else: - print(" st.{} = {}();".format(s, t), file=f) - print(" block_0();", file=f) - print(" }", file=f) - print("", file=f) - - print(" void run(std::function on_accept_f) {{".format(prefix), file=f) - print(" run([&](){on_accept_f(*this);});", file=f) - print(" }", file=f) - print("", file=f) + for current_pattern in sorted(patterns.keys()): + print(" void run_{}(std::function on_accept_f) {{".format(current_pattern), file=f) + print(" on_accept = on_accept_f;", file=f) + print(" rollback = 0;", file=f) + print(" blacklist_dirty = false;", file=f) + for s, t in sorted(state_types[current_pattern].items()): + if t.endswith("*"): + print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f) + else: + print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f) + print(" block_{}();".format(patterns[current_pattern]), file=f) + print(" }", file=f) + print("", file=f) + print(" void run_{}(std::function on_accept_f) {{".format(current_pattern, prefix), file=f) + print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f) + print(" }", file=f) + print("", file=f) + print(" void run_{}(std::function on_accept_f) {{".format(current_pattern, current_pattern), file=f) + print(" run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f) + print(" }", file=f) + print("", file=f) + current_pattern = None for index in range(len(blocks)): block = blocks[index] print(" void block_{}() {{".format(index), file=f) + current_pattern = block["pattern"] + + if block["type"] == "final": + print(" on_accept();", file=f) + print(" check_blacklist_{}();".format(current_pattern), file=f) + print(" }", file=f) + if index+1 != len(blocks): + print("", file=f) + continue const_st = set() nonconst_st = set() restore_st = set() - for i in range(index): + for i in range(patterns[current_pattern], index): if blocks[i]["type"] == "code": for s in blocks[i]["states"]: const_st.add(s) @@ -402,27 +463,27 @@ with open(outfile, "w") as f: assert False for s in sorted(const_st): - t = state_types[s] + t = state_types[current_pattern][s] if t.endswith("*"): - print(" {} const &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) + print(" {} const &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) else: - print(" const {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) + print(" const {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) for s in sorted(nonconst_st): - t = state_types[s] - print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) + t = state_types[current_pattern][s] + print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) if len(restore_st): print("", file=f) for s in sorted(restore_st): - t = state_types[s] + t = state_types[current_pattern][s] print(" {} backup_{} = {};".format(t, s, s), file=f) if block["type"] == "code": print("", file=f) print(" do {", file=f) - print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) - print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) + print("#define reject do {{ check_blacklist_{}(); goto rollback_label; }} while(0)".format(current_pattern), file=f) + print("#define accept do {{ on_accept(); check_blacklist_{}(); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f) print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) for line in block["code"]: @@ -441,11 +502,11 @@ with open(outfile, "w") as f: if len(restore_st) or len(nonconst_st): print("", file=f) for s in sorted(restore_st): - t = state_types[s] + t = state_types[current_pattern][s] print(" {} = backup_{};".format(s, s), file=f) for s in sorted(nonconst_st): if s not in restore_st: - t = state_types[s] + t = state_types[current_pattern][s] if t.endswith("*"): print(" {} = nullptr;".format(s), file=f) else: @@ -494,17 +555,10 @@ with open(outfile, "w") as f: else: assert False - + current_pattern = None print(" }", file=f) print("", file=f) - print(" void block_{}() {{".format(len(blocks)), file=f) - print(" on_accept();", file=f) - print(" check_blacklist();", file=f) - print(" }", file=f) print("};", file=f) - print("", file=f) print("YOSYS_NAMESPACE_END", file=f) - -# pp.pprint(blocks) From ea547bcaa355239d927a8b43fde37fcfdaf71ffb Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 29 Apr 2019 13:38:56 +0200 Subject: [PATCH 07/41] Add "peepopt" skeleton Signed-off-by: Clifford Wolf --- passes/pmgen/.gitignore | 1 + passes/pmgen/Makefile.inc | 14 ++++++++- passes/pmgen/peepopt.cc | 60 +++++++++++++++++++++++++++++++++++++++ passes/pmgen/peepopt.pmg | 34 ++++++++++++++++++++++ passes/pmgen/pmgen.py | 4 +++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 passes/pmgen/peepopt.cc create mode 100644 passes/pmgen/peepopt.pmg diff --git a/passes/pmgen/.gitignore b/passes/pmgen/.gitignore index c9263057e..0ad36ea2c 100644 --- a/passes/pmgen/.gitignore +++ b/passes/pmgen/.gitignore @@ -1 +1,2 @@ /ice40_dsp_pm.h +/peepopt_pm.h diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index e0609d9ba..b8a14df90 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -1,8 +1,20 @@ OBJS += passes/pmgen/ice40_dsp.o +OBJS += passes/pmgen/peepopt.o + +# -------------------------------------- passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg - $(P) mkdir -p passes/pmgen && python3 $^ $@ + $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^) + +# -------------------------------------- + +passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h +EXTRA_OBJS += passes/pmgen/peepopt_pm.h +.SECONDARY: passes/pmgen/peepopt_pm.h + +passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py passes/pmgen/peepopt.pmg + $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc new file mode 100644 index 000000000..e9aa8e37a --- /dev/null +++ b/passes/pmgen/peepopt.cc @@ -0,0 +1,60 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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/yosys.h" +#include "kernel/sigtools.h" +#include "passes/pmgen/peepopt_pm.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct PeepoptPass : public Pass { + PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" peepopt [options] [selection]\n"); + log("\n"); + log("This pass applies a collection of peephole optimizers to the current design.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing PEEOPOPT pass (run peephole optimizers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) { + peepopt_pm pm(module, module->selected_cells()); + pm.run_shiftmul(); + } + } +} PeepoptPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/pmgen/peepopt.pmg b/passes/pmgen/peepopt.pmg new file mode 100644 index 000000000..0a56016b2 --- /dev/null +++ b/passes/pmgen/peepopt.pmg @@ -0,0 +1,34 @@ +pattern shiftmul + +state shamt + +match shift + select shift->type.in($shift, $shiftx, $shr) +endmatch + +code shamt + shamt = port(shift, \B); + if (shamt[GetSize(shamt)-1] == State::S0) { + do { + shamt.remove(GetSize(shamt)-1); + } while (shamt[GetSize(shamt)-1] == State::S0); + } else + if (param(shift, \B_SIGNED).as_bool()) { + reject; + } +endcode + +match mul + select mul->type.in($mul) + select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const() + index port(mul, \Y) === shamt +endmatch + +code + IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; + int const_factor = port(mul, const_factor_port).as_int(); + if (GetSize(port(shift, \Y)) > const_factor) + reject; + log_dump(shift, shamt, mul, const_factor); + reject; +endcode diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index bb4c9d66b..24ad07359 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -420,6 +420,10 @@ with open(outfile, "w") as f: print(" run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f) print(" }", file=f) print("", file=f) + print(" void run_{}() {{".format(current_pattern), file=f) + print(" run_{}([](){{}});".format(current_pattern, current_pattern), file=f) + print(" }", file=f) + print("", file=f) current_pattern = None for index in range(len(blocks)): From 58238da133fd236642f352c06f4056832b52d21c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 30 Apr 2019 07:59:39 +0200 Subject: [PATCH 08/41] Progress in shiftmul peepopt pattern Signed-off-by: Clifford Wolf --- passes/pmgen/peepopt.pmg | 54 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/passes/pmgen/peepopt.pmg b/passes/pmgen/peepopt.pmg index 0a56016b2..d9d5757ca 100644 --- a/passes/pmgen/peepopt.pmg +++ b/passes/pmgen/peepopt.pmg @@ -13,9 +13,11 @@ code shamt shamt.remove(GetSize(shamt)-1); } while (shamt[GetSize(shamt)-1] == State::S0); } else - if (param(shift, \B_SIGNED).as_bool()) { + if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) { reject; } + if (GetSize(shamt) > 20) + reject; endcode match mul @@ -26,9 +28,55 @@ endmatch code IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; - int const_factor = port(mul, const_factor_port).as_int(); + IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED; + Const const_factor_cnst = port(mul, const_factor_port).as_const(); + int const_factor = const_factor_cnst.as_int(); + + if (GetSize(const_factor_cnst) == 0) + reject; + + if (const_factor_cnst.bits[GetSize(const_factor_cnst)-1] != State::S0 && + param(mul, const_factor_signed).as_bool()) + reject; + + if (GetSize(const_factor_cnst) > 20) + reject; + if (GetSize(port(shift, \Y)) > const_factor) reject; - log_dump(shift, shamt, mul, const_factor); + + log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); + + int new_const_factor_log2 = ceil_log2(const_factor); + int new_const_factor = 1 << new_const_factor_log2; + + SigSpec padding(State::Sx, new_const_factor-const_factor); + SigSpec old_a = port(shift, \A), new_a; + int trunc = 0; + + if (GetSize(old_a) % const_factor != 0) { + trunc = const_factor - GetSize(old_a) % const_factor; + old_a.append(SigSpec(State::Sx, trunc)); + } + + for (int i = 0; i*const_factor < GetSize(old_a); i++) { + SigSpec slice = old_a.extract(i*const_factor, const_factor); + new_a.append(slice); + new_a.append(padding); + } + + if (trunc > 0) + new_a.remove(GetSize(new_a)-trunc, trunc); + + SigSpec new_b = {port(mul, const_factor_port == \A ? \B : \A), SigSpec(State::S0, new_const_factor_log2)}; + if (param(shift, \B_SIGNED).as_bool()) + new_b.append(State::S0); + + shift->setPort(\A, new_a); + shift->setParam(\A_WIDTH, GetSize(new_a)); + shift->setPort(\B, new_b); + shift->setParam(\B_WIDTH, GetSize(new_b)); + + blacklist(shift); reject; endcode From bb4f3642deb1f607b82bff132e0aba5b1cef555b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 30 Apr 2019 08:04:22 +0200 Subject: [PATCH 09/41] Some pmgen reorg, rename peepopt.pmg to peepopt_shiftmul.pmg Signed-off-by: Clifford Wolf --- passes/pmgen/Makefile.inc | 4 +++- passes/pmgen/{peepopt.pmg => peepopt_shiftmul.pmg} | 0 passes/pmgen/pmgen.py | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) rename passes/pmgen/{peepopt.pmg => peepopt_shiftmul.pmg} (100%) diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index b8a14df90..a8cac7ea4 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -16,5 +16,7 @@ passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h EXTRA_OBJS += passes/pmgen/peepopt_pm.h .SECONDARY: passes/pmgen/peepopt_pm.h -passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py passes/pmgen/peepopt.pmg +PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg + +passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) diff --git a/passes/pmgen/peepopt.pmg b/passes/pmgen/peepopt_shiftmul.pmg similarity index 100% rename from passes/pmgen/peepopt.pmg rename to passes/pmgen/peepopt_shiftmul.pmg diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 24ad07359..5860c634a 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -23,8 +23,7 @@ for o, a in opts: debug = True if outfile is None: - outfile = args[-1] - args = args[0:-1] + outfile = "/dev/stdout" for a in args: assert a.endswith(".pmg") @@ -246,7 +245,8 @@ if debug: pp.pprint(blocks) with open(outfile, "w") as f: - print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) + for fn in pmgfiles: + print("// Generated by pmgen.py from {}".format(fn), file=f) print("", file=f) print("#include \"kernel/yosys.h\"", file=f) From d2d402e62567abe15873c0357b4e34b8f83d03cd Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 30 Apr 2019 08:10:37 +0200 Subject: [PATCH 10/41] Run "peepopt" in generic "synth" pass and "synth_ice40" Signed-off-by: Clifford Wolf --- techlibs/common/synth.cc | 2 ++ techlibs/ice40/synth_ice40.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index ccfa76e02..e41c0fe97 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -201,6 +201,8 @@ struct SynthPass : public ScriptPass run("check"); run("opt"); run("wreduce"); + run("peepopt"); + run("opt_clean"); if (help_mode) run("techmap -map +/cmp2lut.v", " (if -lut)"); else diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 8899bfcc4..f5249e567 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -239,6 +239,8 @@ struct SynthIce40Pass : public ScriptPass run("check"); run("opt"); run("wreduce"); + run("peepopt"); + run("opt_clean"); run("share"); run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); run("opt_expr"); From 4306bebe586dc3a6a954a6630b9f0292c1b1b1dd Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 30 Apr 2019 10:51:51 +0200 Subject: [PATCH 11/41] pmgen progress Signed-off-by: Clifford Wolf --- passes/pmgen/ice40_dsp.cc | 3 ++- passes/pmgen/peepopt.cc | 13 ++++++++++--- passes/pmgen/peepopt_shiftmul.pmg | 1 + passes/pmgen/pmgen.py | 23 ++++++++++++++--------- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 36ba1dabe..39d033a04 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -19,11 +19,12 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" -#include "passes/pmgen/ice40_dsp_pm.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +#include "passes/pmgen/ice40_dsp_pm.h" + void create_ice40_dsp(ice40_dsp_pm &pm) { auto &st = pm.st_ice40_dsp; diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index e9aa8e37a..0584878c3 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -19,11 +19,14 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" -#include "passes/pmgen/peepopt_pm.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +bool did_something; + +#include "passes/pmgen/peepopt_pm.h" + struct PeepoptPass : public Pass { PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { } void help() YS_OVERRIDE @@ -51,8 +54,12 @@ struct PeepoptPass : public Pass { extra_args(args, argidx, design); for (auto module : design->selected_modules()) { - peepopt_pm pm(module, module->selected_cells()); - pm.run_shiftmul(); + did_something = true; + while (did_something) { + did_something = false; + peepopt_pm pm(module, module->selected_cells()); + pm.run_shiftmul(); + } } } } PeepoptPass; diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index d9d5757ca..1f9b3c2b9 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -45,6 +45,7 @@ code if (GetSize(port(shift, \Y)) > const_factor) reject; + did_something = true; log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); int new_const_factor_log2 = ceil_log2(const_factor); diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 5860c634a..95a0a5f5d 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -11,8 +11,9 @@ prefix = None pmgfiles = list() outfile = None debug = False +genhdr = False -opts, args = getopt.getopt(sys.argv[1:], "p:o:d") +opts, args = getopt.getopt(sys.argv[1:], "p:o:dg") for o, a in opts: if o == "-p": @@ -21,6 +22,8 @@ for o, a in opts: outfile = a elif o == "-d": debug = True + elif o == "-g": + genhdr = True if outfile is None: outfile = "/dev/stdout" @@ -249,12 +252,12 @@ with open(outfile, "w") as f: print("// Generated by pmgen.py from {}".format(fn), file=f) print("", file=f) - print("#include \"kernel/yosys.h\"", file=f) - print("#include \"kernel/sigtools.h\"", file=f) - print("", file=f) - - print("YOSYS_NAMESPACE_BEGIN", file=f) - print("", file=f) + if genhdr: + print("#include \"kernel/yosys.h\"", file=f) + print("#include \"kernel/sigtools.h\"", file=f) + print("", file=f) + print("YOSYS_NAMESPACE_BEGIN", file=f) + print("", file=f) print("struct {}_pm {{".format(prefix), file=f) print(" Module *module;", file=f) @@ -564,5 +567,7 @@ with open(outfile, "w") as f: print("", file=f) print("};", file=f) - print("", file=f) - print("YOSYS_NAMESPACE_END", file=f) + + if genhdr: + print("", file=f) + print("YOSYS_NAMESPACE_END", file=f) From b515fd2d25851c90c9a0b08414c5ea5edeb916a0 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 30 Apr 2019 11:25:15 +0200 Subject: [PATCH 12/41] Add peepopt_muldiv, fixes #930 Signed-off-by: Clifford Wolf --- passes/opt/wreduce.cc | 36 +++++++++++++++++++++++++++++++++ passes/pmgen/Makefile.inc | 3 ++- passes/pmgen/peepopt.cc | 1 + passes/pmgen/peepopt_muldiv.pmg | 36 +++++++++++++++++++++++++++++++++ passes/pmgen/pmgen.py | 2 ++ tests/simple/peepopt.v | 9 +++++++++ 6 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 passes/pmgen/peepopt_muldiv.pmg create mode 100644 tests/simple/peepopt.v diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 68e077cf9..bbb1f4c48 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -529,6 +529,42 @@ struct WreducePass : public Pass { module->connect(sig, Const(0, GetSize(sig))); } } + + if (c->type.in("$div", "$mod", "$pow")) + { + SigSpec A = c->getPort("\\A"); + int original_a_width = GetSize(A); + if (c->getParam("\\A_SIGNED").as_bool()) { + while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0) + A.remove(GetSize(A)-1, 1); + } else { + while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0) + A.remove(GetSize(A)-1, 1); + } + if (original_a_width != GetSize(A)) { + log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n", + original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type)); + c->setPort("\\A", A); + c->setParam("\\A_WIDTH", GetSize(A)); + } + + SigSpec B = c->getPort("\\B"); + int original_b_width = GetSize(B); + if (c->getParam("\\B_SIGNED").as_bool()) { + while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0) + B.remove(GetSize(B)-1, 1); + } else { + while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0) + B.remove(GetSize(B)-1, 1); + } + if (original_b_width != GetSize(B)) { + log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n", + original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type)); + c->setPort("\\B", B); + c->setParam("\\B_WIDTH", GetSize(B)); + } + } + if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) { IdString memid = c->getParam("\\MEMID").decode_string(); RTLIL::Memory *mem = module->memories.at(memid); diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index a8cac7ea4..7911132db 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -16,7 +16,8 @@ passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h EXTRA_OBJS += passes/pmgen/peepopt_pm.h .SECONDARY: passes/pmgen/peepopt_pm.h -PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg +PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 0584878c3..78eb68c7a 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -59,6 +59,7 @@ struct PeepoptPass : public Pass { did_something = false; peepopt_pm pm(module, module->selected_cells()); pm.run_shiftmul(); + pm.run_muldiv(); } } } diff --git a/passes/pmgen/peepopt_muldiv.pmg b/passes/pmgen/peepopt_muldiv.pmg new file mode 100644 index 000000000..06c275834 --- /dev/null +++ b/passes/pmgen/peepopt_muldiv.pmg @@ -0,0 +1,36 @@ +pattern muldiv + +state t x y + +match mul + select mul->type == $mul + select GetSize(port(mul, \A)) + GetSize(port(mul, \B)) <= GetSize(port(mul, \Y)) +endmatch + +code t x y + t = port(mul, \Y); + x = port(mul, \A); + y = port(mul, \B); + branch; + std::swap(x, y); +endcode + +match div + select div->type.in($div) + index port(div, \A) === t + index port(div, \B) === x +endmatch + +code + SigSpec div_y = port(div, \Y); + SigSpec val_y = y; + + if (GetSize(div_y) != GetSize(val_y)) + val_y.extend_u0(GetSize(div_y), param(div, \A_SIGNED).as_bool()); + + did_something = true; + log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div)); + module->connect(div_y, val_y); + autoremove(div); + reject; +endcode diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 95a0a5f5d..81052afce 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -335,6 +335,8 @@ with open(outfile, "w") as f: print(" blacklist_dirty = false;", file=f) for index in range(len(blocks)): block = blocks[index] + if block["pattern"] != current_pattern: + continue if block["type"] == "match": print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f) print(" rollback = {};".format(index+1), file=f) diff --git a/tests/simple/peepopt.v b/tests/simple/peepopt.v new file mode 100644 index 000000000..b27b9fe57 --- /dev/null +++ b/tests/simple/peepopt.v @@ -0,0 +1,9 @@ +module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output [W-1:0] o); +assign o = i[s*W+:W]; +endmodule + +module peepopt_muldiv_0(input [1:0] i, output [1:0] o); +wire [3:0] t; +assign t = i * 3; +assign o = t / 3; +endmodule From 3b6a02d3a74dc0113d595c6d26a4436160e28a6f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 1 May 2019 09:57:26 +0200 Subject: [PATCH 13/41] Fix width detection of memory access with bit slice, fixes #974 Signed-off-by: Clifford Wolf --- frontends/ast/genrtlil.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index b3a2a84be..d4515babf 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (!id_ast->children[0]->range_valid) log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; + if (children.size() > 1) + range = children[1]; } else log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); if (range) { From 6bbe2fdbf32e6335cdbecc21547e54992c3a606d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 1 May 2019 10:01:54 +0200 Subject: [PATCH 14/41] Add splitcmplxassign test case and silence splitcmplxassign warning Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 1 + tests/simple/mem2reg.v | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 4d4b9dfe1..d6561682a 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1607,6 +1607,7 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_tmp->str] = wire_tmp; wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } + wire_tmp->is_logic = true; AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); wire_tmp_id->str = wire_tmp->str; diff --git a/tests/simple/mem2reg.v b/tests/simple/mem2reg.v index 9839fd4a8..100426785 100644 --- a/tests/simple/mem2reg.v +++ b/tests/simple/mem2reg.v @@ -92,3 +92,25 @@ module mem2reg_test5(input ctrl, output out); assign out = bar[foo[0]]; endmodule +// ------------------------------------------------------ + +module mem2reg_test6 (din, dout); + input wire [3:0] din; + output reg [3:0] dout; + + reg [1:0] din_array [1:0]; + reg [1:0] dout_array [1:0]; + + always @* begin + din_array[0] = din[0 +: 2]; + din_array[1] = din[2 +: 2]; + + dout_array[0] = din_array[0]; + dout_array[1] = din_array[1]; + + {dout_array[0][1], dout_array[0][0]} = dout_array[0][0] + dout_array[1][0]; + + dout[0 +: 2] = dout_array[0]; + dout[2 +: 2] = dout_array[1]; + end +endmodule From 93b7fd77449ea385d12db71fd8205312441535d9 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 1 May 2019 15:06:46 +0200 Subject: [PATCH 15/41] Fix floating point exception in qwp, fixes #923 Signed-off-by: Clifford Wolf --- passes/cmds/qwp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc index 1c64a7b77..adbe89e31 100644 --- a/passes/cmds/qwp.cc +++ b/passes/cmds/qwp.cc @@ -291,7 +291,7 @@ struct QwpWorker // gaussian elimination for (int i = 0; i < N; i++) { - if (config.verbose && ((i+1) % (N/15)) == 0) + if (config.verbose && N > 15 && ((i+1) % (N/15)) == 0) log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N); // find best row From 38f5424f92389d6f4fdf020b214023b2b6efa71a Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 1 May 2019 13:16:01 -0700 Subject: [PATCH 16/41] Fix #938 - Crash occurs in case when use write_firrtl command Add missing memory initialization. Sanity-check memory parameters. Add Cell pointer to memory object (for error reporting). --- backends/firrtl/firrtl.cc | 45 +++++++++++++++++++++++++++++++++---- tests/memories/firrtl_938.v | 22 ++++++++++++++++++ tests/simple/xfirrtl | 1 + 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 tests/memories/firrtl_938.v diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index ed6e9f8ee..a8a1bb078 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -164,6 +164,7 @@ struct FirrtlWorker }; /* Memories defined within this module. */ struct memory { + Cell *pCell; // for error reporting string name; // memory name int abits; // number of address bits int size; // size (in units) of the memory @@ -174,8 +175,37 @@ struct FirrtlWorker vector write_ports; std::string init_file; std::string init_file_srcFileSpec; - memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {} - memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} + string srcLine; + memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") { + // Provide defaults for abits or size if one (but not the other) is specified. + if (this->abits == 0 && this->size != 0) { + this->abits = ceil_log2(this->size); + } else if (this->abits != 0 && this->size == 0) { + this->size = 1 << this->abits; + } + // Sanity-check this construction. + if (this->name == "") { + log_error("Nameless memory%s\n", this->atLine()); + } + if (this->abits == 0 && this->size == 0) { + log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine()); + } + if (this->width == 0) { + log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine()); + } + } + // We need a default constructor for the dict insert. + memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} + + const char *atLine() { + if (srcLine == "") { + if (pCell) { + auto p = pCell->attributes.find("\\src"); + srcLine = " at " + p->second.decode_string(); + } + } + return srcLine.c_str(); + } void add_memory_read_port(read_port &rp) { read_ports.push_back(rp); } @@ -604,7 +634,7 @@ struct FirrtlWorker int abits = cell->parameters.at("\\ABITS").as_int(); int width = cell->parameters.at("\\WIDTH").as_int(); int size = cell->parameters.at("\\SIZE").as_int(); - memory m(mem_id, abits, size, width); + memory m(cell, mem_id, abits, size, width); int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); @@ -681,6 +711,8 @@ struct FirrtlWorker { std::string cell_type = fid(cell->type); std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); + int abits = cell->parameters.at("\\ABITS").as_int(); + int width = cell->parameters.at("\\WIDTH").as_int(); memory *mp = nullptr; if (cell->type == "$meminit" ) { log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); @@ -693,6 +725,11 @@ struct FirrtlWorker Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); + // Do we already have an entry for this memory? + if (memories.count(mem_id) == 0) { + memory m(cell, mem_id, abits, 0, width); + register_memory(m); + } mp = &memories.at(mem_id); int portNum = 0; bool transparency = false; @@ -890,7 +927,7 @@ struct FirrtlWorker // If we have any memory definitions, output them. for (auto kv : memories) { - memory m = kv.second; + memory &m = kv.second; f << stringf(" mem %s:\n", m.name.c_str()); f << stringf(" data-type => UInt<%d>\n", m.width); f << stringf(" depth => %d\n", m.size); diff --git a/tests/memories/firrtl_938.v b/tests/memories/firrtl_938.v new file mode 100644 index 000000000..af5efcd25 --- /dev/null +++ b/tests/memories/firrtl_938.v @@ -0,0 +1,22 @@ +module top +( + input [7:0] data_a, + input [6:1] addr_a, + input we_a, clk, + output reg [7:0] q_a +); + // Declare the RAM variable + reg [7:0] ram[63:0]; + + // Port A + always @ (posedge clk) + begin + if (we_a) + begin + ram[addr_a] <= data_a; + q_a <= data_a; + end + q_a <= ram[addr_a]; + end + +endmodule diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl index 50d693513..ba61a4476 100644 --- a/tests/simple/xfirrtl +++ b/tests/simple/xfirrtl @@ -16,6 +16,7 @@ operators.v $pow partsel.v drops modules process.v drops modules realexpr.v drops modules +retime.v Initial value (11110101) for (retime_test.ff) not supported scopes.v original verilog issues ( -x where x isn't declared signed) sincos.v $adff specify.v no code (empty module generates error From 521663f09e8bc22f57a7c03476672b0b9718bc84 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 2 May 2019 00:03:31 +0200 Subject: [PATCH 17/41] Add missing enable_undef to "sat -tempinduct-def", fixes #883 Signed-off-by: Clifford Wolf --- passes/sat/sat.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 695a03e15..cbba738f0 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -1169,6 +1169,7 @@ struct SatPass : public Pass { if (args[argidx] == "-tempinduct-def") { tempinduct = true; tempinduct_def = true; + enable_undef = true; continue; } if (args[argidx] == "-tempinduct-baseonly") { From 6ea09caf01cf06ad7f93eb62fa85ec9361b7e5a1 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 1 May 2019 16:21:13 -0700 Subject: [PATCH 18/41] Re-indent firrtl.cc:struct memory - no functional change. --- backends/firrtl/firrtl.cc | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index a8a1bb078..9feff71c6 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -163,20 +163,20 @@ struct FirrtlWorker } }; /* Memories defined within this module. */ - struct memory { - Cell *pCell; // for error reporting - string name; // memory name - int abits; // number of address bits - int size; // size (in units) of the memory - int width; // size (in bits) of each element - int read_latency; - int write_latency; - vector read_ports; - vector write_ports; - std::string init_file; - std::string init_file_srcFileSpec; - string srcLine; - memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") { + struct memory { + Cell *pCell; // for error reporting + string name; // memory name + int abits; // number of address bits + int size; // size (in units) of the memory + int width; // size (in bits) of each element + int read_latency; + int write_latency; + vector read_ports; + vector write_ports; + std::string init_file; + std::string init_file_srcFileSpec; + string srcLine; + memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") { // Provide defaults for abits or size if one (but not the other) is specified. if (this->abits == 0 && this->size != 0) { this->abits = ceil_log2(this->size); @@ -206,18 +206,18 @@ struct FirrtlWorker } return srcLine.c_str(); } - void add_memory_read_port(read_port &rp) { - read_ports.push_back(rp); - } - void add_memory_write_port(write_port &wp) { - write_ports.push_back(wp); - } - void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { - this->init_file = init_file; - this->init_file_srcFileSpec = init_file_srcFileSpec; - } + void add_memory_read_port(read_port &rp) { + read_ports.push_back(rp); + } + void add_memory_write_port(write_port &wp) { + write_ports.push_back(wp); + } + void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { + this->init_file = init_file; + this->init_file_srcFileSpec = init_file_srcFileSpec; + } - }; + }; dict memories; void register_memory(memory &m) From d394b9301b2619b8cb64f9faea4c112bf2a07925 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 1 May 2019 18:23:21 -0700 Subject: [PATCH 19/41] Back to passing all xc7srl tests! --- techlibs/xilinx/synth_xilinx.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index dbafec301..8aa7b508e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -205,17 +205,16 @@ struct SynthXilinxPass : public ScriptPass } if (check_label("fine")) { - run("opt -fast"); - run("memory_map"); - run("dffsr2dff"); - run("dff2dffe"); - // shregmap -tech xilinx can cope with $shiftx and $mux // cells for identifiying variable-length shift registers, // so attempt to convert $pmux-es to the former if (!nosrl || help_mode) run("pmux2shiftx", "(skip if '-nosrl')"); + run("opt -fast -full"); + run("memory_map"); + run("dffsr2dff"); + run("dff2dffe"); run("opt -full"); if (!vpr || help_mode) From 98ffe5fb007c0e0d348f961a4e99d8b2f241eac1 Mon Sep 17 00:00:00 2001 From: Jakob Wenzel Date: Thu, 25 Apr 2019 15:12:24 +0200 Subject: [PATCH 20/41] fail svinterfaces testcases on yosys error exit --- tests/svinterfaces/runone.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/svinterfaces/runone.sh b/tests/svinterfaces/runone.sh index 0adecc797..71c2d4976 100755 --- a/tests/svinterfaces/runone.sh +++ b/tests/svinterfaces/runone.sh @@ -11,13 +11,13 @@ echo "" > $STDERRFILE echo -n "Test: ${TESTNAME} -> " +set -e + $PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE >> $STDERRFILE $PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE >> $STDERRFILE rm -f a.out reference_result.txt dut_result.txt -set -e - iverilog -g2012 ${TESTNAME}_syn.v iverilog -g2012 ${TESTNAME}_ref_syn.v From aa081f83c791b1d666214776aaf744a80ce6a690 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 2 May 2019 17:40:39 -0700 Subject: [PATCH 21/41] dffinit -noreinit to silently continue when init value is 1'bx --- passes/techmap/dffinit.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index 48390488e..37479da65 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -135,10 +135,18 @@ struct DffinitPass : public Pass { continue; while (GetSize(value.bits) <= i) value.bits.push_back(State::S0); - if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i])) - log_error("Trying to assign a different init value for %s.%s.%s which technically " - "have a conflicted init value.\n", - log_id(module), log_id(cell), log_id(it.second)); + if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i])) { + if (init_bits.at(sig[i]) != State::Sx) { + log_error("Trying to assign a different init value for %s.%s.%s which technically " + "have a conflicted init value.\n", + log_id(module), log_id(cell), log_id(it.second)); + } + else { + // Trying to overwrite an existing INIT value with 1'bx, + // silently ignore? + continue; + } + } value.bits[i] = init_bits.at(sig[i]); cleanup_bits.insert(sig[i]); } From 1f62dc9081feb4852b1848d01951f631853edb38 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 2 May 2019 17:41:20 -0700 Subject: [PATCH 22/41] synth_xilinx to call dffinit with -noreinit --- 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 8aa7b508e..fc0e76bad 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -250,7 +250,7 @@ struct SynthXilinxPass : public ScriptPass if (!nosrl || help_mode) run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')"); run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); - run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " + run("dffinit -noreinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); run("clean"); } From e8c5afcb84a2f52c26759952cb9288e42821a49f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 May 2019 08:25:30 +0200 Subject: [PATCH 23/41] Fix typo Signed-off-by: Clifford Wolf --- passes/pmgen/peepopt.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 78eb68c7a..e7f95cf85 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -40,7 +40,7 @@ struct PeepoptPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - log_header(design, "Executing PEEOPOPT pass (run peephole optimizers).\n"); + log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) From 2b29aa5c86021eb79c461975a0281b6d7635bb67 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 May 2019 08:35:45 +0200 Subject: [PATCH 24/41] Update pmgen documentation Signed-off-by: Clifford Wolf --- passes/pmgen/README.md | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 320e95a77..2f0b1fd5a 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -29,19 +29,25 @@ up in any future matches: pm.blacklist(some_cell); -The `.run(callback_function)` method searches for all matches and calls the -callback function for each found match: +The `.run_(callback_function)` method searches for all matches +for the pattern`` and calls the callback function for each found +match: - pm.run([&](){ + pm.run_foobar([&](){ log("found matching 'foo' cell: %s\n", log_id(pm.st.foo)); log(" with 'bar' cell: %s\n", log_id(pm.st.bar)); }); The `.pmg` file declares matcher state variables that are accessible via the -`.st.` members. (The `.st` member is of type `foobar_pm::state_t`.) +`.st_.` members. (The `.st_` member is +of type `foobar_pm::state__t`.) Similarly the `.pmg` file declares user data variables that become members of -`.ud`, a struct of type `foobar_pm::udata_t`. +`.ud_`, a struct of type `foobar_pm::udata__t`. + +There are four versions of the `run_()` method: Without callback, +callback without arguments, callback with reference to `pm`, and callback with +reference to `pm.st_`. The .pmg File Format @@ -52,6 +58,12 @@ lines consist of whitespace-separated tokens. Lines in `.pmg` files starting with `//` are comments. +Declaring a pattern +------------------- + +A `.pmg` file contains one or more patterns. Each pattern starts with a line +with the `pattern` keyword followed by the name of the pattern. + Declaring state variables ------------------------- @@ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith and saved and restored as needed. They are automatically initialized to the default constructed value of their type -when `.run(callback_function)` is called. +when `.run_(callback_function)` is called. Declaring udata variables ------------------------- From 42190207b4a5ae37240e58652d173c7164f025f7 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 May 2019 14:24:53 +0200 Subject: [PATCH 25/41] Improve opt_expr and opt_clean handling of (partially) undriven and/or unused wires, fixes #981 Signed-off-by: Clifford Wolf --- passes/opt/opt_clean.cc | 116 +++++++++++++++++++++++++--------------- passes/opt/opt_expr.cc | 13 +++-- 2 files changed, 83 insertions(+), 46 deletions(-) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 5d95c4f1a..96118e906 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -274,50 +274,53 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos std::vector maybe_del_wires; for (auto wire : module->wires()) { + SigSpec s1 = SigSpec(wire), s2 = assign_map(s1); + log_assert(GetSize(s1) == GetSize(s2)); + + bool maybe_del = false; if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) { - RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1; - assign_map.apply(s2); - if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) { - maybe_del_wires.push_back(wire); - } else { - log_assert(GetSize(s1) == GetSize(s2)); - Const initval; - if (wire->attributes.count("\\init")) - initval = wire->attributes.at("\\init"); - if (GetSize(initval) != GetSize(wire)) - initval.bits.resize(GetSize(wire), State::Sx); - RTLIL::SigSig new_conn; - for (int i = 0; i < GetSize(s1); i++) - if (s1[i] != s2[i]) { - if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) { - s2[i] = initval[i]; - initval[i] = State::Sx; - } - new_conn.first.append_bit(s1[i]); - new_conn.second.append_bit(s2[i]); - } - if (new_conn.first.size() > 0) { - if (initval.is_fully_undef()) - wire->attributes.erase("\\init"); - else - wire->attributes.at("\\init") = initval; - used_signals.add(new_conn.first); - used_signals.add(new_conn.second); - module->connect(new_conn); - } - } + if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) + maybe_del = true; } else { - if (!used_signals.check_any(RTLIL::SigSpec(wire))) - maybe_del_wires.push_back(wire); + if (!used_signals.check_any(s2)) + maybe_del = true; } - RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire)); - if (!used_signals_nodrivers.check_any(sig)) { + if (maybe_del) { + maybe_del_wires.push_back(wire); + } else { + Const initval; + if (wire->attributes.count("\\init")) + initval = wire->attributes.at("\\init"); + if (GetSize(initval) != GetSize(wire)) + initval.bits.resize(GetSize(wire), State::Sx); + RTLIL::SigSig new_conn; + for (int i = 0; i < GetSize(s1); i++) + if (s1[i] != s2[i]) { + if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) { + s2[i] = initval[i]; + initval[i] = State::Sx; + } + new_conn.first.append_bit(s1[i]); + new_conn.second.append_bit(s2[i]); + } + if (new_conn.first.size() > 0) { + if (initval.is_fully_undef()) + wire->attributes.erase("\\init"); + else + wire->attributes.at("\\init") = initval; + used_signals.add(new_conn.first); + used_signals.add(new_conn.second); + module->connect(new_conn); + } + } + + if (!used_signals_nodrivers.check_all(s2)) { std::string unused_bits; - for (int i = 0; i < GetSize(sig); i++) { - if (sig[i].wire == NULL) + for (int i = 0; i < GetSize(s2); i++) { + if (s2[i].wire == NULL) continue; - if (!used_signals_nodrivers.check(sig[i])) { + if (!used_signals_nodrivers.check(s2[i])) { if (!unused_bits.empty()) unused_bits += " "; unused_bits += stringf("%d", i); @@ -336,14 +339,40 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos pool del_wires; int del_wires_count = 0; - for (auto wire : maybe_del_wires) - if (!used_signals.check_any(RTLIL::SigSpec(wire))) { - if (check_public_name(wire->name) && verbose) { + for (auto wire : maybe_del_wires) { + SigSpec s1 = SigSpec(wire); + if (used_signals.check_any(s1)) { + SigSpec s2 = assign_map(s1); + Const initval; + if (wire->attributes.count("\\init")) + initval = wire->attributes.at("\\init"); + if (GetSize(initval) != GetSize(wire)) + initval.bits.resize(GetSize(wire), State::Sx); + RTLIL::SigSig new_conn; + for (int i = 0; i < GetSize(s1); i++) + if (s1[i] != s2[i]) { + if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) { + s2[i] = initval[i]; + initval[i] = State::Sx; + } + new_conn.first.append_bit(s1[i]); + new_conn.second.append_bit(s2[i]); + } + if (new_conn.first.size() > 0) { + if (initval.is_fully_undef()) + wire->attributes.erase("\\init"); + else + wire->attributes.at("\\init") = initval; + module->connect(new_conn); + } + } else { + if (ys_debug() || (check_public_name(wire->name) && verbose)) { log_debug(" removing unused non-port wire %s.\n", wire->name.c_str()); } del_wires.insert(wire); del_wires_count++; } + } module->remove(del_wires); count_rm_wires += del_wires.size(); @@ -496,6 +525,9 @@ struct OptCleanPass : public Pass { ct_all.setup(design); + count_rm_cells = 0; + count_rm_wires = 0; + for (auto module : design->selected_whole_modules_warn()) { if (module->has_processes_warn()) continue; @@ -561,7 +593,7 @@ struct CleanPass : public Pass { for (auto module : design->selected_whole_modules()) { if (module->has_processes()) continue; - rmunused_module(module, purge_mode, false, false); + rmunused_module(module, purge_mode, ys_debug(), false); } log_suppressed(); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index b445afdc8..512ef0cbf 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -61,7 +61,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) } if (wire->port_input) driven_signals.add(sigmap(wire)); - if (wire->port_output) + if (wire->port_output || wire->get_bool_attribute("\\keep")) used_signals.add(sigmap(wire)); all_signals.add(sigmap(wire)); } @@ -88,7 +88,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) } } - log_debug("Setting undriven signal in %s to constant: %s = %s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(val)); + log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val)); module->connect(sig, val); did_something = true; } @@ -104,10 +104,15 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) if (SigBit(initval[i]) == sig[i]) initval[i] = State::Sx; } - if (initval.is_fully_undef()) + if (initval.is_fully_undef()) { + log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire)); wire->attributes.erase("\\init"); - else + did_something = true; + } else if (initval != wire->attributes.at("\\init")) { + log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval)); wire->attributes["\\init"] = initval; + did_something = true; + } } } } From d2aa123226f39fb6d076b9a0add2ad4f0e596166 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 May 2019 14:40:51 +0200 Subject: [PATCH 26/41] Fix typo in tests/svinterfaces/runone.sh Signed-off-by: Clifford Wolf --- tests/svinterfaces/runone.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/svinterfaces/runone.sh b/tests/svinterfaces/runone.sh index 71c2d4976..54cf5f2ec 100755 --- a/tests/svinterfaces/runone.sh +++ b/tests/svinterfaces/runone.sh @@ -13,8 +13,8 @@ echo -n "Test: ${TESTNAME} -> " set -e -$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE >> $STDERRFILE -$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE >> $STDERRFILE +$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE 2>> $STDERRFILE +$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE 2>> $STDERRFILE rm -f a.out reference_result.txt dut_result.txt From fc349de0338db3831e7156a5dc60f028382bcab1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 May 2019 08:05:37 -0700 Subject: [PATCH 27/41] Revert "dffinit -noreinit to silently continue when init value is 1'bx" This reverts commit aa081f83c791b1d666214776aaf744a80ce6a690. --- passes/techmap/dffinit.cc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index 37479da65..48390488e 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -135,18 +135,10 @@ struct DffinitPass : public Pass { continue; while (GetSize(value.bits) <= i) value.bits.push_back(State::S0); - if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i])) { - if (init_bits.at(sig[i]) != State::Sx) { - log_error("Trying to assign a different init value for %s.%s.%s which technically " - "have a conflicted init value.\n", - log_id(module), log_id(cell), log_id(it.second)); - } - else { - // Trying to overwrite an existing INIT value with 1'bx, - // silently ignore? - continue; - } - } + if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i])) + log_error("Trying to assign a different init value for %s.%s.%s which technically " + "have a conflicted init value.\n", + log_id(module), log_id(cell), log_id(it.second)); value.bits[i] = init_bits.at(sig[i]); cleanup_bits.insert(sig[i]); } From e08df0c7390e1e7736c3d5b0abbe2679bf9b4518 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 May 2019 08:06:16 -0700 Subject: [PATCH 28/41] If init is 1'bx, do not add to dict as per @cliffordwolf --- passes/techmap/dffinit.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index 48390488e..0ad33dc0e 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -102,7 +102,8 @@ struct DffinitPass : public Pass { if (wire->attributes.count("\\init")) { Const value = wire->attributes.at("\\init"); for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) - init_bits[sigmap(SigBit(wire, i))] = value[i]; + if (value[i] != State::Sx) + init_bits[sigmap(SigBit(wire, i))] = value[i]; } if (wire->port_output) for (auto bit : sigmap(wire)) From 1d43a25f08920643f413cf74b18adfb32815fcd8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 May 2019 09:55:02 -0700 Subject: [PATCH 29/41] Revert "synth_xilinx to call dffinit with -noreinit" This reverts commit 1f62dc9081feb4852b1848d01951f631853edb38. --- 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 fc0e76bad..8aa7b508e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -250,7 +250,7 @@ struct SynthXilinxPass : public ScriptPass if (!nosrl || help_mode) run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')"); run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); - run("dffinit -noreinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " + run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); run("clean"); } From 1e5f072c0556158924387dedbb78b4cc61bfcf7a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 May 2019 14:03:51 -0700 Subject: [PATCH 30/41] iverilog with simcells.v as well --- tests/tools/autotest.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index bb9c3bfb5..920474a84 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -147,7 +147,8 @@ do fi if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \ - "$toolsdir"/../../techlibs/common/simlib.v + "$toolsdir"/../../techlibs/common/simlib.v \ + "$toolsdir"/../../techlibs/common/simcells.v if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi test_count=0 From c2e29ab809c5eb3ac89d50868d0e88d831c33d52 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 May 2019 14:40:32 -0700 Subject: [PATCH 31/41] Rename cells_map.v to prevent clash with ff_map.v --- techlibs/xilinx/cells_map.v | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index b29238a12..40789ddbe 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -18,12 +18,14 @@ */ // Convert negative-polarity reset to positive-polarity -module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule - -module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule - +(* techmap_celltype = "$_DFF_NN0_" *) +module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$_DFF_PN0_" *) +module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$_DFF_NN1_" *) +module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$_DFF_PN1_" *) +module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$__SHREG_ (input C, input D, input E, output Q); parameter DEPTH = 0; From 9804c86e87ec83edd29d224f01311b6ae1d41181 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 4 May 2019 07:52:51 +0200 Subject: [PATCH 32/41] Add approximate support for SV "var" keyword, fixes #987 Signed-off-by: Clifford Wolf --- frontends/verilog/verilog_lexer.l | 1 + frontends/verilog/verilog_parser.y | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 6ef38252a..59ef3e36e 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -207,6 +207,7 @@ YOSYS_NAMESPACE_END "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } "logic" { SV_KEYWORD(TOK_LOGIC); } +"var" { SV_KEYWORD(TOK_VAR); } "bit" { SV_KEYWORD(TOK_REG); } "eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 40968d17a..f011e07ea 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -110,7 +110,7 @@ static void free_attr(std::map *al) %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP -%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT +%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT @@ -456,6 +456,9 @@ wire_type_token: TOK_LOGIC { astbuf3->is_logic = true; } | + TOK_VAR { + astbuf3->is_logic = true; + } | TOK_INTEGER { astbuf3->is_reg = true; astbuf3->range_left = 31; From 66d6ca2de2e31d7c0460ae314b61136e42ded8c5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 4 May 2019 09:25:32 +0200 Subject: [PATCH 33/41] Add support for SVA "final" keyword Signed-off-by: Clifford Wolf --- frontends/verilog/verilog_lexer.l | 1 + frontends/verilog/verilog_parser.y | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 6ef38252a..e97632663 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -206,6 +206,7 @@ YOSYS_NAMESPACE_END "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } +"final" { SV_KEYWORD(TOK_FINAL); } "logic" { SV_KEYWORD(TOK_LOGIC); } "bit" { SV_KEYWORD(TOK_REG); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 40968d17a..9edb61a39 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -106,7 +106,7 @@ static void free_attr(std::map *al) } %token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL -%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER +%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP @@ -1341,6 +1341,9 @@ opt_property: TOK_PROPERTY { $$ = true; } | + TOK_FINAL { + $$ = false; + } | /* empty */ { $$ = false; }; From a01386c0e45b4eee5295db440740a1ab271396fe Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 4 May 2019 09:47:16 +0200 Subject: [PATCH 34/41] Improve opt_clean handling of unused wires Signed-off-by: Clifford Wolf --- passes/opt/opt_clean.cc | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 96118e906..9f6212526 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -242,6 +242,10 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos } } + SigPool raw_used_signals_noaliases; + for (auto &it : module->connections_) + raw_used_signals_noaliases.add(it.second); + module->connections_.clear(); SigPool used_signals; @@ -251,6 +255,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos for (auto &it2 : cell->connections_) { assign_map.apply(it2.second); used_signals.add(it2.second); + raw_used_signals_noaliases.add(it2.second); if (!ct_all.cell_output(cell->type, it2.first)) used_signals_nodrivers.add(it2.second); } @@ -277,23 +282,30 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos SigSpec s1 = SigSpec(wire), s2 = assign_map(s1); log_assert(GetSize(s1) == GetSize(s2)); + Const initval; + if (wire->attributes.count("\\init")) + initval = wire->attributes.at("\\init"); + if (GetSize(initval) != GetSize(wire)) + initval.bits.resize(GetSize(wire), State::Sx); + if (initval.is_fully_undef()) + wire->attributes.erase("\\init"); + bool maybe_del = false; - if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) { - if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) - maybe_del = true; + if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) { + /* do not delete anything with "keep" or module ports or initialized wires */ + } else + if (!purge_mode && check_public_name(wire->name)) { + /* do not get rid of public names unless in purge mode */ } else { - if (!used_signals.check_any(s2)) + if (!raw_used_signals_noaliases.check_any(s1)) + maybe_del = true; + if (!used_signals_nodrivers.check_any(s2)) maybe_del = true; } if (maybe_del) { maybe_del_wires.push_back(wire); } else { - Const initval; - if (wire->attributes.count("\\init")) - initval = wire->attributes.at("\\init"); - if (GetSize(initval) != GetSize(wire)) - initval.bits.resize(GetSize(wire), State::Sx); RTLIL::SigSig new_conn; for (int i = 0; i < GetSize(s1); i++) if (s1[i] != s2[i]) { @@ -341,7 +353,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos int del_wires_count = 0; for (auto wire : maybe_del_wires) { SigSpec s1 = SigSpec(wire); - if (used_signals.check_any(s1)) { + if (used_signals_nodrivers.check_any(s1)) { SigSpec s2 = assign_map(s1); Const initval; if (wire->attributes.count("\\init")) From 5ce9113eda2e82034fd47106d6f75b8f30fd79ab Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 4 May 2019 16:53:25 +0100 Subject: [PATCH 35/41] abc: Improve name recovery Signed-off-by: David Shah --- passes/techmap/abc.cc | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 547115459..d7500f3c3 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -330,18 +330,31 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) { std::string abc_sname = abc_name.substr(1); - if (abc_sname.substr(0, 5) == "ys__n") { + bool isnew = false; + if (abc_sname.substr(0, 4) == "new_") + { + abc_sname.erase(0, 4); + isnew = true; + } + if (abc_sname.substr(0, 5) == "ys__n") + { bool inv = abc_sname.back() == 'v'; if (inv) abc_sname.pop_back(); abc_sname.erase(0, 5); - if (abc_sname.find_last_not_of("012345689") == std::string::npos) { + if (std::isdigit(abc_sname.at(0))) + { int sid = std::stoi(abc_sname); - for (auto sig : signal_list) { - if (sig.id == sid && sig.bit.wire != nullptr) { + if (sid < GetSize(signal_list)) + { + auto sig = signal_list.at(sid); + if (sig.bit.wire != nullptr) + { std::stringstream sstr; sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); if (sig.bit.wire->width != 1) sstr << "[" << sig.bit.offset << "]"; + if (isnew) + sstr << "_new"; if (inv) sstr << "_inv"; if (orig_wire != nullptr) From a84256aa366cd1e74de48444c136052564fdd0fe Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 4 May 2019 17:17:30 +0100 Subject: [PATCH 36/41] abc: Fix handling of postfixed names (e.g. for retiming) Signed-off-by: David Shah --- passes/techmap/abc.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index d7500f3c3..5b19d84fb 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -338,12 +338,13 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp } if (abc_sname.substr(0, 5) == "ys__n") { - bool inv = abc_sname.back() == 'v'; - if (inv) abc_sname.pop_back(); abc_sname.erase(0, 5); if (std::isdigit(abc_sname.at(0))) { int sid = std::stoi(abc_sname); + size_t postfix_start = abc_sname.find_first_not_of("0123456789"); + std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : ""; + if (sid < GetSize(signal_list)) { auto sig = signal_list.at(sid); @@ -355,8 +356,7 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp sstr << "[" << sig.bit.offset << "]"; if (isnew) sstr << "_new"; - if (inv) - sstr << "_inv"; + sstr << postfix; if (orig_wire != nullptr) *orig_wire = sig.bit.wire; return sstr.str(); From a98069d76284ac31fd6652236ab40ecc3f584816 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sun, 5 May 2019 19:29:11 -0700 Subject: [PATCH 37/41] verilog_parser: Fix Bison warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of Bison 2.6, name-prefix is deprecated. This fixes frontends/verilog/verilog_parser.y:99.1-34: warning: deprecated directive, use ‘%define api.prefix {frontend_verilog_yy}’ [-Wdeprecated] %name-prefix "frontend_verilog_yy" For details: https://www.gnu.org/software/bison/manual/html_node/Multiple-Parsers.html Compile tested only. Signed-off-by: Ben Widawsky --- frontends/verilog/verilog_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 08377ad9a..46b3a9025 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -96,7 +96,7 @@ static void free_attr(std::map *al) %} -%name-prefix "frontend_verilog_yy" +%define api.prefix {frontend_verilog_yy} %union { std::string *string; From ba6ce21a74425788b5a98e2e628c089841b47aa3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 6 May 2019 12:45:22 +0200 Subject: [PATCH 38/41] Cleanups in opt_clean Signed-off-by: Clifford Wolf --- passes/opt/opt_clean.cc | 63 +++++++++++------------------------------ 1 file changed, 16 insertions(+), 47 deletions(-) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 9f6212526..81432b175 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -276,7 +276,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos } } - std::vector maybe_del_wires; + pool del_wires_queue; for (auto wire : module->wires()) { SigSpec s1 = SigSpec(wire), s2 = assign_map(s1); @@ -290,7 +290,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos if (initval.is_fully_undef()) wire->attributes.erase("\\init"); - bool maybe_del = false; + bool delete_this_wire = false; if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) { /* do not delete anything with "keep" or module ports or initialized wires */ } else @@ -298,13 +298,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos /* do not get rid of public names unless in purge mode */ } else { if (!raw_used_signals_noaliases.check_any(s1)) - maybe_del = true; + delete_this_wire = true; if (!used_signals_nodrivers.check_any(s2)) - maybe_del = true; + delete_this_wire = true; } - if (maybe_del) { - maybe_del_wires.push_back(wire); + if (delete_this_wire) { + del_wires_queue.insert(wire); } else { RTLIL::SigSig new_conn; for (int i = 0; i < GetSize(s1); i++) @@ -347,50 +347,19 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos } } - - pool del_wires; - - int del_wires_count = 0; - for (auto wire : maybe_del_wires) { - SigSpec s1 = SigSpec(wire); - if (used_signals_nodrivers.check_any(s1)) { - SigSpec s2 = assign_map(s1); - Const initval; - if (wire->attributes.count("\\init")) - initval = wire->attributes.at("\\init"); - if (GetSize(initval) != GetSize(wire)) - initval.bits.resize(GetSize(wire), State::Sx); - RTLIL::SigSig new_conn; - for (int i = 0; i < GetSize(s1); i++) - if (s1[i] != s2[i]) { - if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) { - s2[i] = initval[i]; - initval[i] = State::Sx; - } - new_conn.first.append_bit(s1[i]); - new_conn.second.append_bit(s2[i]); - } - if (new_conn.first.size() > 0) { - if (initval.is_fully_undef()) - wire->attributes.erase("\\init"); - else - wire->attributes.at("\\init") = initval; - module->connect(new_conn); - } - } else { - if (ys_debug() || (check_public_name(wire->name) && verbose)) { - log_debug(" removing unused non-port wire %s.\n", wire->name.c_str()); - } - del_wires.insert(wire); - del_wires_count++; - } + int del_temp_wires_count = 0; + for (auto wire : del_wires_queue) { + if (ys_debug() || (check_public_name(wire->name) && verbose)) + log_debug(" removing unused non-port wire %s.\n", wire->name.c_str()); + else + del_temp_wires_count++; } - module->remove(del_wires); - count_rm_wires += del_wires.size(); + module->remove(del_wires_queue); + count_rm_wires += GetSize(del_wires_queue); - if (verbose && del_wires_count > 0) - log_debug(" removed %d unused temporary wires.\n", del_wires_count); + if (verbose && del_temp_wires_count) + log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count); } bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) From f02e22a35a2b23bbeefa38e68f4fd06a7a7cebc7 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 6 May 2019 13:30:43 +0200 Subject: [PATCH 39/41] Fix bug in "expose -input" Signed-off-by: Clifford Wolf --- passes/sat/expose.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc index 809345486..71ce1683d 100644 --- a/passes/sat/expose.cc +++ b/passes/sat/expose.cc @@ -508,7 +508,7 @@ struct ExposePass : public Pass { } for (auto &conn : module->connections_) - conn.first = out_to_in_map(sigmap(conn.first)); + conn.first = out_to_in_map(conn.first); } if (flag_cut) From b37c31e2cb82343e363d39e4b35ebdb82f4f69a3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 6 May 2019 15:34:19 +0200 Subject: [PATCH 40/41] Bugfix in peepopt_shiftmul.pmg Signed-off-by: Clifford Wolf --- passes/pmgen/peepopt_shiftmul.pmg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index 1f9b3c2b9..fe861b728 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -8,9 +8,13 @@ endmatch code shamt shamt = port(shift, \B); + if (shamt.empty()) + reject; if (shamt[GetSize(shamt)-1] == State::S0) { do { shamt.remove(GetSize(shamt)-1); + if (shamt.empty()) + reject; } while (shamt[GetSize(shamt)-1] == State::S0); } else if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) { From 20268d12a51e157effc209de5613f0ac8308a61f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 6 May 2019 15:38:43 +0200 Subject: [PATCH 41/41] Fix the other bison warning in ilang_parser.y Signed-off-by: Clifford Wolf --- frontends/ilang/ilang_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index f83824088..7bb216dd0 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -45,7 +45,7 @@ YOSYS_NAMESPACE_END USING_YOSYS_NAMESPACE %} -%name-prefix "rtlil_frontend_ilang_yy" +%define api.prefix {rtlil_frontend_ilang_yy} %union { char *string;