mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-12 20:18:20 +00:00
abc9_techmap -> _map; called from abc9 script pass along with abc9_ops
This commit is contained in:
parent
ec25394808
commit
f348ffa44d
|
@ -8,7 +8,8 @@ OBJS += passes/techmap/libparse.o
|
||||||
ifeq ($(ENABLE_ABC),1)
|
ifeq ($(ENABLE_ABC),1)
|
||||||
OBJS += passes/techmap/abc.o
|
OBJS += passes/techmap/abc.o
|
||||||
OBJS += passes/techmap/abc9.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),)
|
ifneq ($(ABCEXTERNAL),)
|
||||||
passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
||||||
passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
|
||||||
|
|
231
passes/techmap/abc9.cc
Normal file
231
passes/techmap/abc9.cc
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* (C) 2019 Eddie Hung <eddie@fpgeh.com>
|
||||||
|
*
|
||||||
|
* 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 <command>\n");
|
||||||
|
#ifdef ABCEXTERNAL
|
||||||
|
log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
|
||||||
|
#else
|
||||||
|
log(" use the specified command instead of \"<yosys-bindir>/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 <file>\n");
|
||||||
|
log(" use the specified ABC script file instead of the default script.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" if <file> 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 <picoseconds>\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 <num>\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 <width>\n");
|
||||||
|
log(" generate netlist using luts of (max) the specified width.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -lut <w1>:<w2>\n");
|
||||||
|
log(" generate netlist using luts of (max) the specified width <w2>. All\n");
|
||||||
|
log(" luts with width <= <w1> have constant cost. for luts larger than <w1>\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 <file>\n");
|
||||||
|
log(" pass this file with lut library to ABC.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\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 [!]<clock-signal-name>[,[!]<enable-signal-name>]\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 <file>\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<std::string> 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 <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig");
|
||||||
|
run(stringf("%s -tempdir %s", map_cmd.str().c_str(), tempdir_name.c_str()),
|
||||||
|
"abc9_map [options] -tempdir <abc-temp-dir>");
|
||||||
|
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
|
|
@ -76,58 +76,6 @@ inline std::string remap_name(RTLIL::IdString abc9_name)
|
||||||
return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);
|
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<RTLIL::Const> 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 add_echos_to_abc9_cmd(std::string str)
|
||||||
{
|
{
|
||||||
std::string new_str, token;
|
std::string new_str, token;
|
||||||
|
@ -254,10 +202,10 @@ struct abc9_output_filter
|
||||||
};
|
};
|
||||||
|
|
||||||
void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
|
void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
|
||||||
bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
|
/*bool cleanup,*/ vector<int> lut_costs, bool dff_mode, std::string clk_str,
|
||||||
bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
|
bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
|
||||||
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, const dict<int,IdString> &box_lookup, bool nomfs
|
std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs, std::string tempdir_name
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
module = current_module;
|
module = current_module;
|
||||||
|
@ -296,10 +244,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
if (dff_mode && clk_sig.empty())
|
if (dff_mode && clk_sig.empty())
|
||||||
log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
|
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",
|
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());
|
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
|
||||||
|
|
||||||
|
@ -383,33 +327,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
log_push();
|
||||||
|
|
||||||
if (count_output)
|
//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::string buffer;
|
||||||
std::ifstream ifs;
|
std::ifstream ifs;
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -428,8 +349,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
design->remove(design->module(ID($__abc9__)));
|
design->remove(design->module(ID($__abc9__)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
design->selection_stack.pop_back();
|
|
||||||
|
|
||||||
log_header(design, "Executing ABC9_MAP.\n");
|
log_header(design, "Executing ABC9_MAP.\n");
|
||||||
|
|
||||||
if (!lut_costs.empty()) {
|
if (!lut_costs.empty()) {
|
||||||
|
@ -773,41 +692,16 @@ clone_lut:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
|
||||||
log("ABC RESULTS: input signals: %8d\n", in_wires);
|
log("ABC RESULTS: input signals: %8d\n", in_wires);
|
||||||
log("ABC RESULTS: output signals: %8d\n", out_wires);
|
log("ABC RESULTS: output signals: %8d\n", out_wires);
|
||||||
|
|
||||||
design->remove(mapped_mod);
|
design->remove(mapped_mod);
|
||||||
}
|
}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
log("Don't call ABC as there is nothing to map.\n");
|
// 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();
|
log_pop();
|
||||||
}
|
}
|
||||||
|
@ -894,10 +788,10 @@ struct Abc9TechmapPass : public Pass {
|
||||||
// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
|
// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
|
||||||
// log(" them, for example for equivalence checking.)\n");
|
// log(" them, for example for equivalence checking.)\n");
|
||||||
// log("\n");
|
// log("\n");
|
||||||
log(" -nocleanup\n");
|
// log(" -nocleanup\n");
|
||||||
log(" when this option is used, the temporary files created by this pass\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(" are not removed. this is useful for debugging.\n");
|
||||||
log("\n");
|
// log("\n");
|
||||||
log(" -showtmp\n");
|
log(" -showtmp\n");
|
||||||
log(" print the temp dir name in log. usually this is suppressed so that the\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(" command output is identical across runs.\n");
|
||||||
|
@ -910,6 +804,9 @@ struct Abc9TechmapPass : public Pass {
|
||||||
log(" -box <file>\n");
|
log(" -box <file>\n");
|
||||||
log(" pass this file with box library to ABC. Use with -lut.\n");
|
log(" pass this file with box library to ABC. Use with -lut.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -tempdir <dir>\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("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("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("ABC on logic snippets extracted from your design. You will not get any useful\n");
|
||||||
|
@ -922,7 +819,7 @@ struct Abc9TechmapPass : public Pass {
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
{
|
{
|
||||||
log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n");
|
log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n");
|
||||||
log_push();
|
log_push();
|
||||||
|
|
||||||
assign_map.clear();
|
assign_map.clear();
|
||||||
|
@ -934,7 +831,8 @@ struct Abc9TechmapPass : public Pass {
|
||||||
#endif
|
#endif
|
||||||
std::string script_file, clk_str, box_file, lut_file;
|
std::string script_file, clk_str, box_file, lut_file;
|
||||||
std::string delay_target, lutin_shared = "-S 1", wire_delay;
|
std::string delay_target, lutin_shared = "-S 1", wire_delay;
|
||||||
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
|
std::string tempdir_name;
|
||||||
|
bool fast_mode = false, dff_mode = false, keepff = false /*, cleanup = true*/;
|
||||||
bool show_tempdir = false;
|
bool show_tempdir = false;
|
||||||
bool nomfs = false;
|
bool nomfs = false;
|
||||||
vector<int> lut_costs;
|
vector<int> lut_costs;
|
||||||
|
@ -1038,10 +936,10 @@ struct Abc9TechmapPass : public Pass {
|
||||||
// keepff = true;
|
// keepff = true;
|
||||||
// continue;
|
// continue;
|
||||||
//}
|
//}
|
||||||
if (arg == "-nocleanup") {
|
//if (arg == "-nocleanup") {
|
||||||
cleanup = false;
|
// cleanup = false;
|
||||||
continue;
|
// continue;
|
||||||
}
|
//}
|
||||||
if (arg == "-showtmp") {
|
if (arg == "-showtmp") {
|
||||||
show_tempdir = true;
|
show_tempdir = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -1062,17 +960,24 @@ struct Abc9TechmapPass : public Pass {
|
||||||
nomfs = true;
|
nomfs = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-tempdir" && argidx+1 < args.size()) {
|
||||||
|
tempdir_name = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
// ABC expects a box file for XAIG
|
// ABC expects a box file for XAIG
|
||||||
if (box_file.empty())
|
if (box_file.empty())
|
||||||
box_file = "+/dummy.box";
|
box_file = "+/dummy.box";
|
||||||
|
|
||||||
rewrite_filename(box_file);
|
rewrite_filename(box_file);
|
||||||
if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+')
|
if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+')
|
||||||
box_file = std::string(pwd) + "/" + box_file;
|
box_file = std::string(pwd) + "/" + box_file;
|
||||||
|
|
||||||
|
if (tempdir_name.empty())
|
||||||
|
log_cmd_error("abc9_map '-tempdir' option is mandatory.\n");
|
||||||
|
|
||||||
dict<int,IdString> box_lookup;
|
dict<int,IdString> box_lookup;
|
||||||
for (auto m : design->modules()) {
|
for (auto m : design->modules()) {
|
||||||
|
@ -1148,9 +1053,9 @@ struct Abc9TechmapPass : public Pass {
|
||||||
assign_map.set(mod);
|
assign_map.set(mod);
|
||||||
|
|
||||||
if (!dff_mode || !clk_str.empty()) {
|
if (!dff_mode || !clk_str.empty()) {
|
||||||
abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
|
abc9_module(design, mod, script_file, exe_file, /*cleanup,*/ lut_costs, dff_mode, clk_str, keepff,
|
||||||
delay_target, lutin_shared, fast_mode, show_tempdir,
|
delay_target, lutin_shared, fast_mode, show_tempdir,
|
||||||
box_file, lut_file, wire_delay, box_lookup, nomfs);
|
box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1294,9 +1199,9 @@ struct Abc9TechmapPass : public Pass {
|
||||||
clk_sig = assign_map(std::get<1>(it.first));
|
clk_sig = assign_map(std::get<1>(it.first));
|
||||||
en_polarity = std::get<2>(it.first);
|
en_polarity = std::get<2>(it.first);
|
||||||
en_sig = assign_map(std::get<3>(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(), "$",
|
abc9_module(design, mod, script_file, exe_file, /*cleanup,*/ lut_costs, !clk_sig.empty(), "$",
|
||||||
keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
|
keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
|
||||||
box_file, lut_file, wire_delay, box_lookup, nomfs);
|
box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name);
|
||||||
assign_map.set(mod);
|
assign_map.set(mod);
|
||||||
}
|
}
|
||||||
}
|
}
|
139
passes/techmap/abc9_ops.cc
Normal file
139
passes/techmap/abc9_ops.cc
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* 2019 Eddie Hung <eddie@fpgeh.com>
|
||||||
|
*
|
||||||
|
* 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<RTLIL::Const> 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<std::string> 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
|
Loading…
Reference in a new issue