3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-23 09:05:32 +00:00

Merge remote-tracking branch 'origin/eddie/abc9_refactor' into eddie/abc9_required

This commit is contained in:
Eddie Hung 2020-01-12 15:19:41 -08:00
commit f9aae90e7a
11 changed files with 198 additions and 156 deletions

View file

@ -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 <command>\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 <picoseconds>\n");
@ -200,10 +190,10 @@ struct Abc9Pass : public ScriptPass
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("aigmap");
run("wbflip @abc9_holes");
}

View file

@ -284,10 +284,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 <command>\n");
#ifdef ABCEXTERNAL
@ -306,18 +308,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 <picoseconds>\n");

View file

@ -98,7 +98,7 @@ void break_scc(RTLIL::Module *module)
// 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()) {
for (auto cell : module->cells()) {
auto it = cell->attributes.find(ID(abc9_scc_id));
if (it == cell->attributes.end())
continue;
@ -174,7 +174,7 @@ void prep_dff(RTLIL::Module *module)
typedef SigSpec clkdomain_t;
dict<clkdomain_t, int> clk_to_mergeability;
for (auto cell : module->selected_cells()) {
for (auto cell : module->cells()) {
if (cell->type != "$__ABC9_FF_")
continue;
@ -202,14 +202,16 @@ void prep_dff(RTLIL::Module *module)
RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str()));
if (holes_module) {
dict<SigSig, SigSig> replace;
SigMap sigmap(holes_module);
dict<SigSpec, SigSpec> 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
// 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)
@ -217,10 +219,10 @@ void prep_dff(RTLIL::Module *module)
else
port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
log_assert(port);
// Prepare to replace "assign <port> = DFF.Q;" with "assign <port> = DFF.D;"
// in order to extract the combinatorial control logic that feeds the box
// Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_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(SigSig(port,Q), SigSig(port,D)));
replace.insert(std::make_pair(Q,D));
// Since `flatten` above would have created wires named "<cell>.Q",
// extract the pre-techmap cell name
auto pos = Q.wire->name.str().rfind(".");
@ -228,7 +230,7 @@ void prep_dff(RTLIL::Module *module)
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 "<cell>.$abc9_currQ"
// wire (which itself is driven an input port) we inserted above
// 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);
@ -237,11 +239,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.second = replace.at(sigmap(conn.second), conn.second);
}
}
@ -256,7 +255,7 @@ void prep_holes(RTLIL::Module *module, bool dff)
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
bool abc9_box_seen = false;
for (auto cell : module->selected_cells()) {
for (auto cell : module->cells()) {
if (cell->type == "$__ABC9_FF_")
continue;
@ -294,21 +293,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<Cell*> box_list;
@ -377,100 +378,97 @@ 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);
cell->type = derived_name;
cell->parameters.clear();
//cell->type = derived_name;
//cell->parameters.clear();
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;
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)
carry_in = port_name;
if (w->port_output)
carry_out = port_name;
auto r = cell_cache.insert(derived_name);
auto &holes_cell = r.first->second;
if (r.second) {
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);
}
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);
}
}
if (box_module->get_bool_attribute("\\whitebox")) {
holes_cell = holes_module->addCell(cell->name, derived_name);
for (const auto &port_name : box_ports.at(cell->type)) {
RTLIL::Wire *w = box_module->wire(port_name);
log_assert(w);
RTLIL::Wire *holes_wire;
RTLIL::SigSpec port_sig;
if (w->port_input)
for (int i = 0; i < GetSize(w); i++) {
if (box_module->has_processes())
Pass::call_on_module(design, box_module, "proc");
int box_inputs = 0;
for (auto port_name : box_ports.at(cell->type)) {
RTLIL::Wire *w = box_module->wire(port_name);
log_assert(w);
log_assert(!w->port_input || !w->port_output);
auto &conn = holes_cell->connections_[port_name];
if (w->port_input) {
for (int i = 0; i < GetSize(w); i++) {
box_inputs++;
RTLIL::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);
}
conn.append(holes_wire);
}
}
else if (w->port_output)
conn = holes_module->addWire(stringf("%s.%s", derived_name.c_str(), log_id(port_name)), GetSize(w));
}
// For flops only, create an extra 1-bit input that drives a new wire
// called "<cell>.abc9_ff.Q" that is used below
if (box_module->get_bool_attribute("\\abc9_flop")) {
box_inputs++;
holes_wire = holes_module->wire(stringf("\\i%d", 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);
}
if (holes_cell)
port_sig.append(holes_wire);
Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
holes_module->connect(Q, 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);
}
else // box_module is a blackbox
log_assert(holes_cell == nullptr);
}
// For flops only, create an extra 1-bit input that drives a new wire
// called "<cell>.$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_ff.Q", cell->name.c_str()));
holes_module->connect(w, holes_wire);
for (auto port_name : box_ports.at(cell->type)) {
RTLIL::Wire *w = box_module->wire(port_name);
log_assert(w);
if (!w->port_output)
continue;
Wire *holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(port_name)), GetSize(w));
holes_wire->port_output = true;
holes_wire->port_id = port_id++;
holes_module->ports.push_back(holes_wire->name);
if (holes_cell) // whitebox
holes_module->connect(holes_wire, holes_cell->getPort(port_name));
else // blackbox
holes_module->connect(holes_wire, Const(State::S0, GetSize(w)));
}
}
}
@ -1059,7 +1057,11 @@ struct Abc9OpsPass : public Pass {
}
extra_args(args, argidx, design);
// TODO: Check at least one mode given
if (!(check_mode || break_scc_mode || unbreak_scc_mode || prep_times_mode || prep_holes_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode))
log_cmd_error("At least one of -check, -{,un}break_scc, -prep_{times,holes,dff}, -write_box, -reintegrate must be specified.\n");
if (dff_mode && !prep_holes_mode)
log_cmd_error("'-dff' option is only relevant for -prep_holes.\n");
if (check_mode)
check(design);
@ -1075,6 +1077,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)