diff options
author | Eddie Hung <eddie@fpgeh.com> | 2019-05-21 14:21:00 -0700 |
---|---|---|
committer | Eddie Hung <eddie@fpgeh.com> | 2019-05-21 14:21:00 -0700 |
commit | fb09c6219b057100d2e43028ec710888c20924fd (patch) | |
tree | 7f1de06040bf3276fb414acf68a12eac1421389d /passes | |
parent | 283e33ba5aad3a66bd14c30e1f52361c5f4c9789 (diff) | |
parent | c907899422884d959632ed42c6589a0720b681e4 (diff) | |
download | yosys-fb09c6219b057100d2e43028ec710888c20924fd.tar.gz yosys-fb09c6219b057100d2e43028ec710888c20924fd.tar.bz2 yosys-fb09c6219b057100d2e43028ec710888c20924fd.zip |
Merge remote-tracking branch 'origin/master' into xc7mux
Diffstat (limited to 'passes')
-rw-r--r-- | passes/cmds/bugpoint.cc | 6 | ||||
-rw-r--r-- | passes/cmds/cover.cc | 10 | ||||
-rw-r--r-- | passes/cmds/stat.cc | 76 | ||||
-rw-r--r-- | passes/hierarchy/hierarchy.cc | 76 | ||||
-rw-r--r-- | passes/opt/opt_clean.cc | 215 | ||||
-rw-r--r-- | passes/opt/opt_expr.cc | 13 | ||||
-rw-r--r-- | passes/opt/opt_muxtree.cc | 14 | ||||
-rw-r--r-- | passes/pmgen/README.md | 24 | ||||
-rw-r--r-- | passes/pmgen/peepopt.cc | 2 | ||||
-rw-r--r-- | passes/pmgen/peepopt_shiftmul.pmg | 4 | ||||
-rw-r--r-- | passes/sat/expose.cc | 2 | ||||
-rw-r--r-- | passes/sat/fmcombine.cc | 41 | ||||
-rw-r--r-- | passes/techmap/abc.cc | 29 | ||||
-rw-r--r-- | passes/techmap/dffinit.cc | 3 | ||||
-rw-r--r-- | passes/techmap/flowmap.cc | 4 | ||||
-rw-r--r-- | passes/techmap/libparse.cc | 2 | ||||
-rw-r--r-- | passes/techmap/zinit.cc | 2 |
17 files changed, 384 insertions, 139 deletions
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc index 4b22f6d2d..038ab7c7c 100644 --- a/passes/cmds/bugpoint.cc +++ b/passes/cmds/bugpoint.cc @@ -281,6 +281,9 @@ struct BugpointPass : public Pass { } extra_args(args, argidx, design); + if (script.empty()) + log_cmd_error("Missing -script option.\n"); + if (!has_part) { modules = true; @@ -298,7 +301,7 @@ struct BugpointPass : public Pass { if (!check_logfile(grep)) log_cmd_error("The provided grep string is not found in the log file!\n"); - int seed = 0, crashing_seed = seed; + int seed = 0; bool found_something = false, stage2 = false; while (true) { @@ -324,7 +327,6 @@ struct BugpointPass : public Pass { if (crashing_design != design) delete crashing_design; crashing_design = simplified; - crashing_seed = seed; found_something = true; } else diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc index 0ec747671..1128116b4 100644 --- a/passes/cmds/cover.cc +++ b/passes/cmds/cover.cc @@ -98,21 +98,23 @@ struct CoverPass : public Pass { } if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) { const char *open_mode = args[argidx] == "-a" ? "a+" : "w"; - std::string filename = args[++argidx]; + const std::string &filename = args[++argidx]; + FILE *f = nullptr; if (args[argidx-1] == "-d") { #ifdef _WIN32 log_cmd_error("The 'cover -d' option is not supported on win32.\n"); #else char filename_buffer[4096]; snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid()); - filename = mkstemps(filename_buffer, 4); + f = fdopen(mkstemps(filename_buffer, 4), "w"); #endif + } else { + f = fopen(filename.c_str(), open_mode); } - FILE *f = fopen(filename.c_str(), open_mode); if (f == NULL) { for (auto f : out_files) fclose(f); - log_cmd_error("Can't create file %s.\n", args[argidx].c_str()); + log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx].c_str()); } out_files.push_back(f); continue; diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 3909c4c8c..c42f7fcdd 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -37,7 +37,9 @@ struct statdata_t STAT_INT_MEMBERS #undef X double area; + string tech; + std::map<RTLIL::IdString, int> techinfo; std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type; std::set<RTLIL::IdString> unknown_cell_area; @@ -70,8 +72,10 @@ struct statdata_t #undef X } - statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area) + statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area, string techname) { + tech = techname; + #define X(_name) _name = 0; STAT_NUMERIC_MEMBERS #undef X @@ -153,7 +157,8 @@ struct statdata_t log(" Number of processes: %6d\n", num_processes); log(" Number of cells: %6d\n", num_cells); for (auto &it : num_cells_by_type) - log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second); + if (it.second) + log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second); if (!unknown_cell_area.empty()) { log("\n"); @@ -165,6 +170,59 @@ struct statdata_t log("\n"); log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); } + + if (tech == "xilinx") + { + int lut6_cnt = num_cells_by_type["\\LUT6"]; + int lut5_cnt = num_cells_by_type["\\LUT5"]; + int lut4_cnt = num_cells_by_type["\\LUT4"]; + int lut3_cnt = num_cells_by_type["\\LUT3"]; + int lut2_cnt = num_cells_by_type["\\LUT2"]; + int lut1_cnt = num_cells_by_type["\\LUT1"]; + int lc_cnt = 0; + + lc_cnt += lut6_cnt; + + lc_cnt += lut5_cnt; + if (lut1_cnt) { + int cnt = std::min(lut5_cnt, lut1_cnt); + lut5_cnt -= cnt; + lut1_cnt -= cnt; + } + + lc_cnt += lut4_cnt; + if (lut1_cnt) { + int cnt = std::min(lut4_cnt, lut1_cnt); + lut4_cnt -= cnt; + lut1_cnt -= cnt; + } + if (lut2_cnt) { + int cnt = std::min(lut4_cnt, lut2_cnt); + lut4_cnt -= cnt; + lut2_cnt -= cnt; + } + + lc_cnt += lut3_cnt; + if (lut1_cnt) { + int cnt = std::min(lut3_cnt, lut1_cnt); + lut3_cnt -= cnt; + lut1_cnt -= cnt; + } + if (lut2_cnt) { + int cnt = std::min(lut3_cnt, lut2_cnt); + lut3_cnt -= cnt; + lut2_cnt -= cnt; + } + if (lut3_cnt) { + int cnt = (lut3_cnt + 1) / 2; + lut3_cnt -= cnt; + } + + lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2; + + log("\n"); + log(" Estimated number of LCs: %10d\n", lc_cnt); + } } }; @@ -226,6 +284,10 @@ struct StatPass : public Pass { log(" -liberty <liberty_file>\n"); log(" use cell area information from the provided liberty file\n"); log("\n"); + log(" -tech <technology>\n"); + log(" print area estemate for the specified technology. Corrently supported\n"); + log(" calues for <technology>: xilinx\n"); + log("\n"); log(" -width\n"); log(" annotate internal cell types with their word width.\n"); log(" e.g. $add_8 for an 8 bit wide $add cell.\n"); @@ -239,6 +301,7 @@ struct StatPass : public Pass { RTLIL::Module *top_mod = NULL; std::map<RTLIL::IdString, statdata_t> mod_stat; dict<IdString, double> cell_area; + string techname; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -253,6 +316,10 @@ struct StatPass : public Pass { read_liberty_cellarea(cell_area, liberty_file); continue; } + if (args[argidx] == "-tech" && argidx+1 < args.size()) { + techname = args[++argidx]; + continue; + } if (args[argidx] == "-top" && argidx+1 < args.size()) { if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0) log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str()); @@ -263,6 +330,9 @@ struct StatPass : public Pass { } extra_args(args, argidx, design); + if (techname != "" && techname != "xilinx") + log_cmd_error("Unsupported technology: '%s'\n", techname.c_str()); + for (auto mod : design->selected_modules()) { if (!top_mod && design->full_selection()) @@ -272,7 +342,7 @@ struct StatPass : public Pass { if (mod->attributes.count("\\abc_box_id")) continue; - statdata_t data(design, mod, width_mode, cell_area); + statdata_t data(design, mod, width_mode, cell_area, techname); mod_stat[mod->name] = data; log("\n"); diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index b8ff99884..72bc2e133 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -570,7 +570,7 @@ struct HierarchyPass : public Pass { log("\n"); log(" -simcheck\n"); log(" like -check, but also throw an error if blackbox modules are\n"); - log(" instantiated, and throw an error if the design has no top module\n"); + log(" instantiated, and throw an error if the design has no top module.\n"); log("\n"); log(" -purge_lib\n"); log(" by default the hierarchy command will not remove library (blackbox)\n"); @@ -583,20 +583,20 @@ struct HierarchyPass : public Pass { log("\n"); log(" -keep_positionals\n"); log(" per default this pass also converts positional arguments in cells\n"); - log(" to arguments using port names. this option disables this behavior.\n"); + log(" to arguments using port names. This option disables this behavior.\n"); log("\n"); log(" -keep_portwidths\n"); log(" per default this pass adjusts the port width on cells that are\n"); - log(" module instances when the width does not match the module port. this\n"); + log(" module instances when the width does not match the module port. This\n"); log(" option disables this behavior.\n"); log("\n"); log(" -nokeep_asserts\n"); log(" per default this pass sets the \"keep\" attribute on all modules\n"); - log(" that directly or indirectly contain one or more $assert cells. this\n"); - log(" option disables this behavior.\n"); + log(" that directly or indirectly contain one or more formal properties.\n"); + log(" This option disables this behavior.\n"); log("\n"); log(" -top <module>\n"); - log(" use the specified top module to built a design hierarchy. modules\n"); + log(" use the specified top module to build the design hierarchy. Modules\n"); log(" outside this tree (unused modules) are removed.\n"); log("\n"); log(" when the -top option is used, the 'top' attribute will be set on the\n"); @@ -606,6 +606,12 @@ struct HierarchyPass : public Pass { log(" -auto-top\n"); log(" automatically determine the top of the design hierarchy and mark it.\n"); log("\n"); + log(" -chparam name value \n"); + log(" elaborate the top module using this parameter value. Modules on which\n"); + log(" this parameter does not exist may cause a warning message to be output.\n"); + log(" This option can be specified multiple times to override multiple\n"); + log(" parameters. String values must be passed in double quotes (\").\n"); + log("\n"); log("In -generate mode this pass generates blackbox modules for the given cell\n"); log("types (wildcards supported). For this the design is searched for cells that\n"); log("match the given types and then the given port declarations are used to\n"); @@ -641,6 +647,7 @@ struct HierarchyPass : public Pass { bool nokeep_asserts = false; std::vector<std::string> generate_cells; std::vector<generate_port_decl_t> generate_ports; + std::map<std::string, std::string> parameters; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -715,28 +722,61 @@ struct HierarchyPass : public Pass { if (args[argidx] == "-top") { if (++argidx >= args.size()) log_cmd_error("Option -top requires an additional argument!\n"); - top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL; - if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) { - dict<RTLIL::IdString, RTLIL::Const> empty_parameters; - design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters); - top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL; - } - if (top_mod == NULL) - load_top_mod = args[argidx]; + load_top_mod = args[argidx]; continue; } if (args[argidx] == "-auto-top") { auto_top_mode = true; continue; } + if (args[argidx] == "-chparam" && argidx+2 < args.size()) { + const std::string &key = args[++argidx]; + const std::string &value = args[++argidx]; + auto r = parameters.emplace(key, value); + if (!r.second) { + log_warning("-chparam %s already specified: overwriting.\n", key.c_str()); + r.first->second = value; + } + continue; + } break; } extra_args(args, argidx, design, false); - if (!load_top_mod.empty()) { + if (!load_top_mod.empty()) + { + IdString top_name = RTLIL::escape_id(load_top_mod); + IdString abstract_id = "$abstract" + RTLIL::escape_id(load_top_mod); + top_mod = design->module(top_name); + + dict<RTLIL::IdString, RTLIL::Const> top_parameters; + for (auto ¶ : parameters) { + SigSpec sig_value; + if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second)) + log_cmd_error("Can't decode value '%s'!\n", para.second.c_str()); + top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); + } + + if (top_mod == nullptr && design->module(abstract_id)) + top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters)); + else if (top_mod != nullptr && !top_parameters.empty()) + top_mod = design->module(top_mod->derive(design, top_parameters)); + + if (top_mod != nullptr && top_mod->name != top_name) { + Module *m = top_mod->clone(); + m->name = top_name; + Module *old_mod = design->module(top_name); + if (old_mod) + design->remove(old_mod); + design->add(m); + top_mod = m; + } + } + + if (top_mod == nullptr && !load_top_mod.empty()) { #ifdef YOSYS_ENABLE_VERIFIC if (verific_import_pending) { - verific_import(design, load_top_mod); + verific_import(design, parameters, load_top_mod); top_mod = design->module(RTLIL::escape_id(load_top_mod)); } #endif @@ -745,7 +785,7 @@ struct HierarchyPass : public Pass { } else { #ifdef YOSYS_ENABLE_VERIFIC if (verific_import_pending) - verific_import(design); + verific_import(design, parameters); #endif } @@ -846,7 +886,7 @@ struct HierarchyPass : public Pass { std::map<RTLIL::Module*, bool> cache; for (auto mod : design->modules()) if (set_keep_assert(cache, mod)) { - log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod)); + log("Module %s directly or indirectly contains formal properties -> setting \"keep\" attribute.\n", log_id(mod)); mod->set_bool_attribute("\\keep"); } } diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 5d95c4f1a..bf8020169 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -64,7 +64,7 @@ struct keep_cache_t bool query(Cell *cell) { - if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover")) + if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule")) return true; if (cell->has_keep_attr()) @@ -85,22 +85,34 @@ void rmunused_module_cells(Module *module, bool verbose) { SigMap sigmap(module); pool<Cell*> queue, unused; + pool<SigBit> used_raw_bits; dict<SigBit, pool<Cell*>> wire2driver; + dict<SigBit, vector<string>> driver_driver_logs; + + SigMap raw_sigmap; + for (auto &it : module->connections_) { + for (int i = 0; i < GetSize(it.second); i++) { + if (it.second[i].wire != nullptr) + raw_sigmap.add(it.first[i], it.second[i]); + } + } for (auto &it : module->cells_) { Cell *cell = it.second; for (auto &it2 : cell->connections()) { - if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first)) - for (auto raw_bit : it2.second) { - if (raw_bit.wire == nullptr) - continue; - auto bit = sigmap(raw_bit); - if (bit.wire == nullptr) - log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n", - log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)); - if (bit.wire != nullptr) - wire2driver[bit].insert(cell); - } + if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first)) + continue; + for (auto raw_bit : it2.second) { + if (raw_bit.wire == nullptr) + continue; + auto bit = sigmap(raw_bit); + if (bit.wire == nullptr) + driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict " + "for %s between cell %s.%s and constant %s in %s: Resolved using constant.", + log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module))); + if (bit.wire != nullptr) + wire2driver[bit].insert(cell); + } } if (keep_cache.query(cell)) queue.insert(cell); @@ -114,6 +126,8 @@ void rmunused_module_cells(Module *module, bool verbose) for (auto bit : sigmap(wire)) for (auto c : wire2driver[bit]) queue.insert(c), unused.erase(c); + for (auto raw_bit : SigSpec(wire)) + used_raw_bits.insert(raw_sigmap(raw_bit)); } } @@ -142,6 +156,22 @@ void rmunused_module_cells(Module *module, bool verbose) module->remove(cell); count_rm_cells++; } + + for (auto &it : module->cells_) { + Cell *cell = it.second; + for (auto &it2 : cell->connections()) { + if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first)) + continue; + for (auto raw_bit : raw_sigmap(it2.second)) + used_raw_bits.insert(raw_bit); + } + } + + for (auto it : driver_driver_logs) { + if (used_raw_bits.count(it.first)) + for (auto msg : it.second) + log_warning("%s\n", msg.c_str()); + } } int count_nontrivial_wire_attrs(RTLIL::Wire *w) @@ -202,7 +232,7 @@ bool check_public_name(RTLIL::IdString id) return true; } -void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose) +bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose) { SigPool register_signals; SigPool connected_signals; @@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos module->connections_.clear(); SigPool used_signals; + SigPool raw_used_signals; SigPool used_signals_nodrivers; for (auto &it : module->cells_) { RTLIL::Cell *cell = it.second; for (auto &it2 : cell->connections_) { assign_map.apply(it2.second); + raw_used_signals.add(it2.second); used_signals.add(it2.second); if (!ct_all.cell_output(cell->type, it2.first)) used_signals_nodrivers.add(it2.second); @@ -259,6 +291,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos RTLIL::Wire *wire = it.second; if (wire->port_id > 0) { RTLIL::SigSpec sig = RTLIL::SigSpec(wire); + raw_used_signals.add(sig); assign_map.apply(sig); used_signals.add(sig); if (!wire->port_input) @@ -271,85 +304,102 @@ 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()) { - 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]); + 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"); + + if (GetSize(wire) == 0) { + // delete zero-width wires + goto delete_this_wire; + } else + 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 (!raw_used_signals.check_any(s1)) { + // delete wires that aren't used by anything directly + goto delete_this_wire; + } else + if (!used_signals.check_any(s2)) { + // delete wires that aren't used by anything indirectly, even though other wires may alias it + goto delete_this_wire; + } + + if (0) + { + delete_this_wire: + del_wires_queue.insert(wire); + } + else + { + 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; } - 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); + 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); } - } else { - if (!used_signals.check_any(RTLIL::SigSpec(wire))) - maybe_del_wires.push_back(wire); - } - RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire)); - if (!used_signals_nodrivers.check_any(sig)) { - std::string unused_bits; - for (int i = 0; i < GetSize(sig); i++) { - if (sig[i].wire == NULL) - continue; - if (!used_signals_nodrivers.check(sig[i])) { - if (!unused_bits.empty()) - unused_bits += " "; - unused_bits += stringf("%d", i); + if (!used_signals_nodrivers.check_all(s2)) { + std::string unused_bits; + for (int i = 0; i < GetSize(s2); i++) { + if (s2[i].wire == NULL) + continue; + if (!used_signals_nodrivers.check(s2[i])) { + if (!unused_bits.empty()) + unused_bits += " "; + unused_bits += stringf("%d", i); + } } - } - if (unused_bits.empty() || wire->port_id != 0) + if (unused_bits.empty() || wire->port_id != 0) + wire->attributes.erase("\\unused_bits"); + else + wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits); + } else { wire->attributes.erase("\\unused_bits"); - else - wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits); - } else { - wire->attributes.erase("\\unused_bits"); + } } } + 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++; + } - pool<RTLIL::Wire*> del_wires; + module->remove(del_wires_queue); + count_rm_wires += GetSize(del_wires_queue); - 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) { - log_debug(" removing unused non-port wire %s.\n", wire->name.c_str()); - } - del_wires.insert(wire); - del_wires_count++; - } + if (verbose && del_temp_wires_count) + log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count); - module->remove(del_wires); - count_rm_wires += del_wires.size(); - - if (verbose && del_wires_count > 0) - log_debug(" removed %d unused temporary wires.\n", del_wires_count); + return !del_wires_queue.empty(); } bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) @@ -447,10 +497,10 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool module->design->scratchpad_set_bool("opt.did_something", true); rmunused_module_cells(module, verbose); - rmunused_module_signals(module, purge_mode, verbose); + while (rmunused_module_signals(module, purge_mode, verbose)) { } if (rminit && rmunused_module_init(module, purge_mode, verbose)) - rmunused_module_signals(module, purge_mode, verbose); + while (rmunused_module_signals(module, purge_mode, verbose)) { } } struct OptCleanPass : public Pass { @@ -496,6 +546,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 +614,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; + } } } } diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index dbebf21e0..6511e091b 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -184,6 +184,10 @@ struct OptMuxtreeWorker log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); root_mux_rerun.erase(mux_idx); eval_root_mux(mux_idx); + if (glob_abort_cnt == 0) { + log(" Giving up (too many iterations)\n"); + return; + } } while (!root_mux_rerun.empty()) { @@ -192,9 +196,14 @@ struct OptMuxtreeWorker log_assert(root_enable_muxes.at(mux_idx)); root_mux_rerun.erase(mux_idx); eval_root_mux(mux_idx); + if (glob_abort_cnt == 0) { + log(" Giving up (too many iterations)\n"); + return; + } } log(" Analyzing evaluation results.\n"); + log_assert(glob_abort_cnt > 0); for (auto &mi : mux2info) { @@ -397,10 +406,8 @@ struct OptMuxtreeWorker void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count) { - if (glob_abort_cnt == 0) { - log(" Giving up (too many iterations)\n"); + if (glob_abort_cnt == 0) return; - } glob_abort_cnt--; muxinfo_t &muxinfo = mux2info[mux_idx]; @@ -454,6 +461,7 @@ struct OptMuxtreeWorker void eval_root_mux(int mux_idx) { + log_assert(glob_abort_cnt > 0); knowledge_t knowledge; knowledge.known_inactive.resize(GetSize(bit2info)); knowledge.known_active.resize(GetSize(bit2info)); diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 7a46558b1..d0711c730 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/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<std::string> 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++) 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()) { diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc index 3add9a9eb..50ab38063 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/sat/fmcombine.cc b/passes/sat/fmcombine.cc index cd75ca860..f64d99dc2 100644 --- a/passes/sat/fmcombine.cc +++ b/passes/sat/fmcombine.cc @@ -26,6 +26,8 @@ PRIVATE_NAMESPACE_BEGIN struct opts_t { + bool initeq = false; + bool anyeq = false; bool fwd = false; bool bwd = false; bool nop = false; @@ -56,7 +58,7 @@ struct FmcombineWorker return newsig; } - void import_prim_cell(Cell *cell, const string &suffix) + Cell *import_prim_cell(Cell *cell, const string &suffix) { Cell *c = module->addCell(cell->name.str() + suffix, cell->type); c->parameters = cell->parameters; @@ -64,6 +66,8 @@ struct FmcombineWorker for (auto &conn : cell->connections()) c->setPort(conn.first, import_sig(conn.second, suffix)); + + return c; } void import_hier_cell(Cell *cell) @@ -102,8 +106,24 @@ struct FmcombineWorker for (auto cell : original->cells()) { if (design->module(cell->type) == nullptr) { - import_prim_cell(cell, "_gold"); - import_prim_cell(cell, "_gate"); + if (opts.anyeq && cell->type.in("$anyseq", "$anyconst")) { + Cell *gold = import_prim_cell(cell, "_gold"); + for (auto &conn : cell->connections()) + module->connect(import_sig(conn.second, "_gate"), gold->getPort(conn.first)); + } else { + Cell *gold = import_prim_cell(cell, "_gold"); + Cell *gate = import_prim_cell(cell, "_gate"); + if (opts.initeq) { + if (cell->type.in("$ff", "$dff", "$dffe", + "$dffsr", "$adff", "$dlatch", "$dlatchsr")) { + SigSpec gold_q = gold->getPort("\\Q"); + SigSpec gate_q = gate->getPort("\\Q"); + SigSpec en = module->Initstate(NEW_ID); + SigSpec eq = module->Eq(NEW_ID, gold_q, gate_q); + module->addAssume(NEW_ID, eq, en); + } + } + } } else { import_hier_cell(cell); } @@ -229,6 +249,13 @@ struct FmcombinePass : public Pass { log("This is useful for formal test benches that check what differences in behavior\n"); log("a slight difference in input causes in a module.\n"); log("\n"); + log(" -initeq\n"); + log(" Insert assumptions that initially all FFs in both circuits have the\n"); + log(" same initial values.\n"); + log("\n"); + log(" -anyeq\n"); + log(" Do not duplicate $anyseq/$anyconst cells.\n"); + log("\n"); log(" -fwd\n"); log(" Insert forward hint assumptions into the combined module.\n"); log("\n"); @@ -261,6 +288,14 @@ struct FmcombinePass : public Pass { // filename = args[++argidx]; // continue; // } + if (args[argidx] == "-initeq") { + opts.initeq = true; + continue; + } + if (args[argidx] == "-anyeq") { + opts.anyeq = true; + continue; + } if (args[argidx] == "-fwd") { opts.fwd = true; continue; 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/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)) diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index 0b7931e48..f5892a60e 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -397,7 +397,6 @@ struct FlowGraph pool<RTLIL::SigBit> x, xi; NodePrime source_prime = {source, true}; - NodePrime sink_prime = {sink, false}; pool<NodePrime> visited; vector<NodePrime> worklist = {source_prime}; while (!worklist.empty()) @@ -1382,7 +1381,8 @@ struct FlowmapWorker vector<RTLIL::SigBit> input_nodes(lut_edges_bw[node].begin(), lut_edges_bw[node].end()); RTLIL::Const lut_table(State::Sx, max(1 << input_nodes.size(), 1 << minlut)); - for (unsigned i = 0; i < (1 << input_nodes.size()); i++) + unsigned const mask = 1 << input_nodes.size(); + for (unsigned i = 0; i < mask; i++) { ce.push(); for (size_t n = 0; n < input_nodes.size(); n++) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 991cc4498..349ccc115 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -94,7 +94,7 @@ int LibertyParser::lexer(std::string &str) // search for identifiers, numbers, plus or minus. if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') { - str = c; + str = static_cast<char>(c); while (1) { c = f.get(); if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc index b46147fb9..2aefc091d 100644 --- a/passes/techmap/zinit.cc +++ b/passes/techmap/zinit.cc @@ -46,7 +46,7 @@ struct ZinitPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-singleton") { + if (args[argidx] == "-all") { all_mode = true; continue; } |