mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-13 04:28:18 +00:00
Further improve extract_fa (seems to be fully functional now)
This commit is contained in:
parent
0bf612506c
commit
382cc90c65
|
@ -54,12 +54,26 @@ struct ExtractFaWorker
|
||||||
dict<SigBit, Cell*> driver;
|
dict<SigBit, Cell*> driver;
|
||||||
pool<SigBit> handled_bits;
|
pool<SigBit> handled_bits;
|
||||||
|
|
||||||
|
const int xor2_func = 0x6, xnor2_func = 0x9;
|
||||||
|
const int xor3_func = 0x96, xnor3_func = 0x69;
|
||||||
|
|
||||||
pool<tuple<SigBit, SigBit>> xorxnor2;
|
pool<tuple<SigBit, SigBit>> xorxnor2;
|
||||||
pool<tuple<SigBit, SigBit, SigBit>> xorxnor3;
|
pool<tuple<SigBit, SigBit, SigBit>> xorxnor3;
|
||||||
|
|
||||||
dict<tuple<SigBit, SigBit>, dict<int, pool<SigBit>>> func2;
|
dict<tuple<SigBit, SigBit>, dict<int, pool<SigBit>>> func2;
|
||||||
dict<tuple<SigBit, SigBit, SigBit>, dict<int, pool<SigBit>>> func3;
|
dict<tuple<SigBit, SigBit, SigBit>, dict<int, pool<SigBit>>> func3;
|
||||||
|
|
||||||
|
struct func2_and_info_t {
|
||||||
|
bool inv_a, inv_b, inv_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct func3_maj_info_t {
|
||||||
|
bool inv_a, inv_b, inv_c, inv_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
dict<int, func2_and_info_t> func2_and_info;
|
||||||
|
dict<int, func3_maj_info_t> func3_maj_info;
|
||||||
|
|
||||||
ExtractFaWorker(const ExtractFaConfig &config, Module *module) :
|
ExtractFaWorker(const ExtractFaConfig &config, Module *module) :
|
||||||
config(config), module(module), ce(module), sigmap(ce.assign_map)
|
config(config), module(module), ce(module), sigmap(ce.assign_map)
|
||||||
{
|
{
|
||||||
|
@ -74,11 +88,68 @@ struct ExtractFaWorker
|
||||||
driver[y] = cell;
|
driver[y] = cell;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int ia = 0; ia < 2; ia++)
|
||||||
|
for (int ib = 0; ib < 2; ib++)
|
||||||
|
{
|
||||||
|
func2_and_info_t f2i;
|
||||||
|
|
||||||
|
f2i.inv_a = ia;
|
||||||
|
f2i.inv_b = ib;
|
||||||
|
f2i.inv_y = false;
|
||||||
|
|
||||||
|
int func = 0;
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
bool a = (i & 1) ? !f2i.inv_a : f2i.inv_a;
|
||||||
|
bool b = (i & 2) ? !f2i.inv_b : f2i.inv_b;
|
||||||
|
if (a && b) func |= 1 << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert(func2_and_info.count(func) == 0);
|
||||||
|
func2_and_info[func] = f2i;
|
||||||
|
|
||||||
|
f2i.inv_y = true;
|
||||||
|
func ^= 15;
|
||||||
|
|
||||||
|
log_assert(func2_and_info.count(func) == 0);
|
||||||
|
func2_and_info[func] = f2i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int ia = 0; ia < 2; ia++)
|
||||||
|
for (int ib = 0; ib < 2; ib++)
|
||||||
|
for (int ic = 0; ic < 2; ic++)
|
||||||
|
{
|
||||||
|
func3_maj_info_t f3i;
|
||||||
|
|
||||||
|
f3i.inv_a = ia;
|
||||||
|
f3i.inv_b = ib;
|
||||||
|
f3i.inv_c = ic;
|
||||||
|
f3i.inv_y = false;
|
||||||
|
|
||||||
|
int func = 0;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
bool a = (i & 1) ? !f3i.inv_a : f3i.inv_a;
|
||||||
|
bool b = (i & 2) ? !f3i.inv_b : f3i.inv_b;
|
||||||
|
bool c = (i & 4) ? !f3i.inv_c : f3i.inv_c;
|
||||||
|
if ((a && b) || (a && c) || (b &&c)) func |= 1 << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert(func3_maj_info.count(func) == 0);
|
||||||
|
func3_maj_info[func] = f3i;
|
||||||
|
|
||||||
|
// f3i.inv_y = true;
|
||||||
|
// func ^= 255;
|
||||||
|
|
||||||
|
// log_assert(func3_maj_info.count(func) == 0);
|
||||||
|
// func3_maj_info[func] = f3i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_partition(SigBit root, pool<SigBit> &leaves)
|
void check_partition(SigBit root, pool<SigBit> &leaves)
|
||||||
{
|
{
|
||||||
if (GetSize(leaves) == 2)
|
if (config.enable_ha && GetSize(leaves) == 2)
|
||||||
{
|
{
|
||||||
leaves.sort();
|
leaves.sort();
|
||||||
|
|
||||||
|
@ -108,13 +179,13 @@ struct ExtractFaWorker
|
||||||
|
|
||||||
// log("%04d %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(root));
|
// log("%04d %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(root));
|
||||||
|
|
||||||
if (func == 0x6 || func == 0x9)
|
if (func == xor2_func || func == xnor2_func)
|
||||||
xorxnor2.insert(tuple<SigBit, SigBit>(A, B));
|
xorxnor2.insert(tuple<SigBit, SigBit>(A, B));
|
||||||
|
|
||||||
func2[tuple<SigBit, SigBit>(A, B)][func].insert(root);
|
func2[tuple<SigBit, SigBit>(A, B)][func].insert(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetSize(leaves) == 3)
|
if (config.enable_fa && GetSize(leaves) == 3)
|
||||||
{
|
{
|
||||||
leaves.sort();
|
leaves.sort();
|
||||||
|
|
||||||
|
@ -147,7 +218,7 @@ struct ExtractFaWorker
|
||||||
|
|
||||||
// log("%08d %s %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(C), log_signal(root));
|
// log("%08d %s %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(C), log_signal(root));
|
||||||
|
|
||||||
if (func == 0x69 || func == 0x96)
|
if (func == xor3_func || func == xnor3_func)
|
||||||
xorxnor3.insert(tuple<SigBit, SigBit, SigBit>(A, B, C));
|
xorxnor3.insert(tuple<SigBit, SigBit, SigBit>(A, B, C));
|
||||||
|
|
||||||
func3[tuple<SigBit, SigBit, SigBit>(A, B, C)][func].insert(root);
|
func3[tuple<SigBit, SigBit, SigBit>(A, B, C)][func].insert(root);
|
||||||
|
@ -159,6 +230,11 @@ struct ExtractFaWorker
|
||||||
if (cache.count(leaves))
|
if (cache.count(leaves))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// log("%*s[%d] %s:", 20-maxdepth, "", maxdepth, log_signal(root));
|
||||||
|
// for (auto bit : leaves)
|
||||||
|
// log(" %s", log_signal(bit));
|
||||||
|
// log("\n");
|
||||||
|
|
||||||
cache.insert(leaves);
|
cache.insert(leaves);
|
||||||
check_partition(root, leaves);
|
check_partition(root, leaves);
|
||||||
|
|
||||||
|
@ -186,15 +262,29 @@ struct ExtractFaWorker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
module->connect(bit, new_driver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
|
log("Extracting full/half adders from %s:\n", log_id(module));
|
||||||
|
|
||||||
for (auto it : driver)
|
for (auto it : driver)
|
||||||
{
|
{
|
||||||
|
if (it.second->type.in("$_BUF_", "$_NOT_"))
|
||||||
|
continue;
|
||||||
|
|
||||||
SigBit root = it.first;
|
SigBit root = it.first;
|
||||||
pool<SigBit> leaves = { root };
|
pool<SigBit> leaves = { root };
|
||||||
pool<pool<SigBit>> cache;
|
pool<pool<SigBit>> cache;
|
||||||
|
|
||||||
find_partitions(root, leaves, cache, 5, 10);
|
find_partitions(root, leaves, cache, 20, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &key : xorxnor3)
|
for (auto &key : xorxnor3)
|
||||||
|
@ -203,14 +293,81 @@ struct ExtractFaWorker
|
||||||
SigBit B = get<1>(key);
|
SigBit B = get<1>(key);
|
||||||
SigBit C = get<2>(key);
|
SigBit C = get<2>(key);
|
||||||
|
|
||||||
log("3-Input XOR/XNOR %s %s %s:\n", log_signal(A), log_signal(B), log_signal(C));
|
log(" 3-Input XOR/XNOR %s %s %s:\n", log_signal(A), log_signal(B), log_signal(C));
|
||||||
|
|
||||||
for (auto &it : func3.at(key)) {
|
for (auto &it : func3.at(key))
|
||||||
log(" %08d ->", bindec(it.first));
|
{
|
||||||
|
if (it.first != xor3_func && it.first != xnor3_func)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log(" %08d ->", bindec(it.first));
|
||||||
for (auto bit : it.second)
|
for (auto bit : it.second)
|
||||||
log(" %s", log_signal(bit));
|
log(" %s", log_signal(bit));
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto &it : func3_maj_info)
|
||||||
|
{
|
||||||
|
int func = it.first;
|
||||||
|
auto f3i = it.second;
|
||||||
|
|
||||||
|
if (func3.at(key).count(func) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (func3.at(key).count(xor3_func) == 0 && func3.at(key).count(xnor3_func) != 0) {
|
||||||
|
f3i.inv_a = !f3i.inv_a;
|
||||||
|
f3i.inv_b = !f3i.inv_b;
|
||||||
|
f3i.inv_c = !f3i.inv_c;
|
||||||
|
f3i.inv_y = !f3i.inv_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!f3i.inv_a && !f3i.inv_b && !f3i.inv_c && !f3i.inv_y) {
|
||||||
|
log(" Majority without inversions:\n");
|
||||||
|
} else {
|
||||||
|
log(" Majority with inverted");
|
||||||
|
if (f3i.inv_a) log(" A");
|
||||||
|
if (f3i.inv_b) log(" B");
|
||||||
|
if (f3i.inv_c) log(" C");
|
||||||
|
if (f3i.inv_y) log(" Y");
|
||||||
|
log(":\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
log(" %08d ->", bindec(func));
|
||||||
|
for (auto bit : func3.at(key).at(func))
|
||||||
|
log(" %s", log_signal(bit));
|
||||||
|
log("\n");
|
||||||
|
|
||||||
|
Cell *cell = module->addCell(NEW_ID, "$fa");
|
||||||
|
cell->setParam("\\WIDTH", 1);
|
||||||
|
|
||||||
|
log(" Created $fa cell %s.\n", log_id(cell));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
SigBit X = module->addWire(NEW_ID);
|
||||||
|
SigBit Y = module->addWire(NEW_ID);
|
||||||
|
|
||||||
|
cell->setPort("\\X", X);
|
||||||
|
cell->setPort("\\Y", Y);
|
||||||
|
|
||||||
|
if (func3.at(key).count(xor3_func)) {
|
||||||
|
for (auto bit : func3.at(key).at(xor3_func))
|
||||||
|
assign_new_driver(bit, Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (func3.at(key).count(xnor3_func)) {
|
||||||
|
SigBit YN = module->NotGate(NEW_ID, Y);
|
||||||
|
for (auto bit : func3.at(key).at(xnor3_func))
|
||||||
|
assign_new_driver(bit, YN);
|
||||||
|
}
|
||||||
|
|
||||||
|
SigBit XX = f3i.inv_y ? module->NotGate(NEW_ID, X) : X;
|
||||||
|
|
||||||
|
for (auto bit : func3.at(key).at(func))
|
||||||
|
assign_new_driver(bit, XX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &key : xorxnor2)
|
for (auto &key : xorxnor2)
|
||||||
|
@ -218,14 +375,73 @@ struct ExtractFaWorker
|
||||||
SigBit A = get<0>(key);
|
SigBit A = get<0>(key);
|
||||||
SigBit B = get<1>(key);
|
SigBit B = get<1>(key);
|
||||||
|
|
||||||
log("2-Input XOR/XNOR %s %s:\n", log_signal(A), log_signal(B));
|
log(" 2-Input XOR/XNOR %s %s:\n", log_signal(A), log_signal(B));
|
||||||
|
|
||||||
|
for (auto &it : func2.at(key))
|
||||||
|
{
|
||||||
|
if (it.first != xor2_func && it.first != xnor2_func)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (auto &it : func2.at(key)) {
|
|
||||||
log(" %04d ->", bindec(it.first));
|
log(" %04d ->", bindec(it.first));
|
||||||
for (auto bit : it.second)
|
for (auto bit : it.second)
|
||||||
log(" %s", log_signal(bit));
|
log(" %s", log_signal(bit));
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto &it : func2_and_info)
|
||||||
|
{
|
||||||
|
int func = it.first;
|
||||||
|
auto &f2i = it.second;
|
||||||
|
|
||||||
|
if (func2.at(key).count(func) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!f2i.inv_a && !f2i.inv_b && !f2i.inv_y) {
|
||||||
|
log(" AND without inversions:\n");
|
||||||
|
} else {
|
||||||
|
log(" AND with inverted");
|
||||||
|
if (f2i.inv_a) log(" A");
|
||||||
|
if (f2i.inv_b) log(" B");
|
||||||
|
if (f2i.inv_y) log(" Y");
|
||||||
|
log(":\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
log(" %04d ->", bindec(func));
|
||||||
|
for (auto bit : func2.at(key).at(func))
|
||||||
|
log(" %s", log_signal(bit));
|
||||||
|
log("\n");
|
||||||
|
|
||||||
|
Cell *cell = module->addCell(NEW_ID, "$fa");
|
||||||
|
cell->setParam("\\WIDTH", 1);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
SigBit X = module->addWire(NEW_ID);
|
||||||
|
SigBit Y = module->addWire(NEW_ID);
|
||||||
|
|
||||||
|
cell->setPort("\\X", X);
|
||||||
|
cell->setPort("\\Y", Y);
|
||||||
|
|
||||||
|
if (func2.at(key).count(xor2_func)) {
|
||||||
|
for (auto bit : func2.at(key).at(xor2_func))
|
||||||
|
assign_new_driver(bit, Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (func2.at(key).count(xnor2_func)) {
|
||||||
|
SigBit YN = module->NotGate(NEW_ID, Y);
|
||||||
|
for (auto bit : func2.at(key).at(xnor2_func))
|
||||||
|
assign_new_driver(bit, YN);
|
||||||
|
}
|
||||||
|
|
||||||
|
SigBit XX = f2i.inv_y ? module->NotGate(NEW_ID, X) : X;
|
||||||
|
|
||||||
|
for (auto bit : func2.at(key).at(func))
|
||||||
|
assign_new_driver(bit, XX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue