mirror of https://github.com/YosysHQ/yosys.git
Compare commits
7 Commits
afc8de73a8
...
fabeaf554b
| Author | SHA1 | Date |
|---|---|---|
|
|
fabeaf554b | |
|
|
a2aeef6c96 | |
|
|
3d5b1e0a93 | |
|
|
5b2252ffd8 | |
|
|
0f770285f3 | |
|
|
f8341affe3 | |
|
|
c87c6a97bc |
4
Makefile
4
Makefile
|
|
@ -161,7 +161,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.58+132
|
||||
YOSYS_VER := 0.58+138
|
||||
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
||||
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
|
||||
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
|
||||
|
|
@ -366,7 +366,7 @@ CXXFLAGS += -I$(PYBIND11_INCLUDE) -DYOSYS_ENABLE_PYTHON
|
|||
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DYOSYS_ENABLE_PYTHON
|
||||
|
||||
OBJS += $(PY_WRAPPER_FILE).o
|
||||
PY_GEN_SCRIPT = pyosys/generator.py
|
||||
PY_GEN_SCRIPT = $(YOSYS_SRC)/pyosys/generator.py
|
||||
PY_WRAP_INCLUDES := $(shell $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes)
|
||||
endif # ENABLE_PYOSYS
|
||||
|
||||
|
|
|
|||
|
|
@ -117,15 +117,6 @@ struct gate_t
|
|||
std::string bit_str;
|
||||
};
|
||||
|
||||
bool map_mux4;
|
||||
bool map_mux8;
|
||||
bool map_mux16;
|
||||
|
||||
bool markgroups;
|
||||
|
||||
pool<std::string> enabled_gates;
|
||||
bool cmos_cost;
|
||||
|
||||
struct AbcConfig
|
||||
{
|
||||
std::string global_tempdir_name;
|
||||
|
|
@ -146,6 +137,12 @@ struct AbcConfig
|
|||
bool show_tempdir = false;
|
||||
bool sop_mode = false;
|
||||
bool abc_dress = false;
|
||||
bool map_mux4 = false;
|
||||
bool map_mux8 = false;
|
||||
bool map_mux16 = false;
|
||||
bool markgroups = false;
|
||||
pool<std::string> enabled_gates;
|
||||
bool cmos_cost = false;
|
||||
};
|
||||
|
||||
struct AbcSigVal {
|
||||
|
|
@ -1382,7 +1379,7 @@ void emit_global_input_files(const AbcConfig &config)
|
|||
fprintf(f, "%d %d.00 1.00\n", i+1, config.lut_costs.at(i));
|
||||
fclose(f);
|
||||
} else {
|
||||
auto &cell_cost = cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost();
|
||||
auto &cell_cost = config.cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost();
|
||||
|
||||
std::string buffer = stringf("%s/stdcells.genlib", config.global_tempdir_name.c_str());
|
||||
FILE *f = fopen(buffer.c_str(), "wt");
|
||||
|
|
@ -1392,39 +1389,39 @@ void emit_global_input_files(const AbcConfig &config)
|
|||
fprintf(f, "GATE ONE 1 Y=CONST1;\n");
|
||||
fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_BUF_)));
|
||||
fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NOT_)));
|
||||
if (enabled_gates.count("AND"))
|
||||
if (config.enabled_gates.count("AND"))
|
||||
fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_AND_)));
|
||||
if (enabled_gates.count("NAND"))
|
||||
if (config.enabled_gates.count("NAND"))
|
||||
fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NAND_)));
|
||||
if (enabled_gates.count("OR"))
|
||||
if (config.enabled_gates.count("OR"))
|
||||
fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_OR_)));
|
||||
if (enabled_gates.count("NOR"))
|
||||
if (config.enabled_gates.count("NOR"))
|
||||
fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NOR_)));
|
||||
if (enabled_gates.count("XOR"))
|
||||
if (config.enabled_gates.count("XOR"))
|
||||
fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_XOR_)));
|
||||
if (enabled_gates.count("XNOR"))
|
||||
if (config.enabled_gates.count("XNOR"))
|
||||
fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_XNOR_)));
|
||||
if (enabled_gates.count("ANDNOT"))
|
||||
if (config.enabled_gates.count("ANDNOT"))
|
||||
fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_ANDNOT_)));
|
||||
if (enabled_gates.count("ORNOT"))
|
||||
if (config.enabled_gates.count("ORNOT"))
|
||||
fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_ORNOT_)));
|
||||
if (enabled_gates.count("AOI3"))
|
||||
if (config.enabled_gates.count("AOI3"))
|
||||
fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_AOI3_)));
|
||||
if (enabled_gates.count("OAI3"))
|
||||
if (config.enabled_gates.count("OAI3"))
|
||||
fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_OAI3_)));
|
||||
if (enabled_gates.count("AOI4"))
|
||||
if (config.enabled_gates.count("AOI4"))
|
||||
fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_AOI4_)));
|
||||
if (enabled_gates.count("OAI4"))
|
||||
if (config.enabled_gates.count("OAI4"))
|
||||
fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_OAI4_)));
|
||||
if (enabled_gates.count("MUX"))
|
||||
if (config.enabled_gates.count("MUX"))
|
||||
fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_MUX_)));
|
||||
if (enabled_gates.count("NMUX"))
|
||||
if (config.enabled_gates.count("NMUX"))
|
||||
fprintf(f, "GATE NMUX %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_NMUX_)));
|
||||
if (map_mux4)
|
||||
if (config.map_mux4)
|
||||
fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*cell_cost.at(ID($_MUX_)));
|
||||
if (map_mux8)
|
||||
if (config.map_mux8)
|
||||
fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost.at(ID($_MUX_)));
|
||||
if (map_mux16)
|
||||
if (config.map_mux16)
|
||||
fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost.at(ID($_MUX_)));
|
||||
fclose(f);
|
||||
}
|
||||
|
|
@ -1456,6 +1453,7 @@ void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL
|
|||
RTLIL::Module *mapped_mod = mapped_design->module(ID(netlist));
|
||||
if (mapped_mod == nullptr)
|
||||
log_error("ABC output file does not contain a module `netlist'.\n");
|
||||
bool markgroups = run_abc.config.markgroups;
|
||||
for (auto w : mapped_mod->wires()) {
|
||||
RTLIL::Wire *orig_wire = nullptr;
|
||||
RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire));
|
||||
|
|
@ -1998,9 +1996,9 @@ struct AbcPass : public Pass {
|
|||
lut_arg = design->scratchpad_get_string("abc.lut", lut_arg);
|
||||
luts_arg = design->scratchpad_get_string("abc.luts", luts_arg);
|
||||
config.sop_mode = design->scratchpad_get_bool("abc.sop", false);
|
||||
map_mux4 = design->scratchpad_get_bool("abc.mux4", map_mux4);
|
||||
map_mux8 = design->scratchpad_get_bool("abc.mux8", map_mux8);
|
||||
map_mux16 = design->scratchpad_get_bool("abc.mux16", map_mux16);
|
||||
config.map_mux4 = design->scratchpad_get_bool("abc.mux4", false);
|
||||
config.map_mux8 = design->scratchpad_get_bool("abc.mux8", false);
|
||||
config.map_mux16 = design->scratchpad_get_bool("abc.mux16", false);
|
||||
config.abc_dress = design->scratchpad_get_bool("abc.dress", false);
|
||||
g_arg = design->scratchpad_get_string("abc.g", g_arg);
|
||||
|
||||
|
|
@ -2014,7 +2012,7 @@ struct AbcPass : public Pass {
|
|||
config.keepff = design->scratchpad_get_bool("abc.keepff", false);
|
||||
config.cleanup = !design->scratchpad_get_bool("abc.nocleanup", false);
|
||||
config.show_tempdir = design->scratchpad_get_bool("abc.showtmp", false);
|
||||
markgroups = design->scratchpad_get_bool("abc.markgroups", markgroups);
|
||||
config.markgroups = design->scratchpad_get_bool("abc.markgroups", false);
|
||||
|
||||
if (config.cleanup)
|
||||
config.global_tempdir_name = get_base_tmpdir() + "/";
|
||||
|
|
@ -2094,15 +2092,15 @@ struct AbcPass : public Pass {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-mux4") {
|
||||
map_mux4 = true;
|
||||
config.map_mux4 = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-mux8") {
|
||||
map_mux8 = true;
|
||||
config.map_mux8 = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-mux16") {
|
||||
map_mux16 = true;
|
||||
config.map_mux16 = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dress") {
|
||||
|
|
@ -2143,7 +2141,7 @@ struct AbcPass : public Pass {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-markgroups") {
|
||||
markgroups = true;
|
||||
config.markgroups = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
|
@ -2236,14 +2234,14 @@ struct AbcPass : public Pass {
|
|||
}
|
||||
if (g == "cmos2") {
|
||||
if (!remove_gates)
|
||||
cmos_cost = true;
|
||||
config.cmos_cost = true;
|
||||
gate_list.push_back("NAND");
|
||||
gate_list.push_back("NOR");
|
||||
goto ok_alias;
|
||||
}
|
||||
if (g == "cmos3") {
|
||||
if (!remove_gates)
|
||||
cmos_cost = true;
|
||||
config.cmos_cost = true;
|
||||
gate_list.push_back("NAND");
|
||||
gate_list.push_back("NOR");
|
||||
gate_list.push_back("AOI3");
|
||||
|
|
@ -2252,7 +2250,7 @@ struct AbcPass : public Pass {
|
|||
}
|
||||
if (g == "cmos4") {
|
||||
if (!remove_gates)
|
||||
cmos_cost = true;
|
||||
config.cmos_cost = true;
|
||||
gate_list.push_back("NAND");
|
||||
gate_list.push_back("NOR");
|
||||
gate_list.push_back("AOI3");
|
||||
|
|
@ -2263,7 +2261,7 @@ struct AbcPass : public Pass {
|
|||
}
|
||||
if (g == "cmos") {
|
||||
if (!remove_gates)
|
||||
cmos_cost = true;
|
||||
config.cmos_cost = true;
|
||||
gate_list.push_back("NAND");
|
||||
gate_list.push_back("NOR");
|
||||
gate_list.push_back("AOI3");
|
||||
|
|
@ -2322,9 +2320,9 @@ struct AbcPass : public Pass {
|
|||
ok_alias:
|
||||
for (auto gate : gate_list) {
|
||||
if (remove_gates)
|
||||
enabled_gates.erase(gate);
|
||||
config.enabled_gates.erase(gate);
|
||||
else
|
||||
enabled_gates.insert(gate);
|
||||
config.enabled_gates.insert(gate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2334,21 +2332,21 @@ struct AbcPass : public Pass {
|
|||
if (!config.constr_file.empty() && (config.liberty_files.empty() && config.genlib_files.empty()))
|
||||
log_cmd_error("Got -constr but no -liberty/-genlib!\n");
|
||||
|
||||
if (enabled_gates.empty()) {
|
||||
enabled_gates.insert("AND");
|
||||
enabled_gates.insert("NAND");
|
||||
enabled_gates.insert("OR");
|
||||
enabled_gates.insert("NOR");
|
||||
enabled_gates.insert("XOR");
|
||||
enabled_gates.insert("XNOR");
|
||||
enabled_gates.insert("ANDNOT");
|
||||
enabled_gates.insert("ORNOT");
|
||||
// enabled_gates.insert("AOI3");
|
||||
// enabled_gates.insert("OAI3");
|
||||
// enabled_gates.insert("AOI4");
|
||||
// enabled_gates.insert("OAI4");
|
||||
enabled_gates.insert("MUX");
|
||||
// enabled_gates.insert("NMUX");
|
||||
if (config.enabled_gates.empty()) {
|
||||
config.enabled_gates.insert("AND");
|
||||
config.enabled_gates.insert("NAND");
|
||||
config.enabled_gates.insert("OR");
|
||||
config.enabled_gates.insert("NOR");
|
||||
config.enabled_gates.insert("XOR");
|
||||
config.enabled_gates.insert("XNOR");
|
||||
config.enabled_gates.insert("ANDNOT");
|
||||
config.enabled_gates.insert("ORNOT");
|
||||
// config.enabled_gates.insert("AOI3");
|
||||
// config.enabled_gates.insert("OAI3");
|
||||
// config.enabled_gates.insert("AOI4");
|
||||
// config.enabled_gates.insert("OAI4");
|
||||
config.enabled_gates.insert("MUX");
|
||||
// config.enabled_gates.insert("NMUX");
|
||||
}
|
||||
|
||||
emit_global_input_files(config);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@
|
|||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "backends/rtlil/rtlil_backend.h"
|
||||
#include "kernel/consteval.h"
|
||||
#include <cstdio>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
|
@ -66,9 +70,6 @@ struct ExtractFaWorker
|
|||
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;
|
||||
};
|
||||
|
|
@ -77,6 +78,26 @@ struct ExtractFaWorker
|
|||
bool inv_a, inv_b, inv_c, inv_y;
|
||||
};
|
||||
|
||||
struct Counters {
|
||||
int count_func2;
|
||||
int count_func3;
|
||||
};
|
||||
|
||||
struct ThreadData {
|
||||
size_t start;
|
||||
size_t end;
|
||||
Counters counters;
|
||||
ExtractFaWorker* instance;
|
||||
std::stringstream log_buffer;
|
||||
std::vector<RTLIL::IdString> ports = {ID::A, ID::B, ID::C, ID::D};
|
||||
pool<tuple<SigBit, SigBit>> tl_xorxnor2;
|
||||
pool<tuple<SigBit, SigBit, SigBit>> tl_xorxnor3;
|
||||
pool<tuple<tuple<SigBit, SigBit>, int, SigBit>> tl_func_2;
|
||||
pool<tuple<tuple<SigBit, SigBit, SigBit>,int, SigBit>> tl_func_3;
|
||||
};
|
||||
|
||||
std::mutex consteval_mtx;
|
||||
|
||||
dict<int, func2_and_info_t> func2_and_info;
|
||||
dict<int, func3_maj_info_t> func3_maj_info;
|
||||
|
||||
|
|
@ -153,7 +174,7 @@ struct ExtractFaWorker
|
|||
}
|
||||
}
|
||||
|
||||
void check_partition(SigBit root, pool<SigBit> &leaves)
|
||||
void check_partition(SigBit root, pool<SigBit> &leaves, ThreadData& data)
|
||||
{
|
||||
if (config.enable_ha && GetSize(leaves) == 2)
|
||||
{
|
||||
|
|
@ -163,35 +184,38 @@ struct ExtractFaWorker
|
|||
SigBit B = SigSpec(leaves)[1];
|
||||
|
||||
int func = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
bool a_value = (i & 1) != 0;
|
||||
bool b_value = (i & 2) != 0;
|
||||
std::lock_guard lock(consteval_mtx);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
bool a_value = (i & 1) != 0;
|
||||
bool b_value = (i & 2) != 0;
|
||||
|
||||
ce.push();
|
||||
ce.set(A, a_value ? State::S1 : State::S0);
|
||||
ce.set(B, b_value ? State::S1 : State::S0);
|
||||
ce.push();
|
||||
ce.set(A, a_value ? State::S1 : State::S0);
|
||||
ce.set(B, b_value ? State::S1 : State::S0);
|
||||
SigSpec sig = root;
|
||||
|
||||
SigSpec sig = root;
|
||||
if (!ce.eval(sig)) {
|
||||
ce.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig == State::S1)
|
||||
func |= 1 << i;
|
||||
|
||||
if (!ce.eval(sig)) {
|
||||
ce.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig == State::S1)
|
||||
func |= 1 << i;
|
||||
|
||||
ce.pop();
|
||||
}
|
||||
|
||||
// log("%04d %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(root));
|
||||
|
||||
if (func == xor2_func || func == xnor2_func)
|
||||
xorxnor2.insert(tuple<SigBit, SigBit>(A, B));
|
||||
data.tl_xorxnor2.insert(tuple<SigBit, SigBit>(A, B));
|
||||
|
||||
count_func2++;
|
||||
func2[tuple<SigBit, SigBit>(A, B)][func].insert(root);
|
||||
data.counters.count_func2++;
|
||||
data.tl_func_2.insert(
|
||||
tuple<tuple<SigBit, SigBit>, int, SigBit>(tuple<SigBit, SigBit>(A, B), func, root)
|
||||
);
|
||||
}
|
||||
|
||||
if (config.enable_fa && GetSize(leaves) == 3)
|
||||
|
|
@ -203,52 +227,70 @@ struct ExtractFaWorker
|
|||
SigBit C = SigSpec(leaves)[2];
|
||||
|
||||
int func = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
bool a_value = (i & 1) != 0;
|
||||
bool b_value = (i & 2) != 0;
|
||||
bool c_value = (i & 4) != 0;
|
||||
std::lock_guard lock(consteval_mtx);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
bool a_value = (i & 1) != 0;
|
||||
bool b_value = (i & 2) != 0;
|
||||
bool c_value = (i & 4) != 0;
|
||||
|
||||
ce.push();
|
||||
ce.set(A, a_value ? State::S1 : State::S0);
|
||||
ce.set(B, b_value ? State::S1 : State::S0);
|
||||
ce.set(C, c_value ? State::S1 : State::S0);
|
||||
ce.push();
|
||||
ce.set(A, a_value ? State::S1 : State::S0);
|
||||
ce.set(B, b_value ? State::S1 : State::S0);
|
||||
ce.set(C, c_value ? State::S1 : State::S0);
|
||||
SigSpec sig = root;
|
||||
|
||||
SigSpec sig = root;
|
||||
if (!ce.eval(sig)) {
|
||||
ce.pop();
|
||||
return;
|
||||
}
|
||||
if (sig == State::S1)
|
||||
func |= 1 << i;
|
||||
|
||||
if (!ce.eval(sig)) {
|
||||
ce.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig == State::S1)
|
||||
func |= 1 << i;
|
||||
|
||||
ce.pop();
|
||||
}
|
||||
|
||||
// log("%08d %s %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(C), log_signal(root));
|
||||
|
||||
if (func == xor3_func || func == xnor3_func)
|
||||
xorxnor3.insert(tuple<SigBit, SigBit, SigBit>(A, B, C));
|
||||
data.tl_xorxnor3.insert(tuple<SigBit, SigBit, SigBit>(A, B, C));
|
||||
|
||||
count_func3++;
|
||||
func3[tuple<SigBit, SigBit, SigBit>(A, B, C)][func].insert(root);
|
||||
data.counters.count_func3++;
|
||||
data.tl_func_3.insert(
|
||||
tuple<tuple<SigBit, SigBit, SigBit>, int, SigBit>(tuple<SigBit, SigBit, SigBit>(A, B, C), func, root)
|
||||
);
|
||||
}
|
||||
}
|
||||
void partition_log_cache(std::stringstream& stream, int depth, SigBit signal, bool format_depth=false) {
|
||||
std::stringstream buf;
|
||||
RTLIL_BACKEND::dump_sigspec(buf, signal, true);
|
||||
if(format_depth) {
|
||||
// at most, this is going to take in maxdepth spaces + 2 brackets + 2 numbers + space + \0
|
||||
std::vector<char> spacer_buffer;
|
||||
spacer_buffer.resize(config.maxdepth + 6);
|
||||
snprintf(spacer_buffer.data(), config.maxdepth + 6, "%*s[%d] ", config.maxdepth-depth, "", depth);
|
||||
stream << spacer_buffer.data();
|
||||
}
|
||||
|
||||
void find_partitions(SigBit root, pool<SigBit> &leaves, pool<pool<SigBit>> &cache, int maxdepth, int maxbreadth)
|
||||
stream << " " << buf.str();
|
||||
if(format_depth)
|
||||
stream << ":";
|
||||
}
|
||||
|
||||
void find_partitions(SigBit root, pool<SigBit> &leaves, pool<pool<SigBit>> &cache, int maxdepth, int maxbreadth, ThreadData& data)
|
||||
{
|
||||
if (cache.count(leaves))
|
||||
return;
|
||||
|
||||
// log("%*s[%d] %s:", 20-maxdepth, "", maxdepth, log_signal(root));
|
||||
// for (auto bit : leaves)
|
||||
// log(" %s", log_signal(bit));
|
||||
// log("\n");
|
||||
partition_log_cache(data.log_buffer, maxdepth, root, true);
|
||||
for (auto bit : leaves)
|
||||
partition_log_cache(data.log_buffer, maxdepth, bit);
|
||||
data.log_buffer << "\n";
|
||||
|
||||
cache.insert(leaves);
|
||||
check_partition(root, leaves);
|
||||
check_partition(root, leaves, data);
|
||||
|
||||
if (maxdepth == 0)
|
||||
return;
|
||||
|
|
@ -262,7 +304,8 @@ struct ExtractFaWorker
|
|||
pool<SigBit> new_leaves = leaves;
|
||||
|
||||
new_leaves.erase(bit);
|
||||
for (auto port : {ID::A, ID::B, ID::C, ID::D}) {
|
||||
|
||||
for (auto port : data.ports) {
|
||||
if (!cell->hasPort(port))
|
||||
continue;
|
||||
auto bit = sigmap(SigBit(cell->getPort(port)));
|
||||
|
|
@ -274,7 +317,7 @@ struct ExtractFaWorker
|
|||
if (GetSize(new_leaves) > maxbreadth)
|
||||
continue;
|
||||
|
||||
find_partitions(root, new_leaves, cache, maxdepth-1, maxbreadth);
|
||||
find_partitions(root, new_leaves, cache, maxdepth-1, maxbreadth, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -290,29 +333,55 @@ struct ExtractFaWorker
|
|||
void run()
|
||||
{
|
||||
log("Extracting full/half adders from %s:\n", log_id(module));
|
||||
const size_t num_threads = std::thread::hardware_concurrency();
|
||||
std::vector<std::thread> threads;
|
||||
std::vector<ThreadData> thread_data(num_threads);
|
||||
|
||||
for (auto it : driver)
|
||||
{
|
||||
if (it.second->type.in(ID($_BUF_), ID($_NOT_)))
|
||||
continue;
|
||||
size_t total_elements = driver.size();
|
||||
size_t thread_elements = total_elements / num_threads;
|
||||
for (size_t i = 0; i < num_threads; ++i) {
|
||||
thread_data[i].start = i * thread_elements;
|
||||
thread_data[i].end = (i == num_threads - 1) ? total_elements : (i + 1) * thread_elements;
|
||||
thread_data[i].instance = this;
|
||||
|
||||
SigBit root = it.first;
|
||||
pool<SigBit> leaves = { root };
|
||||
pool<pool<SigBit>> cache;
|
||||
threads.emplace_back([&data = thread_data[i]]() {
|
||||
auto& driver = data.instance->driver;
|
||||
auto& config = data.instance->config;
|
||||
|
||||
if (config.verbose)
|
||||
log(" checking %s\n", log_signal(it.first));
|
||||
for (size_t i = data.start; i < data.end; ++i) {
|
||||
const auto& it = *driver.element(i);
|
||||
if (it.second->type.in(ID($_BUF_), ID($_NOT_)))
|
||||
continue;
|
||||
|
||||
count_func2 = 0;
|
||||
count_func3 = 0;
|
||||
SigBit root = it.first;
|
||||
pool<SigBit> leaves = { root };
|
||||
pool<pool<SigBit>> cache;
|
||||
|
||||
find_partitions(root, leaves, cache, config.maxdepth, config.maxbreadth);
|
||||
if (config.verbose)
|
||||
log(" checking %s\n", log_signal(it.first));
|
||||
|
||||
if (config.verbose && count_func2 > 0)
|
||||
log(" extracted %d two-input functions\n", count_func2);
|
||||
data.instance->find_partitions(root, leaves, cache, config.maxdepth, config.maxbreadth, data);
|
||||
// log("%s", log_buffer.str().c_str());
|
||||
|
||||
if (config.verbose && count_func3 > 0)
|
||||
log(" extracted %d three-input functions\n", count_func3);
|
||||
if (config.verbose && data.counters.count_func2 > 0)
|
||||
log(" extracted %d two-input functions\n", data.counters.count_func2);
|
||||
|
||||
if (config.verbose && data.counters.count_func3 > 0)
|
||||
log(" extracted %d three-input functions\n", data.counters.count_func3);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_threads; ++i) {
|
||||
threads[i].join();
|
||||
for(auto& x3 : thread_data[i].tl_xorxnor3)
|
||||
xorxnor3.insert(x3);
|
||||
for(auto& x2 : thread_data[i].tl_xorxnor2)
|
||||
xorxnor2.insert(x2);
|
||||
for(auto& f3 : thread_data[i].tl_func_3)
|
||||
func3[get<0>(f3)][get<1>(f3)].insert(get<2>(f3));
|
||||
for(auto& f2 : thread_data[i].tl_func_2)
|
||||
func2[get<0>(f2)][get<1>(f2)].insert(get<2>(f2));
|
||||
}
|
||||
|
||||
for (auto &key : xorxnor3)
|
||||
|
|
@ -341,10 +410,13 @@ struct ExtractFaWorker
|
|||
int func = it.first;
|
||||
auto f3i = it.second;
|
||||
|
||||
int xor_cnt, xnor_cnt;
|
||||
xor_cnt = func3.at(key).count(xor3_func);
|
||||
xnor_cnt = func3.at(key).count(xnor3_func);
|
||||
if (func3.at(key).count(func) == 0)
|
||||
continue;
|
||||
|
||||
if (func3.at(key).count(xor3_func) == 0 && func3.at(key).count(xnor3_func) != 0) {
|
||||
if (xor_cnt == 0 && xnor_cnt != 0) {
|
||||
f3i.inv_a = !f3i.inv_a;
|
||||
f3i.inv_b = !f3i.inv_b;
|
||||
f3i.inv_c = !f3i.inv_c;
|
||||
|
|
@ -413,13 +485,13 @@ struct ExtractFaWorker
|
|||
}
|
||||
|
||||
bool invert_y = f3i.inv_a ^ f3i.inv_b ^ f3i.inv_c;
|
||||
if (func3.at(key).count(xor3_func)) {
|
||||
if (xor_cnt) {
|
||||
SigBit YY = invert_xy ^ invert_y ? module->NotGate(NEW_ID, Y) : Y;
|
||||
for (auto bit : func3.at(key).at(xor3_func))
|
||||
assign_new_driver(bit, YY);
|
||||
}
|
||||
|
||||
if (func3.at(key).count(xnor3_func)) {
|
||||
if (xnor_cnt) {
|
||||
SigBit YY = invert_xy ^ invert_y ? Y : module->NotGate(NEW_ID, Y);
|
||||
for (auto bit : func3.at(key).at(xnor3_func))
|
||||
assign_new_driver(bit, YY);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
read_verilog <<EOT
|
||||
module simple(I1, I2, O);
|
||||
input wire I1;
|
||||
input wire I2;
|
||||
output wire O;
|
||||
|
||||
assign O = I1 | I2;
|
||||
endmodule
|
||||
EOT
|
||||
abc -g all
|
||||
|
||||
design -reset
|
||||
read_verilog <<EOT
|
||||
module simple(I1, I2, O);
|
||||
input wire I1;
|
||||
input wire I2;
|
||||
output wire O;
|
||||
|
||||
assign O = I1 | I2;
|
||||
endmodule
|
||||
EOT
|
||||
techmap
|
||||
abc -g AND
|
||||
|
||||
select -assert-count 0 t:$_OR_
|
||||
select -assert-count 1 t:$_AND_
|
||||
Loading…
Reference in New Issue