diff options
-rw-r--r-- | frontends/ilang/ilang_parser.y | 2 | ||||
-rw-r--r-- | frontends/verilog/verilog_lexer.l | 2 | ||||
-rw-r--r-- | frontends/verilog/verilog_parser.y | 12 | ||||
-rw-r--r-- | passes/opt/opt_clean.cc | 91 | ||||
-rw-r--r-- | passes/opt/wreduce.cc | 36 | ||||
-rw-r--r-- | passes/pmgen/.gitignore | 1 | ||||
-rw-r--r-- | passes/pmgen/Makefile.inc | 17 | ||||
-rw-r--r-- | passes/pmgen/README.md | 24 | ||||
-rw-r--r-- | passes/pmgen/ice40_dsp.cc | 117 | ||||
-rw-r--r-- | passes/pmgen/ice40_dsp.pmg | 2 | ||||
-rw-r--r-- | passes/pmgen/peepopt.cc | 68 | ||||
-rw-r--r-- | passes/pmgen/peepopt_muldiv.pmg | 36 | ||||
-rw-r--r-- | passes/pmgen/peepopt_shiftmul.pmg | 87 | ||||
-rw-r--r-- | passes/pmgen/pmgen.py | 263 | ||||
-rw-r--r-- | passes/sat/expose.cc | 2 | ||||
-rw-r--r-- | passes/techmap/abc.cc | 29 | ||||
-rw-r--r-- | techlibs/common/synth.cc | 2 | ||||
-rw-r--r-- | techlibs/ice40/synth_ice40.cc | 2 | ||||
-rw-r--r-- | techlibs/xilinx/cells_map.v | 14 | ||||
-rw-r--r-- | tests/simple/peepopt.v | 9 | ||||
-rwxr-xr-x | tests/tools/autotest.sh | 3 |
21 files changed, 593 insertions, 226 deletions
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; diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 6ef38252a..08e556e8e 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -206,7 +206,9 @@ 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); } +"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..46b3a9025 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -96,7 +96,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) %} -%name-prefix "frontend_verilog_yy" +%define api.prefix {frontend_verilog_yy} %union { std::string *string; @@ -106,11 +106,11 @@ static void free_attr(std::map<std::string, AstNode*> *al) } %token <string> 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 -%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; @@ -1341,6 +1344,9 @@ opt_property: TOK_PROPERTY { $$ = true; } | + TOK_FINAL { + $$ = false; + } | /* empty */ { $$ = false; }; diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 96118e906..81432b175 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); } @@ -271,29 +276,36 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos } } - std::vector<RTLIL::Wire*> maybe_del_wires; + pool<RTLIL::Wire*> del_wires_queue; 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")) { - if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) - maybe_del = true; + 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 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 + 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)) - maybe_del = true; + if (!raw_used_signals_noaliases.check_any(s1)) + delete_this_wire = true; + if (!used_signals_nodrivers.check_any(s2)) + delete_this_wire = true; } - if (maybe_del) { - maybe_del_wires.push_back(wire); + if (delete_this_wire) { + del_wires_queue.insert(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]) { @@ -335,50 +347,19 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos } } - - pool<RTLIL::Wire*> del_wires; - - int del_wires_count = 0; - 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++; - } + 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) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 41de8aad1..58c6e4b4b 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -531,6 +531,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/.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..7911132db 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -1,8 +1,23 @@ 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 + +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/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_<pattern_name>(callback_function)` method searches for all matches +for the pattern`<pattern_name>` 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.<state_name>` members. (The `.st` member is of type `foobar_pm::state_t`.) +`.st_<pattern_name>.<state_name>` members. (The `.st_<pattern_name>` member is +of type `foobar_pm::state_<pattern_name>_t`.) Similarly the `.pmg` file declares user data variables that become members of -`.ud`, a struct of type `foobar_pm::udata_t`. +`.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`. + +There are four versions of the `run_<pattern_name>()` method: Without callback, +callback without arguments, callback with reference to `pm`, and callback with +reference to `pm.st_<pattern_name>`. 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_<pattern_name>(callback_function)` is called. Declaring udata variables ------------------------- diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 3a054a463..39d033a04 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -19,47 +19,50 @@ #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; + #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 +72,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 +94,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 +105,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 +147,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 +169,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 +182,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 +201,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 +233,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 <SigBit> clock state <bool> clock_pol clock_vld state <SigSpec> sigA sigB sigY sigS diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc new file mode 100644 index 000000000..e7f95cf85 --- /dev/null +++ b/passes/pmgen/peepopt.cc @@ -0,0 +1,68 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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" + +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 + { + // |---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<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing PEEPOPT 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()) { + did_something = true; + while (did_something) { + did_something = false; + peepopt_pm pm(module, module->selected_cells()); + pm.run_shiftmul(); + pm.run_muldiv(); + } + } + } +} PeepoptPass; + +PRIVATE_NAMESPACE_END 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 <SigSpec> 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 <SigSpec> port(div, \A) === t + index <SigSpec> 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/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg new file mode 100644 index 000000000..fe861b728 --- /dev/null +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -0,0 +1,87 @@ +pattern shiftmul + +state <SigSpec> shamt + +match shift + select shift->type.in($shift, $shiftx, $shr) +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()) { + reject; + } + if (GetSize(shamt) > 20) + reject; +endcode + +match mul + select mul->type.in($mul) + select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const() + index <SigSpec> port(mul, \Y) === shamt +endmatch + +code + IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; + 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; + + 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); + 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 diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index d9747b065..81052afce 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -3,15 +3,42 @@ 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 +debug = False +genhdr = False + +opts, args = getopt.getopt(sys.argv[1:], "p:o:dg") + +for o, a in opts: + if o == "-p": + prefix = a + elif o == "-o": + outfile = a + elif o == "-d": + debug = True + elif o == "-g": + genhdr = True + +if outfile is None: + outfile = "/dev/stdout" + +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 + +current_pattern = None +patterns = dict() state_types = dict() udata_types = dict() blocks = list() @@ -77,7 +104,8 @@ def rewrite_cpp(s): return "".join(t) -with open(pmgfile, "r") as f: +def process_pmgfile(f): + global current_pattern while True: line = f.readline() if line == "": break @@ -87,14 +115,31 @@ with open(pmgfile, "r") as 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": @@ -103,19 +148,20 @@ with open(pmgfile, "r") as 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() @@ -158,15 +204,18 @@ with open(pmgfile, "r") as 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: @@ -179,18 +228,37 @@ with open(pmgfile, "r") as f: block["code"].append(rewrite_cpp(l.rstrip())) blocks.append(block) + continue -with open(outfile, "w") as f: - print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) - print("", file=f) + assert False - print("#include \"kernel/yosys.h\"", file=f) - print("#include \"kernel/sigtools.h\"", file=f) - print("", file=f) +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) - print("YOSYS_NAMESPACE_BEGIN", file=f) +with open(outfile, "w") as f: + for fn in pmgfiles: + print("// Generated by pmgen.py from {}".format(fn), 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) print(" SigMap sigmap;", file=f) @@ -212,17 +280,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] == "\\": @@ -258,20 +328,24 @@ 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["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) + 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) @@ -294,11 +368,13 @@ with open(outfile, "w") as f: print(" {}_pm(Module *module, const vector<Cell*> &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) @@ -328,34 +404,52 @@ with open(outfile, "w") as f: print(" }", file=f) print("", file=f) - print(" void run(std::function<void()> 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<void({}_pm&)> 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<void()> 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<void({}_pm&)> 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<void(state_{}_t&)> 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) + 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)): 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) @@ -378,27 +472,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"]: @@ -417,11 +511,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: @@ -470,17 +564,12 @@ 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) + if genhdr: + print("", file=f) + print("YOSYS_NAMESPACE_END", file=f) 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) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 547115459..5b19d84fb 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -330,20 +330,33 @@ 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 inv = abc_sname.back() == 'v'; - if (inv) abc_sname.pop_back(); + 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") + { 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) { + 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); + 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 (inv) - sstr << "_inv"; + if (isnew) + sstr << "_new"; + sstr << postfix; if (orig_wire != nullptr) *orig_wire = sig.bit.wire; return sstr.str(); 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 5de33110a..bb96d66d1 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -241,6 +241,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"); 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; 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 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 |