Merge pull request #1188 from YosysHQ/eddie/abc9_push_inverters

abc9: push inverters driving box inputs (comb outputs) through $lut soft logic
This commit is contained in:
Eddie Hung 2019-07-16 08:53:47 -07:00 committed by GitHub
commit 5939b5d636
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 128 additions and 45 deletions

View File

@ -24,12 +24,13 @@
#if 0 #if 0
// Based on &flow3 - better QoR but more experimental // Based on &flow3 - better QoR but more experimental
#define ABC_COMMAND_LUT "&st; &ps -l; "/*"&sweep -v;"*/" &scorr; " \ #define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \
"&st; &if {W}; &save; &st; &syn2; &if {W}; &save; &load; "\ "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\
"&st; &if -g -K 6; &dch -f; &if {W}; &save; &load; "\ "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\
"&st; &if -g -K 6; &synch2; &if {W}; &save; &load" "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\
"&mfs; &ps -l"
#else #else
#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps -l; &if {W} {D} -v; &mfs; &ps -l" #define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l"
#endif #endif
@ -53,6 +54,7 @@
#endif #endif
#include "frontends/aiger/aigerparse.h" #include "frontends/aiger/aigerparse.h"
#include "kernel/utils.h"
#ifdef YOSYS_LINK_ABC #ifdef YOSYS_LINK_ABC
extern "C" int Abc_RealMain(int argc, char *argv[]); extern "C" int Abc_RealMain(int argc, char *argv[]);
@ -570,13 +572,23 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
boxes.emplace_back(cell); boxes.emplace_back(cell);
} }
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers;
dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
std::map<std::string, int> cell_stats; std::map<std::string, int> cell_stats;
for (auto c : mapped_mod->cells()) for (auto c : mapped_mod->cells())
{ {
toposort.node(c->name);
RTLIL::Cell *cell = nullptr; RTLIL::Cell *cell = nullptr;
if (c->type == "$_NOT_") { if (c->type == "$_NOT_") {
RTLIL::SigBit a_bit = c->getPort("\\A").as_bit(); RTLIL::SigBit a_bit = c->getPort("\\A");
RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit(); RTLIL::SigBit y_bit = c->getPort("\\Y");
bit_users[a_bit].insert(c->name);
bit_drivers[y_bit].insert(c->name);
if (!a_bit.wire) { if (!a_bit.wire) {
c->setPort("\\Y", module->addWire(NEW_ID)); c->setPort("\\Y", module->addWire(NEW_ID));
RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
@ -584,11 +596,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
module->connect(RTLIL::SigBit(wire, y_bit.offset), RTLIL::S1); module->connect(RTLIL::SigBit(wire, y_bit.offset), RTLIL::S1);
} }
else if (!lut_costs.empty() || !lut_file.empty()) { else if (!lut_costs.empty() || !lut_file.empty()) {
RTLIL::Cell* driving_lut = nullptr; RTLIL::Cell* driver_lut = nullptr;
// ABC can return NOT gates that drive POs // ABC can return NOT gates that drive POs
if (!a_bit.wire->port_input) { if (!a_bit.wire->port_input) {
// If it's not a NOT gate that that comes from a PI directly, // If it's not a NOT gate that that comes from a PI directly,
// find the driving LUT and clone that to guarantee that we won't // find the driver LUT and clone that to guarantee that we won't
// increase the max logic depth // increase the max logic depth
// (TODO: Optimise by not cloning unless will increase depth) // (TODO: Optimise by not cloning unless will increase depth)
RTLIL::IdString driver_name; RTLIL::IdString driver_name;
@ -596,38 +608,25 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
else else
driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
driving_lut = mapped_mod->cell(driver_name); driver_lut = mapped_mod->cell(driver_name);
} }
if (!driving_lut) { if (!driver_lut) {
// If a driver couldn't be found (could be from PI, // If a driver couldn't be found (could be from PI or box CI)
// or from a box) then implement using a LUT // then implement using a LUT
cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset), RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset), RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
1); RTLIL::Const::from_string("01"));
bit2sinks[cell->getPort("\\A")].push_back(cell);
cell_stats["$lut"]++;
} }
else { else
auto driver_a = driving_lut->getPort("\\A").chunks(); not2drivers[c] = driver_lut;
for (auto &chunk : driver_a) continue;
chunk.wire = module->wires_[remap_name(chunk.wire->name)];
RTLIL::Const driver_lut = driving_lut->getParam("\\LUT");
for (auto &b : driver_lut.bits) {
if (b == RTLIL::State::S0) b = RTLIL::State::S1;
else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
}
cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
driver_a,
RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
driver_lut);
}
}
else {
cell = module->addCell(remap_name(c->name), "$_NOT_");
cell->setPort("\\A", RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset));
cell->setPort("\\Y", RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset));
cell_stats[RTLIL::unescape_id(c->type)]++;
} }
else
log_abort();
if (cell && markgroups) cell->attributes["\\abcgroup"] = map_autoidx; if (cell && markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
continue; continue;
} }
@ -635,11 +634,12 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
RTLIL::Cell *existing_cell = nullptr; RTLIL::Cell *existing_cell = nullptr;
if (c->type == "$lut") { if (c->type == "$lut") {
if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) { if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT") == RTLIL::Const::from_string("01")) {
SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]; SigSpec my_a = module->wires_.at(remap_name(c->getPort("\\A").as_wire()->name));
SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]; SigSpec my_y = module->wires_.at(remap_name(c->getPort("\\Y").as_wire()->name));
module->connect(my_y, my_a); module->connect(my_y, my_a);
if (markgroups) c->attributes["\\abcgroup"] = map_autoidx; if (markgroups) c->attributes["\\abcgroup"] = map_autoidx;
log_abort();
continue; continue;
} }
cell = module->addCell(remap_name(c->name), c->type); cell = module->addCell(remap_name(c->name), c->type);
@ -666,10 +666,20 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
continue; continue;
//log_assert(c.width == 1); //log_assert(c.width == 1);
if (c.wire) if (c.wire)
c.wire = module->wires_[remap_name(c.wire->name)]; c.wire = module->wires_.at(remap_name(c.wire->name));
newsig.append(c); newsig.append(c);
} }
cell->setPort(conn.first, newsig); 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);
} }
} }
@ -681,14 +691,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (!conn.first.is_fully_const()) { if (!conn.first.is_fully_const()) {
auto chunks = conn.first.chunks(); auto chunks = conn.first.chunks();
for (auto &c : chunks) for (auto &c : chunks)
c.wire = module->wires_[remap_name(c.wire->name)]; c.wire = module->wires_.at(remap_name(c.wire->name));
conn.first = std::move(chunks); conn.first = std::move(chunks);
} }
if (!conn.second.is_fully_const()) { if (!conn.second.is_fully_const()) {
auto chunks = conn.second.chunks(); auto chunks = conn.second.chunks();
for (auto &c : chunks) for (auto &c : chunks)
if (c.wire) if (c.wire)
c.wire = module->wires_[remap_name(c.wire->name)]; c.wire = module->wires_.at(remap_name(c.wire->name));
conn.second = std::move(chunks); conn.second = std::move(chunks);
} }
module->connect(conn); module->connect(conn);
@ -725,6 +735,79 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
} }
} }
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 = 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 != "$_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("\\A");
RTLIL::SigBit y_bit = not_cell->getPort("\\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 != "$lut")
goto clone_lut;
// Push downstream LUTs past inverter
for (auto sink_cell : jt->second) {
SigSpec A = sink_cell->getPort("\\A");
RTLIL::Const mask = sink_cell->getParam("\\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("\\A", A);
sink_cell->setParam("\\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("\\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("\\A"),
y_bit,
driver_mask);
for (auto &bit : cell->connections_.at("\\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: 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);

View File

@ -19,6 +19,6 @@ hierarchy -top abc9_test028
proc proc
abc9 -lut 4 abc9 -lut 4
select -assert-count 1 t:$lut r:LUT=1 r:WIDTH=1 %i %i select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i
select -assert-count 1 t:unknown select -assert-count 1 t:unknown
select -assert-none t:$lut t:unknown %% t: %D select -assert-none t:$lut t:unknown %% t: %D