3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-13 04:28:18 +00:00

Merge branch 'xaig' into xc7mux

This commit is contained in:
Eddie Hung 2019-04-22 11:58:59 -07:00
commit 4cfef7897f
31 changed files with 952 additions and 282 deletions

View file

@ -685,7 +685,7 @@ struct AigerBackend : public Backend {
log("invariant constraints.\n"); log("invariant constraints.\n");
log("\n"); log("\n");
log(" -ascii\n"); log(" -ascii\n");
log(" write ASCII version of AGIER format\n"); log(" write ASCII version of AIGER format\n");
log("\n"); log("\n");
log(" -zinit\n"); log(" -zinit\n");
log(" convert FFs to zero-initialized FFs, adding additional inputs for\n"); log(" convert FFs to zero-initialized FFs, adding additional inputs for\n");

View file

@ -20,6 +20,8 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/utils.h"
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
@ -46,9 +48,8 @@ struct XAigerWriter
pool<SigBit> input_bits, output_bits; pool<SigBit> input_bits, output_bits;
dict<SigBit, SigBit> not_map, ff_map, alias_map; dict<SigBit, SigBit> not_map, ff_map, alias_map;
dict<SigBit, pair<SigBit, SigBit>> and_map; dict<SigBit, pair<SigBit, SigBit>> and_map;
pool<SigBit> initstate_bits; //pool<SigBit> initstate_bits;
vector<std::pair<SigBit,int>> ci_bits, co_bits; vector<std::pair<SigBit,int>> ci_bits, co_bits;
dict<IdString, unsigned> type_map;
vector<pair<int, int>> aig_gates; vector<pair<int, int>> aig_gates;
vector<int> aig_latchin, aig_latchinit, aig_outputs; vector<int> aig_latchin, aig_latchinit, aig_outputs;
@ -58,11 +59,11 @@ struct XAigerWriter
dict<SigBit, int> ordered_outputs; dict<SigBit, int> ordered_outputs;
dict<SigBit, int> ordered_latches; dict<SigBit, int> ordered_latches;
dict<SigBit, int> init_inputs;
int initstate_ff = 0;
vector<Cell*> box_list; vector<Cell*> box_list;
//dict<SigBit, int> init_inputs;
//int initstate_ff = 0;
int mkgate(int a0, int a1) int mkgate(int a0, int a1)
{ {
aig_m++, aig_a++; aig_m++, aig_a++;
@ -76,10 +77,10 @@ struct XAigerWriter
{ {
aig_map[bit] = -1; aig_map[bit] = -1;
if (initstate_bits.count(bit)) { //if (initstate_bits.count(bit)) {
log_assert(initstate_ff > 0); // log_assert(initstate_ff > 0);
aig_map[bit] = initstate_ff; // aig_map[bit] = initstate_ff;
} else //} else
if (not_map.count(bit)) { if (not_map.count(bit)) {
int a = bit2aig(not_map.at(bit)) ^ 1; int a = bit2aig(not_map.at(bit)) ^ 1;
aig_map[bit] = a; aig_map[bit] = a;
@ -102,7 +103,7 @@ struct XAigerWriter
return aig_map.at(bit); return aig_map.at(bit);
} }
XAigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module) XAigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode, bool holes_mode=false) : module(module), zinit_mode(zinit_mode), sigmap(module)
{ {
pool<SigBit> undriven_bits; pool<SigBit> undriven_bits;
pool<SigBit> unused_bits; pool<SigBit> unused_bits;
@ -159,19 +160,56 @@ struct XAigerWriter
} }
} }
for (auto bit : input_bits) { for (auto bit : input_bits)
if (!bit.wire->port_output) undriven_bits.erase(bit);
undriven_bits.erase(bit);
// Erase POs that are also PIs
output_bits.erase(bit);
}
for (auto bit : output_bits) for (auto bit : output_bits)
if (!bit.wire->port_input) if (!bit.wire->port_input)
unused_bits.erase(bit); unused_bits.erase(bit);
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
bool abc_box_seen = false;
for (auto cell : module->cells()) for (auto cell : module->cells())
{ {
RTLIL::Module* inst_module = module->design->module(cell->type);
bool known_type = yosys_celltypes.cell_known(cell->type);
if (!holes_mode) {
toposort.node(cell->name);
for (const auto &conn : cell->connections())
{
if (!cell->type.in("$_NOT_", "$_AND_")) {
if (known_type) {
if (conn.first.in("\\Q", "\\CTRL_OUT", "\\RD_DATA"))
continue;
if (cell->type == "$memrd" && conn.first == "\\DATA")
continue;
}
if (inst_module) {
RTLIL::Wire* inst_module_port = inst_module->wire(conn.first);
log_assert(inst_module_port);
if (inst_module_port->attributes.count("\\abc_flop_q"))
continue;
}
}
if (cell->input(conn.first)) {
// Ignore inout for the sake of topographical ordering
if (cell->output(conn.first)) continue;
for (auto bit : sigmap(conn.second))
bit_users[bit].insert(cell->name);
}
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
bit_drivers[bit].insert(cell->name);
}
}
if (cell->type == "$_NOT_") if (cell->type == "$_NOT_")
{ {
SigBit A = sigmap(cell->getPort("\\A").as_bit()); SigBit A = sigmap(cell->getPort("\\A").as_bit());
@ -204,59 +242,100 @@ struct XAigerWriter
continue; continue;
} }
if (cell->type == "$initstate") //if (cell->type == "$initstate")
{ //{
SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); // SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
undriven_bits.erase(Y); // undriven_bits.erase(Y);
initstate_bits.insert(Y); // initstate_bits.insert(Y);
continue; // continue;
//}
if (inst_module && inst_module->attributes.count("\\abc_box_id")) {
abc_box_seen = true;
} }
else {
RTLIL::Module* box_module = module->design->module(cell->type); for (const auto &c : cell->connections()) {
bool abc_box = box_module && box_module->attributes.count("\\abc_box_id"); if (c.second.is_fully_const()) continue;
for (auto b : c.second.bits()) {
for (const auto &c : cell->connections()) { Wire *w = b.wire;
/*if (c.second.is_fully_const()) continue;*/ if (!w) continue;
for (auto b : c.second.bits()) { auto is_input = cell->input(c.first);
auto is_input = cell->input(c.first); auto is_output = cell->output(c.first);
auto is_output = cell->output(c.first); log_assert(is_input || is_output);
log_assert(is_input || is_output); if (is_input) {
if (is_input) { if (!w->port_input) {
/*if (!w->port_input)*/ { SigBit I = sigmap(b);
SigBit I = sigmap(b); if (I != b)
if (I != b) alias_map[b] = I;
alias_map[b] = I;
/*if (!output_bits.count(b))*/
if (abc_box)
co_bits.emplace_back(b, 0);
else if (b.wire) {
output_bits.insert(b); output_bits.insert(b);
if (!b.wire->port_input) unused_bits.erase(b);
unused_bits.erase(b);
} }
} }
} if (is_output) {
if (is_output) { SigBit O = sigmap(b);
SigBit O = sigmap(b);
/*if (!input_bits.count(O))*/
if (abc_box)
ci_bits.emplace_back(O, 0);
else {
input_bits.insert(O); input_bits.insert(O);
if (!O.wire->port_output) undriven_bits.erase(O);
undriven_bits.erase(O);
} }
} }
} }
if (!type_map.count(cell->type))
type_map[cell->type] = type_map.size()+1;
} }
if (abc_box)
box_list.emplace_back(cell);
//log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
} }
if (abc_box_seen) {
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);
#ifndef NDEBUG
toposort.analyze_loops = true;
#endif
toposort.sort();
#ifndef NDEBUG
for (auto &it : toposort.loops) {
log(" loop");
for (auto cell : it)
log(" %s", log_id(cell));
log("\n");
}
#endif
log_assert(!toposort.found_loops);
for (auto cell_name : toposort.sorted) {
RTLIL::Cell *cell = module->cell(cell_name);
RTLIL::Module* box_module = module->design->module(cell->type);
if (!box_module || !box_module->attributes.count("\\abc_box_id"))
continue;
// Box ordering is alphabetical
cell->connections_.sort(RTLIL::sort_by_id_str());
for (const auto &c : cell->connections()) {
for (auto b : c.second.bits()) {
auto is_input = cell->input(c.first);
auto is_output = cell->output(c.first);
log_assert(is_input || is_output);
if (is_input) {
SigBit I = sigmap(b);
if (I != b)
alias_map[b] = I;
co_bits.emplace_back(b, 0);
}
if (is_output) {
SigBit O = sigmap(b);
ci_bits.emplace_back(O, 0);
}
}
}
box_list.emplace_back(cell);
}
// TODO: Free memory from toposort, bit_drivers, bit_users
}
for (auto bit : input_bits) { for (auto bit : input_bits) {
RTLIL::Wire *wire = bit.wire; RTLIL::Wire *wire = bit.wire;
// If encountering an inout port, then create a new wire with $inout.out // If encountering an inout port, then create a new wire with $inout.out
@ -274,27 +353,23 @@ struct XAigerWriter
and_map[new_bit] = and_map.at(bit); and_map[new_bit] = and_map.at(bit);
else if (alias_map.count(bit)) else if (alias_map.count(bit))
alias_map[new_bit] = alias_map.at(bit); alias_map[new_bit] = alias_map.at(bit);
else
alias_map[new_bit] = bit;
output_bits.insert(new_bit); output_bits.insert(new_bit);
} }
} }
// Do some CI/CO post-processing: // Do some CI/CO post-processing:
// Erase all POs and COs that are undriven // Erase all POs that are undriven
for (auto bit : undriven_bits) { for (auto bit : undriven_bits)
//co_bits.erase(bit);
output_bits.erase(bit); output_bits.erase(bit);
}
// Erase all CIs that are also COs
//for (auto bit : co_bits)
// ci_bits.erase(bit);
// CIs cannot be undriven // CIs cannot be undriven
for (const auto &c : ci_bits) for (const auto &c : ci_bits)
undriven_bits.erase(c.first); undriven_bits.erase(c.first);
for (auto bit : unused_bits) for (auto bit : unused_bits)
undriven_bits.erase(bit); undriven_bits.erase(bit);
if (!undriven_bits.empty()) { if (!undriven_bits.empty() && !holes_mode) {
undriven_bits.sort(); undriven_bits.sort();
for (auto bit : undriven_bits) { for (auto bit : undriven_bits) {
log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit)); log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit));
@ -313,30 +388,30 @@ struct XAigerWriter
aig_map[State::S0] = 0; aig_map[State::S0] = 0;
aig_map[State::S1] = 1; aig_map[State::S1] = 1;
for (auto &c : ci_bits) {
aig_m++, aig_i++;
c.second = 2*aig_m;
aig_map[c.first] = c.second;
}
for (auto bit : input_bits) { for (auto bit : input_bits) {
aig_m++, aig_i++; aig_m++, aig_i++;
aig_map[bit] = 2*aig_m; aig_map[bit] = 2*aig_m;
} }
for (auto &c : ci_bits) {
aig_m++, aig_i++;
c.second = 2*aig_m;
aig_map[c.first] = c.second;
}
if (imode && input_bits.empty()) { if (imode && input_bits.empty()) {
aig_m++, aig_i++; aig_m++, aig_i++;
} }
if (zinit_mode) //if (zinit_mode)
{ //{
for (auto it : ff_map) { // for (auto it : ff_map) {
if (init_map.count(it.first)) // if (init_map.count(it.first))
continue; // continue;
aig_m++, aig_i++; // aig_m++, aig_i++;
init_inputs[it.first] = 2*aig_m; // init_inputs[it.first] = 2*aig_m;
} // }
} //}
for (auto it : ff_map) { for (auto it : ff_map) {
aig_m++, aig_l++; aig_m++, aig_l++;
@ -348,29 +423,29 @@ struct XAigerWriter
aig_latchinit.push_back(init_map.at(it.first) ? 1 : 0); aig_latchinit.push_back(init_map.at(it.first) ? 1 : 0);
} }
if (!initstate_bits.empty() || !init_inputs.empty()) { //if (!initstate_bits.empty() || !init_inputs.empty()) {
aig_m++, aig_l++; // aig_m++, aig_l++;
initstate_ff = 2*aig_m+1; // initstate_ff = 2*aig_m+1;
aig_latchinit.push_back(0); // aig_latchinit.push_back(0);
} //}
if (zinit_mode) //if (zinit_mode)
{ //{
for (auto it : ff_map) // for (auto it : ff_map)
{ // {
int l = ordered_latches[it.first]; // int l = ordered_latches[it.first];
if (aig_latchinit.at(l) == 1) // if (aig_latchinit.at(l) == 1)
aig_map[it.first] ^= 1; // aig_map[it.first] ^= 1;
if (aig_latchinit.at(l) == 2) // if (aig_latchinit.at(l) == 2)
{ // {
int gated_ffout = mkgate(aig_map[it.first], initstate_ff^1); // int gated_ffout = mkgate(aig_map[it.first], initstate_ff^1);
int gated_initin = mkgate(init_inputs[it.first], initstate_ff); // int gated_initin = mkgate(init_inputs[it.first], initstate_ff);
aig_map[it.first] = mkgate(gated_ffout^1, gated_initin^1)^1; // aig_map[it.first] = mkgate(gated_ffout^1, gated_initin^1)^1;
} // }
} // }
} //}
for (auto it : ff_map) { for (auto it : ff_map) {
int a = bit2aig(it.second); int a = bit2aig(it.second);
@ -381,8 +456,8 @@ struct XAigerWriter
aig_latchin.push_back(a); aig_latchin.push_back(a);
} }
if (!initstate_bits.empty() || !init_inputs.empty()) //if (!initstate_bits.empty() || !init_inputs.empty())
aig_latchin.push_back(1); // aig_latchin.push_back(1);
for (auto &c : co_bits) { for (auto &c : co_bits) {
RTLIL::SigBit bit = c.first; RTLIL::SigBit bit = c.first;
@ -517,14 +592,14 @@ struct XAigerWriter
symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", log_id(wire))); symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", log_id(wire)));
} }
if (init_inputs.count(sig[i])) { //if (init_inputs.count(sig[i])) {
int a = init_inputs.at(sig[i]); // int a = init_inputs.at(sig[i]);
log_assert((a & 1) == 0); // log_assert((a & 1) == 0);
if (GetSize(wire) != 1) // if (GetSize(wire) != 1)
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", log_id(wire), i)); // symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", log_id(wire), i));
else // else
symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", log_id(wire))); // symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", log_id(wire)));
} //}
if (ordered_latches.count(sig[i])) { if (ordered_latches.count(sig[i])) {
int l = ordered_latches.at(sig[i]); int l = ordered_latches.at(sig[i]);
@ -584,17 +659,17 @@ struct XAigerWriter
if (holes_module && !holes_module->cell(stringf("\\u%d", box_id))) if (holes_module && !holes_module->cell(stringf("\\u%d", box_id)))
holes_cell = holes_module->addCell(stringf("\\u%d", box_id), cell->type); holes_cell = holes_module->addCell(stringf("\\u%d", box_id), cell->type);
RTLIL::Wire *holes_wire; RTLIL::Wire *holes_wire;
int num_inputs = 0; // NB: cell->connections_ already sorted from before
for (const auto &c : cell->connections()) { for (const auto &c : cell->connections()) {
log_assert(c.second.size() == 1);
if (cell->input(c.first)) { if (cell->input(c.first)) {
box_inputs += c.second.size(); box_inputs += c.second.size();
if (holes_cell) { if (holes_cell) {
holes_wire = holes_module->wire(stringf("\\i%d", num_inputs)); holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
if (!holes_wire) { if (!holes_wire) {
holes_wire = holes_module->addWire(stringf("\\i%d", num_inputs)); holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
holes_wire->port_input = true; holes_wire->port_input = true;
} }
++num_inputs;
holes_cell->setPort(c.first, holes_wire); holes_cell->setPort(c.first, holes_wire);
} }
} }
@ -631,12 +706,12 @@ struct XAigerWriter
RTLIL::Selection& sel = holes_module->design->selection_stack.back(); RTLIL::Selection& sel = holes_module->design->selection_stack.back();
sel.select(holes_module); sel.select(holes_module);
Pass::call(holes_module->design, "flatten; aigmap"); Pass::call(holes_module->design, "flatten -wb; aigmap; clean -purge");
holes_module->design->selection_stack.pop_back(); holes_module->design->selection_stack.pop_back();
std::stringstream a_buffer; std::stringstream a_buffer;
XAigerWriter writer(holes_module, false /*zinit_mode*/, false /*imode*/, false /*omode*/, false /*bmode*/); XAigerWriter writer(holes_module, false /*zinit_mode*/, false /*imode*/, false /*omode*/, false /*bmode*/, true /* holes_mode */);
writer.write_aiger(a_buffer, false /*ascii_mode*/, false /*miter_mode*/, false /*symbols_mode*/, false /*omode*/); writer.write_aiger(a_buffer, false /*ascii_mode*/, false /*miter_mode*/, false /*symbols_mode*/, false /*omode*/);
f << "a"; f << "a";
@ -686,12 +761,12 @@ struct XAigerWriter
continue; continue;
} }
if (init_inputs.count(sig[i])) { //if (init_inputs.count(sig[i])) {
int a = init_inputs.at(sig[i]); // int a = init_inputs.at(sig[i]);
log_assert((a & 1) == 0); // log_assert((a & 1) == 0);
init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, i, log_id(wire)); // init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, i, log_id(wire));
continue; // continue;
} //}
if (ordered_latches.count(sig[i])) { if (ordered_latches.count(sig[i])) {
int l = ordered_latches.at(sig[i]); int l = ordered_latches.at(sig[i]);
@ -716,7 +791,7 @@ struct XAigerWriter
RTLIL::SigBit b = c.first; RTLIL::SigBit b = c.first;
RTLIL::Wire *wire = b.wire; RTLIL::Wire *wire = b.wire;
int i = b.offset; int i = b.offset;
int a = c.second; int a = bit2aig(b);
log_assert((a & 1) == 0); log_assert((a & 1) == 0);
input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire)); input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire));
} }
@ -769,7 +844,7 @@ struct XAigerBackend : public Backend {
log("all unsupported cells will be converted into psuedo-inputs and pseudo-outputs.\n"); log("all unsupported cells will be converted into psuedo-inputs and pseudo-outputs.\n");
log("\n"); log("\n");
log(" -ascii\n"); log(" -ascii\n");
log(" write ASCII version of AGIER format\n"); log(" write ASCII version of AIGER format\n");
log("\n"); log("\n");
log(" -zinit\n"); log(" -zinit\n");
log(" convert FFs to zero-initialized FFs, adding additional inputs for\n"); log(" convert FFs to zero-initialized FFs, adding additional inputs for\n");

View file

@ -130,72 +130,75 @@ struct JsonWriter
f << stringf(" }"); f << stringf(" }");
first = false; first = false;
} }
f << stringf("\n },\n"); f << stringf("\n }");
f << stringf(" \"cells\": {"); if (!module->get_blackbox_attribute()) {
first = true; f << stringf(",\n \"cells\": {");
for (auto c : module->cells()) { first = true;
if (use_selection && !module->selected(c)) for (auto c : module->cells()) {
continue; if (use_selection && !module->selected(c))
f << stringf("%s\n", first ? "" : ","); continue;
f << stringf(" %s: {\n", get_name(c->name).c_str()); f << stringf("%s\n", first ? "" : ",");
f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0"); f << stringf(" %s: {\n", get_name(c->name).c_str());
f << stringf(" \"type\": %s,\n", get_name(c->type).c_str()); f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
if (aig_mode) { f << stringf(" \"type\": %s,\n", get_name(c->type).c_str());
Aig aig(c); if (aig_mode) {
if (!aig.name.empty()) { Aig aig(c);
f << stringf(" \"model\": \"%s\",\n", aig.name.c_str()); if (!aig.name.empty()) {
aig_models.insert(aig); f << stringf(" \"model\": \"%s\",\n", aig.name.c_str());
aig_models.insert(aig);
}
} }
} f << stringf(" \"parameters\": {");
f << stringf(" \"parameters\": {"); write_parameters(c->parameters);
write_parameters(c->parameters); f << stringf("\n },\n");
f << stringf("\n },\n"); f << stringf(" \"attributes\": {");
f << stringf(" \"attributes\": {"); write_parameters(c->attributes);
write_parameters(c->attributes); f << stringf("\n },\n");
f << stringf("\n },\n"); if (c->known()) {
if (c->known()) { f << stringf(" \"port_directions\": {");
f << stringf(" \"port_directions\": {"); bool first2 = true;
for (auto &conn : c->connections()) {
string direction = "output";
if (c->input(conn.first))
direction = c->output(conn.first) ? "inout" : "input";
f << stringf("%s\n", first2 ? "" : ",");
f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str());
first2 = false;
}
f << stringf("\n },\n");
}
f << stringf(" \"connections\": {");
bool first2 = true; bool first2 = true;
for (auto &conn : c->connections()) { for (auto &conn : c->connections()) {
string direction = "output";
if (c->input(conn.first))
direction = c->output(conn.first) ? "inout" : "input";
f << stringf("%s\n", first2 ? "" : ","); f << stringf("%s\n", first2 ? "" : ",");
f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str()); f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
first2 = false; first2 = false;
} }
f << stringf("\n },\n"); f << stringf("\n }\n");
f << stringf(" }");
first = false;
} }
f << stringf(" \"connections\": {"); f << stringf("\n },\n");
bool first2 = true;
for (auto &conn : c->connections()) {
f << stringf("%s\n", first2 ? "" : ",");
f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
first2 = false;
}
f << stringf("\n }\n");
f << stringf(" }");
first = false;
}
f << stringf("\n },\n");
f << stringf(" \"netnames\": {"); f << stringf(" \"netnames\": {");
first = true; first = true;
for (auto w : module->wires()) { for (auto w : module->wires()) {
if (use_selection && !module->selected(w)) if (use_selection && !module->selected(w))
continue; continue;
f << stringf("%s\n", first ? "" : ","); f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(w->name).c_str()); f << stringf(" %s: {\n", get_name(w->name).c_str());
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
f << stringf(" \"attributes\": {"); f << stringf(" \"attributes\": {");
write_parameters(w->attributes); write_parameters(w->attributes);
f << stringf("\n }\n"); f << stringf("\n }\n");
f << stringf(" }"); f << stringf(" }");
first = false; first = false;
}
f << stringf("\n }");
} }
f << stringf("\n }\n"); f << stringf("\n");
f << stringf(" }"); f << stringf(" }");
} }

View file

@ -187,6 +187,10 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
{ {
if (width < 0) if (width < 0)
width = data.bits.size() - offset; width = data.bits.size() - offset;
if (width == 0) {
f << "\"\"";
return;
}
if (nostr) if (nostr)
goto dump_hex; goto dump_hex;
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
@ -340,6 +344,10 @@ void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decima
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
{ {
if (GetSize(sig) == 0) {
f << "\"\"";
return;
}
if (sig.is_chunk()) { if (sig.is_chunk()) {
dump_sigchunk(f, sig.as_chunk()); dump_sigchunk(f, sig.as_chunk());
} else { } else {

View file

@ -35,9 +35,6 @@
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
//#define log_debug log
#define log_debug(...) ;
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports) AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports)
: design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports) : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports)
{ {
@ -368,6 +365,13 @@ void AigerReader::parse_xaiger()
f >> s; f >> s;
log_debug("n: '%s'\n", s.c_str()); log_debug("n: '%s'\n", s.c_str());
} }
else if (c == 'a' || c == 'i' || c == 'o' || c == 'h') {
uint32_t dataSize = parse_xaiger_literal(f);
f.ignore(dataSize);
}
else {
break;
}
} }
else if (c == 'i' || c == 'l' || c == 'o') { else if (c == 'i' || c == 'l' || c == 'o') {
f.ignore(1); f.ignore(1);

View file

@ -1085,7 +1085,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 1st expression // eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone(); AstNode *varbuf = init_ast->children[1]->clone();
while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } {
int expr_width_hint = -1;
bool expr_sign_hint = true;
varbuf->detectSignWidth(expr_width_hint, expr_sign_hint);
while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
}
if (varbuf->type != AST_CONSTANT) if (varbuf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n"); log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n");
@ -1107,7 +1112,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{ {
// eval 2nd expression // eval 2nd expression
AstNode *buf = while_ast->clone(); AstNode *buf = while_ast->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } {
int expr_width_hint = -1;
bool expr_sign_hint = true;
buf->detectSignWidth(expr_width_hint, expr_sign_hint);
while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { }
}
if (buf->type != AST_CONSTANT) if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n"); log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n");
@ -1148,7 +1158,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 3rd expression // eval 3rd expression
buf = next_ast->children[1]->clone(); buf = next_ast->children[1]->clone();
while (buf->simplify(true, false, false, stage, 32, true, false)) { } {
int expr_width_hint = -1;
bool expr_sign_hint = true;
buf->detectSignWidth(expr_width_hint, expr_sign_hint);
while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { }
}
if (buf->type != AST_CONSTANT) if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n"); log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n");

View file

@ -295,6 +295,9 @@ int main(int argc, char **argv)
printf(" -E <depsfile>\n"); printf(" -E <depsfile>\n");
printf(" write a Makefile dependencies file with in- and output file names\n"); printf(" write a Makefile dependencies file with in- and output file names\n");
printf("\n"); printf("\n");
printf(" -g\n");
printf(" globally enable debug log messages\n");
printf("\n");
printf(" -V\n"); printf(" -V\n");
printf(" print version information and exit\n"); printf(" print version information and exit\n");
printf("\n"); printf("\n");
@ -315,7 +318,7 @@ int main(int argc, char **argv)
} }
int opt; int opt;
while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1) while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1)
{ {
switch (opt) switch (opt)
{ {
@ -340,6 +343,9 @@ int main(int argc, char **argv)
case 'S': case 'S':
passes_commands.push_back("synth"); passes_commands.push_back("synth");
break; break;
case 'g':
log_force_debug++;
break;
case 'm': case 'm':
plugin_filenames.push_back(optarg); plugin_filenames.push_back(optarg);
break; break;

View file

@ -56,6 +56,10 @@ int log_verbose_level;
string log_last_error; string log_last_error;
void (*log_error_atexit)() = NULL; void (*log_error_atexit)() = NULL;
int log_make_debug = 0;
int log_force_debug = 0;
int log_debug_suppressed = 0;
vector<int> header_count; vector<int> header_count;
pool<RTLIL::IdString> log_id_cache; pool<RTLIL::IdString> log_id_cache;
vector<shared_str> string_buf; vector<shared_str> string_buf;
@ -92,6 +96,9 @@ void logv(const char *format, va_list ap)
format++; format++;
} }
if (log_make_debug && !ys_debug(1))
return;
std::string str = vstringf(format, ap); std::string str = vstringf(format, ap);
if (str.empty()) if (str.empty())

View file

@ -64,6 +64,10 @@ extern int log_verbose_level;
extern string log_last_error; extern string log_last_error;
extern void (*log_error_atexit)(); extern void (*log_error_atexit)();
extern int log_make_debug;
extern int log_force_debug;
extern int log_debug_suppressed;
void logv(const char *format, va_list ap); void logv(const char *format, va_list ap);
void logv_header(RTLIL::Design *design, const char *format, va_list ap); void logv_header(RTLIL::Design *design, const char *format, va_list ap);
void logv_warning(const char *format, va_list ap); void logv_warning(const char *format, va_list ap);
@ -82,6 +86,45 @@ YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf,
void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn); void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn);
YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
#ifndef NDEBUG
static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; }
# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
#else
static inline bool ys_debug(int n = 0) { return false; }
# define log_debug(_fmt, ...) do { } while (0)
#endif
static inline void log_suppressed() {
if (log_debug_suppressed && !log_make_debug) {
log("<suppressed ~%d debug messages>\n", log_debug_suppressed);
log_debug_suppressed = 0;
}
}
struct LogMakeDebugHdl {
bool status = false;
LogMakeDebugHdl(bool start_on = false) {
if (start_on)
on();
}
~LogMakeDebugHdl() {
off();
}
void on() {
if (status) return;
status=true;
log_make_debug++;
}
void off_silent() {
if (!status) return;
status=false;
log_make_debug--;
}
void off() {
off_silent();
}
};
void log_spacer(); void log_spacer();
void log_push(); void log_push();
void log_pop(); void log_pop();

View file

@ -87,6 +87,7 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
void Pass::post_execute(Pass::pre_post_exec_state_t state) void Pass::post_execute(Pass::pre_post_exec_state_t state)
{ {
IdString::checkpoint(); IdString::checkpoint();
log_suppressed();
int64_t time_ns = PerformanceTimer::query() - state.begin_ns; int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
runtime_ns += time_ns; runtime_ns += time_ns;

View file

@ -94,4 +94,38 @@ struct TracePass : public Pass {
} }
} TracePass; } TracePass;
struct DebugPass : public Pass {
DebugPass() : Pass("debug", "run command with debug log messages enabled") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" debug cmd\n");
log("\n");
log("Execute the specified command with debug log messages enabled\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// .. parse options ..
break;
}
log_force_debug++;
try {
std::vector<std::string> new_args(args.begin() + argidx, args.end());
Pass::call(design, new_args);
} catch (...) {
log_force_debug--;
throw;
}
log_force_debug--;
}
} DebugPass;
PRIVATE_NAMESPACE_END PRIVATE_NAMESPACE_END

View file

@ -137,7 +137,7 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto cell : unused) { for (auto cell : unused) {
if (verbose) if (verbose)
log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str()); log_debug(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
module->design->scratchpad_set_bool("opt.did_something", true); module->design->scratchpad_set_bool("opt.did_something", true);
module->remove(cell); module->remove(cell);
count_rm_cells++; count_rm_cells++;
@ -326,7 +326,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
for (auto wire : maybe_del_wires) for (auto wire : maybe_del_wires)
if (!used_signals.check_any(RTLIL::SigSpec(wire))) { if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) { if (check_public_name(wire->name) && verbose) {
log(" removing unused non-port wire %s.\n", wire->name.c_str()); log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
} }
del_wires.insert(wire); del_wires.insert(wire);
del_wires_count++; del_wires_count++;
@ -336,7 +336,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
count_rm_wires += del_wires.size(); count_rm_wires += del_wires.size();
if (verbose && del_wires_count > 0) if (verbose && del_wires_count > 0)
log(" removed %d unused temporary wires.\n", del_wires_count); log_debug(" removed %d unused temporary wires.\n", del_wires_count);
} }
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@ -399,7 +399,7 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
} }
if (verbose) if (verbose)
log(" removing redundant init attribute on %s.\n", log_id(wire)); log_debug(" removing redundant init attribute on %s.\n", log_id(wire));
wire->attributes.erase("\\init"); wire->attributes.erase("\\init");
did_something = true; did_something = true;
@ -426,7 +426,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
} }
for (auto cell : delcells) { for (auto cell : delcells) {
if (verbose) if (verbose)
log(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(), log_debug(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A"))); log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A")));
module->remove(cell); module->remove(cell);
} }
@ -551,6 +551,7 @@ struct CleanPass : public Pass {
rmunused_module(module, purge_mode, false, false); rmunused_module(module, purge_mode, false, false);
} }
log_suppressed();
if (count_rm_cells > 0 || count_rm_wires > 0) if (count_rm_cells > 0 || count_rm_wires > 0)
log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires); log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires);

View file

@ -67,7 +67,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
if (sig.size() == 0) if (sig.size() == 0)
continue; continue;
log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); log_debug("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c));
module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
did_something = true; did_something = true;
} }
@ -78,7 +78,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
RTLIL::SigSpec Y = cell->getPort(out_port); RTLIL::SigSpec Y = cell->getPort(out_port);
out_val.extend_u0(Y.size(), false); out_val.extend_u0(Y.size(), false);
log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
cell->type.c_str(), cell->name.c_str(), info.c_str(), cell->type.c_str(), cell->name.c_str(), info.c_str(),
module->name.c_str(), log_signal(Y), log_signal(out_val)); module->name.c_str(), log_signal(Y), log_signal(out_val));
// log_cell(cell); // log_cell(cell);
@ -134,7 +134,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
if (GetSize(grouped_bits[i]) == GetSize(bits_y)) if (GetSize(grouped_bits[i]) == GetSize(bits_y))
return false; return false;
log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
log_id(cell->type), log_id(cell), log_id(module)); log_id(cell->type), log_id(cell), log_id(module));
for (int i = 0; i < GRP_N; i++) for (int i = 0; i < GRP_N; i++)
@ -156,7 +156,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
} }
if (cell->type.in("$and", "$or") && i == GRP_CONST_A) { if (cell->type.in("$and", "$or") && i == GRP_CONST_A) {
log(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a));
module->connect(new_y, new_b); module->connect(new_y, new_b);
module->connect(new_conn); module->connect(new_conn);
continue; continue;
@ -180,10 +180,10 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
module->connect(new_conn); module->connect(new_conn);
log(" New cell `%s': A=%s", log_id(c), log_signal(new_a)); log_debug(" New cell `%s': A=%s", log_id(c), log_signal(new_a));
if (b_name == "\\B") if (b_name == "\\B")
log(", B=%s", log_signal(new_b)); log_debug(", B=%s", log_signal(new_b));
log("\n"); log_debug("\n");
} }
cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
@ -197,7 +197,7 @@ void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap
{ {
SigSpec sig = assign_map(cell->getPort(port)); SigSpec sig = assign_map(cell->getPort(port));
if (invert_map.count(sig)) { if (invert_map.count(sig)) {
log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
log_signal(sig), log_signal(invert_map.at(sig))); log_signal(sig), log_signal(invert_map.at(sig)));
cell->setPort(port, (invert_map.at(sig))); cell->setPort(port, (invert_map.at(sig)));
@ -226,7 +226,7 @@ void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdStrin
if (cell->type.in(type1, type2)) { if (cell->type.in(type1, type2)) {
SigSpec sig = assign_map(cell->getPort(port)); SigSpec sig = assign_map(cell->getPort(port));
if (invert_map.count(sig)) { if (invert_map.count(sig)) {
log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
log_signal(sig), log_signal(invert_map.at(sig))); log_signal(sig), log_signal(invert_map.at(sig)));
cell->setPort(port, (invert_map.at(sig))); cell->setPort(port, (invert_map.at(sig)));
@ -455,9 +455,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
if (cell->type == "$reduce_xnor") { if (cell->type == "$reduce_xnor") {
cover("opt.opt_expr.reduce_xnor_not"); cover("opt.opt_expr.reduce_xnor_not");
log("Replacing %s cell `%s' in module `%s' with $not cell.\n", log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n",
log_id(cell->type), log_id(cell->name), log_id(module)); log_id(cell->type), log_id(cell->name), log_id(module));
cell->type = "$not"; cell->type = "$not";
did_something = true;
} else { } else {
cover("opt.opt_expr.unary_buffer"); cover("opt.opt_expr.unary_buffer");
replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A")); replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A"));
@ -488,7 +489,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (GetSize(new_sig_a) < GetSize(sig_a)) { if (GetSize(new_sig_a) < GetSize(sig_a)) {
cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str()); cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str());
log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a));
cell->setPort("\\A", new_sig_a); cell->setPort("\\A", new_sig_a);
cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a); cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a);
@ -511,7 +512,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (GetSize(new_sig_b) < GetSize(sig_b)) { if (GetSize(new_sig_b) < GetSize(sig_b)) {
cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str()); cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str());
log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b));
cell->setPort("\\B", new_sig_b); cell->setPort("\\B", new_sig_b);
cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b); cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b);
@ -537,7 +538,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
cover("opt.opt_expr.fine.$reduce_and"); cover("opt.opt_expr.fine.$reduce_and");
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a); cell->setPort("\\A", sig_a = new_a);
cell->parameters.at("\\A_WIDTH") = 1; cell->parameters.at("\\A_WIDTH") = 1;
@ -563,7 +564,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a); cell->setPort("\\A", sig_a = new_a);
cell->parameters.at("\\A_WIDTH") = 1; cell->parameters.at("\\A_WIDTH") = 1;
@ -589,7 +590,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) {
cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str()); cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str());
log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
cell->setPort("\\B", sig_b = new_b); cell->setPort("\\B", sig_b = new_b);
cell->parameters.at("\\B_WIDTH") = 1; cell->parameters.at("\\B_WIDTH") = 1;
@ -640,7 +641,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) { if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
RTLIL::SigSpec tmp = cell->getPort("\\A"); RTLIL::SigSpec tmp = cell->getPort("\\A");
cell->setPort("\\A", cell->getPort("\\B")); cell->setPort("\\A", cell->getPort("\\B"));
cell->setPort("\\B", tmp); cell->setPort("\\B", tmp);
@ -750,7 +751,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
ACTION_DO("\\Y", cell->getPort("\\A")); ACTION_DO("\\Y", cell->getPort("\\A"));
if (input == State::S0 && !a.is_fully_undef()) { if (input == State::S0 && !a.is_fully_undef()) {
cover("opt.opt_expr.action_" S__LINE__); cover("opt.opt_expr.action_" S__LINE__);
log("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str()); cell->type.c_str(), cell->name.c_str(), module->name.c_str());
cell->setPort("\\A", SigSpec(State::Sx, GetSize(a))); cell->setPort("\\A", SigSpec(State::Sx, GetSize(a)));
did_something = true; did_something = true;
@ -822,7 +823,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
ACTION_DO("\\Y", cell->getPort("\\A")); ACTION_DO("\\Y", cell->getPort("\\A"));
} else { } else {
cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str()); cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = "$not"; cell->type = "$not";
cell->parameters.erase("\\B_WIDTH"); cell->parameters.erase("\\B_WIDTH");
cell->parameters.erase("\\B_SIGNED"); cell->parameters.erase("\\B_SIGNED");
@ -837,7 +838,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
(assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero())) (assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero()))
{ {
cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), "$eq" ? "$logic_not" : "$reduce_bool"); log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool"; cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool";
if (assign_map(cell->getPort("\\A")).is_fully_zero()) { if (assign_map(cell->getPort("\\A")).is_fully_zero()) {
@ -876,7 +877,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y)); log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
module->connect(cell->getPort("\\Y"), sig_y); module->connect(cell->getPort("\\Y"), sig_y);
@ -939,7 +940,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (identity_wrt_b) if (identity_wrt_b)
cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
if (!identity_wrt_a) { if (!identity_wrt_a) {
@ -969,7 +970,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) { cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S")); cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\B"); cell->unsetPort("\\B");
cell->unsetPort("\\S"); cell->unsetPort("\\S");
@ -988,7 +989,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) { if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S")); cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\S"); cell->unsetPort("\\S");
if (cell->type == "$mux") { if (cell->type == "$mux") {
@ -1008,7 +1009,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\B", cell->getPort("\\S")); cell->setPort("\\B", cell->getPort("\\S"));
cell->unsetPort("\\S"); cell->unsetPort("\\S");
if (cell->type == "$mux") { if (cell->type == "$mux") {
@ -1061,7 +1062,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (cell->getPort("\\S").size() != new_s.size()) { if (cell->getPort("\\S").size() != new_s.size()) {
cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str()); cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", new_a); cell->setPort("\\A", new_a);
cell->setPort("\\B", new_b); cell->setPort("\\B", new_b);
@ -1179,7 +1180,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
cover("opt.opt_expr.mul_shift.zero"); cover("opt.opt_expr.mul_shift.zero");
log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
cell->name.c_str(), module->name.c_str()); cell->name.c_str(), module->name.c_str());
module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
@ -1197,7 +1198,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
else else
cover("opt.opt_expr.mul_shift.unswapped"); cover("opt.opt_expr.mul_shift.unswapped");
log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", log_debug("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
a_val, cell->name.c_str(), module->name.c_str(), i); a_val, cell->name.c_str(), module->name.c_str(), i);
if (!swapped_ab) { if (!swapped_ab) {
@ -1237,7 +1238,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
cover("opt.opt_expr.divmod_zero"); cover("opt.opt_expr.divmod_zero");
log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
cell->name.c_str(), module->name.c_str()); cell->name.c_str(), module->name.c_str());
module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size()))); module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size())));
@ -1254,7 +1255,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
cover("opt.opt_expr.div_shift"); cover("opt.opt_expr.div_shift");
log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
b_val, cell->name.c_str(), module->name.c_str(), i); b_val, cell->name.c_str(), module->name.c_str(), i);
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
@ -1272,7 +1273,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{ {
cover("opt.opt_expr.mod_mask"); cover("opt.opt_expr.mod_mask");
log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
b_val, cell->name.c_str(), module->name.c_str()); b_val, cell->name.c_str(), module->name.c_str());
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i); std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
@ -1342,7 +1343,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
SigSpec y_sig = cell->getPort("\\Y"); SigSpec y_sig = cell->getPort("\\Y");
Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig)); Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig));
log("Replacing cell `%s' in module `%s' with constant driver %s.\n", log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n",
log_id(cell), log_id(module), log_signal(y_value)); log_id(cell), log_id(module), log_signal(y_value));
module->connect(y_sig, y_value); module->connect(y_sig, y_value);
@ -1354,7 +1355,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (redundant_bits) if (redundant_bits)
{ {
log("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n", log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
redundant_bits, log_id(cell->type), log_id(cell), log_id(module)); redundant_bits, log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", sig_a); cell->setPort("\\A", sig_a);
@ -1493,7 +1494,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (replace || remove) if (replace || remove)
{ {
log("Replacing %s cell `%s' (implementing %s) with %s.\n", log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n",
log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str()); log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str());
if (replace) if (replace)
module->connect(cell->getPort("\\Y"), replace_sig); module->connect(cell->getPort("\\Y"), replace_sig);
@ -1599,8 +1600,14 @@ struct OptExprPass : public Pass {
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
{ {
if (undriven) log("Optimizing module %s.\n", log_id(module));
if (undriven) {
did_something = false;
replace_undriven(design, module); replace_undriven(design, module);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
}
do { do {
do { do {
@ -1610,7 +1617,11 @@ struct OptExprPass : public Pass {
design->scratchpad_set_bool("opt.did_something", true); design->scratchpad_set_bool("opt.did_something", true);
} while (did_something); } while (did_something);
replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something); } while (did_something);
log_suppressed();
} }
log_pop(); log_pop();

View file

@ -315,17 +315,17 @@ struct OptMergeWorker
{ {
if (sharemap.count(cell) > 0) { if (sharemap.count(cell) > 0) {
did_something = true; did_something = true;
log(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str());
for (auto &it : cell->connections()) { for (auto &it : cell->connections()) {
if (cell->output(it.first)) { if (cell->output(it.first)) {
RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first); RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first);
log(" Redirecting output %s: %s = %s\n", it.first.c_str(), log_debug(" Redirecting output %s: %s = %s\n", it.first.c_str(),
log_signal(it.second), log_signal(other_sig)); log_signal(it.second), log_signal(other_sig));
module->connect(RTLIL::SigSig(it.second, other_sig)); module->connect(RTLIL::SigSig(it.second, other_sig));
assign_map.add(it.second, other_sig); assign_map.add(it.second, other_sig);
} }
} }
log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
#ifdef USE_CELL_HASH_CACHE #ifdef USE_CELL_HASH_CACHE
cell_hash_cache.erase(cell); cell_hash_cache.erase(cell);
#endif #endif
@ -336,6 +336,8 @@ struct OptMergeWorker
} }
} }
} }
log_suppressed();
} }
}; };

View file

@ -181,14 +181,14 @@ struct OptMuxtreeWorker
for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++) for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++)
if (root_muxes.at(mux_idx)) { if (root_muxes.at(mux_idx)) {
log(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
root_mux_rerun.erase(mux_idx); root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx); eval_root_mux(mux_idx);
} }
while (!root_mux_rerun.empty()) { while (!root_mux_rerun.empty()) {
int mux_idx = *root_mux_rerun.begin(); int mux_idx = *root_mux_rerun.begin();
log(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell)); log_debug(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell));
log_assert(root_enable_muxes.at(mux_idx)); log_assert(root_enable_muxes.at(mux_idx));
root_mux_rerun.erase(mux_idx); root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx); eval_root_mux(mux_idx);
@ -326,7 +326,7 @@ struct OptMuxtreeWorker
if (abort_count == 0) { if (abort_count == 0) {
root_mux_rerun.insert(m); root_mux_rerun.insert(m);
root_enable_muxes.at(m) = true; root_enable_muxes.at(m) = true;
log(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell));
} else } else
eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1); eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1);
} else } else

View file

@ -369,6 +369,7 @@ struct Pmux2ShiftxPass : public Pass {
dict<SigSpec, pool<int>> seldb; dict<SigSpec, pool<int>> seldb;
SigSpec A = cell->getPort("\\A");
SigSpec B = cell->getPort("\\B"); SigSpec B = cell->getPort("\\B");
SigSpec S = sigmap(cell->getPort("\\S")); SigSpec S = sigmap(cell->getPort("\\S"));
for (int i = 0; i < GetSize(S); i++) for (int i = 0; i < GetSize(S); i++)
@ -419,6 +420,8 @@ struct Pmux2ShiftxPass : public Pass {
choices[val] = i; choices[val] = i;
} }
bool full_pmux = GetSize(choices) == GetSize(S);
// TBD: also find choices that are using signals that are subsets of the bits in "sig" // TBD: also find choices that are using signals that are subsets of the bits in "sig"
if (!verbose) if (!verbose)
@ -634,7 +637,21 @@ struct Pmux2ShiftxPass : public Pass {
log(" range density: %d%%\n", range_density); log(" range density: %d%%\n", range_density);
log(" absolute density: %d%%\n", absolute_density); log(" absolute density: %d%%\n", absolute_density);
bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (max_choice+1 == GetSize(choices)); if (full_pmux) {
int full_density = 100*GetSize(choices) / (1 << GetSize(sig));
log(" full density: %d%%\n", full_density);
if (full_density < min_density) {
full_pmux = false;
} else {
min_choice = 0;
max_choice = (1 << GetSize(sig))-1;
log(" update to full case.\n");
log(" new min choice: %d\n", min_choice);
log(" new max choice: %d\n", max_choice);
}
}
bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (full_pmux || max_choice+1 == GetSize(choices));
log(" full case: %s\n", full_case ? "true" : "false"); log(" full case: %s\n", full_case ? "true" : "false");
// check density percentages // check density percentages
@ -677,6 +694,10 @@ struct Pmux2ShiftxPass : public Pass {
// create data signal // create data signal
SigSpec data(State::Sx, (max_choice+1)*extwidth); SigSpec data(State::Sx, (max_choice+1)*extwidth);
if (full_pmux) {
for (int i = 0; i <= max_choice; i++)
data.replace(i*extwidth, A);
}
for (auto &it : perm_choices) { for (auto &it : perm_choices) {
int position = it.first.as_int()*extwidth; int position = it.first.as_int()*extwidth;
int data_index = it.second; int data_index = it.second;

View file

@ -25,7 +25,8 @@
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" #define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p" #define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
//#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2" //#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
#define ABC_COMMAND_LUT "&st; &fraig; &scorr; &dc2; &retime; &dch -f; &if; &mfs" //#define ABC_COMMAND_LUT "&st; &sweep; &scorr; &dc2; &retime; &dch -f; &if; &mfs; &ps"
#define ABC_COMMAND_LUT "&st; &scorr; &dc2; &retime; &dch -f; &if; &ps -l -m"
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}" #define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" #define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
@ -343,7 +344,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
else else
abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str()); abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str());
abc_script += stringf("&read %s/input.xaig; &ps ", tempdir_name.c_str()); abc_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());
if (!script_file.empty()) { if (!script_file.empty()) {
if (script_file[0] == '+') { if (script_file[0] == '+') {
@ -1401,6 +1402,9 @@ struct Abc9Pass : public Pass {
for (auto mod : design->selected_modules()) for (auto mod : design->selected_modules())
{ {
if (mod->attributes.count("\\abc_box_id"))
continue;
if (mod->processes.size() > 0) { if (mod->processes.size() > 0) {
log("Skipping module %s as it contains processes.\n", log_id(mod)); log("Skipping module %s as it contains processes.\n", log_id(mod));
continue; continue;

View file

@ -72,6 +72,8 @@ struct TechmapWorker
pool<IdString> flatten_done_list; pool<IdString> flatten_done_list;
pool<Cell*> flatten_keep_list; pool<Cell*> flatten_keep_list;
pool<string> log_msg_cache;
struct TechmapWireData { struct TechmapWireData {
RTLIL::Wire *wire; RTLIL::Wire *wire;
RTLIL::SigSpec value; RTLIL::SigSpec value;
@ -390,6 +392,7 @@ struct TechmapWorker
bool log_continue = false; bool log_continue = false;
bool did_something = false; bool did_something = false;
LogMakeDebugHdl mkdebug;
SigMap sigmap(module); SigMap sigmap(module);
@ -547,6 +550,7 @@ struct TechmapWorker
if (extmapper_name == "wrap") { if (extmapper_name == "wrap") {
std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string(); std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string();
log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module)); log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module));
mkdebug.on();
Pass::call_on_module(extmapper_design, extmapper_module, cmd_string); Pass::call_on_module(extmapper_design, extmapper_module, cmd_string);
log_continue = true; log_continue = true;
} }
@ -560,11 +564,21 @@ struct TechmapWorker
goto use_wrapper_tpl; goto use_wrapper_tpl;
} }
log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type));
if (!log_msg_cache.count(msg)) {
log_msg_cache.insert(msg);
log("%s\n", msg.c_str());
}
log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module));
} }
else else
{ {
log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type));
if (!log_msg_cache.count(msg)) {
log_msg_cache.insert(msg);
log("%s\n", msg.c_str());
}
log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str());
if (extmapper_name == "simplemap") { if (extmapper_name == "simplemap") {
if (simplemap_mappers.count(cell->type) == 0) if (simplemap_mappers.count(cell->type) == 0)
@ -662,6 +676,7 @@ struct TechmapWorker
tpl = techmap_cache[key]; tpl = techmap_cache[key];
} else { } else {
if (parameters.size() != 0) { if (parameters.size() != 0) {
mkdebug.on();
derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end())); derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end()));
tpl = map->module(derived_name); tpl = map->module(derived_name);
log_continue = true; log_continue = true;
@ -831,6 +846,7 @@ struct TechmapWorker
if (log_continue) { if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n"); log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false; log_continue = false;
mkdebug.off();
} }
while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { }
} }
@ -842,6 +858,7 @@ struct TechmapWorker
if (log_continue) { if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n"); log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false; log_continue = false;
mkdebug.off();
} }
if (extern_mode && !in_recursion) if (extern_mode && !in_recursion)
@ -861,13 +878,18 @@ struct TechmapWorker
module_queue.insert(m); module_queue.insert(m);
} }
log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name));
cell->type = m_name; cell->type = m_name;
cell->parameters.clear(); cell->parameters.clear();
} }
else else
{ {
log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl)); auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type));
if (!log_msg_cache.count(msg)) {
log_msg_cache.insert(msg);
log("%s\n", msg.c_str());
}
log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl));
techmap_module_worker(design, module, cell, tpl); techmap_module_worker(design, module, cell, tpl);
cell = NULL; cell = NULL;
} }
@ -885,6 +907,7 @@ struct TechmapWorker
if (log_continue) { if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n"); log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false; log_continue = false;
mkdebug.off();
} }
return did_something; return did_something;
@ -1085,7 +1108,7 @@ struct TechmapPass : public Pass {
if (map_files.empty()) { if (map_files.empty()) {
std::istringstream f(stdcells_code); std::istringstream f(stdcells_code);
Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend); Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend);
} else } else {
for (auto &fn : map_files) for (auto &fn : map_files)
if (fn.substr(0, 1) == "%") { if (fn.substr(0, 1) == "%") {
if (!saved_designs.count(fn.substr(1))) { if (!saved_designs.count(fn.substr(1))) {
@ -1104,6 +1127,9 @@ struct TechmapPass : public Pass {
log_cmd_error("Can't open map file `%s'\n", fn.c_str()); log_cmd_error("Can't open map file `%s'\n", fn.c_str());
Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
} }
}
log_header(design, "Continuing TECHMAP pass.\n");
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
for (auto &it : map->modules_) { for (auto &it : map->modules_) {
@ -1211,6 +1237,7 @@ struct FlattenPass : public Pass {
} }
} }
log_suppressed();
log("No more expansions possible.\n"); log("No more expansions possible.\n");
if (top_mod != NULL) if (top_mod != NULL)

View file

@ -28,6 +28,12 @@ $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.box))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.lut))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.box))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.lut))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.box))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.lut))
$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init1.vh)) $(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init1.vh))
$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init2.vh)) $(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init2.vh))

113
techlibs/ice40/abc_hx.box Normal file
View file

@ -0,0 +1,113 @@
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt
# NB: Inputs/Outputs must be ordered alphabetically
# Inputs: C D
# Outputs: Q
SB_DFF 1 1 2 1
- -
# Inputs: C D E
# Outputs: Q
SB_DFFE 2 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFSR 3 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFR 4 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFSS 5 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFS 6 0 3 1
- - -
# Inputs: C D E R
# Outputs: Q
SB_DFFESR 7 0 4 1
- - - -
# Inputs: C D E R
# Outputs: Q
SB_DFFER 8 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFESS 9 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFES 10 0 4 1
- - - -
# Inputs: C D
# Outputs: Q
SB_DFFN 11 0 2 1
- -
# Inputs: C D E
# Outputs: Q
SB_DFFNE 12 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFNSR 13 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFNR 14 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFNSS 15 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFNS 16 0 3 1
- - -
# Inputs: C D E R
# Outputs: Q
SB_DFFNESR 17 0 4 1
- - - -
# Inputs: C D E R
# Outputs: Q
SB_DFFNER 18 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFNESS 19 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFNES 20 0 4 1
- - - -
# Inputs: CI I0 I1
# Outputs: CO
SB_CARRY 21 1 3 1
126 259 231
# Inputs: I0 I1 I2 I3
# Outputs: O
SB_LUT4 22 0 4 1
449 400 379 316

View file

@ -0,0 +1,6 @@
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt
# I3 I2 I1 I0
1 1 316
2 1 316 379
3 1 316 379 400
4 1 316 379 400 449

113
techlibs/ice40/abc_lp.box Normal file
View file

@ -0,0 +1,113 @@
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt
# NB: Inputs/Outputs must be ordered alphabetically
# Inputs: C D
# Outputs: Q
SB_DFF 1 1 2 1
- -
# Inputs: C D E
# Outputs: Q
SB_DFFE 2 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFSR 3 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFR 4 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFSS 5 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFS 6 0 3 1
- - -
# Inputs: C D E R
# Outputs: Q
SB_DFFESR 7 0 4 1
- - - -
# Inputs: C D E R
# Outputs: Q
SB_DFFER 8 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFESS 9 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFES 10 0 4 1
- - - -
# Inputs: C D
# Outputs: Q
SB_DFFN 11 0 2 1
- -
# Inputs: C D E
# Outputs: Q
SB_DFFNE 12 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFNSR 13 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFNR 14 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFNSS 15 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFNS 16 0 3 1
- - -
# Inputs: C D E R
# Outputs: Q
SB_DFFNESR 17 0 4 1
- - - -
# Inputs: C D E R
# Outputs: Q
SB_DFFNER 18 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFNESS 19 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFNES 20 0 4 1
- - - -
# Inputs: CI I0 I1
# Outputs: CO
SB_CARRY 21 1 3 1
186 675 609
# Inputs: I0 I1 I2 I3
# Outputs: O
SB_LUT4 22 0 4 1
465 558 589 661

View file

@ -0,0 +1,6 @@
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt
# I3 I2 I1 I0
1 1 465
2 1 465 558
3 1 465 558 589
4 1 465 558 589 661

113
techlibs/ice40/abc_u.box Normal file
View file

@ -0,0 +1,113 @@
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt
# NB: Inputs/Outputs must be ordered alphabetically
# Inputs: C D
# Outputs: Q
SB_DFF 1 1 2 1
- -
# Inputs: C D E
# Outputs: Q
SB_DFFE 2 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFSR 3 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFR 4 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFSS 5 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFS 6 0 3 1
- - -
# Inputs: C D E R
# Outputs: Q
SB_DFFESR 7 0 4 1
- - - -
# Inputs: C D E R
# Outputs: Q
SB_DFFER 8 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFESS 9 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFES 10 0 4 1
- - - -
# Inputs: C D
# Outputs: Q
SB_DFFN 11 0 2 1
- -
# Inputs: C D E
# Outputs: Q
SB_DFFNE 12 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFNSR 13 0 3 1
- - -
# Inputs: C D R
# Outputs: Q
SB_DFFNR 14 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFNSS 15 0 3 1
- - -
# Inputs: C D S
# Outputs: Q
SB_DFFNS 16 0 3 1
- - -
# Inputs: C D E R
# Outputs: Q
SB_DFFNESR 17 0 4 1
- - - -
# Inputs: C D E R
# Outputs: Q
SB_DFFNER 18 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFNESS 19 0 4 1
- - - -
# Inputs: C D E S
# Outputs: Q
SB_DFFNES 20 0 4 1
- - - -
# Inputs: CI I0 I1
# Outputs: CO
SB_CARRY 21 1 3 1
278 675 609
# Inputs: I0 I1 I2 I3
# Outputs: O
SB_LUT4 22 0 4 1
1285 1231 1205 874

6
techlibs/ice40/abc_u.lut Normal file
View file

@ -0,0 +1,6 @@
# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt
# I3 I2 I1 I0
1 1 874
2 1 874 1205
3 1 874 1205 1231
4 1 874 1205 1231 1285

View file

@ -37,20 +37,24 @@ module \$lut (A, Y);
generate generate
if (WIDTH == 1) begin if (WIDTH == 1) begin
SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), localparam [15:0] INIT = {{8{LUT[1]}}, {8{LUT[0]}}};
.I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0)); SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(1'b0), .I1(1'b0), .I2(1'b0), .I3(A[0]));
end else end else
if (WIDTH == 2) begin if (WIDTH == 2) begin
SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[1]}}, {4{LUT[2]}}, {4{LUT[0]}}};
.I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0)); SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(1'b0), .I1(1'b0), .I2(A[1]), .I3(A[0]));
end else end else
if (WIDTH == 3) begin if (WIDTH == 3) begin
SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[3]}}, {2{LUT[5]}}, {2{LUT[1]}}, {2{LUT[6]}}, {2{LUT[2]}}, {2{LUT[4]}}, {2{LUT[0]}}};
.I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0)); SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(1'b0), .I1(A[2]), .I2(A[1]), .I3(A[0]));
end else end else
if (WIDTH == 4) begin if (WIDTH == 4) begin
localparam [15:0] INIT = {LUT[15], LUT[7], LUT[11], LUT[3], LUT[13], LUT[5], LUT[9], LUT[1], LUT[14], LUT[6], LUT[10], LUT[2], LUT[12], LUT[4], LUT[8], LUT[0]};
SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3])); .I0(A[3]), .I1(A[2]), .I2(A[1]), .I3(A[0]));
end else begin end else begin
wire _TECHMAP_FAIL_ = 1; wire _TECHMAP_FAIL_ = 1;
end end

View file

@ -127,6 +127,7 @@ endmodule
// SiliconBlue Logic Cells // SiliconBlue Logic Cells
(* abc_box_id = 22 *)
module SB_LUT4 (output O, input I0, I1, I2, I3); module SB_LUT4 (output O, input I0, I1, I2, I3);
parameter [15:0] LUT_INIT = 0; parameter [15:0] LUT_INIT = 0;
wire [7:0] s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0]; wire [7:0] s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
@ -135,24 +136,32 @@ module SB_LUT4 (output O, input I0, I1, I2, I3);
assign O = I0 ? s1[1] : s1[0]; assign O = I0 ? s1[1] : s1[0];
endmodule endmodule
(* abc_box_id = 21, lib_whitebox *)
module SB_CARRY (output CO, input I0, I1, CI); module SB_CARRY (output CO, input I0, I1, CI);
assign CO = (I0 && I1) || ((I0 || I1) && CI); assign CO = (I0 && I1) || ((I0 || I1) && CI);
endmodule endmodule
// Positive Edge SiliconBlue FF Cells // Positive Edge SiliconBlue FF Cells
module SB_DFF (output `SB_DFF_REG, input C, D); (* abc_box_id = 1, abc_flop, lib_whitebox *)
module SB_DFF ((* abc_flop_q *) output `SB_DFF_REG, input C, (* abc_flop_d *) input D);
`ifndef ABC_MODEL
always @(posedge C) always @(posedge C)
Q <= D; Q <= D;
`else
always @* Q = D;
`endif
endmodule endmodule
module SB_DFFE (output `SB_DFF_REG, input C, E, D); //(* abc_box_id = 2, abc_flop *)
module SB_DFFE ((* abc_flop_q *) output `SB_DFF_REG, input C, E, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (E) if (E)
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFSR (output `SB_DFF_REG, input C, R, D); //(* abc_box_id = 3, abc_flop *)
module SB_DFFSR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (R) if (R)
Q <= 0; Q <= 0;
@ -160,7 +169,8 @@ module SB_DFFSR (output `SB_DFF_REG, input C, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFR (output `SB_DFF_REG, input C, R, D); //(* abc_box_id = 4, abc_flop *)
module SB_DFFR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
always @(posedge C, posedge R) always @(posedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -168,7 +178,8 @@ module SB_DFFR (output `SB_DFF_REG, input C, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFSS (output `SB_DFF_REG, input C, S, D); //(* abc_box_id = 5, abc_flop *)
module SB_DFFSS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (S) if (S)
Q <= 1; Q <= 1;
@ -176,7 +187,8 @@ module SB_DFFSS (output `SB_DFF_REG, input C, S, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFS (output `SB_DFF_REG, input C, S, D); //(* abc_box_id = 6, abc_flop *)
module SB_DFFS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
always @(posedge C, posedge S) always @(posedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -184,7 +196,8 @@ module SB_DFFS (output `SB_DFF_REG, input C, S, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D); //(* abc_box_id = 7, abc_flop *)
module SB_DFFESR ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (E) begin if (E) begin
if (R) if (R)
@ -194,7 +207,8 @@ module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D);
end end
endmodule endmodule
module SB_DFFER (output `SB_DFF_REG, input C, E, R, D); //(* abc_box_id = 8, abc_flop *)
module SB_DFFER ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
always @(posedge C, posedge R) always @(posedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -202,7 +216,8 @@ module SB_DFFER (output `SB_DFF_REG, input C, E, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D); //(* abc_box_id = 9, abc_flop *)
module SB_DFFESS ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
always @(posedge C) always @(posedge C)
if (E) begin if (E) begin
if (S) if (S)
@ -212,7 +227,8 @@ module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D);
end end
endmodule endmodule
module SB_DFFES (output `SB_DFF_REG, input C, E, S, D); //(* abc_box_id = 10, abc_flop *)
module SB_DFFES ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
always @(posedge C, posedge S) always @(posedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -222,18 +238,21 @@ endmodule
// Negative Edge SiliconBlue FF Cells // Negative Edge SiliconBlue FF Cells
module SB_DFFN (output `SB_DFF_REG, input C, D); //(* abc_box_id = 11, abc_flop *)
module SB_DFFN ((* abc_flop_q *) output `SB_DFF_REG, input C, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNE (output `SB_DFF_REG, input C, E, D); //(* abc_box_id = 12, abc_flop *)
module SB_DFFNE ((* abc_flop_q *) output `SB_DFF_REG, input C, E, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (E) if (E)
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNSR (output `SB_DFF_REG, input C, R, D); //(* abc_box_id = 13, abc_flop *)
module SB_DFFNSR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (R) if (R)
Q <= 0; Q <= 0;
@ -241,7 +260,8 @@ module SB_DFFNSR (output `SB_DFF_REG, input C, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNR (output `SB_DFF_REG, input C, R, D); //(* abc_box_id = 14, abc_flop *)
module SB_DFFNR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
always @(negedge C, posedge R) always @(negedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -249,7 +269,8 @@ module SB_DFFNR (output `SB_DFF_REG, input C, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNSS (output `SB_DFF_REG, input C, S, D); //(* abc_box_id = 15, abc_flop *)
module SB_DFFNSS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (S) if (S)
Q <= 1; Q <= 1;
@ -257,7 +278,8 @@ module SB_DFFNSS (output `SB_DFF_REG, input C, S, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNS (output `SB_DFF_REG, input C, S, D); //(* abc_box_id = 16, abc_flop *)
module SB_DFFNS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
always @(negedge C, posedge S) always @(negedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -265,7 +287,8 @@ module SB_DFFNS (output `SB_DFF_REG, input C, S, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D); //(* abc_box_id = 17, abc_flop *)
module SB_DFFNESR ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (E) begin if (E) begin
if (R) if (R)
@ -275,7 +298,8 @@ module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D);
end end
endmodule endmodule
module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D); //(* abc_box_id = 18, abc_flop *)
module SB_DFFNER ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
always @(negedge C, posedge R) always @(negedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -283,7 +307,8 @@ module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D); //(* abc_box_id = 19, abc_flop *)
module SB_DFFNESS ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
always @(negedge C) always @(negedge C)
if (E) begin if (E) begin
if (S) if (S)
@ -293,7 +318,8 @@ module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D);
end end
endmodule endmodule
module SB_DFFNES (output `SB_DFF_REG, input C, E, S, D); //(* abc_box_id = 20, abc_flop *)
module SB_DFFNES ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
always @(negedge C, posedge S) always @(negedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -304,7 +330,7 @@ endmodule
// SiliconBlue RAM Cells // SiliconBlue RAM Cells
module SB_RAM40_4K ( module SB_RAM40_4K (
output [15:0] RDATA, (* abc_flop_q *) output [15:0] RDATA,
input RCLK, RCLKE, RE, input RCLK, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
input WCLK, WCLKE, WE, input WCLK, WCLKE, WE,
@ -472,7 +498,7 @@ module SB_RAM40_4K (
endmodule endmodule
module SB_RAM40_4KNR ( module SB_RAM40_4KNR (
output [15:0] RDATA, (* abc_flop_q *) output [15:0] RDATA,
input RCLKN, RCLKE, RE, input RCLKN, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
input WCLK, WCLKE, WE, input WCLK, WCLKE, WE,
@ -537,7 +563,7 @@ module SB_RAM40_4KNR (
endmodule endmodule
module SB_RAM40_4KNW ( module SB_RAM40_4KNW (
output [15:0] RDATA, (* abc_flop_q *) output [15:0] RDATA,
input RCLK, RCLKE, RE, input RCLK, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
input WCLKN, WCLKE, WE, input WCLKN, WCLKE, WE,
@ -602,7 +628,7 @@ module SB_RAM40_4KNW (
endmodule endmodule
module SB_RAM40_4KNRNW ( module SB_RAM40_4KNRNW (
output [15:0] RDATA, (* abc_flop_q *) output [15:0] RDATA,
input RCLKN, RCLKE, RE, input RCLKN, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
input WCLKN, WCLKE, WE, input WCLKN, WCLKE, WE,
@ -890,12 +916,13 @@ module SB_WARMBOOT (
); );
endmodule endmodule
(* nomem2reg *)
module SB_SPRAM256KA ( module SB_SPRAM256KA (
input [13:0] ADDRESS, input [13:0] ADDRESS,
input [15:0] DATAIN, input [15:0] DATAIN,
input [3:0] MASKWREN, input [3:0] MASKWREN,
input WREN, CHIPSELECT, CLOCK, STANDBY, SLEEP, POWEROFF, input WREN, CHIPSELECT, CLOCK, STANDBY, SLEEP, POWEROFF,
output reg [15:0] DATAOUT (* abc_flop_q *) output reg [15:0] DATAOUT
); );
`ifndef BLACKBOX `ifndef BLACKBOX
`ifndef EQUIV `ifndef EQUIV

View file

@ -37,6 +37,10 @@ struct SynthIce40Pass : public ScriptPass
log("\n"); log("\n");
log("This command runs synthesis for iCE40 FPGAs.\n"); log("This command runs synthesis for iCE40 FPGAs.\n");
log("\n"); log("\n");
log(" -device < hx | lp | u >\n");
log(" optimise the synthesis netlist for the specified device.\n");
log(" HX is the default target if no device argument specified.\n");
log("\n");
log(" -top <module>\n"); log(" -top <module>\n");
log(" use the specified module as top module\n"); log(" use the specified module as top module\n");
log("\n"); log("\n");
@ -102,7 +106,7 @@ struct SynthIce40Pass : public ScriptPass
} }
string top_opt, blif_file, edif_file, json_file, abc; string top_opt, blif_file, edif_file, json_file, abc, device_opt;
bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr; bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
int min_ce_use; int min_ce_use;
@ -124,6 +128,7 @@ struct SynthIce40Pass : public ScriptPass
abc2 = false; abc2 = false;
vpr = false; vpr = false;
abc = "abc"; abc = "abc";
device_opt = "hx";
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -210,12 +215,18 @@ struct SynthIce40Pass : public ScriptPass
abc = "abc9"; abc = "abc9";
continue; continue;
} }
if (args[argidx] == "-device" && argidx+1 < args.size()) {
device_opt = args[++argidx];
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n"); log_cmd_error("This command only operates on fully selected designs!\n");
if (device_opt != "hx" && device_opt != "lp" && device_opt !="u")
log_cmd_error("Invalid or no device specified: '%s'\n", device_opt.c_str());
log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_header(design, "Executing SYNTH_ICE40 pass.\n");
log_push(); log_push();
@ -229,7 +240,7 @@ struct SynthIce40Pass : public ScriptPass
{ {
if (check_label("begin")) if (check_label("begin"))
{ {
run("read_verilog -lib +/ice40/cells_sim.v"); run("read_verilog -lib -D ABC_MODEL +/ice40/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
run("proc"); run("proc");
} }
@ -282,7 +293,7 @@ struct SynthIce40Pass : public ScriptPass
run("techmap"); run("techmap");
else else
run("techmap -map +/techmap.v -map +/ice40/arith_map.v"); run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
if (retime || help_mode) if ((retime || help_mode) && abc != "abc9")
run(abc + " -dff", "(only if -retime)"); run(abc + " -dff", "(only if -retime)");
run("ice40_opt"); run("ice40_opt");
} }
@ -316,7 +327,10 @@ struct SynthIce40Pass : public ScriptPass
run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
} }
if (!noabc) { if (!noabc) {
run(abc + " -dress -lut 4", "(skip if -noabc)"); if (abc == "abc9")
run(abc + stringf(" -dress -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
else
run(abc + " -lut 4", "(skip if -noabc)");
} }
run("clean"); run("clean");
if (relut || help_mode) { if (relut || help_mode) {

View file

@ -38,7 +38,7 @@ struct SynthIntelPass : public ScriptPass {
log("\n"); log("\n");
log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n"); log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
log(" generate the synthesis netlist for the specified family.\n"); log(" generate the synthesis netlist for the specified family.\n");
log(" MAX10 is the default target if not family argument specified.\n"); log(" MAX10 is the default target if no family argument specified.\n");
log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n"); log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n"); log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
log("\n"); log("\n");
@ -146,7 +146,7 @@ struct SynthIntelPass : public ScriptPass {
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n"); log_cmd_error("This command only operates on fully selected designs!\n");
if (family_opt != "max10" && family_opt !="a10gx" && family_opt != "cyclonev" && family_opt !="cycloneiv" && family_opt !="cycloneive" && family_opt != "cyclone10") if (family_opt != "max10" && family_opt !="a10gx" && family_opt != "cyclonev" && family_opt !="cycloneiv" && family_opt !="cycloneive" && family_opt != "cyclone10")
log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str()); log_cmd_error("Invalid or no family specified: '%s'\n", family_opt.c_str());
log_header(design, "Executing SYNTH_INTEL pass.\n"); log_header(design, "Executing SYNTH_INTEL pass.\n");
log_push(); log_push();

View file

@ -19,4 +19,4 @@ fi
cp ../simple/*.v . cp ../simple/*.v .
DOLLAR='?' DOLLAR='?'
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-p 'hierarchy; synth -run coarse; techmap; opt -full; abc9 -lut 4; stat; check -assert; select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_'" exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-p 'hierarchy; synth -run coarse; techmap; opt -full; abc9 -lut 4; stat; check -assert; select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"

View file

@ -9,8 +9,8 @@ opt
stat stat
# show -width # show -width
select -assert-count 1 t:$sub select -assert-count 1 t:$sub
select -assert-count 2 t:$mux select -assert-count 1 t:$mux
select -assert-count 2 t:$shift select -assert-count 1 t:$shift
select -assert-count 3 t:$shiftx select -assert-count 3 t:$shiftx
design -stash gate design -stash gate