From accfc70fc2bcfaa5f9f58e8a113a32e506f5081d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 9 Apr 2020 14:42:43 -0700 Subject: abc9: fix behaviour and help for -box option --- passes/techmap/abc9.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 1b3d5ff06..d8f2f0357 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -303,7 +303,7 @@ struct Abc9Pass : public ScriptPass if (help_mode) { run("foreach module in selection"); run(" abc9_ops -write_lut /input.lut", "(skip if '-lut' or '-luts')"); - run(" abc9_ops -write_box /input.box"); + run(" abc9_ops -write_box /input.box", "(skip if '-box')"); run(" write_xaiger -map /input.sym /input.xaig"); run(" abc9_exe [options] -cwd [-lut /input.lut] -box /input.box"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); @@ -333,7 +333,8 @@ struct Abc9Pass : public ScriptPass if (!lut_mode) run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str())); - run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); + if (box_file.empty()) + run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs"); @@ -349,7 +350,10 @@ struct Abc9Pass : public ScriptPass abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()); if (!lut_mode) abc9_exe_cmd += stringf(" -lut %s/input.lut", tempdir_name.c_str()); - abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str()); + if (box_file.empty()) + abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str()); + else + abc9_exe_cmd += stringf(" -box %s", box_file.c_str()); run_nocheck(abc9_exe_cmd); run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str())); run_nocheck("abc9_ops -reintegrate"); -- cgit v1.2.3 From 95763c8d18eec49de3acff5d38a82f54cc25cb1b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 09:38:07 -0700 Subject: abc9_ops: add 'dff' label for auto handling of (* abc9_flop *) boxes --- passes/hierarchy/submod.cc | 2 +- passes/techmap/abc9.cc | 89 ++++++-- passes/techmap/abc9_ops.cc | 558 +++++++++++++++++++++++++-------------------- 3 files changed, 391 insertions(+), 258 deletions(-) (limited to 'passes') diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc index 2db7cf26b..1f30a5160 100644 --- a/passes/hierarchy/submod.cc +++ b/passes/hierarchy/submod.cc @@ -389,7 +389,7 @@ struct SubmodPass : public Pass { while (did_something) { did_something = false; std::vector queued_modules; - for (auto mod : design->modules()) + for (auto mod : design->selected_modules()) if (handled_modules.count(mod->name) == 0 && design->selected_whole_module(mod->name)) queued_modules.push_back(mod->name); for (auto &modname : queued_modules) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index d8f2f0357..7f3e6abcc 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -151,8 +151,8 @@ struct Abc9Pass : public ScriptPass log(" specified).\n"); log("\n"); log(" -dff\n"); - log(" also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n"); - log(" domains are marked as such and automatically partitioned by ABC.\n"); + log(" also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n"); + log(" domains are supported and automatically partitioned by ABC.\n"); log("\n"); log(" -nocleanup\n"); log(" when this option is used, the temporary files created by this pass\n"); @@ -274,26 +274,74 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { - if (check_label("pre")) { + if (check_label("check")) { run("abc9_ops -check"); + } + + if (check_label("dff", "(only if -dff)")) { + if (dff_mode || help_mode) { + run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules + run("design -stash $abc9"); + run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in + run("proc"); + run("wbflip"); + run("techmap"); + run("opt"); + run("abc9_ops -prep_dff_map"); // rewrite specify + // TODO: Select fan-in cone $_DFF_[NP]_.Q + run("setattr -set submod \"$abc9_flop\" t:* t:$_DFF_N_ %d t:$_DFF_P_ %d"); + run("submod"); + run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out + run("delete *_$abc9_flop"); + if (help_mode) { + run("foreach module in design"); + run(" cd "); + run(" rename _$abc9_flop _TECHMAP_REPLACE_"); + run(" cd"); + } + else { + // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs + for (auto module : active_design->selected_modules()) { + run(stringf("cd %s", log_id(module->name))); + run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); + run("cd"); + } + } + run("design -stash $abc9_map"); + run("design -load $abc9"); + run("abc9_ops -prep_dff_unmap"); // create $abc9_unmap design + run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); + if (!help_mode) { + // TODO: Need a way to delete saved designs? + auto it = saved_designs.find("$abc9_map"); + delete it->second; + saved_designs.erase(it); + // TODO: Need a way to delete selections + active_design->selection_vars.erase(ID($abc9_flops)); + active_design->selection_vars.erase(ID($abc9_cells)); + } + } + } + + if (check_label("pre")) { run("scc -set_attr abc9_scc_id {}"); if (help_mode) run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)"); else - run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); + run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : "")); if (help_mode) run("abc9_ops -prep_lut ", "(skip if -lut or -luts)"); else if (!lut_mode) run(stringf("abc9_ops -prep_lut %d", maxlut)); if (help_mode) - run("abc9_ops -prep_box [-dff]", "(skip if -box)"); - else if (box_file.empty()) - run(stringf("abc9_ops -prep_box %s", dff_mode ? "-dff" : "")); + run("abc9_ops -prep_box", "(skip if -box)"); + else if (box_file.empty()) { + run("abc9_ops -prep_box"); + } run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); - if (dff_mode || help_mode) - run("abc9_ops -prep_dff", "(only if -dff)"); run("opt -purge @abc9_holes"); run("aigmap"); run("wbflip @abc9_holes"); @@ -304,10 +352,10 @@ struct Abc9Pass : public ScriptPass run("foreach module in selection"); run(" abc9_ops -write_lut /input.lut", "(skip if '-lut' or '-luts')"); run(" abc9_ops -write_box /input.box", "(skip if '-box')"); - run(" write_xaiger -map /input.sym /input.xaig"); - run(" abc9_exe [options] -cwd [-lut /input.lut] -box /input.box"); + run(" write_xaiger -map /input.sym [-dff] /input.xaig"); + run(" abc9_exe [options] -cwd -lut [/input.lut] -box [/input.box]"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); - run(" abc9_ops -reintegrate"); + run(" abc9_ops -reintegrate [-dff]"); } else { auto selected_modules = active_design->selected_modules(); @@ -335,7 +383,7 @@ struct Abc9Pass : public ScriptPass run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str())); if (box_file.empty()) run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); - run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); + run_nocheck(stringf("write_xaiger -map %s/input.sym %s %s/input.xaig", tempdir_name.c_str(), dff_mode ? "-dff" : "", tempdir_name.c_str())); int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs"); @@ -356,7 +404,7 @@ struct Abc9Pass : public ScriptPass abc9_exe_cmd += stringf(" -box %s", box_file.c_str()); run_nocheck(abc9_exe_cmd); run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str())); - run_nocheck("abc9_ops -reintegrate"); + run_nocheck(stringf("abc9_ops -reintegrate %s", dff_mode ? "-dff" : "")); } else log("Don't call ABC as there is nothing to map.\n"); @@ -373,6 +421,19 @@ struct Abc9Pass : public ScriptPass active_design->selection_stack.pop_back(); } } + + if (check_label("post")) { + if (dff_mode || help_mode) { + run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell + // ($_DFF_[NP]_ already shorted by -reintegrate) + if (!help_mode) { + // TODO: Need a way to delete saved designs? + auto it = saved_designs.find("$abc9_unmap"); + delete it->second; + saved_designs.erase(it); + } + } + } } } Abc9Pass; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 1345188a4..fe2e5c3ac 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -119,81 +119,127 @@ void mark_scc(RTLIL::Module *module) } } -void prep_dff(RTLIL::Module *module) -{ - auto design = module->design; - log_assert(design); - SigMap assign_map(module); - - typedef SigSpec clkdomain_t; - dict clk_to_mergeability; +void prep_dff_hier(RTLIL::Design *design) +{ + pool seen; + dict selection_vars; + auto r YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false))); + log_assert(r.second); + auto r2 YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_cells), RTLIL::Selection(false))); + log_assert(r2.second); + auto &modules_sel = design->selection_vars.at(ID($abc9_flops)); + auto &cells_sel = design->selection_vars.at(ID($abc9_cells)); + + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + auto inst_module = design->module(cell->type); + if (inst_module && inst_module->get_bool_attribute(ID::abc9_flop)) { + modules_sel.select(inst_module); + // Derive modules for all instantiations of (* abc9_flop *) + auto derived_type = inst_module->derive(design, cell->parameters); + // And remember one representative cell (for its parameters) + if (modules_sel.selected_modules.insert(derived_type).second) + cells_sel.select(module, cell); + } + } +} - for (auto cell : module->cells()) { - if (cell->type != ID($__ABC9_FF_)) - continue; +void prep_dff_map(RTLIL::Design *design) +{ + for (auto module : design->modules()) { + vector specify_cells; + SigBit D, Q; + for (auto cell : module->cells()) + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + if (D != SigBit()) + log_error("More than one $_DFF_[NP]_ cell found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + D = cell->getPort(ID::D); + Q = cell->getPort(ID::Q); + + // TODO: Can we avoid doing this? + // Convert (* init *) on $_DFF_[NP]_.Q to (* abc9_init *) attr on cell + log_assert(GetSize(Q.wire) == 1); + auto it = Q.wire->attributes.find(ID::init); + Const init; + if (it != Q.wire->attributes.end()) { + log_assert(GetSize(it->second) == 1); + init = it->second; + Q.wire->attributes.erase(it); + } + else + init = State::Sx; + auto r YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID::abc9_init, init)); + log_assert(r.second); + if (init == State::S1) { + log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); - Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str())); - if (abc9_clock_wire == NULL) - log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - SigSpec abc9_clock = assign_map(abc9_clock_wire); + module->makeblackbox(); - clkdomain_t key(abc9_clock); + auto wire = module->addWire(ID(_TECHMAP_FAIL_)); + wire->set_bool_attribute(ID::keep); + module->connect(wire, State::S1); - auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); - auto r2 = cell->attributes.insert(ID::abc9_mergeability); - log_assert(r2.second); - r2.first->second = r.first->second; + goto continue_outer_loop; + } + } + else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) + specify_cells.emplace_back(cell); + if (D == SigBit()) + log_error("$_DFF_[NP]_ cell not found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + + // Rewrite $specify cells that end with $_DFF_[NP]_.Q + // to $_DFF_[NP]_.D since it will be moved into + // the submodule + for (auto cell : specify_cells) { + auto DST = cell->getPort(ID::DST); + DST.replace(Q, D); + cell->setPort(ID::DST, DST); + } +continue_outer_loop: ; } +} - RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); - if (holes_module) { - SigMap sigmap(holes_module); - - dict replace; - for (auto cell : holes_module->cells().to_vector()) { - if (!cell->type.in(ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), - ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1), ID($_DFF_PP0_), ID($_DFF_PP1_))) - continue; - SigBit D = cell->getPort(ID::D); - SigBit Q = cell->getPort(ID::Q); - // Emulate async control embedded inside $_DFF_* cell with mux in front of D - if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_PN0_))) - D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort(ID::R)); - else if (cell->type.in(ID($_DFF_NN1_), ID($_DFF_PN1_))) - D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort(ID::R)); - else if (cell->type.in(ID($_DFF_NP0_), ID($_DFF_PP0_))) - D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort(ID::R)); - else if (cell->type.in(ID($_DFF_NP1_), ID($_DFF_PP1_))) - D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort(ID::R)); - // Remove the $_DFF_* cell from what needs to be a combinatorial box - holes_module->remove(cell); - Wire *port; - if (GetSize(Q.wire) == 1) - port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); - else - port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); - log_assert(port); - // Prepare to replace "assign = $_DFF_*.Q;" with "assign = $_DFF_*.D;" - // in order to extract just the combinatorial control logic that feeds the box - // (i.e. clock enable, synchronous reset, etc.) - replace.insert(std::make_pair(Q,D)); - // Since `flatten` above would have created wires named ".Q", - // extract the pre-techmap cell name - auto pos = Q.wire->name.str().rfind("."); - log_assert(pos != std::string::npos); - IdString driver = Q.wire->name.substr(0, pos); - // And drive the signal that was previously driven by "DFF.Q" (typically - // used to implement clock-enable functionality) with the ".$abc9_currQ" - // wire (which itself is driven an by input port) we inserted above - Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str())); - log_assert(currQ); - holes_module->connect(Q, currQ); +void prep_dff_unmap(RTLIL::Design *design) +{ + dict derived_to_cell; + const auto &cells_sel = design->selection_vars.at(ID($abc9_cells)); + for (auto &i : cells_sel.selected_members) { + auto module = design->module(i.first); + for (auto cell_name : i.second) { + auto cell = module->cell(cell_name); + log_assert(cell); + auto inst_module = design->module(cell->type); + log_assert(inst_module); + auto derived_type = inst_module->derive(design, cell->parameters); + derived_to_cell.insert(std::make_pair(derived_type, cell)); } + } - for (auto &conn : holes_module->connections_) - conn.second = replace.at(sigmap(conn.second), conn.second); + Design *unmap_design = new Design; + + // Create the reverse techmap rule -- (* abc9_box *) back to flop + for (const auto &i : derived_to_cell) { + auto module_name = i.first; + auto flop_module = design->module(module_name.str() + "_$abc9_flop"); + if (!flop_module) + continue; // May not exist if init = 1'b1 + + auto unmap_module = unmap_design->addModule(flop_module->name); + for (auto port : flop_module->ports) + unmap_module->addWire(port, flop_module->wire(port)); + unmap_module->ports = flop_module->ports; + unmap_module->check(); + + auto orig_cell = i.second; + auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, orig_cell->type); + for (const auto &conn : orig_cell->connections()) + unmap_cell->setPort(conn.first, unmap_module->wire(conn.first)); + unmap_cell->parameters = orig_cell->parameters; } + + auto r YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design); + log_assert(r.second); } void prep_xaiger(RTLIL::Module *module, bool dff) @@ -208,17 +254,17 @@ void prep_xaiger(RTLIL::Module *module, bool dff) dict> box_ports; for (auto cell : module->cells()) { - if (cell->type == ID($__ABC9_FF_)) + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) continue; if (cell->has_keep_attr()) continue; - auto inst_module = module->design->module(cell->type); + auto inst_module = design->module(cell->type); bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop); if (abc9_flop && !dff) continue; - if ((inst_module && inst_module->get_bool_attribute(ID::abc9_box)) || abc9_flop) { + if (inst_module && inst_module->get_bool_attribute(ID::abc9_box)) { auto r = box_ports.insert(cell->type); if (r.second) { // Make carry in the last PI, and carry out the last PO @@ -305,15 +351,16 @@ void prep_xaiger(RTLIL::Module *module, bool dff) cell->attributes[ID::abc9_box_seq] = box_count++; - IdString derived_type = box_module->derive(design, cell->parameters); + IdString derived_type; + if (cell->parameters.empty()) + derived_type = cell->type; + else + derived_type = box_module->derive(design, cell->parameters); box_module = design->module(derived_type); auto r = cell_cache.insert(derived_type); auto &holes_cell = r.first->second; if (r.second) { - if (box_module->has_processes()) - Pass::call_on_module(design, box_module, "proc"); - if (box_module->get_bool_attribute(ID::whitebox)) { holes_cell = holes_module->addCell(cell->name, derived_type); @@ -342,21 +389,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) else if (w->port_output) conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w)); } - - // For flops only, create an extra 1-bit input that drives a new wire - // called ".abc9_ff.Q" that is used below - if (box_module->get_bool_attribute(ID::abc9_flop)) { - box_inputs++; - Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); - if (!holes_wire) { - holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); - holes_wire->port_input = true; - holes_wire->port_id = port_id++; - holes_module->ports.push_back(holes_wire->name); - } - Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str())); - holes_module->connect(Q, holes_wire); - } } else // box_module is a blackbox log_assert(holes_cell == nullptr); @@ -394,7 +426,7 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) } for (auto cell : module->cells()) { - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY))) continue; RTLIL::Module* inst_module = module->design->module(cell->type); @@ -540,7 +572,7 @@ void write_lut(RTLIL::Module *module, const std::string &dst) { ofs.close(); } -void prep_box(RTLIL::Design *design, bool dff_mode) +void prep_box(RTLIL::Design *design) { TimingInfo timing; @@ -555,165 +587,153 @@ void prep_box(RTLIL::Design *design, bool dff_mode) dict> box_ports; for (auto module : design->modules()) { - auto abc9_flop = module->get_bool_attribute(ID::abc9_flop); - if (abc9_flop) { - auto r = module->attributes.insert(ID::abc9_box_id); - if (!r.second) - continue; - r.first->second = abc9_box_id++; - - if (dff_mode) { - int num_inputs = 0, num_outputs = 0; - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - log_assert(GetSize(wire) == 1); - if (wire->port_input) num_inputs++; - if (wire->port_output) num_outputs++; - } - log_assert(num_outputs == 1); + if (!module->attributes.erase(ID::abc9_box)) + continue; - ss << log_id(module) << " " << r.first->second.as_int(); - ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); - ss << " " << num_inputs+1 << " " << num_outputs << std::endl; + auto r = module->attributes.insert(ID::abc9_box_id); + if (!r.second) + continue; + r.first->second = abc9_box_id++; + + if (module->get_bool_attribute(ID::abc9_flop)) { + int num_inputs = 0, num_outputs = 0; + for (auto port_name : module->ports) { + auto wire = module->wire(port_name); + log_assert(GetSize(wire) == 1); + if (wire->port_input) num_inputs++; + if (wire->port_output) num_outputs++; + } + log_assert(num_outputs == 1); - ss << "#"; - bool first = true; - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - if (!wire->port_input) - continue; - if (first) - first = false; - else - ss << " "; - ss << log_id(wire); - } - ss << " abc9_ff.Q" << std::endl; + ss << log_id(module) << " " << r.first->second.as_int(); + ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); + ss << " " << num_inputs << " " << num_outputs << std::endl; - auto &t = timing.setup_module(module).required; - first = true; - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - if (!wire->port_input) - continue; - if (first) - first = false; - else - ss << " "; - log_assert(GetSize(wire) == 1); - auto it = t.find(TimingInfo::NameBit(port_name,0)); - if (it == t.end()) - // Assume that no setup time means zero - ss << 0; - else { - ss << it->second; + ss << "#"; + bool first = true; + for (auto port_name : module->ports) { + auto wire = module->wire(port_name); + if (!wire->port_input) + continue; + if (first) + first = false; + else + ss << " "; + ss << log_id(wire); + } + ss << std::endl; + + auto &t = timing.setup_module(module).required; + first = true; + for (auto port_name : module->ports) { + auto wire = module->wire(port_name); + if (!wire->port_input) + continue; + if (first) + first = false; + else + ss << " "; + log_assert(GetSize(wire) == 1); + auto it = t.find(TimingInfo::NameBit(port_name,0)); + if (it == t.end()) + // Assume that no setup time means zero + ss << 0; + else { + ss << it->second; #ifndef NDEBUG - if (ys_debug(1)) { - static std::set> seen; - if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module), - log_id(port_name), it->second); - } -#endif + if (ys_debug(1)) { + static std::set> seen; + if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module), + log_id(port_name), it->second); } - +#endif } - // Last input is 'abc9_ff.Q' - ss << " 0" << std::endl << std::endl; - continue; } + ss << " # $_DFF_[NP]_.D" << std::endl; + ss << std::endl; } else { - if (!module->attributes.erase(ID::abc9_box)) - continue; - - auto r = module->attributes.insert(ID::abc9_box_id); - if (!r.second) - continue; - r.first->second = abc9_box_id++; - } + auto r2 = box_ports.insert(module->name); + if (r2.second) { + // Make carry in the last PI, and carry out the last PO + // since ABC requires it this way + IdString carry_in, carry_out; + for (const auto &port_name : module->ports) { + auto w = module->wire(port_name); + log_assert(w); + if (w->get_bool_attribute(ID::abc9_carry)) { + log_assert(w->port_input != w->port_output); + if (w->port_input) + carry_in = port_name; + else if (w->port_output) + carry_out = port_name; + } + else + r2.first->second.push_back(port_name); + } - auto r = box_ports.insert(module->name); - if (r.second) { - // Make carry in the last PI, and carry out the last PO - // since ABC requires it this way - IdString carry_in, carry_out; - for (const auto &port_name : module->ports) { - auto w = module->wire(port_name); - log_assert(w); - if (w->get_bool_attribute(ID::abc9_carry)) { - log_assert(w->port_input != w->port_output); - if (w->port_input) - carry_in = port_name; - else if (w->port_output) - carry_out = port_name; + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); } - else - r.first->second.push_back(port_name); } - if (carry_in != IdString()) { - r.first->second.push_back(carry_in); - r.first->second.push_back(carry_out); + std::vector inputs, outputs; + for (auto port_name : r2.first->second) { + auto wire = module->wire(port_name); + if (wire->port_input) + for (int i = 0; i < GetSize(wire); i++) + inputs.emplace_back(wire, i); + if (wire->port_output) + for (int i = 0; i < GetSize(wire); i++) + outputs.emplace_back(wire, i); } - } - - std::vector inputs; - std::vector outputs; - for (auto port_name : r.first->second) { - auto wire = module->wire(port_name); - if (wire->port_input) - for (int i = 0; i < GetSize(wire); i++) - inputs.emplace_back(wire, i); - if (wire->port_output) - for (int i = 0; i < GetSize(wire); i++) - outputs.emplace_back(wire, i); - } - - ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int(); - ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); - ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl; - - bool first = true; - ss << "#"; - for (const auto &i : inputs) { - if (first) - first = false; - else - ss << " "; - if (GetSize(i.wire) == 1) - ss << log_id(i.wire); - else - ss << log_id(i.wire) << "[" << i.offset << "]"; - } - ss << std::endl; - auto &t = timing.setup_module(module).comb; - if (!abc9_flop && t.empty()) - log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module)); + ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int(); + ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); + ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl; - for (const auto &o : outputs) { - first = true; + bool first = true; + ss << "#"; for (const auto &i : inputs) { if (first) first = false; else ss << " "; - auto jt = t.find(TimingInfo::BitBit(i,o)); - if (jt == t.end()) - ss << "-"; + if (GetSize(i.wire) == 1) + ss << log_id(i.wire); else - ss << jt->second; + ss << log_id(i.wire) << "[" << i.offset << "]"; } - ss << " # "; - if (GetSize(o.wire) == 1) - ss << log_id(o.wire); - else - ss << log_id(o.wire) << "[" << o.offset << "]"; ss << std::endl; + auto &t = timing.setup_module(module).comb; + if (t.empty()) + log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module)); + + for (const auto &o : outputs) { + first = true; + for (const auto &i : inputs) { + if (first) + first = false; + else + ss << " "; + auto jt = t.find(TimingInfo::BitBit(i,o)); + if (jt == t.end()) + ss << "-"; + else + ss << jt->second; + } + ss << " # "; + if (GetSize(o.wire) == 1) + ss << log_id(o.wire); + else + ss << log_id(o.wire) << "[" << o.offset << "]"; + ss << std::endl; + } + ss << std::endl; } - ss << std::endl; } // ABC expects at least one box @@ -730,7 +750,7 @@ void write_box(RTLIL::Module *module, const std::string &dst) { ofs.close(); } -void reintegrate(RTLIL::Module *module) +void reintegrate(RTLIL::Module *module, bool dff_mode) { auto design = module->design; log_assert(design); @@ -783,7 +803,12 @@ void reintegrate(RTLIL::Module *module) for (auto cell : module->cells().to_vector()) { if (cell->has_keep_attr()) continue; - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) + + if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + module->connect(cell->getPort(ID::Q), cell->getPort(ID::D)); + module->remove(cell); + } + else if (cell->type.in(ID($_AND_), ID($_NOT_))) module->remove(cell); else if (cell->attributes.erase(ID::abc9_box_seq)) boxes.emplace_back(cell); @@ -797,6 +822,16 @@ void reintegrate(RTLIL::Module *module) std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { + if (dff_mode && mapped_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + SigBit D = mapped_cell->getPort(ID::D); + SigBit Q = mapped_cell->getPort(ID::Q); + if (D.wire) + D.wire = module->wires_.at(remap_name(D.wire->name)); + Q.wire = module->wires_.at(remap_name(Q.wire->name)); + module->connect(Q, D); + continue; + } + // TODO: Speed up toposort -- we care about NOT ordering only toposort.node(mapped_cell->name); @@ -846,7 +881,7 @@ void reintegrate(RTLIL::Module *module) continue; } - if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { + if (mapped_cell->type == ID($lut)) { RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = mapped_cell->parameters; cell->attributes = mapped_cell->attributes; @@ -893,7 +928,11 @@ void reintegrate(RTLIL::Module *module) } RTLIL::Module* box_module = design->module(existing_cell->type); - IdString derived_type = box_module->derive(design, existing_cell->parameters); + IdString derived_type; + if (existing_cell->parameters.empty()) + derived_type = existing_cell->type; + else + derived_type = box_module->derive(design, existing_cell->parameters); RTLIL::Module* derived_module = design->module(derived_type); log_assert(derived_module); log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at(ID::abc9_box_id).as_int())); @@ -1116,6 +1155,21 @@ struct Abc9OpsPass : public Pass { log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n"); log(" (* abc9_carry *) is only given for one input/output port, etc.\n"); log("\n"); + log(" -prep_dff_hier\n"); + log(" derive all cells with a type instantiating an (* abc9_flop *) module.\n"); + log(" store such modules in named selection '$abc9_flops'.\n"); + log("\n"); + log(" -prep_dff_map\n"); + log(" within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n"); + log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n"); + log(" the DFF's 'D' port. this is to prepare such specify cells to be moved into\n"); + log(" a submodule.\n"); + log("\n"); + log(" -prep_dff_unmap\n"); + log(" create a new design '$abc9_unmap' containing techmap rules that map\n"); + log(" *_$abc9_flop cells back into their original (* abc9_flop *) cells\n"); + log(" (including their original parameters).\n"); + log("\n"); log(" -prep_delays\n"); log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); log(" certain required times.\n"); @@ -1136,10 +1190,6 @@ struct Abc9OpsPass : public Pass { log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n"); log(" during -prep_{delays,xaiger,box}.\n"); log("\n"); - log(" -prep_dff\n"); - log(" compute the clock domain and initial value of each flop in the design.\n"); - log(" process the '$holes' module to support clock-enable functionality.\n"); - log("\n"); log(" -prep_lut \n"); log(" pre-compute the lut library by analysing all modules marked with\n"); log(" (* abc9_lut= *).\n"); @@ -1167,7 +1217,7 @@ struct Abc9OpsPass : public Pass { bool check_mode = false; bool prep_delays_mode = false; bool mark_scc_mode = false; - bool prep_dff_mode = false; + bool prep_dff_hier_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false; bool prep_xaiger_mode = false; bool prep_lut_mode = false; bool prep_box_mode = false; @@ -1177,53 +1227,71 @@ struct Abc9OpsPass : public Pass { int maxlut = 0; std::string write_box_dst; + bool valid = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-check") { check_mode = true; + valid = true; continue; } if (arg == "-mark_scc") { mark_scc_mode = true; + valid = true; + continue; + } + if (arg == "-prep_dff_hier") { + prep_dff_hier_mode = true; + valid = true; continue; } - if (arg == "-prep_dff") { - prep_dff_mode = true; + if (arg == "-prep_dff_map") { + prep_dff_map_mode = true; + valid = true; + continue; + } + if (arg == "-prep_dff_unmap") { + prep_dff_unmap_mode = true; + valid = true; continue; } if (arg == "-prep_xaiger") { prep_xaiger_mode = true; + valid = true; continue; } if (arg == "-prep_delays") { prep_delays_mode = true; + valid = true; continue; } if (arg == "-prep_lut" && argidx+1 < args.size()) { prep_lut_mode = true; maxlut = atoi(args[++argidx].c_str()); - continue; - } - if (arg == "-maxlut" && argidx+1 < args.size()) { + valid = true; continue; } if (arg == "-write_lut" && argidx+1 < args.size()) { write_lut_dst = args[++argidx]; rewrite_filename(write_lut_dst); + valid = true; continue; } if (arg == "-prep_box") { prep_box_mode = true; + valid = true; continue; } if (arg == "-write_box" && argidx+1 < args.size()) { write_box_dst = args[++argidx]; rewrite_filename(write_box_dst); + valid = true; continue; } if (arg == "-reintegrate") { reintegrate_mode = true; + valid = true; continue; } if (arg == "-dff") { @@ -1234,20 +1302,26 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); - if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || prep_lut_mode || prep_box_mode || !write_lut_dst.empty() || !write_box_dst.empty() || reintegrate_mode)) - log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n"); + if (!valid) + log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n"); - if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !prep_box_mode) - log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n"); + if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode) + log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger} or -reintegrate.\n"); if (check_mode) check(design); + if (prep_dff_hier_mode) + prep_dff_hier(design); + if (prep_dff_map_mode) + prep_dff_map(design); + if (prep_dff_unmap_mode) + prep_dff_unmap(design); if (prep_delays_mode) prep_delays(design, dff_mode); if (prep_lut_mode) prep_lut(design, maxlut); if (prep_box_mode) - prep_box(design, dff_mode); + prep_box(design); for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute(ID::abc9_holes)) @@ -1267,12 +1341,10 @@ struct Abc9OpsPass : public Pass { write_box(mod, write_box_dst); if (mark_scc_mode) mark_scc(mod); - if (prep_dff_mode) - prep_dff(mod); if (prep_xaiger_mode) prep_xaiger(mod, dff_mode); if (reintegrate_mode) - reintegrate(mod); + reintegrate(mod, dff_mode); } } } Abc9OpsPass; -- cgit v1.2.3 From edacb8f437bd1d3c61a12dfa35214e3a1d47af99 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 13:12:37 -0700 Subject: abc9_ops: do not use (* abc9_init *) --- passes/techmap/abc9_ops.cc | 47 ++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index fe2e5c3ac..2ad082d38 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -157,20 +157,11 @@ void prep_dff_map(RTLIL::Design *design) D = cell->getPort(ID::D); Q = cell->getPort(ID::Q); - // TODO: Can we avoid doing this? - // Convert (* init *) on $_DFF_[NP]_.Q to (* abc9_init *) attr on cell + // Block sequential synthesis on cells with (* init = 1 *) + // because ABC9 doesn't support them log_assert(GetSize(Q.wire) == 1); - auto it = Q.wire->attributes.find(ID::init); - Const init; - if (it != Q.wire->attributes.end()) { - log_assert(GetSize(it->second) == 1); - init = it->second; - Q.wire->attributes.erase(it); - } - else - init = State::Sx; - auto r YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID::abc9_init, init)); - log_assert(r.second); + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); if (init == State::S1) { log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); @@ -226,8 +217,10 @@ void prep_dff_unmap(RTLIL::Design *design) continue; // May not exist if init = 1'b1 auto unmap_module = unmap_design->addModule(flop_module->name); - for (auto port : flop_module->ports) - unmap_module->addWire(port, flop_module->wire(port)); + for (auto port : flop_module->ports) { + auto w = unmap_module->addWire(port, flop_module->wire(port)); + w->attributes.erase(ID::init); + } unmap_module->ports = flop_module->ports; unmap_module->check(); @@ -757,6 +750,17 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) map_autoidx = autoidx++; + // TODO: Get rid of this expensive lookup + dict> sig2inits; + SigMap sigmap(module); + for (auto w : module->wires()) { + auto it = w->attributes.find(ID::init); + if (it == w->attributes.end()) + continue; + for (const auto &b : SigSpec(w)) + sig2inits[sigmap(b)].emplace_back(b); + } + RTLIL::Module *mapped_mod = design->module(stringf("%s$abc9", module->name.c_str())); if (mapped_mod == NULL) log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module)); @@ -764,6 +768,8 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) for (auto w : mapped_mod->wires()) { auto nw = module->addWire(remap_name(w->name), GetSize(w)); nw->start_offset = w->start_offset; + // Remove all (* init *) since they only existon $_DFF_[NP]_ + w->attributes.erase(ID::init); } dict> box_ports; @@ -804,8 +810,15 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) if (cell->has_keep_attr()) continue; + // Short out $_DFF_[NP]_ cells since the flop box already has + // all the information we need to reconstruct cell if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - module->connect(cell->getPort(ID::Q), cell->getPort(ID::D)); + SigBit Q = cell->getPort(ID::Q); + auto it = sig2inits.find(Q); + if (it != sig2inits.end()) + for (const auto &b : it->second) + b.wire->attributes.at(ID::init)[b.offset] = State::Sx; + module->connect(Q, cell->getPort(ID::D)); module->remove(cell); } else if (cell->type.in(ID($_AND_), ID($_NOT_))) @@ -822,6 +835,8 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { + // Short out $_DFF_[NP]_ cells since the flop box already has + // all the information we need to reconstruct cell if (dff_mode && mapped_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { SigBit D = mapped_cell->getPort(ID::D); SigBit Q = mapped_cell->getPort(ID::Q); -- cgit v1.2.3 From 6b3aa91a2a1f717ebf4ce7155b134e9d556ac1ab Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 13:12:45 -0700 Subject: abc9: cleanup --- passes/techmap/abc9.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7f3e6abcc..97ee57aaa 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -295,16 +295,13 @@ struct Abc9Pass : public ScriptPass run("delete *_$abc9_flop"); if (help_mode) { run("foreach module in design"); - run(" cd "); run(" rename _$abc9_flop _TECHMAP_REPLACE_"); - run(" cd"); } else { // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs for (auto module : active_design->selected_modules()) { - run(stringf("cd %s", log_id(module->name))); + active_design->selected_active_module = module->name.str(); run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); - run("cd"); } } run("design -stash $abc9_map"); -- cgit v1.2.3 From a1ae5845f83f12f2893c48c23c377aea25c1b280 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 17:30:29 -0700 Subject: abc9_ops: -prep_dff_map to cope with plain $_DFF_[NP]_ flops --- passes/techmap/abc9_ops.cc | 51 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 12 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2ad082d38..cf3bd689e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -134,13 +134,22 @@ void prep_dff_hier(RTLIL::Design *design) for (auto module : design->selected_modules()) for (auto cell : module->cells()) { auto inst_module = design->module(cell->type); - if (inst_module && inst_module->get_bool_attribute(ID::abc9_flop)) { - modules_sel.select(inst_module); + if (inst_module && inst_module->attributes.count(ID::abc9_flop)) { + if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) + log_error("Module '%s' with (* abc9_flop *) is not a whitebox.\n", log_id(inst_module)); // Derive modules for all instantiations of (* abc9_flop *) auto derived_type = inst_module->derive(design, cell->parameters); + auto derived_module = design->module(derived_type); + if (!derived_module->get_bool_attribute(ID::abc9_flop)) + continue; // And remember one representative cell (for its parameters) - if (modules_sel.selected_modules.insert(derived_type).second) + if (!modules_sel.selected_whole_module(derived_type)) { + if (derived_type != cell->type) + modules_sel.select(inst_module); + + modules_sel.select(derived_module); cells_sel.select(module, cell); + } } } } @@ -150,19 +159,20 @@ void prep_dff_map(RTLIL::Design *design) for (auto module : design->modules()) { vector specify_cells; SigBit D, Q; + Cell* dff_cell = nullptr; for (auto cell : module->cells()) if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - if (D != SigBit()) + if (dff_cell) log_error("More than one $_DFF_[NP]_ cell found in module '%s' marked (* abc9_flop *)\n", log_id(module)); - D = cell->getPort(ID::D); - Q = cell->getPort(ID::Q); + dff_cell = cell; - // Block sequential synthesis on cells with (* init = 1 *) + // Block sequential synthesis on cells with (* init *) != 1'b0 // because ABC9 doesn't support them + Q = cell->getPort(ID::Q); log_assert(GetSize(Q.wire) == 1); Const init = Q.wire->attributes.at(ID::init, State::Sx); log_assert(GetSize(init) == 1); - if (init == State::S1) { + if (init != State::S0) { log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); module->makeblackbox(); @@ -176,9 +186,26 @@ void prep_dff_map(RTLIL::Design *design) } else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) specify_cells.emplace_back(cell); - if (D == SigBit()) + if (!dff_cell) log_error("$_DFF_[NP]_ cell not found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + D = dff_cell->getPort(ID::D); + + // Add a dummy enable mux feeding DFF.D to ensure that: + // (i) a driving cell exists, so that 'submod' will have + // an output port + // (ii) DFF.Q will exist in this submodule + { + auto c = module->addCell(NEW_ID, ID($_MUX_)); + auto w = module->addWire(NEW_ID); + c->setPort(ID::A, D); + c->setPort(ID::B, Q); + c->setPort(ID::S, State::S0); + c->setPort(ID::Y, w); + dff_cell->setPort(ID::D, w); + D = w; + } + // Rewrite $specify cells that end with $_DFF_[NP]_.Q // to $_DFF_[NP]_.D since it will be moved into // the submodule @@ -253,7 +280,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) continue; auto inst_module = design->module(cell->type); - bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop); + bool abc9_flop = inst_module && inst_module->attributes.count(ID::abc9_flop); if (abc9_flop && !dff) continue; @@ -339,7 +366,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) log_assert(cell); RTLIL::Module* box_module = design->module(cell->type); - if (!box_module || (!box_module->get_bool_attribute(ID::abc9_box) && !box_module->get_bool_attribute(ID::abc9_flop))) + if (!box_module || !box_module->get_bool_attribute(ID::abc9_box)) continue; cell->attributes[ID::abc9_box_seq] = box_count++; @@ -967,7 +994,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) SigSpec outputs = std::move(jt->second); mapped_cell->connections_.erase(jt); - auto abc9_flop = box_module->attributes.count(ID::abc9_flop); + auto abc9_flop = box_module->get_bool_attribute(ID::abc9_flop); if (!abc9_flop) { for (const auto &i : inputs) bit_users[i].insert(mapped_cell->name); -- cgit v1.2.3 From e38b1280f9752d22c6d2a5803bec6a6cedf12a10 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 07:49:55 -0700 Subject: abc9_ops: -prep_dff_map to warn if no specify cells --- passes/techmap/abc9_ops.cc | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index cf3bd689e..c640d06f8 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -206,13 +206,18 @@ void prep_dff_map(RTLIL::Design *design) D = w; } - // Rewrite $specify cells that end with $_DFF_[NP]_.Q - // to $_DFF_[NP]_.D since it will be moved into - // the submodule - for (auto cell : specify_cells) { - auto DST = cell->getPort(ID::DST); - DST.replace(Q, D); - cell->setPort(ID::DST, DST); + if (GetSize(specify_cells) == 0) { + log_warning("Module '%s' marked (* abc9_flop *) contains no specify timing information.\n", log_id(module)); + } + else { + // Rewrite $specify cells that end with $_DFF_[NP]_.Q + // to $_DFF_[NP]_.D since it will be moved into + // the submodule + for (auto cell : specify_cells) { + auto DST = cell->getPort(ID::DST); + DST.replace(Q, D); + cell->setPort(ID::DST, DST); + } } continue_outer_loop: ; } -- cgit v1.2.3 From 509de98468973838aa3b3ff958084693434c8c83 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 08:53:07 -0700 Subject: submod: revert accidental change --- passes/hierarchy/submod.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc index 1f30a5160..2db7cf26b 100644 --- a/passes/hierarchy/submod.cc +++ b/passes/hierarchy/submod.cc @@ -389,7 +389,7 @@ struct SubmodPass : public Pass { while (did_something) { did_something = false; std::vector queued_modules; - for (auto mod : design->selected_modules()) + for (auto mod : design->modules()) if (handled_modules.count(mod->name) == 0 && design->selected_whole_module(mod->name)) queued_modules.push_back(mod->name); for (auto &modname : queued_modules) -- cgit v1.2.3 From 043ad8e76cd45bb573c804ffddb4a478cd4a99d4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 11:10:48 -0700 Subject: abc9_ops: use new 'design -delete' and 'select -unset' --- passes/techmap/abc9.cc | 20 +++++--------------- passes/techmap/abc9_ops.cc | 3 ++- 2 files changed, 7 insertions(+), 16 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 97ee57aaa..adb28189e 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -309,15 +309,10 @@ struct Abc9Pass : public ScriptPass run("abc9_ops -prep_dff_unmap"); // create $abc9_unmap design run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); - if (!help_mode) { - // TODO: Need a way to delete saved designs? - auto it = saved_designs.find("$abc9_map"); - delete it->second; - saved_designs.erase(it); - // TODO: Need a way to delete selections - active_design->selection_vars.erase(ID($abc9_flops)); - active_design->selection_vars.erase(ID($abc9_cells)); - } + run("design -delete $abc9"); + run("design -delete $abc9_map"); + run("select -unset $abc9_flops"); + run("select -unset $abc9_cells"); } } @@ -423,12 +418,7 @@ struct Abc9Pass : public ScriptPass if (dff_mode || help_mode) { run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell // ($_DFF_[NP]_ already shorted by -reintegrate) - if (!help_mode) { - // TODO: Need a way to delete saved designs? - auto it = saved_designs.find("$abc9_unmap"); - delete it->second; - saved_designs.erase(it); - } + run("design -delete $abc9_unmap"); } } } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index c640d06f8..57f51503c 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1204,7 +1204,8 @@ struct Abc9OpsPass : public Pass { log("\n"); log(" -prep_dff_hier\n"); log(" derive all cells with a type instantiating an (* abc9_flop *) module.\n"); - log(" store such modules in named selection '$abc9_flops'.\n"); + log(" store such modules in named selection '$abc9_flops'. store one cell\n"); + log(" instantiating each derived module into named selection '$abc9_cells'.\n"); log("\n"); log(" -prep_dff_map\n"); log(" within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n"); -- cgit v1.2.3 From 489e83fc1ea7051cc400b043f75ce1ad359038f0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 11:38:44 -0700 Subject: abc9_ops: do away with '$abc9_cells' selection --- passes/techmap/abc9.cc | 1 - passes/techmap/abc9_ops.cc | 69 ++++++++++++++++++++-------------------------- 2 files changed, 30 insertions(+), 40 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index adb28189e..bddf9d2d9 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -312,7 +312,6 @@ struct Abc9Pass : public ScriptPass run("design -delete $abc9"); run("design -delete $abc9_map"); run("select -unset $abc9_flops"); - run("select -unset $abc9_cells"); } } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 57f51503c..d15da348a 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -122,14 +122,11 @@ void mark_scc(RTLIL::Module *module) void prep_dff_hier(RTLIL::Design *design) { - pool seen; - dict selection_vars; auto r YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false))); log_assert(r.second); - auto r2 YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_cells), RTLIL::Selection(false))); - log_assert(r2.second); auto &modules_sel = design->selection_vars.at(ID($abc9_flops)); - auto &cells_sel = design->selection_vars.at(ID($abc9_cells)); + + Design *unmap_design = new Design; for (auto module : design->selected_modules()) for (auto cell : module->cells()) { @@ -142,16 +139,24 @@ void prep_dff_hier(RTLIL::Design *design) auto derived_module = design->module(derived_type); if (!derived_module->get_bool_attribute(ID::abc9_flop)) continue; - // And remember one representative cell (for its parameters) + // And create the stub in the $abc9_unmap design if (!modules_sel.selected_whole_module(derived_type)) { if (derived_type != cell->type) modules_sel.select(inst_module); modules_sel.select(derived_module); - cells_sel.select(module, cell); + + auto unmap_module = unmap_design->addModule(derived_type.str() + "_$abc9_flop"); + auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); + for (const auto &conn : cell->connections()) + unmap_cell->setPort(conn.first, SigSpec()); + unmap_cell->parameters = cell->parameters; } } } + + auto r2 YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design); + log_assert(r2.second); } void prep_dff_map(RTLIL::Design *design) @@ -225,46 +230,32 @@ continue_outer_loop: ; void prep_dff_unmap(RTLIL::Design *design) { - dict derived_to_cell; - const auto &cells_sel = design->selection_vars.at(ID($abc9_cells)); - for (auto &i : cells_sel.selected_members) { - auto module = design->module(i.first); - for (auto cell_name : i.second) { - auto cell = module->cell(cell_name); - log_assert(cell); - auto inst_module = design->module(cell->type); - log_assert(inst_module); - auto derived_type = inst_module->derive(design, cell->parameters); - derived_to_cell.insert(std::make_pair(derived_type, cell)); - } - } - - Design *unmap_design = new Design; + Design *unmap_design = saved_designs.at("$abc9_unmap"); // Create the reverse techmap rule -- (* abc9_box *) back to flop - for (const auto &i : derived_to_cell) { - auto module_name = i.first; - auto flop_module = design->module(module_name.str() + "_$abc9_flop"); + for (auto module : unmap_design->modules()) { + auto flop_module = design->module(module->name.str()); if (!flop_module) continue; // May not exist if init = 1'b1 - auto unmap_module = unmap_design->addModule(flop_module->name); + auto unmap_module = unmap_design->module(flop_module->name); + log_assert(unmap_module); for (auto port : flop_module->ports) { auto w = unmap_module->addWire(port, flop_module->wire(port)); + // Do not propagate (* init *) values inside the box w->attributes.erase(ID::init); } unmap_module->ports = flop_module->ports; unmap_module->check(); - auto orig_cell = i.second; - auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, orig_cell->type); - for (const auto &conn : orig_cell->connections()) - unmap_cell->setPort(conn.first, unmap_module->wire(conn.first)); - unmap_cell->parameters = orig_cell->parameters; + auto unmap_cell = unmap_module->cell(ID::_TECHMAP_REPLACE_); + log_assert(unmap_cell); + for (const auto &conn : unmap_cell->connections()) { + auto rhs = unmap_module->wire(conn.first); + log_assert(rhs); + unmap_cell->setPort(conn.first, rhs); + } } - - auto r YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design); - log_assert(r.second); } void prep_xaiger(RTLIL::Module *module, bool dff) @@ -1204,8 +1195,8 @@ struct Abc9OpsPass : public Pass { log("\n"); log(" -prep_dff_hier\n"); log(" derive all cells with a type instantiating an (* abc9_flop *) module.\n"); - log(" store such modules in named selection '$abc9_flops'. store one cell\n"); - log(" instantiating each derived module into named selection '$abc9_cells'.\n"); + log(" store such modules in named selection '$abc9_flops'. create stubs within\n"); + log(" a new '$abc9_unmap' design to be used by -prep_dff_unmap.\n"); log("\n"); log(" -prep_dff_map\n"); log(" within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n"); @@ -1214,9 +1205,9 @@ struct Abc9OpsPass : public Pass { log(" a submodule.\n"); log("\n"); log(" -prep_dff_unmap\n"); - log(" create a new design '$abc9_unmap' containing techmap rules that map\n"); - log(" *_$abc9_flop cells back into their original (* abc9_flop *) cells\n"); - log(" (including their original parameters).\n"); + log(" fill in previously created '$abc9_unmap' design to contain techmap rules\n"); + log(" for mapping *_$abc9_flop cells back into their original (* abc9_flop *)\n"); + log(" cells(including their original parameters).\n"); log("\n"); log(" -prep_delays\n"); log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); -- cgit v1.2.3 From 8bad885e782181837c710f738f6184bd473d88ae Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 12:35:12 -0700 Subject: abc9_ops: -prep_dff_map to check $_DFF_[NP]_.Q drives module output --- passes/techmap/abc9_ops.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index d15da348a..2f1b531e2 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -175,6 +175,10 @@ void prep_dff_map(RTLIL::Design *design) // because ABC9 doesn't support them Q = cell->getPort(ID::Q); log_assert(GetSize(Q.wire) == 1); + + if (!Q.wire->port_output) + log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(module), log_id(cell->type)); + Const init = Q.wire->attributes.at(ID::init, State::Sx); log_assert(GetSize(init) == 1); if (init != State::S0) { @@ -1207,7 +1211,7 @@ struct Abc9OpsPass : public Pass { log(" -prep_dff_unmap\n"); log(" fill in previously created '$abc9_unmap' design to contain techmap rules\n"); log(" for mapping *_$abc9_flop cells back into their original (* abc9_flop *)\n"); - log(" cells(including their original parameters).\n"); + log(" cells (including their original parameters).\n"); log("\n"); log(" -prep_delays\n"); log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); -- cgit v1.2.3 From fb447951be5ac481106f06a911234614b576b40f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 09:38:29 -0700 Subject: abc9: cleanup --- passes/techmap/abc9.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index bddf9d2d9..b57ea3cf7 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -280,7 +280,8 @@ struct Abc9Pass : public ScriptPass if (check_label("dff", "(only if -dff)")) { if (dff_mode || help_mode) { - run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules + run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules, + // create stubs in $abc9_unmap design run("design -stash $abc9"); run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in run("proc"); @@ -288,8 +289,11 @@ struct Abc9Pass : public ScriptPass run("techmap"); run("opt"); run("abc9_ops -prep_dff_map"); // rewrite specify - // TODO: Select fan-in cone $_DFF_[NP]_.Q - run("setattr -set submod \"$abc9_flop\" t:* t:$_DFF_N_ %d t:$_DFF_P_ %d"); + // select all $_DFF_[NP]_ + // then select all its fanins + // then select all fanouts of all that + // lastly remove $_DFF_[NP]_ cells + run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); run("submod"); run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out run("delete *_$abc9_flop"); @@ -306,12 +310,12 @@ struct Abc9Pass : public ScriptPass } run("design -stash $abc9_map"); run("design -load $abc9"); - run("abc9_ops -prep_dff_unmap"); // create $abc9_unmap design - run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ - run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); run("design -delete $abc9"); - run("design -delete $abc9_map"); run("select -unset $abc9_flops"); + run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design + run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ + run("design -delete $abc9_map"); + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); } } -- cgit v1.2.3 From 8d7b3c06b2ced88d40bc5c024805c778edd6fe2f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 15:41:55 -0700 Subject: abc9: suppress warnings when no compatible + used flop boxes formed --- passes/techmap/abc9.cc | 61 +++++++++++++++++++++++++++------------------- passes/techmap/abc9_ops.cc | 39 ++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 37 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index b57ea3cf7..1a5604f7d 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -281,41 +281,52 @@ struct Abc9Pass : public ScriptPass if (check_label("dff", "(only if -dff)")) { if (dff_mode || help_mode) { run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules, - // create stubs in $abc9_unmap design + // create stubs in $abc9_unmap design run("design -stash $abc9"); run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in run("proc"); run("wbflip"); run("techmap"); run("opt"); + if (!help_mode) + active_design->scratchpad_unset("abc9_ops.prep_dff_map.did_something"); run("abc9_ops -prep_dff_map"); // rewrite specify - // select all $_DFF_[NP]_ - // then select all its fanins - // then select all fanouts of all that - // lastly remove $_DFF_[NP]_ cells - run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); - run("submod"); - run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out - run("delete *_$abc9_flop"); - if (help_mode) { - run("foreach module in design"); - run(" rename _$abc9_flop _TECHMAP_REPLACE_"); + bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_map.did_something"); + if (did_something) { + // select all $_DFF_[NP]_ + // then select all its fanins + // then select all fanouts of all that + // lastly remove $_DFF_[NP]_ cells + run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); + run("submod"); + run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out + run("delete *_$abc9_flop"); + if (help_mode) { + run("foreach module in design"); + run(" rename _$abc9_flop _TECHMAP_REPLACE_"); + } + else { + // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs + for (auto module : active_design->selected_modules()) { + active_design->selected_active_module = module->name.str(); + if (module->cell(stringf("%s_$abc9_flop", module->name.c_str()))) + run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); + } + } + run("design -stash $abc9_map"); + run("design -load $abc9"); + run("design -delete $abc9"); + run("select -unset $abc9_flops"); + run("techmap -wb -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ + run("design -delete $abc9_map"); + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); + run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design } else { - // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs - for (auto module : active_design->selected_modules()) { - active_design->selected_active_module = module->name.str(); - run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); - } + run("design -load $abc9"); + run("design -delete $abc9"); + run("select -unset $abc9_flops"); } - run("design -stash $abc9_map"); - run("design -load $abc9"); - run("design -delete $abc9"); - run("select -unset $abc9_flops"); - run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design - run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ - run("design -delete $abc9_map"); - run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); } } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2f1b531e2..e00a4dc81 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -161,10 +161,23 @@ void prep_dff_hier(RTLIL::Design *design) void prep_dff_map(RTLIL::Design *design) { + Design *unmap_design = saved_designs.at("$abc9_unmap"); + for (auto module : design->modules()) { vector specify_cells; SigBit D, Q; Cell* dff_cell = nullptr; + + // If module has a public name (i.e. not $paramod) and it doesn't exist + // in the $abc9_unmap then it means only derived modules were + // instantiated, so make this a blackbox + if (module->name[0] == '\\' && !unmap_design->module(module->name.str() + "_$abc9_flop")) { + module->makeblackbox(); + module->set_bool_attribute(ID::blackbox, false); + module->set_bool_attribute(ID::whitebox, true); + continue; + } + for (auto cell : module->cells()) if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { if (dff_cell) @@ -185,6 +198,7 @@ void prep_dff_map(RTLIL::Design *design) log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); module->makeblackbox(); + module->set_bool_attribute(ID::blackbox, false); auto wire = module->addWire(ID(_TECHMAP_FAIL_)); wire->set_bool_attribute(ID::keep); @@ -215,19 +229,20 @@ void prep_dff_map(RTLIL::Design *design) D = w; } - if (GetSize(specify_cells) == 0) { - log_warning("Module '%s' marked (* abc9_flop *) contains no specify timing information.\n", log_id(module)); - } - else { - // Rewrite $specify cells that end with $_DFF_[NP]_.Q - // to $_DFF_[NP]_.D since it will be moved into - // the submodule - for (auto cell : specify_cells) { - auto DST = cell->getPort(ID::DST); - DST.replace(Q, D); - cell->setPort(ID::DST, DST); - } + if (GetSize(specify_cells) == 0) + log_error("Module '%s' marked (* abc9_flop *) contains no specify timing information.\n", log_id(module)); + + // Rewrite $specify cells that end with $_DFF_[NP]_.Q + // to $_DFF_[NP]_.D since it will be moved into + // the submodule + for (auto cell : specify_cells) { + auto DST = cell->getPort(ID::DST); + DST.replace(Q, D); + cell->setPort(ID::DST, DST); } + + design->scratchpad_set_bool("abc9_ops.prep_dff_map.did_something", true); + continue_outer_loop: ; } } -- cgit v1.2.3 From c52bb11fb6a4a34ba702e35c2950efb978b953ad Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 15:50:57 -0700 Subject: abc9_ops: more robust --- passes/techmap/abc9_ops.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index e00a4dc81..544fefdfb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -641,7 +641,8 @@ void prep_box(RTLIL::Design *design) log_assert(num_outputs == 1); ss << log_id(module) << " " << r.first->second.as_int(); - ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); + log_assert(module->get_bool_attribute(ID::whitebox)); + ss << " " << "1"; ss << " " << num_inputs << " " << num_outputs << std::endl; ss << "#"; @@ -659,6 +660,9 @@ void prep_box(RTLIL::Design *design) ss << std::endl; auto &t = timing.setup_module(module).required; + if (t.empty()) + log_error("Module '%s' with (* abc9_flop *) has no clk-to-q timing (and thus no connectivity) information.\n", log_id(module)); + first = true; for (auto port_name : module->ports) { auto wire = module->wire(port_name); @@ -671,8 +675,8 @@ void prep_box(RTLIL::Design *design) log_assert(GetSize(wire) == 1); auto it = t.find(TimingInfo::NameBit(port_name,0)); if (it == t.end()) - // Assume that no setup time means zero - ss << 0; + // Assume no connectivity if no setup time + ss << "-"; else { ss << it->second; @@ -743,9 +747,11 @@ void prep_box(RTLIL::Design *design) } ss << std::endl; - auto &t = timing.setup_module(module).comb; - if (t.empty()) - log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module)); + auto &t = timing.setup_module(module); + if (t.comb.empty()) + log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module)); + if (!t.arrival.empty() || !t.required.empty()) + log_error("Module '%s' with (* abc9_box *) has setup and/or edge-sensitive timing information.\n", log_id(module)); for (const auto &o : outputs) { first = true; @@ -754,8 +760,8 @@ void prep_box(RTLIL::Design *design) first = false; else ss << " "; - auto jt = t.find(TimingInfo::BitBit(i,o)); - if (jt == t.end()) + auto jt = t.comb.find(TimingInfo::BitBit(i,o)); + if (jt == t.comb.end()) ss << "-"; else ss << jt->second; -- cgit v1.2.3 From ec4bbb1444b24d36c03a6635738e34b652e5aa1b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 16:13:57 -0700 Subject: abc9: generate $abc9_holes design instead of $holes --- passes/techmap/abc9.cc | 18 +++++++++++------- passes/techmap/abc9_ops.cc | 16 ++++++++-------- 2 files changed, 19 insertions(+), 15 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 1a5604f7d..dc96a765f 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -345,15 +345,18 @@ struct Abc9Pass : public ScriptPass else if (box_file.empty()) { run("abc9_ops -prep_box"); } - run("select -set abc9_holes A:abc9_holes"); - run("flatten -wb @abc9_holes"); - run("techmap @abc9_holes"); - run("opt -purge @abc9_holes"); + run("design -stash $abc9"); + run("design -load $abc9_holes"); + run("techmap -wb -map %$abc9 -map +/techmap.v"); + run("opt -purge"); run("aigmap"); - run("wbflip @abc9_holes"); + run("wbflip"); + run("design -stash $abc9_holes"); + run("design -load $abc9"); } if (check_label("map")) { + run("aigmap"); if (help_mode) { run("foreach module in selection"); run(" abc9_ops -write_lut /input.lut", "(skip if '-lut' or '-luts')"); @@ -372,7 +375,6 @@ struct Abc9Pass : public ScriptPass log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; } - log_assert(!mod->attributes.count(ID::abc9_box_id)); log_push(); active_design->selection().select(mod); @@ -432,8 +434,10 @@ struct Abc9Pass : public ScriptPass if (dff_mode || help_mode) { run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell // ($_DFF_[NP]_ already shorted by -reintegrate) - run("design -delete $abc9_unmap"); + run("design -delete $abc9_unmap", " (only if -dff)"); } + if (saved_designs.count("$abc9_holes") || help_mode) + run("design -delete $abc9_holes"); } } } Abc9Pass; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 544fefdfb..ee25866c3 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -368,9 +368,13 @@ void prep_xaiger(RTLIL::Module *module, bool dff) log_assert(no_loops); - RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); + auto r = saved_designs.emplace("$abc9_holes", nullptr); + if (r.second) + r.first->second = new Design; + RTLIL::Design *holes_design = r.first->second; + log_assert(holes_design); + RTLIL::Module *holes_module = holes_design->addModule(module->name); log_assert(holes_module); - holes_module->set_bool_attribute(ID::abc9_holes); dict cell_cache; TimingInfo timing; @@ -1246,9 +1250,8 @@ struct Abc9OpsPass : public Pass { log("\n"); log(" -prep_xaiger\n"); log(" prepare the design for XAIGER output. this includes computing the\n"); - log(" topological ordering of ABC9 boxes, as well as preparing the\n"); - log(" '$holes' module that contains the logic behaviour of ABC9\n"); - log(" whiteboxes.\n"); + log(" topological ordering of ABC9 boxes, as well as preparing the '$abc9_holes'\n"); + log(" design that contains the logic behaviour of ABC9 whiteboxes.\n"); log("\n"); log(" -dff\n"); log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n"); @@ -1388,9 +1391,6 @@ struct Abc9OpsPass : public Pass { prep_box(design); for (auto mod : design->selected_modules()) { - if (mod->get_bool_attribute(ID::abc9_holes)) - continue; - if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; -- cgit v1.2.3 From c41c180f68b161cfeb8b82efe06c56d02394a831 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 16:18:37 -0700 Subject: abc9: remove redundant wbflip --- passes/techmap/abc9.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index dc96a765f..fbb8356a5 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -350,7 +350,6 @@ struct Abc9Pass : public ScriptPass run("techmap -wb -map %$abc9 -map +/techmap.v"); run("opt -purge"); run("aigmap"); - run("wbflip"); run("design -stash $abc9_holes"); run("design -load $abc9"); } -- cgit v1.2.3 From 4cec21b93e62e9c43a0ab9618c0111ee65e520c1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 16:29:11 -0700 Subject: abc9_ops: -prep_dff_map to error if async flop found --- passes/techmap/abc9_ops.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index ee25866c3..62007c61e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -181,7 +181,7 @@ void prep_dff_map(RTLIL::Design *design) for (auto cell : module->cells()) if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { if (dff_cell) - log_error("More than one $_DFF_[NP]_ cell found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(module)); dff_cell = cell; // Block sequential synthesis on cells with (* init *) != 1'b0 @@ -207,10 +207,15 @@ void prep_dff_map(RTLIL::Design *design) goto continue_outer_loop; } } + else if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), + ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1), + ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1))) + log_error("Module '%s' with (* abc9_flop *) contains an asynchronous $_DFFE?_[NP][NP][01]_? cell, which is not supported for sequential synthesis.\n", log_id(module)); else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) specify_cells.emplace_back(cell); if (!dff_cell) - log_error("$_DFF_[NP]_ cell not found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + log_error("Module '%s' with (* abc9_flop *) does not any contain $_DFF_[NP]_ cells.\n", log_id(module)); D = dff_cell->getPort(ID::D); @@ -229,9 +234,6 @@ void prep_dff_map(RTLIL::Design *design) D = w; } - if (GetSize(specify_cells) == 0) - log_error("Module '%s' marked (* abc9_flop *) contains no specify timing information.\n", log_id(module)); - // Rewrite $specify cells that end with $_DFF_[NP]_.Q // to $_DFF_[NP]_.D since it will be moved into // the submodule -- cgit v1.2.3 From 48052ad813db3561a959a1921466d571bafa354c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 10:24:02 -0700 Subject: abc9: add flop boxes to basic $_DFF_P_ and $_DFF_N_ too --- passes/techmap/abc9.cc | 19 ++++++++++--------- passes/techmap/abc9_ops.cc | 26 ++++++++++++++++---------- 2 files changed, 26 insertions(+), 19 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index fbb8356a5..911254aa6 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -314,23 +314,24 @@ struct Abc9Pass : public ScriptPass } } run("design -stash $abc9_map"); - run("design -load $abc9"); - run("design -delete $abc9"); - run("select -unset $abc9_flops"); - run("techmap -wb -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ + } + run("design -load $abc9"); + run("design -delete $abc9"); + run("select -unset $abc9_flops"); + if (did_something) { // techmap user design into submod + $_DFF_[NP]_ + run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v"); run("design -delete $abc9_map"); run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design } - else { - run("design -load $abc9"); - run("design -delete $abc9"); - run("select -unset $abc9_flops"); - } + else + run("techmap -wb -max_iter 1 -map +/abc9_map.v"); + } } if (check_label("pre")) { + run("read_verilog -icells -lib -specify +/abc9_model.v"); run("scc -set_attr abc9_scc_id {}"); if (help_mode) run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 62007c61e..976b6462e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -128,7 +128,7 @@ void prep_dff_hier(RTLIL::Design *design) Design *unmap_design = new Design; - for (auto module : design->selected_modules()) + for (auto module : design->modules()) for (auto cell : module->cells()) { auto inst_module = design->module(cell->type); if (inst_module && inst_module->attributes.count(ID::abc9_flop)) { @@ -219,17 +219,23 @@ void prep_dff_map(RTLIL::Design *design) D = dff_cell->getPort(ID::D); - // Add a dummy enable mux feeding DFF.D to ensure that: - // (i) a driving cell exists, so that 'submod' will have - // an output port - // (ii) DFF.Q will exist in this submodule { - auto c = module->addCell(NEW_ID, ID($_MUX_)); + // Add dummy buffers for all module inputs/outputs + // to ensure that these ports exists in the flop box + // created by later submod pass + for (auto port_name : module->ports) { + auto port = module->wire(port_name); + log_assert(GetSize(port) == 1); + auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); + // Need to set (* keep *) otherwise opt_clean + // inside submod will blow it away + c->set_bool_attribute(ID::keep); + } + // Add an additional buffer that drives $_DFF_[NP]_.D + // so that the flop box will have an output auto w = module->addWire(NEW_ID); - c->setPort(ID::A, D); - c->setPort(ID::B, Q); - c->setPort(ID::S, State::S0); - c->setPort(ID::Y, w); + auto c = module->addBufGate(NEW_ID, D, w); + c->set_bool_attribute(ID::keep); dff_cell->setPort(ID::D, w); D = w; } -- cgit v1.2.3 From c50601e35e9444e9fb77fd89622b3263d85d1fd0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 10:40:33 -0700 Subject: abc9: restore selected_modules() --- passes/techmap/abc9_ops.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 976b6462e..4843200d8 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -128,7 +128,7 @@ void prep_dff_hier(RTLIL::Design *design) Design *unmap_design = new Design; - for (auto module : design->modules()) + for (auto module : design->selected_modules()) for (auto cell : module->cells()) { auto inst_module = design->module(cell->type); if (inst_module && inst_module->attributes.count(ID::abc9_flop)) { -- cgit v1.2.3 From bb840cca9cd62ad59b2054049e979263325ba664 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 14:03:54 -0700 Subject: abc9_ops: -reintegrate to handle $_FF_; cleanup --- passes/techmap/abc9_ops.cc | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 4843200d8..8fc56b773 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -166,6 +166,7 @@ void prep_dff_map(RTLIL::Design *design) for (auto module : design->modules()) { vector specify_cells; SigBit D, Q; + Cell *c; Cell* dff_cell = nullptr; // If module has a public name (i.e. not $paramod) and it doesn't exist @@ -217,28 +218,23 @@ void prep_dff_map(RTLIL::Design *design) if (!dff_cell) log_error("Module '%s' with (* abc9_flop *) does not any contain $_DFF_[NP]_ cells.\n", log_id(module)); - D = dff_cell->getPort(ID::D); - - { - // Add dummy buffers for all module inputs/outputs - // to ensure that these ports exists in the flop box - // created by later submod pass - for (auto port_name : module->ports) { - auto port = module->wire(port_name); - log_assert(GetSize(port) == 1); - auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); - // Need to set (* keep *) otherwise opt_clean - // inside submod will blow it away - c->set_bool_attribute(ID::keep); - } - // Add an additional buffer that drives $_DFF_[NP]_.D - // so that the flop box will have an output - auto w = module->addWire(NEW_ID); - auto c = module->addBufGate(NEW_ID, D, w); + // Add dummy buffers for all module inputs/outputs + // to ensure that these ports exists in the flop box + // created by later submod pass + for (auto port_name : module->ports) { + auto port = module->wire(port_name); + log_assert(GetSize(port) == 1); + auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); + // Need to set (* keep *) otherwise opt_clean + // inside submod will blow it away c->set_bool_attribute(ID::keep); - dff_cell->setPort(ID::D, w); - D = w; } + // Add an additional buffer that drives $_DFF_[NP]_.D + // so that the flop box will have an output + D = module->addWire(NEW_ID); + c = module->addBufGate(NEW_ID, dff_cell->getPort(ID::D), D); + c->set_bool_attribute(ID::keep); + dff_cell->setPort(ID::D, D); // Rewrite $specify cells that end with $_DFF_[NP]_.Q // to $_DFF_[NP]_.D since it will be moved into @@ -895,9 +891,9 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { - // Short out $_DFF_[NP]_ cells since the flop box already has + // Short out $_FF_ cells since the flop box already has // all the information we need to reconstruct cell - if (dff_mode && mapped_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + if (dff_mode && mapped_cell->type == ID($_FF_)) { SigBit D = mapped_cell->getPort(ID::D); SigBit Q = mapped_cell->getPort(ID::Q); if (D.wire) -- cgit v1.2.3 From 7cd3f4a79bde6dbe2cd7f90d0a4996aebe70fd10 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 12:22:39 -0700 Subject: abc9_ops: add -prep_bypass for auto bypass boxes; refactor Eliminate need for abc9_{,un}map.v in xilinx -prep_dff_{hier,unmap} -> -prep_hier --- passes/techmap/abc9.cc | 64 ++--- passes/techmap/abc9_ops.cc | 618 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 509 insertions(+), 173 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 911254aa6..ff9b46b5f 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -275,22 +275,31 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { if (check_label("check")) { - run("abc9_ops -check"); + if (help_mode) + run("abc9_ops -check [-dff]", "(option if -dff)"); + else + run(stringf("abc9_ops -check %s", dff_mode ? "-dff" : "")); } - if (check_label("dff", "(only if -dff)")) { - if (dff_mode || help_mode) { - run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules, - // create stubs in $abc9_unmap design - run("design -stash $abc9"); - run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in - run("proc"); - run("wbflip"); - run("techmap"); - run("opt"); + if (check_label("map")) { + if (help_mode) + run("abc9_ops -prep_hier -prep_bypass [-prep_dff -dff]", "(option if -dff)"); + else + run(stringf("abc9_ops -prep_hier -prep_bypass %s", dff_mode ? "-prep_dff -dff" : "")); + if (dff_mode) { + run("design -copy-to $abc9_map @$abc9_flops", "(only if -dff)"); + run("select -unset $abc9_flops", " (only if -dff)"); + } + run("design -stash $abc9"); + run("design -load $abc9_map"); + run("proc"); + run("wbflip"); + run("techmap"); + run("opt"); + if (dff_mode) { if (!help_mode) active_design->scratchpad_unset("abc9_ops.prep_dff_map.did_something"); - run("abc9_ops -prep_dff_map"); // rewrite specify + run("abc9_ops -prep_dff_map", "(only if -dff)"); // rewrite specify bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_map.did_something"); if (did_something) { // select all $_DFF_[NP]_ @@ -299,6 +308,8 @@ struct Abc9Pass : public ScriptPass // lastly remove $_DFF_[NP]_ cells run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); run("submod"); + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); + run("abc9_ops -prep_dff_unmap"); run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out run("delete *_$abc9_flop"); if (help_mode) { @@ -313,21 +324,13 @@ struct Abc9Pass : public ScriptPass run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); } } - run("design -stash $abc9_map"); - } - run("design -load $abc9"); - run("design -delete $abc9"); - run("select -unset $abc9_flops"); - if (did_something) { // techmap user design into submod + $_DFF_[NP]_ - run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v"); - run("design -delete $abc9_map"); - run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); - run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design } - else - run("techmap -wb -max_iter 1 -map +/abc9_map.v"); - } + run("design -stash $abc9_map"); + run("design -load $abc9"); + run("design -delete $abc9"); + run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v"); + run("design -delete $abc9_map"); } if (check_label("pre")) { @@ -353,9 +356,10 @@ struct Abc9Pass : public ScriptPass run("aigmap"); run("design -stash $abc9_holes"); run("design -load $abc9"); + run("design -delete $abc9"); } - if (check_label("map")) { + if (check_label("exe")) { run("aigmap"); if (help_mode) { run("foreach module in selection"); @@ -430,12 +434,10 @@ struct Abc9Pass : public ScriptPass } } - if (check_label("post")) { - if (dff_mode || help_mode) { - run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell + if (check_label("unmap")) { + run("techmap -wb -map %$abc9_unmap -map +/abc9_unmap.v"); // techmap user design from submod back to original cell // ($_DFF_[NP]_ already shorted by -reintegrate) - run("design -delete $abc9_unmap", " (only if -dff)"); - } + run("design -delete $abc9_unmap"); if (saved_designs.count("$abc9_holes") || help_mode) run("design -delete $abc9_holes"); } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 8fc56b773..25ac5c340 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -34,13 +34,10 @@ inline std::string remap_name(RTLIL::IdString abc9_name) return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); } -void check(RTLIL::Design *design) +void check(RTLIL::Design *design, bool dff_mode) { dict box_lookup; for (auto m : design->modules()) { - if (m->name.begins_with("$paramod")) - continue; - auto flop = m->get_bool_attribute(ID::abc9_flop); auto it = m->attributes.find(ID::abc9_box_id); if (!flop) { @@ -88,135 +85,405 @@ void check(RTLIL::Design *design) log_error("Module '%s' with (* abc9_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); } } + + if (dff_mode) { + pool unsupported{ + ID($adff), ID($dlatch), ID($dlatchsr), ID($sr), + ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), + ID($_DLATCH_N_), ID($_DLATCH_P_), + ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_), + ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), + ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_) + }; + pool processed; + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->attributes.count(ID::abc9_flop)) + continue; + auto derived_type = inst_module->derive(design, cell->parameters); + if (!processed.insert(derived_type).second) + continue; + if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) + log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type)); + + auto derived_module = design->module(derived_type); + if (derived_module->has_processes()) + Pass::call_on_module(design, derived_module, "proc"); + + if (derived_module->get_bool_attribute(ID::abc9_flop)) { + bool found = false; + for (auto derived_cell : derived_module->cells()) + if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { + if (found) + log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(derived_module)); + found = true; + + SigBit Q = derived_cell->getPort(ID::Q); + log_assert(GetSize(Q.wire) == 1); + + if (!Q.wire->port_output) + log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(derived_module), log_id(derived_cell->type)); + + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); + } + else if (unsupported.count(derived_cell->type)) { + log_error("Module '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis.\n", log_id(derived_module), log_id(derived_cell->type)); + } + } + } + } } -void mark_scc(RTLIL::Module *module) +void prep_hier(RTLIL::Design *design, bool dff_mode) { - // For every unique SCC found, (arbitrarily) find the first - // cell in the component, and replace its output connections - // with a new wire driven by the old connection but with a - // special (* abc9_scc *) attribute set (which is used by - // write_xaiger to break this wire into PI and POs) - pool ids_seen; - for (auto cell : module->cells()) { - auto it = cell->attributes.find(ID::abc9_scc_id); - if (it == cell->attributes.end()) - continue; - auto id = it->second; - auto r = ids_seen.insert(id); - cell->attributes.erase(it); - if (!r.second) - continue; - for (auto &c : cell->connections_) { - if (c.second.is_fully_const()) continue; - if (cell->output(c.first)) { - Wire *w = module->addWire(NEW_ID, GetSize(c.second)); - w->set_bool_attribute(ID::abc9_scc); - module->connect(w, c.second); - c.second = w; + auto r = saved_designs.emplace("$abc9_unmap", nullptr); + if (r.second) + r.first->second = new Design; + Design *unmap_design = r.first->second; + + pool seq_types{ + ID($dff), ID($dffsr), ID($adff), + ID($dlatch), ID($dlatchsr), ID($sr), + ID($mem), + ID($_DFF_N_), ID($_DFF_P_), + ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), + ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_), + ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), + ID($_DLATCH_N_), ID($_DLATCH_P_), + ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_), + ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), + ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_) + }; + + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + auto derived_type = inst_module->derive(design, cell->parameters); + auto derived_module = design->module(derived_type); + if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) + continue; + + if (inst_module->attributes.count(ID::abc9_flop) && !dff_mode) + continue; + if (!inst_module->attributes.count(ID::abc9_box) && !inst_module->attributes.count(ID::abc9_flop)) + continue; + + if (!unmap_design->module(derived_type)) { + if (derived_module->has_processes()) + Pass::call_on_module(design, derived_module, "proc"); + + if (derived_module->get_bool_attribute(ID::abc9_flop)) { + for (auto derived_cell : derived_module->cells()) + if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { + SigBit Q = derived_cell->getPort(ID::Q); + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); + + // Block sequential synthesis on cells with (* init *) != 1'b0 + // because ABC9 doesn't support them + if (init != State::S0) { + log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(derived_module), log_id(derived_cell->type)); + // TODO: still necessary? + // Do not use set_bool_attribute() as it will unset the value + // and (attributes.count(ID::abc9_flop) will fail) + derived_module->attributes[ID::abc9_flop] = false; + goto skip_cell; + } + break; + } + } + else if (derived_module->get_bool_attribute(ID::abc9_box)) { + bool found = false; + for (auto derived_cell : derived_module->cells()) + if (seq_types.count(derived_cell->type)) { + found = true; + break; + } + + if (!found) { + derived_module->set_bool_attribute(ID::abc9_box, false); + log_assert(!derived_module->attributes.count(ID::abc9_box)); + goto skip_cell; + } + + // TODO: still necessary? + // Do not use set_bool_attribute() as it will unset the value + // and (attributes.count(ID::abc9_box) will fail) + derived_module->attributes[ID::abc9_box] = false; + } + + if (derived_type != cell->type) { + auto unmap_module = unmap_design->addModule(derived_type); + for (auto port : derived_module->ports) { + auto w = unmap_module->addWire(port, derived_module->wire(port)); + // Do not propagate (* init *) values inside the box + if (w->port_output) + w->attributes.erase(ID::init); + } + unmap_module->ports = derived_module->ports; + unmap_module->check(); + + auto replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); + for (const auto &conn : cell->connections()) { + auto w = unmap_module->wire(conn.first); + log_assert(w); + replace_cell->setPort(conn.first, w); + } + replace_cell->parameters = cell->parameters; + } } + + cell->type = derived_type; + cell->parameters.clear(); + +skip_cell: ; } - } } - -void prep_dff_hier(RTLIL::Design *design) +void prep_bypass(RTLIL::Design *design) { - auto r YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false))); - log_assert(r.second); - auto &modules_sel = design->selection_vars.at(ID($abc9_flops)); + auto r = saved_designs.emplace("$abc9_map", nullptr); + if (r.second) + r.first->second = new Design; + Design *map_design = r.first->second; - Design *unmap_design = new Design; + r = saved_designs.emplace("$abc9_unmap", nullptr); + if (r.second) + r.first->second = new Design; + Design *unmap_design = r.first->second; + pool processed; for (auto module : design->selected_modules()) for (auto cell : module->cells()) { + if (!processed.insert(cell->type).second) + continue; auto inst_module = design->module(cell->type); - if (inst_module && inst_module->attributes.count(ID::abc9_flop)) { - if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) - log_error("Module '%s' with (* abc9_flop *) is not a whitebox.\n", log_id(inst_module)); - // Derive modules for all instantiations of (* abc9_flop *) - auto derived_type = inst_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); - if (!derived_module->get_bool_attribute(ID::abc9_flop)) + if (!inst_module) + continue; + auto derived_type = inst_module->derive(design, cell->parameters); + inst_module = design->module(derived_type); + log_assert(inst_module); + if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) + continue; + // Skip if (* abc9_box *) exists or is true + auto it = inst_module->attributes.find(ID::abc9_box); + if (it == inst_module->attributes.end() || it->second.as_bool()) + continue; + + + // The idea is to create two techmap designs, one which maps: + // + // box u0 (.i(i), .o(o)); + // + // to + // + // wire $abc9$o; + // box u0 (.i(i), .o($abc9_byp$o)); + // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o)); + // + // the purpose being to move the (* abc9_box *) status from 'box' + // (which is stateful) to 'box_$abc9_byp' (which becomes a new + // combinatorial black- (not white-) box with all state elements + // removed). This has the effect of preserving any combinatorial + // paths through an otherwise sequential primitive -- e.g. LUTRAMs. + // + // The unmap design performs the reverse: + // + // wire $abc9$o; + // box u0 (.i(i), .o($abc9_byp$o)); + // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o)); + // + // to: + // + // wire $abc9$o; + // box u0 (.i(i), .o($abc9_byp$o)); + // assign o = $abc9_byp$o; + + + // Copy derived_module into map_design, with the same interface + // and duplicate $abc9$* wires for its output ports + auto map_module = map_design->addModule(cell->type); + for (auto port_name : inst_module->ports) { + auto w = map_module->addWire(port_name, inst_module->wire(port_name)); + if (w->port_output) + w->attributes.erase(ID::init); + } + map_module->ports = inst_module->ports; + map_module->check(); + map_module->set_bool_attribute(ID::whitebox); + + // Create the bypass module in the user design, which has the same + // interface as the derived module but with additional input + // ports driven by the outputs of the replaced cell + auto bypass_module = design->addModule(cell->type.str() + "_$abc9_byp"); + for (auto port_name : inst_module->ports) { + auto port = inst_module->wire(port_name); + if (!port->port_output) + continue; + auto dst = bypass_module->addWire(port_name, port); + auto src = bypass_module->addWire("$abc9byp$" + port_name.str(), GetSize(port)); + src->port_input = true; + // For these new input ports driven by the replaced + // cell, then create a new simple-path specify entry: + // (input => output) = 0 + auto specify = bypass_module->addCell(NEW_ID, ID($specify2)); + specify->setPort(ID::EN, State::S1); + specify->setPort(ID::SRC, src); + specify->setPort(ID::DST, dst); + specify->setParam(ID::FULL, 0); + specify->setParam(ID::SRC_WIDTH, GetSize(src)); + specify->setParam(ID::DST_WIDTH, GetSize(dst)); + specify->setParam(ID::SRC_DST_PEN, 0); + specify->setParam(ID::SRC_DST_POL, 0); + specify->setParam(ID::T_RISE_MIN, 0); + specify->setParam(ID::T_RISE_TYP, 0); + specify->setParam(ID::T_RISE_MAX, 0); + specify->setParam(ID::T_FALL_MIN, 0); + specify->setParam(ID::T_FALL_TYP, 0); + specify->setParam(ID::T_FALL_MAX, 0); + } + bypass_module->set_bool_attribute(ID::blackbox); + bypass_module->set_bool_attribute(ID::abc9_box); + + // Copy any 'simple' (combinatorial) specify paths from + // the derived module into the bypass module, if EN + // is not false and SRC/DST are driven only by + // module ports; create new input port if one doesn't + // already exist + for (auto cell : inst_module->cells()) { + if (cell->type != ID($specify2)) + continue; + auto EN = cell->getPort(ID::EN).as_bit(); + SigBit newEN; + if (!EN.wire && EN != State::S1) continue; - // And create the stub in the $abc9_unmap design - if (!modules_sel.selected_whole_module(derived_type)) { - if (derived_type != cell->type) - modules_sel.select(inst_module); - - modules_sel.select(derived_module); - - auto unmap_module = unmap_design->addModule(derived_type.str() + "_$abc9_flop"); - auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); - for (const auto &conn : cell->connections()) - unmap_cell->setPort(conn.first, SigSpec()); - unmap_cell->parameters = cell->parameters; + auto SRC = cell->getPort(ID::SRC); + for (const auto &c : SRC.chunks()) + if (c.wire && !c.wire->port_input) { + SRC = SigSpec(); + break; + } + if (SRC.empty()) + continue; + auto DST = cell->getPort(ID::DST); + for (const auto &c : DST.chunks()) + if (c.wire && !c.wire->port_output) { + DST = SigSpec(); + break; + } + if (DST.empty()) + continue; + auto rw = [bypass_module](RTLIL::SigSpec &sig) + { + SigSpec new_sig; + for (auto c : sig.chunks()) { + if (c.wire) { + auto port = bypass_module->wire(c.wire->name); + if (!port) + port = bypass_module->addWire(c.wire->name, c.wire); + c.wire = port; + } + new_sig.append(std::move(c)); + } + sig = std::move(new_sig); + }; + auto specify = bypass_module->addCell(NEW_ID, cell); + specify->rewrite_sigspecs(rw); + } + bypass_module->fixup_ports(); + + // Create an _TECHMAP_REPLACE_ cell identical to the original cell, + // and a bypass cell that has the same inputs/outputs as the + // original cell, but with additional inputs taken from the + // replaced cell + auto replace_cell = map_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); + auto bypass_cell = map_module->addCell(NEW_ID, cell->type.str() + "_$abc9_byp"); + for (const auto &conn : cell->connections()) { + auto port = map_module->wire(conn.first); + if (cell->input(conn.first)) { + replace_cell->setPort(conn.first, port); + if (bypass_module->wire(conn.first)) + bypass_cell->setPort(conn.first, port); + } + if (cell->output(conn.first)) { + bypass_cell->setPort(conn.first, port); + auto n = "$abc9byp$" + conn.first.str(); + auto w = map_module->addWire(n, GetSize(conn.second)); + replace_cell->setPort(conn.first, w); + bypass_cell->setPort(n, w); } } + + + // Lastly, create a new module in the unmap_design that shorts + // out the bypass cell back to leave the replace cell behind + // driving the outputs + auto unmap_module = unmap_design->addModule(cell->type.str() + "_$abc9_byp"); + for (auto port_name : inst_module->ports) { + auto w = unmap_module->addWire(port_name, inst_module->wire(port_name)); + if (w->port_output) { + w->attributes.erase(ID::init); + auto w2 = unmap_module->addWire("$abc9byp$" + port_name.str(), GetSize(w)); + w2->port_input = true; + unmap_module->connect(w, w2); + } + } + unmap_module->fixup_ports(); } +} + +void prep_dff(RTLIL::Design *design) +{ + auto r = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false))); + auto &modules_sel = r.first->second; - auto r2 YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design); - log_assert(r2.second); + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + if (modules_sel.selected_whole_module(cell->type)) + continue; + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->attributes.count(ID::abc9_flop)) + continue; + auto derived_type = inst_module->derive(design, cell->parameters); + auto derived_module = design->module(derived_type); + log_assert(derived_module); + if (!derived_module->get_bool_attribute(ID::abc9_flop)) + continue; + log_assert(!derived_module->get_blackbox_attribute(true /* ignore_wb */)); + modules_sel.select(derived_module); + } } void prep_dff_map(RTLIL::Design *design) { - Design *unmap_design = saved_designs.at("$abc9_unmap"); - for (auto module : design->modules()) { vector specify_cells; - SigBit D, Q; - Cell *c; + SigBit Q; Cell* dff_cell = nullptr; - // If module has a public name (i.e. not $paramod) and it doesn't exist - // in the $abc9_unmap then it means only derived modules were - // instantiated, so make this a blackbox - if (module->name[0] == '\\' && !unmap_design->module(module->name.str() + "_$abc9_flop")) { - module->makeblackbox(); - module->set_bool_attribute(ID::blackbox, false); - module->set_bool_attribute(ID::whitebox, true); + if (!module->get_bool_attribute(ID::abc9_flop)) continue; - } for (auto cell : module->cells()) if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - if (dff_cell) - log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(module)); + log_assert(!dff_cell); dff_cell = cell; - - // Block sequential synthesis on cells with (* init *) != 1'b0 - // because ABC9 doesn't support them Q = cell->getPort(ID::Q); log_assert(GetSize(Q.wire) == 1); - - if (!Q.wire->port_output) - log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(module), log_id(cell->type)); - - Const init = Q.wire->attributes.at(ID::init, State::Sx); - log_assert(GetSize(init) == 1); - if (init != State::S0) { - log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); - - module->makeblackbox(); - module->set_bool_attribute(ID::blackbox, false); - - auto wire = module->addWire(ID(_TECHMAP_FAIL_)); - wire->set_bool_attribute(ID::keep); - module->connect(wire, State::S1); - - goto continue_outer_loop; - } } - else if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), - ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), - ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1), - ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1))) - log_error("Module '%s' with (* abc9_flop *) contains an asynchronous $_DFFE?_[NP][NP][01]_? cell, which is not supported for sequential synthesis.\n", log_id(module)); - else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) + else if (cell->type.in(ID($specify3), ID($specrule))) specify_cells.emplace_back(cell); - if (!dff_cell) - log_error("Module '%s' with (* abc9_flop *) does not any contain $_DFF_[NP]_ cells.\n", log_id(module)); + log_assert(dff_cell); // Add dummy buffers for all module inputs/outputs // to ensure that these ports exists in the flop box @@ -231,8 +498,8 @@ void prep_dff_map(RTLIL::Design *design) } // Add an additional buffer that drives $_DFF_[NP]_.D // so that the flop box will have an output - D = module->addWire(NEW_ID); - c = module->addBufGate(NEW_ID, dff_cell->getPort(ID::D), D); + SigBit D = module->addWire(NEW_ID); + Cell *c = module->addBufGate(NEW_ID, dff_cell->getPort(ID::D), D); c->set_bool_attribute(ID::keep); dff_cell->setPort(ID::D, D); @@ -246,8 +513,6 @@ void prep_dff_map(RTLIL::Design *design) } design->scratchpad_set_bool("abc9_ops.prep_dff_map.did_something", true); - -continue_outer_loop: ; } } @@ -255,28 +520,61 @@ void prep_dff_unmap(RTLIL::Design *design) { Design *unmap_design = saved_designs.at("$abc9_unmap"); - // Create the reverse techmap rule -- (* abc9_box *) back to flop - for (auto module : unmap_design->modules()) { - auto flop_module = design->module(module->name.str()); - if (!flop_module) - continue; // May not exist if init = 1'b1 + for (auto module : design->modules()) { + if (!module->get_bool_attribute(ID::abc9_flop) || module->get_bool_attribute(ID::abc9_box)) + continue; - auto unmap_module = unmap_design->module(flop_module->name); - log_assert(unmap_module); - for (auto port : flop_module->ports) { - auto w = unmap_module->addWire(port, flop_module->wire(port)); + auto unmap_module = unmap_design->addModule(module->name.str() + "_$abc9_flop"); + auto replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, module->name); + for (auto port_name : module->ports) { + auto w = unmap_module->addWire(port_name, module->wire(port_name)); // Do not propagate (* init *) values inside the box - w->attributes.erase(ID::init); + if (w->port_output) + w->attributes.erase(ID::init); + replace_cell->setPort(port_name, w); + } + + // Add new ports appearing in "_$abc9_flop" + auto box_module = design->module(unmap_module->name); + log_assert(box_module); + for (auto port_name : box_module->ports) { + auto port = box_module->wire(port_name); + auto unmap_port = unmap_module->wire(port_name); + if (!unmap_port) + unmap_port = unmap_module->addWire(port_name, port); + else + unmap_port->port_id = port->port_id; } - unmap_module->ports = flop_module->ports; + unmap_module->ports = box_module->ports; unmap_module->check(); + } +} - auto unmap_cell = unmap_module->cell(ID::_TECHMAP_REPLACE_); - log_assert(unmap_cell); - for (const auto &conn : unmap_cell->connections()) { - auto rhs = unmap_module->wire(conn.first); - log_assert(rhs); - unmap_cell->setPort(conn.first, rhs); +void mark_scc(RTLIL::Module *module) +{ + // For every unique SCC found, (arbitrarily) find the first + // cell in the component, and replace its output connections + // with a new wire driven by the old connection but with a + // special (* abc9_scc *) attribute set (which is used by + // write_xaiger to break this wire into PI and POs) + pool ids_seen; + for (auto cell : module->cells()) { + auto it = cell->attributes.find(ID::abc9_scc_id); + if (it == cell->attributes.end()) + continue; + auto id = it->second; + auto r = ids_seen.insert(id); + cell->attributes.erase(it); + if (!r.second) + continue; + for (auto &c : cell->connections_) { + if (c.second.is_fully_const()) continue; + if (cell->output(c.first)) { + Wire *w = module->addWire(NEW_ID, GetSize(c.second)); + w->set_bool_attribute(ID::abc9_scc); + module->connect(w, c.second); + c.second = w; + } } } } @@ -477,7 +775,7 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) continue; if (!inst_module->get_blackbox_attribute()) continue; - if (inst_module->attributes.count(ID::abc9_box)) + if (inst_module->get_bool_attribute(ID::abc9_box)) continue; IdString derived_type = inst_module->derive(design, cell->parameters); inst_module = design->module(derived_type); @@ -630,7 +928,12 @@ void prep_box(RTLIL::Design *design) dict> box_ports; for (auto module : design->modules()) { - if (!module->attributes.erase(ID::abc9_box)) + auto it = module->attributes.find(ID::abc9_box); + if (it == module->attributes.end()) + continue; + bool box = it->second.as_bool(); + module->attributes.erase(it); + if (!box) continue; auto r = module->attributes.insert(ID::abc9_box_id); @@ -758,8 +1061,6 @@ void prep_box(RTLIL::Design *design) auto &t = timing.setup_module(module); if (t.comb.empty()) log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module)); - if (!t.arrival.empty() || !t.required.empty()) - log_error("Module '%s' with (* abc9_box *) has setup and/or edge-sensitive timing information.\n", log_id(module)); for (const auto &o : outputs) { first = true; @@ -1226,21 +1527,38 @@ struct Abc9OpsPass : public Pass { log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n"); log(" (* abc9_carry *) is only given for one input/output port, etc.\n"); log("\n"); - log(" -prep_dff_hier\n"); - log(" derive all cells with a type instantiating an (* abc9_flop *) module.\n"); - log(" store such modules in named selection '$abc9_flops'. create stubs within\n"); - log(" a new '$abc9_unmap' design to be used by -prep_dff_unmap.\n"); + log(" -prep_hier\n"); + log(" derive all used (* abc9_box *) requiring bypass, or (* abc9_flop *) (if\n"); + log(" -dff option) whitebox modules. with (* abc9_box *) modules, bypassing is\n"); + log(" necessary if sequential elements (e.g. $dff, $mem, etc.) are discovered\n"); + log(" inside, to ensure that any combinatorial paths are correctly captured.\n"); + log(" with (* abc9_flop *) modules, only those containing $dff/$_DFF_[NP]_\n"); + log(" cells with zero initial state -- due to an ABC limitation -- will be\n"); + log(" derived. for such derived modules, add a rule inside the '$abc9_unmap'\n"); + log(" design that can map a cell instantiating a derived module back to the\n"); + log(" original cell with parameters.\n"); + log("\n"); + log(" -prep_bypass\n"); + log(" create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for\n"); + log(" bypassing sequential (* abc9_box *) modules using a combinatorial box\n"); + log(" (named *_$abc9_byp) that has inherited all its $specify2 (simple path)\n"); + log(" cells.\n"); + log("\n"); + log(" -prep_dff\n"); + log(" select all (* abc9_flop *) modules instantiated in the design and store\n"); + log(" in the named selection '$abc9_flops'.\n"); log("\n"); log(" -prep_dff_map\n"); - log(" within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n"); - log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n"); - log(" the DFF's 'D' port. this is to prepare such specify cells to be moved into\n"); - log(" a submodule.\n"); + log(" within (* abc9_flop *) modules, attach dummy buffers to all ports and move\n"); + log(" all $specify3/$specrule cells that share a 'DST' port with the $_DFF_[NP]_.Q\n"); + log(" port from this 'Q' port to the DFF's 'D' port. this is to ensure that all\n"); + log(" module ports will exist in any submodule, and prepare such specify cells to\n"); + log(" be moved within.\n"); log("\n"); log(" -prep_dff_unmap\n"); - log(" fill in previously created '$abc9_unmap' design to contain techmap rules\n"); - log(" for mapping *_$abc9_flop cells back into their original (* abc9_flop *)\n"); - log(" cells (including their original parameters).\n"); + log(" populate the '$abc9_unmap' design with techmap rules for mapping *_$abc9_flop\n"); + log(" cells back into their derived cell types (where the rules created by\n"); + log(" -prep_hier will then map back to the original cell with parameters).\n"); log("\n"); log(" -prep_delays\n"); log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); @@ -1288,7 +1606,9 @@ struct Abc9OpsPass : public Pass { bool check_mode = false; bool prep_delays_mode = false; bool mark_scc_mode = false; - bool prep_dff_hier_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false; + bool prep_hier_mode = false; + bool prep_bypass_mode = false; + bool prep_dff_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false; bool prep_xaiger_mode = false; bool prep_lut_mode = false; bool prep_box_mode = false; @@ -1312,8 +1632,18 @@ struct Abc9OpsPass : public Pass { valid = true; continue; } - if (arg == "-prep_dff_hier") { - prep_dff_hier_mode = true; + if (arg == "-prep_hier") { + prep_hier_mode = true; + valid = true; + continue; + } + if (arg == "-prep_bypass") { + prep_bypass_mode = true; + valid = true; + continue; + } + if (arg == "-prep_dff") { + prep_dff_mode = true; valid = true; continue; } @@ -1376,13 +1706,17 @@ struct Abc9OpsPass : public Pass { if (!valid) log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n"); - if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode) - log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger} or -reintegrate.\n"); + if (dff_mode && !check_mode && !prep_hier_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode) + log_cmd_error("'-dff' option is only relevant for -prep_{hier,delay,xaiger} or -reintegrate.\n"); if (check_mode) - check(design); - if (prep_dff_hier_mode) - prep_dff_hier(design); + check(design, dff_mode); + if (prep_hier_mode) + prep_hier(design, dff_mode); + if (prep_bypass_mode) + prep_bypass(design); + if (prep_dff_mode) + prep_dff(design); if (prep_dff_map_mode) prep_dff_map(design); if (prep_dff_unmap_mode) -- cgit v1.2.3 From 8b5fb99245969f62068e3b0b118d7b553ee628e8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 12:30:25 -0700 Subject: abc9_ops: cleanup; -prep_dff -> -prep_dff_submod --- passes/techmap/abc9.cc | 6 +++--- passes/techmap/abc9_ops.cc | 30 +++++++++++------------------- 2 files changed, 14 insertions(+), 22 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index ff9b46b5f..3355cd7aa 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -298,9 +298,9 @@ struct Abc9Pass : public ScriptPass run("opt"); if (dff_mode) { if (!help_mode) - active_design->scratchpad_unset("abc9_ops.prep_dff_map.did_something"); - run("abc9_ops -prep_dff_map", "(only if -dff)"); // rewrite specify - bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_map.did_something"); + active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something"); + run("abc9_ops -prep_dff_submod", "(only if -dff)"); // rewrite specify + bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_submod.did_something"); if (did_something) { // select all $_DFF_[NP]_ // then select all its fanins diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 25ac5c340..bc20d4731 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -191,10 +191,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) // because ABC9 doesn't support them if (init != State::S0) { log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(derived_module), log_id(derived_cell->type)); - // TODO: still necessary? - // Do not use set_bool_attribute() as it will unset the value - // and (attributes.count(ID::abc9_flop) will fail) - derived_module->attributes[ID::abc9_flop] = false; + derived_module->set_bool_attribute(ID::abc9_flop, false); goto skip_cell; } break; @@ -214,10 +211,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) goto skip_cell; } - // TODO: still necessary? - // Do not use set_bool_attribute() as it will unset the value - // and (attributes.count(ID::abc9_box) will fail) - derived_module->attributes[ID::abc9_box] = false; + derived_module->set_bool_attribute(ID::abc9_box, false); } if (derived_type != cell->type) { @@ -273,9 +267,7 @@ void prep_bypass(RTLIL::Design *design) log_assert(inst_module); if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) continue; - // Skip if (* abc9_box *) exists or is true - auto it = inst_module->attributes.find(ID::abc9_box); - if (it == inst_module->attributes.end() || it->second.as_bool()) + if (!inst_module->get_bool_attribute(ID::abc9_box)) continue; @@ -464,7 +456,7 @@ void prep_dff(RTLIL::Design *design) } } -void prep_dff_map(RTLIL::Design *design) +void prep_dff_submod(RTLIL::Design *design) { for (auto module : design->modules()) { vector specify_cells; @@ -512,7 +504,7 @@ void prep_dff_map(RTLIL::Design *design) cell->setPort(ID::DST, DST); } - design->scratchpad_set_bool("abc9_ops.prep_dff_map.did_something", true); + design->scratchpad_set_bool("abc9_ops.prep_dff_submod.did_something", true); } } @@ -1548,7 +1540,7 @@ struct Abc9OpsPass : public Pass { log(" select all (* abc9_flop *) modules instantiated in the design and store\n"); log(" in the named selection '$abc9_flops'.\n"); log("\n"); - log(" -prep_dff_map\n"); + log(" -prep_dff_submod\n"); log(" within (* abc9_flop *) modules, attach dummy buffers to all ports and move\n"); log(" all $specify3/$specrule cells that share a 'DST' port with the $_DFF_[NP]_.Q\n"); log(" port from this 'Q' port to the DFF's 'D' port. this is to ensure that all\n"); @@ -1608,7 +1600,7 @@ struct Abc9OpsPass : public Pass { bool mark_scc_mode = false; bool prep_hier_mode = false; bool prep_bypass_mode = false; - bool prep_dff_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false; + bool prep_dff_mode = false, prep_dff_submod_mode = false, prep_dff_unmap_mode = false; bool prep_xaiger_mode = false; bool prep_lut_mode = false; bool prep_box_mode = false; @@ -1647,8 +1639,8 @@ struct Abc9OpsPass : public Pass { valid = true; continue; } - if (arg == "-prep_dff_map") { - prep_dff_map_mode = true; + if (arg == "-prep_dff_submod") { + prep_dff_submod_mode = true; valid = true; continue; } @@ -1717,8 +1709,8 @@ struct Abc9OpsPass : public Pass { prep_bypass(design); if (prep_dff_mode) prep_dff(design); - if (prep_dff_map_mode) - prep_dff_map(design); + if (prep_dff_submod_mode) + prep_dff_submod(design); if (prep_dff_unmap_mode) prep_dff_unmap(design); if (prep_delays_mode) -- cgit v1.2.3 From e2044fd9c7de4534428ee4f3e8cf1448c493a7fc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 12:32:30 -0700 Subject: abc9_ops: -prep_delays to not insert delay box if input connection is const --- passes/techmap/abc9_ops.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index bc20d4731..d7280e3fd 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -804,6 +804,8 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); if (!port_wire->port_input) continue; + if (conn.second.is_fully_const()) + continue; SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); for (int i = 0; i < GetSize(conn.second); i++) { -- cgit v1.2.3 From d5a8aaba8c6160fe51214677f7452492e950b702 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 12:42:09 -0700 Subject: abc9_ops: tidy up, suppress error if no boxes/holes --- passes/techmap/abc9.cc | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 3355cd7aa..8fa1f60c5 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -296,25 +296,25 @@ struct Abc9Pass : public ScriptPass run("wbflip"); run("techmap"); run("opt"); - if (dff_mode) { + if (dff_mode || help_mode) { if (!help_mode) active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something"); - run("abc9_ops -prep_dff_submod", "(only if -dff)"); // rewrite specify + run("abc9_ops -prep_dff_submod", " (only if -dff)"); // rewrite specify bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_submod.did_something"); if (did_something) { // select all $_DFF_[NP]_ // then select all its fanins // then select all fanouts of all that // lastly remove $_DFF_[NP]_ cells - run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); - run("submod"); - run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); - run("abc9_ops -prep_dff_unmap"); - run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out - run("delete *_$abc9_flop"); + run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d", " (only if -dff)"); + run("submod", " (only if -dff)"); + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop", "(only if -dff)"); + run("abc9_ops -prep_dff_unmap", " (only if -dff)"); + run("design -copy-to $abc9 *_$abc9_flop", " (only if -dff)"); // copy submod out + run("delete *_$abc9_flop", " (only if -dff)"); if (help_mode) { run("foreach module in design"); - run(" rename _$abc9_flop _TECHMAP_REPLACE_"); + run(" rename _$abc9_flop _TECHMAP_REPLACE_", " (only if -dff)"); } else { // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs @@ -346,17 +346,17 @@ struct Abc9Pass : public ScriptPass run(stringf("abc9_ops -prep_lut %d", maxlut)); if (help_mode) run("abc9_ops -prep_box", "(skip if -box)"); - else if (box_file.empty()) { + else if (box_file.empty()) run("abc9_ops -prep_box"); + if (saved_designs.count("$abc9_holes") || help_mode) { + run("design -stash $abc9"); + run("design -load $abc9_holes"); + run("techmap -wb -map %$abc9 -map +/techmap.v"); + run("opt -purge"); + run("design -stash $abc9_holes"); + run("design -load $abc9"); + run("design -delete $abc9"); } - run("design -stash $abc9"); - run("design -load $abc9_holes"); - run("techmap -wb -map %$abc9 -map +/techmap.v"); - run("opt -purge"); - run("aigmap"); - run("design -stash $abc9_holes"); - run("design -load $abc9"); - run("design -delete $abc9"); } if (check_label("exe")) { -- cgit v1.2.3 From b3e2538a140cac36c32b133d4475a052cfc46809 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 14:12:28 -0700 Subject: abc9_ops: fix bypass boxes using (* abc9_bypass *) --- passes/techmap/abc9_ops.cc | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index d7280e3fd..37d0528c1 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -102,7 +102,7 @@ void check(RTLIL::Design *design, bool dff_mode) auto inst_module = design->module(cell->type); if (!inst_module) continue; - if (!inst_module->attributes.count(ID::abc9_flop)) + if (!inst_module->get_bool_attribute(ID::abc9_flop)) continue; auto derived_type = inst_module->derive(design, cell->parameters); if (!processed.insert(derived_type).second) @@ -171,9 +171,9 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) continue; - if (inst_module->attributes.count(ID::abc9_flop) && !dff_mode) + if (inst_module->get_bool_attribute(ID::abc9_flop) && !dff_mode) continue; - if (!inst_module->attributes.count(ID::abc9_box) && !inst_module->attributes.count(ID::abc9_flop)) + if (!inst_module->get_bool_attribute(ID::abc9_box) && !inst_module->get_bool_attribute(ID::abc9_flop)) continue; if (!unmap_design->module(derived_type)) { @@ -205,13 +205,11 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) break; } - if (!found) { - derived_module->set_bool_attribute(ID::abc9_box, false); - log_assert(!derived_module->attributes.count(ID::abc9_box)); + if (!found) goto skip_cell; - } derived_module->set_bool_attribute(ID::abc9_box, false); + derived_module->set_bool_attribute(ID::abc9_bypass); } if (derived_type != cell->type) { @@ -265,9 +263,8 @@ void prep_bypass(RTLIL::Design *design) auto derived_type = inst_module->derive(design, cell->parameters); inst_module = design->module(derived_type); log_assert(inst_module); - if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) - continue; - if (!inst_module->get_bool_attribute(ID::abc9_box)) + log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); + if (!inst_module->get_bool_attribute(ID::abc9_bypass)) continue; @@ -444,7 +441,7 @@ void prep_dff(RTLIL::Design *design) auto inst_module = design->module(cell->type); if (!inst_module) continue; - if (!inst_module->attributes.count(ID::abc9_flop)) + if (!inst_module->get_bool_attribute(ID::abc9_flop)) continue; auto derived_type = inst_module->derive(design, cell->parameters); auto derived_module = design->module(derived_type); @@ -589,7 +586,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) continue; auto inst_module = design->module(cell->type); - bool abc9_flop = inst_module && inst_module->attributes.count(ID::abc9_flop); + bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop); if (abc9_flop && !dff) continue; -- cgit v1.2.3 From ed7cb0b095e0eaf0ced643f7f828ea2c61b939b5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 15:42:05 -0700 Subject: abc9: put 'aigmap' back --- passes/techmap/abc9.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 8fa1f60c5..93751e0bc 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -353,6 +353,7 @@ struct Abc9Pass : public ScriptPass run("design -load $abc9_holes"); run("techmap -wb -map %$abc9 -map +/techmap.v"); run("opt -purge"); + run("aigmap"); run("design -stash $abc9_holes"); run("design -load $abc9"); run("design -delete $abc9"); -- cgit v1.2.3 From b65610fb628cfd38edcab3c64507477a58cbdd10 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 15:44:56 -0700 Subject: abc9_ops: move assert --- passes/techmap/abc9_ops.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 37d0528c1..b3f5b9919 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -263,9 +263,9 @@ void prep_bypass(RTLIL::Design *design) auto derived_type = inst_module->derive(design, cell->parameters); inst_module = design->module(derived_type); log_assert(inst_module); - log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); if (!inst_module->get_bool_attribute(ID::abc9_bypass)) continue; + log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); // The idea is to create two techmap designs, one which maps: -- cgit v1.2.3 From 2946bb60e95408be1ffc5b667b6c84160f7f41e6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 17:25:15 -0700 Subject: abc9: rework submod -- since it won't move (* keep *) cells --- passes/techmap/abc9.cc | 7 +++--- passes/techmap/abc9_ops.cc | 56 +++++++++++++++++++++------------------------- 2 files changed, 29 insertions(+), 34 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 93751e0bc..147d6e572 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -309,9 +309,6 @@ struct Abc9Pass : public ScriptPass run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d", " (only if -dff)"); run("submod", " (only if -dff)"); run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop", "(only if -dff)"); - run("abc9_ops -prep_dff_unmap", " (only if -dff)"); - run("design -copy-to $abc9 *_$abc9_flop", " (only if -dff)"); // copy submod out - run("delete *_$abc9_flop", " (only if -dff)"); if (help_mode) { run("foreach module in design"); run(" rename _$abc9_flop _TECHMAP_REPLACE_", " (only if -dff)"); @@ -323,7 +320,11 @@ struct Abc9Pass : public ScriptPass if (module->cell(stringf("%s_$abc9_flop", module->name.c_str()))) run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); } + active_design->selected_active_module.clear(); } + run("abc9_ops -prep_dff_unmap", " (only if -dff)"); + run("design -copy-to $abc9 *_$abc9_flop", " (only if -dff)"); // copy submod out + run("delete *_$abc9_flop", " (only if -dff)"); } } run("design -stash $abc9_map"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index b3f5b9919..5521bdf62 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -474,22 +474,11 @@ void prep_dff_submod(RTLIL::Design *design) specify_cells.emplace_back(cell); log_assert(dff_cell); - // Add dummy buffers for all module inputs/outputs - // to ensure that these ports exists in the flop box - // created by later submod pass - for (auto port_name : module->ports) { - auto port = module->wire(port_name); - log_assert(GetSize(port) == 1); - auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); - // Need to set (* keep *) otherwise opt_clean - // inside submod will blow it away - c->set_bool_attribute(ID::keep); - } - // Add an additional buffer that drives $_DFF_[NP]_.D - // so that the flop box will have an output + // Add an always-enabled CE mux that drives $_DFF_[NP]_.D so that: + // (a) flop box will have an output + // (b) $_DFF_[NP]_.Q will be present as an input SigBit D = module->addWire(NEW_ID); - Cell *c = module->addBufGate(NEW_ID, dff_cell->getPort(ID::D), D); - c->set_bool_attribute(ID::keep); + module->addMuxGate(NEW_ID, dff_cell->getPort(ID::D), Q, State::S0, D); dff_cell->setPort(ID::D, D); // Rewrite $specify cells that end with $_DFF_[NP]_.Q @@ -513,26 +502,31 @@ void prep_dff_unmap(RTLIL::Design *design) if (!module->get_bool_attribute(ID::abc9_flop) || module->get_bool_attribute(ID::abc9_box)) continue; - auto unmap_module = unmap_design->addModule(module->name.str() + "_$abc9_flop"); - auto replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, module->name); + // Make sure the box module has all the same ports present on flop cell + auto replace_cell = module->cell(ID::_TECHMAP_REPLACE_); + log_assert(replace_cell); + auto box_module = design->module(module->name.str() + "_$abc9_flop"); + log_assert(box_module); for (auto port_name : module->ports) { - auto w = unmap_module->addWire(port_name, module->wire(port_name)); - // Do not propagate (* init *) values inside the box - if (w->port_output) - w->attributes.erase(ID::init); - replace_cell->setPort(port_name, w); + auto port = module->wire(port_name); + auto box_port = box_module->wire(port_name); + if (box_port) { + // Do not propagate init -- already captured by box + box_port->attributes.erase(ID::init); + continue; + } + log_assert(port->port_input); + box_module->addWire(port_name, port); + replace_cell->setPort(port_name, port); } + box_module->fixup_ports(); - // Add new ports appearing in "_$abc9_flop" - auto box_module = design->module(unmap_module->name); - log_assert(box_module); + auto unmap_module = unmap_design->addModule(box_module->name); + replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, module->name); for (auto port_name : box_module->ports) { - auto port = box_module->wire(port_name); - auto unmap_port = unmap_module->wire(port_name); - if (!unmap_port) - unmap_port = unmap_module->addWire(port_name, port); - else - unmap_port->port_id = port->port_id; + auto w = unmap_module->addWire(port_name, box_module->wire(port_name)); + if (module->wire(port_name)) + replace_cell->setPort(port_name, w); } unmap_module->ports = box_module->ports; unmap_module->check(); -- cgit v1.2.3 From 57c478c537ef23c05ca34ecdf4c4334fd82c104e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 17:54:24 -0700 Subject: abc9: only do +/abc9_map if `DFF --- passes/techmap/abc9.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 147d6e572..60a88f729 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -330,7 +330,10 @@ struct Abc9Pass : public ScriptPass run("design -stash $abc9_map"); run("design -load $abc9"); run("design -delete $abc9"); - run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v"); + if (help_mode) + run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v [-D DFF]", "(option if -dff)"); + else + run(stringf("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : "")); run("design -delete $abc9_map"); } -- cgit v1.2.3 From f652a9c11c75b7728db838c1c74c587ba92043ca Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Apr 2020 13:07:19 -0700 Subject: abc9_ops: update docs --- passes/techmap/abc9_ops.cc | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 5521bdf62..a87a94b1d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1516,29 +1516,28 @@ struct Abc9OpsPass : public Pass { log(" derive all used (* abc9_box *) requiring bypass, or (* abc9_flop *) (if\n"); log(" -dff option) whitebox modules. with (* abc9_box *) modules, bypassing is\n"); log(" necessary if sequential elements (e.g. $dff, $mem, etc.) are discovered\n"); - log(" inside, to ensure that any combinatorial paths are correctly captured.\n"); + log(" inside to ensure that any combinatorial paths are correctly captured.\n"); log(" with (* abc9_flop *) modules, only those containing $dff/$_DFF_[NP]_\n"); log(" cells with zero initial state -- due to an ABC limitation -- will be\n"); - log(" derived. for such derived modules, add a rule inside the '$abc9_unmap'\n"); - log(" design that can map a cell instantiating a derived module back to the\n"); - log(" original cell with parameters.\n"); + log(" derived.\n"); log("\n"); log(" -prep_bypass\n"); log(" create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for\n"); log(" bypassing sequential (* abc9_box *) modules using a combinatorial box\n"); - log(" (named *_$abc9_byp) that has inherited all its $specify2 (simple path)\n"); - log(" cells.\n"); + log(" (named *_$abc9_byp). this bypass box will only contain ports that are\n"); + log(" referenced by a simple path declaration ($specify2 cell) inside a\n"); + log(" specify block.\n"); log("\n"); log(" -prep_dff\n"); log(" select all (* abc9_flop *) modules instantiated in the design and store\n"); log(" in the named selection '$abc9_flops'.\n"); log("\n"); log(" -prep_dff_submod\n"); - log(" within (* abc9_flop *) modules, attach dummy buffers to all ports and move\n"); - log(" all $specify3/$specrule cells that share a 'DST' port with the $_DFF_[NP]_.Q\n"); - log(" port from this 'Q' port to the DFF's 'D' port. this is to ensure that all\n"); - log(" module ports will exist in any submodule, and prepare such specify cells to\n"); - log(" be moved within.\n"); + log(" within (* abc9_flop *) modules, rewrite all edge-sensitive path\n"); + log(" declarations and $setup() timing checks ($specify3 and $specrule cells)\n"); + log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n"); + log(" the DFF's 'D' port. this is to prepare such specify cells to be moved\n"); + log(" into the flop box.\n"); log("\n"); log(" -prep_dff_unmap\n"); log(" populate the '$abc9_unmap' design with techmap rules for mapping *_$abc9_flop\n"); -- cgit v1.2.3 From 8d34aee3d5addfc796ca7057d38e77628c6a77b4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Apr 2020 17:37:07 -0700 Subject: abc9: update to =_$abc9_flops pattern which includes whiteboxes --- passes/techmap/abc9.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 60a88f729..06097a6f7 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -323,8 +323,8 @@ struct Abc9Pass : public ScriptPass active_design->selected_active_module.clear(); } run("abc9_ops -prep_dff_unmap", " (only if -dff)"); - run("design -copy-to $abc9 *_$abc9_flop", " (only if -dff)"); // copy submod out - run("delete *_$abc9_flop", " (only if -dff)"); + run("design -copy-to $abc9 =*_$abc9_flop", " (only if -dff)"); // copy submod out + run("delete =*_$abc9_flop", " (only if -dff)"); } } run("design -stash $abc9_map"); @@ -333,7 +333,7 @@ struct Abc9Pass : public ScriptPass if (help_mode) run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v [-D DFF]", "(option if -dff)"); else - run(stringf("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : "")); + run(stringf("techmap -wb -max_iter 1 -map %%$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : "")); run("design -delete $abc9_map"); } -- cgit v1.2.3 From e79127fcebf9c5aed47f6f56fcfc8a4c4f98705c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 18:02:05 -0700 Subject: Cleanup; reduce Module::derive() calls --- passes/techmap/abc9_ops.cc | 271 +++++++++++++++++++++++---------------------- 1 file changed, 140 insertions(+), 131 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index a87a94b1d..2fbae8c5e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -87,7 +87,7 @@ void check(RTLIL::Design *design, bool dff_mode) } if (dff_mode) { - pool unsupported{ + static pool unsupported{ ID($adff), ID($dlatch), ID($dlatchsr), ID($sr), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), @@ -102,38 +102,38 @@ void check(RTLIL::Design *design, bool dff_mode) auto inst_module = design->module(cell->type); if (!inst_module) continue; - if (!inst_module->get_bool_attribute(ID::abc9_flop)) + if (!inst_module->get_blackbox_attribute()) continue; auto derived_type = inst_module->derive(design, cell->parameters); if (!processed.insert(derived_type).second) continue; - if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) + auto derived_module = design->module(derived_type); + if (!derived_module->get_bool_attribute(ID::abc9_flop)) + continue; + if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type)); - auto derived_module = design->module(derived_type); if (derived_module->has_processes()) Pass::call_on_module(design, derived_module, "proc"); - if (derived_module->get_bool_attribute(ID::abc9_flop)) { - bool found = false; - for (auto derived_cell : derived_module->cells()) - if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { - if (found) - log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(derived_module)); - found = true; + bool found = false; + for (auto derived_cell : derived_module->cells()) { + if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { + if (found) + log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(derived_module)); + found = true; - SigBit Q = derived_cell->getPort(ID::Q); - log_assert(GetSize(Q.wire) == 1); + SigBit Q = derived_cell->getPort(ID::Q); + log_assert(GetSize(Q.wire) == 1); - if (!Q.wire->port_output) - log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(derived_module), log_id(derived_cell->type)); + if (!Q.wire->port_output) + log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(derived_module), log_id(derived_cell->type)); - Const init = Q.wire->attributes.at(ID::init, State::Sx); - log_assert(GetSize(init) == 1); - } - else if (unsupported.count(derived_cell->type)) { - log_error("Module '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis.\n", log_id(derived_module), log_id(derived_cell->type)); - } + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); + } + else if (unsupported.count(derived_cell->type)) + log_error("Module '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis.\n", log_id(derived_module), log_id(derived_cell->type)); } } } @@ -146,7 +146,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) r.first->second = new Design; Design *unmap_design = r.first->second; - pool seq_types{ + static const pool seq_types{ ID($dff), ID($dffsr), ID($adff), ID($dlatch), ID($dlatchsr), ID($sr), ID($mem), @@ -166,14 +166,16 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) auto inst_module = design->module(cell->type); if (!inst_module) continue; + if (!inst_module->get_blackbox_attribute()) + continue; auto derived_type = inst_module->derive(design, cell->parameters); auto derived_module = design->module(derived_type); if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) continue; - if (inst_module->get_bool_attribute(ID::abc9_flop) && !dff_mode) + if (derived_module->get_bool_attribute(ID::abc9_flop) && !dff_mode) continue; - if (!inst_module->get_bool_attribute(ID::abc9_box) && !inst_module->get_bool_attribute(ID::abc9_flop)) + if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_flop)) continue; if (!unmap_design->module(derived_type)) { @@ -260,11 +262,9 @@ void prep_bypass(RTLIL::Design *design) auto inst_module = design->module(cell->type); if (!inst_module) continue; - auto derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); if (!inst_module->get_bool_attribute(ID::abc9_bypass)) continue; + log_assert(cell->parameters.empty()); log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); @@ -297,7 +297,7 @@ void prep_bypass(RTLIL::Design *design) // assign o = $abc9_byp$o; - // Copy derived_module into map_design, with the same interface + // Copy inst_module into map_design, with the same interface // and duplicate $abc9$* wires for its output ports auto map_module = map_design->addModule(cell->type); for (auto port_name : inst_module->ports) { @@ -443,13 +443,9 @@ void prep_dff(RTLIL::Design *design) continue; if (!inst_module->get_bool_attribute(ID::abc9_flop)) continue; - auto derived_type = inst_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); - log_assert(derived_module); - if (!derived_module->get_bool_attribute(ID::abc9_flop)) - continue; - log_assert(!derived_module->get_blackbox_attribute(true /* ignore_wb */)); - modules_sel.select(derived_module); + log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); + log_assert(cell->parameters.empty()); + modules_sel.select(inst_module); } } @@ -562,6 +558,99 @@ void mark_scc(RTLIL::Module *module) } } +void prep_delays(RTLIL::Design *design, bool dff_mode) +{ + TimingInfo timing; + + // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes + // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations + pool flops; + std::vector> cells; + for (auto module : design->selected_modules()) { + if (module->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(module)); + continue; + } + + for (auto cell : module->cells()) { + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY))) + continue; + + RTLIL::Module* inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->get_blackbox_attribute()) + continue; + + IdString derived_type; + if (cell->parameters.empty()) + derived_type = cell->type; + else + derived_type = inst_module->derive(design, cell->parameters); + auto derived_module = design->module(derived_type); + log_assert(derived_module); + log_assert(derived_module->get_blackbox_attribute()); + + if (derived_module->get_bool_attribute(ID::abc9_box)) + continue; + if (derived_module->get_bool_attribute(ID::abc9_bypass)) + continue; + + if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) { + flops.insert(inst_module); + continue; // do not add $__ABC9_DELAY boxes to flops + // as delays will be captured in the flop box + } + + if (!timing.count(derived_type)) + timing.setup_module(derived_module); + + cells.emplace_back(cell, derived_module); + } + } + + // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes + // (or bypassed white-boxes with required times) + for (const auto &i : cells) { + auto cell = i.first; + auto module = cell->module; + auto derived_module = i.second; + auto derived_type = derived_module->name; + + auto &t = timing.at(derived_type).required; + for (auto &conn : cell->connections_) { + auto port_wire = derived_module->wire(conn.first); + if (!port_wire) + log_error("Port %s in cell %s (type %s) of module %s does not actually exist", + log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); + if (!port_wire->port_input) + continue; + if (conn.second.is_fully_const()) + continue; + + SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); + for (int i = 0; i < GetSize(conn.second); i++) { + auto d = t.at(TimingInfo::NameBit(conn.first,i), 0); + if (d == 0) + continue; + +#ifndef NDEBUG + if (ys_debug(1)) { + static std::set> seen; + if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", + log_id(cell->type), log_id(conn.first), i, d); + } +#endif + auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); + box->setPort(ID::I, conn.second[i]); + box->setPort(ID::O, O[i]); + box->setParam(ID::DELAY, d); + conn.second[i] = O[i]; + } + } + } +} + void prep_xaiger(RTLIL::Module *module, bool dff) { auto design = module->design; @@ -670,30 +759,36 @@ void prep_xaiger(RTLIL::Module *module, bool dff) log_assert(cell); RTLIL::Module* box_module = design->module(cell->type); - if (!box_module || !box_module->get_bool_attribute(ID::abc9_box)) + if (!box_module) + continue; + if (!box_module->get_blackbox_attribute()) continue; - - cell->attributes[ID::abc9_box_seq] = box_count++; IdString derived_type; if (cell->parameters.empty()) derived_type = cell->type; else derived_type = box_module->derive(design, cell->parameters); - box_module = design->module(derived_type); + auto derived_module = design->module(derived_type); + log_assert(derived_module); + + if (!derived_module->get_bool_attribute(ID::abc9_box)) + continue; + + cell->attributes[ID::abc9_box_seq] = box_count++; auto r = cell_cache.insert(derived_type); auto &holes_cell = r.first->second; if (r.second) { - if (box_module->get_bool_attribute(ID::whitebox)) { + if (derived_module->get_bool_attribute(ID::whitebox)) { holes_cell = holes_module->addCell(cell->name, derived_type); - if (box_module->has_processes()) - Pass::call_on_module(design, box_module, "proc"); + if (derived_module->has_processes()) + Pass::call_on_module(design, derived_module, "proc"); int box_inputs = 0; for (auto port_name : box_ports.at(cell->type)) { - RTLIL::Wire *w = box_module->wire(port_name); + RTLIL::Wire *w = derived_module->wire(port_name); log_assert(w); log_assert(!w->port_input || !w->port_output); auto &conn = holes_cell->connections_[port_name]; @@ -714,12 +809,12 @@ void prep_xaiger(RTLIL::Module *module, bool dff) conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w)); } } - else // box_module is a blackbox + else // derived_module is a blackbox log_assert(holes_cell == nullptr); } for (auto port_name : box_ports.at(cell->type)) { - RTLIL::Wire *w = box_module->wire(port_name); + RTLIL::Wire *w = derived_module->wire(port_name); log_assert(w); if (!w->port_output) continue; @@ -735,92 +830,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } -void prep_delays(RTLIL::Design *design, bool dff_mode) -{ - TimingInfo timing; - - // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes - // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations - pool flops; - std::vector cells; - for (auto module : design->selected_modules()) { - if (module->processes.size() > 0) { - log("Skipping module %s as it contains processes.\n", log_id(module)); - continue; - } - - for (auto cell : module->cells()) { - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY))) - continue; - - RTLIL::Module* inst_module = module->design->module(cell->type); - if (!inst_module) - continue; - if (!inst_module->get_blackbox_attribute()) - continue; - if (inst_module->get_bool_attribute(ID::abc9_box)) - continue; - IdString derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); - - if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) { - flops.insert(inst_module); - continue; // do not add $__ABC9_DELAY boxes to flops - // as delays will be captured in the flop box - } - - if (!timing.count(derived_type)) - timing.setup_module(inst_module); - - cells.emplace_back(cell); - } - } - - // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes - // with required times - for (auto cell : cells) { - auto module = cell->module; - RTLIL::Module* inst_module = module->design->module(cell->type); - log_assert(inst_module); - IdString derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); - - auto &t = timing.at(derived_type).required; - for (auto &conn : cell->connections_) { - auto port_wire = inst_module->wire(conn.first); - if (!port_wire) - log_error("Port %s in cell %s (type %s) of module %s does not actually exist", - log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); - if (!port_wire->port_input) - continue; - if (conn.second.is_fully_const()) - continue; - - SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); - for (int i = 0; i < GetSize(conn.second); i++) { - auto d = t.at(TimingInfo::NameBit(conn.first,i), 0); - if (d == 0) - continue; - -#ifndef NDEBUG - if (ys_debug(1)) { - static std::set> seen; - if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", - log_id(cell->type), log_id(conn.first), i, d); - } -#endif - auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); - box->setPort(ID::I, conn.second[i]); - box->setPort(ID::O, O[i]); - box->setParam(ID::DELAY, d); - conn.second[i] = O[i]; - } - } - } -} - void prep_lut(RTLIL::Design *design, int maxlut) { TimingInfo timing; -- cgit v1.2.3 From 97a0a0431489568300b40c1d376af7b5d8cb7027 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 21:56:06 -0700 Subject: abc9_ops/xaiger: further reducing Module::derive() calls by ... replacing _all_ (* abc9_box *) instantiations with their derived types --- passes/techmap/abc9_ops.cc | 172 ++++++++++++++++++++++----------------------- 1 file changed, 84 insertions(+), 88 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2fbae8c5e..2794c913a 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -104,10 +104,17 @@ void check(RTLIL::Design *design, bool dff_mode) continue; if (!inst_module->get_blackbox_attribute()) continue; - auto derived_type = inst_module->derive(design, cell->parameters); - if (!processed.insert(derived_type).second) - continue; - auto derived_module = design->module(derived_type); + IdString derived_type; + Module *derived_module; + if (cell->parameters.empty()) { + derived_type = cell->type; + derived_module = inst_module; + } + else { + derived_type = inst_module->derive(design, cell->parameters); + derived_module = design->module(derived_type); + log_assert(derived_module); + } if (!derived_module->get_bool_attribute(ID::abc9_flop)) continue; if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) @@ -168,15 +175,27 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) continue; if (!inst_module->get_blackbox_attribute()) continue; - auto derived_type = inst_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); + IdString derived_type; + Module *derived_module; + if (cell->parameters.empty()) { + derived_type = cell->type; + derived_module = inst_module; + } + else { + derived_type = inst_module->derive(design, cell->parameters); + derived_module = design->module(derived_type); + } if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) continue; - if (derived_module->get_bool_attribute(ID::abc9_flop) && !dff_mode) - continue; - if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_flop)) - continue; + if (derived_module->get_bool_attribute(ID::abc9_flop)) { + if (!dff_mode) + continue; + } + else { + if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass)) + continue; + } if (!unmap_design->module(derived_type)) { if (derived_module->has_processes()) @@ -200,18 +219,12 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) } } else if (derived_module->get_bool_attribute(ID::abc9_box)) { - bool found = false; for (auto derived_cell : derived_module->cells()) if (seq_types.count(derived_cell->type)) { - found = true; + derived_module->set_bool_attribute(ID::abc9_box, false); + derived_module->set_bool_attribute(ID::abc9_bypass); break; } - - if (!found) - goto skip_cell; - - derived_module->set_bool_attribute(ID::abc9_box, false); - derived_module->set_bool_attribute(ID::abc9_bypass); } if (derived_type != cell->type) { @@ -264,8 +277,8 @@ void prep_bypass(RTLIL::Design *design) continue; if (!inst_module->get_bool_attribute(ID::abc9_bypass)) continue; - log_assert(cell->parameters.empty()); log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); + log_assert(cell->parameters.empty()); // The idea is to create two techmap designs, one which maps: @@ -564,8 +577,7 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations - pool flops; - std::vector> cells; + std::vector cells; for (auto module : design->selected_modules()) { if (module->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(module)); @@ -573,56 +585,51 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) } for (auto cell : module->cells()) { - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY))) + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_))) continue; + log_assert(!cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")); RTLIL::Module* inst_module = design->module(cell->type); if (!inst_module) continue; if (!inst_module->get_blackbox_attribute()) continue; + if (!cell->parameters.empty()) + continue; - IdString derived_type; - if (cell->parameters.empty()) - derived_type = cell->type; - else - derived_type = inst_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); - log_assert(derived_module); - log_assert(derived_module->get_blackbox_attribute()); - - if (derived_module->get_bool_attribute(ID::abc9_box)) + if (inst_module->get_bool_attribute(ID::abc9_box)) continue; - if (derived_module->get_bool_attribute(ID::abc9_bypass)) + if (inst_module->get_bool_attribute(ID::abc9_bypass)) continue; if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) { - flops.insert(inst_module); continue; // do not add $__ABC9_DELAY boxes to flops // as delays will be captured in the flop box } - if (!timing.count(derived_type)) - timing.setup_module(derived_module); + if (!timing.count(cell->type)) + timing.setup_module(inst_module); - cells.emplace_back(cell, derived_module); + cells.emplace_back(cell); } } // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes // (or bypassed white-boxes with required times) - for (const auto &i : cells) { - auto cell = i.first; + dict box_cache; + Module *delay_module = design->module(ID($__ABC9_DELAY)); + log_assert(delay_module); + for (auto cell : cells) { auto module = cell->module; - auto derived_module = i.second; - auto derived_type = derived_module->name; + auto inst_module = design->module(cell->type); + log_assert(inst_module); - auto &t = timing.at(derived_type).required; + auto &t = timing.at(cell->type).required; for (auto &conn : cell->connections_) { - auto port_wire = derived_module->wire(conn.first); + auto port_wire = inst_module->wire(conn.first); if (!port_wire) - log_error("Port %s in cell %s (type %s) of module %s does not actually exist", - log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); + log_error("Port %s in cell %s (type %s) from module %s does not actually exist", + log_id(conn.first), log_id(cell), log_id(cell->type), log_id(module)); if (!port_wire->port_input) continue; if (conn.second.is_fully_const()) @@ -637,14 +644,18 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) #ifndef NDEBUG if (ys_debug(1)) { static std::set> seen; - if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", + if (seen.emplace(cell->type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", log_id(cell->type), log_id(conn.first), i, d); } #endif - auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); + auto r = box_cache.insert(d); + if (r.second) { + r.first->second = delay_module->derive(design, {{ID::DELAY, d}}); + log_assert(r.first->second.begins_with("$paramod$__ABC9_DELAY\\DELAY=")); + } + auto box = module->addCell(NEW_ID, r.first->second); box->setPort(ID::I, conn.second[i]); box->setPort(ID::O, O[i]); - box->setParam(ID::DELAY, d); conn.second[i] = O[i]; } } @@ -761,34 +772,26 @@ void prep_xaiger(RTLIL::Module *module, bool dff) RTLIL::Module* box_module = design->module(cell->type); if (!box_module) continue; - if (!box_module->get_blackbox_attribute()) - continue; - - IdString derived_type; - if (cell->parameters.empty()) - derived_type = cell->type; - else - derived_type = box_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); - log_assert(derived_module); - - if (!derived_module->get_bool_attribute(ID::abc9_box)) + if (!box_module->get_bool_attribute(ID::abc9_box)) continue; +log_cell(cell); + log_assert(cell->parameters.empty()); + log_assert(box_module->get_blackbox_attribute()); cell->attributes[ID::abc9_box_seq] = box_count++; - auto r = cell_cache.insert(derived_type); + auto r = cell_cache.insert(cell->type); auto &holes_cell = r.first->second; if (r.second) { - if (derived_module->get_bool_attribute(ID::whitebox)) { - holes_cell = holes_module->addCell(cell->name, derived_type); + if (box_module->get_bool_attribute(ID::whitebox)) { + holes_cell = holes_module->addCell(cell->name, cell->type); - if (derived_module->has_processes()) - Pass::call_on_module(design, derived_module, "proc"); + if (box_module->has_processes()) + Pass::call_on_module(design, box_module, "proc"); int box_inputs = 0; for (auto port_name : box_ports.at(cell->type)) { - RTLIL::Wire *w = derived_module->wire(port_name); + RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); log_assert(!w->port_input || !w->port_output); auto &conn = holes_cell->connections_[port_name]; @@ -806,15 +809,15 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } else if (w->port_output) - conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w)); + conn = holes_module->addWire(stringf("%s.%s", cell->type.c_str(), log_id(port_name)), GetSize(w)); } } - else // derived_module is a blackbox + else // box_module is a blackbox log_assert(holes_cell == nullptr); } for (auto port_name : box_ports.at(cell->type)) { - RTLIL::Wire *w = derived_module->wire(port_name); + RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); if (!w->port_output) continue; @@ -1282,7 +1285,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) if (!existing_cell) log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell)); - if (existing_cell->type == ID($__ABC9_DELAY)) { + if (existing_cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) { SigBit I = mapped_cell->getPort(ID(i)); SigBit O = mapped_cell->getPort(ID(o)); if (I.wire) @@ -1294,14 +1297,8 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) } RTLIL::Module* box_module = design->module(existing_cell->type); - IdString derived_type; - if (existing_cell->parameters.empty()) - derived_type = existing_cell->type; - else - derived_type = box_module->derive(design, existing_cell->parameters); - RTLIL::Module* derived_module = design->module(derived_type); - log_assert(derived_module); - log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at(ID::abc9_box_id).as_int())); + log_assert(existing_cell->parameters.empty()); + log_assert(mapped_cell->type == stringf("$__boxid%d", box_module->attributes.at(ID::abc9_box_id).as_int())); mapped_cell->type = existing_cell->type; RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); @@ -1329,7 +1326,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) } int input_count = 0, output_count = 0; - for (const auto &port_name : box_ports.at(derived_type)) { + for (const auto &port_name : box_ports.at(existing_cell->type)) { RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); @@ -1522,19 +1519,18 @@ struct Abc9OpsPass : public Pass { log(" (* abc9_carry *) is only given for one input/output port, etc.\n"); log("\n"); log(" -prep_hier\n"); - log(" derive all used (* abc9_box *) requiring bypass, or (* abc9_flop *) (if\n"); - log(" -dff option) whitebox modules. with (* abc9_box *) modules, bypassing is\n"); - log(" necessary if sequential elements (e.g. $dff, $mem, etc.) are discovered\n"); - log(" inside to ensure that any combinatorial paths are correctly captured.\n"); - log(" with (* abc9_flop *) modules, only those containing $dff/$_DFF_[NP]_\n"); - log(" cells with zero initial state -- due to an ABC limitation -- will be\n"); - log(" derived.\n"); + log(" derive all used (* abc9_box *) or (* abc9_flop *) (if -dff option)\n"); + log(" whitebox modules. with (* abc9_flop *) modules, only those containing\n"); + log(" $dff/$_DFF_[NP]_ cells with zero initial state -- due to an ABC limitation\n"); + log(" -- will be derived.\n"); log("\n"); log(" -prep_bypass\n"); log(" create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for\n"); log(" bypassing sequential (* abc9_box *) modules using a combinatorial box\n"); - log(" (named *_$abc9_byp). this bypass box will only contain ports that are\n"); - log(" referenced by a simple path declaration ($specify2 cell) inside a\n"); + log(" (named *_$abc9_byp). bypassing is necessary if sequential elements (e.g.\n"); + log(" $dff, $mem, etc.) are discovered inside so that any combinatorial paths\n"); + log(" will be correctly captured. this bypass box will only contain ports that\n"); + log(" are referenced by a simple path declaration ($specify2 cell) inside a\n"); log(" specify block.\n"); log("\n"); log(" -prep_dff\n"); -- cgit v1.2.3 From fa31e84112c004348fae30e64ca224367b71d187 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 22:10:24 -0700 Subject: Fix broken test when ignoring abc9_flop with init == 1'b1 --- passes/techmap/abc9_ops.cc | 3 --- 1 file changed, 3 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2794c913a..41a11e9a7 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -213,7 +213,6 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) if (init != State::S0) { log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(derived_module), log_id(derived_cell->type)); derived_module->set_bool_attribute(ID::abc9_flop, false); - goto skip_cell; } break; } @@ -250,8 +249,6 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) cell->type = derived_type; cell->parameters.clear(); - -skip_cell: ; } } -- cgit v1.2.3 From 13f9d65b6fc09af76330c02ab420324b50db61da Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 00:29:45 -0700 Subject: abc9: preserve $_DFF_?_.Q's (* init *); rely on clean to remove it --- passes/techmap/abc9_ops.cc | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 41a11e9a7..03a3c5583 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1101,17 +1101,6 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) map_autoidx = autoidx++; - // TODO: Get rid of this expensive lookup - dict> sig2inits; - SigMap sigmap(module); - for (auto w : module->wires()) { - auto it = w->attributes.find(ID::init); - if (it == w->attributes.end()) - continue; - for (const auto &b : SigSpec(w)) - sig2inits[sigmap(b)].emplace_back(b); - } - RTLIL::Module *mapped_mod = design->module(stringf("%s$abc9", module->name.c_str())); if (mapped_mod == NULL) log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module)); @@ -1164,12 +1153,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) // Short out $_DFF_[NP]_ cells since the flop box already has // all the information we need to reconstruct cell if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - SigBit Q = cell->getPort(ID::Q); - auto it = sig2inits.find(Q); - if (it != sig2inits.end()) - for (const auto &b : it->second) - b.wire->attributes.at(ID::init)[b.offset] = State::Sx; - module->connect(Q, cell->getPort(ID::D)); + module->connect(cell->getPort(ID::Q), cell->getPort(ID::D)); module->remove(cell); } else if (cell->type.in(ID($_AND_), ID($_NOT_))) -- cgit v1.2.3 From 02df0198b65a2514d1343eeff8827f4e2cf858d0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 02:09:13 -0700 Subject: abc9_ops: -prep_hier to create unmap module that removes Q's (* init *) --- passes/techmap/abc9_ops.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 03a3c5583..6a8dbde8b 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -230,9 +230,12 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) auto unmap_module = unmap_design->addModule(derived_type); for (auto port : derived_module->ports) { auto w = unmap_module->addWire(port, derived_module->wire(port)); - // Do not propagate (* init *) values inside the box - if (w->port_output) - w->attributes.erase(ID::init); + // Do not propagate (* init *) values into the box, + // in fact, remove it from outside too + if (w->port_output && w->attributes.erase(ID::init)) { + auto r = unmap_module->addWire(stringf("\\_TECHMAP_REMOVEINIT_%s_", log_id(port))); + unmap_module->connect(r, State::S1); + } } unmap_module->ports = derived_module->ports; unmap_module->check(); @@ -771,7 +774,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) continue; if (!box_module->get_bool_attribute(ID::abc9_box)) continue; -log_cell(cell); log_assert(cell->parameters.empty()); log_assert(box_module->get_blackbox_attribute()); -- cgit v1.2.3 From 67fc0c3698693f049e805211c49d6219f17d7c7d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 16:44:35 -0700 Subject: abc9: use (* abc9_keep *) instead of (* abc9_scc *); apply to $_DFF_?_ instead of moving them to $__ prefix --- passes/techmap/abc9_ops.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 6a8dbde8b..10c980f73 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -563,7 +563,7 @@ void mark_scc(RTLIL::Module *module) if (c.second.is_fully_const()) continue; if (cell->output(c.first)) { Wire *w = module->addWire(NEW_ID, GetSize(c.second)); - w->set_bool_attribute(ID::abc9_scc); + w->set_bool_attribute(ID::abc9_keep); module->connect(w, c.second); c.second = w; } @@ -1154,7 +1154,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) // Short out $_DFF_[NP]_ cells since the flop box already has // all the information we need to reconstruct cell - if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep)) { module->connect(cell->getPort(ID::Q), cell->getPort(ID::D)); module->remove(cell); } @@ -1373,7 +1373,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) RTLIL::Wire *mapped_wire = mapped_mod->wire(port); RTLIL::Wire *wire = module->wire(port); log_assert(wire); - wire->attributes.erase(ID::abc9_scc); + wire->attributes.erase(ID::abc9_keep); RTLIL::Wire *remap_wire = module->wire(remap_name(port)); RTLIL::SigSpec signal(wire, remap_wire->start_offset-wire->start_offset, GetSize(remap_wire)); -- cgit v1.2.3