From abf99d4dae8a464910b81122f9720660c59a631e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 12 Dec 2019 14:32:29 -0800 Subject: tribuf: set scratchpad boolean 'tribuf.added_something' --- passes/techmap/tribuf.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'passes/techmap') diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc index 41fdc8f3d..decf9a202 100644 --- a/passes/techmap/tribuf.cc +++ b/passes/techmap/tribuf.cc @@ -86,6 +86,7 @@ struct TribufWorker { cell->unsetPort(ID(S)); cell->type = tri_type; tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); + module->design->scratchpad_set_bool("tribuf.added_something", true); continue; } @@ -95,6 +96,7 @@ struct TribufWorker { cell->unsetPort(ID(S)); cell->type = tri_type; tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); + module->design->scratchpad_set_bool("tribuf.added_something", true); continue; } } @@ -130,8 +132,10 @@ struct TribufWorker { if (no_tribuf) module->connect(it.first, muxout); - else + else { module->addTribuf(NEW_ID, muxout, module->ReduceOr(NEW_ID, pmux_s), it.first); + module->design->scratchpad_set_bool("tribuf.added_something", true); + } } } } -- cgit v1.2.3 From ec2539480867fcc05c904043747b2f3cba9a9866 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 28 Dec 2019 03:16:28 -0800 Subject: Rename abc9.cc -> abc9_techmap.cc --- passes/techmap/Makefile.inc | 1 + passes/techmap/abc9.cc | 1310 ---------------------------------------- passes/techmap/abc9_techmap.cc | 1310 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1311 insertions(+), 1310 deletions(-) delete mode 100644 passes/techmap/abc9.cc create mode 100644 passes/techmap/abc9_techmap.cc (limited to 'passes/techmap') diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index cd357d72a..a7c8d8c2b 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -8,6 +8,7 @@ OBJS += passes/techmap/libparse.o ifeq ($(ENABLE_ABC),1) OBJS += passes/techmap/abc.o OBJS += passes/techmap/abc9.o +OBJS += passes/techmap/abc9_techmap.o ifneq ($(ABCEXTERNAL),) passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc deleted file mode 100644 index d03e5da8e..000000000 --- a/passes/techmap/abc9.cc +++ /dev/null @@ -1,1310 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * 2019 Eddie Hung - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// [[CITE]] ABC -// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification -// http://www.eecs.berkeley.edu/~alanmi/abc/ - -#if 0 -// Based on &flow3 - better QoR but more experimental -#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \ - "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\ - "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\ - "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ - "&mfs; &ps -l" -#else -#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" -#endif - - -#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}" - -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/cost.h" -#include "kernel/log.h" -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -# include -# include -#endif - -#include "frontends/aiger/aigerparse.h" -#include "kernel/utils.h" - -#ifdef YOSYS_LINK_ABC -extern "C" int Abc_RealMain(int argc, char *argv[]); -#endif - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -bool markgroups; -int map_autoidx; -SigMap assign_map; -RTLIL::Module *module; - -bool clk_polarity, en_polarity; -RTLIL::SigSpec clk_sig, en_sig; - -inline std::string remap_name(RTLIL::IdString abc9_name) -{ - return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); -} - -void handle_loops(RTLIL::Design *design) -{ - Pass::call(design, "scc -set_attr abc9_scc_id {}"); - - // For every unique SCC found, (arbitrarily) find the first - // cell in the component, and select (and mark) all its output - // wires - pool ids_seen; - for (auto cell : module->cells()) { - auto it = cell->attributes.find(ID(abc9_scc_id)); - if (it != cell->attributes.end()) { - auto r = ids_seen.insert(it->second); - if (r.second) { - for (auto &c : cell->connections_) { - if (c.second.is_fully_const()) continue; - if (cell->output(c.first)) { - SigBit b = c.second.as_bit(); - Wire *w = b.wire; - if (w->port_input) { - // In this case, hopefully the loop break has been already created - // Get the non-prefixed wire - Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str())); - log_assert(wo != nullptr); - log_assert(wo->port_output); - log_assert(b.offset < GetSize(wo)); - c.second = RTLIL::SigBit(wo, b.offset); - } - else { - // Create a new output/input loop break - w->port_input = true; - w = module->wire(stringf("%s.abco", w->name.c_str())); - if (!w) { - w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire)); - w->port_output = true; - } - else { - log_assert(w->port_input); - log_assert(b.offset < GetSize(w)); - } - w->set_bool_attribute(ID(abc9_scc_break)); - c.second = RTLIL::SigBit(w, b.offset); - } - } - } - } - cell->attributes.erase(it); - } - } - - module->fixup_ports(); -} - -std::string add_echos_to_abc9_cmd(std::string str) -{ - std::string new_str, token; - for (size_t i = 0; i < str.size(); i++) { - token += str[i]; - if (str[i] == ';') { - while (i+1 < str.size() && str[i+1] == ' ') - i++; - new_str += "echo + " + token + " " + token + " "; - token.clear(); - } - } - - if (!token.empty()) { - if (!new_str.empty()) - new_str += "echo + " + token + "; "; - new_str += token; - } - - return new_str; -} - -std::string fold_abc9_cmd(std::string str) -{ - std::string token, new_str = " "; - int char_counter = 10; - - for (size_t i = 0; i <= str.size(); i++) { - if (i < str.size()) - token += str[i]; - if (i == str.size() || str[i] == ';') { - if (char_counter + token.size() > 75) - new_str += "\n ", char_counter = 14; - new_str += token, char_counter += token.size(); - token.clear(); - } - } - - return new_str; -} - -std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir) -{ - if (show_tempdir) - return text; - - while (1) { - size_t pos = text.find(tempdir_name); - if (pos == std::string::npos) - break; - text = text.substr(0, pos) + "" + text.substr(pos + GetSize(tempdir_name)); - } - - std::string selfdir_name = proc_self_dirname(); - if (selfdir_name != "/") { - while (1) { - size_t pos = text.find(selfdir_name); - if (pos == std::string::npos) - break; - text = text.substr(0, pos) + "/" + text.substr(pos + GetSize(selfdir_name)); - } - } - - return text; -} - -struct abc9_output_filter -{ - bool got_cr; - int escape_seq_state; - std::string linebuf; - std::string tempdir_name; - bool show_tempdir; - - abc9_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) - { - got_cr = false; - escape_seq_state = 0; - } - - void next_char(char ch) - { - if (escape_seq_state == 0 && ch == '\033') { - escape_seq_state = 1; - return; - } - if (escape_seq_state == 1) { - escape_seq_state = ch == '[' ? 2 : 0; - return; - } - if (escape_seq_state == 2) { - if ((ch < '0' || '9' < ch) && ch != ';') - escape_seq_state = 0; - return; - } - escape_seq_state = 0; - if (ch == '\r') { - got_cr = true; - return; - } - if (ch == '\n') { - log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str()); - got_cr = false, linebuf.clear(); - return; - } - if (got_cr) - got_cr = false, linebuf.clear(); - linebuf += ch; - } - - void next_line(const std::string &line) - { - //int pi, po; - //if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { - // log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", - // pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", - // po, po_map.count(po) ? po_map.at(po).c_str() : "???"); - // return; - //} - - for (char ch : line) - next_char(ch); - } -}; - -void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, - bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, - bool show_tempdir, std::string box_file, std::string lut_file, - std::string wire_delay, const dict &box_lookup, bool nomfs -) -{ - module = current_module; - map_autoidx = autoidx++; - - if (clk_str != "$") - { - clk_polarity = true; - clk_sig = RTLIL::SigSpec(); - - en_polarity = true; - en_sig = RTLIL::SigSpec(); - } - - if (!clk_str.empty() && clk_str != "$") - { - if (clk_str.find(',') != std::string::npos) { - int pos = clk_str.find(','); - std::string en_str = clk_str.substr(pos+1); - clk_str = clk_str.substr(0, pos); - if (en_str[0] == '!') { - en_polarity = false; - en_str = en_str.substr(1); - } - if (module->wires_.count(RTLIL::escape_id(en_str)) != 0) - en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0)); - } - if (clk_str[0] == '!') { - clk_polarity = false; - clk_str = clk_str.substr(1); - } - if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0) - clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); - } - - if (dff_mode && clk_sig.empty()) - log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); - - std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; - if (!cleanup) - tempdir_name[0] = tempdir_name[4] = '_'; - tempdir_name = make_temp_dir(tempdir_name); - log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", - module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); - - std::string abc9_script; - - if (!lut_costs.empty()) { - abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); - if (!box_file.empty()) - abc9_script += stringf("read_box -v %s; ", box_file.c_str()); - } - else - if (!lut_file.empty()) { - abc9_script += stringf("read_lut %s; ", lut_file.c_str()); - if (!box_file.empty()) - abc9_script += stringf("read_box -v %s; ", box_file.c_str()); - } - else - log_abort(); - - abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); - - if (!script_file.empty()) { - if (script_file[0] == '+') { - for (size_t i = 1; i < script_file.size(); i++) - if (script_file[i] == '\'') - abc9_script += "'\\''"; - else if (script_file[i] == ',') - abc9_script += " "; - else - abc9_script += script_file[i]; - } else - abc9_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty() || !lut_file.empty()) { - //bool all_luts_cost_same = true; - //for (int this_cost : lut_costs) - // if (this_cost != lut_costs.front()) - // all_luts_cost_same = false; - abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; - //if (all_luts_cost_same && !fast_mode) - // abc9_script += "; lutpack {S}"; - } else - log_abort(); - - //if (script_file.empty() && !delay_target.empty()) - // for (size_t pos = abc9_script.find("dretime;"); pos != std::string::npos; pos = abc9_script.find("dretime;", pos+1)) - // abc9_script = abc9_script.substr(0, pos) + "dretime; retime -o {D};" + abc9_script.substr(pos+8); - - for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) - abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); - - //for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos)) - // abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3); - - for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos)) - abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3); - - if (nomfs) - for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) - abc9_script = abc9_script.erase(pos, strlen("&mfs")); - - abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str()); - abc9_script = add_echos_to_abc9_cmd(abc9_script); - - for (size_t i = 0; i+1 < abc9_script.size(); i++) - if (abc9_script[i] == ';' && abc9_script[i+1] == ' ') - abc9_script[i+1] = '\n'; - - FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); - fprintf(f, "%s\n", abc9_script.c_str()); - fclose(f); - - if (dff_mode || !clk_str.empty()) - { - if (clk_sig.size() == 0) - log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); - else { - log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig)); - if (en_sig.size() != 0) - log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig)); - log("\n"); - } - } - - bool count_output = false; - for (auto port_name : module->ports) { - RTLIL::Wire *port_wire = module->wire(port_name); - log_assert(port_wire); - if (port_wire->port_output) { - count_output = true; - break; - } - } - - log_push(); - - if (count_output) - { - design->selection_stack.emplace_back(false); - RTLIL::Selection& sel = design->selection_stack.back(); - sel.select(module); - - handle_loops(design); - - Pass::call(design, "aigmap"); - - //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n", - // count_gates, GetSize(signal_list), count_input, count_output); - - Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); - - std::string buffer; - std::ifstream ifs; -#if 0 - buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig"); - ifs.open(buffer); - if (ifs.fail()) - log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); - log_assert(!design->module(ID($__abc9__))); - { - AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); - reader.parse_xaiger(); - } - ifs.close(); - Pass::call(design, stringf("write_verilog -noexpr -norename")); - design->remove(design->module(ID($__abc9__))); -#endif - - design->selection_stack.pop_back(); - - log_header(design, "Executing ABC9.\n"); - - if (!lut_costs.empty()) { - buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); - f = fopen(buffer.c_str(), "wt"); - if (f == NULL) - log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); - for (int i = 0; i < GetSize(lut_costs); i++) - fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); - fclose(f); - } - - buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); - log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); - -#ifndef YOSYS_LINK_ABC - abc9_output_filter filt(tempdir_name, show_tempdir); - int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1)); -#else - // These needs to be mutable, supposedly due to getopt - char *abc9_argv[5]; - string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); - abc9_argv[0] = strdup(exe_file.c_str()); - abc9_argv[1] = strdup("-s"); - abc9_argv[2] = strdup("-f"); - abc9_argv[3] = strdup(tmp_script_name.c_str()); - abc9_argv[4] = 0; - int ret = Abc_RealMain(4, abc9_argv); - free(abc9_argv[0]); - free(abc9_argv[1]); - free(abc9_argv[2]); - free(abc9_argv[3]); -#endif - if (ret != 0) - log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); - - buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig"); - ifs.open(buffer, std::ifstream::binary); - if (ifs.fail()) - log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - - buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); - log_assert(!design->module(ID($__abc9__))); - - AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); - reader.parse_xaiger(box_lookup); - ifs.close(); - -#if 0 - Pass::call(design, stringf("write_verilog -noexpr -norename")); -#endif - - log_header(design, "Re-integrating ABC9 results.\n"); - RTLIL::Module *mapped_mod = design->module(ID($__abc9__)); - if (mapped_mod == NULL) - log_error("ABC output file does not contain a module `$__abc9__'.\n"); - - pool output_bits; - for (auto &it : mapped_mod->wires_) { - RTLIL::Wire *w = it.second; - RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w)); - if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx; - if (w->port_output) { - RTLIL::Wire *wire = module->wire(w->name); - log_assert(wire); - for (int i = 0; i < GetSize(w); i++) - output_bits.insert({wire, i}); - } - } - - for (auto &it : module->connections_) { - auto &signal = it.first; - auto bits = signal.bits(); - for (auto &b : bits) - if (output_bits.count(b)) - b = module->addWire(NEW_ID); - signal = std::move(bits); - } - - dict abc9_box; - vector boxes; - for (const auto &it : module->cells_) { - auto cell = it.second; - if (cell->type.in(ID($_AND_), ID($_NOT_))) { - module->remove(cell); - continue; - } - auto jt = abc9_box.find(cell->type); - if (jt == abc9_box.end()) { - RTLIL::Module* box_module = design->module(cell->type); - jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first; - } - if (jt->second) - boxes.emplace_back(cell); - } - - dict> bit_drivers, bit_users; - TopoSort toposort; - dict not2drivers; - dict> bit2sinks; - - std::map cell_stats; - for (auto c : mapped_mod->cells()) - { - toposort.node(c->name); - - RTLIL::Cell *cell = nullptr; - if (c->type == ID($_NOT_)) { - RTLIL::SigBit a_bit = c->getPort(ID::A); - RTLIL::SigBit y_bit = c->getPort(ID::Y); - bit_users[a_bit].insert(c->name); - bit_drivers[y_bit].insert(c->name); - - if (!a_bit.wire) { - c->setPort(ID::Y, module->addWire(NEW_ID)); - RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); - log_assert(wire); - module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); - } - else if (!lut_costs.empty() || !lut_file.empty()) { - RTLIL::Cell* driver_lut = nullptr; - // ABC can return NOT gates that drive POs - if (!a_bit.wire->port_input) { - // If it's not a NOT gate that that comes from a PI directly, - // find the driver LUT and clone that to guarantee that we won't - // increase the max logic depth - // (TODO: Optimise by not cloning unless will increase depth) - RTLIL::IdString driver_name; - if (GetSize(a_bit.wire) == 1) - driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); - else - driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); - driver_lut = mapped_mod->cell(driver_name); - } - - if (!driver_lut) { - // If a driver couldn't be found (could be from PI or box CI) - // then implement using a LUT - cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), - RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), - RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), - RTLIL::Const::from_string("01")); - bit2sinks[cell->getPort(ID::A)].push_back(cell); - cell_stats[ID($lut)]++; - } - else - not2drivers[c] = driver_lut; - continue; - } - else - log_abort(); - if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; - continue; - } - cell_stats[c->type]++; - - RTLIL::Cell *existing_cell = nullptr; - if (c->type == ID($lut)) { - if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { - SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name)); - SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); - if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; - log_abort(); - continue; - } - cell = module->addCell(remap_name(c->name), c->type); - } - else { - existing_cell = module->cell(c->name); - log_assert(existing_cell); - cell = module->addCell(remap_name(c->name), c->type); - } - - if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; - if (existing_cell) { - cell->parameters = existing_cell->parameters; - cell->attributes = existing_cell->attributes; - } - else { - cell->parameters = c->parameters; - cell->attributes = c->attributes; - } - for (auto &conn : c->connections()) { - RTLIL::SigSpec newsig; - for (auto c : conn.second.chunks()) { - if (c.width == 0) - continue; - //log_assert(c.width == 1); - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - newsig.append(c); - } - cell->setPort(conn.first, newsig); - - if (cell->input(conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : conn.second) - bit_users[i].insert(c->name); - } - if (cell->output(conn.first)) - for (auto i : conn.second) - bit_drivers[i].insert(c->name); - } - } - - for (auto existing_cell : boxes) { - Cell *cell = module->cell(remap_name(existing_cell->name)); - if (cell) { - for (auto &conn : existing_cell->connections()) { - if (!conn.second.is_wire()) - continue; - Wire *wire = conn.second.as_wire(); - if (!wire->get_bool_attribute(ID(abc9_padding))) - continue; - cell->unsetPort(conn.first); - log_debug("Dropping padded port connection for %s (%s) .%s (%s )\n", log_id(cell), cell->type.c_str(), log_id(conn.first), log_signal(conn.second)); - } - module->swap_names(cell, existing_cell); - } - module->remove(existing_cell); - } - - // Copy connections (and rename) from mapped_mod to module - for (auto conn : mapped_mod->connections()) { - if (!conn.first.is_fully_const()) { - auto chunks = conn.first.chunks(); - for (auto &c : chunks) - c.wire = module->wires_.at(remap_name(c.wire->name)); - conn.first = std::move(chunks); - } - if (!conn.second.is_fully_const()) { - auto chunks = conn.second.chunks(); - for (auto &c : chunks) - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - conn.second = std::move(chunks); - } - module->connect(conn); - } - - for (auto &it : cell_stats) - log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); - int in_wires = 0, out_wires = 0; - - // Stitch in mapped_mod's inputs/outputs into module - for (auto port : mapped_mod->ports) { - RTLIL::Wire *w = mapped_mod->wire(port); - RTLIL::Wire *wire = module->wire(port); - log_assert(wire); - RTLIL::Wire *remap_wire = module->wire(remap_name(port)); - RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); - log_assert(GetSize(signal) >= GetSize(remap_wire)); - - RTLIL::SigSig conn; - if (w->port_output) { - conn.first = signal; - conn.second = remap_wire; - out_wires++; - module->connect(conn); - } - else if (w->port_input) { - conn.first = remap_wire; - conn.second = signal; - in_wires++; - module->connect(conn); - } - } - - for (auto &it : bit_users) - if (bit_drivers.count(it.first)) - for (auto driver_cell : bit_drivers.at(it.first)) - for (auto user_cell : it.second) - toposort.edge(driver_cell, user_cell); - bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); - log_assert(no_loops); - - for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { - RTLIL::Cell *not_cell = mapped_mod->cell(*ii); - log_assert(not_cell); - if (not_cell->type != ID($_NOT_)) - continue; - auto it = not2drivers.find(not_cell); - if (it == not2drivers.end()) - continue; - RTLIL::Cell *driver_lut = it->second; - RTLIL::SigBit a_bit = not_cell->getPort(ID::A); - RTLIL::SigBit y_bit = not_cell->getPort(ID::Y); - RTLIL::Const driver_mask; - - a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name)); - y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name)); - - auto jt = bit2sinks.find(a_bit); - if (jt == bit2sinks.end()) - goto clone_lut; - - for (auto sink_cell : jt->second) - if (sink_cell->type != ID($lut)) - goto clone_lut; - - // Push downstream LUTs past inverter - for (auto sink_cell : jt->second) { - SigSpec A = sink_cell->getPort(ID::A); - RTLIL::Const mask = sink_cell->getParam(ID(LUT)); - int index = 0; - for (; index < GetSize(A); index++) - if (A[index] == a_bit) - break; - log_assert(index < GetSize(A)); - int i = 0; - while (i < GetSize(mask)) { - for (int j = 0; j < (1 << index); j++) - std::swap(mask[i+j], mask[i+j+(1 << index)]); - i += 1 << (index+1); - } - A[index] = y_bit; - sink_cell->setPort(ID::A, A); - sink_cell->setParam(ID(LUT), mask); - } - - // Since we have rewritten all sinks (which we know - // to be only LUTs) to be after the inverter, we can - // go ahead and clone the LUT with the expectation - // that the original driving LUT will become dangling - // and get cleaned away -clone_lut: - driver_mask = driver_lut->getParam(ID(LUT)); - for (auto &b : driver_mask.bits) { - if (b == RTLIL::State::S0) b = RTLIL::State::S1; - else if (b == RTLIL::State::S1) b = RTLIL::State::S0; - } - auto cell = module->addLut(NEW_ID, - driver_lut->getPort(ID::A), - y_bit, - driver_mask); - for (auto &bit : cell->connections_.at(ID::A)) { - bit.wire = module->wires_.at(remap_name(bit.wire->name)); - bit2sinks[bit].push_back(cell); - } - } - - // Now 'unexpose' those wires by undoing - // the expose operation -- remove them from PO/PI - // and re-connecting them back together - for (auto wire : module->wires()) { - auto it = wire->attributes.find(ID(abc9_scc_break)); - if (it != wire->attributes.end()) { - wire->attributes.erase(it); - log_assert(wire->port_output); - wire->port_output = false; - std::string name = wire->name.str(); - RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5)); - log_assert(i_wire); - log_assert(i_wire->port_input); - i_wire->port_input = false; - module->connect(i_wire, wire); - } - } - module->fixup_ports(); - - //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); - log("ABC RESULTS: input signals: %8d\n", in_wires); - log("ABC RESULTS: output signals: %8d\n", out_wires); - - design->remove(mapped_mod); - } - else - { - log("Don't call ABC as there is nothing to map.\n"); - } - - if (cleanup) - { - log("Removing temp directory.\n"); - remove_directory(tempdir_name); - } - - log_pop(); -} - -struct Abc9Pass : public Pass { - Abc9Pass() : Pass("abc9", "use ABC9 for technology mapping") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" abc9 [options] [selection]\n"); - log("\n"); - log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); - log("library to a target architecture.\n"); - log("\n"); - log(" -exe \n"); -#ifdef ABCEXTERNAL - log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); -#else - log(" use the specified command instead of \"/yosys-abc\" to execute ABC.\n"); -#endif - log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n"); - log("\n"); - log(" -script \n"); - log(" use the specified ABC script file instead of the default script.\n"); - log("\n"); - log(" if starts with a plus sign (+), then the rest of the filename\n"); - log(" string is interpreted as the command string to be passed to ABC. The\n"); - log(" leading plus sign is removed and all commas (,) in the string are\n"); - log(" replaced with blanks before the string is passed to ABC.\n"); - log("\n"); - log(" if no -script parameter is given, the following scripts are used:\n"); - log("\n"); - log(" for -lut/-luts (only one LUT size):\n"); - log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); - log("\n"); - log(" for -lut/-luts (different LUT sizes):\n"); - log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); - log("\n"); - log(" -fast\n"); - log(" use different default scripts that are slightly faster (at the cost\n"); - log(" of output quality):\n"); - log("\n"); - log(" for -lut/-luts:\n"); - log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); - log("\n"); - log(" -D \n"); - log(" set delay target. the string {D} in the default scripts above is\n"); - log(" replaced by this option when used, and an empty string otherwise\n"); - log(" (indicating best possible delay).\n"); -// log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n"); -// log(" default scripts above.\n"); - log("\n"); -// log(" -S \n"); -// log(" maximum number of LUT inputs shared.\n"); -// log(" (replaces {S} in the default scripts above, default: -S 1)\n"); -// log("\n"); - log(" -lut \n"); - log(" generate netlist using luts of (max) the specified width.\n"); - log("\n"); - log(" -lut :\n"); - log(" generate netlist using luts of (max) the specified width . All\n"); - log(" luts with width <= have constant cost. for luts larger than \n"); - log(" the area cost doubles with each additional input bit. the delay cost\n"); - log(" is still constant for all lut widths.\n"); - log("\n"); - log(" -lut \n"); - log(" pass this file with lut library to ABC.\n"); - log("\n"); - log(" -luts ,,,:,..\n"); - log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); - log(" 2, 3, .. inputs.\n"); - log("\n"); -// log(" -dff\n"); -// log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n"); -// log(" clock domains are automatically partitioned in clock domains and each\n"); -// log(" domain is passed through ABC independently.\n"); -// log("\n"); -// log(" -clk [!][,[!]]\n"); -// log(" use only the specified clock domain. this is like -dff, but only FF\n"); -// log(" cells that belong to the specified clock domain are used.\n"); -// log("\n"); -// log(" -keepff\n"); -// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n"); -// log(" them, for example for equivalence checking.)\n"); -// log("\n"); - log(" -nocleanup\n"); - log(" when this option is used, the temporary files created by this pass\n"); - log(" are not removed. this is useful for debugging.\n"); - log("\n"); - log(" -showtmp\n"); - log(" print the temp dir name in log. usually this is suppressed so that the\n"); - log(" command output is identical across runs.\n"); - log("\n"); - log(" -markgroups\n"); - log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n"); - log(" this attribute is a unique integer for each ABC process started. This\n"); - log(" is useful for debugging the partitioning of clock domains.\n"); - log("\n"); - log(" -box \n"); - log(" pass this file with box library to ABC. Use with -lut.\n"); - log("\n"); - log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); - log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); - log("ABC on logic snippets extracted from your design. You will not get any useful\n"); - log("output when passing an ABC script that writes a file. Instead write your full\n"); - log("design as BLIF file with write_blif and then load that into ABC externally if\n"); - log("you want to use ABC to convert your design into another format.\n"); - log("\n"); - log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n"); - log_push(); - - assign_map.clear(); - -#ifdef ABCEXTERNAL - std::string exe_file = ABCEXTERNAL; -#else - std::string exe_file = proc_self_dirname() + "yosys-abc"; -#endif - std::string script_file, clk_str, box_file, lut_file; - std::string delay_target, lutin_shared = "-S 1", wire_delay; - bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; - bool show_tempdir = false; - bool nomfs = false; - vector lut_costs; - markgroups = false; - -#if 0 - cleanup = false; - show_tempdir = true; -#endif - -#ifdef _WIN32 -#ifndef ABCEXTERNAL - if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) - exe_file = proc_self_dirname() + "..\\yosys-abc"; -#endif -#endif - - size_t argidx; - char pwd [PATH_MAX]; - if (!getcwd(pwd, sizeof(pwd))) { - log_cmd_error("getcwd failed: %s\n", strerror(errno)); - log_abort(); - } - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-exe" && argidx+1 < args.size()) { - exe_file = args[++argidx]; - continue; - } - if (arg == "-script" && argidx+1 < args.size()) { - script_file = args[++argidx]; - rewrite_filename(script_file); - if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') - script_file = std::string(pwd) + "/" + script_file; - continue; - } - if (arg == "-D" && argidx+1 < args.size()) { - delay_target = "-D " + args[++argidx]; - continue; - } - //if (arg == "-S" && argidx+1 < args.size()) { - // lutin_shared = "-S " + args[++argidx]; - // continue; - //} - if (arg == "-lut" && argidx+1 < args.size()) { - string arg = args[++argidx]; - if (arg.find_first_not_of("0123456789:") == std::string::npos) { - size_t pos = arg.find_first_of(':'); - int lut_mode = 0, lut_mode2 = 0; - if (pos != string::npos) { - lut_mode = atoi(arg.substr(0, pos).c_str()); - lut_mode2 = atoi(arg.substr(pos+1).c_str()); - } else { - lut_mode = atoi(arg.c_str()); - lut_mode2 = lut_mode; - } - lut_costs.clear(); - for (int i = 0; i < lut_mode; i++) - lut_costs.push_back(1); - for (int i = lut_mode; i < lut_mode2; i++) - lut_costs.push_back(2 << (i - lut_mode)); - } - else { - lut_file = arg; - rewrite_filename(lut_file); - if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+') - lut_file = std::string(pwd) + "/" + lut_file; - } - continue; - } - if (arg == "-luts" && argidx+1 < args.size()) { - lut_costs.clear(); - for (auto &tok : split_tokens(args[++argidx], ",")) { - auto parts = split_tokens(tok, ":"); - if (GetSize(parts) == 0 && !lut_costs.empty()) - lut_costs.push_back(lut_costs.back()); - else if (GetSize(parts) == 1) - lut_costs.push_back(atoi(parts.at(0).c_str())); - else if (GetSize(parts) == 2) - while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) - lut_costs.push_back(atoi(parts.at(1).c_str())); - else - log_cmd_error("Invalid -luts syntax.\n"); - } - continue; - } - if (arg == "-fast") { - fast_mode = true; - continue; - } - //if (arg == "-dff") { - // dff_mode = true; - // continue; - //} - //if (arg == "-clk" && argidx+1 < args.size()) { - // clk_str = args[++argidx]; - // dff_mode = true; - // continue; - //} - //if (arg == "-keepff") { - // keepff = true; - // continue; - //} - if (arg == "-nocleanup") { - cleanup = false; - continue; - } - if (arg == "-showtmp") { - show_tempdir = true; - continue; - } - if (arg == "-markgroups") { - markgroups = true; - continue; - } - if (arg == "-box" && argidx+1 < args.size()) { - box_file = args[++argidx]; - continue; - } - if (arg == "-W" && argidx+1 < args.size()) { - wire_delay = "-W " + args[++argidx]; - continue; - } - if (arg == "-nomfs") { - nomfs = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - // ABC expects a box file for XAIG - if (box_file.empty()) - box_file = "+/dummy.box"; - - rewrite_filename(box_file); - if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') - box_file = std::string(pwd) + "/" + box_file; - - dict box_lookup; - for (auto m : design->modules()) { - auto it = m->attributes.find(ID(abc9_box_id)); - if (it == m->attributes.end()) - continue; - if (m->name.begins_with("$paramod")) - continue; - auto id = it->second.as_int(); - auto r = box_lookup.insert(std::make_pair(id, m->name)); - if (!r.second) - log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", - log_id(m), id, log_id(r.first->second)); - log_assert(r.second); - - RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; - for (auto p : m->ports) { - auto w = m->wire(p); - log_assert(w); - if (w->attributes.count(ID(abc9_carry))) { - if (w->port_input) { - if (carry_in) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); - carry_in = w; - } - else if (w->port_output) { - if (carry_out) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); - carry_out = w; - } - } - } - if (carry_in || carry_out) { - if (carry_in && !carry_out) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); - if (!carry_in && carry_out) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); - // Make carry_in the last PI, and carry_out the last PO - // since ABC requires it this way - auto &ports = m->ports; - for (auto it = ports.begin(); it != ports.end(); ) { - RTLIL::Wire* w = m->wire(*it); - log_assert(w); - if (w == carry_in || w == carry_out) { - it = ports.erase(it); - continue; - } - if (w->port_id > carry_in->port_id) - --w->port_id; - if (w->port_id > carry_out->port_id) - --w->port_id; - log_assert(w->port_input || w->port_output); - log_assert(ports[w->port_id-1] == w->name); - ++it; - } - ports.push_back(carry_in->name); - carry_in->port_id = ports.size(); - ports.push_back(carry_out->name); - carry_out->port_id = ports.size(); - } - } - - for (auto mod : design->selected_modules()) - { - if (mod->attributes.count(ID(abc9_box_id))) - continue; - - if (mod->processes.size() > 0) { - log("Skipping module %s as it contains processes.\n", log_id(mod)); - continue; - } - - assign_map.set(mod); - - if (!dff_mode || !clk_str.empty()) { - abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay, box_lookup, nomfs); - continue; - } - - CellTypes ct(design); - - std::vector all_cells = mod->selected_cells(); - std::set unassigned_cells(all_cells.begin(), all_cells.end()); - - std::set expand_queue, next_expand_queue; - std::set expand_queue_up, next_expand_queue_up; - std::set expand_queue_down, next_expand_queue_down; - - typedef tuple clkdomain_t; - std::map> assigned_cells; - std::map assigned_cells_reverse; - - std::map> cell_to_bit, cell_to_bit_up, cell_to_bit_down; - std::map> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - - for (auto cell : all_cells) - { - clkdomain_t key; - - for (auto &conn : cell->connections()) - for (auto bit : conn.second) { - bit = assign_map(bit); - if (bit.wire != nullptr) { - cell_to_bit[cell].insert(bit); - bit_to_cell[bit].insert(cell); - if (ct.cell_input(cell->type, conn.first)) { - cell_to_bit_up[cell].insert(bit); - bit_to_cell_down[bit].insert(cell); - } - if (ct.cell_output(cell->type, conn.first)) { - cell_to_bit_down[cell].insert(bit); - bit_to_cell_up[bit].insert(cell); - } - } - } - - if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) - { - key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); - } - else - if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) - { - bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); - bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)); - key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E)))); - } - else - continue; - - unassigned_cells.erase(cell); - expand_queue.insert(cell); - expand_queue_up.insert(cell); - expand_queue_down.insert(cell); - - assigned_cells[key].push_back(cell); - assigned_cells_reverse[cell] = key; - } - - while (!expand_queue_up.empty() || !expand_queue_down.empty()) - { - if (!expand_queue_up.empty()) - { - RTLIL::Cell *cell = *expand_queue_up.begin(); - clkdomain_t key = assigned_cells_reverse.at(cell); - expand_queue_up.erase(cell); - - for (auto bit : cell_to_bit_up[cell]) - for (auto c : bit_to_cell_up[bit]) - if (unassigned_cells.count(c)) { - unassigned_cells.erase(c); - next_expand_queue_up.insert(c); - assigned_cells[key].push_back(c); - assigned_cells_reverse[c] = key; - expand_queue.insert(c); - } - } - - if (!expand_queue_down.empty()) - { - RTLIL::Cell *cell = *expand_queue_down.begin(); - clkdomain_t key = assigned_cells_reverse.at(cell); - expand_queue_down.erase(cell); - - for (auto bit : cell_to_bit_down[cell]) - for (auto c : bit_to_cell_down[bit]) - if (unassigned_cells.count(c)) { - unassigned_cells.erase(c); - next_expand_queue_up.insert(c); - assigned_cells[key].push_back(c); - assigned_cells_reverse[c] = key; - expand_queue.insert(c); - } - } - - if (expand_queue_up.empty() && expand_queue_down.empty()) { - expand_queue_up.swap(next_expand_queue_up); - expand_queue_down.swap(next_expand_queue_down); - } - } - - while (!expand_queue.empty()) - { - RTLIL::Cell *cell = *expand_queue.begin(); - clkdomain_t key = assigned_cells_reverse.at(cell); - expand_queue.erase(cell); - - for (auto bit : cell_to_bit.at(cell)) { - for (auto c : bit_to_cell[bit]) - if (unassigned_cells.count(c)) { - unassigned_cells.erase(c); - next_expand_queue.insert(c); - assigned_cells[key].push_back(c); - assigned_cells_reverse[c] = key; - } - bit_to_cell[bit].clear(); - } - - if (expand_queue.empty()) - expand_queue.swap(next_expand_queue); - } - - clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec()); - for (auto cell : unassigned_cells) { - assigned_cells[key].push_back(cell); - assigned_cells_reverse[cell] = key; - } - - log_header(design, "Summary of detected clock domains:\n"); - for (auto &it : assigned_cells) - log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second), - std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), - std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); - - for (auto &it : assigned_cells) { - clk_polarity = std::get<0>(it.first); - clk_sig = assign_map(std::get<1>(it.first)); - en_polarity = std::get<2>(it.first); - en_sig = assign_map(std::get<3>(it.first)); - abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", - keepff, delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay, box_lookup, nomfs); - assign_map.set(mod); - } - } - - assign_map.clear(); - - log_pop(); - } -} Abc9Pass; - -PRIVATE_NAMESPACE_END diff --git a/passes/techmap/abc9_techmap.cc b/passes/techmap/abc9_techmap.cc new file mode 100644 index 000000000..7ff68f382 --- /dev/null +++ b/passes/techmap/abc9_techmap.cc @@ -0,0 +1,1310 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +// [[CITE]] ABC +// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification +// http://www.eecs.berkeley.edu/~alanmi/abc/ + +#if 0 +// Based on &flow3 - better QoR but more experimental +#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \ + "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\ + "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\ + "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ + "&mfs; &ps -l" +#else +#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" +#endif + + +#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}" + +#include "kernel/register.h" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" +#include "kernel/cost.h" +#include "kernel/log.h" +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +# include +# include +#endif + +#include "frontends/aiger/aigerparse.h" +#include "kernel/utils.h" + +#ifdef YOSYS_LINK_ABC +extern "C" int Abc_RealMain(int argc, char *argv[]); +#endif + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +bool markgroups; +int map_autoidx; +SigMap assign_map; +RTLIL::Module *module; + +bool clk_polarity, en_polarity; +RTLIL::SigSpec clk_sig, en_sig; + +inline std::string remap_name(RTLIL::IdString abc9_name) +{ + return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); +} + +void handle_loops(RTLIL::Design *design) +{ + Pass::call(design, "scc -set_attr abc9_scc_id {}"); + + // For every unique SCC found, (arbitrarily) find the first + // cell in the component, and select (and mark) all its output + // wires + pool ids_seen; + for (auto cell : module->cells()) { + auto it = cell->attributes.find(ID(abc9_scc_id)); + if (it != cell->attributes.end()) { + auto r = ids_seen.insert(it->second); + if (r.second) { + for (auto &c : cell->connections_) { + if (c.second.is_fully_const()) continue; + if (cell->output(c.first)) { + SigBit b = c.second.as_bit(); + Wire *w = b.wire; + if (w->port_input) { + // In this case, hopefully the loop break has been already created + // Get the non-prefixed wire + Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str())); + log_assert(wo != nullptr); + log_assert(wo->port_output); + log_assert(b.offset < GetSize(wo)); + c.second = RTLIL::SigBit(wo, b.offset); + } + else { + // Create a new output/input loop break + w->port_input = true; + w = module->wire(stringf("%s.abco", w->name.c_str())); + if (!w) { + w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire)); + w->port_output = true; + } + else { + log_assert(w->port_input); + log_assert(b.offset < GetSize(w)); + } + w->set_bool_attribute(ID(abc9_scc_break)); + c.second = RTLIL::SigBit(w, b.offset); + } + } + } + } + cell->attributes.erase(it); + } + } + + module->fixup_ports(); +} + +std::string add_echos_to_abc9_cmd(std::string str) +{ + std::string new_str, token; + for (size_t i = 0; i < str.size(); i++) { + token += str[i]; + if (str[i] == ';') { + while (i+1 < str.size() && str[i+1] == ' ') + i++; + new_str += "echo + " + token + " " + token + " "; + token.clear(); + } + } + + if (!token.empty()) { + if (!new_str.empty()) + new_str += "echo + " + token + "; "; + new_str += token; + } + + return new_str; +} + +std::string fold_abc9_cmd(std::string str) +{ + std::string token, new_str = " "; + int char_counter = 10; + + for (size_t i = 0; i <= str.size(); i++) { + if (i < str.size()) + token += str[i]; + if (i == str.size() || str[i] == ';') { + if (char_counter + token.size() > 75) + new_str += "\n ", char_counter = 14; + new_str += token, char_counter += token.size(); + token.clear(); + } + } + + return new_str; +} + +std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir) +{ + if (show_tempdir) + return text; + + while (1) { + size_t pos = text.find(tempdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "" + text.substr(pos + GetSize(tempdir_name)); + } + + std::string selfdir_name = proc_self_dirname(); + if (selfdir_name != "/") { + while (1) { + size_t pos = text.find(selfdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "/" + text.substr(pos + GetSize(selfdir_name)); + } + } + + return text; +} + +struct abc9_output_filter +{ + bool got_cr; + int escape_seq_state; + std::string linebuf; + std::string tempdir_name; + bool show_tempdir; + + abc9_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) + { + got_cr = false; + escape_seq_state = 0; + } + + void next_char(char ch) + { + if (escape_seq_state == 0 && ch == '\033') { + escape_seq_state = 1; + return; + } + if (escape_seq_state == 1) { + escape_seq_state = ch == '[' ? 2 : 0; + return; + } + if (escape_seq_state == 2) { + if ((ch < '0' || '9' < ch) && ch != ';') + escape_seq_state = 0; + return; + } + escape_seq_state = 0; + if (ch == '\r') { + got_cr = true; + return; + } + if (ch == '\n') { + log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str()); + got_cr = false, linebuf.clear(); + return; + } + if (got_cr) + got_cr = false, linebuf.clear(); + linebuf += ch; + } + + void next_line(const std::string &line) + { + //int pi, po; + //if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { + // log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", + // pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", + // po, po_map.count(po) ? po_map.at(po).c_str() : "???"); + // return; + //} + + for (char ch : line) + next_char(ch); + } +}; + +void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, + bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, + bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, + bool show_tempdir, std::string box_file, std::string lut_file, + std::string wire_delay, const dict &box_lookup, bool nomfs +) +{ + module = current_module; + map_autoidx = autoidx++; + + if (clk_str != "$") + { + clk_polarity = true; + clk_sig = RTLIL::SigSpec(); + + en_polarity = true; + en_sig = RTLIL::SigSpec(); + } + + if (!clk_str.empty() && clk_str != "$") + { + if (clk_str.find(',') != std::string::npos) { + int pos = clk_str.find(','); + std::string en_str = clk_str.substr(pos+1); + clk_str = clk_str.substr(0, pos); + if (en_str[0] == '!') { + en_polarity = false; + en_str = en_str.substr(1); + } + if (module->wires_.count(RTLIL::escape_id(en_str)) != 0) + en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0)); + } + if (clk_str[0] == '!') { + clk_polarity = false; + clk_str = clk_str.substr(1); + } + if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0) + clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); + } + + if (dff_mode && clk_sig.empty()) + log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); + + std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; + if (!cleanup) + tempdir_name[0] = tempdir_name[4] = '_'; + tempdir_name = make_temp_dir(tempdir_name); + log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", + module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); + + std::string abc9_script; + + if (!lut_costs.empty()) { + abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); + if (!box_file.empty()) + abc9_script += stringf("read_box -v %s; ", box_file.c_str()); + } + else + if (!lut_file.empty()) { + abc9_script += stringf("read_lut %s; ", lut_file.c_str()); + if (!box_file.empty()) + abc9_script += stringf("read_box -v %s; ", box_file.c_str()); + } + else + log_abort(); + + abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); + + if (!script_file.empty()) { + if (script_file[0] == '+') { + for (size_t i = 1; i < script_file.size(); i++) + if (script_file[i] == '\'') + abc9_script += "'\\''"; + else if (script_file[i] == ',') + abc9_script += " "; + else + abc9_script += script_file[i]; + } else + abc9_script += stringf("source %s", script_file.c_str()); + } else if (!lut_costs.empty() || !lut_file.empty()) { + //bool all_luts_cost_same = true; + //for (int this_cost : lut_costs) + // if (this_cost != lut_costs.front()) + // all_luts_cost_same = false; + abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; + //if (all_luts_cost_same && !fast_mode) + // abc9_script += "; lutpack {S}"; + } else + log_abort(); + + //if (script_file.empty() && !delay_target.empty()) + // for (size_t pos = abc9_script.find("dretime;"); pos != std::string::npos; pos = abc9_script.find("dretime;", pos+1)) + // abc9_script = abc9_script.substr(0, pos) + "dretime; retime -o {D};" + abc9_script.substr(pos+8); + + for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) + abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); + + //for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos)) + // abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3); + + for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos)) + abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3); + + if (nomfs) + for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) + abc9_script = abc9_script.erase(pos, strlen("&mfs")); + + abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str()); + abc9_script = add_echos_to_abc9_cmd(abc9_script); + + for (size_t i = 0; i+1 < abc9_script.size(); i++) + if (abc9_script[i] == ';' && abc9_script[i+1] == ' ') + abc9_script[i+1] = '\n'; + + FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); + fprintf(f, "%s\n", abc9_script.c_str()); + fclose(f); + + if (dff_mode || !clk_str.empty()) + { + if (clk_sig.size() == 0) + log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); + else { + log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig)); + if (en_sig.size() != 0) + log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig)); + log("\n"); + } + } + + bool count_output = false; + for (auto port_name : module->ports) { + RTLIL::Wire *port_wire = module->wire(port_name); + log_assert(port_wire); + if (port_wire->port_output) { + count_output = true; + break; + } + } + + log_push(); + + if (count_output) + { + design->selection_stack.emplace_back(false); + RTLIL::Selection& sel = design->selection_stack.back(); + sel.select(module); + + handle_loops(design); + + Pass::call(design, "aigmap"); + + //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n", + // count_gates, GetSize(signal_list), count_input, count_output); + + Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); + + std::string buffer; + std::ifstream ifs; +#if 0 + buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig"); + ifs.open(buffer); + if (ifs.fail()) + log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); + buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); + log_assert(!design->module(ID($__abc9__))); + { + AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); + reader.parse_xaiger(); + } + ifs.close(); + Pass::call(design, stringf("write_verilog -noexpr -norename")); + design->remove(design->module(ID($__abc9__))); +#endif + + design->selection_stack.pop_back(); + + log_header(design, "Executing ABC9_MAP.\n"); + + if (!lut_costs.empty()) { + buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); + f = fopen(buffer.c_str(), "wt"); + if (f == NULL) + log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); + for (int i = 0; i < GetSize(lut_costs); i++) + fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); + fclose(f); + } + + buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); + log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); + +#ifndef YOSYS_LINK_ABC + abc9_output_filter filt(tempdir_name, show_tempdir); + int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1)); +#else + // These needs to be mutable, supposedly due to getopt + char *abc9_argv[5]; + string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); + abc9_argv[0] = strdup(exe_file.c_str()); + abc9_argv[1] = strdup("-s"); + abc9_argv[2] = strdup("-f"); + abc9_argv[3] = strdup(tmp_script_name.c_str()); + abc9_argv[4] = 0; + int ret = Abc_RealMain(4, abc9_argv); + free(abc9_argv[0]); + free(abc9_argv[1]); + free(abc9_argv[2]); + free(abc9_argv[3]); +#endif + if (ret != 0) + log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); + + buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig"); + ifs.open(buffer, std::ifstream::binary); + if (ifs.fail()) + log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); + + buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); + log_assert(!design->module(ID($__abc9__))); + + AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); + reader.parse_xaiger(box_lookup); + ifs.close(); + +#if 0 + Pass::call(design, stringf("write_verilog -noexpr -norename")); +#endif + + log_header(design, "Re-integrating ABC9 results.\n"); + RTLIL::Module *mapped_mod = design->module(ID($__abc9__)); + if (mapped_mod == NULL) + log_error("ABC output file does not contain a module `$__abc9__'.\n"); + + pool output_bits; + for (auto &it : mapped_mod->wires_) { + RTLIL::Wire *w = it.second; + RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w)); + if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx; + if (w->port_output) { + RTLIL::Wire *wire = module->wire(w->name); + log_assert(wire); + for (int i = 0; i < GetSize(w); i++) + output_bits.insert({wire, i}); + } + } + + for (auto &it : module->connections_) { + auto &signal = it.first; + auto bits = signal.bits(); + for (auto &b : bits) + if (output_bits.count(b)) + b = module->addWire(NEW_ID); + signal = std::move(bits); + } + + dict abc9_box; + vector boxes; + for (const auto &it : module->cells_) { + auto cell = it.second; + if (cell->type.in(ID($_AND_), ID($_NOT_))) { + module->remove(cell); + continue; + } + auto jt = abc9_box.find(cell->type); + if (jt == abc9_box.end()) { + RTLIL::Module* box_module = design->module(cell->type); + jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first; + } + if (jt->second) + boxes.emplace_back(cell); + } + + dict> bit_drivers, bit_users; + TopoSort toposort; + dict not2drivers; + dict> bit2sinks; + + std::map cell_stats; + for (auto c : mapped_mod->cells()) + { + toposort.node(c->name); + + RTLIL::Cell *cell = nullptr; + if (c->type == ID($_NOT_)) { + RTLIL::SigBit a_bit = c->getPort(ID::A); + RTLIL::SigBit y_bit = c->getPort(ID::Y); + bit_users[a_bit].insert(c->name); + bit_drivers[y_bit].insert(c->name); + + if (!a_bit.wire) { + c->setPort(ID::Y, module->addWire(NEW_ID)); + RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); + log_assert(wire); + module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); + } + else if (!lut_costs.empty() || !lut_file.empty()) { + RTLIL::Cell* driver_lut = nullptr; + // ABC can return NOT gates that drive POs + if (!a_bit.wire->port_input) { + // If it's not a NOT gate that that comes from a PI directly, + // find the driver LUT and clone that to guarantee that we won't + // increase the max logic depth + // (TODO: Optimise by not cloning unless will increase depth) + RTLIL::IdString driver_name; + if (GetSize(a_bit.wire) == 1) + driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); + else + driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); + driver_lut = mapped_mod->cell(driver_name); + } + + if (!driver_lut) { + // If a driver couldn't be found (could be from PI or box CI) + // then implement using a LUT + cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), + RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), + RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), + RTLIL::Const::from_string("01")); + bit2sinks[cell->getPort(ID::A)].push_back(cell); + cell_stats[ID($lut)]++; + } + else + not2drivers[c] = driver_lut; + continue; + } + else + log_abort(); + if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + continue; + } + cell_stats[c->type]++; + + RTLIL::Cell *existing_cell = nullptr; + if (c->type == ID($lut)) { + if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { + SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name)); + SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name)); + module->connect(my_y, my_a); + if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; + log_abort(); + continue; + } + cell = module->addCell(remap_name(c->name), c->type); + } + else { + existing_cell = module->cell(c->name); + log_assert(existing_cell); + cell = module->addCell(remap_name(c->name), c->type); + } + + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + if (existing_cell) { + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + } + else { + cell->parameters = c->parameters; + cell->attributes = c->attributes; + } + for (auto &conn : c->connections()) { + RTLIL::SigSpec newsig; + for (auto c : conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + cell->setPort(conn.first, newsig); + + if (cell->input(conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : conn.second) + bit_users[i].insert(c->name); + } + if (cell->output(conn.first)) + for (auto i : conn.second) + bit_drivers[i].insert(c->name); + } + } + + for (auto existing_cell : boxes) { + Cell *cell = module->cell(remap_name(existing_cell->name)); + if (cell) { + for (auto &conn : existing_cell->connections()) { + if (!conn.second.is_wire()) + continue; + Wire *wire = conn.second.as_wire(); + if (!wire->get_bool_attribute(ID(abc9_padding))) + continue; + cell->unsetPort(conn.first); + log_debug("Dropping padded port connection for %s (%s) .%s (%s )\n", log_id(cell), cell->type.c_str(), log_id(conn.first), log_signal(conn.second)); + } + module->swap_names(cell, existing_cell); + } + module->remove(existing_cell); + } + + // Copy connections (and rename) from mapped_mod to module + for (auto conn : mapped_mod->connections()) { + if (!conn.first.is_fully_const()) { + auto chunks = conn.first.chunks(); + for (auto &c : chunks) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.first = std::move(chunks); + } + if (!conn.second.is_fully_const()) { + auto chunks = conn.second.chunks(); + for (auto &c : chunks) + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.second = std::move(chunks); + } + module->connect(conn); + } + + for (auto &it : cell_stats) + log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); + int in_wires = 0, out_wires = 0; + + // Stitch in mapped_mod's inputs/outputs into module + for (auto port : mapped_mod->ports) { + RTLIL::Wire *w = mapped_mod->wire(port); + RTLIL::Wire *wire = module->wire(port); + log_assert(wire); + RTLIL::Wire *remap_wire = module->wire(remap_name(port)); + RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); + log_assert(GetSize(signal) >= GetSize(remap_wire)); + + RTLIL::SigSig conn; + if (w->port_output) { + conn.first = signal; + conn.second = remap_wire; + out_wires++; + module->connect(conn); + } + else if (w->port_input) { + conn.first = remap_wire; + conn.second = signal; + in_wires++; + module->connect(conn); + } + } + + for (auto &it : bit_users) + if (bit_drivers.count(it.first)) + for (auto driver_cell : bit_drivers.at(it.first)) + for (auto user_cell : it.second) + toposort.edge(driver_cell, user_cell); + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); + log_assert(no_loops); + + for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { + RTLIL::Cell *not_cell = mapped_mod->cell(*ii); + log_assert(not_cell); + if (not_cell->type != ID($_NOT_)) + continue; + auto it = not2drivers.find(not_cell); + if (it == not2drivers.end()) + continue; + RTLIL::Cell *driver_lut = it->second; + RTLIL::SigBit a_bit = not_cell->getPort(ID::A); + RTLIL::SigBit y_bit = not_cell->getPort(ID::Y); + RTLIL::Const driver_mask; + + a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name)); + y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name)); + + auto jt = bit2sinks.find(a_bit); + if (jt == bit2sinks.end()) + goto clone_lut; + + for (auto sink_cell : jt->second) + if (sink_cell->type != ID($lut)) + goto clone_lut; + + // Push downstream LUTs past inverter + for (auto sink_cell : jt->second) { + SigSpec A = sink_cell->getPort(ID::A); + RTLIL::Const mask = sink_cell->getParam(ID(LUT)); + int index = 0; + for (; index < GetSize(A); index++) + if (A[index] == a_bit) + break; + log_assert(index < GetSize(A)); + int i = 0; + while (i < GetSize(mask)) { + for (int j = 0; j < (1 << index); j++) + std::swap(mask[i+j], mask[i+j+(1 << index)]); + i += 1 << (index+1); + } + A[index] = y_bit; + sink_cell->setPort(ID::A, A); + sink_cell->setParam(ID(LUT), mask); + } + + // Since we have rewritten all sinks (which we know + // to be only LUTs) to be after the inverter, we can + // go ahead and clone the LUT with the expectation + // that the original driving LUT will become dangling + // and get cleaned away +clone_lut: + driver_mask = driver_lut->getParam(ID(LUT)); + for (auto &b : driver_mask.bits) { + if (b == RTLIL::State::S0) b = RTLIL::State::S1; + else if (b == RTLIL::State::S1) b = RTLIL::State::S0; + } + auto cell = module->addLut(NEW_ID, + driver_lut->getPort(ID::A), + y_bit, + driver_mask); + for (auto &bit : cell->connections_.at(ID::A)) { + bit.wire = module->wires_.at(remap_name(bit.wire->name)); + bit2sinks[bit].push_back(cell); + } + } + + // Now 'unexpose' those wires by undoing + // the expose operation -- remove them from PO/PI + // and re-connecting them back together + for (auto wire : module->wires()) { + auto it = wire->attributes.find(ID(abc9_scc_break)); + if (it != wire->attributes.end()) { + wire->attributes.erase(it); + log_assert(wire->port_output); + wire->port_output = false; + std::string name = wire->name.str(); + RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5)); + log_assert(i_wire); + log_assert(i_wire->port_input); + i_wire->port_input = false; + module->connect(i_wire, wire); + } + } + module->fixup_ports(); + + //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); + log("ABC RESULTS: input signals: %8d\n", in_wires); + log("ABC RESULTS: output signals: %8d\n", out_wires); + + design->remove(mapped_mod); + } + else + { + log("Don't call ABC as there is nothing to map.\n"); + } + + if (cleanup) + { + log("Removing temp directory.\n"); + remove_directory(tempdir_name); + } + + log_pop(); +} + +struct Abc9TechmapPass : public Pass { + Abc9TechmapPass() : Pass("abc9_map", "use ABC9 for technology mapping") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" abc9_map [options] [selection]\n"); + log("\n"); + log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); + log("library to a target architecture.\n"); + log("\n"); + log(" -exe \n"); +#ifdef ABCEXTERNAL + log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); +#else + log(" use the specified command instead of \"/yosys-abc\" to execute ABC.\n"); +#endif + log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n"); + log("\n"); + log(" -script \n"); + log(" use the specified ABC script file instead of the default script.\n"); + log("\n"); + log(" if starts with a plus sign (+), then the rest of the filename\n"); + log(" string is interpreted as the command string to be passed to ABC. The\n"); + log(" leading plus sign is removed and all commas (,) in the string are\n"); + log(" replaced with blanks before the string is passed to ABC.\n"); + log("\n"); + log(" if no -script parameter is given, the following scripts are used:\n"); + log("\n"); + log(" for -lut/-luts (only one LUT size):\n"); + log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); + log("\n"); + log(" for -lut/-luts (different LUT sizes):\n"); + log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); + log("\n"); + log(" -fast\n"); + log(" use different default scripts that are slightly faster (at the cost\n"); + log(" of output quality):\n"); + log("\n"); + log(" for -lut/-luts:\n"); + log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); + log("\n"); + log(" -D \n"); + log(" set delay target. the string {D} in the default scripts above is\n"); + log(" replaced by this option when used, and an empty string otherwise\n"); + log(" (indicating best possible delay).\n"); +// log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n"); +// log(" default scripts above.\n"); + log("\n"); +// log(" -S \n"); +// log(" maximum number of LUT inputs shared.\n"); +// log(" (replaces {S} in the default scripts above, default: -S 1)\n"); +// log("\n"); + log(" -lut \n"); + log(" generate netlist using luts of (max) the specified width.\n"); + log("\n"); + log(" -lut :\n"); + log(" generate netlist using luts of (max) the specified width . All\n"); + log(" luts with width <= have constant cost. for luts larger than \n"); + log(" the area cost doubles with each additional input bit. the delay cost\n"); + log(" is still constant for all lut widths.\n"); + log("\n"); + log(" -lut \n"); + log(" pass this file with lut library to ABC.\n"); + log("\n"); + log(" -luts ,,,:,..\n"); + log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); + log(" 2, 3, .. inputs.\n"); + log("\n"); +// log(" -dff\n"); +// log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n"); +// log(" clock domains are automatically partitioned in clock domains and each\n"); +// log(" domain is passed through ABC independently.\n"); +// log("\n"); +// log(" -clk [!][,[!]]\n"); +// log(" use only the specified clock domain. this is like -dff, but only FF\n"); +// log(" cells that belong to the specified clock domain are used.\n"); +// log("\n"); +// log(" -keepff\n"); +// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n"); +// log(" them, for example for equivalence checking.)\n"); +// log("\n"); + log(" -nocleanup\n"); + log(" when this option is used, the temporary files created by this pass\n"); + log(" are not removed. this is useful for debugging.\n"); + log("\n"); + log(" -showtmp\n"); + log(" print the temp dir name in log. usually this is suppressed so that the\n"); + log(" command output is identical across runs.\n"); + log("\n"); + log(" -markgroups\n"); + log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n"); + log(" this attribute is a unique integer for each ABC process started. This\n"); + log(" is useful for debugging the partitioning of clock domains.\n"); + log("\n"); + log(" -box \n"); + log(" pass this file with box library to ABC. Use with -lut.\n"); + log("\n"); + log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); + log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); + log("ABC on logic snippets extracted from your design. You will not get any useful\n"); + log("output when passing an ABC script that writes a file. Instead write your full\n"); + log("design as BLIF file with write_blif and then load that into ABC externally if\n"); + log("you want to use ABC to convert your design into another format.\n"); + log("\n"); + log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n"); + log_push(); + + assign_map.clear(); + +#ifdef ABCEXTERNAL + std::string exe_file = ABCEXTERNAL; +#else + std::string exe_file = proc_self_dirname() + "yosys-abc"; +#endif + std::string script_file, clk_str, box_file, lut_file; + std::string delay_target, lutin_shared = "-S 1", wire_delay; + bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; + bool show_tempdir = false; + bool nomfs = false; + vector lut_costs; + markgroups = false; + +#if 0 + cleanup = false; + show_tempdir = true; +#endif + +#ifdef _WIN32 +#ifndef ABCEXTERNAL + if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) + exe_file = proc_self_dirname() + "..\\yosys-abc"; +#endif +#endif + + size_t argidx; + char pwd [PATH_MAX]; + if (!getcwd(pwd, sizeof(pwd))) { + log_cmd_error("getcwd failed: %s\n", strerror(errno)); + log_abort(); + } + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-exe" && argidx+1 < args.size()) { + exe_file = args[++argidx]; + continue; + } + if (arg == "-script" && argidx+1 < args.size()) { + script_file = args[++argidx]; + rewrite_filename(script_file); + if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') + script_file = std::string(pwd) + "/" + script_file; + continue; + } + if (arg == "-D" && argidx+1 < args.size()) { + delay_target = "-D " + args[++argidx]; + continue; + } + //if (arg == "-S" && argidx+1 < args.size()) { + // lutin_shared = "-S " + args[++argidx]; + // continue; + //} + if (arg == "-lut" && argidx+1 < args.size()) { + string arg = args[++argidx]; + if (arg.find_first_not_of("0123456789:") == std::string::npos) { + size_t pos = arg.find_first_of(':'); + int lut_mode = 0, lut_mode2 = 0; + if (pos != string::npos) { + lut_mode = atoi(arg.substr(0, pos).c_str()); + lut_mode2 = atoi(arg.substr(pos+1).c_str()); + } else { + lut_mode = atoi(arg.c_str()); + lut_mode2 = lut_mode; + } + lut_costs.clear(); + for (int i = 0; i < lut_mode; i++) + lut_costs.push_back(1); + for (int i = lut_mode; i < lut_mode2; i++) + lut_costs.push_back(2 << (i - lut_mode)); + } + else { + lut_file = arg; + rewrite_filename(lut_file); + if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+') + lut_file = std::string(pwd) + "/" + lut_file; + } + continue; + } + if (arg == "-luts" && argidx+1 < args.size()) { + lut_costs.clear(); + for (auto &tok : split_tokens(args[++argidx], ",")) { + auto parts = split_tokens(tok, ":"); + if (GetSize(parts) == 0 && !lut_costs.empty()) + lut_costs.push_back(lut_costs.back()); + else if (GetSize(parts) == 1) + lut_costs.push_back(atoi(parts.at(0).c_str())); + else if (GetSize(parts) == 2) + while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) + lut_costs.push_back(atoi(parts.at(1).c_str())); + else + log_cmd_error("Invalid -luts syntax.\n"); + } + continue; + } + if (arg == "-fast") { + fast_mode = true; + continue; + } + //if (arg == "-dff") { + // dff_mode = true; + // continue; + //} + //if (arg == "-clk" && argidx+1 < args.size()) { + // clk_str = args[++argidx]; + // dff_mode = true; + // continue; + //} + //if (arg == "-keepff") { + // keepff = true; + // continue; + //} + if (arg == "-nocleanup") { + cleanup = false; + continue; + } + if (arg == "-showtmp") { + show_tempdir = true; + continue; + } + if (arg == "-markgroups") { + markgroups = true; + continue; + } + if (arg == "-box" && argidx+1 < args.size()) { + box_file = args[++argidx]; + continue; + } + if (arg == "-W" && argidx+1 < args.size()) { + wire_delay = "-W " + args[++argidx]; + continue; + } + if (arg == "-nomfs") { + nomfs = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + // ABC expects a box file for XAIG + if (box_file.empty()) + box_file = "+/dummy.box"; + + rewrite_filename(box_file); + if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') + box_file = std::string(pwd) + "/" + box_file; + + dict box_lookup; + for (auto m : design->modules()) { + auto it = m->attributes.find(ID(abc9_box_id)); + if (it == m->attributes.end()) + continue; + if (m->name.begins_with("$paramod")) + continue; + auto id = it->second.as_int(); + auto r = box_lookup.insert(std::make_pair(id, m->name)); + if (!r.second) + log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", + log_id(m), id, log_id(r.first->second)); + log_assert(r.second); + + RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; + for (auto p : m->ports) { + auto w = m->wire(p); + log_assert(w); + if (w->attributes.count(ID(abc9_carry))) { + if (w->port_input) { + if (carry_in) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); + carry_in = w; + } + else if (w->port_output) { + if (carry_out) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); + carry_out = w; + } + } + } + if (carry_in || carry_out) { + if (carry_in && !carry_out) + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); + if (!carry_in && carry_out) + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); + // Make carry_in the last PI, and carry_out the last PO + // since ABC requires it this way + auto &ports = m->ports; + for (auto it = ports.begin(); it != ports.end(); ) { + RTLIL::Wire* w = m->wire(*it); + log_assert(w); + if (w == carry_in || w == carry_out) { + it = ports.erase(it); + continue; + } + if (w->port_id > carry_in->port_id) + --w->port_id; + if (w->port_id > carry_out->port_id) + --w->port_id; + log_assert(w->port_input || w->port_output); + log_assert(ports[w->port_id-1] == w->name); + ++it; + } + ports.push_back(carry_in->name); + carry_in->port_id = ports.size(); + ports.push_back(carry_out->name); + carry_out->port_id = ports.size(); + } + } + + for (auto mod : design->selected_modules()) + { + if (mod->attributes.count(ID(abc9_box_id))) + continue; + + if (mod->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(mod)); + continue; + } + + assign_map.set(mod); + + if (!dff_mode || !clk_str.empty()) { + abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, + delay_target, lutin_shared, fast_mode, show_tempdir, + box_file, lut_file, wire_delay, box_lookup, nomfs); + continue; + } + + CellTypes ct(design); + + std::vector all_cells = mod->selected_cells(); + std::set unassigned_cells(all_cells.begin(), all_cells.end()); + + std::set expand_queue, next_expand_queue; + std::set expand_queue_up, next_expand_queue_up; + std::set expand_queue_down, next_expand_queue_down; + + typedef tuple clkdomain_t; + std::map> assigned_cells; + std::map assigned_cells_reverse; + + std::map> cell_to_bit, cell_to_bit_up, cell_to_bit_down; + std::map> bit_to_cell, bit_to_cell_up, bit_to_cell_down; + + for (auto cell : all_cells) + { + clkdomain_t key; + + for (auto &conn : cell->connections()) + for (auto bit : conn.second) { + bit = assign_map(bit); + if (bit.wire != nullptr) { + cell_to_bit[cell].insert(bit); + bit_to_cell[bit].insert(cell); + if (ct.cell_input(cell->type, conn.first)) { + cell_to_bit_up[cell].insert(bit); + bit_to_cell_down[bit].insert(cell); + } + if (ct.cell_output(cell->type, conn.first)) { + cell_to_bit_down[cell].insert(bit); + bit_to_cell_up[bit].insert(cell); + } + } + } + + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) + { + key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); + } + else + if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + { + bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); + bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)); + key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E)))); + } + else + continue; + + unassigned_cells.erase(cell); + expand_queue.insert(cell); + expand_queue_up.insert(cell); + expand_queue_down.insert(cell); + + assigned_cells[key].push_back(cell); + assigned_cells_reverse[cell] = key; + } + + while (!expand_queue_up.empty() || !expand_queue_down.empty()) + { + if (!expand_queue_up.empty()) + { + RTLIL::Cell *cell = *expand_queue_up.begin(); + clkdomain_t key = assigned_cells_reverse.at(cell); + expand_queue_up.erase(cell); + + for (auto bit : cell_to_bit_up[cell]) + for (auto c : bit_to_cell_up[bit]) + if (unassigned_cells.count(c)) { + unassigned_cells.erase(c); + next_expand_queue_up.insert(c); + assigned_cells[key].push_back(c); + assigned_cells_reverse[c] = key; + expand_queue.insert(c); + } + } + + if (!expand_queue_down.empty()) + { + RTLIL::Cell *cell = *expand_queue_down.begin(); + clkdomain_t key = assigned_cells_reverse.at(cell); + expand_queue_down.erase(cell); + + for (auto bit : cell_to_bit_down[cell]) + for (auto c : bit_to_cell_down[bit]) + if (unassigned_cells.count(c)) { + unassigned_cells.erase(c); + next_expand_queue_up.insert(c); + assigned_cells[key].push_back(c); + assigned_cells_reverse[c] = key; + expand_queue.insert(c); + } + } + + if (expand_queue_up.empty() && expand_queue_down.empty()) { + expand_queue_up.swap(next_expand_queue_up); + expand_queue_down.swap(next_expand_queue_down); + } + } + + while (!expand_queue.empty()) + { + RTLIL::Cell *cell = *expand_queue.begin(); + clkdomain_t key = assigned_cells_reverse.at(cell); + expand_queue.erase(cell); + + for (auto bit : cell_to_bit.at(cell)) { + for (auto c : bit_to_cell[bit]) + if (unassigned_cells.count(c)) { + unassigned_cells.erase(c); + next_expand_queue.insert(c); + assigned_cells[key].push_back(c); + assigned_cells_reverse[c] = key; + } + bit_to_cell[bit].clear(); + } + + if (expand_queue.empty()) + expand_queue.swap(next_expand_queue); + } + + clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec()); + for (auto cell : unassigned_cells) { + assigned_cells[key].push_back(cell); + assigned_cells_reverse[cell] = key; + } + + log_header(design, "Summary of detected clock domains:\n"); + for (auto &it : assigned_cells) + log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second), + std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), + std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); + + for (auto &it : assigned_cells) { + clk_polarity = std::get<0>(it.first); + clk_sig = assign_map(std::get<1>(it.first)); + en_polarity = std::get<2>(it.first); + en_sig = assign_map(std::get<3>(it.first)); + abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", + keepff, delay_target, lutin_shared, fast_mode, show_tempdir, + box_file, lut_file, wire_delay, box_lookup, nomfs); + assign_map.set(mod); + } + } + + assign_map.clear(); + + log_pop(); + } +} Abc9TechmapPass; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3 From f348ffa44d4ec00537499ffe79ce627beeeefe85 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 28 Dec 2019 05:07:46 -0800 Subject: abc9_techmap -> _map; called from abc9 script pass along with abc9_ops --- passes/techmap/Makefile.inc | 3 +- passes/techmap/abc9.cc | 231 +++++++ passes/techmap/abc9_map.cc | 1215 +++++++++++++++++++++++++++++++++++++ passes/techmap/abc9_ops.cc | 139 +++++ passes/techmap/abc9_techmap.cc | 1310 ---------------------------------------- 5 files changed, 1587 insertions(+), 1311 deletions(-) create mode 100644 passes/techmap/abc9.cc create mode 100644 passes/techmap/abc9_map.cc create mode 100644 passes/techmap/abc9_ops.cc delete mode 100644 passes/techmap/abc9_techmap.cc (limited to 'passes/techmap') diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index a7c8d8c2b..734d6c10f 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -8,7 +8,8 @@ OBJS += passes/techmap/libparse.o ifeq ($(ENABLE_ABC),1) OBJS += passes/techmap/abc.o OBJS += passes/techmap/abc9.o -OBJS += passes/techmap/abc9_techmap.o +OBJS += passes/techmap/abc9_map.o +OBJS += passes/techmap/abc9_ops.o ifneq ($(ABCEXTERNAL),) passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc new file mode 100644 index 000000000..e1cf188ce --- /dev/null +++ b/passes/techmap/abc9.cc @@ -0,0 +1,231 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * (C) 2019 Eddie Hung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/register.h" +#include "kernel/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +#define XC7_WIRE_DELAY 300 // Number with which ABC will map a 6-input gate + // to one LUT6 (instead of a LUT5 + LUT2) + +struct Abc9Pass : public ScriptPass +{ + Abc9Pass() : ScriptPass("abc9", "use ABC9 for technology mapping") { } + + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" abc9 [options] [selection]\n"); + log("\n"); + log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); + log("library to a target architecture.\n"); + log("\n"); + log(" -exe \n"); +#ifdef ABCEXTERNAL + log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); +#else + log(" use the specified command instead of \"/yosys-abc\" to execute ABC.\n"); +#endif + log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n"); + log("\n"); + log(" -script \n"); + log(" use the specified ABC script file instead of the default script.\n"); + log("\n"); + log(" if starts with a plus sign (+), then the rest of the filename\n"); + log(" string is interpreted as the command string to be passed to ABC. The\n"); + log(" leading plus sign is removed and all commas (,) in the string are\n"); + log(" replaced with blanks before the string is passed to ABC.\n"); + log("\n"); + log(" if no -script parameter is given, the following scripts are used:\n"); + log("\n"); + log(" for -lut/-luts (only one LUT size):\n"); + // FIXME + //log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); + log("\n"); + log(" for -lut/-luts (different LUT sizes):\n"); + // FIXME + //log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); + log("\n"); + log(" -fast\n"); + log(" use different default scripts that are slightly faster (at the cost\n"); + log(" of output quality):\n"); + log("\n"); + log(" for -lut/-luts:\n"); + // FIXME + //log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); + log("\n"); + log(" -D \n"); + log(" set delay target. the string {D} in the default scripts above is\n"); + log(" replaced by this option when used, and an empty string otherwise\n"); + log(" (indicating best possible delay).\n"); +// log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n"); +// log(" default scripts above.\n"); + log("\n"); +// log(" -S \n"); +// log(" maximum number of LUT inputs shared.\n"); +// log(" (replaces {S} in the default scripts above, default: -S 1)\n"); +// log("\n"); + log(" -lut \n"); + log(" generate netlist using luts of (max) the specified width.\n"); + log("\n"); + log(" -lut :\n"); + log(" generate netlist using luts of (max) the specified width . All\n"); + log(" luts with width <= have constant cost. for luts larger than \n"); + log(" the area cost doubles with each additional input bit. the delay cost\n"); + log(" is still constant for all lut widths.\n"); + log("\n"); + log(" -lut \n"); + log(" pass this file with lut library to ABC.\n"); + log("\n"); + log(" -luts ,,,:,..\n"); + log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); + log(" 2, 3, .. inputs.\n"); + log("\n"); +// log(" -dff\n"); +// log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n"); +// log(" clock domains are automatically partitioned in clock domains and each\n"); +// log(" domain is passed through ABC independently.\n"); +// log("\n"); +// log(" -clk [!][,[!]]\n"); +// log(" use only the specified clock domain. this is like -dff, but only FF\n"); +// log(" cells that belong to the specified clock domain are used.\n"); +// log("\n"); +// log(" -keepff\n"); +// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n"); +// log(" them, for example for equivalence checking.)\n"); +// log("\n"); + log(" -nocleanup\n"); + log(" when this option is used, the temporary files created by this pass\n"); + log(" are not removed. this is useful for debugging.\n"); + log("\n"); + log(" -showtmp\n"); + log(" print the temp dir name in log. usually this is suppressed so that the\n"); + log(" command output is identical across runs.\n"); + log("\n"); + log(" -markgroups\n"); + log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n"); + log(" this attribute is a unique integer for each ABC process started. This\n"); + log(" is useful for debugging the partitioning of clock domains.\n"); + log("\n"); + log(" -box \n"); + log(" pass this file with box library to ABC. Use with -lut.\n"); + log("\n"); + log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); + log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); + log("ABC on logic snippets extracted from your design. You will not get any useful\n"); + log("output when passing an ABC script that writes a file. Instead write your full\n"); + log("design as BLIF file with write_blif and then load that into ABC externally if\n"); + log("you want to use ABC to convert your design into another format.\n"); + log("\n"); + log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); + log("\n"); + help_script(); + log("\n"); + } + + std::stringstream map_cmd; + bool cleanup; + + void clear_flags() YS_OVERRIDE + { + map_cmd.str(""); + map_cmd << "abc9_map"; + cleanup = true; + } + + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + std::string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if ((arg == "-exe" || arg == "-script" || arg == "-D" || + /* arg == "-S" || */ arg == "-lut" || arg == "-luts" || + arg == "-clk" || arg == "-box" || arg == "-W") && + argidx+1 < args.size()) { + map_cmd << " " << arg << " " << args[++argidx]; + continue; + } + if (arg == "-fast" || /*arg == "-dff" ||*/ arg == "-keepff" + /*|| arg == "-nocleanup"*/ || arg == "-showtmp" || arg == "-markgroups" + || arg == "-nomfs") { + map_cmd << " " << arg; + continue; + } + if (arg == "-nocleanup") { + cleanup = false; + continue; + } + break; + } + extra_args(args, argidx, design); + + log_header(design, "Executing ABC9 pass.\n"); + + run_script(design, run_from, run_to); + } + + void script() YS_OVERRIDE + { + auto selected_modules = active_design->selected_modules(); + active_design->selection_stack.emplace_back(false); + + for (auto mod : selected_modules) { + log_push(); + + active_design->selection().select(mod); + + std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; + if (!cleanup) + tempdir_name[0] = tempdir_name[4] = '_'; + tempdir_name = make_temp_dir(tempdir_name); + + run("scc -set_attr abc9_scc_id {}"); + run("abc9_ops -break_scc"); + run("aigmap"); + run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), + "write_xaiger -map /input.sym /input.xaig"); + run(stringf("%s -tempdir %s", map_cmd.str().c_str(), tempdir_name.c_str()), + "abc9_map [options] -tempdir "); + run("abc9_ops -unbreak_scc"); + + if (cleanup) + { + log("Removing temp directory.\n"); + remove_directory(tempdir_name); + } + + active_design->selection().selected_modules.clear(); + + log_pop(); + } + + active_design->selection_stack.pop_back(); + } +} Abc9Pass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc new file mode 100644 index 000000000..40ff4bbf0 --- /dev/null +++ b/passes/techmap/abc9_map.cc @@ -0,0 +1,1215 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +// [[CITE]] ABC +// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification +// http://www.eecs.berkeley.edu/~alanmi/abc/ + +#if 0 +// Based on &flow3 - better QoR but more experimental +#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \ + "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\ + "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\ + "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ + "&mfs; &ps -l" +#else +#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" +#endif + + +#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}" + +#include "kernel/register.h" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" +#include "kernel/cost.h" +#include "kernel/log.h" +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +# include +# include +#endif + +#include "frontends/aiger/aigerparse.h" +#include "kernel/utils.h" + +#ifdef YOSYS_LINK_ABC +extern "C" int Abc_RealMain(int argc, char *argv[]); +#endif + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +bool markgroups; +int map_autoidx; +SigMap assign_map; +RTLIL::Module *module; + +bool clk_polarity, en_polarity; +RTLIL::SigSpec clk_sig, en_sig; + +inline std::string remap_name(RTLIL::IdString abc9_name) +{ + return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); +} + +std::string add_echos_to_abc9_cmd(std::string str) +{ + std::string new_str, token; + for (size_t i = 0; i < str.size(); i++) { + token += str[i]; + if (str[i] == ';') { + while (i+1 < str.size() && str[i+1] == ' ') + i++; + new_str += "echo + " + token + " " + token + " "; + token.clear(); + } + } + + if (!token.empty()) { + if (!new_str.empty()) + new_str += "echo + " + token + "; "; + new_str += token; + } + + return new_str; +} + +std::string fold_abc9_cmd(std::string str) +{ + std::string token, new_str = " "; + int char_counter = 10; + + for (size_t i = 0; i <= str.size(); i++) { + if (i < str.size()) + token += str[i]; + if (i == str.size() || str[i] == ';') { + if (char_counter + token.size() > 75) + new_str += "\n ", char_counter = 14; + new_str += token, char_counter += token.size(); + token.clear(); + } + } + + return new_str; +} + +std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir) +{ + if (show_tempdir) + return text; + + while (1) { + size_t pos = text.find(tempdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "" + text.substr(pos + GetSize(tempdir_name)); + } + + std::string selfdir_name = proc_self_dirname(); + if (selfdir_name != "/") { + while (1) { + size_t pos = text.find(selfdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "/" + text.substr(pos + GetSize(selfdir_name)); + } + } + + return text; +} + +struct abc9_output_filter +{ + bool got_cr; + int escape_seq_state; + std::string linebuf; + std::string tempdir_name; + bool show_tempdir; + + abc9_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) + { + got_cr = false; + escape_seq_state = 0; + } + + void next_char(char ch) + { + if (escape_seq_state == 0 && ch == '\033') { + escape_seq_state = 1; + return; + } + if (escape_seq_state == 1) { + escape_seq_state = ch == '[' ? 2 : 0; + return; + } + if (escape_seq_state == 2) { + if ((ch < '0' || '9' < ch) && ch != ';') + escape_seq_state = 0; + return; + } + escape_seq_state = 0; + if (ch == '\r') { + got_cr = true; + return; + } + if (ch == '\n') { + log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str()); + got_cr = false, linebuf.clear(); + return; + } + if (got_cr) + got_cr = false, linebuf.clear(); + linebuf += ch; + } + + void next_line(const std::string &line) + { + //int pi, po; + //if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { + // log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", + // pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", + // po, po_map.count(po) ? po_map.at(po).c_str() : "???"); + // return; + //} + + for (char ch : line) + next_char(ch); + } +}; + +void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, + /*bool cleanup,*/ vector lut_costs, bool dff_mode, std::string clk_str, + bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, + bool show_tempdir, std::string box_file, std::string lut_file, + std::string wire_delay, const dict &box_lookup, bool nomfs, std::string tempdir_name +) +{ + module = current_module; + map_autoidx = autoidx++; + + if (clk_str != "$") + { + clk_polarity = true; + clk_sig = RTLIL::SigSpec(); + + en_polarity = true; + en_sig = RTLIL::SigSpec(); + } + + if (!clk_str.empty() && clk_str != "$") + { + if (clk_str.find(',') != std::string::npos) { + int pos = clk_str.find(','); + std::string en_str = clk_str.substr(pos+1); + clk_str = clk_str.substr(0, pos); + if (en_str[0] == '!') { + en_polarity = false; + en_str = en_str.substr(1); + } + if (module->wires_.count(RTLIL::escape_id(en_str)) != 0) + en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0)); + } + if (clk_str[0] == '!') { + clk_polarity = false; + clk_str = clk_str.substr(1); + } + if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0) + clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); + } + + if (dff_mode && clk_sig.empty()) + log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); + + log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", + module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); + + std::string abc9_script; + + if (!lut_costs.empty()) { + abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); + if (!box_file.empty()) + abc9_script += stringf("read_box -v %s; ", box_file.c_str()); + } + else + if (!lut_file.empty()) { + abc9_script += stringf("read_lut %s; ", lut_file.c_str()); + if (!box_file.empty()) + abc9_script += stringf("read_box -v %s; ", box_file.c_str()); + } + else + log_abort(); + + abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); + + if (!script_file.empty()) { + if (script_file[0] == '+') { + for (size_t i = 1; i < script_file.size(); i++) + if (script_file[i] == '\'') + abc9_script += "'\\''"; + else if (script_file[i] == ',') + abc9_script += " "; + else + abc9_script += script_file[i]; + } else + abc9_script += stringf("source %s", script_file.c_str()); + } else if (!lut_costs.empty() || !lut_file.empty()) { + //bool all_luts_cost_same = true; + //for (int this_cost : lut_costs) + // if (this_cost != lut_costs.front()) + // all_luts_cost_same = false; + abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; + //if (all_luts_cost_same && !fast_mode) + // abc9_script += "; lutpack {S}"; + } else + log_abort(); + + //if (script_file.empty() && !delay_target.empty()) + // for (size_t pos = abc9_script.find("dretime;"); pos != std::string::npos; pos = abc9_script.find("dretime;", pos+1)) + // abc9_script = abc9_script.substr(0, pos) + "dretime; retime -o {D};" + abc9_script.substr(pos+8); + + for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) + abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); + + //for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos)) + // abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3); + + for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos)) + abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3); + + if (nomfs) + for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) + abc9_script = abc9_script.erase(pos, strlen("&mfs")); + + abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str()); + abc9_script = add_echos_to_abc9_cmd(abc9_script); + + for (size_t i = 0; i+1 < abc9_script.size(); i++) + if (abc9_script[i] == ';' && abc9_script[i+1] == ' ') + abc9_script[i+1] = '\n'; + + FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); + fprintf(f, "%s\n", abc9_script.c_str()); + fclose(f); + + if (dff_mode || !clk_str.empty()) + { + if (clk_sig.size() == 0) + log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); + else { + log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig)); + if (en_sig.size() != 0) + log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig)); + log("\n"); + } + } + + log_push(); + + //if (count_output) + { + std::string buffer; + std::ifstream ifs; +#if 0 + buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig"); + ifs.open(buffer); + if (ifs.fail()) + log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); + buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); + log_assert(!design->module(ID($__abc9__))); + { + AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); + reader.parse_xaiger(); + } + ifs.close(); + Pass::call(design, stringf("write_verilog -noexpr -norename")); + design->remove(design->module(ID($__abc9__))); +#endif + + log_header(design, "Executing ABC9_MAP.\n"); + + if (!lut_costs.empty()) { + buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); + f = fopen(buffer.c_str(), "wt"); + if (f == NULL) + log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); + for (int i = 0; i < GetSize(lut_costs); i++) + fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); + fclose(f); + } + + buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); + log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); + +#ifndef YOSYS_LINK_ABC + abc9_output_filter filt(tempdir_name, show_tempdir); + int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1)); +#else + // These needs to be mutable, supposedly due to getopt + char *abc9_argv[5]; + string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); + abc9_argv[0] = strdup(exe_file.c_str()); + abc9_argv[1] = strdup("-s"); + abc9_argv[2] = strdup("-f"); + abc9_argv[3] = strdup(tmp_script_name.c_str()); + abc9_argv[4] = 0; + int ret = Abc_RealMain(4, abc9_argv); + free(abc9_argv[0]); + free(abc9_argv[1]); + free(abc9_argv[2]); + free(abc9_argv[3]); +#endif + if (ret != 0) + log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); + + buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig"); + ifs.open(buffer, std::ifstream::binary); + if (ifs.fail()) + log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); + + buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); + log_assert(!design->module(ID($__abc9__))); + + AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); + reader.parse_xaiger(box_lookup); + ifs.close(); + +#if 0 + Pass::call(design, stringf("write_verilog -noexpr -norename")); +#endif + + log_header(design, "Re-integrating ABC9 results.\n"); + RTLIL::Module *mapped_mod = design->module(ID($__abc9__)); + if (mapped_mod == NULL) + log_error("ABC output file does not contain a module `$__abc9__'.\n"); + + pool output_bits; + for (auto &it : mapped_mod->wires_) { + RTLIL::Wire *w = it.second; + RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w)); + if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx; + if (w->port_output) { + RTLIL::Wire *wire = module->wire(w->name); + log_assert(wire); + for (int i = 0; i < GetSize(w); i++) + output_bits.insert({wire, i}); + } + } + + for (auto &it : module->connections_) { + auto &signal = it.first; + auto bits = signal.bits(); + for (auto &b : bits) + if (output_bits.count(b)) + b = module->addWire(NEW_ID); + signal = std::move(bits); + } + + dict abc9_box; + vector boxes; + for (const auto &it : module->cells_) { + auto cell = it.second; + if (cell->type.in(ID($_AND_), ID($_NOT_))) { + module->remove(cell); + continue; + } + auto jt = abc9_box.find(cell->type); + if (jt == abc9_box.end()) { + RTLIL::Module* box_module = design->module(cell->type); + jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first; + } + if (jt->second) + boxes.emplace_back(cell); + } + + dict> bit_drivers, bit_users; + TopoSort toposort; + dict not2drivers; + dict> bit2sinks; + + std::map cell_stats; + for (auto c : mapped_mod->cells()) + { + toposort.node(c->name); + + RTLIL::Cell *cell = nullptr; + if (c->type == ID($_NOT_)) { + RTLIL::SigBit a_bit = c->getPort(ID::A); + RTLIL::SigBit y_bit = c->getPort(ID::Y); + bit_users[a_bit].insert(c->name); + bit_drivers[y_bit].insert(c->name); + + if (!a_bit.wire) { + c->setPort(ID::Y, module->addWire(NEW_ID)); + RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); + log_assert(wire); + module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); + } + else if (!lut_costs.empty() || !lut_file.empty()) { + RTLIL::Cell* driver_lut = nullptr; + // ABC can return NOT gates that drive POs + if (!a_bit.wire->port_input) { + // If it's not a NOT gate that that comes from a PI directly, + // find the driver LUT and clone that to guarantee that we won't + // increase the max logic depth + // (TODO: Optimise by not cloning unless will increase depth) + RTLIL::IdString driver_name; + if (GetSize(a_bit.wire) == 1) + driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); + else + driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); + driver_lut = mapped_mod->cell(driver_name); + } + + if (!driver_lut) { + // If a driver couldn't be found (could be from PI or box CI) + // then implement using a LUT + cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), + RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), + RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), + RTLIL::Const::from_string("01")); + bit2sinks[cell->getPort(ID::A)].push_back(cell); + cell_stats[ID($lut)]++; + } + else + not2drivers[c] = driver_lut; + continue; + } + else + log_abort(); + if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + continue; + } + cell_stats[c->type]++; + + RTLIL::Cell *existing_cell = nullptr; + if (c->type == ID($lut)) { + if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { + SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name)); + SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name)); + module->connect(my_y, my_a); + if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; + log_abort(); + continue; + } + cell = module->addCell(remap_name(c->name), c->type); + } + else { + existing_cell = module->cell(c->name); + log_assert(existing_cell); + cell = module->addCell(remap_name(c->name), c->type); + } + + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + if (existing_cell) { + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + } + else { + cell->parameters = c->parameters; + cell->attributes = c->attributes; + } + for (auto &conn : c->connections()) { + RTLIL::SigSpec newsig; + for (auto c : conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + cell->setPort(conn.first, newsig); + + if (cell->input(conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : conn.second) + bit_users[i].insert(c->name); + } + if (cell->output(conn.first)) + for (auto i : conn.second) + bit_drivers[i].insert(c->name); + } + } + + for (auto existing_cell : boxes) { + Cell *cell = module->cell(remap_name(existing_cell->name)); + if (cell) { + for (auto &conn : existing_cell->connections()) { + if (!conn.second.is_wire()) + continue; + Wire *wire = conn.second.as_wire(); + if (!wire->get_bool_attribute(ID(abc9_padding))) + continue; + cell->unsetPort(conn.first); + log_debug("Dropping padded port connection for %s (%s) .%s (%s )\n", log_id(cell), cell->type.c_str(), log_id(conn.first), log_signal(conn.second)); + } + module->swap_names(cell, existing_cell); + } + module->remove(existing_cell); + } + + // Copy connections (and rename) from mapped_mod to module + for (auto conn : mapped_mod->connections()) { + if (!conn.first.is_fully_const()) { + auto chunks = conn.first.chunks(); + for (auto &c : chunks) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.first = std::move(chunks); + } + if (!conn.second.is_fully_const()) { + auto chunks = conn.second.chunks(); + for (auto &c : chunks) + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.second = std::move(chunks); + } + module->connect(conn); + } + + for (auto &it : cell_stats) + log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); + int in_wires = 0, out_wires = 0; + + // Stitch in mapped_mod's inputs/outputs into module + for (auto port : mapped_mod->ports) { + RTLIL::Wire *w = mapped_mod->wire(port); + RTLIL::Wire *wire = module->wire(port); + log_assert(wire); + RTLIL::Wire *remap_wire = module->wire(remap_name(port)); + RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); + log_assert(GetSize(signal) >= GetSize(remap_wire)); + + RTLIL::SigSig conn; + if (w->port_output) { + conn.first = signal; + conn.second = remap_wire; + out_wires++; + module->connect(conn); + } + else if (w->port_input) { + conn.first = remap_wire; + conn.second = signal; + in_wires++; + module->connect(conn); + } + } + + for (auto &it : bit_users) + if (bit_drivers.count(it.first)) + for (auto driver_cell : bit_drivers.at(it.first)) + for (auto user_cell : it.second) + toposort.edge(driver_cell, user_cell); + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); + log_assert(no_loops); + + for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { + RTLIL::Cell *not_cell = mapped_mod->cell(*ii); + log_assert(not_cell); + if (not_cell->type != ID($_NOT_)) + continue; + auto it = not2drivers.find(not_cell); + if (it == not2drivers.end()) + continue; + RTLIL::Cell *driver_lut = it->second; + RTLIL::SigBit a_bit = not_cell->getPort(ID::A); + RTLIL::SigBit y_bit = not_cell->getPort(ID::Y); + RTLIL::Const driver_mask; + + a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name)); + y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name)); + + auto jt = bit2sinks.find(a_bit); + if (jt == bit2sinks.end()) + goto clone_lut; + + for (auto sink_cell : jt->second) + if (sink_cell->type != ID($lut)) + goto clone_lut; + + // Push downstream LUTs past inverter + for (auto sink_cell : jt->second) { + SigSpec A = sink_cell->getPort(ID::A); + RTLIL::Const mask = sink_cell->getParam(ID(LUT)); + int index = 0; + for (; index < GetSize(A); index++) + if (A[index] == a_bit) + break; + log_assert(index < GetSize(A)); + int i = 0; + while (i < GetSize(mask)) { + for (int j = 0; j < (1 << index); j++) + std::swap(mask[i+j], mask[i+j+(1 << index)]); + i += 1 << (index+1); + } + A[index] = y_bit; + sink_cell->setPort(ID::A, A); + sink_cell->setParam(ID(LUT), mask); + } + + // Since we have rewritten all sinks (which we know + // to be only LUTs) to be after the inverter, we can + // go ahead and clone the LUT with the expectation + // that the original driving LUT will become dangling + // and get cleaned away +clone_lut: + driver_mask = driver_lut->getParam(ID(LUT)); + for (auto &b : driver_mask.bits) { + if (b == RTLIL::State::S0) b = RTLIL::State::S1; + else if (b == RTLIL::State::S1) b = RTLIL::State::S0; + } + auto cell = module->addLut(NEW_ID, + driver_lut->getPort(ID::A), + y_bit, + driver_mask); + for (auto &bit : cell->connections_.at(ID::A)) { + bit.wire = module->wires_.at(remap_name(bit.wire->name)); + bit2sinks[bit].push_back(cell); + } + } + + //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); + log("ABC RESULTS: input signals: %8d\n", in_wires); + log("ABC RESULTS: output signals: %8d\n", out_wires); + + design->remove(mapped_mod); + } + //else + //{ + // log("Don't call ABC as there is nothing to map.\n"); + //} + + log_pop(); +} + +struct Abc9TechmapPass : public Pass { + Abc9TechmapPass() : Pass("abc9_map", "use ABC9 for technology mapping") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" abc9_map [options] [selection]\n"); + log("\n"); + log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); + log("library to a target architecture.\n"); + log("\n"); + log(" -exe \n"); +#ifdef ABCEXTERNAL + log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); +#else + log(" use the specified command instead of \"/yosys-abc\" to execute ABC.\n"); +#endif + log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n"); + log("\n"); + log(" -script \n"); + log(" use the specified ABC script file instead of the default script.\n"); + log("\n"); + log(" if starts with a plus sign (+), then the rest of the filename\n"); + log(" string is interpreted as the command string to be passed to ABC. The\n"); + log(" leading plus sign is removed and all commas (,) in the string are\n"); + log(" replaced with blanks before the string is passed to ABC.\n"); + log("\n"); + log(" if no -script parameter is given, the following scripts are used:\n"); + log("\n"); + log(" for -lut/-luts (only one LUT size):\n"); + log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); + log("\n"); + log(" for -lut/-luts (different LUT sizes):\n"); + log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); + log("\n"); + log(" -fast\n"); + log(" use different default scripts that are slightly faster (at the cost\n"); + log(" of output quality):\n"); + log("\n"); + log(" for -lut/-luts:\n"); + log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); + log("\n"); + log(" -D \n"); + log(" set delay target. the string {D} in the default scripts above is\n"); + log(" replaced by this option when used, and an empty string otherwise\n"); + log(" (indicating best possible delay).\n"); +// log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n"); +// log(" default scripts above.\n"); + log("\n"); +// log(" -S \n"); +// log(" maximum number of LUT inputs shared.\n"); +// log(" (replaces {S} in the default scripts above, default: -S 1)\n"); +// log("\n"); + log(" -lut \n"); + log(" generate netlist using luts of (max) the specified width.\n"); + log("\n"); + log(" -lut :\n"); + log(" generate netlist using luts of (max) the specified width . All\n"); + log(" luts with width <= have constant cost. for luts larger than \n"); + log(" the area cost doubles with each additional input bit. the delay cost\n"); + log(" is still constant for all lut widths.\n"); + log("\n"); + log(" -lut \n"); + log(" pass this file with lut library to ABC.\n"); + log("\n"); + log(" -luts ,,,:,..\n"); + log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); + log(" 2, 3, .. inputs.\n"); + log("\n"); +// log(" -dff\n"); +// log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n"); +// log(" clock domains are automatically partitioned in clock domains and each\n"); +// log(" domain is passed through ABC independently.\n"); +// log("\n"); +// log(" -clk [!][,[!]]\n"); +// log(" use only the specified clock domain. this is like -dff, but only FF\n"); +// log(" cells that belong to the specified clock domain are used.\n"); +// log("\n"); +// log(" -keepff\n"); +// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n"); +// log(" them, for example for equivalence checking.)\n"); +// log("\n"); +// log(" -nocleanup\n"); +// log(" when this option is used, the temporary files created by this pass\n"); +// log(" are not removed. this is useful for debugging.\n"); +// log("\n"); + log(" -showtmp\n"); + log(" print the temp dir name in log. usually this is suppressed so that the\n"); + log(" command output is identical across runs.\n"); + log("\n"); + log(" -markgroups\n"); + log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n"); + log(" this attribute is a unique integer for each ABC process started. This\n"); + log(" is useful for debugging the partitioning of clock domains.\n"); + log("\n"); + log(" -box \n"); + log(" pass this file with box library to ABC. Use with -lut.\n"); + log("\n"); + log(" -tempdir \n"); + log(" use this as the temp dir.\n"); + log("\n"); + log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); + log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); + log("ABC on logic snippets extracted from your design. You will not get any useful\n"); + log("output when passing an ABC script that writes a file. Instead write your full\n"); + log("design as BLIF file with write_blif and then load that into ABC externally if\n"); + log("you want to use ABC to convert your design into another format.\n"); + log("\n"); + log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n"); + log_push(); + + assign_map.clear(); + +#ifdef ABCEXTERNAL + std::string exe_file = ABCEXTERNAL; +#else + std::string exe_file = proc_self_dirname() + "yosys-abc"; +#endif + std::string script_file, clk_str, box_file, lut_file; + std::string delay_target, lutin_shared = "-S 1", wire_delay; + std::string tempdir_name; + bool fast_mode = false, dff_mode = false, keepff = false /*, cleanup = true*/; + bool show_tempdir = false; + bool nomfs = false; + vector lut_costs; + markgroups = false; + +#if 0 + cleanup = false; + show_tempdir = true; +#endif + +#ifdef _WIN32 +#ifndef ABCEXTERNAL + if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) + exe_file = proc_self_dirname() + "..\\yosys-abc"; +#endif +#endif + + size_t argidx; + char pwd [PATH_MAX]; + if (!getcwd(pwd, sizeof(pwd))) { + log_cmd_error("getcwd failed: %s\n", strerror(errno)); + log_abort(); + } + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-exe" && argidx+1 < args.size()) { + exe_file = args[++argidx]; + continue; + } + if (arg == "-script" && argidx+1 < args.size()) { + script_file = args[++argidx]; + rewrite_filename(script_file); + if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') + script_file = std::string(pwd) + "/" + script_file; + continue; + } + if (arg == "-D" && argidx+1 < args.size()) { + delay_target = "-D " + args[++argidx]; + continue; + } + //if (arg == "-S" && argidx+1 < args.size()) { + // lutin_shared = "-S " + args[++argidx]; + // continue; + //} + if (arg == "-lut" && argidx+1 < args.size()) { + string arg = args[++argidx]; + if (arg.find_first_not_of("0123456789:") == std::string::npos) { + size_t pos = arg.find_first_of(':'); + int lut_mode = 0, lut_mode2 = 0; + if (pos != string::npos) { + lut_mode = atoi(arg.substr(0, pos).c_str()); + lut_mode2 = atoi(arg.substr(pos+1).c_str()); + } else { + lut_mode = atoi(arg.c_str()); + lut_mode2 = lut_mode; + } + lut_costs.clear(); + for (int i = 0; i < lut_mode; i++) + lut_costs.push_back(1); + for (int i = lut_mode; i < lut_mode2; i++) + lut_costs.push_back(2 << (i - lut_mode)); + } + else { + lut_file = arg; + rewrite_filename(lut_file); + if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+') + lut_file = std::string(pwd) + "/" + lut_file; + } + continue; + } + if (arg == "-luts" && argidx+1 < args.size()) { + lut_costs.clear(); + for (auto &tok : split_tokens(args[++argidx], ",")) { + auto parts = split_tokens(tok, ":"); + if (GetSize(parts) == 0 && !lut_costs.empty()) + lut_costs.push_back(lut_costs.back()); + else if (GetSize(parts) == 1) + lut_costs.push_back(atoi(parts.at(0).c_str())); + else if (GetSize(parts) == 2) + while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) + lut_costs.push_back(atoi(parts.at(1).c_str())); + else + log_cmd_error("Invalid -luts syntax.\n"); + } + continue; + } + if (arg == "-fast") { + fast_mode = true; + continue; + } + //if (arg == "-dff") { + // dff_mode = true; + // continue; + //} + //if (arg == "-clk" && argidx+1 < args.size()) { + // clk_str = args[++argidx]; + // dff_mode = true; + // continue; + //} + //if (arg == "-keepff") { + // keepff = true; + // continue; + //} + //if (arg == "-nocleanup") { + // cleanup = false; + // continue; + //} + if (arg == "-showtmp") { + show_tempdir = true; + continue; + } + if (arg == "-markgroups") { + markgroups = true; + continue; + } + if (arg == "-box" && argidx+1 < args.size()) { + box_file = args[++argidx]; + continue; + } + if (arg == "-W" && argidx+1 < args.size()) { + wire_delay = "-W " + args[++argidx]; + continue; + } + if (arg == "-nomfs") { + nomfs = true; + continue; + } + if (arg == "-tempdir" && argidx+1 < args.size()) { + tempdir_name = args[++argidx]; + continue; + } + break; + } + extra_args(args, argidx, design); + + // ABC expects a box file for XAIG + if (box_file.empty()) + box_file = "+/dummy.box"; + + rewrite_filename(box_file); + if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') + box_file = std::string(pwd) + "/" + box_file; + + if (tempdir_name.empty()) + log_cmd_error("abc9_map '-tempdir' option is mandatory.\n"); + + dict box_lookup; + for (auto m : design->modules()) { + auto it = m->attributes.find(ID(abc9_box_id)); + if (it == m->attributes.end()) + continue; + if (m->name.begins_with("$paramod")) + continue; + auto id = it->second.as_int(); + auto r = box_lookup.insert(std::make_pair(id, m->name)); + if (!r.second) + log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", + log_id(m), id, log_id(r.first->second)); + log_assert(r.second); + + RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; + for (auto p : m->ports) { + auto w = m->wire(p); + log_assert(w); + if (w->attributes.count(ID(abc9_carry))) { + if (w->port_input) { + if (carry_in) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); + carry_in = w; + } + else if (w->port_output) { + if (carry_out) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); + carry_out = w; + } + } + } + if (carry_in || carry_out) { + if (carry_in && !carry_out) + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); + if (!carry_in && carry_out) + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); + // Make carry_in the last PI, and carry_out the last PO + // since ABC requires it this way + auto &ports = m->ports; + for (auto it = ports.begin(); it != ports.end(); ) { + RTLIL::Wire* w = m->wire(*it); + log_assert(w); + if (w == carry_in || w == carry_out) { + it = ports.erase(it); + continue; + } + if (w->port_id > carry_in->port_id) + --w->port_id; + if (w->port_id > carry_out->port_id) + --w->port_id; + log_assert(w->port_input || w->port_output); + log_assert(ports[w->port_id-1] == w->name); + ++it; + } + ports.push_back(carry_in->name); + carry_in->port_id = ports.size(); + ports.push_back(carry_out->name); + carry_out->port_id = ports.size(); + } + } + + for (auto mod : design->selected_modules()) + { + if (mod->attributes.count(ID(abc9_box_id))) + continue; + + if (mod->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(mod)); + continue; + } + + assign_map.set(mod); + + if (!dff_mode || !clk_str.empty()) { + abc9_module(design, mod, script_file, exe_file, /*cleanup,*/ lut_costs, dff_mode, clk_str, keepff, + delay_target, lutin_shared, fast_mode, show_tempdir, + box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name); + continue; + } + + CellTypes ct(design); + + std::vector all_cells = mod->selected_cells(); + std::set unassigned_cells(all_cells.begin(), all_cells.end()); + + std::set expand_queue, next_expand_queue; + std::set expand_queue_up, next_expand_queue_up; + std::set expand_queue_down, next_expand_queue_down; + + typedef tuple clkdomain_t; + std::map> assigned_cells; + std::map assigned_cells_reverse; + + std::map> cell_to_bit, cell_to_bit_up, cell_to_bit_down; + std::map> bit_to_cell, bit_to_cell_up, bit_to_cell_down; + + for (auto cell : all_cells) + { + clkdomain_t key; + + for (auto &conn : cell->connections()) + for (auto bit : conn.second) { + bit = assign_map(bit); + if (bit.wire != nullptr) { + cell_to_bit[cell].insert(bit); + bit_to_cell[bit].insert(cell); + if (ct.cell_input(cell->type, conn.first)) { + cell_to_bit_up[cell].insert(bit); + bit_to_cell_down[bit].insert(cell); + } + if (ct.cell_output(cell->type, conn.first)) { + cell_to_bit_down[cell].insert(bit); + bit_to_cell_up[bit].insert(cell); + } + } + } + + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) + { + key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); + } + else + if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + { + bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); + bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)); + key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E)))); + } + else + continue; + + unassigned_cells.erase(cell); + expand_queue.insert(cell); + expand_queue_up.insert(cell); + expand_queue_down.insert(cell); + + assigned_cells[key].push_back(cell); + assigned_cells_reverse[cell] = key; + } + + while (!expand_queue_up.empty() || !expand_queue_down.empty()) + { + if (!expand_queue_up.empty()) + { + RTLIL::Cell *cell = *expand_queue_up.begin(); + clkdomain_t key = assigned_cells_reverse.at(cell); + expand_queue_up.erase(cell); + + for (auto bit : cell_to_bit_up[cell]) + for (auto c : bit_to_cell_up[bit]) + if (unassigned_cells.count(c)) { + unassigned_cells.erase(c); + next_expand_queue_up.insert(c); + assigned_cells[key].push_back(c); + assigned_cells_reverse[c] = key; + expand_queue.insert(c); + } + } + + if (!expand_queue_down.empty()) + { + RTLIL::Cell *cell = *expand_queue_down.begin(); + clkdomain_t key = assigned_cells_reverse.at(cell); + expand_queue_down.erase(cell); + + for (auto bit : cell_to_bit_down[cell]) + for (auto c : bit_to_cell_down[bit]) + if (unassigned_cells.count(c)) { + unassigned_cells.erase(c); + next_expand_queue_up.insert(c); + assigned_cells[key].push_back(c); + assigned_cells_reverse[c] = key; + expand_queue.insert(c); + } + } + + if (expand_queue_up.empty() && expand_queue_down.empty()) { + expand_queue_up.swap(next_expand_queue_up); + expand_queue_down.swap(next_expand_queue_down); + } + } + + while (!expand_queue.empty()) + { + RTLIL::Cell *cell = *expand_queue.begin(); + clkdomain_t key = assigned_cells_reverse.at(cell); + expand_queue.erase(cell); + + for (auto bit : cell_to_bit.at(cell)) { + for (auto c : bit_to_cell[bit]) + if (unassigned_cells.count(c)) { + unassigned_cells.erase(c); + next_expand_queue.insert(c); + assigned_cells[key].push_back(c); + assigned_cells_reverse[c] = key; + } + bit_to_cell[bit].clear(); + } + + if (expand_queue.empty()) + expand_queue.swap(next_expand_queue); + } + + clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec()); + for (auto cell : unassigned_cells) { + assigned_cells[key].push_back(cell); + assigned_cells_reverse[cell] = key; + } + + log_header(design, "Summary of detected clock domains:\n"); + for (auto &it : assigned_cells) + log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second), + std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), + std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); + + for (auto &it : assigned_cells) { + clk_polarity = std::get<0>(it.first); + clk_sig = assign_map(std::get<1>(it.first)); + en_polarity = std::get<2>(it.first); + en_sig = assign_map(std::get<3>(it.first)); + abc9_module(design, mod, script_file, exe_file, /*cleanup,*/ lut_costs, !clk_sig.empty(), "$", + keepff, delay_target, lutin_shared, fast_mode, show_tempdir, + box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name); + assign_map.set(mod); + } + } + + assign_map.clear(); + + log_pop(); + } +} Abc9TechmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc new file mode 100644 index 000000000..4c30efd06 --- /dev/null +++ b/passes/techmap/abc9_ops.cc @@ -0,0 +1,139 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/register.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void break_scc(RTLIL::Module *module) +{ + // For every unique SCC found, (arbitrarily) find the first + // cell in the component, and convert all wires driven by + // its output ports into a new PO, and drive its previous + // sinks with a new PI + pool ids_seen; + for (auto cell : module->selected_cells()) { + auto it = cell->attributes.find(ID(abc9_scc_id)); + if (it == cell->attributes.end()) + continue; + auto r = ids_seen.insert(it->second); + 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)) { + SigBit b = c.second.as_bit(); + Wire *w = b.wire; + if (w->port_input) { + // In this case, hopefully the loop break has been already created + // Get the non-prefixed wire + Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str())); + log_assert(wo != nullptr); + log_assert(wo->port_output); + log_assert(b.offset < GetSize(wo)); + c.second = RTLIL::SigBit(wo, b.offset); + } + else { + // Create a new output/input loop break + w->port_input = true; + w = module->wire(stringf("%s.abco", w->name.c_str())); + if (!w) { + w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire)); + w->port_output = true; + } + else { + log_assert(w->port_input); + log_assert(b.offset < GetSize(w)); + } + w->set_bool_attribute(ID(abc9_scc_break)); + c.second = RTLIL::SigBit(w, b.offset); + } + } + } + } + + module->fixup_ports(); +} + +void unbreak_scc(RTLIL::Module *module) { + // Now 'unexpose' those wires by undoing + // the expose operation -- remove them from PO/PI + // and re-connecting them back together + for (auto wire : module->wires()) { + auto it = wire->attributes.find(ID(abc9_scc_break)); + if (it != wire->attributes.end()) { + wire->attributes.erase(it); + log_assert(wire->port_output); + wire->port_output = false; + std::string name = wire->name.str(); + RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5)); + log_assert(i_wire); + log_assert(i_wire->port_input); + i_wire->port_input = false; + module->connect(i_wire, wire); + } + } + module->fixup_ports(); +} + +struct Abc9PrepPass : public Pass { + Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" abc9_ops [options] [selection]\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); + log_push(); + + bool break_scc_mode = false; + bool unbreak_scc_mode = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-break_scc") { + break_scc_mode = true; + continue; + } + if (arg == "-unbreak_scc") { + unbreak_scc_mode = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto mod : design->selected_modules()) { + if (break_scc_mode) + break_scc(mod); + if (unbreak_scc_mode) + unbreak_scc(mod); + } + } +} Abc9PrepPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/abc9_techmap.cc b/passes/techmap/abc9_techmap.cc deleted file mode 100644 index 7ff68f382..000000000 --- a/passes/techmap/abc9_techmap.cc +++ /dev/null @@ -1,1310 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * 2019 Eddie Hung - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// [[CITE]] ABC -// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification -// http://www.eecs.berkeley.edu/~alanmi/abc/ - -#if 0 -// Based on &flow3 - better QoR but more experimental -#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \ - "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\ - "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\ - "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ - "&mfs; &ps -l" -#else -#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" -#endif - - -#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}" - -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/cost.h" -#include "kernel/log.h" -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -# include -# include -#endif - -#include "frontends/aiger/aigerparse.h" -#include "kernel/utils.h" - -#ifdef YOSYS_LINK_ABC -extern "C" int Abc_RealMain(int argc, char *argv[]); -#endif - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -bool markgroups; -int map_autoidx; -SigMap assign_map; -RTLIL::Module *module; - -bool clk_polarity, en_polarity; -RTLIL::SigSpec clk_sig, en_sig; - -inline std::string remap_name(RTLIL::IdString abc9_name) -{ - return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); -} - -void handle_loops(RTLIL::Design *design) -{ - Pass::call(design, "scc -set_attr abc9_scc_id {}"); - - // For every unique SCC found, (arbitrarily) find the first - // cell in the component, and select (and mark) all its output - // wires - pool ids_seen; - for (auto cell : module->cells()) { - auto it = cell->attributes.find(ID(abc9_scc_id)); - if (it != cell->attributes.end()) { - auto r = ids_seen.insert(it->second); - if (r.second) { - for (auto &c : cell->connections_) { - if (c.second.is_fully_const()) continue; - if (cell->output(c.first)) { - SigBit b = c.second.as_bit(); - Wire *w = b.wire; - if (w->port_input) { - // In this case, hopefully the loop break has been already created - // Get the non-prefixed wire - Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str())); - log_assert(wo != nullptr); - log_assert(wo->port_output); - log_assert(b.offset < GetSize(wo)); - c.second = RTLIL::SigBit(wo, b.offset); - } - else { - // Create a new output/input loop break - w->port_input = true; - w = module->wire(stringf("%s.abco", w->name.c_str())); - if (!w) { - w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire)); - w->port_output = true; - } - else { - log_assert(w->port_input); - log_assert(b.offset < GetSize(w)); - } - w->set_bool_attribute(ID(abc9_scc_break)); - c.second = RTLIL::SigBit(w, b.offset); - } - } - } - } - cell->attributes.erase(it); - } - } - - module->fixup_ports(); -} - -std::string add_echos_to_abc9_cmd(std::string str) -{ - std::string new_str, token; - for (size_t i = 0; i < str.size(); i++) { - token += str[i]; - if (str[i] == ';') { - while (i+1 < str.size() && str[i+1] == ' ') - i++; - new_str += "echo + " + token + " " + token + " "; - token.clear(); - } - } - - if (!token.empty()) { - if (!new_str.empty()) - new_str += "echo + " + token + "; "; - new_str += token; - } - - return new_str; -} - -std::string fold_abc9_cmd(std::string str) -{ - std::string token, new_str = " "; - int char_counter = 10; - - for (size_t i = 0; i <= str.size(); i++) { - if (i < str.size()) - token += str[i]; - if (i == str.size() || str[i] == ';') { - if (char_counter + token.size() > 75) - new_str += "\n ", char_counter = 14; - new_str += token, char_counter += token.size(); - token.clear(); - } - } - - return new_str; -} - -std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir) -{ - if (show_tempdir) - return text; - - while (1) { - size_t pos = text.find(tempdir_name); - if (pos == std::string::npos) - break; - text = text.substr(0, pos) + "" + text.substr(pos + GetSize(tempdir_name)); - } - - std::string selfdir_name = proc_self_dirname(); - if (selfdir_name != "/") { - while (1) { - size_t pos = text.find(selfdir_name); - if (pos == std::string::npos) - break; - text = text.substr(0, pos) + "/" + text.substr(pos + GetSize(selfdir_name)); - } - } - - return text; -} - -struct abc9_output_filter -{ - bool got_cr; - int escape_seq_state; - std::string linebuf; - std::string tempdir_name; - bool show_tempdir; - - abc9_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) - { - got_cr = false; - escape_seq_state = 0; - } - - void next_char(char ch) - { - if (escape_seq_state == 0 && ch == '\033') { - escape_seq_state = 1; - return; - } - if (escape_seq_state == 1) { - escape_seq_state = ch == '[' ? 2 : 0; - return; - } - if (escape_seq_state == 2) { - if ((ch < '0' || '9' < ch) && ch != ';') - escape_seq_state = 0; - return; - } - escape_seq_state = 0; - if (ch == '\r') { - got_cr = true; - return; - } - if (ch == '\n') { - log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str()); - got_cr = false, linebuf.clear(); - return; - } - if (got_cr) - got_cr = false, linebuf.clear(); - linebuf += ch; - } - - void next_line(const std::string &line) - { - //int pi, po; - //if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { - // log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", - // pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", - // po, po_map.count(po) ? po_map.at(po).c_str() : "???"); - // return; - //} - - for (char ch : line) - next_char(ch); - } -}; - -void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, - bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, - bool show_tempdir, std::string box_file, std::string lut_file, - std::string wire_delay, const dict &box_lookup, bool nomfs -) -{ - module = current_module; - map_autoidx = autoidx++; - - if (clk_str != "$") - { - clk_polarity = true; - clk_sig = RTLIL::SigSpec(); - - en_polarity = true; - en_sig = RTLIL::SigSpec(); - } - - if (!clk_str.empty() && clk_str != "$") - { - if (clk_str.find(',') != std::string::npos) { - int pos = clk_str.find(','); - std::string en_str = clk_str.substr(pos+1); - clk_str = clk_str.substr(0, pos); - if (en_str[0] == '!') { - en_polarity = false; - en_str = en_str.substr(1); - } - if (module->wires_.count(RTLIL::escape_id(en_str)) != 0) - en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0)); - } - if (clk_str[0] == '!') { - clk_polarity = false; - clk_str = clk_str.substr(1); - } - if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0) - clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); - } - - if (dff_mode && clk_sig.empty()) - log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); - - std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; - if (!cleanup) - tempdir_name[0] = tempdir_name[4] = '_'; - tempdir_name = make_temp_dir(tempdir_name); - log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", - module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); - - std::string abc9_script; - - if (!lut_costs.empty()) { - abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); - if (!box_file.empty()) - abc9_script += stringf("read_box -v %s; ", box_file.c_str()); - } - else - if (!lut_file.empty()) { - abc9_script += stringf("read_lut %s; ", lut_file.c_str()); - if (!box_file.empty()) - abc9_script += stringf("read_box -v %s; ", box_file.c_str()); - } - else - log_abort(); - - abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); - - if (!script_file.empty()) { - if (script_file[0] == '+') { - for (size_t i = 1; i < script_file.size(); i++) - if (script_file[i] == '\'') - abc9_script += "'\\''"; - else if (script_file[i] == ',') - abc9_script += " "; - else - abc9_script += script_file[i]; - } else - abc9_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty() || !lut_file.empty()) { - //bool all_luts_cost_same = true; - //for (int this_cost : lut_costs) - // if (this_cost != lut_costs.front()) - // all_luts_cost_same = false; - abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; - //if (all_luts_cost_same && !fast_mode) - // abc9_script += "; lutpack {S}"; - } else - log_abort(); - - //if (script_file.empty() && !delay_target.empty()) - // for (size_t pos = abc9_script.find("dretime;"); pos != std::string::npos; pos = abc9_script.find("dretime;", pos+1)) - // abc9_script = abc9_script.substr(0, pos) + "dretime; retime -o {D};" + abc9_script.substr(pos+8); - - for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) - abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); - - //for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos)) - // abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3); - - for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos)) - abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3); - - if (nomfs) - for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) - abc9_script = abc9_script.erase(pos, strlen("&mfs")); - - abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str()); - abc9_script = add_echos_to_abc9_cmd(abc9_script); - - for (size_t i = 0; i+1 < abc9_script.size(); i++) - if (abc9_script[i] == ';' && abc9_script[i+1] == ' ') - abc9_script[i+1] = '\n'; - - FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); - fprintf(f, "%s\n", abc9_script.c_str()); - fclose(f); - - if (dff_mode || !clk_str.empty()) - { - if (clk_sig.size() == 0) - log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); - else { - log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig)); - if (en_sig.size() != 0) - log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig)); - log("\n"); - } - } - - bool count_output = false; - for (auto port_name : module->ports) { - RTLIL::Wire *port_wire = module->wire(port_name); - log_assert(port_wire); - if (port_wire->port_output) { - count_output = true; - break; - } - } - - log_push(); - - if (count_output) - { - design->selection_stack.emplace_back(false); - RTLIL::Selection& sel = design->selection_stack.back(); - sel.select(module); - - handle_loops(design); - - Pass::call(design, "aigmap"); - - //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n", - // count_gates, GetSize(signal_list), count_input, count_output); - - Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); - - std::string buffer; - std::ifstream ifs; -#if 0 - buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig"); - ifs.open(buffer); - if (ifs.fail()) - log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); - log_assert(!design->module(ID($__abc9__))); - { - AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); - reader.parse_xaiger(); - } - ifs.close(); - Pass::call(design, stringf("write_verilog -noexpr -norename")); - design->remove(design->module(ID($__abc9__))); -#endif - - design->selection_stack.pop_back(); - - log_header(design, "Executing ABC9_MAP.\n"); - - if (!lut_costs.empty()) { - buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); - f = fopen(buffer.c_str(), "wt"); - if (f == NULL) - log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); - for (int i = 0; i < GetSize(lut_costs); i++) - fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); - fclose(f); - } - - buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); - log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); - -#ifndef YOSYS_LINK_ABC - abc9_output_filter filt(tempdir_name, show_tempdir); - int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1)); -#else - // These needs to be mutable, supposedly due to getopt - char *abc9_argv[5]; - string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); - abc9_argv[0] = strdup(exe_file.c_str()); - abc9_argv[1] = strdup("-s"); - abc9_argv[2] = strdup("-f"); - abc9_argv[3] = strdup(tmp_script_name.c_str()); - abc9_argv[4] = 0; - int ret = Abc_RealMain(4, abc9_argv); - free(abc9_argv[0]); - free(abc9_argv[1]); - free(abc9_argv[2]); - free(abc9_argv[3]); -#endif - if (ret != 0) - log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); - - buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig"); - ifs.open(buffer, std::ifstream::binary); - if (ifs.fail()) - log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - - buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); - log_assert(!design->module(ID($__abc9__))); - - AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); - reader.parse_xaiger(box_lookup); - ifs.close(); - -#if 0 - Pass::call(design, stringf("write_verilog -noexpr -norename")); -#endif - - log_header(design, "Re-integrating ABC9 results.\n"); - RTLIL::Module *mapped_mod = design->module(ID($__abc9__)); - if (mapped_mod == NULL) - log_error("ABC output file does not contain a module `$__abc9__'.\n"); - - pool output_bits; - for (auto &it : mapped_mod->wires_) { - RTLIL::Wire *w = it.second; - RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w)); - if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx; - if (w->port_output) { - RTLIL::Wire *wire = module->wire(w->name); - log_assert(wire); - for (int i = 0; i < GetSize(w); i++) - output_bits.insert({wire, i}); - } - } - - for (auto &it : module->connections_) { - auto &signal = it.first; - auto bits = signal.bits(); - for (auto &b : bits) - if (output_bits.count(b)) - b = module->addWire(NEW_ID); - signal = std::move(bits); - } - - dict abc9_box; - vector boxes; - for (const auto &it : module->cells_) { - auto cell = it.second; - if (cell->type.in(ID($_AND_), ID($_NOT_))) { - module->remove(cell); - continue; - } - auto jt = abc9_box.find(cell->type); - if (jt == abc9_box.end()) { - RTLIL::Module* box_module = design->module(cell->type); - jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first; - } - if (jt->second) - boxes.emplace_back(cell); - } - - dict> bit_drivers, bit_users; - TopoSort toposort; - dict not2drivers; - dict> bit2sinks; - - std::map cell_stats; - for (auto c : mapped_mod->cells()) - { - toposort.node(c->name); - - RTLIL::Cell *cell = nullptr; - if (c->type == ID($_NOT_)) { - RTLIL::SigBit a_bit = c->getPort(ID::A); - RTLIL::SigBit y_bit = c->getPort(ID::Y); - bit_users[a_bit].insert(c->name); - bit_drivers[y_bit].insert(c->name); - - if (!a_bit.wire) { - c->setPort(ID::Y, module->addWire(NEW_ID)); - RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); - log_assert(wire); - module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); - } - else if (!lut_costs.empty() || !lut_file.empty()) { - RTLIL::Cell* driver_lut = nullptr; - // ABC can return NOT gates that drive POs - if (!a_bit.wire->port_input) { - // If it's not a NOT gate that that comes from a PI directly, - // find the driver LUT and clone that to guarantee that we won't - // increase the max logic depth - // (TODO: Optimise by not cloning unless will increase depth) - RTLIL::IdString driver_name; - if (GetSize(a_bit.wire) == 1) - driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); - else - driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); - driver_lut = mapped_mod->cell(driver_name); - } - - if (!driver_lut) { - // If a driver couldn't be found (could be from PI or box CI) - // then implement using a LUT - cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), - RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), - RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), - RTLIL::Const::from_string("01")); - bit2sinks[cell->getPort(ID::A)].push_back(cell); - cell_stats[ID($lut)]++; - } - else - not2drivers[c] = driver_lut; - continue; - } - else - log_abort(); - if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; - continue; - } - cell_stats[c->type]++; - - RTLIL::Cell *existing_cell = nullptr; - if (c->type == ID($lut)) { - if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { - SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name)); - SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); - if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; - log_abort(); - continue; - } - cell = module->addCell(remap_name(c->name), c->type); - } - else { - existing_cell = module->cell(c->name); - log_assert(existing_cell); - cell = module->addCell(remap_name(c->name), c->type); - } - - if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; - if (existing_cell) { - cell->parameters = existing_cell->parameters; - cell->attributes = existing_cell->attributes; - } - else { - cell->parameters = c->parameters; - cell->attributes = c->attributes; - } - for (auto &conn : c->connections()) { - RTLIL::SigSpec newsig; - for (auto c : conn.second.chunks()) { - if (c.width == 0) - continue; - //log_assert(c.width == 1); - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - newsig.append(c); - } - cell->setPort(conn.first, newsig); - - if (cell->input(conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : conn.second) - bit_users[i].insert(c->name); - } - if (cell->output(conn.first)) - for (auto i : conn.second) - bit_drivers[i].insert(c->name); - } - } - - for (auto existing_cell : boxes) { - Cell *cell = module->cell(remap_name(existing_cell->name)); - if (cell) { - for (auto &conn : existing_cell->connections()) { - if (!conn.second.is_wire()) - continue; - Wire *wire = conn.second.as_wire(); - if (!wire->get_bool_attribute(ID(abc9_padding))) - continue; - cell->unsetPort(conn.first); - log_debug("Dropping padded port connection for %s (%s) .%s (%s )\n", log_id(cell), cell->type.c_str(), log_id(conn.first), log_signal(conn.second)); - } - module->swap_names(cell, existing_cell); - } - module->remove(existing_cell); - } - - // Copy connections (and rename) from mapped_mod to module - for (auto conn : mapped_mod->connections()) { - if (!conn.first.is_fully_const()) { - auto chunks = conn.first.chunks(); - for (auto &c : chunks) - c.wire = module->wires_.at(remap_name(c.wire->name)); - conn.first = std::move(chunks); - } - if (!conn.second.is_fully_const()) { - auto chunks = conn.second.chunks(); - for (auto &c : chunks) - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - conn.second = std::move(chunks); - } - module->connect(conn); - } - - for (auto &it : cell_stats) - log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); - int in_wires = 0, out_wires = 0; - - // Stitch in mapped_mod's inputs/outputs into module - for (auto port : mapped_mod->ports) { - RTLIL::Wire *w = mapped_mod->wire(port); - RTLIL::Wire *wire = module->wire(port); - log_assert(wire); - RTLIL::Wire *remap_wire = module->wire(remap_name(port)); - RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); - log_assert(GetSize(signal) >= GetSize(remap_wire)); - - RTLIL::SigSig conn; - if (w->port_output) { - conn.first = signal; - conn.second = remap_wire; - out_wires++; - module->connect(conn); - } - else if (w->port_input) { - conn.first = remap_wire; - conn.second = signal; - in_wires++; - module->connect(conn); - } - } - - for (auto &it : bit_users) - if (bit_drivers.count(it.first)) - for (auto driver_cell : bit_drivers.at(it.first)) - for (auto user_cell : it.second) - toposort.edge(driver_cell, user_cell); - bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); - log_assert(no_loops); - - for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { - RTLIL::Cell *not_cell = mapped_mod->cell(*ii); - log_assert(not_cell); - if (not_cell->type != ID($_NOT_)) - continue; - auto it = not2drivers.find(not_cell); - if (it == not2drivers.end()) - continue; - RTLIL::Cell *driver_lut = it->second; - RTLIL::SigBit a_bit = not_cell->getPort(ID::A); - RTLIL::SigBit y_bit = not_cell->getPort(ID::Y); - RTLIL::Const driver_mask; - - a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name)); - y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name)); - - auto jt = bit2sinks.find(a_bit); - if (jt == bit2sinks.end()) - goto clone_lut; - - for (auto sink_cell : jt->second) - if (sink_cell->type != ID($lut)) - goto clone_lut; - - // Push downstream LUTs past inverter - for (auto sink_cell : jt->second) { - SigSpec A = sink_cell->getPort(ID::A); - RTLIL::Const mask = sink_cell->getParam(ID(LUT)); - int index = 0; - for (; index < GetSize(A); index++) - if (A[index] == a_bit) - break; - log_assert(index < GetSize(A)); - int i = 0; - while (i < GetSize(mask)) { - for (int j = 0; j < (1 << index); j++) - std::swap(mask[i+j], mask[i+j+(1 << index)]); - i += 1 << (index+1); - } - A[index] = y_bit; - sink_cell->setPort(ID::A, A); - sink_cell->setParam(ID(LUT), mask); - } - - // Since we have rewritten all sinks (which we know - // to be only LUTs) to be after the inverter, we can - // go ahead and clone the LUT with the expectation - // that the original driving LUT will become dangling - // and get cleaned away -clone_lut: - driver_mask = driver_lut->getParam(ID(LUT)); - for (auto &b : driver_mask.bits) { - if (b == RTLIL::State::S0) b = RTLIL::State::S1; - else if (b == RTLIL::State::S1) b = RTLIL::State::S0; - } - auto cell = module->addLut(NEW_ID, - driver_lut->getPort(ID::A), - y_bit, - driver_mask); - for (auto &bit : cell->connections_.at(ID::A)) { - bit.wire = module->wires_.at(remap_name(bit.wire->name)); - bit2sinks[bit].push_back(cell); - } - } - - // Now 'unexpose' those wires by undoing - // the expose operation -- remove them from PO/PI - // and re-connecting them back together - for (auto wire : module->wires()) { - auto it = wire->attributes.find(ID(abc9_scc_break)); - if (it != wire->attributes.end()) { - wire->attributes.erase(it); - log_assert(wire->port_output); - wire->port_output = false; - std::string name = wire->name.str(); - RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5)); - log_assert(i_wire); - log_assert(i_wire->port_input); - i_wire->port_input = false; - module->connect(i_wire, wire); - } - } - module->fixup_ports(); - - //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); - log("ABC RESULTS: input signals: %8d\n", in_wires); - log("ABC RESULTS: output signals: %8d\n", out_wires); - - design->remove(mapped_mod); - } - else - { - log("Don't call ABC as there is nothing to map.\n"); - } - - if (cleanup) - { - log("Removing temp directory.\n"); - remove_directory(tempdir_name); - } - - log_pop(); -} - -struct Abc9TechmapPass : public Pass { - Abc9TechmapPass() : Pass("abc9_map", "use ABC9 for technology mapping") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" abc9_map [options] [selection]\n"); - log("\n"); - log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); - log("library to a target architecture.\n"); - log("\n"); - log(" -exe \n"); -#ifdef ABCEXTERNAL - log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); -#else - log(" use the specified command instead of \"/yosys-abc\" to execute ABC.\n"); -#endif - log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n"); - log("\n"); - log(" -script \n"); - log(" use the specified ABC script file instead of the default script.\n"); - log("\n"); - log(" if starts with a plus sign (+), then the rest of the filename\n"); - log(" string is interpreted as the command string to be passed to ABC. The\n"); - log(" leading plus sign is removed and all commas (,) in the string are\n"); - log(" replaced with blanks before the string is passed to ABC.\n"); - log("\n"); - log(" if no -script parameter is given, the following scripts are used:\n"); - log("\n"); - log(" for -lut/-luts (only one LUT size):\n"); - log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); - log("\n"); - log(" for -lut/-luts (different LUT sizes):\n"); - log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); - log("\n"); - log(" -fast\n"); - log(" use different default scripts that are slightly faster (at the cost\n"); - log(" of output quality):\n"); - log("\n"); - log(" for -lut/-luts:\n"); - log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); - log("\n"); - log(" -D \n"); - log(" set delay target. the string {D} in the default scripts above is\n"); - log(" replaced by this option when used, and an empty string otherwise\n"); - log(" (indicating best possible delay).\n"); -// log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n"); -// log(" default scripts above.\n"); - log("\n"); -// log(" -S \n"); -// log(" maximum number of LUT inputs shared.\n"); -// log(" (replaces {S} in the default scripts above, default: -S 1)\n"); -// log("\n"); - log(" -lut \n"); - log(" generate netlist using luts of (max) the specified width.\n"); - log("\n"); - log(" -lut :\n"); - log(" generate netlist using luts of (max) the specified width . All\n"); - log(" luts with width <= have constant cost. for luts larger than \n"); - log(" the area cost doubles with each additional input bit. the delay cost\n"); - log(" is still constant for all lut widths.\n"); - log("\n"); - log(" -lut \n"); - log(" pass this file with lut library to ABC.\n"); - log("\n"); - log(" -luts ,,,:,..\n"); - log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); - log(" 2, 3, .. inputs.\n"); - log("\n"); -// log(" -dff\n"); -// log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n"); -// log(" clock domains are automatically partitioned in clock domains and each\n"); -// log(" domain is passed through ABC independently.\n"); -// log("\n"); -// log(" -clk [!][,[!]]\n"); -// log(" use only the specified clock domain. this is like -dff, but only FF\n"); -// log(" cells that belong to the specified clock domain are used.\n"); -// log("\n"); -// log(" -keepff\n"); -// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n"); -// log(" them, for example for equivalence checking.)\n"); -// log("\n"); - log(" -nocleanup\n"); - log(" when this option is used, the temporary files created by this pass\n"); - log(" are not removed. this is useful for debugging.\n"); - log("\n"); - log(" -showtmp\n"); - log(" print the temp dir name in log. usually this is suppressed so that the\n"); - log(" command output is identical across runs.\n"); - log("\n"); - log(" -markgroups\n"); - log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n"); - log(" this attribute is a unique integer for each ABC process started. This\n"); - log(" is useful for debugging the partitioning of clock domains.\n"); - log("\n"); - log(" -box \n"); - log(" pass this file with box library to ABC. Use with -lut.\n"); - log("\n"); - log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); - log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); - log("ABC on logic snippets extracted from your design. You will not get any useful\n"); - log("output when passing an ABC script that writes a file. Instead write your full\n"); - log("design as BLIF file with write_blif and then load that into ABC externally if\n"); - log("you want to use ABC to convert your design into another format.\n"); - log("\n"); - log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n"); - log_push(); - - assign_map.clear(); - -#ifdef ABCEXTERNAL - std::string exe_file = ABCEXTERNAL; -#else - std::string exe_file = proc_self_dirname() + "yosys-abc"; -#endif - std::string script_file, clk_str, box_file, lut_file; - std::string delay_target, lutin_shared = "-S 1", wire_delay; - bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; - bool show_tempdir = false; - bool nomfs = false; - vector lut_costs; - markgroups = false; - -#if 0 - cleanup = false; - show_tempdir = true; -#endif - -#ifdef _WIN32 -#ifndef ABCEXTERNAL - if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) - exe_file = proc_self_dirname() + "..\\yosys-abc"; -#endif -#endif - - size_t argidx; - char pwd [PATH_MAX]; - if (!getcwd(pwd, sizeof(pwd))) { - log_cmd_error("getcwd failed: %s\n", strerror(errno)); - log_abort(); - } - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-exe" && argidx+1 < args.size()) { - exe_file = args[++argidx]; - continue; - } - if (arg == "-script" && argidx+1 < args.size()) { - script_file = args[++argidx]; - rewrite_filename(script_file); - if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') - script_file = std::string(pwd) + "/" + script_file; - continue; - } - if (arg == "-D" && argidx+1 < args.size()) { - delay_target = "-D " + args[++argidx]; - continue; - } - //if (arg == "-S" && argidx+1 < args.size()) { - // lutin_shared = "-S " + args[++argidx]; - // continue; - //} - if (arg == "-lut" && argidx+1 < args.size()) { - string arg = args[++argidx]; - if (arg.find_first_not_of("0123456789:") == std::string::npos) { - size_t pos = arg.find_first_of(':'); - int lut_mode = 0, lut_mode2 = 0; - if (pos != string::npos) { - lut_mode = atoi(arg.substr(0, pos).c_str()); - lut_mode2 = atoi(arg.substr(pos+1).c_str()); - } else { - lut_mode = atoi(arg.c_str()); - lut_mode2 = lut_mode; - } - lut_costs.clear(); - for (int i = 0; i < lut_mode; i++) - lut_costs.push_back(1); - for (int i = lut_mode; i < lut_mode2; i++) - lut_costs.push_back(2 << (i - lut_mode)); - } - else { - lut_file = arg; - rewrite_filename(lut_file); - if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+') - lut_file = std::string(pwd) + "/" + lut_file; - } - continue; - } - if (arg == "-luts" && argidx+1 < args.size()) { - lut_costs.clear(); - for (auto &tok : split_tokens(args[++argidx], ",")) { - auto parts = split_tokens(tok, ":"); - if (GetSize(parts) == 0 && !lut_costs.empty()) - lut_costs.push_back(lut_costs.back()); - else if (GetSize(parts) == 1) - lut_costs.push_back(atoi(parts.at(0).c_str())); - else if (GetSize(parts) == 2) - while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) - lut_costs.push_back(atoi(parts.at(1).c_str())); - else - log_cmd_error("Invalid -luts syntax.\n"); - } - continue; - } - if (arg == "-fast") { - fast_mode = true; - continue; - } - //if (arg == "-dff") { - // dff_mode = true; - // continue; - //} - //if (arg == "-clk" && argidx+1 < args.size()) { - // clk_str = args[++argidx]; - // dff_mode = true; - // continue; - //} - //if (arg == "-keepff") { - // keepff = true; - // continue; - //} - if (arg == "-nocleanup") { - cleanup = false; - continue; - } - if (arg == "-showtmp") { - show_tempdir = true; - continue; - } - if (arg == "-markgroups") { - markgroups = true; - continue; - } - if (arg == "-box" && argidx+1 < args.size()) { - box_file = args[++argidx]; - continue; - } - if (arg == "-W" && argidx+1 < args.size()) { - wire_delay = "-W " + args[++argidx]; - continue; - } - if (arg == "-nomfs") { - nomfs = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - // ABC expects a box file for XAIG - if (box_file.empty()) - box_file = "+/dummy.box"; - - rewrite_filename(box_file); - if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') - box_file = std::string(pwd) + "/" + box_file; - - dict box_lookup; - for (auto m : design->modules()) { - auto it = m->attributes.find(ID(abc9_box_id)); - if (it == m->attributes.end()) - continue; - if (m->name.begins_with("$paramod")) - continue; - auto id = it->second.as_int(); - auto r = box_lookup.insert(std::make_pair(id, m->name)); - if (!r.second) - log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", - log_id(m), id, log_id(r.first->second)); - log_assert(r.second); - - RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; - for (auto p : m->ports) { - auto w = m->wire(p); - log_assert(w); - if (w->attributes.count(ID(abc9_carry))) { - if (w->port_input) { - if (carry_in) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); - carry_in = w; - } - else if (w->port_output) { - if (carry_out) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); - carry_out = w; - } - } - } - if (carry_in || carry_out) { - if (carry_in && !carry_out) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); - if (!carry_in && carry_out) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); - // Make carry_in the last PI, and carry_out the last PO - // since ABC requires it this way - auto &ports = m->ports; - for (auto it = ports.begin(); it != ports.end(); ) { - RTLIL::Wire* w = m->wire(*it); - log_assert(w); - if (w == carry_in || w == carry_out) { - it = ports.erase(it); - continue; - } - if (w->port_id > carry_in->port_id) - --w->port_id; - if (w->port_id > carry_out->port_id) - --w->port_id; - log_assert(w->port_input || w->port_output); - log_assert(ports[w->port_id-1] == w->name); - ++it; - } - ports.push_back(carry_in->name); - carry_in->port_id = ports.size(); - ports.push_back(carry_out->name); - carry_out->port_id = ports.size(); - } - } - - for (auto mod : design->selected_modules()) - { - if (mod->attributes.count(ID(abc9_box_id))) - continue; - - if (mod->processes.size() > 0) { - log("Skipping module %s as it contains processes.\n", log_id(mod)); - continue; - } - - assign_map.set(mod); - - if (!dff_mode || !clk_str.empty()) { - abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay, box_lookup, nomfs); - continue; - } - - CellTypes ct(design); - - std::vector all_cells = mod->selected_cells(); - std::set unassigned_cells(all_cells.begin(), all_cells.end()); - - std::set expand_queue, next_expand_queue; - std::set expand_queue_up, next_expand_queue_up; - std::set expand_queue_down, next_expand_queue_down; - - typedef tuple clkdomain_t; - std::map> assigned_cells; - std::map assigned_cells_reverse; - - std::map> cell_to_bit, cell_to_bit_up, cell_to_bit_down; - std::map> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - - for (auto cell : all_cells) - { - clkdomain_t key; - - for (auto &conn : cell->connections()) - for (auto bit : conn.second) { - bit = assign_map(bit); - if (bit.wire != nullptr) { - cell_to_bit[cell].insert(bit); - bit_to_cell[bit].insert(cell); - if (ct.cell_input(cell->type, conn.first)) { - cell_to_bit_up[cell].insert(bit); - bit_to_cell_down[bit].insert(cell); - } - if (ct.cell_output(cell->type, conn.first)) { - cell_to_bit_down[cell].insert(bit); - bit_to_cell_up[bit].insert(cell); - } - } - } - - if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) - { - key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); - } - else - if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) - { - bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); - bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)); - key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E)))); - } - else - continue; - - unassigned_cells.erase(cell); - expand_queue.insert(cell); - expand_queue_up.insert(cell); - expand_queue_down.insert(cell); - - assigned_cells[key].push_back(cell); - assigned_cells_reverse[cell] = key; - } - - while (!expand_queue_up.empty() || !expand_queue_down.empty()) - { - if (!expand_queue_up.empty()) - { - RTLIL::Cell *cell = *expand_queue_up.begin(); - clkdomain_t key = assigned_cells_reverse.at(cell); - expand_queue_up.erase(cell); - - for (auto bit : cell_to_bit_up[cell]) - for (auto c : bit_to_cell_up[bit]) - if (unassigned_cells.count(c)) { - unassigned_cells.erase(c); - next_expand_queue_up.insert(c); - assigned_cells[key].push_back(c); - assigned_cells_reverse[c] = key; - expand_queue.insert(c); - } - } - - if (!expand_queue_down.empty()) - { - RTLIL::Cell *cell = *expand_queue_down.begin(); - clkdomain_t key = assigned_cells_reverse.at(cell); - expand_queue_down.erase(cell); - - for (auto bit : cell_to_bit_down[cell]) - for (auto c : bit_to_cell_down[bit]) - if (unassigned_cells.count(c)) { - unassigned_cells.erase(c); - next_expand_queue_up.insert(c); - assigned_cells[key].push_back(c); - assigned_cells_reverse[c] = key; - expand_queue.insert(c); - } - } - - if (expand_queue_up.empty() && expand_queue_down.empty()) { - expand_queue_up.swap(next_expand_queue_up); - expand_queue_down.swap(next_expand_queue_down); - } - } - - while (!expand_queue.empty()) - { - RTLIL::Cell *cell = *expand_queue.begin(); - clkdomain_t key = assigned_cells_reverse.at(cell); - expand_queue.erase(cell); - - for (auto bit : cell_to_bit.at(cell)) { - for (auto c : bit_to_cell[bit]) - if (unassigned_cells.count(c)) { - unassigned_cells.erase(c); - next_expand_queue.insert(c); - assigned_cells[key].push_back(c); - assigned_cells_reverse[c] = key; - } - bit_to_cell[bit].clear(); - } - - if (expand_queue.empty()) - expand_queue.swap(next_expand_queue); - } - - clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec()); - for (auto cell : unassigned_cells) { - assigned_cells[key].push_back(cell); - assigned_cells_reverse[cell] = key; - } - - log_header(design, "Summary of detected clock domains:\n"); - for (auto &it : assigned_cells) - log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second), - std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), - std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); - - for (auto &it : assigned_cells) { - clk_polarity = std::get<0>(it.first); - clk_sig = assign_map(std::get<1>(it.first)); - en_polarity = std::get<2>(it.first); - en_sig = assign_map(std::get<3>(it.first)); - abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", - keepff, delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay, box_lookup, nomfs); - assign_map.set(mod); - } - } - - assign_map.clear(); - - log_pop(); - } -} Abc9TechmapPass; - -PRIVATE_NAMESPACE_END -- cgit v1.2.3 From dbffbeef5c2df2345c786e195d2006d7bb23578a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 16:21:20 -0800 Subject: Fix struct name --- passes/techmap/abc9_map.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index 6c431b185..7d53db5ea 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -650,8 +650,8 @@ clone_lut: log_pop(); } -struct Abc9TechmapPass : public Pass { - Abc9TechmapPass() : Pass("abc9_map", "use ABC9 for technology mapping") { } +struct Abc9MapPass : public Pass { + Abc9MapPass() : Pass("abc9_map", "use ABC9 for technology mapping") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -1017,6 +1017,6 @@ struct Abc9TechmapPass : public Pass { log_pop(); } -} Abc9TechmapPass; +} Abc9MapPass; PRIVATE_NAMESPACE_END -- cgit v1.2.3 From 88b9c8d46ddac513831dc79d370f8abb23ab68fc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 16:29:08 -0800 Subject: Restore count_outputs, move process check to abc --- passes/techmap/abc9.cc | 10 +++++++++- passes/techmap/abc9_map.cc | 14 ++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index d507a6973..ac64ae86d 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -164,7 +164,7 @@ struct Abc9Pass : public ScriptPass map_cmd << " " << arg << " " << args[++argidx]; continue; } - if (arg == "-fast" || /*arg == "-dff" ||*/ arg == "-keepff" + if (arg == "-fast" /*|| arg == "-nocleanup"*/ || arg == "-showtmp" || arg == "-markgroups" || arg == "-nomfs") { map_cmd << " " << arg; @@ -189,6 +189,14 @@ struct Abc9Pass : public ScriptPass active_design->selection_stack.emplace_back(false); for (auto mod : selected_modules) { + if (module->attributes.count(ID(abc9_box_id))) + continue; + + if (module->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(module)); + continue; + } + log_push(); active_design->selection().select(mod); diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index 7d53db5ea..83f90a762 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -268,15 +268,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip log_push(); - // FIXME: - /*int count_outputs = design->scratchpad_get_int("write_xaiger.num_outputs"); + int count_outputs = design->scratchpad_get_int("write_xaiger.num_outputs"); log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", design->scratchpad_get_int("write_xaiger.num_ands"), design->scratchpad_get_int("write_xaiger.num_wires"), design->scratchpad_get_int("write_xaiger.num_inputs"), count_outputs); - if (count_outputs > 0)*/ { + if (count_outputs > 0) { std::string buffer; std::ifstream ifs; #if 0 @@ -965,13 +964,8 @@ struct Abc9MapPass : public Pass { CellTypes ct(design); for (auto module : design->selected_modules()) { - if (module->attributes.count(ID(abc9_box_id))) - continue; - - if (module->processes.size() > 0) { - log("Skipping module %s as it contains processes.\n", log_id(module)); - continue; - } + if (module->processes.size() > 0) + log_error("Module '%s' has processes!\n", log_id(module)); assign_map.set(module); -- cgit v1.2.3 From 16c4ec7edaa3cb66ced2f856d3c48f30d7d2acf1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 16:36:33 -0800 Subject: Add abc9_ops -prep_dff --- passes/techmap/abc9.cc | 8 ++++---- passes/techmap/abc9_map.cc | 35 ----------------------------------- passes/techmap/abc9_ops.cc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 39 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index ac64ae86d..cd798cfbe 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -189,11 +189,11 @@ struct Abc9Pass : public ScriptPass active_design->selection_stack.emplace_back(false); for (auto mod : selected_modules) { - if (module->attributes.count(ID(abc9_box_id))) + if (mod->attributes.count(ID(abc9_box_id))) continue; - if (module->processes.size() > 0) { - log("Skipping module %s as it contains processes.\n", log_id(module)); + if (mod->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; } @@ -207,7 +207,7 @@ struct Abc9Pass : public ScriptPass tempdir_name = make_temp_dir(tempdir_name); run("scc -set_attr abc9_scc_id {}"); - run("abc9_ops -break_scc"); + run("abc9_ops -break_scc -prep_dff"); run("aigmap"); run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), "write_xaiger -map /input.sym /input.xaig"); diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index 83f90a762..6b9d0afff 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -960,48 +960,13 @@ struct Abc9MapPass : public Pass { } } - SigMap assign_map; - CellTypes ct(design); for (auto module : design->selected_modules()) { if (module->processes.size() > 0) log_error("Module '%s' has processes!\n", log_id(module)); - assign_map.set(module); - - typedef SigSpec clkdomain_t; - dict clk_to_mergeability; - const std::vector all_cells = module->selected_cells(); - for (auto cell : all_cells) { - auto inst_module = design->module(cell->type); - if (!inst_module || !inst_module->attributes.count("\\abc9_flop") - || cell->get_bool_attribute("\\abc9_keep")) - continue; - - Wire *abc9_clock_wire = module->wire(stringf("%s.$abc9_clock", cell->name.c_str())); - if (abc9_clock_wire == NULL) - log_error("'%s$abc9_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); - - clkdomain_t key(abc9_clock); - - auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); - auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second)); - log_assert(r2.second); - - Wire *abc9_init_wire = module->wire(stringf("%s.$abc9_init", cell->name.c_str())); - if (abc9_init_wire == NULL) - log_error("'%s.$abc9_init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - log_assert(GetSize(abc9_init_wire) == 1); - SigSpec abc9_init = assign_map(abc9_init_wire); - if (!abc9_init.is_fully_const()) - log_error("'%s.$abc9_init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); - log_assert(r2.second); - } - design->selected_active_module = module->name.str(); abc9_module(design, module, script_file, exe_file, lut_costs, delay_target, lutin_shared, fast_mode, all_cells, show_tempdir, diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 4c30efd06..3e7e5ec7f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -19,6 +19,7 @@ */ #include "kernel/register.h" +#include "kernel/sigtools.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -95,6 +96,44 @@ void unbreak_scc(RTLIL::Module *module) { module->fixup_ports(); } +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; + + for (auto cell : module->selected_cells()) { + auto inst_module = design->module(cell->type); + if (!inst_module || !inst_module->attributes.count("\\abc9_flop") + || cell->get_bool_attribute("\\abc9_keep")) + continue; + + Wire *abc9_clock_wire = module->wire(stringf("%s.$abc9_clock", cell->name.c_str())); + if (abc9_clock_wire == NULL) + log_error("'%s$abc9_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); + + clkdomain_t key(abc9_clock); + + auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); + auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second)); + log_assert(r2.second); + + Wire *abc9_init_wire = module->wire(stringf("%s.$abc9_init", cell->name.c_str())); + if (abc9_init_wire == NULL) + log_error("'%s.$abc9_init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + log_assert(GetSize(abc9_init_wire) == 1); + SigSpec abc9_init = assign_map(abc9_init_wire); + if (!abc9_init.is_fully_const()) + log_error("'%s.$abc9_init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); + log_assert(r2.second); + } +} + struct Abc9PrepPass : public Pass { Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { } void help() YS_OVERRIDE @@ -111,6 +150,7 @@ struct Abc9PrepPass : public Pass { bool break_scc_mode = false; bool unbreak_scc_mode = false; + bool prep_dff_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -123,6 +163,10 @@ struct Abc9PrepPass : public Pass { unbreak_scc_mode = true; continue; } + if (arg == "-prep_dff") { + prep_dff_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -132,6 +176,8 @@ struct Abc9PrepPass : public Pass { break_scc(mod); if (unbreak_scc_mode) unbreak_scc(mod); + if (prep_dff_mode) + prep_dff(mod); } } } Abc9PrepPass; -- cgit v1.2.3 From b50de28c045e786f3140c95ab23cb2f426918093 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 18:00:49 -0800 Subject: Add abc9_ops -prep_holes --- passes/techmap/abc9.cc | 2 +- passes/techmap/abc9_ops.cc | 314 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 313 insertions(+), 3 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index cd798cfbe..e11b15065 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -207,7 +207,7 @@ struct Abc9Pass : public ScriptPass tempdir_name = make_temp_dir(tempdir_name); run("scc -set_attr abc9_scc_id {}"); - run("abc9_ops -break_scc -prep_dff"); + run("abc9_ops -break_scc -prep_dff -prep_holes"); run("aigmap"); run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), "write_xaiger -map /input.sym /input.xaig"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 3e7e5ec7f..8eb935e1f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -20,6 +20,7 @@ #include "kernel/register.h" #include "kernel/sigtools.h" +#include "kernel/utils.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -75,7 +76,8 @@ void break_scc(RTLIL::Module *module) module->fixup_ports(); } -void unbreak_scc(RTLIL::Module *module) { +void unbreak_scc(RTLIL::Module *module) +{ // Now 'unexpose' those wires by undoing // the expose operation -- remove them from PO/PI // and re-connecting them back together @@ -96,7 +98,8 @@ void unbreak_scc(RTLIL::Module *module) { module->fixup_ports(); } -void prep_dff(RTLIL::Module *module) { +void prep_dff(RTLIL::Module *module) +{ auto design = module->design; log_assert(design); @@ -134,6 +137,306 @@ void prep_dff(RTLIL::Module *module) { } } +void prep_holes(RTLIL::Module *module) +{ + auto design = module->design; + log_assert(design); + + SigMap sigmap(module); + + // TODO: Speed up toposort -- ultimately we care about + // box ordering, but not individual AIG cells + dict> bit_drivers, bit_users; + TopoSort toposort; + bool abc9_box_seen = false; + + for (auto cell : module->selected_cells()) { + if (cell->type == "$_NOT_") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + toposort.node(cell->name); + bit_users[A].insert(cell->name); + bit_drivers[Y].insert(cell->name); + continue; + } + + if (cell->type == "$_AND_") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit B = sigmap(cell->getPort("\\B").as_bit()); + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + toposort.node(cell->name); + bit_users[A].insert(cell->name); + bit_users[B].insert(cell->name); + bit_drivers[Y].insert(cell->name); + continue; + } + + if (cell->type == "$__ABC9_FF_") + continue; + + RTLIL::Module* inst_module = design->module(cell->type); + if (inst_module) { + if (!inst_module->attributes.count("\\abc9_box_id") || cell->get_bool_attribute("\\abc9_keep")) + continue; + + for (const auto &conn : cell->connections()) { + auto port_wire = inst_module->wire(conn.first); + // Ignore inout for the sake of topographical ordering + if (port_wire->port_input && !port_wire->port_output) + for (auto bit : sigmap(conn.second)) + bit_users[bit].insert(cell->name); + if (port_wire->port_output) + for (auto bit : sigmap(conn.second)) + bit_drivers[bit].insert(cell->name); + } + + abc9_box_seen = true; + + toposort.node(cell->name); + } + } + + if (!abc9_box_seen) + return; + + for (auto &it : bit_users) + if (bit_drivers.count(it.first)) + for (auto driver_cell : bit_drivers.at(it.first)) + for (auto user_cell : it.second) + toposort.edge(driver_cell, user_cell); + +#if 0 + toposort.analyze_loops = true; +#endif + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); +#if 0 + unsigned i = 0; + for (auto &it : toposort.loops) { + log(" loop %d\n", i++); + for (auto cell_name : it) { + auto cell = module->cell(cell_name); + log_assert(cell); + log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); + } + } +#endif + log_assert(no_loops); + + vector box_list; + for (auto cell_name : toposort.sorted) { + RTLIL::Cell *cell = module->cell(cell_name); + log_assert(cell); + + RTLIL::Module* box_module = design->module(cell->type); + if (!box_module || !box_module->attributes.count("\\abc9_box_id") + || cell->get_bool_attribute("\\abc9_keep")) + continue; + + bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); + + // Fully pad all unused input connections of this box cell with S0 + // Fully pad all undriven output connections of this box cell with anonymous wires + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + for (const auto &port_name : box_module->ports) { + RTLIL::Wire* w = box_module->wire(port_name); + log_assert(w); + auto it = cell->connections_.find(port_name); + if (w->port_input) { + RTLIL::SigSpec rhs; + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + rhs = RTLIL::SigSpec(State::S0, GetSize(w)); + cell->setPort(port_name, rhs); + } + } + if (w->port_output) { + RTLIL::SigSpec rhs; + auto it = cell->connections_.find(w->name); + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + Wire *wire = module->addWire(NEW_ID, GetSize(w)); + if (blackbox) + wire->set_bool_attribute(ID(abc9_padding)); + rhs = wire; + cell->setPort(port_name, rhs); + } + } + } + + box_list.emplace_back(cell); + } + log_assert(!box_list.empty()); + + RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); + log_assert(holes_module); + + dict cell_cache; + + int port_id = 1; + for (auto cell : box_list) { + RTLIL::Module* orig_box_module = design->module(cell->type); + log_assert(orig_box_module); + IdString derived_name = orig_box_module->derive(design, cell->parameters); + RTLIL::Module* box_module = design->module(derived_name); + if (box_module->has_processes()) + Pass::call_on_module(design, box_module, "proc"); + + int box_inputs = 0; + auto r = cell_cache.insert(std::make_pair(derived_name, nullptr)); + Cell *holes_cell = r.first->second; + if (r.second && box_module->get_bool_attribute("\\whitebox")) { + holes_cell = holes_module->addCell(cell->name, cell->type); + holes_cell->parameters = cell->parameters; + r.first->second = holes_cell; + + // Since Module::derive() will create a new module, there + // is a chance that the ports will be alphabetically ordered + // again, which is a problem when carry-chains are involved. + // Inherit the port ordering from the original module here... + // (and set the port_id below, when iterating through those) + log_assert(GetSize(box_module->ports) == GetSize(orig_box_module->ports)); + box_module->ports = orig_box_module->ports; + } + + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + int box_port_id = 1; + for (const auto &port_name : box_module->ports) { + RTLIL::Wire *w = box_module->wire(port_name); + log_assert(w); + if (r.second) + w->port_id = box_port_id++; + RTLIL::Wire *holes_wire; + RTLIL::SigSpec port_sig; + if (w->port_input) + for (int i = 0; i < GetSize(w); i++) { + box_inputs++; + 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); + } + if (holes_cell) + port_sig.append(holes_wire); + } + if (w->port_output) + for (int i = 0; i < GetSize(w); i++) { + if (GetSize(w) == 1) + holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(w->name))); + else + holes_wire = holes_module->addWire(stringf("$abc%s.%s[%d]", cell->name.c_str(), log_id(w->name), i)); + holes_wire->port_output = true; + holes_wire->port_id = port_id++; + holes_module->ports.push_back(holes_wire->name); + if (holes_cell) + port_sig.append(holes_wire); + else + holes_module->connect(holes_wire, State::S0); + } + if (!port_sig.empty()) { + if (r.second) + holes_cell->setPort(w->name, port_sig); + else + holes_module->connect(holes_cell->getPort(w->name), port_sig); + } + } + + // For flops only, create an extra 1-bit input that drives a new wire + // called ".$abc9_currQ" that is used below + if (box_module->get_bool_attribute("\\abc9_flop")) { + log_assert(holes_cell); + + 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 *w = holes_module->addWire(stringf("%s.$abc9_currQ", cell->name.c_str())); + holes_module->connect(w, holes_wire); + } + } + + log_push(); + + // NB: fixup_ports() will sort ports by name + //holes_module->fixup_ports(); + holes_module->check(); + + // Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger + // since boxes may contain parameters in which case `flatten` would have + // created a new $paramod ... + Pass::call_on_module(design, holes_module, "flatten -wb; techmap; aigmap"); + + dict replace; + for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { + auto cell = it->second; + if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + // Remove the DFF cell from what needs to be a combinatorial box + it = holes_module->cells_.erase(it); + 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 the combinatorial control logic that feeds the box + // (i.e. clock enable, synchronous reset, etc.) + replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,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 input port) we inserted above + Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); + log_assert(currQ); + holes_module->connect(Q, currQ); + continue; + } + else if (!cell->type.in("$_NOT_", "$_AND_")) + log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n"); + ++it; + } + + for (auto &conn : holes_module->connections_) { + auto it = replace.find(conn); + if (it != replace.end()) + conn = it->second; + } + + // Move into a new (temporary) design so that "clean" will only + // operate (and run checks on) this one module + RTLIL::Design *holes_design = new RTLIL::Design; + holes_design->add(holes_module); + Pass::call(holes_design, "opt -purge"); + holes_design->modules_.erase(holes_module->name); + holes_module->design = design; + + log_pop(); +} + struct Abc9PrepPass : public Pass { Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { } void help() YS_OVERRIDE @@ -151,6 +454,7 @@ struct Abc9PrepPass : public Pass { bool break_scc_mode = false; bool unbreak_scc_mode = false; bool prep_dff_mode = false; + bool prep_holes_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -167,6 +471,10 @@ struct Abc9PrepPass : public Pass { prep_dff_mode = true; continue; } + if (arg == "-prep_holes") { + prep_holes_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -178,6 +486,8 @@ struct Abc9PrepPass : public Pass { unbreak_scc(mod); if (prep_dff_mode) prep_dff(mod); + if (prep_holes_mode) + prep_holes(mod); } } } Abc9PrepPass; -- cgit v1.2.3 From 0317a2b476f5ec78cab35b79a02d166c84c0f53e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 18:46:22 -0800 Subject: holes_module to be whitebox --- passes/techmap/abc9_ops.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 8eb935e1f..e65b16fc6 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -434,6 +434,8 @@ void prep_holes(RTLIL::Module *module) holes_design->modules_.erase(holes_module->name); holes_module->design = design; + holes_module->set_bool_attribute(ID::whitebox); + log_pop(); } @@ -480,6 +482,14 @@ struct Abc9PrepPass : public Pass { extra_args(args, argidx, design); for (auto mod : design->selected_modules()) { + if (mod->get_blackbox_attribute()) + continue; + + if (mod->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(mod)); + continue; + } + if (break_scc_mode) break_scc(mod); if (unbreak_scc_mode) -- cgit v1.2.3 From 52f649dcfd2bba3e4efc219b53e7937281a658c6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 18:47:06 -0800 Subject: Use function arg --- passes/techmap/abc9_map.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index 6b9d0afff..9764d057c 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -198,7 +198,7 @@ struct abc9_output_filter void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string script_file, std::string exe_file, vector lut_costs, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, - const std::vector &/*cells*/, bool show_tempdir, std::string box_file, std::string lut_file, + const std::vector &cells, bool show_tempdir, std::string box_file, std::string lut_file, std::string wire_delay, const dict &box_lookup, bool nomfs, std::string tempdir_name ) { @@ -359,7 +359,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip dict abc9_box; vector boxes; - for (auto cell : module->selected_cells()) { + for (auto cell : cells) { if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) { module->remove(cell); continue; @@ -960,18 +960,18 @@ struct Abc9MapPass : public Pass { } } - for (auto module : design->selected_modules()) + for (auto mod : design->selected_modules()) { - if (module->processes.size() > 0) - log_error("Module '%s' has processes!\n", log_id(module)); + if (mod->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(mod)); + continue; + } - const std::vector all_cells = module->selected_cells(); + const std::vector all_cells = mod->selected_cells(); - design->selected_active_module = module->name.str(); - abc9_module(design, module, script_file, exe_file, lut_costs, + abc9_module(design, mod, script_file, exe_file, lut_costs, delay_target, lutin_shared, fast_mode, all_cells, show_tempdir, box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name); - design->selected_active_module.clear(); } log_pop(); -- cgit v1.2.3 From b42b64e8ed713b0e9810f18db7cafcf356e2b4f6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 19:23:54 -0800 Subject: Move Pass::call() out of abc9_ops into abc9 --- passes/techmap/abc9.cc | 14 +++++- passes/techmap/abc9_ops.cc | 113 +++++++++++++++++++-------------------------- 2 files changed, 59 insertions(+), 68 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index e11b15065..7d922df56 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -185,11 +185,21 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { + run("abc9_ops -prep_holes"); + run("select -set abc9_holes A:abc9_holes"); + run("flatten -wb @abc9_holes"); + run("techmap @abc9_holes"); + run("aigmap @abc9_holes"); + run("select -list @abc9_holes"); + run("abc9_ops -prep_dff"); + run("opt -purge @abc9_holes"); + run("setattr -mod -set whitebox 1 @abc9_holes"); + auto selected_modules = active_design->selected_modules(); active_design->selection_stack.emplace_back(false); for (auto mod : selected_modules) { - if (mod->attributes.count(ID(abc9_box_id))) + if (mod->get_blackbox_attribute()) continue; if (mod->processes.size() > 0) { @@ -207,7 +217,7 @@ struct Abc9Pass : public ScriptPass tempdir_name = make_temp_dir(tempdir_name); run("scc -set_attr abc9_scc_id {}"); - run("abc9_ops -break_scc -prep_dff -prep_holes"); + run("abc9_ops -break_scc"); run("aigmap"); run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), "write_xaiger -map /input.sym /input.xaig"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index e65b16fc6..b52382972 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -135,6 +135,50 @@ void prep_dff(RTLIL::Module *module) r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); log_assert(r2.second); } + + RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); + log_assert(holes_module); + + dict replace; + for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { + auto cell = it->second; + if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + // Remove the DFF cell from what needs to be a combinatorial box + it = holes_module->cells_.erase(it); + 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 the combinatorial control logic that feeds the box + // (i.e. clock enable, synchronous reset, etc.) + replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,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 input port) we inserted above + Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); + log_assert(currQ); + holes_module->connect(Q, currQ); + } + else + ++it; + } + + for (auto &conn : holes_module->connections_) { + auto it = replace.find(conn); + if (it != replace.end()) + conn = it->second; + } } void prep_holes(RTLIL::Module *module) @@ -280,6 +324,7 @@ void prep_holes(RTLIL::Module *module) RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); log_assert(holes_module); + holes_module->set_bool_attribute("\\abc9_holes"); dict cell_cache; @@ -371,72 +416,6 @@ void prep_holes(RTLIL::Module *module) holes_module->connect(w, holes_wire); } } - - log_push(); - - // NB: fixup_ports() will sort ports by name - //holes_module->fixup_ports(); - holes_module->check(); - - // Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger - // since boxes may contain parameters in which case `flatten` would have - // created a new $paramod ... - Pass::call_on_module(design, holes_module, "flatten -wb; techmap; aigmap"); - - dict replace; - for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { - auto cell = it->second; - if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", - "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { - SigBit D = cell->getPort("\\D"); - SigBit Q = cell->getPort("\\Q"); - // Remove the DFF cell from what needs to be a combinatorial box - it = holes_module->cells_.erase(it); - 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 the combinatorial control logic that feeds the box - // (i.e. clock enable, synchronous reset, etc.) - replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,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 input port) we inserted above - Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); - log_assert(currQ); - holes_module->connect(Q, currQ); - continue; - } - else if (!cell->type.in("$_NOT_", "$_AND_")) - log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n"); - ++it; - } - - for (auto &conn : holes_module->connections_) { - auto it = replace.find(conn); - if (it != replace.end()) - conn = it->second; - } - - // Move into a new (temporary) design so that "clean" will only - // operate (and run checks on) this one module - RTLIL::Design *holes_design = new RTLIL::Design; - holes_design->add(holes_module); - Pass::call(holes_design, "opt -purge"); - holes_design->modules_.erase(holes_module->name); - holes_module->design = design; - - holes_module->set_bool_attribute(ID::whitebox); - - log_pop(); } struct Abc9PrepPass : public Pass { @@ -484,6 +463,8 @@ struct Abc9PrepPass : public Pass { for (auto mod : design->selected_modules()) { if (mod->get_blackbox_attribute()) continue; + if (mod->get_bool_attribute("\\abc9_holes")) + continue; if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); -- cgit v1.2.3 From a367f703ea0633a4a6289415ae8a4545440ee705 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 22:56:19 -0800 Subject: Rename struct --- passes/techmap/abc9_ops.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index b52382972..271b76a39 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -418,8 +418,8 @@ void prep_holes(RTLIL::Module *module) } } -struct Abc9PrepPass : public Pass { - Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { } +struct Abc9OpsPass : public Pass { + Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -481,6 +481,6 @@ struct Abc9PrepPass : public Pass { prep_holes(mod); } } -} Abc9PrepPass; +} Abc9OpsPass; PRIVATE_NAMESPACE_END -- cgit v1.2.3 From f1bf44ae8f66e81b7de6a2ec47c4a9dffe7e6587 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 22:58:39 -0800 Subject: abc9_ops -prep_dff cope with lack of holes module --- passes/techmap/abc9_ops.cc | 76 +++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 271b76a39..019868adb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -137,47 +137,47 @@ void prep_dff(RTLIL::Module *module) } RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); - log_assert(holes_module); - - dict replace; - for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { - auto cell = it->second; - if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", - "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { - SigBit D = cell->getPort("\\D"); - SigBit Q = cell->getPort("\\Q"); - // Remove the DFF cell from what needs to be a combinatorial box - it = holes_module->cells_.erase(it); - Wire *port; - if (GetSize(Q.wire) == 1) - port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); + if (holes_module) { + dict replace; + for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { + auto cell = it->second; + if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + // Remove the DFF cell from what needs to be a combinatorial box + it = holes_module->cells_.erase(it); + 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 the combinatorial control logic that feeds the box + // (i.e. clock enable, synchronous reset, etc.) + replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,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 input port) we inserted above + Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); + log_assert(currQ); + holes_module->connect(Q, currQ); + } 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 the combinatorial control logic that feeds the box - // (i.e. clock enable, synchronous reset, etc.) - replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,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 input port) we inserted above - Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); - log_assert(currQ); - holes_module->connect(Q, currQ); + ++it; } - else - ++it; - } - for (auto &conn : holes_module->connections_) { - auto it = replace.find(conn); - if (it != replace.end()) - conn = it->second; + for (auto &conn : holes_module->connections_) { + auto it = replace.find(conn); + if (it != replace.end()) + conn = it->second; + } } } -- cgit v1.2.3 From dacdc6cc941015aff45d1fde4d5365ab5e36e883 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 22:59:14 -0800 Subject: Remove abc9 -clk option --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 9e1318700..f44e3df06 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -150,7 +150,7 @@ struct Abc9Pass : public ScriptPass std::string arg = args[argidx]; if ((arg == "-exe" || arg == "-script" || arg == "-D" || /* arg == "-S" || */ arg == "-lut" || arg == "-luts" || - arg == "-clk" || arg == "-box" || arg == "-W") && + arg == "-box" || arg == "-W") && argidx+1 < args.size()) { map_cmd << " " << arg << " " << args[++argidx]; continue; -- cgit v1.2.3 From 222e5e58ad1ae8845797a2afb63cdcb8c2396401 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 2 Jan 2020 15:58:45 -0800 Subject: Cleanup --- passes/techmap/abc9.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index a7e748ce7..8e17460e1 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -190,11 +190,10 @@ struct Abc9Pass : public ScriptPass run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); run("aigmap @abc9_holes"); - run("select -list @abc9_holes"); if (dff_mode) run("abc9_ops -prep_dff"); run("opt -purge @abc9_holes"); - run("setattr -mod -set whitebox 1 @abc9_holes"); + run("wbflip @abc9_holes"); auto selected_modules = active_design->selected_modules(); active_design->selection_stack.emplace_back(false); -- cgit v1.2.3 From 7fe268fcdb17d28dbb187d4c5c3b53e648c190ca Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 2 Jan 2020 16:00:26 -0800 Subject: Move scc operations out of inner loop --- passes/techmap/abc9.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 8e17460e1..df59ff857 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -189,6 +189,8 @@ struct Abc9Pass : public ScriptPass run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); + run("scc -set_attr abc9_scc_id {}"); + run("abc9_ops -break_scc"); run("aigmap @abc9_holes"); if (dff_mode) run("abc9_ops -prep_dff"); @@ -207,8 +209,6 @@ struct Abc9Pass : public ScriptPass continue; } - log_push(); - active_design->selection().select(mod); std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; @@ -216,14 +216,10 @@ struct Abc9Pass : public ScriptPass tempdir_name[0] = tempdir_name[4] = '_'; tempdir_name = make_temp_dir(tempdir_name); - run("scc -set_attr abc9_scc_id {}"); - run("abc9_ops -break_scc"); - run("aigmap"); run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), "write_xaiger -map /input.sym /input.xaig"); run(stringf("%s -tempdir %s", map_cmd.str().c_str(), tempdir_name.c_str()), "abc9_map [options] -tempdir "); - run("abc9_ops -unbreak_scc"); if (cleanup) { @@ -232,11 +228,11 @@ struct Abc9Pass : public ScriptPass } active_design->selection().selected_modules.clear(); - - log_pop(); } active_design->selection_stack.pop_back(); + + run("abc9_ops -unbreak_scc"); } } Abc9Pass; -- cgit v1.2.3 From 4eaf41505256fc6f20065b3e5a64d74e607b15e7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 2 Jan 2020 16:13:44 -0800 Subject: aigmap everything --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index df59ff857..e7fcb9165 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -191,7 +191,7 @@ struct Abc9Pass : public ScriptPass run("techmap @abc9_holes"); run("scc -set_attr abc9_scc_id {}"); run("abc9_ops -break_scc"); - run("aigmap @abc9_holes"); + run("aigmap"); if (dff_mode) run("abc9_ops -prep_dff"); run("opt -purge @abc9_holes"); -- cgit v1.2.3 From a050f9c80887f9962c326566c1f351c991e0c8b0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 2 Jan 2020 16:14:04 -0800 Subject: Remove a few log_{push,pop}() --- passes/techmap/abc9_map.cc | 7 ------- passes/techmap/abc9_ops.cc | 1 - 2 files changed, 8 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index 9b56f04a8..171289c6d 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -266,8 +266,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip fprintf(f, "%s\n", abc9_script.c_str()); fclose(f); - log_push(); - int count_outputs = design->scratchpad_get_int("write_xaiger.num_outputs"); log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", design->scratchpad_get_int("write_xaiger.num_ands"), @@ -645,8 +643,6 @@ clone_lut: //{ // log("Don't call ABC as there is nothing to map.\n"); //} - - log_pop(); } struct Abc9MapPass : public Pass { @@ -759,7 +755,6 @@ struct Abc9MapPass : public Pass { void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n"); - log_push(); #ifdef ABCEXTERNAL std::string exe_file = ABCEXTERNAL; @@ -913,8 +908,6 @@ struct Abc9MapPass : public Pass { delay_target, lutin_shared, fast_mode, all_cells, show_tempdir, box_file, lut_file, wire_delay, nomfs, tempdir_name); } - - log_pop(); } } Abc9MapPass; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index dcb8a8a78..a4059bd4d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -436,7 +436,6 @@ struct Abc9OpsPass : public Pass { void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); - log_push(); bool break_scc_mode = false; bool unbreak_scc_mode = false; -- cgit v1.2.3 From e1f494ab1db523f90cf1e386ba133b1550dcb300 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 Jan 2020 13:08:52 -0800 Subject: WIP --- passes/techmap/abc9.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index e7fcb9165..6dd4de2e0 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -185,17 +185,17 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { - run("abc9_ops -prep_holes"); - run("select -set abc9_holes A:abc9_holes"); - run("flatten -wb @abc9_holes"); - run("techmap @abc9_holes"); run("scc -set_attr abc9_scc_id {}"); - run("abc9_ops -break_scc"); + run("abc9_ops -break_scc"/*" -prep_holes"*/); +// run("select -set abc9_holes A:abc9_holes"); +// run("dump @abc9_holes"); +// run("flatten -wb @abc9_holes"); +// run("techmap @abc9_holes"); run("aigmap"); if (dff_mode) run("abc9_ops -prep_dff"); - run("opt -purge @abc9_holes"); - run("wbflip @abc9_holes"); +// run("opt -purge @abc9_holes"); +// run("wbflip @abc9_holes"); auto selected_modules = active_design->selected_modules(); active_design->selection_stack.emplace_back(false); -- cgit v1.2.3 From bb70915fb8adcd7ede7719174dea3bc9c04e613e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 Jan 2020 13:21:56 -0800 Subject: WIP --- passes/techmap/abc9.cc | 6 +++++- passes/techmap/abc9_ops.cc | 48 +++++++++++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 14 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 6dd4de2e0..25fe3fbc8 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -195,7 +195,11 @@ struct Abc9Pass : public ScriptPass if (dff_mode) run("abc9_ops -prep_dff"); // run("opt -purge @abc9_holes"); -// run("wbflip @abc9_holes"); + + run("abc9_ops -prep_holes"); + + run("select -set abc9_holes A:abc9_holes"); + run("wbflip @abc9_holes"); auto selected_modules = active_design->selected_modules(); active_design->selection_stack.emplace_back(false); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index a4059bd4d..c671553e2 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -288,8 +288,6 @@ void prep_holes(RTLIL::Module *module) // Fully pad all unused input connections of this box cell with S0 // Fully pad all undriven output connections of this box cell with anonymous wires - // NB: Assume box_module->ports are sorted alphabetically - // (as RTLIL::Module::fixup_ports() would do) for (const auto &port_name : box_module->ports) { RTLIL::Wire* w = box_module->wire(port_name); log_assert(w); @@ -333,6 +331,7 @@ void prep_holes(RTLIL::Module *module) holes_module->set_bool_attribute("\\abc9_holes"); dict cell_cache; + dict> box_ports; int port_id = 1; for (auto cell : box_list) { @@ -350,24 +349,47 @@ void prep_holes(RTLIL::Module *module) holes_cell = holes_module->addCell(cell->name, cell->type); holes_cell->parameters = cell->parameters; r.first->second = holes_cell; + } - // Since Module::derive() will create a new module, there - // is a chance that the ports will be alphabetically ordered - // again, which is a problem when carry-chains are involved. - // Inherit the port ordering from the original module here... - // (and set the port_id below, when iterating through those) - log_assert(GetSize(box_module->ports) == GetSize(orig_box_module->ports)); - box_module->ports = orig_box_module->ports; + auto r2 = box_ports.insert(cell->type); + 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 : box_module->ports) { + auto w = box_module->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) { + if (carry_in != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module)); + carry_in = port_name; + } + if (w->port_output) { + if (carry_out != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module)); + carry_out = port_name; + } + } + else + r2.first->second.push_back(port_name); + } + + if (carry_in != IdString() && carry_out == IdString()) + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module)); + if (carry_in == IdString() && carry_out != IdString()) + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module)); + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); + } } // NB: Assume box_module->ports are sorted alphabetically // (as RTLIL::Module::fixup_ports() would do) - int box_port_id = 1; - for (const auto &port_name : box_module->ports) { + for (const auto &port_name : box_ports.at(cell->type)) { RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); - if (r.second) - w->port_id = box_port_id++; RTLIL::Wire *holes_wire; RTLIL::SigSpec port_sig; if (w->port_input) -- cgit v1.2.3 From 559f3379e852f304a0255afcc37714b9d0da59d9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 Jan 2020 14:37:58 -0800 Subject: Preserve topo ordering from -prep_holes to write_xaiger --- passes/techmap/abc9.cc | 6 +----- passes/techmap/abc9_ops.cc | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 25fe3fbc8..af37ecb5c 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -187,17 +187,13 @@ struct Abc9Pass : public ScriptPass { run("scc -set_attr abc9_scc_id {}"); run("abc9_ops -break_scc"/*" -prep_holes"*/); -// run("select -set abc9_holes A:abc9_holes"); -// run("dump @abc9_holes"); // run("flatten -wb @abc9_holes"); // run("techmap @abc9_holes"); run("aigmap"); + run("abc9_ops -prep_holes"); if (dff_mode) run("abc9_ops -prep_dff"); // run("opt -purge @abc9_holes"); - - run("abc9_ops -prep_holes"); - run("select -set abc9_holes A:abc9_holes"); run("wbflip @abc9_holes"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index c671553e2..bcf622dba 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -322,6 +322,7 @@ void prep_holes(RTLIL::Module *module) } } + cell->attributes["\\abc9_box_order"] = box_list.size(); box_list.emplace_back(cell); } log_assert(!box_list.empty()); -- cgit v1.2.3 From a819656972dd44c479422fa688874926d6239a95 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 Jan 2020 14:59:55 -0800 Subject: WIP --- passes/techmap/abc9.cc | 12 +++++++----- passes/techmap/abc9_ops.cc | 2 -- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index af37ecb5c..da56f42ea 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -186,15 +186,17 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { run("scc -set_attr abc9_scc_id {}"); - run("abc9_ops -break_scc"/*" -prep_holes"*/); -// run("flatten -wb @abc9_holes"); -// run("techmap @abc9_holes"); + run("abc9_ops -break_scc"); run("aigmap"); + run("abc9_ops -prep_holes"); + run("select -set abc9_holes A:abc9_holes"); + run("flatten -wb @abc9_holes"); + run("techmap @abc9_holes"); + run("aigmap @abc9_holes"); if (dff_mode) run("abc9_ops -prep_dff"); -// run("opt -purge @abc9_holes"); - run("select -set abc9_holes A:abc9_holes"); + run("opt -purge @abc9_holes"); run("wbflip @abc9_holes"); auto selected_modules = active_design->selected_modules(); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index bcf622dba..632f2bc8a 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -386,8 +386,6 @@ void prep_holes(RTLIL::Module *module) } } - // NB: Assume box_module->ports are sorted alphabetically - // (as RTLIL::Module::fixup_ports() would do) for (const auto &port_name : box_ports.at(cell->type)) { RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); -- cgit v1.2.3 From 930f03e8830ed8a8023ff88207b97e757ae8496c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 Jan 2020 15:38:18 -0800 Subject: Call -prep_holes before aigmap; fix topo ordering --- passes/techmap/abc9.cc | 7 ++---- passes/techmap/abc9_ops.cc | 55 +++++++++++++--------------------------------- 2 files changed, 17 insertions(+), 45 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index da56f42ea..0da815870 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -186,14 +186,11 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { run("scc -set_attr abc9_scc_id {}"); - run("abc9_ops -break_scc"); - run("aigmap"); - - run("abc9_ops -prep_holes"); + run("abc9_ops -break_scc -prep_holes"); run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); - run("aigmap @abc9_holes"); + run("aigmap"); if (dff_mode) run("abc9_ops -prep_dff"); run("opt -purge @abc9_holes"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 632f2bc8a..2f07de8d4 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -21,6 +21,7 @@ #include "kernel/register.h" #include "kernel/sigtools.h" #include "kernel/utils.h" +#include "kernel/celltypes.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -194,58 +195,32 @@ void prep_holes(RTLIL::Module *module) SigMap sigmap(module); - // TODO: Speed up toposort -- ultimately we care about - // box ordering, but not individual AIG cells dict> bit_drivers, bit_users; TopoSort toposort; bool abc9_box_seen = false; for (auto cell : module->selected_cells()) { - if (cell->type == "$_NOT_") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); - toposort.node(cell->name); - bit_users[A].insert(cell->name); - bit_drivers[Y].insert(cell->name); - continue; - } - - if (cell->type == "$_AND_") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit B = sigmap(cell->getPort("\\B").as_bit()); - SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); - toposort.node(cell->name); - bit_users[A].insert(cell->name); - bit_users[B].insert(cell->name); - bit_drivers[Y].insert(cell->name); - continue; - } - if (cell->type == "$__ABC9_FF_") continue; - RTLIL::Module* inst_module = design->module(cell->type); - if (inst_module) { - if (!inst_module->attributes.count("\\abc9_box_id") || cell->get_bool_attribute("\\abc9_keep")) - continue; + auto inst_module = module->design->module(cell->type); + bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id") && !cell->get_bool_attribute("\\abc9_keep"); + abc9_box_seen = abc9_box_seen || abc9_box; - for (const auto &conn : cell->connections()) { - auto port_wire = inst_module->wire(conn.first); - // Ignore inout for the sake of topographical ordering - if (port_wire->port_input && !port_wire->port_output) - for (auto bit : sigmap(conn.second)) - bit_users[bit].insert(cell->name); - if (port_wire->port_output) - for (auto bit : sigmap(conn.second)) - bit_drivers[bit].insert(cell->name); - } + if (!abc9_box && !yosys_celltypes.cell_known(cell->type)) + continue; - abc9_box_seen = true; + for (auto conn : cell->connections()) { + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + bit_users[bit].insert(cell->name); - toposort.node(cell->name); + if (cell->output(conn.first)) + for (auto bit : sigmap(conn.second)) + bit_drivers[bit].insert(cell->name); } + + toposort.node(cell->name); } if (!abc9_box_seen) -- cgit v1.2.3 From 6556a1347ab56b022a599835071c6b3059787462 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 4 Jan 2020 09:17:01 -0800 Subject: Fix when -dff not given --- passes/techmap/abc9.cc | 5 ++- passes/techmap/abc9_map.cc | 18 ++-------- passes/techmap/abc9_ops.cc | 85 +++++++++++++++++++++++----------------------- 3 files changed, 49 insertions(+), 59 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 0da815870..d51ed3352 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -186,7 +186,10 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { run("scc -set_attr abc9_scc_id {}"); - run("abc9_ops -break_scc -prep_holes"); + if (help_mode) + run("abc9_ops -break_scc -prep_holes [-dff]", "(option for -dff)"); + else + run("abc9_ops -break_scc -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index 171289c6d..d007dbcc2 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -355,28 +355,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx; } - dict abc9_box; vector boxes; for (auto cell : cells) { if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) { module->remove(cell); continue; } - auto jt = abc9_box.find(cell->type); - if (jt == abc9_box.end()) { - RTLIL::Module* box_module = design->module(cell->type); - jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first; - } - if (jt->second) { - auto kt = cell->attributes.find("\\abc9_keep"); - bool abc9_keep = false; - if (kt != cell->attributes.end()) { - abc9_keep = kt->second.as_bool(); - cell->attributes.erase(kt); - } - if (!abc9_keep) - boxes.emplace_back(cell); - } + if (cell->attributes.erase("\\abc9_box_seq")) + boxes.emplace_back(cell); } dict> bit_drivers, bit_users; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2f07de8d4..ab5aa9f8d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -109,39 +109,31 @@ void prep_dff(RTLIL::Module *module) typedef SigSpec clkdomain_t; dict clk_to_mergeability; - //if (dff_mode) - for (auto cell : module->selected_cells()) { - if (cell->type != "$__ABC9_FF_") - continue; + for (auto cell : module->selected_cells()) { + if (cell->type != "$__ABC9_FF_") + continue; - 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); - - clkdomain_t key(abc9_clock); - - auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); - auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second)); - log_assert(r2.second); - - Wire *abc9_init_wire = module->wire(stringf("%s.init", cell->name.c_str())); - if (abc9_init_wire == NULL) - log_error("'%s.init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - log_assert(GetSize(abc9_init_wire) == 1); - SigSpec abc9_init = assign_map(abc9_init_wire); - if (!abc9_init.is_fully_const()) - log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); - log_assert(r2.second); - } - //else - // for (auto cell : module->selected_cells()) { - // auto inst_module = design->module(cell->type); - // if (!inst_module || !inst_module->get_bool_attribute("\\abc9_flop")) - // continue; - // cell->set_bool_attribute("\\abc9_keep"); - // } + 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); + + clkdomain_t key(abc9_clock); + + auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); + auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second)); + log_assert(r2.second); + + Wire *abc9_init_wire = module->wire(stringf("%s.init", cell->name.c_str())); + if (abc9_init_wire == NULL) + log_error("'%s.init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + log_assert(GetSize(abc9_init_wire) == 1); + SigSpec abc9_init = assign_map(abc9_init_wire); + if (!abc9_init.is_fully_const()) + log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); + log_assert(r2.second); + } RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); if (holes_module) { @@ -188,7 +180,7 @@ void prep_dff(RTLIL::Module *module) } } -void prep_holes(RTLIL::Module *module) +void prep_holes(RTLIL::Module *module, bool dff) { auto design = module->design; log_assert(design); @@ -204,10 +196,15 @@ void prep_holes(RTLIL::Module *module) continue; auto inst_module = module->design->module(cell->type); - bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id") && !cell->get_bool_attribute("\\abc9_keep"); - abc9_box_seen = abc9_box_seen || abc9_box; - - if (!abc9_box && !yosys_celltypes.cell_known(cell->type)) + bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id"); + bool abc9_flop = false; + if (abc9_box) { + abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); + if (abc9_flop && !dff) + continue; + abc9_box_seen = abc9_box; + } + else if (!yosys_celltypes.cell_known(cell->type)) continue; for (auto conn : cell->connections()) { @@ -215,7 +212,7 @@ void prep_holes(RTLIL::Module *module) for (auto bit : sigmap(conn.second)) bit_users[bit].insert(cell->name); - if (cell->output(conn.first)) + if (cell->output(conn.first) && !abc9_flop) for (auto bit : sigmap(conn.second)) bit_drivers[bit].insert(cell->name); } @@ -255,8 +252,7 @@ void prep_holes(RTLIL::Module *module) log_assert(cell); RTLIL::Module* box_module = design->module(cell->type); - if (!box_module || !box_module->attributes.count("\\abc9_box_id") - || cell->get_bool_attribute("\\abc9_keep")) + if (!box_module || !box_module->attributes.count("\\abc9_box_id")) continue; bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); @@ -297,7 +293,7 @@ void prep_holes(RTLIL::Module *module) } } - cell->attributes["\\abc9_box_order"] = box_list.size(); + cell->attributes["\\abc9_box_seq"] = box_list.size(); box_list.emplace_back(cell); } log_assert(!box_list.empty()); @@ -437,6 +433,7 @@ struct Abc9OpsPass : public Pass { bool unbreak_scc_mode = false; bool prep_dff_mode = false; bool prep_holes_mode = false; + bool dff_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -457,6 +454,10 @@ struct Abc9OpsPass : public Pass { prep_holes_mode = true; continue; } + if (arg == "-dff") { + dff_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -479,7 +480,7 @@ struct Abc9OpsPass : public Pass { if (prep_dff_mode) prep_dff(mod); if (prep_holes_mode) - prep_holes(mod); + prep_holes(mod, dff_mode); } } } Abc9OpsPass; -- cgit v1.2.3 From 8293a3fe749701c7df425acd81e24a2a34f5032e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 4 Jan 2020 09:30:48 -0800 Subject: Cleanup --- passes/techmap/abc9_map.cc | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index d007dbcc2..b3642ab22 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -198,7 +198,7 @@ struct abc9_output_filter void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string script_file, std::string exe_file, vector lut_costs, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, - const std::vector &cells, bool show_tempdir, std::string box_file, std::string lut_file, + bool show_tempdir, std::string box_file, std::string lut_file, std::string wire_delay, bool nomfs, std::string tempdir_name ) { @@ -355,15 +355,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx; } - vector boxes; - for (auto cell : cells) { - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) { - module->remove(cell); - continue; - } - if (cell->attributes.erase("\\abc9_box_seq")) - boxes.emplace_back(cell); - } + for (auto it = module->cells_.begin(); it != module->cells_.end(); ) + if (it->second->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) + it = module->cells_.erase(it); + else + ++it; dict> bit_drivers, bit_users; TopoSort toposort; @@ -455,9 +451,18 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip cell->attributes = mapped_cell->attributes; } + auto abc9_box = cell->attributes.erase("\\abc9_box_seq"); + if (abc9_box) { + module->swap_names(cell, existing_cell); + module->remove(existing_cell); + } RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); for (auto &conn : mapped_cell->connections()) { + // Skip entire box ports composed entirely of padding only + if (abc9_box && conn.second.is_wire() && conn.second.as_wire()->get_bool_attribute(ID(abc9_padding))) + continue; + RTLIL::SigSpec newsig; for (auto c : conn.second.chunks()) { if (c.width == 0) @@ -483,23 +488,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip } } - for (auto existing_cell : boxes) { - Cell *cell = module->cell(remap_name(existing_cell->name)); - if (cell) { - for (auto &conn : existing_cell->connections()) { - if (!conn.second.is_wire()) - continue; - Wire *wire = conn.second.as_wire(); - if (!wire->get_bool_attribute(ID(abc9_padding))) - continue; - cell->unsetPort(conn.first); - log_debug("Dropping padded port connection for %s (%s) .%s (%s )\n", log_id(cell), cell->type.c_str(), log_id(conn.first), log_signal(conn.second)); - } - module->swap_names(cell, existing_cell); - } - module->remove(existing_cell); - } - // Copy connections (and rename) from mapped_mod to module for (auto conn : mapped_mod->connections()) { if (!conn.first.is_fully_const()) { @@ -888,10 +876,8 @@ struct Abc9MapPass : public Pass { continue; } - const std::vector all_cells = mod->selected_cells(); - abc9_module(design, mod, script_file, exe_file, lut_costs, - delay_target, lutin_shared, fast_mode, all_cells, show_tempdir, + delay_target, lutin_shared, fast_mode, show_tempdir, box_file, lut_file, wire_delay, nomfs, tempdir_name); } } -- cgit v1.2.3 From b5f60e055d07579a2d4f23fc053ca030f103f377 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 5 Jan 2020 10:20:24 -0800 Subject: write_xaiger to pad, not abc9_ops -prep_holes --- passes/techmap/abc9_map.cc | 13 ++++--------- passes/techmap/abc9_ops.cc | 39 --------------------------------------- 2 files changed, 4 insertions(+), 48 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index b3642ab22..e061cadeb 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -445,24 +445,19 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip if (existing_cell) { cell->parameters = existing_cell->parameters; cell->attributes = existing_cell->attributes; + if (cell->attributes.erase("\\abc9_box_seq")) { + module->swap_names(cell, existing_cell); + module->remove(existing_cell); + } } else { cell->parameters = mapped_cell->parameters; cell->attributes = mapped_cell->attributes; } - auto abc9_box = cell->attributes.erase("\\abc9_box_seq"); - if (abc9_box) { - module->swap_names(cell, existing_cell); - module->remove(existing_cell); - } RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); for (auto &conn : mapped_cell->connections()) { - // Skip entire box ports composed entirely of padding only - if (abc9_box && conn.second.is_wire() && conn.second.as_wire()->get_bool_attribute(ID(abc9_padding))) - continue; - RTLIL::SigSpec newsig; for (auto c : conn.second.chunks()) { if (c.width == 0) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index ab5aa9f8d..730431ebf 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -254,45 +254,6 @@ void prep_holes(RTLIL::Module *module, bool dff) RTLIL::Module* box_module = design->module(cell->type); if (!box_module || !box_module->attributes.count("\\abc9_box_id")) continue; - - bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); - - // Fully pad all unused input connections of this box cell with S0 - // Fully pad all undriven output connections of this box cell with anonymous wires - for (const auto &port_name : box_module->ports) { - RTLIL::Wire* w = box_module->wire(port_name); - log_assert(w); - auto it = cell->connections_.find(port_name); - if (w->port_input) { - RTLIL::SigSpec rhs; - if (it != cell->connections_.end()) { - if (GetSize(it->second) < GetSize(w)) - it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); - rhs = it->second; - } - else { - rhs = RTLIL::SigSpec(State::S0, GetSize(w)); - cell->setPort(port_name, rhs); - } - } - if (w->port_output) { - RTLIL::SigSpec rhs; - auto it = cell->connections_.find(w->name); - if (it != cell->connections_.end()) { - if (GetSize(it->second) < GetSize(w)) - it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); - rhs = it->second; - } - else { - Wire *wire = module->addWire(NEW_ID, GetSize(w)); - if (blackbox) - wire->set_bool_attribute(ID(abc9_padding)); - rhs = wire; - cell->setPort(port_name, rhs); - } - } - } - cell->attributes["\\abc9_box_seq"] = box_list.size(); box_list.emplace_back(cell); } -- cgit v1.2.3 From 36ae2e52e49ee510a0bec45e7faa4ed60fdc760d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 6 Jan 2020 12:28:58 -0800 Subject: Fix bad merge --- passes/techmap/abc9.cc | 21 ++------- passes/techmap/abc9_map.cc | 107 ++++++++++++++++++++++++++++----------------- 2 files changed, 69 insertions(+), 59 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index d54891167..94eea2983 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -146,23 +146,8 @@ struct Abc9Pass : public ScriptPass clear_flags(); // get arguments from scratchpad first, then override by command arguments - std::string lut_arg, luts_arg; - exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */); - script_file = design->scratchpad_get_string("abc9.script", script_file); - if (design->scratchpad.count("abc9.D")) { - delay_target = "-D " + design->scratchpad_get_string("abc9.D"); - } - lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg); - luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg); - fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode); dff_mode = design->scratchpad_get_bool("abc9.dff", dff_mode); cleanup = !design->scratchpad_get_bool("abc9.nocleanup", !cleanup); - show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir); - box_file = design->scratchpad_get_string("abc9.box", box_file); - if (design->scratchpad.count("abc9.W")) { - wire_delay = "-W " + design->scratchpad_get_string("abc9.W"); - } - nomfs = design->scratchpad_get_bool("abc9.nomfs", nomfs); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -224,10 +209,10 @@ struct Abc9Pass : public ScriptPass log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; } - log_assert(!module->attributes.count(ID(abc9_box_id))); + log_assert(!mod->attributes.count(ID(abc9_box_id))); - if (!design->selected_whole_module(module)) - log_error("Can't handle partially selected module %s!\n", log_id(module)); + if (!active_design->selected_whole_module(mod)) + log_error("Can't handle partially selected module %s!\n", log_id(mod)); active_design->selection().select(mod); diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index 0877906ca..e6e4e3e72 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -348,7 +348,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip if (mapped_mod == NULL) log_error("ABC output file does not contain a module `$__abc9__'.\n"); - for (auto wire : mapped_mod->wires()) + for (auto w : mapped_mod->wires()) module->addWire(remap_name(w->name), GetSize(w)); for (auto it = module->cells_.begin(); it != module->cells_.end(); ) @@ -727,6 +727,22 @@ struct Abc9MapPass : public Pass { #endif #endif + std::string lut_arg, luts_arg; + exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */); + script_file = design->scratchpad_get_string("abc9.script", script_file); + if (design->scratchpad.count("abc9.D")) { + delay_target = "-D " + design->scratchpad_get_string("abc9.D"); + } + lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg); + luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg); + fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode); + show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir); + box_file = design->scratchpad_get_string("abc9.box", box_file); + if (design->scratchpad.count("abc9.W")) { + wire_delay = "-W " + design->scratchpad_get_string("abc9.W"); + } + nomfs = design->scratchpad_get_bool("abc9.nomfs", nomfs); + size_t argidx; char pwd [PATH_MAX]; if (!getcwd(pwd, sizeof(pwd))) { @@ -741,9 +757,6 @@ struct Abc9MapPass : public Pass { } if (arg == "-script" && argidx+1 < args.size()) { script_file = args[++argidx]; - rewrite_filename(script_file); - if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') - script_file = std::string(pwd) + "/" + script_file; continue; } if (arg == "-D" && argidx+1 < args.size()) { @@ -755,45 +768,11 @@ struct Abc9MapPass : public Pass { // continue; //} if (arg == "-lut" && argidx+1 < args.size()) { - string arg = args[++argidx]; - if (arg.find_first_not_of("0123456789:") == std::string::npos) { - size_t pos = arg.find_first_of(':'); - int lut_mode = 0, lut_mode2 = 0; - if (pos != string::npos) { - lut_mode = atoi(arg.substr(0, pos).c_str()); - lut_mode2 = atoi(arg.substr(pos+1).c_str()); - } else { - lut_mode = atoi(arg.c_str()); - lut_mode2 = lut_mode; - } - lut_costs.clear(); - for (int i = 0; i < lut_mode; i++) - lut_costs.push_back(1); - for (int i = lut_mode; i < lut_mode2; i++) - lut_costs.push_back(2 << (i - lut_mode)); - } - else { - lut_file = arg; - rewrite_filename(lut_file); - if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+') - lut_file = std::string(pwd) + "/" + lut_file; - } + lut_arg = args[++argidx]; continue; } if (arg == "-luts" && argidx+1 < args.size()) { - lut_costs.clear(); - for (auto &tok : split_tokens(args[++argidx], ",")) { - auto parts = split_tokens(tok, ":"); - if (GetSize(parts) == 0 && !lut_costs.empty()) - lut_costs.push_back(lut_costs.back()); - else if (GetSize(parts) == 1) - lut_costs.push_back(atoi(parts.at(0).c_str())); - else if (GetSize(parts) == 2) - while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) - lut_costs.push_back(atoi(parts.at(1).c_str())); - else - log_cmd_error("Invalid -luts syntax.\n"); - } + lut_arg = args[++argidx]; continue; } if (arg == "-fast") { @@ -824,6 +803,52 @@ struct Abc9MapPass : public Pass { } extra_args(args, argidx, design); + rewrite_filename(script_file); + if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') + script_file = std::string(pwd) + "/" + script_file; + + // handle -lut / -luts args + if (!lut_arg.empty()) { + string arg = lut_arg; + if (arg.find_first_not_of("0123456789:") == std::string::npos) { + size_t pos = arg.find_first_of(':'); + int lut_mode = 0, lut_mode2 = 0; + if (pos != string::npos) { + lut_mode = atoi(arg.substr(0, pos).c_str()); + lut_mode2 = atoi(arg.substr(pos+1).c_str()); + } else { + lut_mode = atoi(arg.c_str()); + lut_mode2 = lut_mode; + } + lut_costs.clear(); + for (int i = 0; i < lut_mode; i++) + lut_costs.push_back(1); + for (int i = lut_mode; i < lut_mode2; i++) + lut_costs.push_back(2 << (i - lut_mode)); + } + else { + lut_file = arg; + rewrite_filename(lut_file); + if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+') + lut_file = std::string(pwd) + "/" + lut_file; + } + } + if (!luts_arg.empty()) { + lut_costs.clear(); + for (auto &tok : split_tokens(luts_arg, ",")) { + auto parts = split_tokens(tok, ":"); + if (GetSize(parts) == 0 && !lut_costs.empty()) + lut_costs.push_back(lut_costs.back()); + else if (GetSize(parts) == 1) + lut_costs.push_back(atoi(parts.at(0).c_str())); + else if (GetSize(parts) == 2) + while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) + lut_costs.push_back(atoi(parts.at(1).c_str())); + else + log_cmd_error("Invalid -luts syntax.\n"); + } + } + // ABC expects a box file for XAIG if (box_file.empty()) box_file = "+/dummy.box"; @@ -844,7 +869,7 @@ struct Abc9MapPass : public Pass { } if (!design->selected_whole_module(mod)) - log_error("Can't handle partially selected module %s!\n", log_id(module)); + log_error("Can't handle partially selected module %s!\n", log_id(mod)); abc9_module(design, mod, script_file, exe_file, lut_costs, delay_target, lutin_shared, fast_mode, show_tempdir, -- cgit v1.2.3 From 2bf442ca011a1495c7c0960e9ea4452fa7e934b5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 6 Jan 2020 13:02:04 -0800 Subject: Cleanup --- passes/techmap/abc9.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 94eea2983..c7db4f557 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -202,20 +202,17 @@ struct Abc9Pass : public ScriptPass active_design->selection_stack.emplace_back(false); for (auto mod : selected_modules) { - if (mod->get_blackbox_attribute()) - continue; - if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; } log_assert(!mod->attributes.count(ID(abc9_box_id))); + active_design->selection().select(mod); + if (!active_design->selected_whole_module(mod)) log_error("Can't handle partially selected module %s!\n", log_id(mod)); - active_design->selection().select(mod); - std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; if (!cleanup) tempdir_name[0] = tempdir_name[4] = '_'; -- cgit v1.2.3 From aa58472a292c2cd3c0f2ba669c9dcfd608d8dc5f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 6 Jan 2020 13:34:45 -0800 Subject: Revert "write_xaiger to pad, not abc9_ops -prep_holes" This reverts commit b5f60e055d07579a2d4f23fc053ca030f103f377. --- passes/techmap/abc9_map.cc | 13 +++++++++---- passes/techmap/abc9_ops.cc | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index e6e4e3e72..c01feedb6 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -438,19 +438,24 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip if (existing_cell) { cell->parameters = existing_cell->parameters; cell->attributes = existing_cell->attributes; - if (cell->attributes.erase("\\abc9_box_seq")) { - module->swap_names(cell, existing_cell); - module->remove(existing_cell); - } } else { cell->parameters = mapped_cell->parameters; cell->attributes = mapped_cell->attributes; } + auto abc9_box = cell->attributes.erase("\\abc9_box_seq"); + if (abc9_box) { + module->swap_names(cell, existing_cell); + module->remove(existing_cell); + } RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); for (auto &conn : mapped_cell->connections()) { + // Skip entire box ports composed entirely of padding only + if (abc9_box && conn.second.is_wire() && conn.second.as_wire()->get_bool_attribute(ID(abc9_padding))) + continue; + RTLIL::SigSpec newsig; for (auto c : conn.second.chunks()) { if (c.width == 0) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 730431ebf..ab5aa9f8d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -254,6 +254,45 @@ void prep_holes(RTLIL::Module *module, bool dff) RTLIL::Module* box_module = design->module(cell->type); if (!box_module || !box_module->attributes.count("\\abc9_box_id")) continue; + + bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); + + // Fully pad all unused input connections of this box cell with S0 + // Fully pad all undriven output connections of this box cell with anonymous wires + for (const auto &port_name : box_module->ports) { + RTLIL::Wire* w = box_module->wire(port_name); + log_assert(w); + auto it = cell->connections_.find(port_name); + if (w->port_input) { + RTLIL::SigSpec rhs; + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + rhs = RTLIL::SigSpec(State::S0, GetSize(w)); + cell->setPort(port_name, rhs); + } + } + if (w->port_output) { + RTLIL::SigSpec rhs; + auto it = cell->connections_.find(w->name); + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + Wire *wire = module->addWire(NEW_ID, GetSize(w)); + if (blackbox) + wire->set_bool_attribute(ID(abc9_padding)); + rhs = wire; + cell->setPort(port_name, rhs); + } + } + } + cell->attributes["\\abc9_box_seq"] = box_list.size(); box_list.emplace_back(cell); } -- cgit v1.2.3 From 46ed507b93aa744bf03ea79a2950a2cb66c250da Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 6 Jan 2020 15:14:54 -0800 Subject: abc9_map: drop padding in box connections --- passes/techmap/abc9_map.cc | 67 ++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 32 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc index c01feedb6..4ed3419f0 100644 --- a/passes/techmap/abc9_map.cc +++ b/passes/techmap/abc9_map.cc @@ -435,29 +435,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); } - if (existing_cell) { - cell->parameters = existing_cell->parameters; - cell->attributes = existing_cell->attributes; - } - else { - cell->parameters = mapped_cell->parameters; - cell->attributes = mapped_cell->attributes; - } - - auto abc9_box = cell->attributes.erase("\\abc9_box_seq"); - if (abc9_box) { - module->swap_names(cell, existing_cell); - module->remove(existing_cell); - } RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); - for (auto &conn : mapped_cell->connections()) { - // Skip entire box ports composed entirely of padding only - if (abc9_box && conn.second.is_wire() && conn.second.as_wire()->get_bool_attribute(ID(abc9_padding))) - continue; - + for (auto &mapped_conn : mapped_cell->connections()) { RTLIL::SigSpec newsig; - for (auto c : conn.second.chunks()) { + for (auto c : mapped_conn.second.chunks()) { if (c.width == 0) continue; //log_assert(c.width == 1); @@ -465,19 +447,40 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip c.wire = module->wires_.at(remap_name(c.wire->name)); newsig.append(c); } - cell->setPort(conn.first, newsig); - - if (!abc9_flop) { - if (cell->input(conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : conn.second) - bit_users[i].insert(mapped_cell->name); - } - if (cell->output(conn.first)) - for (auto i : conn.second) - bit_drivers[i].insert(mapped_cell->name); + if (existing_cell) { + auto it = existing_cell->connections_.find(mapped_conn.first); + if (it == existing_cell->connections_.end()) + continue; + log_assert(GetSize(newsig) >= GetSize(it->second)); + newsig = newsig.extract(0, GetSize(it->second)); } + cell->setPort(mapped_conn.first, newsig); + + if (abc9_flop) + continue; + + if (cell->input(mapped_conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : mapped_conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(mapped_conn.first)) + for (auto i : mapped_conn.second) + bit_drivers[i].insert(mapped_cell->name); + } + + if (existing_cell) { + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + if (cell->attributes.erase("\\abc9_box_seq")) { + module->swap_names(cell, existing_cell); + module->remove(existing_cell); + } + } + else { + cell->parameters = mapped_cell->parameters; + cell->attributes = mapped_cell->attributes; } } -- cgit v1.2.3 From cf3a13746d27fee141700e2c6ea40d528267190f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 6 Jan 2020 15:52:59 -0800 Subject: Add abc9_ops -reintegrate; moved out from now abc9_exe --- passes/techmap/Makefile.inc | 2 +- passes/techmap/abc9.cc | 20 +- passes/techmap/abc9_exe.cc | 557 +++++++++++++++++++++++++++ passes/techmap/abc9_map.cc | 889 -------------------------------------------- passes/techmap/abc9_ops.cc | 286 +++++++++++++- 5 files changed, 854 insertions(+), 900 deletions(-) create mode 100644 passes/techmap/abc9_exe.cc delete mode 100644 passes/techmap/abc9_map.cc (limited to 'passes/techmap') diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 734d6c10f..369c9de64 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -8,7 +8,7 @@ OBJS += passes/techmap/libparse.o ifeq ($(ENABLE_ABC),1) OBJS += passes/techmap/abc.o OBJS += passes/techmap/abc9.o -OBJS += passes/techmap/abc9_map.o +OBJS += passes/techmap/abc9_exe.o OBJS += passes/techmap/abc9_ops.o ifneq ($(ABCEXTERNAL),) passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index c7db4f557..7c261e220 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -129,13 +129,13 @@ struct Abc9Pass : public ScriptPass log("\n"); } - std::stringstream map_cmd; + std::stringstream exe_cmd; bool dff_mode, cleanup; void clear_flags() YS_OVERRIDE { - map_cmd.str(""); - map_cmd << "abc9_map"; + exe_cmd.str(""); + exe_cmd << "abc9_exe"; dff_mode = false; cleanup = true; } @@ -156,13 +156,13 @@ struct Abc9Pass : public ScriptPass /* arg == "-S" || */ arg == "-lut" || arg == "-luts" || arg == "-box" || arg == "-W") && argidx+1 < args.size()) { - map_cmd << " " << arg << " " << args[++argidx]; + exe_cmd << " " << arg << " " << args[++argidx]; continue; } if (arg == "-fast" || /* arg == "-dff" || */ /* arg == "-nocleanup" || */ arg == "-showtmp" || arg == "-nomfs") { - map_cmd << " " << arg; + exe_cmd << " " << arg; continue; } if (arg == "-dff") { @@ -219,9 +219,13 @@ struct Abc9Pass : public ScriptPass tempdir_name = make_temp_dir(tempdir_name); run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), - "write_xaiger -map /input.sym /input.xaig"); - run(stringf("%s -tempdir %s", map_cmd.str().c_str(), tempdir_name.c_str()), - "abc9_map [options] -tempdir "); + "write_xaiger -map /input.sym /input.xaig"); + run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()), + "abc9_exe [options] -cwd "); + + run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()), + "read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); + run("abc9_ops -reintegrate"); if (cleanup) { diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc new file mode 100644 index 000000000..36d7faf1b --- /dev/null +++ b/passes/techmap/abc9_exe.cc @@ -0,0 +1,557 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +// [[CITE]] ABC +// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification +// http://www.eecs.berkeley.edu/~alanmi/abc/ + +#if 0 +// Based on &flow3 - better QoR but more experimental +#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \ + "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\ + "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\ + "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ + "&mfs; &ps -l" +#else +#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" +#endif + + +#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}" + +#include "kernel/register.h" +#include "kernel/log.h" + +#ifndef _WIN32 +# include +# include +#endif + +#ifdef YOSYS_LINK_ABC +extern "C" int Abc_RealMain(int argc, char *argv[]); +#endif + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +std::string add_echos_to_abc9_cmd(std::string str) +{ + std::string new_str, token; + for (size_t i = 0; i < str.size(); i++) { + token += str[i]; + if (str[i] == ';') { + while (i+1 < str.size() && str[i+1] == ' ') + i++; + new_str += "echo + " + token + " " + token + " "; + token.clear(); + } + } + + if (!token.empty()) { + if (!new_str.empty()) + new_str += "echo + " + token + "; "; + new_str += token; + } + + return new_str; +} + +std::string fold_abc9_cmd(std::string str) +{ + std::string token, new_str = " "; + int char_counter = 10; + + for (size_t i = 0; i <= str.size(); i++) { + if (i < str.size()) + token += str[i]; + if (i == str.size() || str[i] == ';') { + if (char_counter + token.size() > 75) + new_str += "\n ", char_counter = 14; + new_str += token, char_counter += token.size(); + token.clear(); + } + } + + return new_str; +} + +std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir) +{ + if (show_tempdir) + return text; + + while (1) { + size_t pos = text.find(tempdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "" + text.substr(pos + GetSize(tempdir_name)); + } + + std::string selfdir_name = proc_self_dirname(); + if (selfdir_name != "/") { + while (1) { + size_t pos = text.find(selfdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "/" + text.substr(pos + GetSize(selfdir_name)); + } + } + + return text; +} + +struct abc9_output_filter +{ + bool got_cr; + int escape_seq_state; + std::string linebuf; + std::string tempdir_name; + bool show_tempdir; + + abc9_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) + { + got_cr = false; + escape_seq_state = 0; + } + + void next_char(char ch) + { + if (escape_seq_state == 0 && ch == '\033') { + escape_seq_state = 1; + return; + } + if (escape_seq_state == 1) { + escape_seq_state = ch == '[' ? 2 : 0; + return; + } + if (escape_seq_state == 2) { + if ((ch < '0' || '9' < ch) && ch != ';') + escape_seq_state = 0; + return; + } + escape_seq_state = 0; + if (ch == '\r') { + got_cr = true; + return; + } + if (ch == '\n') { + log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str()); + got_cr = false, linebuf.clear(); + return; + } + if (got_cr) + got_cr = false, linebuf.clear(); + linebuf += ch; + } + + void next_line(const std::string &line) + { + //int pi, po; + //if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { + // log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", + // pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", + // po, po_map.count(po) ? po_map.at(po).c_str() : "???"); + // return; + //} + + for (char ch : line) + next_char(ch); + } +}; + +void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe_file, + vector lut_costs, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, + bool show_tempdir, std::string box_file, std::string lut_file, + std::string wire_delay, bool nomfs, std::string tempdir_name +) +{ + //FIXME: + //log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", + // module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); + + std::string abc9_script; + + if (!lut_costs.empty()) { + abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); + if (!box_file.empty()) + abc9_script += stringf("read_box %s; ", box_file.c_str()); + } + else + if (!lut_file.empty()) { + abc9_script += stringf("read_lut %s; ", lut_file.c_str()); + if (!box_file.empty()) + abc9_script += stringf("read_box %s; ", box_file.c_str()); + } + else + log_abort(); + + abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); + + if (!script_file.empty()) { + if (script_file[0] == '+') { + for (size_t i = 1; i < script_file.size(); i++) + if (script_file[i] == '\'') + abc9_script += "'\\''"; + else if (script_file[i] == ',') + abc9_script += " "; + else + abc9_script += script_file[i]; + } else + abc9_script += stringf("source %s", script_file.c_str()); + } else if (!lut_costs.empty() || !lut_file.empty()) { + abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; + } else + log_abort(); + + for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) + abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); + + //for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos)) + // abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3); + + for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos)) + abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3); + + if (nomfs) + for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) + abc9_script = abc9_script.erase(pos, strlen("&mfs")); + + abc9_script += stringf("; &write -n %s/output.aig", tempdir_name.c_str()); + abc9_script = add_echos_to_abc9_cmd(abc9_script); + + for (size_t i = 0; i+1 < abc9_script.size(); i++) + if (abc9_script[i] == ';' && abc9_script[i+1] == ' ') + abc9_script[i+1] = '\n'; + + FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); + fprintf(f, "%s\n", abc9_script.c_str()); + fclose(f); + + int count_outputs = design->scratchpad_get_int("write_xaiger.num_outputs"); + log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", + design->scratchpad_get_int("write_xaiger.num_ands"), + design->scratchpad_get_int("write_xaiger.num_wires"), + design->scratchpad_get_int("write_xaiger.num_inputs"), + count_outputs); + + if (count_outputs > 0) { + std::string buffer; + + log_header(design, "Executing ABC9.\n"); + + if (!lut_costs.empty()) { + buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); + f = fopen(buffer.c_str(), "wt"); + if (f == NULL) + log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); + for (int i = 0; i < GetSize(lut_costs); i++) + fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); + fclose(f); + } + + buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); + log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); + +#ifndef YOSYS_LINK_ABC + abc9_output_filter filt(tempdir_name, show_tempdir); + int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1)); +#else + // These needs to be mutable, supposedly due to getopt + char *abc9_argv[5]; + string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); + abc9_argv[0] = strdup(exe_file.c_str()); + abc9_argv[1] = strdup("-s"); + abc9_argv[2] = strdup("-f"); + abc9_argv[3] = strdup(tmp_script_name.c_str()); + abc9_argv[4] = 0; + int ret = Abc_RealMain(4, abc9_argv); + free(abc9_argv[0]); + free(abc9_argv[1]); + free(abc9_argv[2]); + free(abc9_argv[3]); +#endif + if (ret != 0) + log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); + } + else + { + log("Don't call ABC as there is nothing to map.\n"); + } +} + +struct Abc9ExePass : public Pass { + Abc9ExePass() : Pass("abc9_exe", "use ABC9 for technology mapping") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" abc9_exe [options] [selection]\n"); + log("\n"); + log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); + log("library to a target architecture.\n"); + log("\n"); + log(" -exe \n"); +#ifdef ABCEXTERNAL + log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); +#else + log(" use the specified command instead of \"/yosys-abc\" to execute ABC.\n"); +#endif + log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n"); + log("\n"); + log(" -script \n"); + log(" use the specified ABC script file instead of the default script.\n"); + log("\n"); + log(" if starts with a plus sign (+), then the rest of the filename\n"); + log(" string is interpreted as the command string to be passed to ABC. The\n"); + log(" leading plus sign is removed and all commas (,) in the string are\n"); + log(" replaced with blanks before the string is passed to ABC.\n"); + log("\n"); + log(" if no -script parameter is given, the following scripts are used:\n"); + log("\n"); + log(" for -lut/-luts (only one LUT size):\n"); + log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); + log("\n"); + log(" for -lut/-luts (different LUT sizes):\n"); + log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); + log("\n"); + log(" -fast\n"); + log(" use different default scripts that are slightly faster (at the cost\n"); + log(" of output quality):\n"); + log("\n"); + log(" for -lut/-luts:\n"); + log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); + log("\n"); + log(" -D \n"); + log(" set delay target. the string {D} in the default scripts above is\n"); + log(" replaced by this option when used, and an empty string otherwise\n"); + log(" (indicating best possible delay).\n"); + log("\n"); +// log(" -S \n"); +// log(" maximum number of LUT inputs shared.\n"); +// log(" (replaces {S} in the default scripts above, default: -S 1)\n"); +// log("\n"); + log(" -lut \n"); + log(" generate netlist using luts of (max) the specified width.\n"); + log("\n"); + log(" -lut :\n"); + log(" generate netlist using luts of (max) the specified width . All\n"); + log(" luts with width <= have constant cost. for luts larger than \n"); + log(" the area cost doubles with each additional input bit. the delay cost\n"); + log(" is still constant for all lut widths.\n"); + log("\n"); + log(" -lut \n"); + log(" pass this file with lut library to ABC.\n"); + log("\n"); + log(" -luts ,,,:,..\n"); + log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); + log(" 2, 3, .. inputs.\n"); + log("\n"); + log(" -showtmp\n"); + log(" print the temp dir name in log. usually this is suppressed so that the\n"); + log(" command output is identical across runs.\n"); + log("\n"); + log(" -box \n"); + log(" pass this file with box library to ABC. Use with -lut.\n"); + log("\n"); + log(" -cwd \n"); + log(" use this as the current working directory, inside which the 'input.xaig'\n"); + log(" file is expected. temporary files will be created in this directory, and\n"); + log(" the mapped result will be written to 'output.aig'.\n"); + log("\n"); + log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); + log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); + log("ABC on logic snippets extracted from your design. You will not get any useful\n"); + log("output when passing an ABC script that writes a file. Instead write your full\n"); + log("design as BLIF file with write_blif and then load that into ABC externally if\n"); + log("you want to use ABC to convert your design into another format.\n"); + log("\n"); + log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n"); + +#ifdef ABCEXTERNAL + std::string exe_file = ABCEXTERNAL; +#else + std::string exe_file = proc_self_dirname() + "yosys-abc"; +#endif + std::string script_file, clk_str, box_file, lut_file; + std::string delay_target, lutin_shared = "-S 1", wire_delay; + std::string tempdir_name; + bool fast_mode = false; + bool show_tempdir = false; + bool nomfs = false; + vector lut_costs; + +#if 0 + cleanup = false; + show_tempdir = true; +#endif + +#ifdef _WIN32 +#ifndef ABCEXTERNAL + if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) + exe_file = proc_self_dirname() + "..\\yosys-abc"; +#endif +#endif + + std::string lut_arg, luts_arg; + exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */); + script_file = design->scratchpad_get_string("abc9.script", script_file); + if (design->scratchpad.count("abc9.D")) { + delay_target = "-D " + design->scratchpad_get_string("abc9.D"); + } + lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg); + luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg); + fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode); + show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir); + box_file = design->scratchpad_get_string("abc9.box", box_file); + if (design->scratchpad.count("abc9.W")) { + wire_delay = "-W " + design->scratchpad_get_string("abc9.W"); + } + nomfs = design->scratchpad_get_bool("abc9.nomfs", nomfs); + + size_t argidx; + char pwd [PATH_MAX]; + if (!getcwd(pwd, sizeof(pwd))) { + log_cmd_error("getcwd failed: %s\n", strerror(errno)); + log_abort(); + } + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-exe" && argidx+1 < args.size()) { + exe_file = args[++argidx]; + continue; + } + if (arg == "-script" && argidx+1 < args.size()) { + script_file = args[++argidx]; + continue; + } + if (arg == "-D" && argidx+1 < args.size()) { + delay_target = "-D " + args[++argidx]; + continue; + } + //if (arg == "-S" && argidx+1 < args.size()) { + // lutin_shared = "-S " + args[++argidx]; + // continue; + //} + if (arg == "-lut" && argidx+1 < args.size()) { + lut_arg = args[++argidx]; + continue; + } + if (arg == "-luts" && argidx+1 < args.size()) { + lut_arg = args[++argidx]; + continue; + } + if (arg == "-fast") { + fast_mode = true; + continue; + } + if (arg == "-showtmp") { + show_tempdir = true; + continue; + } + if (arg == "-box" && argidx+1 < args.size()) { + box_file = args[++argidx]; + continue; + } + if (arg == "-W" && argidx+1 < args.size()) { + wire_delay = "-W " + args[++argidx]; + continue; + } + if (arg == "-nomfs") { + nomfs = true; + continue; + } + if (arg == "-cwd" && argidx+1 < args.size()) { + tempdir_name = args[++argidx]; + continue; + } + break; + } + extra_args(args, argidx, design); + + rewrite_filename(script_file); + if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') + script_file = std::string(pwd) + "/" + script_file; + + // handle -lut / -luts args + if (!lut_arg.empty()) { + string arg = lut_arg; + if (arg.find_first_not_of("0123456789:") == std::string::npos) { + size_t pos = arg.find_first_of(':'); + int lut_mode = 0, lut_mode2 = 0; + if (pos != string::npos) { + lut_mode = atoi(arg.substr(0, pos).c_str()); + lut_mode2 = atoi(arg.substr(pos+1).c_str()); + } else { + lut_mode = atoi(arg.c_str()); + lut_mode2 = lut_mode; + } + lut_costs.clear(); + for (int i = 0; i < lut_mode; i++) + lut_costs.push_back(1); + for (int i = lut_mode; i < lut_mode2; i++) + lut_costs.push_back(2 << (i - lut_mode)); + } + else { + lut_file = arg; + rewrite_filename(lut_file); + if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+') + lut_file = std::string(pwd) + "/" + lut_file; + } + } + if (!luts_arg.empty()) { + lut_costs.clear(); + for (auto &tok : split_tokens(luts_arg, ",")) { + auto parts = split_tokens(tok, ":"); + if (GetSize(parts) == 0 && !lut_costs.empty()) + lut_costs.push_back(lut_costs.back()); + else if (GetSize(parts) == 1) + lut_costs.push_back(atoi(parts.at(0).c_str())); + else if (GetSize(parts) == 2) + while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) + lut_costs.push_back(atoi(parts.at(1).c_str())); + else + log_cmd_error("Invalid -luts syntax.\n"); + } + } + + // ABC expects a box file for XAIG + if (box_file.empty()) + box_file = "+/dummy.box"; + + rewrite_filename(box_file); + if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') + box_file = std::string(pwd) + "/" + box_file; + + if (tempdir_name.empty()) + log_cmd_error("abc9_exe '-cwd' option is mandatory.\n"); + + + abc9_module(design, script_file, exe_file, lut_costs, + delay_target, lutin_shared, fast_mode, show_tempdir, + box_file, lut_file, wire_delay, nomfs, tempdir_name); + } +} Abc9ExePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/abc9_map.cc b/passes/techmap/abc9_map.cc deleted file mode 100644 index 4ed3419f0..000000000 --- a/passes/techmap/abc9_map.cc +++ /dev/null @@ -1,889 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * 2019 Eddie Hung - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// [[CITE]] ABC -// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification -// http://www.eecs.berkeley.edu/~alanmi/abc/ - -#if 0 -// Based on &flow3 - better QoR but more experimental -#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \ - "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\ - "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\ - "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ - "&mfs; &ps -l" -#else -#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" -#endif - - -#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}" - -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/cost.h" -#include "kernel/log.h" -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -# include -# include -#endif - -#include "frontends/aiger/aigerparse.h" -#include "kernel/utils.h" - -#ifdef YOSYS_LINK_ABC -extern "C" int Abc_RealMain(int argc, char *argv[]); -#endif - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -int map_autoidx; - -inline std::string remap_name(RTLIL::IdString abc9_name) -{ - return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); -} - -std::string add_echos_to_abc9_cmd(std::string str) -{ - std::string new_str, token; - for (size_t i = 0; i < str.size(); i++) { - token += str[i]; - if (str[i] == ';') { - while (i+1 < str.size() && str[i+1] == ' ') - i++; - new_str += "echo + " + token + " " + token + " "; - token.clear(); - } - } - - if (!token.empty()) { - if (!new_str.empty()) - new_str += "echo + " + token + "; "; - new_str += token; - } - - return new_str; -} - -std::string fold_abc9_cmd(std::string str) -{ - std::string token, new_str = " "; - int char_counter = 10; - - for (size_t i = 0; i <= str.size(); i++) { - if (i < str.size()) - token += str[i]; - if (i == str.size() || str[i] == ';') { - if (char_counter + token.size() > 75) - new_str += "\n ", char_counter = 14; - new_str += token, char_counter += token.size(); - token.clear(); - } - } - - return new_str; -} - -std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir) -{ - if (show_tempdir) - return text; - - while (1) { - size_t pos = text.find(tempdir_name); - if (pos == std::string::npos) - break; - text = text.substr(0, pos) + "" + text.substr(pos + GetSize(tempdir_name)); - } - - std::string selfdir_name = proc_self_dirname(); - if (selfdir_name != "/") { - while (1) { - size_t pos = text.find(selfdir_name); - if (pos == std::string::npos) - break; - text = text.substr(0, pos) + "/" + text.substr(pos + GetSize(selfdir_name)); - } - } - - return text; -} - -struct abc9_output_filter -{ - bool got_cr; - int escape_seq_state; - std::string linebuf; - std::string tempdir_name; - bool show_tempdir; - - abc9_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) - { - got_cr = false; - escape_seq_state = 0; - } - - void next_char(char ch) - { - if (escape_seq_state == 0 && ch == '\033') { - escape_seq_state = 1; - return; - } - if (escape_seq_state == 1) { - escape_seq_state = ch == '[' ? 2 : 0; - return; - } - if (escape_seq_state == 2) { - if ((ch < '0' || '9' < ch) && ch != ';') - escape_seq_state = 0; - return; - } - escape_seq_state = 0; - if (ch == '\r') { - got_cr = true; - return; - } - if (ch == '\n') { - log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str()); - got_cr = false, linebuf.clear(); - return; - } - if (got_cr) - got_cr = false, linebuf.clear(); - linebuf += ch; - } - - void next_line(const std::string &line) - { - //int pi, po; - //if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { - // log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", - // pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", - // po, po_map.count(po) ? po_map.at(po).c_str() : "???"); - // return; - //} - - for (char ch : line) - next_char(ch); - } -}; - -void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string script_file, std::string exe_file, - vector lut_costs, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, - bool show_tempdir, std::string box_file, std::string lut_file, - std::string wire_delay, bool nomfs, std::string tempdir_name -) -{ - map_autoidx = autoidx++; - - //FIXME: - //log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", - // module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); - - std::string abc9_script; - - if (!lut_costs.empty()) { - abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); - if (!box_file.empty()) - abc9_script += stringf("read_box %s; ", box_file.c_str()); - } - else - if (!lut_file.empty()) { - abc9_script += stringf("read_lut %s; ", lut_file.c_str()); - if (!box_file.empty()) - abc9_script += stringf("read_box %s; ", box_file.c_str()); - } - else - log_abort(); - - abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); - - if (!script_file.empty()) { - if (script_file[0] == '+') { - for (size_t i = 1; i < script_file.size(); i++) - if (script_file[i] == '\'') - abc9_script += "'\\''"; - else if (script_file[i] == ',') - abc9_script += " "; - else - abc9_script += script_file[i]; - } else - abc9_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty() || !lut_file.empty()) { - abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; - } else - log_abort(); - - for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) - abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); - - //for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos)) - // abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3); - - for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos)) - abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3); - - if (nomfs) - for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) - abc9_script = abc9_script.erase(pos, strlen("&mfs")); - - abc9_script += stringf("; &write -n %s/output.aig", tempdir_name.c_str()); - abc9_script = add_echos_to_abc9_cmd(abc9_script); - - for (size_t i = 0; i+1 < abc9_script.size(); i++) - if (abc9_script[i] == ';' && abc9_script[i+1] == ' ') - abc9_script[i+1] = '\n'; - - FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); - fprintf(f, "%s\n", abc9_script.c_str()); - fclose(f); - - int count_outputs = design->scratchpad_get_int("write_xaiger.num_outputs"); - log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", - design->scratchpad_get_int("write_xaiger.num_ands"), - design->scratchpad_get_int("write_xaiger.num_wires"), - design->scratchpad_get_int("write_xaiger.num_inputs"), - count_outputs); - - if (count_outputs > 0) { - std::string buffer; - std::ifstream ifs; -#if 0 - buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig"); - ifs.open(buffer); - if (ifs.fail()) - log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); - log_assert(!design->module(ID($__abc9__))); - { - AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); - reader.parse_xaiger(); - } - ifs.close(); - Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected")); - design->remove(design->module(ID($__abc9__))); -#endif - - log_header(design, "Executing ABC9.\n"); - - if (!lut_costs.empty()) { - buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); - f = fopen(buffer.c_str(), "wt"); - if (f == NULL) - log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); - for (int i = 0; i < GetSize(lut_costs); i++) - fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); - fclose(f); - } - - buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); - log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); - -#ifndef YOSYS_LINK_ABC - abc9_output_filter filt(tempdir_name, show_tempdir); - int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1)); -#else - // These needs to be mutable, supposedly due to getopt - char *abc9_argv[5]; - string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); - abc9_argv[0] = strdup(exe_file.c_str()); - abc9_argv[1] = strdup("-s"); - abc9_argv[2] = strdup("-f"); - abc9_argv[3] = strdup(tmp_script_name.c_str()); - abc9_argv[4] = 0; - int ret = Abc_RealMain(4, abc9_argv); - free(abc9_argv[0]); - free(abc9_argv[1]); - free(abc9_argv[2]); - free(abc9_argv[3]); -#endif - if (ret != 0) - log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); - - buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig"); - ifs.open(buffer, std::ifstream::binary); - if (ifs.fail()) - log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - - buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); - log_assert(!design->module(ID($__abc9__))); - - AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); - reader.parse_xaiger(); - ifs.close(); - -#if 0 - Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected")); -#endif - - log_header(design, "Re-integrating ABC9 results.\n"); - RTLIL::Module *mapped_mod = design->module(ID($__abc9__)); - if (mapped_mod == NULL) - log_error("ABC output file does not contain a module `$__abc9__'.\n"); - - for (auto w : mapped_mod->wires()) - module->addWire(remap_name(w->name), GetSize(w)); - - for (auto it = module->cells_.begin(); it != module->cells_.end(); ) - if (it->second->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) - it = module->cells_.erase(it); - else - ++it; - - dict> bit_drivers, bit_users; - TopoSort toposort; - dict not2drivers; - dict> bit2sinks; - - std::map cell_stats; - for (auto mapped_cell : mapped_mod->cells()) - { - toposort.node(mapped_cell->name); - - RTLIL::Cell *cell = nullptr; - if (mapped_cell->type == ID($_NOT_)) { - RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); - RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); - bit_users[a_bit].insert(mapped_cell->name); - bit_drivers[y_bit].insert(mapped_cell->name); - - if (!a_bit.wire) { - mapped_cell->setPort(ID::Y, module->addWire(NEW_ID)); - RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); - log_assert(wire); - module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); - } - else if (!lut_costs.empty() || !lut_file.empty()) { - RTLIL::Cell* driver_lut = nullptr; - // ABC can return NOT gates that drive POs - if (!a_bit.wire->port_input) { - // If it's not a NOT gate that that comes from a PI directly, - // find the driver LUT and clone that to guarantee that we won't - // increase the max logic depth - // (TODO: Optimise by not cloning unless will increase depth) - RTLIL::IdString driver_name; - if (GetSize(a_bit.wire) == 1) - driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); - else - driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); - driver_lut = mapped_mod->cell(driver_name); - } - - if (!driver_lut) { - // If a driver couldn't be found (could be from PI or box CI) - // then implement using a LUT - cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), - RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), - RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), - RTLIL::Const::from_string("01")); - bit2sinks[cell->getPort(ID::A)].push_back(cell); - cell_stats[ID($lut)]++; - } - else - not2drivers[mapped_cell] = driver_lut; - continue; - } - else - log_abort(); - continue; - } - cell_stats[mapped_cell->type]++; - - RTLIL::Cell *existing_cell = nullptr; - if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { - if (mapped_cell->type == ID($lut) && - GetSize(mapped_cell->getPort(ID::A)) == 1 && - mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { - SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name)); - SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); - log_abort(); - continue; - } - cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); - } - else { - existing_cell = module->cell(mapped_cell->name); - log_assert(existing_cell); - cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); - } - - RTLIL::Module* box_module = design->module(mapped_cell->type); - auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); - for (auto &mapped_conn : mapped_cell->connections()) { - RTLIL::SigSpec newsig; - for (auto c : mapped_conn.second.chunks()) { - if (c.width == 0) - continue; - //log_assert(c.width == 1); - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - newsig.append(c); - } - if (existing_cell) { - auto it = existing_cell->connections_.find(mapped_conn.first); - if (it == existing_cell->connections_.end()) - continue; - log_assert(GetSize(newsig) >= GetSize(it->second)); - newsig = newsig.extract(0, GetSize(it->second)); - } - cell->setPort(mapped_conn.first, newsig); - - if (abc9_flop) - continue; - - if (cell->input(mapped_conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : mapped_conn.second) - bit_users[i].insert(mapped_cell->name); - } - if (cell->output(mapped_conn.first)) - for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); - } - - if (existing_cell) { - cell->parameters = existing_cell->parameters; - cell->attributes = existing_cell->attributes; - if (cell->attributes.erase("\\abc9_box_seq")) { - module->swap_names(cell, existing_cell); - module->remove(existing_cell); - } - } - else { - cell->parameters = mapped_cell->parameters; - cell->attributes = mapped_cell->attributes; - } - } - - // Copy connections (and rename) from mapped_mod to module - for (auto conn : mapped_mod->connections()) { - if (!conn.first.is_fully_const()) { - auto chunks = conn.first.chunks(); - for (auto &c : chunks) - c.wire = module->wires_.at(remap_name(c.wire->name)); - conn.first = std::move(chunks); - } - if (!conn.second.is_fully_const()) { - auto chunks = conn.second.chunks(); - for (auto &c : chunks) - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - conn.second = std::move(chunks); - } - module->connect(conn); - } - - for (auto &it : cell_stats) - log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); - int in_wires = 0, out_wires = 0; - - // Stitch in mapped_mod's inputs/outputs into module - for (auto port : mapped_mod->ports) { - RTLIL::Wire *w = mapped_mod->wire(port); - RTLIL::Wire *wire = module->wire(port); - log_assert(wire); - RTLIL::Wire *remap_wire = module->wire(remap_name(port)); - RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); - log_assert(GetSize(signal) >= GetSize(remap_wire)); - - RTLIL::SigSig conn; - if (w->port_output) { - conn.first = signal; - conn.second = remap_wire; - out_wires++; - module->connect(conn); - } - else if (w->port_input) { - conn.first = remap_wire; - conn.second = signal; - in_wires++; - module->connect(conn); - } - } - - for (auto &it : bit_users) - if (bit_drivers.count(it.first)) - for (auto driver_cell : bit_drivers.at(it.first)) - for (auto user_cell : it.second) - toposort.edge(driver_cell, user_cell); - bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); - log_assert(no_loops); - - for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { - RTLIL::Cell *not_cell = mapped_mod->cell(*ii); - log_assert(not_cell); - if (not_cell->type != ID($_NOT_)) - continue; - auto it = not2drivers.find(not_cell); - if (it == not2drivers.end()) - continue; - RTLIL::Cell *driver_lut = it->second; - RTLIL::SigBit a_bit = not_cell->getPort(ID::A); - RTLIL::SigBit y_bit = not_cell->getPort(ID::Y); - RTLIL::Const driver_mask; - - a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name)); - y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name)); - - auto jt = bit2sinks.find(a_bit); - if (jt == bit2sinks.end()) - goto clone_lut; - - for (auto sink_cell : jt->second) - if (sink_cell->type != ID($lut)) - goto clone_lut; - - // Push downstream LUTs past inverter - for (auto sink_cell : jt->second) { - SigSpec A = sink_cell->getPort(ID::A); - RTLIL::Const mask = sink_cell->getParam(ID(LUT)); - int index = 0; - for (; index < GetSize(A); index++) - if (A[index] == a_bit) - break; - log_assert(index < GetSize(A)); - int i = 0; - while (i < GetSize(mask)) { - for (int j = 0; j < (1 << index); j++) - std::swap(mask[i+j], mask[i+j+(1 << index)]); - i += 1 << (index+1); - } - A[index] = y_bit; - sink_cell->setPort(ID::A, A); - sink_cell->setParam(ID(LUT), mask); - } - - // Since we have rewritten all sinks (which we know - // to be only LUTs) to be after the inverter, we can - // go ahead and clone the LUT with the expectation - // that the original driving LUT will become dangling - // and get cleaned away -clone_lut: - driver_mask = driver_lut->getParam(ID(LUT)); - for (auto &b : driver_mask.bits) { - if (b == RTLIL::State::S0) b = RTLIL::State::S1; - else if (b == RTLIL::State::S1) b = RTLIL::State::S0; - } - auto cell = module->addLut(NEW_ID, - driver_lut->getPort(ID::A), - y_bit, - driver_mask); - for (auto &bit : cell->connections_.at(ID::A)) { - bit.wire = module->wires_.at(remap_name(bit.wire->name)); - bit2sinks[bit].push_back(cell); - } - } - - //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); - log("ABC RESULTS: input signals: %8d\n", in_wires); - log("ABC RESULTS: output signals: %8d\n", out_wires); - - design->remove(mapped_mod); - } - //else - //{ - // log("Don't call ABC as there is nothing to map.\n"); - //} -} - -struct Abc9MapPass : public Pass { - Abc9MapPass() : Pass("abc9_map", "use ABC9 for technology mapping") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" abc9_map [options] [selection]\n"); - log("\n"); - log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); - log("library to a target architecture.\n"); - log("\n"); - log(" -exe \n"); -#ifdef ABCEXTERNAL - log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); -#else - log(" use the specified command instead of \"/yosys-abc\" to execute ABC.\n"); -#endif - log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n"); - log("\n"); - log(" -script \n"); - log(" use the specified ABC script file instead of the default script.\n"); - log("\n"); - log(" if starts with a plus sign (+), then the rest of the filename\n"); - log(" string is interpreted as the command string to be passed to ABC. The\n"); - log(" leading plus sign is removed and all commas (,) in the string are\n"); - log(" replaced with blanks before the string is passed to ABC.\n"); - log("\n"); - log(" if no -script parameter is given, the following scripts are used:\n"); - log("\n"); - log(" for -lut/-luts (only one LUT size):\n"); - log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); - log("\n"); - log(" for -lut/-luts (different LUT sizes):\n"); - log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); - log("\n"); - log(" -fast\n"); - log(" use different default scripts that are slightly faster (at the cost\n"); - log(" of output quality):\n"); - log("\n"); - log(" for -lut/-luts:\n"); - log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); - log("\n"); - log(" -D \n"); - log(" set delay target. the string {D} in the default scripts above is\n"); - log(" replaced by this option when used, and an empty string otherwise\n"); - log(" (indicating best possible delay).\n"); - log("\n"); -// log(" -S \n"); -// log(" maximum number of LUT inputs shared.\n"); -// log(" (replaces {S} in the default scripts above, default: -S 1)\n"); -// log("\n"); - log(" -lut \n"); - log(" generate netlist using luts of (max) the specified width.\n"); - log("\n"); - log(" -lut :\n"); - log(" generate netlist using luts of (max) the specified width . All\n"); - log(" luts with width <= have constant cost. for luts larger than \n"); - log(" the area cost doubles with each additional input bit. the delay cost\n"); - log(" is still constant for all lut widths.\n"); - log("\n"); - log(" -lut \n"); - log(" pass this file with lut library to ABC.\n"); - log("\n"); - log(" -luts ,,,:,..\n"); - log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); - log(" 2, 3, .. inputs.\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("\n"); - log(" -showtmp\n"); - log(" print the temp dir name in log. usually this is suppressed so that the\n"); - log(" command output is identical across runs.\n"); - log("\n"); - log(" -box \n"); - log(" pass this file with box library to ABC. Use with -lut.\n"); - log("\n"); - log(" -tempdir \n"); - log(" use this as the temp dir.\n"); - log("\n"); - log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); - log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); - log("ABC on logic snippets extracted from your design. You will not get any useful\n"); - log("output when passing an ABC script that writes a file. Instead write your full\n"); - log("design as BLIF file with write_blif and then load that into ABC externally if\n"); - log("you want to use ABC to convert your design into another format.\n"); - log("\n"); - log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n"); - -#ifdef ABCEXTERNAL - std::string exe_file = ABCEXTERNAL; -#else - std::string exe_file = proc_self_dirname() + "yosys-abc"; -#endif - std::string script_file, clk_str, box_file, lut_file; - std::string delay_target, lutin_shared = "-S 1", wire_delay; - std::string tempdir_name; - bool fast_mode = false; - bool show_tempdir = false; - bool nomfs = false; - vector lut_costs; - -#if 0 - cleanup = false; - show_tempdir = true; -#endif - -#ifdef _WIN32 -#ifndef ABCEXTERNAL - if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) - exe_file = proc_self_dirname() + "..\\yosys-abc"; -#endif -#endif - - std::string lut_arg, luts_arg; - exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */); - script_file = design->scratchpad_get_string("abc9.script", script_file); - if (design->scratchpad.count("abc9.D")) { - delay_target = "-D " + design->scratchpad_get_string("abc9.D"); - } - lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg); - luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg); - fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode); - show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir); - box_file = design->scratchpad_get_string("abc9.box", box_file); - if (design->scratchpad.count("abc9.W")) { - wire_delay = "-W " + design->scratchpad_get_string("abc9.W"); - } - nomfs = design->scratchpad_get_bool("abc9.nomfs", nomfs); - - size_t argidx; - char pwd [PATH_MAX]; - if (!getcwd(pwd, sizeof(pwd))) { - log_cmd_error("getcwd failed: %s\n", strerror(errno)); - log_abort(); - } - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-exe" && argidx+1 < args.size()) { - exe_file = args[++argidx]; - continue; - } - if (arg == "-script" && argidx+1 < args.size()) { - script_file = args[++argidx]; - continue; - } - if (arg == "-D" && argidx+1 < args.size()) { - delay_target = "-D " + args[++argidx]; - continue; - } - //if (arg == "-S" && argidx+1 < args.size()) { - // lutin_shared = "-S " + args[++argidx]; - // continue; - //} - if (arg == "-lut" && argidx+1 < args.size()) { - lut_arg = args[++argidx]; - continue; - } - if (arg == "-luts" && argidx+1 < args.size()) { - lut_arg = args[++argidx]; - continue; - } - if (arg == "-fast") { - fast_mode = true; - continue; - } - if (arg == "-showtmp") { - show_tempdir = true; - continue; - } - if (arg == "-box" && argidx+1 < args.size()) { - box_file = args[++argidx]; - continue; - } - if (arg == "-W" && argidx+1 < args.size()) { - wire_delay = "-W " + args[++argidx]; - continue; - } - if (arg == "-nomfs") { - nomfs = true; - continue; - } - if (arg == "-tempdir" && argidx+1 < args.size()) { - tempdir_name = args[++argidx]; - continue; - } - break; - } - extra_args(args, argidx, design); - - rewrite_filename(script_file); - if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') - script_file = std::string(pwd) + "/" + script_file; - - // handle -lut / -luts args - if (!lut_arg.empty()) { - string arg = lut_arg; - if (arg.find_first_not_of("0123456789:") == std::string::npos) { - size_t pos = arg.find_first_of(':'); - int lut_mode = 0, lut_mode2 = 0; - if (pos != string::npos) { - lut_mode = atoi(arg.substr(0, pos).c_str()); - lut_mode2 = atoi(arg.substr(pos+1).c_str()); - } else { - lut_mode = atoi(arg.c_str()); - lut_mode2 = lut_mode; - } - lut_costs.clear(); - for (int i = 0; i < lut_mode; i++) - lut_costs.push_back(1); - for (int i = lut_mode; i < lut_mode2; i++) - lut_costs.push_back(2 << (i - lut_mode)); - } - else { - lut_file = arg; - rewrite_filename(lut_file); - if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+') - lut_file = std::string(pwd) + "/" + lut_file; - } - } - if (!luts_arg.empty()) { - lut_costs.clear(); - for (auto &tok : split_tokens(luts_arg, ",")) { - auto parts = split_tokens(tok, ":"); - if (GetSize(parts) == 0 && !lut_costs.empty()) - lut_costs.push_back(lut_costs.back()); - else if (GetSize(parts) == 1) - lut_costs.push_back(atoi(parts.at(0).c_str())); - else if (GetSize(parts) == 2) - while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) - lut_costs.push_back(atoi(parts.at(1).c_str())); - else - log_cmd_error("Invalid -luts syntax.\n"); - } - } - - // ABC expects a box file for XAIG - if (box_file.empty()) - box_file = "+/dummy.box"; - - rewrite_filename(box_file); - if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') - box_file = std::string(pwd) + "/" + box_file; - - if (tempdir_name.empty()) - log_cmd_error("abc9_map '-tempdir' option is mandatory.\n"); - - - for (auto mod : design->selected_modules()) - { - if (mod->processes.size() > 0) { - log("Skipping module %s as it contains processes.\n", log_id(mod)); - continue; - } - - if (!design->selected_whole_module(mod)) - log_error("Can't handle partially selected module %s!\n", log_id(mod)); - - abc9_module(design, mod, script_file, exe_file, lut_costs, - delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay, nomfs, tempdir_name); - } - } -} Abc9MapPass; - -PRIVATE_NAMESPACE_END diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index ab5aa9f8d..c8d91a6ac 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -26,6 +26,13 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +int map_autoidx; + +inline std::string remap_name(RTLIL::IdString abc9_name) +{ + return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); +} + void break_scc(RTLIL::Module *module) { // For every unique SCC found, (arbitrarily) find the first @@ -416,6 +423,276 @@ void prep_holes(RTLIL::Module *module, bool dff) } } +void reintegrate(RTLIL::Module *module) +{ + auto design = module->design; + log_assert(design); + + map_autoidx = autoidx++; + + 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)); + + for (auto w : mapped_mod->wires()) + module->addWire(remap_name(w->name), GetSize(w)); + + for (auto it = module->cells_.begin(); it != module->cells_.end(); ) + if (it->second->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) + it = module->cells_.erase(it); + else + ++it; + + dict> bit_drivers, bit_users; + TopoSort toposort; + dict not2drivers; + dict> bit2sinks; + + std::map cell_stats; + for (auto mapped_cell : mapped_mod->cells()) + { + toposort.node(mapped_cell->name); + + RTLIL::Cell *cell = nullptr; + if (mapped_cell->type == ID($_NOT_)) { + RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); + RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); + bit_users[a_bit].insert(mapped_cell->name); + bit_drivers[y_bit].insert(mapped_cell->name); + + if (!a_bit.wire) { + mapped_cell->setPort(ID::Y, module->addWire(NEW_ID)); + RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); + log_assert(wire); + module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); + } + else { + RTLIL::Cell* driver_lut = nullptr; + // ABC can return NOT gates that drive POs + if (!a_bit.wire->port_input) { + // If it's not a NOT gate that that comes from a PI directly, + // find the driver LUT and clone that to guarantee that we won't + // increase the max logic depth + // (TODO: Optimise by not cloning unless will increase depth) + RTLIL::IdString driver_name; + if (GetSize(a_bit.wire) == 1) + driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); + else + driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); + driver_lut = mapped_mod->cell(driver_name); + } + + if (!driver_lut) { + // If a driver couldn't be found (could be from PI or box CI) + // then implement using a LUT + cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), + RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), + RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), + RTLIL::Const::from_string("01")); + bit2sinks[cell->getPort(ID::A)].push_back(cell); + cell_stats[ID($lut)]++; + } + else + not2drivers[mapped_cell] = driver_lut; + } + continue; + } + cell_stats[mapped_cell->type]++; + + RTLIL::Cell *existing_cell = nullptr; + if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { + if (mapped_cell->type == ID($lut) && + GetSize(mapped_cell->getPort(ID::A)) == 1 && + mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { + SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name)); + SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name)); + module->connect(my_y, my_a); + log_abort(); + continue; + } + cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + } + else { + existing_cell = module->cell(mapped_cell->name); + log_assert(existing_cell); + cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + } + + RTLIL::Module* box_module = design->module(mapped_cell->type); + auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); + for (auto &mapped_conn : mapped_cell->connections()) { + RTLIL::SigSpec newsig; + for (auto c : mapped_conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + if (existing_cell) { + auto it = existing_cell->connections_.find(mapped_conn.first); + if (it == existing_cell->connections_.end()) + continue; + log_assert(GetSize(newsig) >= GetSize(it->second)); + newsig = newsig.extract(0, GetSize(it->second)); + } + cell->setPort(mapped_conn.first, newsig); + + if (abc9_flop) + continue; + + if (cell->input(mapped_conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : mapped_conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(mapped_conn.first)) + for (auto i : mapped_conn.second) + bit_drivers[i].insert(mapped_cell->name); + } + + if (existing_cell) { + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + if (cell->attributes.erase("\\abc9_box_seq")) { + module->swap_names(cell, existing_cell); + module->remove(existing_cell); + } + } + else { + cell->parameters = mapped_cell->parameters; + cell->attributes = mapped_cell->attributes; + } + } + + // Copy connections (and rename) from mapped_mod to module + for (auto conn : mapped_mod->connections()) { + if (!conn.first.is_fully_const()) { + auto chunks = conn.first.chunks(); + for (auto &c : chunks) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.first = std::move(chunks); + } + if (!conn.second.is_fully_const()) { + auto chunks = conn.second.chunks(); + for (auto &c : chunks) + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.second = std::move(chunks); + } + module->connect(conn); + } + + for (auto &it : cell_stats) + log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); + int in_wires = 0, out_wires = 0; + + // Stitch in mapped_mod's inputs/outputs into module + for (auto port : mapped_mod->ports) { + RTLIL::Wire *w = mapped_mod->wire(port); + RTLIL::Wire *wire = module->wire(port); + log_assert(wire); + RTLIL::Wire *remap_wire = module->wire(remap_name(port)); + RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); + log_assert(GetSize(signal) >= GetSize(remap_wire)); + + RTLIL::SigSig conn; + if (w->port_output) { + conn.first = signal; + conn.second = remap_wire; + out_wires++; + module->connect(conn); + } + else if (w->port_input) { + conn.first = remap_wire; + conn.second = signal; + in_wires++; + module->connect(conn); + } + } + + for (auto &it : bit_users) + if (bit_drivers.count(it.first)) + for (auto driver_cell : bit_drivers.at(it.first)) + for (auto user_cell : it.second) + toposort.edge(driver_cell, user_cell); + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); + log_assert(no_loops); + + for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { + RTLIL::Cell *not_cell = mapped_mod->cell(*ii); + log_assert(not_cell); + if (not_cell->type != ID($_NOT_)) + continue; + auto it = not2drivers.find(not_cell); + if (it == not2drivers.end()) + continue; + RTLIL::Cell *driver_lut = it->second; + RTLIL::SigBit a_bit = not_cell->getPort(ID::A); + RTLIL::SigBit y_bit = not_cell->getPort(ID::Y); + RTLIL::Const driver_mask; + + a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name)); + y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name)); + + auto jt = bit2sinks.find(a_bit); + if (jt == bit2sinks.end()) + goto clone_lut; + + for (auto sink_cell : jt->second) + if (sink_cell->type != ID($lut)) + goto clone_lut; + + // Push downstream LUTs past inverter + for (auto sink_cell : jt->second) { + SigSpec A = sink_cell->getPort(ID::A); + RTLIL::Const mask = sink_cell->getParam(ID(LUT)); + int index = 0; + for (; index < GetSize(A); index++) + if (A[index] == a_bit) + break; + log_assert(index < GetSize(A)); + int i = 0; + while (i < GetSize(mask)) { + for (int j = 0; j < (1 << index); j++) + std::swap(mask[i+j], mask[i+j+(1 << index)]); + i += 1 << (index+1); + } + A[index] = y_bit; + sink_cell->setPort(ID::A, A); + sink_cell->setParam(ID(LUT), mask); + } + + // Since we have rewritten all sinks (which we know + // to be only LUTs) to be after the inverter, we can + // go ahead and clone the LUT with the expectation + // that the original driving LUT will become dangling + // and get cleaned away +clone_lut: + driver_mask = driver_lut->getParam(ID(LUT)); + for (auto &b : driver_mask.bits) { + if (b == RTLIL::State::S0) b = RTLIL::State::S1; + else if (b == RTLIL::State::S1) b = RTLIL::State::S0; + } + auto cell = module->addLut(NEW_ID, + driver_lut->getPort(ID::A), + y_bit, + driver_mask); + for (auto &bit : cell->connections_.at(ID::A)) { + bit.wire = module->wires_.at(remap_name(bit.wire->name)); + bit2sinks[bit].push_back(cell); + } + } + + //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); + log("ABC RESULTS: input signals: %8d\n", in_wires); + log("ABC RESULTS: output signals: %8d\n", out_wires); + + design->remove(mapped_mod); +} + struct Abc9OpsPass : public Pass { Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { } void help() YS_OVERRIDE @@ -433,6 +710,7 @@ struct Abc9OpsPass : public Pass { bool unbreak_scc_mode = false; bool prep_dff_mode = false; bool prep_holes_mode = false; + bool reintegrate_mode = false; bool dff_mode = false; size_t argidx; @@ -454,6 +732,10 @@ struct Abc9OpsPass : public Pass { prep_holes_mode = true; continue; } + if (arg == "-reintegrate") { + reintegrate_mode = true; + continue; + } if (arg == "-dff") { dff_mode = true; continue; @@ -463,8 +745,6 @@ struct Abc9OpsPass : public Pass { extra_args(args, argidx, design); for (auto mod : design->selected_modules()) { - if (mod->get_blackbox_attribute()) - continue; if (mod->get_bool_attribute("\\abc9_holes")) continue; @@ -481,6 +761,8 @@ struct Abc9OpsPass : public Pass { prep_dff(mod); if (prep_holes_mode) prep_holes(mod, dff_mode); + if (reintegrate_mode) + reintegrate(mod); } } } Abc9OpsPass; -- cgit v1.2.3 From 5d9050a9551628f838ee419404cf1b1d3920a3ed Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 7 Jan 2020 08:00:32 -0800 Subject: abc_exe: move 'count_outputs' check to abc --- passes/techmap/abc9.cc | 27 ++++++++++------ passes/techmap/abc9_exe.cc | 77 +++++++++++++++++++--------------------------- 2 files changed, 50 insertions(+), 54 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7c261e220..0a5454d99 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -219,16 +219,25 @@ struct Abc9Pass : public ScriptPass tempdir_name = make_temp_dir(tempdir_name); run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), - "write_xaiger -map /input.sym /input.xaig"); - run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()), - "abc9_exe [options] -cwd "); - - run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()), - "read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); - run("abc9_ops -reintegrate"); + "write_xaiger -map /input.sym /input.xaig"); + + int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs"); + log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", + active_design->scratchpad_get_int("write_xaiger.num_ands"), + active_design->scratchpad_get_int("write_xaiger.num_wires"), + active_design->scratchpad_get_int("write_xaiger.num_inputs"), + num_outputs); + if (num_outputs) { + run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()), + "abc9_exe [options] -cwd "); + run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()), + "read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); + run("abc9_ops -reintegrate"); + } + else + log("Don't call ABC as there is nothing to map.\n"); - if (cleanup) - { + if (cleanup) { log("Removing temp directory.\n"); remove_directory(tempdir_name); } diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index 36d7faf1b..f7dafda96 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -244,56 +244,43 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe fprintf(f, "%s\n", abc9_script.c_str()); fclose(f); - int count_outputs = design->scratchpad_get_int("write_xaiger.num_outputs"); - log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", - design->scratchpad_get_int("write_xaiger.num_ands"), - design->scratchpad_get_int("write_xaiger.num_wires"), - design->scratchpad_get_int("write_xaiger.num_inputs"), - count_outputs); - - if (count_outputs > 0) { - std::string buffer; - - log_header(design, "Executing ABC9.\n"); - - if (!lut_costs.empty()) { - buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); - f = fopen(buffer.c_str(), "wt"); - if (f == NULL) - log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); - for (int i = 0; i < GetSize(lut_costs); i++) - fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); - fclose(f); - } + std::string buffer; + + log_header(design, "Executing ABC9.\n"); + + if (!lut_costs.empty()) { + buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); + f = fopen(buffer.c_str(), "wt"); + if (f == NULL) + log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); + for (int i = 0; i < GetSize(lut_costs); i++) + fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); + fclose(f); + } - buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); - log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); + buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); + log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); #ifndef YOSYS_LINK_ABC - abc9_output_filter filt(tempdir_name, show_tempdir); - int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1)); + abc9_output_filter filt(tempdir_name, show_tempdir); + int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1)); #else - // These needs to be mutable, supposedly due to getopt - char *abc9_argv[5]; - string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); - abc9_argv[0] = strdup(exe_file.c_str()); - abc9_argv[1] = strdup("-s"); - abc9_argv[2] = strdup("-f"); - abc9_argv[3] = strdup(tmp_script_name.c_str()); - abc9_argv[4] = 0; - int ret = Abc_RealMain(4, abc9_argv); - free(abc9_argv[0]); - free(abc9_argv[1]); - free(abc9_argv[2]); - free(abc9_argv[3]); + // These needs to be mutable, supposedly due to getopt + char *abc9_argv[5]; + string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); + abc9_argv[0] = strdup(exe_file.c_str()); + abc9_argv[1] = strdup("-s"); + abc9_argv[2] = strdup("-f"); + abc9_argv[3] = strdup(tmp_script_name.c_str()); + abc9_argv[4] = 0; + int ret = Abc_RealMain(4, abc9_argv); + free(abc9_argv[0]); + free(abc9_argv[1]); + free(abc9_argv[2]); + free(abc9_argv[3]); #endif - if (ret != 0) - log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); - } - else - { - log("Don't call ABC as there is nothing to map.\n"); - } + if (ret != 0) + log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); } struct Abc9ExePass : public Pass { -- cgit v1.2.3 From 6e12ba218be1beaa6da712ebf96ff08593793967 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 7 Jan 2020 09:32:58 -0800 Subject: Fix tabs and cleanup --- passes/techmap/abc9_ops.cc | 76 +++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index c8d91a6ac..69239c93d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -521,49 +521,49 @@ void reintegrate(RTLIL::Module *module) RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); for (auto &mapped_conn : mapped_cell->connections()) { - RTLIL::SigSpec newsig; - for (auto c : mapped_conn.second.chunks()) { - if (c.width == 0) - continue; - //log_assert(c.width == 1); - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - newsig.append(c); - } - if (existing_cell) { - auto it = existing_cell->connections_.find(mapped_conn.first); - if (it == existing_cell->connections_.end()) - continue; - log_assert(GetSize(newsig) >= GetSize(it->second)); - newsig = newsig.extract(0, GetSize(it->second)); - } - cell->setPort(mapped_conn.first, newsig); - - if (abc9_flop) - continue; + RTLIL::SigSpec newsig; + for (auto c : mapped_conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + if (existing_cell) { + auto it = existing_cell->connections_.find(mapped_conn.first); + if (it == existing_cell->connections_.end()) + continue; + log_assert(GetSize(newsig) >= GetSize(it->second)); + newsig = newsig.extract(0, GetSize(it->second)); + } + cell->setPort(mapped_conn.first, newsig); - if (cell->input(mapped_conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : mapped_conn.second) - bit_users[i].insert(mapped_cell->name); - } - if (cell->output(mapped_conn.first)) - for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); + if (abc9_flop) + continue; + + if (cell->input(mapped_conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : mapped_conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(mapped_conn.first)) + for (auto i : mapped_conn.second) + bit_drivers[i].insert(mapped_cell->name); } if (existing_cell) { - cell->parameters = existing_cell->parameters; - cell->attributes = existing_cell->attributes; - if (cell->attributes.erase("\\abc9_box_seq")) { - module->swap_names(cell, existing_cell); - module->remove(existing_cell); - } + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + if (cell->attributes.erase("\\abc9_box_seq")) { + module->swap_names(cell, existing_cell); + module->remove(existing_cell); + } } else { - cell->parameters = mapped_cell->parameters; - cell->attributes = mapped_cell->attributes; + cell->parameters = mapped_cell->parameters; + cell->attributes = mapped_cell->attributes; } } @@ -595,7 +595,7 @@ void reintegrate(RTLIL::Module *module) RTLIL::Wire *wire = module->wire(port); log_assert(wire); RTLIL::Wire *remap_wire = module->wire(remap_name(port)); - RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); + RTLIL::SigSpec signal(wire, 0, GetSize(remap_wire)); log_assert(GetSize(signal) >= GetSize(remap_wire)); RTLIL::SigSig conn; -- cgit v1.2.3 From dc3b21c1c050416aae443231729c8f4e4faf93ab Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 7 Jan 2020 09:48:57 -0800 Subject: abc9_ops -reintegrate: process box connections --- passes/techmap/abc9_ops.cc | 161 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 134 insertions(+), 27 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 69239c93d..721a33f09 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -437,6 +437,57 @@ void reintegrate(RTLIL::Module *module) for (auto w : mapped_mod->wires()) module->addWire(remap_name(w->name), GetSize(w)); + dict box_lookup; + dict> box_ports; + + for (auto m : design->modules()) { + auto it = m->attributes.find(ID(abc9_box_id)); + if (it == m->attributes.end()) + continue; + if (m->name.begins_with("$paramod")) + continue; + auto id = it->second.as_int(); + auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); + if (!r.second) + log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", + log_id(m), id, log_id(r.first->second)); + log_assert(r.second); + + auto r2 = box_ports.insert(m->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 : m->ports) { + auto w = m->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) { + if (carry_in != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); + carry_in = port_name; + } + if (w->port_output) { + if (carry_out != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(m)); + carry_out = port_name; + } + } + else + r2.first->second.push_back(port_name); + } + + if (carry_in != IdString() && carry_out == IdString()) + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); + if (carry_in == IdString() && carry_out != IdString()) + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); + } + } + } + for (auto it = module->cells_.begin(); it != module->cells_.end(); ) if (it->second->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) it = module->cells_.erase(it); @@ -515,42 +566,98 @@ void reintegrate(RTLIL::Module *module) else { existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); + + if (mapped_cell->type.begins_with("$__boxid")) { + auto type = box_lookup.at(mapped_cell->type, IdString()); + if (type == IdString()) + log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); + mapped_cell->type = type; + } cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); } - RTLIL::Module* box_module = design->module(mapped_cell->type); - auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); - for (auto &mapped_conn : mapped_cell->connections()) { - RTLIL::SigSpec newsig; - for (auto c : mapped_conn.second.chunks()) { - if (c.width == 0) - continue; - //log_assert(c.width == 1); - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - newsig.append(c); + if (existing_cell) { + auto it = mapped_cell->connections_.find("\\i"); + log_assert(it != mapped_cell->connections_.end()); + SigSpec inputs = std::move(it->second); + mapped_cell->connections_.erase(it); + it = mapped_cell->connections_.find("\\o"); + log_assert(it != mapped_cell->connections_.end()); + SigSpec outputs = std::move(it->second); + mapped_cell->connections_.erase(it); + + RTLIL::Module* box_module = design->module(mapped_cell->type); + auto abc9_flop = box_module->attributes.count("\\abc9_flop"); + if (!abc9_flop) { + for (const auto &i : inputs) + bit_users[i].insert(mapped_cell->name); + for (const auto &i : outputs) + bit_drivers[i].insert(mapped_cell->name); } - if (existing_cell) { - auto it = existing_cell->connections_.find(mapped_conn.first); + + int input_count = 0, output_count = 0; + for (const auto &port_name : box_ports.at(cell->type)) { + RTLIL::Wire *w = box_module->wire(port_name); + log_assert(w); + + SigSpec sig; + if (w->port_input) { + sig = inputs.extract(input_count, GetSize(w)); + input_count += GetSize(w); + } + if (w->port_output) { + sig = outputs.extract(output_count, GetSize(w)); + output_count += GetSize(w); + } + + SigSpec newsig; + for (auto c : sig.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + + auto it = existing_cell->connections_.find(port_name); if (it == existing_cell->connections_.end()) continue; - log_assert(GetSize(newsig) >= GetSize(it->second)); - newsig = newsig.extract(0, GetSize(it->second)); - } - cell->setPort(mapped_conn.first, newsig); + if (GetSize(newsig) > GetSize(it->second)) + newsig = newsig.extract(0, GetSize(it->second)); + else + log_assert(GetSize(newsig) == GetSize(it->second)); - if (abc9_flop) - continue; + cell->setPort(port_name, newsig); - if (cell->input(mapped_conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : mapped_conn.second) - bit_users[i].insert(mapped_cell->name); + if (w->port_input && !abc9_flop) + for (const auto &i : newsig) + bit2sinks[i].push_back(cell); + } + } + else { + for (auto &mapped_conn : mapped_cell->connections()) { + RTLIL::SigSpec newsig; + for (auto c : mapped_conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + cell->setPort(mapped_conn.first, newsig); + + if (cell->input(mapped_conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : mapped_conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(mapped_conn.first)) + for (auto i : mapped_conn.second) + bit_drivers[i].insert(mapped_cell->name); } - if (cell->output(mapped_conn.first)) - for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); } if (existing_cell) { -- cgit v1.2.3 From 8a47e6ddfdb49ec172f783621a64b3a8906ff5d6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 8 Jan 2020 10:00:50 -0800 Subject: Fix abc9 help, add labels --- passes/techmap/abc9.cc | 129 +++++++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 58 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 0a5454d99..f6627602b 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -184,70 +184,83 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { - run("scc -set_attr abc9_scc_id {}"); - if (help_mode) - run("abc9_ops -break_scc -prep_holes [-dff]", "(option for -dff)"); - else - run("abc9_ops -break_scc -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); - run("select -set abc9_holes A:abc9_holes"); - run("flatten -wb @abc9_holes"); - run("techmap @abc9_holes"); - run("aigmap"); - if (dff_mode) - run("abc9_ops -prep_dff"); - run("opt -purge @abc9_holes"); - run("wbflip @abc9_holes"); - - auto selected_modules = active_design->selected_modules(); - active_design->selection_stack.emplace_back(false); - - for (auto mod : selected_modules) { - if (mod->processes.size() > 0) { - log("Skipping module %s as it contains processes.\n", log_id(mod)); - continue; - } - log_assert(!mod->attributes.count(ID(abc9_box_id))); - - active_design->selection().select(mod); - - if (!active_design->selected_whole_module(mod)) - log_error("Can't handle partially selected module %s!\n", log_id(mod)); - - std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; - if (!cleanup) - tempdir_name[0] = tempdir_name[4] = '_'; - tempdir_name = make_temp_dir(tempdir_name); - - run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), - "write_xaiger -map /input.sym /input.xaig"); - - int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs"); - log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", - active_design->scratchpad_get_int("write_xaiger.num_ands"), - active_design->scratchpad_get_int("write_xaiger.num_wires"), - active_design->scratchpad_get_int("write_xaiger.num_inputs"), - num_outputs); - if (num_outputs) { - run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()), - "abc9_exe [options] -cwd "); - run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()), - "read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); - run("abc9_ops -reintegrate"); - } + if (check_label("pre")) { + run("scc -set_attr abc9_scc_id {}"); + if (help_mode) + run("abc9_ops -break_scc -prep_holes [-dff]", "(option for -dff)"); else - log("Don't call ABC as there is nothing to map.\n"); + run("abc9_ops -break_scc -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); + run("select -set abc9_holes A:abc9_holes"); + run("flatten -wb @abc9_holes"); + run("techmap @abc9_holes"); + run("aigmap"); + if (dff_mode || help_mode) + run("abc9_ops -prep_dff", "(only if -dff)"); + run("opt -purge @abc9_holes"); + run("wbflip @abc9_holes"); + } - if (cleanup) { - log("Removing temp directory.\n"); - remove_directory(tempdir_name); + if (check_label("map")) { + if (help_mode) { + run("foreach module in selection"); + run(" write_xaiger -map /input.sym /input.xaig"); + run(" abc9_exe [options] -cwd "); + run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); + run(" abc9_ops -reintegrate"); } + else { + auto selected_modules = active_design->selected_modules(); + active_design->selection_stack.emplace_back(false); - active_design->selection().selected_modules.clear(); - } + for (auto mod : selected_modules) { + if (mod->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(mod)); + continue; + } + log_assert(!mod->attributes.count(ID(abc9_box_id))); + + active_design->selection().select(mod); + + if (!active_design->selected_whole_module(mod)) + log_error("Can't handle partially selected module %s!\n", log_id(mod)); - active_design->selection_stack.pop_back(); + std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; + if (!cleanup) + tempdir_name[0] = tempdir_name[4] = '_'; + tempdir_name = make_temp_dir(tempdir_name); + + run(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"); + log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", + active_design->scratchpad_get_int("write_xaiger.num_ands"), + active_design->scratchpad_get_int("write_xaiger.num_wires"), + active_design->scratchpad_get_int("write_xaiger.num_inputs"), + num_outputs); + if (num_outputs) { + run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()), + "abc9_exe [options] -cwd "); + run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()), + "read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); + run("abc9_ops -reintegrate"); + } + else + log("Don't call ABC as there is nothing to map.\n"); + + if (cleanup) { + log("Removing temp directory.\n"); + remove_directory(tempdir_name); + } + + active_design->selection().selected_modules.clear(); + } + + active_design->selection_stack.pop_back(); + } + } - run("abc9_ops -unbreak_scc"); + if (check_label("post")) + run("abc9_ops -unbreak_scc"); } } Abc9Pass; -- cgit v1.2.3 From 88f14b8bca811a3945aa642ccd50d22ffa0adcbd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 8 Jan 2020 10:02:45 -0800 Subject: Cleanup --- passes/techmap/abc9.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index f6627602b..ba5f97626 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -204,7 +204,7 @@ struct Abc9Pass : public ScriptPass if (help_mode) { run("foreach module in selection"); run(" write_xaiger -map /input.sym /input.xaig"); - run(" abc9_exe [options] -cwd "); + run(" abc9_exe -cwd [options]"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); run(" abc9_ops -reintegrate"); } @@ -238,10 +238,8 @@ struct Abc9Pass : public ScriptPass active_design->scratchpad_get_int("write_xaiger.num_inputs"), num_outputs); if (num_outputs) { - run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()), - "abc9_exe [options] -cwd "); - run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()), - "read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); + run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str())); + run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str())); run("abc9_ops -reintegrate"); } else -- cgit v1.2.3 From 4e396ee7a39682cb859aa64a89b40a149cb4148b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 9 Jan 2020 11:21:03 -0800 Subject: abc9_ops: fix reintegration by removing optimised-away boxes --- passes/techmap/abc9_ops.cc | 106 +++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 56 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 721a33f09..7c7208711 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -488,11 +488,13 @@ void reintegrate(RTLIL::Module *module) } } - for (auto it = module->cells_.begin(); it != module->cells_.end(); ) - if (it->second->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) - it = module->cells_.erase(it); - else - ++it; + std::vector boxes; + for (auto cell : module->cells().to_vector()) { + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) + module->remove(cell); + else if (cell->attributes.erase("\\abc9_box_seq")) + boxes.emplace_back(cell); + } dict> bit_drivers, bit_users; TopoSort toposort; @@ -504,7 +506,6 @@ void reintegrate(RTLIL::Module *module) { toposort.node(mapped_cell->name); - RTLIL::Cell *cell = nullptr; if (mapped_cell->type == ID($_NOT_)) { RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); @@ -536,7 +537,7 @@ void reintegrate(RTLIL::Module *module) if (!driver_lut) { // If a driver couldn't be found (could be from PI or box CI) // then implement using a LUT - cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), + RTLIL::Cell *cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), RTLIL::Const::from_string("01")); @@ -548,10 +549,9 @@ void reintegrate(RTLIL::Module *module) } continue; } - cell_stats[mapped_cell->type]++; - RTLIL::Cell *existing_cell = nullptr; if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { + // Convert buffer into direct connection if (mapped_cell->type == ID($lut) && GetSize(mapped_cell->getPort(ID::A)) == 1 && mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { @@ -561,22 +561,48 @@ void reintegrate(RTLIL::Module *module) log_abort(); continue; } - cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + cell->parameters = mapped_cell->parameters; + cell->attributes = mapped_cell->attributes; + + for (auto &mapped_conn : mapped_cell->connections()) { + RTLIL::SigSpec newsig; + for (auto c : mapped_conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + cell->setPort(mapped_conn.first, newsig); + + if (cell->input(mapped_conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : mapped_conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(mapped_conn.first)) + for (auto i : mapped_conn.second) + bit_drivers[i].insert(mapped_cell->name); + } } else { - existing_cell = module->cell(mapped_cell->name); + RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); + log_assert(mapped_cell->type.begins_with("$__boxid")); - if (mapped_cell->type.begins_with("$__boxid")) { - auto type = box_lookup.at(mapped_cell->type, IdString()); - if (type == IdString()) - log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); - mapped_cell->type = type; - } - cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); - } + auto type = box_lookup.at(mapped_cell->type, IdString()); + if (type == IdString()) + log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); + mapped_cell->type = type; + + RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + module->swap_names(cell, existing_cell); - if (existing_cell) { auto it = mapped_cell->connections_.find("\\i"); log_assert(it != mapped_cell->connections_.end()); SigSpec inputs = std::move(it->second); @@ -635,45 +661,13 @@ void reintegrate(RTLIL::Module *module) bit2sinks[i].push_back(cell); } } - else { - for (auto &mapped_conn : mapped_cell->connections()) { - RTLIL::SigSpec newsig; - for (auto c : mapped_conn.second.chunks()) { - if (c.width == 0) - continue; - //log_assert(c.width == 1); - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - newsig.append(c); - } - cell->setPort(mapped_conn.first, newsig); - - if (cell->input(mapped_conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : mapped_conn.second) - bit_users[i].insert(mapped_cell->name); - } - if (cell->output(mapped_conn.first)) - for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); - } - } - if (existing_cell) { - cell->parameters = existing_cell->parameters; - cell->attributes = existing_cell->attributes; - if (cell->attributes.erase("\\abc9_box_seq")) { - module->swap_names(cell, existing_cell); - module->remove(existing_cell); - } - } - else { - cell->parameters = mapped_cell->parameters; - cell->attributes = mapped_cell->attributes; - } + cell_stats[mapped_cell->type]++; } + for (auto cell : boxes) + module->remove(cell); + // Copy connections (and rename) from mapped_mod to module for (auto conn : mapped_mod->connections()) { if (!conn.first.is_fully_const()) { -- cgit v1.2.3 From 5e280a3b591d3d8b556992b0708fcaaf6a6a3e0d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 9 Jan 2020 14:04:10 -0800 Subject: abc9_exe: -box to not require -lut --- passes/techmap/abc9_exe.cc | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index f7dafda96..b3afaebe6 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -188,20 +188,15 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe std::string abc9_script; - if (!lut_costs.empty()) { + if (!lut_costs.empty()) abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); - if (!box_file.empty()) - abc9_script += stringf("read_box %s; ", box_file.c_str()); - } else - if (!lut_file.empty()) { + if (!lut_file.empty()) abc9_script += stringf("read_lut %s; ", lut_file.c_str()); - if (!box_file.empty()) - abc9_script += stringf("read_box %s; ", box_file.c_str()); - } else log_abort(); + abc9_script += stringf("read_box %s; ", box_file.c_str()); abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); if (!script_file.empty()) { @@ -355,7 +350,7 @@ struct Abc9ExePass : public Pass { log(" command output is identical across runs.\n"); log("\n"); log(" -box \n"); - log(" pass this file with box library to ABC. Use with -lut.\n"); + log(" pass this file with box library to ABC.\n"); log("\n"); log(" -cwd \n"); log(" use this as the current working directory, inside which the 'input.xaig'\n"); -- cgit v1.2.3 From b2259a920165930261050065d870d03fc7573346 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 10 Jan 2020 11:45:41 -0800 Subject: Add abc9_ops -check, -prep_times, -write_box for required times --- passes/techmap/abc9.cc | 26 ++-- passes/techmap/abc9_ops.cc | 300 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 251 insertions(+), 75 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index f6627602b..41cfdeece 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -131,6 +131,7 @@ struct Abc9Pass : public ScriptPass std::stringstream exe_cmd; bool dff_mode, cleanup; + std::string box_file; void clear_flags() YS_OVERRIDE { @@ -138,6 +139,7 @@ struct Abc9Pass : public ScriptPass exe_cmd << "abc9_exe"; dff_mode = false; cleanup = true; + box_file.clear(); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -154,7 +156,7 @@ struct Abc9Pass : public ScriptPass std::string arg = args[argidx]; if ((arg == "-exe" || arg == "-script" || arg == "-D" || /* arg == "-S" || */ arg == "-lut" || arg == "-luts" || - arg == "-box" || arg == "-W") && + /*arg == "-box" ||*/ arg == "-W") && argidx+1 < args.size()) { exe_cmd << " " << arg << " " << args[++argidx]; continue; @@ -173,6 +175,10 @@ struct Abc9Pass : public ScriptPass cleanup = false; continue; } + if (arg == "-box" && argidx+1 < args.size()) { + box_file = args[++argidx]; + continue; + } break; } extra_args(args, argidx, design); @@ -185,11 +191,12 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { if (check_label("pre")) { + run("abc9_ops -check"); run("scc -set_attr abc9_scc_id {}"); if (help_mode) - run("abc9_ops -break_scc -prep_holes [-dff]", "(option for -dff)"); + run("abc9_ops -break_scc -prep_times -prep_holes [-dff]", "(option for -dff)"); else - run("abc9_ops -break_scc -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); + run("abc9_ops -break_scc -prep_times -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); @@ -203,8 +210,9 @@ struct Abc9Pass : public ScriptPass if (check_label("map")) { if (help_mode) { run("foreach module in selection"); + run(" abc9_ops -write_box [(-box value)|(null)] /input.box"); run(" write_xaiger -map /input.sym /input.xaig"); - run(" abc9_exe [options] -cwd "); + run(" abc9_exe [options] -cwd -box /input.box"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); run(" abc9_ops -reintegrate"); } @@ -229,6 +237,10 @@ struct Abc9Pass : public ScriptPass tempdir_name[0] = tempdir_name[4] = '_'; tempdir_name = make_temp_dir(tempdir_name); + if (box_file.empty()) + run(stringf("abc9_ops -write_box (null) %s/input.box", tempdir_name.c_str())); + else + run(stringf("abc9_ops -write_box %s %s/input.box", box_file.c_str(), tempdir_name.c_str())); run(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"); @@ -238,10 +250,8 @@ struct Abc9Pass : public ScriptPass active_design->scratchpad_get_int("write_xaiger.num_inputs"), num_outputs); if (num_outputs) { - run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()), - "abc9_exe [options] -cwd "); - run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()), - "read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); + run(stringf("%s -cwd %s -box %s/input.box", exe_cmd.str().c_str(), tempdir_name.c_str(), tempdir_name.c_str())); + run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str())); run("abc9_ops -reintegrate"); } else diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 7c7208711..4d49bb4d2 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -23,6 +23,8 @@ #include "kernel/utils.h" #include "kernel/celltypes.h" +#define ABC9_DELAY_BASE_ID 9000 + USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -33,6 +35,48 @@ 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) +{ + dict box_lookup; + for (auto m : design->modules()) { + auto it = m->attributes.find(ID(abc9_box_id)); + if (it == m->attributes.end()) + continue; + if (m->name.begins_with("$paramod")) + continue; + auto id = it->second.as_int(); + auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); + if (!r.second) + log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", + log_id(m), id, log_id(r.first->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 : m->ports) { + auto w = m->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) { + if (carry_in != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); + carry_in = port_name; + } + if (w->port_output) { + if (carry_out != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(m)); + carry_out = port_name; + } + } + } + + if (carry_in != IdString() && carry_out == IdString()) + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); + if (carry_in == IdString() && carry_out != IdString()) + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); + } +} + void break_scc(RTLIL::Module *module) { // For every unique SCC found, (arbitrarily) find the first @@ -301,6 +345,7 @@ void prep_holes(RTLIL::Module *module, bool dff) } cell->attributes["\\abc9_box_seq"] = box_list.size(); + //log_debug("%s.%s is box %d\n", log_id(module), log_id(cell), box_list.size()); box_list.emplace_back(cell); } log_assert(!box_list.empty()); @@ -318,8 +363,8 @@ void prep_holes(RTLIL::Module *module, bool dff) log_assert(orig_box_module); IdString derived_name = orig_box_module->derive(design, cell->parameters); RTLIL::Module* box_module = design->module(derived_name); - if (box_module->has_processes()) - Pass::call_on_module(design, box_module, "proc"); + cell->type = derived_name; + cell->parameters.clear(); int box_inputs = 0; auto r = cell_cache.insert(std::make_pair(derived_name, nullptr)); @@ -328,6 +373,9 @@ void prep_holes(RTLIL::Module *module, bool dff) holes_cell = holes_module->addCell(cell->name, cell->type); holes_cell->parameters = cell->parameters; r.first->second = holes_cell; + + if (box_module->has_processes()) + Pass::call_on_module(design, box_module, "proc"); } auto r2 = box_ports.insert(cell->type); @@ -339,25 +387,15 @@ void prep_holes(RTLIL::Module *module, bool dff) auto w = box_module->wire(port_name); log_assert(w); if (w->get_bool_attribute("\\abc9_carry")) { - if (w->port_input) { - if (carry_in != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module)); + if (w->port_input) carry_in = port_name; - } - if (w->port_output) { - if (carry_out != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module)); + if (w->port_output) carry_out = port_name; - } } else r2.first->second.push_back(port_name); } - if (carry_in != IdString() && carry_out == IdString()) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module)); - if (carry_in == IdString() && carry_out != IdString()) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module)); if (carry_in != IdString()) { r2.first->second.push_back(carry_in); r2.first->second.push_back(carry_out); @@ -423,6 +461,116 @@ void prep_holes(RTLIL::Module *module, bool dff) } } +void prep_times(RTLIL::Design *design) +{ + std::set delays; + std::vector boxes; + std::map> requireds; + for (auto module : design->selected_modules()) { + if (module->get_bool_attribute("\\abc9_holes")) + continue; + + if (module->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(module)); + continue; + } + + boxes.clear(); + for (auto cell : module->cells()) { + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) + continue; + + RTLIL::Module* inst_module = module->design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->get_blackbox_attribute()) + continue; + // Flop inputs cannot have required times + // (required time should be captured by flop box) + // TODO: enforce this + if (cell->attributes.count(ID(abc9_box_id))) + continue; + boxes.emplace_back(cell); + } + + delays.clear(); + requireds.clear(); + for (auto cell : boxes) { + RTLIL::Module* inst_module = module->design->module(cell->type); + + for (auto &conn : cell->connections_) { + auto port_wire = inst_module->wire(conn.first); + if (!port_wire->port_input) + continue; + + auto it = port_wire->attributes.find("\\abc9_required"); + if (it == port_wire->attributes.end()) + continue; + + int count = 0; + requireds.clear(); + if (it->second.flags == 0) { + count = 1; + requireds[it->second.as_int()].push_back(0); + } + else + for (const auto &tok : split_tokens(it->second.decode_string())) + requireds[atoi(tok.c_str())].push_back(count++); + if (count > 1 && count != GetSize(port_wire)) + log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), + GetSize(port_wire), log_signal(it->second), count); + + SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); + for (const auto &i : requireds) { + delays.insert(i.first); + for (auto offset : i.second) { + auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); + box->setPort(ID(I), conn.second[offset]); + box->setPort(ID(O), O[offset]); + box->setParam(ID(DELAY), i.first); + conn.second[offset] = O[offset]; + } + } + } + } + + std::stringstream ss; + bool first = true; + for (auto d : delays) + if (first) { + first = false; + ss << d; + } + else + ss << " " << d; + module->attributes[ID(abc9_delays)] = ss.str(); + } +} + +void write_box(RTLIL::Module *module, const std::string &src, const std::string &dst) { + std::ofstream ofs(dst); + log_assert(ofs.is_open()); + + // Since ABC can only accept one box file, we have to copy + // over the existing box file + if (src != "(null)") { + std::ifstream ifs(src); + ofs << ifs.rdbuf() << std::endl; + ifs.close(); + } + + auto it = module->attributes.find(ID(abc9_delays)); + if (it != module->attributes.end()) { + for (const auto &tok : split_tokens(it->second.decode_string())) { + int d = atoi(tok.c_str()); + ofs << "$__ABC9_DELAY@" << d << " " << ABC9_DELAY_BASE_ID + d << " 0 1 1" << std::endl; + ofs << d << std::endl; + } + } + + ofs.close(); +} + void reintegrate(RTLIL::Module *module) { auto design = module->design; @@ -438,8 +586,6 @@ void reintegrate(RTLIL::Module *module) module->addWire(remap_name(w->name), GetSize(w)); dict box_lookup; - dict> box_ports; - for (auto m : design->modules()) { auto it = m->attributes.find(ID(abc9_box_id)); if (it == m->attributes.end()) @@ -447,51 +593,19 @@ void reintegrate(RTLIL::Module *module) if (m->name.begins_with("$paramod")) continue; auto id = it->second.as_int(); - auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); - if (!r.second) - log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", - log_id(m), id, log_id(r.first->second)); + auto r YS_ATTRIBUTE(unused) = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); log_assert(r.second); - - auto r2 = box_ports.insert(m->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 : m->ports) { - auto w = m->wire(port_name); - log_assert(w); - if (w->get_bool_attribute("\\abc9_carry")) { - if (w->port_input) { - if (carry_in != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); - carry_in = port_name; - } - if (w->port_output) { - if (carry_out != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(m)); - carry_out = port_name; - } - } - else - r2.first->second.push_back(port_name); - } - - if (carry_in != IdString() && carry_out == IdString()) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); - if (carry_in == IdString() && carry_out != IdString()) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); - if (carry_in != IdString()) { - r2.first->second.push_back(carry_in); - r2.first->second.push_back(carry_out); - } - } } + pool delay_boxes; std::vector boxes; for (auto cell : module->cells().to_vector()) { if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) module->remove(cell); + else if (cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) { + delay_boxes.insert(cell->name); + module->remove(cell); + } else if (cell->attributes.erase("\\abc9_box_seq")) boxes.emplace_back(cell); } @@ -501,6 +615,7 @@ void reintegrate(RTLIL::Module *module) dict not2drivers; dict> bit2sinks; + dict> box_ports; std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { @@ -551,16 +666,6 @@ void reintegrate(RTLIL::Module *module) } if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { - // Convert buffer into direct connection - if (mapped_cell->type == ID($lut) && - GetSize(mapped_cell->getPort(ID::A)) == 1 && - mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { - SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name)); - SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); - log_abort(); - continue; - } RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = mapped_cell->parameters; cell->attributes = mapped_cell->attributes; @@ -588,6 +693,16 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } } + else if (delay_boxes.count(mapped_cell->name)) { + SigBit I = mapped_cell->getPort(ID(i)); + SigBit O = mapped_cell->getPort(ID(o)); + if (I.wire) + I.wire = module->wires_.at(remap_name(I.wire->name)); + log_assert(O.wire); + O.wire = module->wires_.at(remap_name(O.wire->name)); + module->connect(O, I); + continue; + } else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); @@ -621,6 +736,30 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } + auto r2 = box_ports.insert(cell->type); + 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 : box_module->ports) { + auto w = box_module->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) + carry_in = port_name; + if (w->port_output) + carry_out = port_name; + } + else + r2.first->second.push_back(port_name); + } + + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); + } + } + int input_count = 0, output_count = 0; for (const auto &port_name : box_ports.at(cell->type)) { RTLIL::Wire *w = box_module->wire(port_name); @@ -807,16 +946,23 @@ struct Abc9OpsPass : public Pass { { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); + bool check_mode = false; + bool prep_times_mode = false; bool break_scc_mode = false; bool unbreak_scc_mode = false; - bool prep_dff_mode = false; bool prep_holes_mode = false; + bool prep_dff_mode = false; + std::string write_box_src, write_box_dst; bool reintegrate_mode = false; bool dff_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; + if (arg == "-check") { + check_mode = true; + continue; + } if (arg == "-break_scc") { break_scc_mode = true; continue; @@ -833,6 +979,17 @@ struct Abc9OpsPass : public Pass { prep_holes_mode = true; continue; } + if (arg == "-prep_times") { + prep_times_mode = true; + continue; + } + if (arg == "-write_box" && argidx+2 < args.size()) { + write_box_src = args[++argidx]; + write_box_dst = args[++argidx]; + rewrite_filename(write_box_src); + rewrite_filename(write_box_dst); + continue; + } if (arg == "-reintegrate") { reintegrate_mode = true; continue; @@ -845,6 +1002,13 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); + // TODO: Check at least one mode given + + if (check_mode) + check(design); + if (prep_times_mode) + prep_times(design); + for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute("\\abc9_holes")) continue; @@ -858,10 +1022,12 @@ struct Abc9OpsPass : public Pass { break_scc(mod); if (unbreak_scc_mode) unbreak_scc(mod); - if (prep_dff_mode) - prep_dff(mod); if (prep_holes_mode) prep_holes(mod, dff_mode); + if (prep_dff_mode) + prep_dff(mod); + if (!write_box_src.empty()) + write_box(mod, write_box_src, write_box_dst); if (reintegrate_mode) reintegrate(mod); } -- cgit v1.2.3 From e0af812180528c45e79291209e2e3726c98b80ae Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 10 Jan 2020 12:38:49 -0800 Subject: abc9_ops -prep_times: update comment --- passes/techmap/abc9_ops.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 4d49bb4d2..14b3f6c43 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -485,9 +485,9 @@ void prep_times(RTLIL::Design *design) continue; if (!inst_module->get_blackbox_attribute()) continue; - // Flop inputs cannot have required times - // (required time should be captured by flop box) - // TODO: enforce this + // Only flop boxes are not combinatorial and may have required times, + // however those times are captured by this flop box, no need to + // add delay boxes if (cell->attributes.count(ID(abc9_box_id))) continue; boxes.emplace_back(cell); @@ -566,6 +566,7 @@ void write_box(RTLIL::Module *module, const std::string &src, const std::string ofs << "$__ABC9_DELAY@" << d << " " << ABC9_DELAY_BASE_ID + d << " 0 1 1" << std::endl; ofs << d << std::endl; } + module->attributes.erase(it); } ofs.close(); -- cgit v1.2.3 From 475d983676a42e57a104aaf5e72462d704c0c3aa Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 10 Jan 2020 14:49:52 -0800 Subject: abc9_ops -prep_times: generate flop boxes from abc9_required attr --- passes/techmap/abc9_ops.cc | 84 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 17 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 14b3f6c43..918afd284 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -39,9 +39,13 @@ void check(RTLIL::Design *design) { dict box_lookup; for (auto m : design->modules()) { + auto flop = m->get_bool_attribute(ID(abc9_flop)); auto it = m->attributes.find(ID(abc9_box_id)); - if (it == m->attributes.end()) + if (it == m->attributes.end()) { + if (flop) + log_error("Module '%s' contains (* abc9_flop *) but not (* abc9_box_id= *).\n", log_id(m)); continue; + } if (m->name.begins_with("$paramod")) continue; auto id = it->second.as_int(); @@ -59,21 +63,31 @@ void check(RTLIL::Design *design) if (w->get_bool_attribute("\\abc9_carry")) { if (w->port_input) { if (carry_in != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); + log_error("Module '%s' contains more than one (* abc9_carry *) input port.\n", log_id(m)); carry_in = port_name; } if (w->port_output) { if (carry_out != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(m)); + log_error("Module '%s' contains more than one (* abc9_carry *) output port.\n", log_id(m)); carry_out = port_name; } } } if (carry_in != IdString() && carry_out == IdString()) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); + log_error("Module '%s' contains an (* abc9_carry *) input port but no output port.\n", log_id(m)); if (carry_in == IdString() && carry_out != IdString()) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); + log_error("Module '%s' contains an (* abc9_carry *) output port but no input port.\n", log_id(m)); + + if (flop) { + int num_outputs = 0; + for (auto port_name : m->ports) { + auto wire = m->wire(port_name); + if (wire->port_output) num_outputs++; + } + if (num_outputs != 1) + log_error("Module '%s' with (* abc_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); + } } } @@ -464,12 +478,10 @@ void prep_holes(RTLIL::Module *module, bool dff) void prep_times(RTLIL::Design *design) { std::set delays; + pool flops; std::vector boxes; std::map> requireds; for (auto module : design->selected_modules()) { - if (module->get_bool_attribute("\\abc9_holes")) - continue; - if (module->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(module)); continue; @@ -485,10 +497,13 @@ void prep_times(RTLIL::Design *design) continue; if (!inst_module->get_blackbox_attribute()) continue; - // Only flop boxes are not combinatorial and may have required times, - // however those times are captured by this flop box, no need to - // add delay boxes - if (cell->attributes.count(ID(abc9_box_id))) + if (inst_module->get_bool_attribute(ID(abc9_flop))) { + flops.insert(inst_module); + continue; + } + // All remaining boxes are combinatorial and cannot + // contain a required time + if (inst_module->attributes.count(ID(abc9_box_id))) continue; boxes.emplace_back(cell); } @@ -536,15 +551,48 @@ void prep_times(RTLIL::Design *design) std::stringstream ss; bool first = true; - for (auto d : delays) - if (first) { + for (auto d : delays) { + if (first) first = false; - ss << d; - } else - ss << " " << d; + ss << " "; + ss << d; + } module->attributes[ID(abc9_delays)] = ss.str(); } + + std::stringstream ss; + for (auto flop_module : flops) { + // Skip parameterised flop_modules for now (since we do not + // dynamically generate the abc9_box_id) + if (flop_module->name.begins_with("$paramod")) + continue; + + int num_inputs = 0, num_outputs = 0; + for (auto port_name : flop_module->ports) { + auto wire = flop_module->wire(port_name); + if (wire->port_input) num_inputs++; + if (wire->port_output) num_outputs++; + } + log_assert(num_outputs == 1); + + ss << log_id(flop_module) << " " << flop_module->attributes.at(ID(abc9_box_id)).as_int(); + ss << " 1 " << num_inputs+1 << " " << num_outputs << std::endl; + bool first = true; + for (auto port_name : flop_module->ports) { + auto wire = flop_module->wire(port_name); + if (!wire->port_input) + continue; + if (first) + first = false; + else + ss << " "; + ss << wire->attributes.at("\\abc9_required", 0).as_int(); + } + // Last input is 'abc9_ff.Q' + ss << " 0" << std::endl << std::endl; + } + design->scratchpad_set_string("abc9_ops.box.flops", ss.str()); } void write_box(RTLIL::Module *module, const std::string &src, const std::string &dst) { @@ -559,6 +607,8 @@ void write_box(RTLIL::Module *module, const std::string &src, const std::string ifs.close(); } + ofs << module->design->scratchpad_get_string("abc9_ops.box.flops"); + auto it = module->attributes.find(ID(abc9_delays)); if (it != module->attributes.end()) { for (const auto &tok : split_tokens(it->second.decode_string())) { -- cgit v1.2.3 From f24de88f385a3eeaadd9b9c8c200a7c338f37448 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 10 Jan 2020 17:13:27 -0800 Subject: log_debug() for abc9_{arrival,required} times --- passes/techmap/abc9_ops.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 918afd284..eac1ff2b6 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -512,7 +512,7 @@ void prep_times(RTLIL::Design *design) requireds.clear(); for (auto cell : boxes) { RTLIL::Module* inst_module = module->design->module(cell->type); - + log_assert(inst_module); for (auto &conn : cell->connections_) { auto port_wire = inst_module->wire(conn.first); if (!port_wire->port_input) @@ -537,6 +537,12 @@ void prep_times(RTLIL::Design *design) SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); for (const auto &i : requireds) { +#ifndef NDEBUG + if (ys_debug(1)) { + static std::set> seen; + if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), i.first); + } +#endif delays.insert(i.first); for (auto offset : i.second) { auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); -- cgit v1.2.3 From 784fec93c901caa6f9d980388356d120b0cdfea9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Jan 2020 08:42:58 -0800 Subject: abc9: cleanup --- passes/techmap/abc9.cc | 20 +++++-------------- passes/techmap/abc9_exe.cc | 15 +++++---------- passes/techmap/abc9_ops.cc | 48 +++++++++++++++++++++++++++------------------- 3 files changed, 38 insertions(+), 45 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index f6627602b..2af0676b1 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -26,9 +26,6 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -#define XC7_WIRE_DELAY 300 // Number with which ABC will map a 6-input gate - // to one LUT6 (instead of a LUT5 + LUT2) - struct Abc9Pass : public ScriptPass { Abc9Pass() : ScriptPass("abc9", "use ABC9 for technology mapping") { } @@ -39,8 +36,9 @@ struct Abc9Pass : public ScriptPass log("\n"); log(" abc9 [options] [selection]\n"); log("\n"); - log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); - log("library to a target architecture. Only fully-selected modules are supported.\n"); + log("This script pass performs a sequence of commands to facilitate the use of the ABC\n"); + log("tool [1] for technology mapping of the current design to a target FPGA\n"); + log("architecture. Only fully-selected modules are supported.\n"); log("\n"); log(" -exe \n"); #ifdef ABCEXTERNAL @@ -59,21 +57,13 @@ struct Abc9Pass : public ScriptPass log(" replaced with blanks before the string is passed to ABC.\n"); log("\n"); log(" if no -script parameter is given, the following scripts are used:\n"); - log("\n"); - log(" for -lut/-luts (only one LUT size):\n"); - // FIXME - //log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); - log("\n"); - log(" for -lut/-luts (different LUT sizes):\n"); - // FIXME + //FIXME: //log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); log("\n"); log(" -fast\n"); log(" use different default scripts that are slightly faster (at the cost\n"); log(" of output quality):\n"); - log("\n"); - log(" for -lut/-luts:\n"); - // FIXME + //FIXME: //log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); log("\n"); log(" -D \n"); diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index f7dafda96..3108765a1 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -289,10 +289,12 @@ struct Abc9ExePass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" abc9_exe [options] [selection]\n"); + log(" abc9_exe [options]\n"); log("\n"); - log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); - log("library to a target architecture.\n"); + log(" \n"); + log("This pass uses the ABC tool [1] for technology mapping of the top module\n"); + log("(according to the (* top *) attribute or if only one module is currently selected)\n"); + log("to a target FPGA architecture.\n"); log("\n"); log(" -exe \n"); #ifdef ABCEXTERNAL @@ -311,18 +313,11 @@ struct Abc9ExePass : public Pass { log(" replaced with blanks before the string is passed to ABC.\n"); log("\n"); log(" if no -script parameter is given, the following scripts are used:\n"); - log("\n"); - log(" for -lut/-luts (only one LUT size):\n"); - log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); - log("\n"); - log(" for -lut/-luts (different LUT sizes):\n"); log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); log("\n"); log(" -fast\n"); log(" use different default scripts that are slightly faster (at the cost\n"); log(" of output quality):\n"); - log("\n"); - log(" for -lut/-luts:\n"); log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); log("\n"); log(" -D \n"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 7c7208711..6f089447e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -40,7 +40,7 @@ void break_scc(RTLIL::Module *module) // its output ports into a new PO, and drive its previous // sinks with a new PI pool ids_seen; - for (auto cell : module->selected_cells()) { + for (auto cell : module->cells()) { auto it = cell->attributes.find(ID(abc9_scc_id)); if (it == cell->attributes.end()) continue; @@ -116,7 +116,7 @@ void prep_dff(RTLIL::Module *module) typedef SigSpec clkdomain_t; dict clk_to_mergeability; - for (auto cell : module->selected_cells()) { + for (auto cell : module->cells()) { if (cell->type != "$__ABC9_FF_") continue; @@ -179,11 +179,8 @@ void prep_dff(RTLIL::Module *module) ++it; } - for (auto &conn : holes_module->connections_) { - auto it = replace.find(conn); - if (it != replace.end()) - conn = it->second; - } + for (auto &conn : holes_module->connections_) + conn = replace.at(conn, conn); } } @@ -198,7 +195,7 @@ void prep_holes(RTLIL::Module *module, bool dff) TopoSort toposort; bool abc9_box_seen = false; - for (auto cell : module->selected_cells()) { + for (auto cell : module->cells()) { if (cell->type == "$__ABC9_FF_") continue; @@ -236,21 +233,23 @@ void prep_holes(RTLIL::Module *module, bool dff) for (auto user_cell : it.second) toposort.edge(driver_cell, user_cell); -#if 0 - toposort.analyze_loops = true; -#endif + if (ys_debug(1)) + toposort.analyze_loops = true; + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); -#if 0 - unsigned i = 0; - for (auto &it : toposort.loops) { - log(" loop %d\n", i++); - for (auto cell_name : it) { - auto cell = module->cell(cell_name); - log_assert(cell); - log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); + + if (ys_debug(1)) { + unsigned i = 0; + for (auto &it : toposort.loops) { + log(" loop %d\n", i++); + for (auto cell_name : it) { + auto cell = module->cell(cell_name); + log_assert(cell); + log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); + } } } -#endif + log_assert(no_loops); vector box_list; @@ -845,6 +844,12 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); + if (!(break_scc_mode || unbreak_scc_mode || prep_dff_mode || reintegrate_mode)) + log_cmd_error("At least one of -{,un}break_scc, -prep_{dff,holes}, -reintegrate must be specified.\n"); + + if (dff_mode && !prep_holes_mode) + log_cmd_error("'-dff' option is only relevant for -prep_holes.\n"); + for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute("\\abc9_holes")) continue; @@ -854,6 +859,9 @@ struct Abc9OpsPass : public Pass { continue; } + if (!design->selected_whole_module(mod)) + log_error("Can't handle partially selected module %s!\n", log_id(mod)); + if (break_scc_mode) break_scc(mod); if (unbreak_scc_mode) -- cgit v1.2.3 From 295e241c074ae275e832fdde9fae6fd897170ac8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Jan 2020 17:28:24 -0800 Subject: cleanup --- passes/techmap/abc9.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 30b62dc79..5d6d8904c 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -182,12 +182,10 @@ struct Abc9Pass : public ScriptPass run("abc9_ops -break_scc -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); -run("dump @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("dump @abc9_holes"); run("aigmap"); run("wbflip @abc9_holes"); } -- cgit v1.2.3 From 808b388e34f3cededd450de35555476874cf2799 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 09:43:57 -0800 Subject: abc9: log which module is being operated on --- passes/techmap/abc9.cc | 4 +++- passes/techmap/abc9_exe.cc | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 2ded1c162..2e3df773e 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -276,9 +276,11 @@ struct Abc9Pass : public ScriptPass run(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"); - log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", + + log("Extracted %d AND gates and %d wires from module `%s' to a netlist network with %d inputs and %d outputs.\n", active_design->scratchpad_get_int("write_xaiger.num_ands"), active_design->scratchpad_get_int("write_xaiger.num_wires"), + log_id(mod), active_design->scratchpad_get_int("write_xaiger.num_inputs"), num_outputs); if (num_outputs) { diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index c1687ef97..a2acfac91 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -168,10 +168,6 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe std::string wire_delay, std::string tempdir_name ) { - //FIXME: - //log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", - // module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); - std::string abc9_script; if (!lut_costs.empty()) -- cgit v1.2.3 From a6d4ea74634826741f09793c36d596f2fa239f62 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 19:21:11 -0800 Subject: abc9: respect (* keep *) on cells --- passes/techmap/abc9_ops.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index cc22fd474..9cc58c99d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -489,6 +489,8 @@ void reintegrate(RTLIL::Module *module) std::vector boxes; for (auto cell : module->cells().to_vector()) { + if (cell->has_keep_attr()) + continue; if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) module->remove(cell); else if (cell->attributes.erase("\\abc9_box_seq")) -- cgit v1.2.3 From a2c4d98da70744253ccbe253083ef9df5fa39305 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 19:22:23 -0800 Subject: abc9: add -run option --- passes/techmap/abc9.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 2e3df773e..2627ab9ca 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -91,6 +91,11 @@ struct Abc9Pass : public ScriptPass log("tool [1] for technology mapping of the current design to a target FPGA\n"); log("architecture. Only fully-selected modules are supported.\n"); log("\n"); + log(" -run :\n"); + log(" only run the commands between the labels (see below). an empty\n"); + log(" from label is synonymous to 'begin', and empty to label is\n"); + log(" synonymous to the end of the command list.\n"); + log("\n"); log(" -exe \n"); #ifdef ABCEXTERNAL log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); @@ -210,13 +215,21 @@ struct Abc9Pass : public ScriptPass } if (arg == "-dff") { dff_mode = true; - exe_cmd << " " << arg; + exe_cmd << " " << arg; continue; } if (arg == "-nocleanup") { cleanup = false; continue; } + if (arg == "-run" && argidx+1 < args.size()) { + size_t pos = args[argidx+1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos+1); + continue; + } break; } extra_args(args, argidx, design); -- cgit v1.2.3 From 2c65e1abacc4401c4fd3e9b48f52c4de120bc511 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 21:45:27 -0800 Subject: abc9: break SCC by setting (* keep *) on output wires --- passes/techmap/abc9.cc | 2 +- passes/techmap/abc9_ops.cc | 29 ++++------------------------- 2 files changed, 5 insertions(+), 26 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 2627ab9ca..dad40be63 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -298,7 +298,7 @@ struct Abc9Pass : public ScriptPass num_outputs); if (num_outputs) { run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str())); - run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str())); + run(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("abc9_ops -reintegrate"); } else diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 9cc58c99d..4da10d94b 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -53,30 +53,7 @@ void break_scc(RTLIL::Module *module) if (cell->output(c.first)) { SigBit b = c.second.as_bit(); Wire *w = b.wire; - if (w->port_input) { - // In this case, hopefully the loop break has been already created - // Get the non-prefixed wire - Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str())); - log_assert(wo != nullptr); - log_assert(wo->port_output); - log_assert(b.offset < GetSize(wo)); - c.second = RTLIL::SigBit(wo, b.offset); - } - else { - // Create a new output/input loop break - w->port_input = true; - w = module->wire(stringf("%s.abco", w->name.c_str())); - if (!w) { - w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire)); - w->port_output = true; - } - else { - log_assert(w->port_input); - log_assert(b.offset < GetSize(w)); - } - w->set_bool_attribute(ID(abc9_scc_break)); - c.second = RTLIL::SigBit(w, b.offset); - } + w->set_bool_attribute(ID::keep); } } } @@ -586,7 +563,9 @@ void reintegrate(RTLIL::Module *module) } if (cell->output(mapped_conn.first)) for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); + // Ignore inouts for topo ordering + if (i.wire && !(i.wire->port_input && i.wire->port_output)) + bit_drivers[i].insert(mapped_cell->name); } } else { -- cgit v1.2.3 From b678b15c6d0d14580ca18e89f86926eabf8fead0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 23:33:37 -0800 Subject: abc9_ops: ignore inouts of all cell outputs for topo ordering --- passes/techmap/abc9_ops.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 4da10d94b..d7ebfdf3f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -488,7 +488,9 @@ void reintegrate(RTLIL::Module *module) RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); bit_users[a_bit].insert(mapped_cell->name); - bit_drivers[y_bit].insert(mapped_cell->name); + // Ignore inouts for topo ordering + if (y_bit.wire && !(y_bit.wire->port_input && y_bit.wire->port_output)) + bit_drivers[y_bit].insert(mapped_cell->name); if (!a_bit.wire) { mapped_cell->setPort(ID::Y, module->addWire(NEW_ID)); @@ -598,7 +600,9 @@ void reintegrate(RTLIL::Module *module) for (const auto &i : inputs) bit_users[i].insert(mapped_cell->name); for (const auto &i : outputs) - bit_drivers[i].insert(mapped_cell->name); + // Ignore inouts for topo ordering + if (i.wire && !(i.wire->port_input && i.wire->port_output)) + bit_drivers[i].insert(mapped_cell->name); } int input_count = 0, output_count = 0; -- cgit v1.2.3 From 531fddf797a79b46df3e462112ca68ff50e6a18e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 23:42:27 -0800 Subject: abc9_ops: -break_scc -> -mark_scc using (* keep *), remove -unbreak_scc --- passes/techmap/abc9.cc | 7 ++---- passes/techmap/abc9_ops.cc | 59 ++++++++++++++-------------------------------- 2 files changed, 20 insertions(+), 46 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index dad40be63..c7fe05795 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -244,9 +244,9 @@ struct Abc9Pass : public ScriptPass if (check_label("pre")) { run("scc -set_attr abc9_scc_id {}"); if (help_mode) - run("abc9_ops -break_scc -prep_holes [-dff]", "(option for -dff)"); + run("abc9_ops -mark_scc -prep_holes [-dff]", "(option for -dff)"); else - run("abc9_ops -break_scc -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); + run("abc9_ops -mark_scc -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); @@ -315,9 +315,6 @@ struct Abc9Pass : public ScriptPass active_design->selection_stack.pop_back(); } } - - if (check_label("post")) - run("abc9_ops -unbreak_scc"); } } Abc9Pass; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index d7ebfdf3f..c7236486f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -33,7 +33,7 @@ inline std::string remap_name(RTLIL::IdString abc9_name) return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); } -void break_scc(RTLIL::Module *module) +void mark_scc(RTLIL::Module *module) { // For every unique SCC found, (arbitrarily) find the first // cell in the component, and convert all wires driven by @@ -44,7 +44,8 @@ void break_scc(RTLIL::Module *module) auto it = cell->attributes.find(ID(abc9_scc_id)); if (it == cell->attributes.end()) continue; - auto r = ids_seen.insert(it->second); + auto id = it->second; + auto r = ids_seen.insert(id); cell->attributes.erase(it); if (!r.second) continue; @@ -54,6 +55,7 @@ void break_scc(RTLIL::Module *module) SigBit b = c.second.as_bit(); Wire *w = b.wire; w->set_bool_attribute(ID::keep); + w->attributes[ID(abc9_scc_id)] = id.as_int(); } } } @@ -61,28 +63,6 @@ void break_scc(RTLIL::Module *module) module->fixup_ports(); } -void unbreak_scc(RTLIL::Module *module) -{ - // Now 'unexpose' those wires by undoing - // the expose operation -- remove them from PO/PI - // and re-connecting them back together - for (auto wire : module->wires()) { - auto it = wire->attributes.find(ID(abc9_scc_break)); - if (it != wire->attributes.end()) { - wire->attributes.erase(it); - log_assert(wire->port_output); - wire->port_output = false; - std::string name = wire->name.str(); - RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5)); - log_assert(i_wire); - log_assert(i_wire->port_input); - i_wire->port_input = false; - module->connect(i_wire, wire); - } - } - module->fixup_ports(); -} - void prep_dff(RTLIL::Module *module) { auto design = module->design; @@ -676,21 +656,25 @@ void reintegrate(RTLIL::Module *module) // Stitch in mapped_mod's inputs/outputs into module for (auto port : mapped_mod->ports) { - RTLIL::Wire *w = mapped_mod->wire(port); + RTLIL::Wire *mapped_wire = mapped_mod->wire(port); RTLIL::Wire *wire = module->wire(port); log_assert(wire); + if (wire->attributes.erase(ID(abc9_scc_id))) { + auto r YS_ATTRIBUTE(unused) = wire->attributes.erase(ID::keep); + log_assert(r); + } RTLIL::Wire *remap_wire = module->wire(remap_name(port)); RTLIL::SigSpec signal(wire, 0, GetSize(remap_wire)); log_assert(GetSize(signal) >= GetSize(remap_wire)); RTLIL::SigSig conn; - if (w->port_output) { + if (mapped_wire->port_output) { conn.first = signal; conn.second = remap_wire; out_wires++; module->connect(conn); } - else if (w->port_input) { + else if (mapped_wire->port_input) { conn.first = remap_wire; conn.second = signal; in_wires++; @@ -791,8 +775,7 @@ struct Abc9OpsPass : public Pass { { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); - bool break_scc_mode = false; - bool unbreak_scc_mode = false; + bool mark_scc_mode = false; bool prep_dff_mode = false; bool prep_holes_mode = false; bool reintegrate_mode = false; @@ -801,12 +784,8 @@ struct Abc9OpsPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; - if (arg == "-break_scc") { - break_scc_mode = true; - continue; - } - if (arg == "-unbreak_scc") { - unbreak_scc_mode = true; + if (arg == "-mark_scc") { + mark_scc_mode = true; continue; } if (arg == "-prep_dff") { @@ -829,8 +808,8 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); - if (!(break_scc_mode || unbreak_scc_mode || prep_dff_mode || reintegrate_mode)) - log_cmd_error("At least one of -{,un}break_scc, -prep_{dff,holes}, -reintegrate must be specified.\n"); + if (!(mark_scc_mode || prep_dff_mode || reintegrate_mode)) + log_cmd_error("At least one of -mark_scc, -prep_{dff,holes}, -reintegrate must be specified.\n"); if (dff_mode && !prep_holes_mode) log_cmd_error("'-dff' option is only relevant for -prep_holes.\n"); @@ -847,10 +826,8 @@ struct Abc9OpsPass : public Pass { if (!design->selected_whole_module(mod)) log_error("Can't handle partially selected module %s!\n", log_id(mod)); - if (break_scc_mode) - break_scc(mod); - if (unbreak_scc_mode) - unbreak_scc(mod); + if (mark_scc_mode) + mark_scc(mod); if (prep_dff_mode) prep_dff(mod); if (prep_holes_mode) -- cgit v1.2.3 From 468386d67d902722562e9a0412a76fca79ec4fa2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 12:25:45 -0800 Subject: abc9_ops: -prep_holes -> -prep_xaiger, move padding to write_xaiger --- passes/techmap/abc9.cc | 4 +- passes/techmap/abc9_ops.cc | 173 +++++++++++++++++++-------------------------- 2 files changed, 73 insertions(+), 104 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index c7fe05795..6a296bfe7 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -244,9 +244,9 @@ struct Abc9Pass : public ScriptPass if (check_label("pre")) { run("scc -set_attr abc9_scc_id {}"); if (help_mode) - run("abc9_ops -mark_scc -prep_holes [-dff]", "(option for -dff)"); + run("abc9_ops -mark_scc -prep_xaiger [-dff]", "(option for -dff)"); else - run("abc9_ops -mark_scc -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); + run("abc9_ops -mark_scc -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index cc82a72cf..405f3e267 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -143,7 +143,7 @@ void prep_dff(RTLIL::Module *module) } } -void prep_holes(RTLIL::Module *module, bool dff) +void prep_xaiger(RTLIL::Module *module, bool dff) { auto design = module->design; log_assert(design); @@ -152,7 +152,7 @@ void prep_holes(RTLIL::Module *module, bool dff) dict> bit_drivers, bit_users; TopoSort toposort; - bool abc9_box_seen = false; + dict> box_ports; for (auto cell : module->cells()) { if (cell->type == "$__ABC9_FF_") @@ -165,7 +165,40 @@ void prep_holes(RTLIL::Module *module, bool dff) abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); if (abc9_flop && !dff) continue; - abc9_box_seen = abc9_box; + + auto r = box_ports.insert(cell->type); + 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 : inst_module->ports) { + auto w = inst_module->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) { + if (carry_in != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(inst_module)); + carry_in = port_name; + } + if (w->port_output) { + if (carry_out != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(inst_module)); + carry_out = port_name; + } + } + else + r.first->second.push_back(port_name); + } + + if (carry_in != IdString() && carry_out == IdString()) + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(inst_module)); + if (carry_in == IdString() && carry_out != IdString()) + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(inst_module)); + if (carry_in != IdString()) { + r.first->second.push_back(carry_in); + r.first->second.push_back(carry_out); + } + } } else if (!yosys_celltypes.cell_known(cell->type)) continue; @@ -183,7 +216,7 @@ void prep_holes(RTLIL::Module *module, bool dff) toposort.node(cell->name); } - if (!abc9_box_seen) + if (box_ports.empty()) return; for (auto &it : bit_users) @@ -211,7 +244,13 @@ void prep_holes(RTLIL::Module *module, bool dff) log_assert(no_loops); - vector box_list; + RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); + log_assert(holes_module); + holes_module->set_bool_attribute("\\abc9_holes"); + + dict cell_cache; + + int port_id = 1, box_count = 0; for (auto cell_name : toposort.sorted) { RTLIL::Cell *cell = module->cell(cell_name); log_assert(cell); @@ -220,62 +259,10 @@ void prep_holes(RTLIL::Module *module, bool dff) if (!box_module || !box_module->attributes.count("\\abc9_box_id")) continue; - bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); - - // Fully pad all unused input connections of this box cell with S0 - // Fully pad all undriven output connections of this box cell with anonymous wires - for (const auto &port_name : box_module->ports) { - RTLIL::Wire* w = box_module->wire(port_name); - log_assert(w); - auto it = cell->connections_.find(port_name); - if (w->port_input) { - RTLIL::SigSpec rhs; - if (it != cell->connections_.end()) { - if (GetSize(it->second) < GetSize(w)) - it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); - rhs = it->second; - } - else { - rhs = RTLIL::SigSpec(State::S0, GetSize(w)); - cell->setPort(port_name, rhs); - } - } - if (w->port_output) { - RTLIL::SigSpec rhs; - auto it = cell->connections_.find(w->name); - if (it != cell->connections_.end()) { - if (GetSize(it->second) < GetSize(w)) - it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); - rhs = it->second; - } - else { - Wire *wire = module->addWire(NEW_ID, GetSize(w)); - if (blackbox) - wire->set_bool_attribute(ID(abc9_padding)); - rhs = wire; - cell->setPort(port_name, rhs); - } - } - } - - cell->attributes["\\abc9_box_seq"] = box_list.size(); - box_list.emplace_back(cell); - } - log_assert(!box_list.empty()); - - RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); - log_assert(holes_module); - holes_module->set_bool_attribute("\\abc9_holes"); + cell->attributes["\\abc9_box_seq"] = box_count++; - dict cell_cache; - dict> box_ports; - - int port_id = 1; - for (auto cell : box_list) { - RTLIL::Module* orig_box_module = design->module(cell->type); - log_assert(orig_box_module); - IdString derived_name = orig_box_module->derive(design, cell->parameters); - RTLIL::Module* box_module = design->module(derived_name); + IdString derived_name = box_module->derive(design, cell->parameters); + box_module = design->module(derived_name); auto r = cell_cache.insert(derived_name); auto &holes_cell = r.first->second; @@ -283,40 +270,6 @@ void prep_holes(RTLIL::Module *module, bool dff) if (box_module->has_processes()) Pass::call_on_module(design, box_module, "proc"); - auto r2 = box_ports.insert(cell->type); - 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 : box_module->ports) { - auto w = box_module->wire(port_name); - log_assert(w); - if (w->get_bool_attribute("\\abc9_carry")) { - if (w->port_input) { - if (carry_in != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module)); - carry_in = port_name; - } - if (w->port_output) { - if (carry_out != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module)); - carry_out = port_name; - } - } - else - r2.first->second.push_back(port_name); - } - - if (carry_in != IdString() && carry_out == IdString()) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module)); - if (carry_in == IdString() && carry_out != IdString()) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module)); - if (carry_in != IdString()) { - r2.first->second.push_back(carry_in); - r2.first->second.push_back(carry_out); - } - } - if (box_module->get_bool_attribute("\\whitebox")) { holes_cell = holes_module->addCell(cell->name, derived_name); @@ -770,6 +723,22 @@ struct Abc9OpsPass : public Pass { log("\n"); log(" abc9_ops [options] [selection]\n"); log("\n"); + log("This pass contains a set of supporting operations for use during ABC technology\n"); + log("mapping, and is expected to be called in conjunction with other operations from\n"); + log("the `abc9' script pass. Only fully-selected modules are supported.\n"); + log("\n"); + log(" -mark_scc\n"); + log(" for an arbitrarily chosen cell in each unique SCC of each selected module\n"); + log(" (tagged with an (* abc9_scc_id = *) attribute), temporarily mark all\n"); + log(" wires driven by this cell's outputs with a (* keep *) attribute in order\n"); + log(" to break the SCC. this temporary attribute will be removed on -reintegrate.\n"); + 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("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -777,7 +746,7 @@ struct Abc9OpsPass : public Pass { bool mark_scc_mode = false; bool prep_dff_mode = false; - bool prep_holes_mode = false; + bool prep_xaiger_mode = false; bool reintegrate_mode = false; bool dff_mode = false; @@ -792,8 +761,8 @@ struct Abc9OpsPass : public Pass { prep_dff_mode = true; continue; } - if (arg == "-prep_holes") { - prep_holes_mode = true; + if (arg == "-prep_xaiger") { + prep_xaiger_mode = true; continue; } if (arg == "-reintegrate") { @@ -809,10 +778,10 @@ struct Abc9OpsPass : public Pass { extra_args(args, argidx, design); if (!(mark_scc_mode || prep_dff_mode || reintegrate_mode)) - log_cmd_error("At least one of -mark_scc, -prep_{dff,holes}, -reintegrate must be specified.\n"); + log_cmd_error("At least one of -mark_scc, -prep_{xaiger,dff}, -reintegrate must be specified.\n"); - if (dff_mode && !prep_holes_mode) - log_cmd_error("'-dff' option is only relevant for -prep_holes.\n"); + if (dff_mode && !prep_xaiger_mode) + log_cmd_error("'-dff' option is only relevant for -prep_xaiger.\n"); for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute("\\abc9_holes")) @@ -830,8 +799,8 @@ struct Abc9OpsPass : public Pass { mark_scc(mod); if (prep_dff_mode) prep_dff(mod); - if (prep_holes_mode) - prep_holes(mod, dff_mode); + if (prep_xaiger_mode) + prep_xaiger(mod, dff_mode); if (reintegrate_mode) reintegrate(mod); } -- cgit v1.2.3 From 654247abe9078566f93960a135ce08b0cfc96442 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 12:40:36 -0800 Subject: abc9_ops/write_xaiger: update doc --- passes/techmap/abc9_ops.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 405f3e267..463941b0b 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -739,6 +739,19 @@ struct Abc9OpsPass : public Pass { log(" '$holes' module that contains the logic behaviour of ABC9\n"); log(" whiteboxes.\n"); log("\n"); + log(" -dff\n"); + log(" consider flop cells (those instantiating modules marked with (* abc9_flop *)\n"); + log(" during -prep_xaiger.\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(" -reintegrate\n"); + log(" for each selected module, re-intergrate the module '$abc9'\n"); + log(" by first recovering ABC9 boxes, and then stitching in the remaining primary\n"); + log(" inputs and outputs.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { -- cgit v1.2.3 From 300003cb7854650cab9dd063a864f8f1df052d6d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 13:09:54 -0800 Subject: abc9_ops: discard $__ABC9_DELAY boxes --- passes/techmap/abc9_ops.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 04a54fd63..e1f6252f2 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -572,17 +572,12 @@ void reintegrate(RTLIL::Module *module) log_assert(r.second); } - pool delay_boxes; std::vector boxes; 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 (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) module->remove(cell); - else if (cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) { - delay_boxes.insert(cell->name); - module->remove(cell); - } else if (cell->attributes.erase("\\abc9_box_seq")) boxes.emplace_back(cell); } @@ -674,7 +669,7 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } } - else if (delay_boxes.count(mapped_cell->name)) { + else if (mapped_cell->type == ID($__ABC9_DELAY)) { SigBit I = mapped_cell->getPort(ID(i)); SigBit O = mapped_cell->getPort(ID(o)); if (I.wire) -- cgit v1.2.3 From 593897ffc0b7bedfd65cdddf68dee6b89295b70b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 13:13:15 -0800 Subject: abc9_ops: cleanup --- passes/techmap/abc9_ops.cc | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index e1f6252f2..9b7901ffb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -233,25 +233,15 @@ void prep_xaiger(RTLIL::Module *module, bool dff) auto w = inst_module->wire(port_name); log_assert(w); if (w->get_bool_attribute("\\abc9_carry")) { - if (w->port_input) { - if (carry_in != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(inst_module)); + log_assert(w->port_input != w->port_output); + if (w->port_input) carry_in = port_name; - } - if (w->port_output) { - if (carry_out != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(inst_module)); + else if (w->port_output) carry_out = port_name; - } } else r.first->second.push_back(port_name); } - - if (carry_in != IdString() && carry_out == IdString()) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(inst_module)); - if (carry_in == IdString() && carry_out != IdString()) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(inst_module)); if (carry_in != IdString()) { r.first->second.push_back(carry_in); r.first->second.push_back(carry_out); @@ -723,9 +713,10 @@ void reintegrate(RTLIL::Module *module) auto w = box_module->wire(port_name); log_assert(w); if (w->get_bool_attribute("\\abc9_carry")) { + log_assert(w->port_input != w->port_output); if (w->port_input) carry_in = port_name; - if (w->port_output) + else if (w->port_output) carry_out = port_name; } else -- cgit v1.2.3 From ec95fbb273872ed41e2baadb644a311d31c3ee79 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 13:21:58 -0800 Subject: abc9_ops: -prep_times -> -prep_delays; add doc --- passes/techmap/abc9.cc | 6 +++--- passes/techmap/abc9_ops.cc | 28 ++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 5ba87fa88..dde0a11d4 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -251,9 +251,9 @@ struct Abc9Pass : public ScriptPass run("abc9_ops -check"); run("scc -set_attr abc9_scc_id {}"); if (help_mode) - run("abc9_ops -mark_scc -prep_times -prep_xaiger [-dff]", "(option for -dff)"); + run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)"); else - run("abc9_ops -mark_scc -prep_times -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); + run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); @@ -267,7 +267,7 @@ struct Abc9Pass : public ScriptPass if (check_label("map")) { if (help_mode) { run("foreach module in selection"); - run(" abc9_ops -write_box [(-box )|(null)] /input.box"); + run(" abc9_ops -write_box [|(null)] /input.box"); run(" write_xaiger -map /input.sym /input.xaig"); run(" abc9_exe [options] -cwd -box /input.box"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 9b7901ffb..af4073594 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -383,7 +383,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } -void prep_times(RTLIL::Design *design) +void prep_delays(RTLIL::Design *design) { std::set delays; pool flops; @@ -918,6 +918,14 @@ struct Abc9OpsPass : public Pass { log("mapping, and is expected to be called in conjunction with other operations from\n"); log("the `abc9' script pass. Only fully-selected modules are supported.\n"); log("\n"); + log(" -check\n"); + 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_delays\n"); + log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); + log(" certain delays, e.g. (* abc9_required *) values.\n"); + log("\n"); log(" -mark_scc\n"); log(" for an arbitrarily chosen cell in each unique SCC of each selected module\n"); log(" (tagged with an (* abc9_scc_id = *) attribute), temporarily mark all\n"); @@ -938,6 +946,10 @@ struct Abc9OpsPass : public Pass { 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(" -write_box (|(null)) \n"); + log(" copy the existing box file from (skip if '(null)') and append any\n"); + log(" new box definitions.\n"); + log("\n"); log(" -reintegrate\n"); log(" for each selected module, re-intergrate the module '$abc9'\n"); log(" by first recovering ABC9 boxes, and then stitching in the remaining primary\n"); @@ -949,7 +961,7 @@ struct Abc9OpsPass : public Pass { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); bool check_mode = false; - bool prep_times_mode = false; + bool prep_delays_mode = false; bool mark_scc_mode = false; bool prep_dff_mode = false; bool prep_xaiger_mode = false; @@ -976,8 +988,8 @@ struct Abc9OpsPass : public Pass { prep_xaiger_mode = true; continue; } - if (arg == "-prep_times") { - prep_times_mode = true; + if (arg == "-prep_delays") { + prep_delays_mode = true; continue; } if (arg == "-write_box" && argidx+2 < args.size()) { @@ -999,16 +1011,16 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); - if (!(check_mode || mark_scc_mode || prep_times_mode || prep_xaiger_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode)) - log_cmd_error("At least one of -check, -mark_scc, -prep_{times,xaiger,dff}, -write_box, -reintegrate must be specified.\n"); + if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode)) + log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff}, -write_box, -reintegrate must be specified.\n"); if (dff_mode && !prep_xaiger_mode) log_cmd_error("'-dff' option is only relevant for -prep_xaiger.\n"); if (check_mode) check(design); - if (prep_times_mode) - prep_times(design); + if (prep_delays_mode) + prep_delays(design); for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute("\\abc9_holes")) -- cgit v1.2.3 From b951ca9e1c25b0c9c021419c3e537c743dca6216 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 14:06:02 -0800 Subject: abc9_ops: fix -reintegrate handling of $__ABC9_DELAY --- passes/techmap/abc9_ops.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index af4073594..816c0276a 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -659,7 +659,7 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } } - else if (mapped_cell->type == ID($__ABC9_DELAY)) { + else if (box_lookup.at(mapped_cell->type, IdString()) == ID($__ABC9_DELAY)) { SigBit I = mapped_cell->getPort(ID(i)); SigBit O = mapped_cell->getPort(ID(o)); if (I.wire) @@ -671,7 +671,8 @@ void reintegrate(RTLIL::Module *module) } else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); - log_assert(existing_cell); + if (!existing_cell) + log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell)); log_assert(mapped_cell->type.begins_with("$__boxid")); auto type = box_lookup.at(mapped_cell->type, IdString()); -- cgit v1.2.3 From 4656f202c6f05d126c1acc79fca675e467c80840 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 14:27:29 -0800 Subject: abc9_ops: -reintegrate to not trim box padding anymore --- passes/techmap/abc9_ops.cc | 9 --------- 1 file changed, 9 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 463941b0b..aa21ff283 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -562,15 +562,6 @@ void reintegrate(RTLIL::Module *module) c.wire = module->wires_.at(remap_name(c.wire->name)); newsig.append(c); } - - auto it = existing_cell->connections_.find(port_name); - if (it == existing_cell->connections_.end()) - continue; - if (GetSize(newsig) > GetSize(it->second)) - newsig = newsig.extract(0, GetSize(it->second)); - else - log_assert(GetSize(newsig) == GetSize(it->second)); - cell->setPort(port_name, newsig); if (w->port_input && !abc9_flop) -- cgit v1.2.3 From 0e4285ca0d92397490768e649626cfdb5a0c9d95 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 15:05:49 -0800 Subject: abc9_ops: generate flop box ids, add abc9_required to FD* cells --- passes/techmap/abc9_ops.cc | 121 +++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 65 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index a686bbd32..0c95f7ff6 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -23,6 +23,7 @@ #include "kernel/utils.h" #include "kernel/celltypes.h" +#define ABC9_FLOPS_BASE_ID 8000 #define ABC9_DELAY_BASE_ID 9000 USING_YOSYS_NAMESPACE @@ -39,20 +40,20 @@ void check(RTLIL::Design *design) { 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 (it == m->attributes.end()) { - if (flop) - log_error("Module '%s' contains (* abc9_flop *) but not (* abc9_box_id= *).\n", log_id(m)); - continue; + if (!flop) { + if (it == m->attributes.end()) + continue; + auto id = it->second.as_int(); + auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); + if (!r.second) + log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", + log_id(m), id, log_id(r.first->second)); } - if (m->name.begins_with("$paramod")) - continue; - auto id = it->second.as_int(); - auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); - if (!r.second) - log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", - log_id(m), id, log_id(r.first->second)); // Make carry in the last PI, and carry out the last PO // since ABC requires it this way @@ -217,13 +218,11 @@ void prep_xaiger(RTLIL::Module *module, bool dff) continue; auto inst_module = module->design->module(cell->type); - bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id"); - bool abc9_flop = false; - if (abc9_box) { - abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); - if (abc9_flop && !dff) - continue; + bool abc9_flop = inst_module && inst_module->get_bool_attribute("\\abc9_flop"); + if (abc9_flop && !dff) + continue; + if ((inst_module && inst_module->attributes.count("\\abc9_box_id")) || abc9_flop) { auto r = box_ports.insert(cell->type); if (r.second) { // Make carry in the last PI, and carry out the last PO @@ -309,17 +308,17 @@ void prep_xaiger(RTLIL::Module *module, bool dff) cell->attributes["\\abc9_box_seq"] = box_count++; - IdString derived_name = box_module->derive(design, cell->parameters); - box_module = design->module(derived_name); + IdString derived_type = box_module->derive(design, cell->parameters); + box_module = design->module(derived_type); - auto r = cell_cache.insert(derived_name); + 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("\\whitebox")) { - holes_cell = holes_module->addCell(cell->name, derived_name); + holes_cell = holes_module->addCell(cell->name, derived_type); if (box_module->has_processes()) Pass::call_on_module(design, box_module, "proc"); @@ -344,7 +343,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } else if (w->port_output) - conn = holes_module->addWire(stringf("%s.%s", derived_name.c_str(), log_id(port_name)), GetSize(w)); + 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 @@ -387,7 +386,7 @@ void prep_delays(RTLIL::Design *design) { std::set delays; pool flops; - std::vector boxes; + std::vector cells; std::map> requireds; for (auto module : design->selected_modules()) { if (module->processes.size() > 0) { @@ -395,7 +394,7 @@ void prep_delays(RTLIL::Design *design) continue; } - boxes.clear(); + cells.clear(); for (auto cell : module->cells()) { if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) continue; @@ -406,19 +405,21 @@ void prep_delays(RTLIL::Design *design) if (!inst_module->get_blackbox_attribute()) continue; if (inst_module->get_bool_attribute(ID(abc9_flop))) { + IdString derived_type = inst_module->derive(design, cell->parameters); + inst_module = design->module(derived_type); + log_assert(inst_module); flops.insert(inst_module); - continue; + continue; // because all flop required times + // will be captured in the flop box } - // All remaining boxes are combinatorial and cannot - // contain a required time if (inst_module->attributes.count(ID(abc9_box_id))) continue; - boxes.emplace_back(cell); + cells.emplace_back(cell); } delays.clear(); requireds.clear(); - for (auto cell : boxes) { + for (auto cell : cells) { RTLIL::Module* inst_module = module->design->module(cell->type); log_assert(inst_module); for (auto &conn : cell->connections_) { @@ -475,13 +476,9 @@ void prep_delays(RTLIL::Design *design) module->attributes[ID(abc9_delays)] = ss.str(); } + int flops_id = ABC9_FLOPS_BASE_ID; std::stringstream ss; for (auto flop_module : flops) { - // Skip parameterised flop_modules for now (since we do not - // dynamically generate the abc9_box_id) - if (flop_module->name.begins_with("$paramod")) - continue; - int num_inputs = 0, num_outputs = 0; for (auto port_name : flop_module->ports) { auto wire = flop_module->wire(port_name); @@ -490,7 +487,11 @@ void prep_delays(RTLIL::Design *design) } log_assert(num_outputs == 1); - ss << log_id(flop_module) << " " << flop_module->attributes.at(ID(abc9_box_id)).as_int(); + auto r = flop_module->attributes.insert(ID(abc9_box_id)); + if (r.second) + r.first->second = flops_id++; + + ss << log_id(flop_module) << " " << r.first->second.as_int(); ss << " 1 " << num_inputs+1 << " " << num_outputs << std::endl; bool first = true; for (auto port_name : flop_module->ports) { @@ -550,23 +551,11 @@ void reintegrate(RTLIL::Module *module) for (auto w : mapped_mod->wires()) module->addWire(remap_name(w->name), GetSize(w)); - dict box_lookup; - for (auto m : design->modules()) { - auto it = m->attributes.find(ID(abc9_box_id)); - if (it == m->attributes.end()) - continue; - if (m->name.begins_with("$paramod")) - continue; - auto id = it->second.as_int(); - auto r YS_ATTRIBUTE(unused) = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); - log_assert(r.second); - } - std::vector boxes; for (auto cell : module->cells().to_vector()) { if (cell->has_keep_attr()) continue; - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) module->remove(cell); else if (cell->attributes.erase("\\abc9_box_seq")) boxes.emplace_back(cell); @@ -659,26 +648,29 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } } - else if (box_lookup.at(mapped_cell->type, IdString()) == ID($__ABC9_DELAY)) { - SigBit I = mapped_cell->getPort(ID(i)); - SigBit O = mapped_cell->getPort(ID(o)); - if (I.wire) - I.wire = module->wires_.at(remap_name(I.wire->name)); - log_assert(O.wire); - O.wire = module->wires_.at(remap_name(O.wire->name)); - module->connect(O, I); - continue; - } else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); if (!existing_cell) log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell)); - log_assert(mapped_cell->type.begins_with("$__boxid")); - - auto type = box_lookup.at(mapped_cell->type, IdString()); - if (type == IdString()) - log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); - mapped_cell->type = type; +#ifndef NDEBUG + RTLIL::Module* box_module = design->module(existing_cell->type); + IdString 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("\\abc9_box_id").as_int())); +#endif + mapped_cell->type = existing_cell->type; + + if (mapped_cell->type == ID($__ABC9_DELAY)) { + SigBit I = mapped_cell->getPort(ID(i)); + SigBit O = mapped_cell->getPort(ID(o)); + if (I.wire) + I.wire = module->wires_.at(remap_name(I.wire->name)); + log_assert(O.wire); + O.wire = module->wires_.at(remap_name(O.wire->name)); + module->connect(O, I); + continue; + } RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = existing_cell->parameters; @@ -694,7 +686,6 @@ void reintegrate(RTLIL::Module *module) SigSpec outputs = std::move(it->second); mapped_cell->connections_.erase(it); - RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module->attributes.count("\\abc9_flop"); if (!abc9_flop) { for (const auto &i : inputs) -- cgit v1.2.3 From 1c88a6c24084743c95db9fb21c2b429a3736fb77 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 15:20:04 -0800 Subject: abc9_ops: implement a requireds_cache --- passes/techmap/abc9_ops.cc | 60 ++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 26 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 0c95f7ff6..1de95128f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -387,7 +387,7 @@ void prep_delays(RTLIL::Design *design) std::set delays; pool flops; std::vector cells; - std::map> requireds; + dict>> requireds_cache; for (auto module : design->selected_modules()) { if (module->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(module)); @@ -418,48 +418,56 @@ void prep_delays(RTLIL::Design *design) } delays.clear(); - requireds.clear(); for (auto cell : cells) { RTLIL::Module* inst_module = module->design->module(cell->type); log_assert(inst_module); + auto &cell_requireds = requireds_cache[cell->type]; for (auto &conn : cell->connections_) { auto port_wire = inst_module->wire(conn.first); if (!port_wire->port_input) continue; - auto it = port_wire->attributes.find("\\abc9_required"); - if (it == port_wire->attributes.end()) - continue; - - int count = 0; - requireds.clear(); - if (it->second.flags == 0) { - count = 1; - requireds[it->second.as_int()].push_back(0); + auto r = cell_requireds.insert(conn.first); + auto &requireds = r.first->second; + if (r.second) { + auto it = port_wire->attributes.find("\\abc9_required"); + if (it == port_wire->attributes.end()) + continue; + if (it->second.flags == 0) { + int delay = it->second.as_int(); + delays.insert(delay); + requireds.emplace_back(delay); + } + else + for (const auto &tok : split_tokens(it->second.decode_string())) { + int delay = atoi(tok.c_str()); + delays.insert(delay); + requireds.push_back(delay); + } } - else - for (const auto &tok : split_tokens(it->second.decode_string())) - requireds[atoi(tok.c_str())].push_back(count++); - if (count > 1 && count != GetSize(port_wire)) + + if (requireds.empty()) + continue; + if (GetSize(requireds) > 1 && GetSize(requireds) != GetSize(port_wire)) log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), - GetSize(port_wire), log_signal(it->second), count); + GetSize(port_wire), log_signal(port_wire->attributes.at("\\abc9_required")), GetSize(requireds)); SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); - for (const auto &i : requireds) { + auto it = requireds.begin(); + for (int i = 0; i < GetSize(conn.second); ++i) { #ifndef NDEBUG if (ys_debug(1)) { static std::set> seen; - if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), i.first); + if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), requireds[i]); } #endif - delays.insert(i.first); - for (auto offset : i.second) { - auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); - box->setPort(ID(I), conn.second[offset]); - box->setPort(ID(O), O[offset]); - box->setParam(ID(DELAY), i.first); - conn.second[offset] = O[offset]; - } + 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), *it); + if (requireds.size() > 1) + it++; + conn.second[i] = O[i]; } } } -- cgit v1.2.3 From f60e071e1c3ab64d1a45c4aea3580027b4242908 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 15:24:44 -0800 Subject: abc9_ops: -check to check abc9_{arrival,required} --- passes/techmap/abc9_ops.cc | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 1de95128f..4d05b5afb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -73,6 +73,36 @@ void check(RTLIL::Design *design) carry_out = port_name; } } + + auto it = w->attributes.find("\\abc9_arrival"); + if (it != w->attributes.end()) { + int count = 0; + if (it->second.flags == 0) + count++; + else + for (const auto &tok : split_tokens(it->second.decode_string())) { + (void) tok; + count++; + } + if (count > 1 && count != GetSize(w)) + log_error("%s.%s is %d bits wide but abc9_arrival = %s has %d value(s)!\n", log_id(m), log_id(port_name), + GetSize(w), log_signal(it->second), count); + } + + it = w->attributes.find("\\abc9_required"); + if (it != w->attributes.end()) { + int count = 0; + if (it->second.flags == 0) + count++; + else + for (const auto &tok : split_tokens(it->second.decode_string())) { + (void) tok; + count++; + } + if (count > 1 && count != GetSize(w)) + log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(m), log_id(port_name), + GetSize(w), log_signal(it->second), count); + } } if (carry_in != IdString() && carry_out == IdString()) @@ -448,9 +478,6 @@ void prep_delays(RTLIL::Design *design) if (requireds.empty()) continue; - if (GetSize(requireds) > 1 && GetSize(requireds) != GetSize(port_wire)) - log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), - GetSize(port_wire), log_signal(port_wire->attributes.at("\\abc9_required")), GetSize(requireds)); SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); auto it = requireds.begin(); -- cgit v1.2.3 From 485e08e4363f2aa93204f8bcc6c1ff5243936ea6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 16:33:41 -0800 Subject: abc9_ops: cope with (* abc9_flop *) in place of (* abc9_box_id *) --- passes/techmap/abc9_ops.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 4d05b5afb..fd2759ae5 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -117,7 +117,7 @@ void check(RTLIL::Design *design) if (wire->port_output) num_outputs++; } if (num_outputs != 1) - log_error("Module '%s' with (* abc_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); + log_error("Module '%s' with (* abc9_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); } } } @@ -333,7 +333,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->attributes.count("\\abc9_box_id")) + if (!box_module || (!box_module->attributes.count("\\abc9_box_id") && !box_module->get_bool_attribute("\\abc9_flop"))) continue; cell->attributes["\\abc9_box_seq"] = box_count++; -- cgit v1.2.3 From 5a63c197477d59567424faab3b56329c426394b9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Jan 2020 13:14:48 -0800 Subject: abc9_ops: -write_box is empty, output a dummy box to prevent ABC error --- passes/techmap/abc9_exe.cc | 3 +-- passes/techmap/abc9_ops.cc | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index a2acfac91..484964ddf 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -510,9 +510,8 @@ struct Abc9ExePass : public Pass { } } - // ABC expects a box file for XAIG if (box_file.empty()) - box_file = "+/dummy.box"; + log_cmd_error("abc9_exe '-box' option is mandatory.\n"); rewrite_filename(box_file); if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index fd2759ae5..13340f311 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -569,6 +569,9 @@ void write_box(RTLIL::Module *module, const std::string &src, const std::string module->attributes.erase(it); } + if (ofs.tellp() == 0) + ofs << "(dummy) 1 0 0 0"; + ofs.close(); } -- cgit v1.2.3 From d4e188299ba729756ee689d14c81aab68a7ca1b7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 12:00:14 -0800 Subject: abc9: add some log_{push,pop}() as per @nakengelhardt --- passes/techmap/abc9.cc | 5 +++++ passes/techmap/alumacc.cc | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 6a296bfe7..f4a89efff 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -235,8 +235,11 @@ struct Abc9Pass : public ScriptPass extra_args(args, argidx, design); log_header(design, "Executing ABC9 pass.\n"); + log_push(); run_script(design, run_from, run_to); + + log_pop(); } void script() YS_OVERRIDE @@ -276,6 +279,7 @@ struct Abc9Pass : public ScriptPass } log_assert(!mod->attributes.count(ID(abc9_box_id))); + log_push(); active_design->selection().select(mod); if (!active_design->selected_whole_module(mod)) @@ -310,6 +314,7 @@ struct Abc9Pass : public ScriptPass } active_design->selection().selected_modules.clear(); + log_pop(); } active_design->selection_stack.pop_back(); diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 034731b87..cf2ac16c9 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -397,18 +397,21 @@ struct AlumaccWorker { log(" creating $alu model for %s (%s):", log_id(cell), log_id(cell->type)); - bool cmp_less = cell->type.in(ID($lt), ID($le)); - bool cmp_equal = cell->type.in(ID($le), ID($ge)); + bool cmp_less = false; //cell->type.in(ID($lt), ID($le)); + bool cmp_equal = false; //cell->type.in(ID($le), ID($ge)); bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); - if (B < A && GetSize(B)) { - cmp_less = !cmp_less; + if (cell->type.in(ID($lt), ID($ge))) std::swap(A, B); - } + + //if (B < A && GetSize(B)) { + // cmp_less = !cmp_less; + // std::swap(A, B); + //} alunode_t *n = nullptr; @@ -432,6 +435,12 @@ struct AlumaccWorker log(" merged with %s.\n", log_id(n->cells.front())); } + if (cell->type.in(ID($le), ID($ge))) { + SigSpec YY = module->addWire(NEW_ID, GetSize(Y)); + module->addNot(NEW_ID, YY, Y); + Y = YY; + } + n->cells.push_back(cell); n->cmp.push_back(std::make_tuple(cmp_less, !cmp_less, cmp_equal, false, Y)); } -- cgit v1.2.3 From 3b44b53e946780ac25581f236be7c836fa6927bf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Jan 2020 09:36:54 -0800 Subject: abc9: fix scratchpad entry abc9.verify --- passes/techmap/abc9.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 1f6cdaa22..b0e2c7697 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -304,14 +304,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip for (size_t pos = abc9_script.find("{R}"); pos != std::string::npos; pos = abc9_script.find("{R}", pos)) abc9_script = abc9_script.substr(0, pos) + R + abc9_script.substr(pos+3); - abc9_script += stringf("; &ps -l; &write -n %s/output.aig;", tempdir_name.c_str()); + abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name.c_str()); if (design->scratchpad_get_bool("abc9.verify")) { if (dff_mode) - abc9_script += "verify -s;"; + abc9_script += "; &verify -s"; else - abc9_script += "verify;"; + abc9_script += "; &verify"; } - abc9_script += "time"; + abc9_script += "; time"; abc9_script = add_echos_to_abc9_cmd(abc9_script); for (size_t i = 0; i+1 < abc9_script.size(); i++) -- cgit v1.2.3 From a94b41011d5ec9514739c52b963e0bd96890973f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Jan 2020 10:08:48 -0800 Subject: abc9: error out if flip-flop init is 1'b1 for '-dff' Due to ABC sequential synthesis restriction --- passes/techmap/abc9.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index b0e2c7697..2568a6cd1 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -1069,6 +1069,8 @@ struct Abc9Pass : public Pass { SigSpec abc9_init = assign_map(abc9_init_wire); if (!abc9_init.is_fully_const()) log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + if (abc9_init == State::S1) + log_error("'%s.init' in module '%s' has value 1'b1 which is not supported by 'abc9 -dff'.\n", cell->name.c_str(), log_id(module)); r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); log_assert(r2.second); } -- cgit v1.2.3 From af0e7637a28f08978bc4dfb77089261f9fe18a5d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Jan 2020 20:54:03 -0800 Subject: alumacc: undo accidental commit --- passes/techmap/alumacc.cc | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index cf2ac16c9..034731b87 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -397,21 +397,18 @@ struct AlumaccWorker { log(" creating $alu model for %s (%s):", log_id(cell), log_id(cell->type)); - bool cmp_less = false; //cell->type.in(ID($lt), ID($le)); - bool cmp_equal = false; //cell->type.in(ID($le), ID($ge)); + bool cmp_less = cell->type.in(ID($lt), ID($le)); + bool cmp_equal = cell->type.in(ID($le), ID($ge)); bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); - if (cell->type.in(ID($lt), ID($ge))) + if (B < A && GetSize(B)) { + cmp_less = !cmp_less; std::swap(A, B); - - //if (B < A && GetSize(B)) { - // cmp_less = !cmp_less; - // std::swap(A, B); - //} + } alunode_t *n = nullptr; @@ -435,12 +432,6 @@ struct AlumaccWorker log(" merged with %s.\n", log_id(n->cells.front())); } - if (cell->type.in(ID($le), ID($ge))) { - SigSpec YY = module->addWire(NEW_ID, GetSize(Y)); - module->addNot(NEW_ID, YY, Y); - Y = YY; - } - n->cells.push_back(cell); n->cmp.push_back(std::make_tuple(cmp_less, !cmp_less, cmp_equal, false, Y)); } -- cgit v1.2.3 From 1d4314d88853feb1fa6af13fe56274d53d81d853 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 14:58:56 -0800 Subject: abc9_ops -prep_dff: insert async s/r mux in holes when replacing $_DFF_* --- passes/techmap/abc9_ops.cc | 68 +++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 31 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 5091ac0f2..750f36ceb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -106,38 +106,44 @@ void prep_dff(RTLIL::Module *module) SigMap sigmap(holes_module); dict replace; - for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { - auto cell = it->second; - if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", - "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { - SigBit D = cell->getPort("\\D"); - SigBit Q = cell->getPort("\\Q"); - // Remove the $_DFF_* cell from what needs to be a combinatorial box - it = holes_module->cells_.erase(it); - 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); - } + for (auto cell : holes_module->cells().to_vector()) { + if (!cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) + continue; + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + // Emulate async control embedded inside $_DFF_* cell with mux in front of D + if (cell->type.in("$_DFF_NN0_", "$_DFF_PN0_")) + D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort("\\R")); + else if (cell->type.in("$_DFF_NN1_", "$_DFF_PN1_")) + D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort("\\R")); + else if (cell->type.in("$_DFF_NP0_", "$_DFF_PP0_")) + D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort("\\R")); + else if (cell->type.in("$_DFF_NP1_", "$_DFF_PP1_")) + D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort("\\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 - ++it; + 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); } for (auto &conn : holes_module->connections_) -- cgit v1.2.3 From f180dba753c9f4bfb3b89575b0d224c73a1e8897 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 18:56:06 -0800 Subject: abc9_ops: -prep_xaiger to skip (* keep *) cells --- passes/techmap/abc9_ops.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 750f36ceb..40622ece7 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -165,6 +165,8 @@ void prep_xaiger(RTLIL::Module *module, bool dff) for (auto cell : module->cells()) { if (cell->type == "$__ABC9_FF_") continue; + if (cell->has_keep_attr()) + continue; auto inst_module = module->design->module(cell->type); bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id"); -- cgit v1.2.3 From 245873d42d7975b6c303c2d04b75f3cafc6c5697 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 19:08:51 -0800 Subject: abc9: warning message if no modules selected --- passes/techmap/abc9.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index f4a89efff..2aeda16d6 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -234,6 +234,12 @@ struct Abc9Pass : public ScriptPass } extra_args(args, argidx, design); + log_assert(design); + if (design->selected_modules().empty()) { + log_warning("No modules selected for ABC9 techmapping.\n"); + return; + } + log_header(design, "Executing ABC9 pass.\n"); log_push(); -- cgit v1.2.3 From dbf351390e68a9d7c453e893de8fa9d09eb24f62 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 22:45:34 -0800 Subject: abc9: -reintegrate recover type from existing cell, check against boxid --- passes/techmap/abc9_ops.cc | 49 ++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 40622ece7..d238ce0ad 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -356,24 +356,14 @@ void reintegrate(RTLIL::Module *module) for (auto w : mapped_mod->wires()) module->addWire(remap_name(w->name), GetSize(w)); - dict box_lookup; dict> box_ports; for (auto m : design->modules()) { - auto it = m->attributes.find(ID(abc9_box_id)); - if (it == m->attributes.end()) + if (!m->attributes.count(ID(abc9_box_id))) continue; - if (m->name.begins_with("$paramod")) - continue; - auto id = it->second.as_int(); - auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); - if (!r.second) - log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", - log_id(m), id, log_id(r.first->second)); - log_assert(r.second); - auto r2 = box_ports.insert(m->name); - if (r2.second) { + auto r = box_ports.insert(m->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; @@ -393,7 +383,7 @@ void reintegrate(RTLIL::Module *module) } } else - r2.first->second.push_back(port_name); + r.first->second.push_back(port_name); } if (carry_in != IdString() && carry_out == IdString()) @@ -401,8 +391,8 @@ void reintegrate(RTLIL::Module *module) if (carry_in == IdString() && carry_out != IdString()) log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); if (carry_in != IdString()) { - r2.first->second.push_back(carry_in); - r2.first->second.push_back(carry_out); + r.first->second.push_back(carry_in); + r.first->second.push_back(carry_out); } } } @@ -516,28 +506,27 @@ void reintegrate(RTLIL::Module *module) else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); - log_assert(mapped_cell->type.begins_with("$__boxid")); - auto type = box_lookup.at(mapped_cell->type, IdString()); - if (type == IdString()) - log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); - mapped_cell->type = type; + RTLIL::Module* box_module = design->module(existing_cell->type); + auto it = box_module->attributes.find(ID(abc9_box_id)); + log_assert(it != box_module->attributes.end()); + log_assert(mapped_cell->type == stringf("$__boxid%d", it->second.as_int())); + mapped_cell->type = existing_cell->type; RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = existing_cell->parameters; cell->attributes = existing_cell->attributes; module->swap_names(cell, existing_cell); - auto it = mapped_cell->connections_.find("\\i"); - log_assert(it != mapped_cell->connections_.end()); - SigSpec inputs = std::move(it->second); - mapped_cell->connections_.erase(it); - it = mapped_cell->connections_.find("\\o"); - log_assert(it != mapped_cell->connections_.end()); - SigSpec outputs = std::move(it->second); - mapped_cell->connections_.erase(it); + auto jt = mapped_cell->connections_.find("\\i"); + log_assert(jt != mapped_cell->connections_.end()); + SigSpec inputs = std::move(jt->second); + mapped_cell->connections_.erase(jt); + jt = mapped_cell->connections_.find("\\o"); + log_assert(jt != mapped_cell->connections_.end()); + SigSpec outputs = std::move(jt->second); + mapped_cell->connections_.erase(jt); - RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module->attributes.count("\\abc9_flop"); if (!abc9_flop) { for (const auto &i : inputs) -- cgit v1.2.3 From 9009b76a69b9e867f69295a8e555305925e83aeb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 27 Jan 2020 11:18:21 -0800 Subject: abc9_ops: add comments --- passes/techmap/abc9_ops.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index d238ce0ad..9ad29a8f6 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -213,6 +213,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) else if (!yosys_celltypes.cell_known(cell->type)) continue; + // TODO: Speed up toposort -- we care about box ordering only for (auto conn : cell->connections()) { if (cell->input(conn.first)) for (auto bit : sigmap(conn.second)) @@ -222,7 +223,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) for (auto bit : sigmap(conn.second)) bit_drivers[bit].insert(cell->name); } - toposort.node(cell->name); } @@ -415,6 +415,7 @@ void reintegrate(RTLIL::Module *module) std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { + // TODO: Speed up toposort -- we care about NOT ordering only toposort.node(mapped_cell->name); if (mapped_cell->type == ID($_NOT_)) { @@ -625,6 +626,17 @@ void reintegrate(RTLIL::Module *module) } } + // ABC9 will return $_NOT_ gates in its mapping (since they are + // treated as being "free"), in particular driving primary + // outputs (real primary outputs, or cells treated as blackboxes) + // or driving box inputs. + // Instead of just mapping those $_NOT_ gates into 2-input $lut-s + // at an area and delay cost, see if it is possible to push + // this $_NOT_ into the driving LUT, or into all sink LUTs. + // When this is not possible, (i.e. this signal drives two primary + // outputs, only one of which is complemented) and when the driver + // is a LUT, then clone the LUT so that it can be inverted without + // increasing depth/delay. for (auto &it : bit_users) if (bit_drivers.count(it.first)) for (auto driver_cell : bit_drivers.at(it.first)) -- cgit v1.2.3 From 21ce1b37fbc93562942c10f631c7f415f8fdba2e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 27 Jan 2020 14:22:46 -0800 Subject: abc9_ops: -check for negative arrival/required times --- passes/techmap/abc9_ops.cc | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'passes/techmap') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 0fc4de3bb..2b4a5c802 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -77,11 +77,20 @@ void check(RTLIL::Design *design) auto it = w->attributes.find("\\abc9_arrival"); if (it != w->attributes.end()) { int count = 0; - if (it->second.flags == 0) + if (it->second.flags == 0) { + if (it->second.as_int() < 0) + log_error("%s.%s has negative arrival value %d!\n", log_id(m), log_id(port_name), + it->second.as_int()); count++; + } else for (const auto &tok : split_tokens(it->second.decode_string())) { - (void) tok; + if (tok.find_first_not_of("0123456789") != std::string::npos) + log_error("%s.%s has non-integer arrival value '%s'!\n", log_id(m), log_id(port_name), + tok.c_str()); + if (atoi(tok.c_str()) < 0) + log_error("%s.%s has negative arrival value %s!\n", log_id(m), log_id(port_name), + tok.c_str()); count++; } if (count > 1 && count != GetSize(w)) @@ -92,11 +101,20 @@ void check(RTLIL::Design *design) it = w->attributes.find("\\abc9_required"); if (it != w->attributes.end()) { int count = 0; - if (it->second.flags == 0) + if (it->second.flags == 0) { + if (it->second.as_int() < 0) + log_error("%s.%s has negative required value %d!\n", log_id(m), log_id(port_name), + it->second.as_int()); count++; + } else for (const auto &tok : split_tokens(it->second.decode_string())) { - (void) tok; + if (tok.find_first_not_of("0123456789") != std::string::npos) + log_error("%s.%s has non-integer required value '%s'!\n", log_id(m), log_id(port_name), + tok.c_str()); + if (atoi(tok.c_str()) < 0) + log_error("%s.%s has negative required value %s!\n", log_id(m), log_id(port_name), + tok.c_str()); count++; } if (count > 1 && count != GetSize(w)) -- cgit v1.2.3 From 8106c3d31b10ac9ddd122f5854679b7fe3c08290 Mon Sep 17 00:00:00 2001 From: Gabriel Somlo Date: Thu, 30 Jan 2020 15:12:43 -0500 Subject: abc9: restore ability to use ABCEXTERNAL Signed-off-by: Gabriel Somlo --- passes/techmap/Makefile.inc | 1 + 1 file changed, 1 insertion(+) (limited to 'passes/techmap') diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 369c9de64..c16db0d57 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -13,6 +13,7 @@ OBJS += passes/techmap/abc9_ops.o ifneq ($(ABCEXTERNAL),) passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' +passes/techmap/abc9_exe.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' endif endif -- cgit v1.2.3