{
bool enable_fa = false;
bool enable_ha = false;
+ bool verbose = false;
+ int maxdepth = 20;
+ int maxbreadth = 6;
};
// http://svn.clifford.at/handicraft/2016/bindec/bindec.c
dict<tuple<SigBit, SigBit>, dict<int, pool<SigBit>>> func2;
dict<tuple<SigBit, SigBit, SigBit>, dict<int, pool<SigBit>>> func3;
+ int count_func2;
+ int count_func3;
+
struct func2_and_info_t {
bool inv_a, inv_b, inv_y;
};
{
for (auto cell : module->selected_cells())
{
- if (cell->type.in( "$_BUF_", "$_NOT_", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_",
- "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_",
- "$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
+ if (cell->type.in( ID($_BUF_), ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_),
+ ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($_MUX_), ID($_NMUX_),
+ ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_)))
{
- SigBit y = sigmap(SigBit(cell->getPort("\\Y")));
+ SigBit y = sigmap(SigBit(cell->getPort(ID::Y)));
log_assert(driver.count(y) == 0);
driver[y] = cell;
}
SigSpec sig = root;
- if (!ce.eval(sig))
- log_abort();
+ if (!ce.eval(sig)) {
+ ce.pop();
+ return;
+ }
if (sig == State::S1)
func |= 1 << i;
if (func == xor2_func || func == xnor2_func)
xorxnor2.insert(tuple<SigBit, SigBit>(A, B));
+ count_func2++;
func2[tuple<SigBit, SigBit>(A, B)][func].insert(root);
}
SigSpec sig = root;
- if (!ce.eval(sig))
- log_abort();
+ if (!ce.eval(sig)) {
+ ce.pop();
+ return;
+ }
if (sig == State::S1)
func |= 1 << i;
if (func == xor3_func || func == xnor3_func)
xorxnor3.insert(tuple<SigBit, SigBit, SigBit>(A, B, C));
+ count_func3++;
func3[tuple<SigBit, SigBit, SigBit>(A, B, C)][func].insert(root);
}
}
pool<SigBit> new_leaves = leaves;
new_leaves.erase(bit);
- if (cell->hasPort("\\A")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\A"))));
- if (cell->hasPort("\\B")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\B"))));
- if (cell->hasPort("\\C")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\C"))));
- if (cell->hasPort("\\D")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\D"))));
+ for (auto port : {ID::A, ID::B, ID(C), ID(D)}) {
+ if (!cell->hasPort(port))
+ continue;
+ auto bit = sigmap(SigBit(cell->getPort(port)));
+ if (!bit.wire)
+ continue;
+ new_leaves.insert(bit);
+ }
if (GetSize(new_leaves) > maxbreadth)
continue;
void assign_new_driver(SigBit bit, SigBit new_driver)
{
Cell *cell = driver.at(bit);
- if (sigmap(cell->getPort("\\Y")) == bit) {
- cell->setPort("\\Y", module->addWire(NEW_ID));
+ if (sigmap(cell->getPort(ID::Y)) == bit) {
+ cell->setPort(ID::Y, module->addWire(NEW_ID));
module->connect(bit, new_driver);
}
}
for (auto it : driver)
{
- if (it.second->type.in("$_BUF_", "$_NOT_"))
+ if (it.second->type.in(ID($_BUF_), ID($_NOT_)))
continue;
SigBit root = it.first;
pool<SigBit> leaves = { root };
pool<pool<SigBit>> cache;
- find_partitions(root, leaves, cache, 20, 10);
+ if (config.verbose)
+ log(" checking %s\n", log_signal(it.first));
+
+ count_func2 = 0;
+ count_func3 = 0;
+
+ find_partitions(root, leaves, cache, config.maxdepth, config.maxbreadth);
+
+ if (config.verbose && count_func2 > 0)
+ log(" extracted %d two-input functions\n", count_func2);
+
+ if (config.verbose && count_func3 > 0)
+ log(" extracted %d three-input functions\n", count_func3);
}
for (auto &key : xorxnor3)
log("\n");
}
+ dict<int, tuple<SigBit, SigBit, Cell*>> facache;
+
for (auto &it : func3_maj_info)
{
int func = it.first;
log(" %s", log_signal(bit));
log("\n");
- Cell *cell = module->addCell(NEW_ID, "$fa");
- cell->setParam("\\WIDTH", 1);
+ int fakey = 0;
+ if (f3i.inv_a) fakey |= 1;
+ if (f3i.inv_b) fakey |= 2;
+ if (f3i.inv_c) fakey |= 4;
+
+ int fakey_inv = fakey ^ 7;
+ bool invert_xy = false;
+ SigBit X, Y;
+
+ if (facache.count(fakey))
+ {
+ auto &fa = facache.at(fakey);
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ if (facache.count(fakey_inv))
+ {
+ auto &fa = facache.at(fakey_inv);
+ invert_xy = true;
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ {
+ Cell *cell = module->addCell(NEW_ID, ID($fa));
+ cell->setParam(ID(WIDTH), 1);
+
+ log(" Created $fa cell %s.\n", log_id(cell));
- log(" Created $fa cell %s.\n", log_id(cell));
+ cell->setPort(ID::A, f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
+ cell->setPort(ID::B, f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
+ cell->setPort(ID(C), f3i.inv_c ? module->NotGate(NEW_ID, C) : C);
- cell->setPort("\\A", f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
- cell->setPort("\\B", f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
- cell->setPort("\\C", f3i.inv_c ? module->NotGate(NEW_ID, C) : C);
+ X = module->addWire(NEW_ID);
+ Y = module->addWire(NEW_ID);
- SigBit X = module->addWire(NEW_ID);
- SigBit Y = module->addWire(NEW_ID);
+ cell->setPort(ID(X), X);
+ cell->setPort(ID::Y, Y);
- cell->setPort("\\X", X);
- cell->setPort("\\Y", Y);
+ facache[fakey] = make_tuple(X, Y, cell);
+ }
if (func3.at(key).count(xor3_func)) {
+ SigBit YY = invert_xy ? module->NotGate(NEW_ID, Y) : Y;
for (auto bit : func3.at(key).at(xor3_func))
- assign_new_driver(bit, Y);
+ assign_new_driver(bit, YY);
}
if (func3.at(key).count(xnor3_func)) {
- SigBit YN = module->NotGate(NEW_ID, Y);
+ SigBit YY = invert_xy ? Y : module->NotGate(NEW_ID, Y);
for (auto bit : func3.at(key).at(xnor3_func))
- assign_new_driver(bit, YN);
+ assign_new_driver(bit, YY);
}
- SigBit XX = f3i.inv_y ? module->NotGate(NEW_ID, X) : X;
+ SigBit XX = invert_xy != f3i.inv_y ? module->NotGate(NEW_ID, X) : X;
for (auto bit : func3.at(key).at(func))
assign_new_driver(bit, XX);
log("\n");
}
+ dict<int, tuple<SigBit, SigBit, Cell*>> facache;
+
for (auto &it : func2_and_info)
{
int func = it.first;
log(" %s", log_signal(bit));
log("\n");
- Cell *cell = module->addCell(NEW_ID, "$fa");
- cell->setParam("\\WIDTH", 1);
+ int fakey = 0;
+ if (f2i.inv_a) fakey |= 1;
+ if (f2i.inv_b) fakey |= 2;
+
+ int fakey_inv = fakey ^ 3;
+ bool invert_xy = false;
+ SigBit X, Y;
+
+ if (facache.count(fakey))
+ {
+ auto &fa = facache.at(fakey);
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ if (facache.count(fakey_inv))
+ {
+ auto &fa = facache.at(fakey_inv);
+ invert_xy = true;
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ {
+ Cell *cell = module->addCell(NEW_ID, ID($fa));
+ cell->setParam(ID(WIDTH), 1);
- log(" Created $fa cell %s.\n", log_id(cell));
+ log(" Created $fa cell %s.\n", log_id(cell));
- cell->setPort("\\A", f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
- cell->setPort("\\B", f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
- cell->setPort("\\C", State::S0);
+ cell->setPort(ID::A, f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
+ cell->setPort(ID::B, f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
+ cell->setPort(ID(C), State::S0);
- SigBit X = module->addWire(NEW_ID);
- SigBit Y = module->addWire(NEW_ID);
+ X = module->addWire(NEW_ID);
+ Y = module->addWire(NEW_ID);
- cell->setPort("\\X", X);
- cell->setPort("\\Y", Y);
+ cell->setPort(ID(X), X);
+ cell->setPort(ID::Y, Y);
+ }
if (func2.at(key).count(xor2_func)) {
+ SigBit YY = invert_xy || (f2i.inv_a && !f2i.inv_b) || (!f2i.inv_a && f2i.inv_b) ? module->NotGate(NEW_ID, Y) : Y;
for (auto bit : func2.at(key).at(xor2_func))
- assign_new_driver(bit, Y);
+ assign_new_driver(bit, YY);
}
if (func2.at(key).count(xnor2_func)) {
- SigBit YN = module->NotGate(NEW_ID, Y);
+ SigBit YY = invert_xy || (f2i.inv_a && !f2i.inv_b) || (!f2i.inv_a && f2i.inv_b) ? Y : module->NotGate(NEW_ID, Y);
for (auto bit : func2.at(key).at(xnor2_func))
- assign_new_driver(bit, YN);
+ assign_new_driver(bit, YY);
}
- SigBit XX = f2i.inv_y ? module->NotGate(NEW_ID, X) : X;
+ SigBit XX = invert_xy != f2i.inv_y ? module->NotGate(NEW_ID, X) : X;
for (auto bit : func2.at(key).at(func))
assign_new_driver(bit, XX);
struct ExtractFaPass : public Pass {
ExtractFaPass() : Pass("extract_fa", "find and extract full/half adders") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" Enable cell types (fa=full adder, ha=half adder)\n");
log(" All types are enabled if none of this options is used\n");
log("\n");
+ log(" -d <int>\n");
+ log(" Set maximum depth for extracted logic cones (default=20)\n");
+ log("\n");
+ log(" -b <int>\n");
+ log(" Set maximum breadth for extracted logic cones (default=6)\n");
+ log("\n");
+ log(" -v\n");
+ log(" Verbose output\n");
+ log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
ExtractFaConfig config;
config.enable_ha = true;
continue;
}
+ if (args[argidx] == "-v") {
+ config.verbose = true;
+ continue;
+ }
+ if (args[argidx] == "-d" && argidx+2 < args.size()) {
+ config.maxdepth = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-b" && argidx+2 < args.size()) {
+ config.maxbreadth = atoi(args[++argidx].c_str());
+ continue;
+ }
break;
}
extra_args(args, argidx, design);