aboutsummaryrefslogtreecommitdiffstats
path: root/backends
diff options
context:
space:
mode:
Diffstat (limited to 'backends')
-rw-r--r--backends/aiger/xaiger.cc385
1 files changed, 293 insertions, 92 deletions
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 4018cc9de..4bdd54772 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -76,13 +76,16 @@ void aiger_encode(std::ostream &f, int x)
struct XAigerWriter
{
Module *module;
+ bool zinit_mode;
SigMap sigmap;
+ dict<SigBit, bool> init_map;
pool<SigBit> input_bits, output_bits;
dict<SigBit, SigBit> not_map, alias_map;
dict<SigBit, pair<SigBit, SigBit>> and_map;
vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits;
vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits;
+ dict<SigBit, int> ff_bits;
dict<SigBit, float> arrival_times;
vector<pair<int, int>> aig_gates;
@@ -91,6 +94,7 @@ struct XAigerWriter
dict<SigBit, int> aig_map;
dict<SigBit, int> ordered_outputs;
+ dict<SigBit, int> ordered_latches;
vector<Cell*> box_list;
bool omode = false;
@@ -137,7 +141,7 @@ struct XAigerWriter
return a;
}
- XAigerWriter(Module *module, bool holes_mode=false) : module(module), sigmap(module)
+ XAigerWriter(Module *module, bool zinit_mode, bool holes_mode=false) : module(module), zinit_mode(zinit_mode), sigmap(module)
{
pool<SigBit> undriven_bits;
pool<SigBit> unused_bits;
@@ -160,6 +164,14 @@ struct XAigerWriter
for (auto wire : module->wires())
{
+ if (wire->attributes.count("\\init")) {
+ SigSpec initsig = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(wire) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ init_map[initsig[i]] = initval[i] == State::S1;
+ }
+
bool keep = wire->attributes.count("\\keep");
for (int i = 0; i < GetSize(wire); i++)
@@ -204,6 +216,7 @@ struct XAigerWriter
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
bool abc_box_seen = false;
+ std::vector<Cell*> flop_boxes;
for (auto cell : module->selected_cells()) {
if (cell->type == "$_NOT_")
@@ -241,76 +254,90 @@ struct XAigerWriter
log_assert(!holes_mode);
+ if (cell->type == "$__ABC_FF_")
+ {
+ SigBit D = sigmap(cell->getPort("\\D").as_bit());
+ SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
+ unused_bits.erase(D);
+ undriven_bits.erase(Q);
+ alias_map[Q] = D;
+ auto r = ff_bits.insert(std::make_pair(D, 0));
+ log_assert(r.second);
+ continue;
+ }
+
RTLIL::Module* inst_module = module->design->module(cell->type);
if (inst_module && inst_module->attributes.count("\\abc_box_id")) {
abc_box_seen = true;
- if (!holes_mode) {
- toposort.node(cell->name);
- for (const auto &conn : cell->connections()) {
- auto port_wire = inst_module->wire(conn.first);
- if (port_wire->port_input) {
- // Ignore inout for the sake of topographical ordering
- if (port_wire->port_output) continue;
- for (auto bit : sigmap(conn.second))
- bit_users[bit].insert(cell->name);
- }
+ toposort.node(cell->name);
- if (port_wire->port_output)
- for (auto bit : sigmap(conn.second))
- bit_drivers[bit].insert(cell->name);
+ for (const auto &conn : cell->connections()) {
+ auto port_wire = inst_module->wire(conn.first);
+ if (port_wire->port_input) {
+ // Ignore inout for the sake of topographical ordering
+ if (port_wire->port_output) continue;
+ for (auto bit : sigmap(conn.second))
+ bit_users[bit].insert(cell->name);
}
+
+ if (port_wire->port_output)
+ for (auto bit : sigmap(conn.second))
+ bit_drivers[bit].insert(cell->name);
}
+
+ if (inst_module->attributes.count("\\abc9_flop"))
+ flop_boxes.push_back(cell);
+ continue;
}
- else {
- bool cell_known = inst_module || cell->known();
- for (const auto &c : cell->connections()) {
- if (c.second.is_fully_const()) continue;
- auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr;
- auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first);
- auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first);
- if (!is_input && !is_output)
- log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
-
- if (is_input) {
- for (auto b : c.second) {
- Wire *w = b.wire;
- if (!w) continue;
- if (!w->port_output || !cell_known) {
- SigBit I = sigmap(b);
- if (I != b)
- alias_map[b] = I;
- output_bits.insert(b);
- unused_bits.erase(b);
- if (!cell_known)
- keep_bits.insert(b);
- }
+ bool cell_known = inst_module || cell->known();
+ for (const auto &c : cell->connections()) {
+ if (c.second.is_fully_const()) continue;
+ auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr;
+ auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first);
+ auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first);
+ if (!is_input && !is_output)
+ log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
+
+ if (is_input) {
+ for (auto b : c.second) {
+ Wire *w = b.wire;
+ if (!w) continue;
+ if (!w->port_output || !cell_known) {
+ SigBit I = sigmap(b);
+ if (I != b)
+ alias_map[b] = I;
+ output_bits.insert(b);
+ unused_bits.erase(b);
+
+ if (!cell_known)
+ keep_bits.insert(b);
}
}
- if (is_output) {
- int arrival = 0;
- if (port_wire) {
- auto it = port_wire->attributes.find("\\abc_arrival");
- if (it != port_wire->attributes.end()) {
- if (it->second.flags != 0)
- log_error("Attribute 'abc_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type));
- arrival = it->second.as_int();
- }
+ }
+ if (is_output) {
+ int arrival = 0;
+ if (port_wire) {
+ auto it = port_wire->attributes.find("\\abc_arrival");
+ if (it != port_wire->attributes.end()) {
+ if (it->second.flags != 0)
+ log_error("Attribute 'abc_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type));
+ arrival = it->second.as_int();
}
+ }
- for (auto b : c.second) {
- Wire *w = b.wire;
- if (!w) continue;
- input_bits.insert(b);
- SigBit O = sigmap(b);
- if (O != b)
- alias_map[O] = b;
- undriven_bits.erase(O);
-
- if (arrival)
- arrival_times[b] = arrival;
- }
+ for (auto b : c.second) {
+ Wire *w = b.wire;
+ if (!w) continue;
+ input_bits.insert(b);
+ SigBit O = sigmap(b);
+ if (O != b)
+ alias_map[O] = b;
+ undriven_bits.erase(O);
+
+ if (arrival)
+ arrival_times[b] = arrival;
}
}
}
@@ -319,6 +346,45 @@ struct XAigerWriter
}
if (abc_box_seen) {
+ dict<IdString, std::pair<IdString,int>> flop_q;
+ for (auto cell : flop_boxes) {
+ auto r = flop_q.insert(std::make_pair(cell->type, std::make_pair(IdString(), 0)));
+ SigBit d;
+ if (r.second) {
+ for (const auto &conn : cell->connections()) {
+ const SigSpec &rhs = conn.second;
+ if (!rhs.is_bit())
+ continue;
+ if (!ff_bits.count(rhs))
+ continue;
+ r.first->second.first = conn.first;
+ Module *inst_module = module->design->module(cell->type);
+ Wire *wire = inst_module->wire(conn.first);
+ log_assert(wire);
+ auto jt = wire->attributes.find("\\abc_arrival");
+ if (jt != wire->attributes.end()) {
+ if (jt->second.flags != 0)
+ log_error("Attribute 'abc_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(wire), log_id(cell->type));
+ r.first->second.second = jt->second.as_int();
+ }
+ d = rhs;
+ log_assert(d == sigmap(d));
+ break;
+ }
+ }
+ else
+ d = cell->getPort(r.first->second.first);
+
+ auto it = cell->attributes.find(ID(abc9_mergeability));
+ log_assert(it != cell->attributes.end());
+ ff_bits.at(d) = it->second.as_int();
+ cell->attributes.erase(it);
+
+ auto arrival = r.first->second.second;
+ if (arrival)
+ arrival_times[d] = arrival;
+ }
+
for (auto &it : bit_users)
if (bit_drivers.count(it.first))
for (auto driver_cell : bit_drivers.at(it.first))
@@ -414,6 +480,30 @@ struct XAigerWriter
}
}
}
+
+ // Connect $currQ as an input to the flop box
+ if (box_module->get_bool_attribute("\\abc9_flop")) {
+ IdString port_name = "\\$currQ";
+ Wire *w = box_module->wire(port_name);
+ SigSpec rhs = module->wire(stringf("%s.$currQ", cell->name.c_str()));
+ log_assert(GetSize(w) == GetSize(rhs));
+
+ int offset = 0;
+ for (auto b : rhs) {
+ SigBit I = sigmap(b);
+ if (b == RTLIL::Sx)
+ b = State::S0;
+ else if (I != b) {
+ if (I == RTLIL::Sx)
+ alias_map[b] = State::S0;
+ else
+ alias_map[b] = I;
+ }
+ co_bits.emplace_back(b, cell, port_name, offset++, 0);
+ unused_bits.erase(b);
+ }
+ }
+
box_list.emplace_back(cell);
}
@@ -458,12 +548,15 @@ struct XAigerWriter
undriven_bits.erase(bit);
if (!undriven_bits.empty() && !holes_mode) {
+ bool whole_module = module->design->selected_whole_module(module->name);
undriven_bits.sort();
for (auto bit : undriven_bits) {
- log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit));
+ if (whole_module)
+ log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit));
input_bits.insert(bit);
}
- log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module));
+ if (whole_module)
+ log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module));
}
if (holes_mode) {
@@ -492,10 +585,20 @@ struct XAigerWriter
aig_map[bit] = 2*aig_m;
}
+ for (const auto &i : ff_bits) {
+ const SigBit &bit = i.first;
+ aig_m++, aig_i++;
+ log_assert(!aig_map.count(bit));
+ aig_map[bit] = 2*aig_m;
+ }
+
+ dict<SigBit, int> ff_aig_map;
for (auto &c : ci_bits) {
RTLIL::SigBit bit = std::get<0>(c);
aig_m++, aig_i++;
- aig_map[bit] = 2*aig_m;
+ auto r = aig_map.insert(std::make_pair(bit, 2*aig_m));
+ if (!r.second)
+ ff_aig_map[bit] = 2*aig_m;
}
for (auto &c : co_bits) {
@@ -514,6 +617,17 @@ struct XAigerWriter
aig_outputs.push_back(bit2aig(bit));
}
+ for (auto &i : ff_bits) {
+ const SigBit &bit = i.first;
+ aig_o++;
+ aig_outputs.push_back(ff_aig_map.at(bit));
+ }
+
+ if (output_bits.empty()) {
+ aig_o++;
+ aig_outputs.push_back(0);
+ omode = true;
+ }
}
void write_aiger(std::ostream &f, bool ascii_mode)
@@ -583,14 +697,14 @@ struct XAigerWriter
std::stringstream h_buffer;
auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
write_h_buffer(1);
- log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits));
- write_h_buffer(input_bits.size() + ci_bits.size());
- log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits));
- write_h_buffer(output_bits.size() + GetSize(co_bits));
- log_debug("piNum = %d\n", GetSize(input_bits));
- write_h_buffer(input_bits.size());
- log_debug("poNum = %d\n", GetSize(output_bits));
- write_h_buffer(output_bits.size());
+ log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ff_bits) + GetSize(ci_bits));
+ write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size());
+ log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(ff_bits) + GetSize(co_bits));
+ write_h_buffer(output_bits.size() + GetSize(ff_bits) + GetSize(co_bits));
+ log_debug("piNum = %d\n", GetSize(input_bits) + GetSize(ff_bits));
+ write_h_buffer(input_bits.size() + ff_bits.size());
+ log_debug("poNum = %d\n", GetSize(output_bits) + GetSize(ff_bits));
+ write_h_buffer(output_bits.size() + ff_bits.size());
log_debug("boxNum = %d\n", GetSize(box_list));
write_h_buffer(box_list.size());
@@ -606,19 +720,27 @@ struct XAigerWriter
//for (auto bit : output_bits)
// write_o_buffer(0);
- if (!box_list.empty()) {
+ if (!box_list.empty() || !ff_bits.empty()) {
RTLIL::Module *holes_module = module->design->addModule("$__holes__");
log_assert(holes_module);
+ dict<IdString, Cell*> cell_cache;
+
int port_id = 1;
int box_count = 0;
for (auto cell : box_list) {
RTLIL::Module* box_module = module->design->module(cell->type);
+ log_assert(box_module);
+ IdString derived_name = box_module->derive(module->design, cell->parameters);
+ box_module = module->design->module(derived_name);
+
int box_inputs = 0, box_outputs = 0;
- Cell *holes_cell = nullptr;
- if (box_module->get_bool_attribute("\\whitebox")) {
+ auto r = cell_cache.insert(std::make_pair(derived_name, nullptr));
+ Cell *holes_cell = r.first->second;
+ if (r.second && !holes_cell && box_module->get_bool_attribute("\\whitebox")) {
holes_cell = holes_module->addCell(cell->name, cell->type);
holes_cell->parameters = cell->parameters;
+ r.first->second = holes_cell;
}
// NB: Assume box_module->ports are sorted alphabetically
@@ -628,7 +750,7 @@ struct XAigerWriter
log_assert(w);
RTLIL::Wire *holes_wire;
RTLIL::SigSpec port_wire;
- if (w->port_input) {
+ if (w->port_input)
for (int i = 0; i < GetSize(w); i++) {
box_inputs++;
holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
@@ -641,9 +763,6 @@ struct XAigerWriter
if (holes_cell)
port_wire.append(holes_wire);
}
- if (!port_wire.empty())
- holes_cell->setPort(w->name, port_wire);
- }
if (w->port_output) {
box_outputs += GetSize(w);
for (int i = 0; i < GetSize(w); i++) {
@@ -659,9 +778,36 @@ struct XAigerWriter
else
holes_module->connect(holes_wire, State::S0);
}
- if (!port_wire.empty())
+ }
+ if (!port_wire.empty()) {
+ if (r.second)
holes_cell->setPort(w->name, port_wire);
+ else
+ holes_module->connect(port_wire, holes_cell->getPort(w->name));
+ }
+ }
+
+ // For flops only, create an extra input for $currQ
+ if (box_module->get_bool_attribute("\\abc9_flop")) {
+ log_assert(holes_cell);
+
+ Wire *w = box_module->wire("\\$currQ");
+ Wire *holes_wire;
+ RTLIL::SigSpec port_wire;
+ for (int i = 0; i < GetSize(w); i++) {
+ box_inputs++;
+ holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
+ if (!holes_wire) {
+ holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
+ holes_wire->port_input = true;
+ holes_wire->port_id = port_id++;
+ holes_module->ports.push_back(holes_wire->name);
+ }
+ port_wire.append(holes_wire);
}
+ w = holes_module->addWire(stringf("%s.$currQ", cell->name.c_str()), GetSize(w));
+ w->set_bool_attribute("\\hierconn");
+ holes_module->connect(w, port_wire);
}
write_h_buffer(box_inputs);
@@ -672,13 +818,43 @@ struct XAigerWriter
std::stringstream r_buffer;
auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1);
- write_r_buffer(0);
+ log_debug("flopNum = %d\n", GetSize(ff_bits));
+ write_r_buffer(ff_bits.size());
+ for (const auto &i : ff_bits) {
+ log_assert(i.second > 0);
+ write_r_buffer(i.second);
+ const SigBit &bit = i.first;
+ write_i_buffer(arrival_times.at(bit, 0));
+ //write_o_buffer(0);
+ }
+
f << "r";
std::string buffer_str = r_buffer.str();
int32_t buffer_size_be = to_big_endian(buffer_str.size());
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
f.write(buffer_str.data(), buffer_str.size());
+ std::stringstream s_buffer;
+ auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1);
+ write_s_buffer(ff_bits.size());
+ for (const auto &i : ff_bits) {
+ const SigBit &bit = i.first;
+ auto it = bit.wire->attributes.find("\\init");
+ if (it != bit.wire->attributes.end()) {
+ auto init = it->second[bit.offset];
+ if (init == RTLIL::S1) {
+ write_s_buffer(1);
+ continue;
+ }
+ }
+ write_s_buffer(0);
+ }
+ f << "s";
+ buffer_str = s_buffer.str();
+ buffer_size_be = to_big_endian(buffer_str.size());
+ f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
+ f.write(buffer_str.data(), buffer_str.size());
+
if (holes_module) {
log_push();
@@ -686,35 +862,35 @@ struct XAigerWriter
//holes_module->fixup_ports();
holes_module->check();
- holes_module->design->selection_stack.emplace_back(false);
- RTLIL::Selection& sel = holes_module->design->selection_stack.back();
+ Design *design = holes_module->design;
+ design->selection_stack.emplace_back(false);
+ RTLIL::Selection& sel = design->selection_stack.back();
+ log_assert(design->selected_active_module == module->name.c_str());
+ design->selected_active_module = holes_module->name.str();
sel.select(holes_module);
- // TODO: Should not need to opt_merge if we only instantiate
- // each box type once...
- Pass::call(holes_module->design, "opt_merge -share_all");
-
- Pass::call(holes_module->design, "flatten -wb");
+ Pass::call(design, "flatten -wb");
// TODO: Should techmap/aigmap/check all lib_whitebox-es just once,
// instead of per write_xaiger call
- Pass::call(holes_module->design, "techmap");
- Pass::call(holes_module->design, "aigmap");
+ Pass::call(design, "techmap");
+ Pass::call(design, "aigmap");
for (auto cell : holes_module->cells())
if (!cell->type.in("$_NOT_", "$_AND_"))
log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
- holes_module->design->selection_stack.pop_back();
+ design->selection_stack.pop_back();
+ design->selected_active_module = module->name.str();
// Move into a new (temporary) design so that "clean" will only
// operate (and run checks on) this one module
RTLIL::Design *holes_design = new RTLIL::Design;
- holes_module->design->modules_.erase(holes_module->name);
+ design->modules_.erase(holes_module->name);
holes_design->add(holes_module);
Pass::call(holes_design, "clean -purge");
std::stringstream a_buffer;
- XAigerWriter writer(holes_module, true /* holes_mode */);
+ XAigerWriter writer(holes_module, false /*zinit_mode*/, true /* holes_mode */);
writer.write_aiger(a_buffer, false /*ascii_mode*/);
delete holes_design;
@@ -752,7 +928,9 @@ struct XAigerWriter
void write_map(std::ostream &f, bool verbose_map)
{
dict<int, string> input_lines;
+ dict<int, string> init_lines;
dict<int, string> output_lines;
+ dict<int, string> latch_lines;
dict<int, string> wire_lines;
for (auto wire : module->wires())
@@ -773,7 +951,11 @@ struct XAigerWriter
if (output_bits.count(b)) {
int o = ordered_outputs.at(b);
- output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), i, log_id(wire));
+ int init = zinit_mode ? 0 : 2;
+ auto it = init_map.find(b);
+ if (it != init_map.end())
+ init = it->second ? 1 : 0;
+ output_lines[o] += stringf("output %d %d %s %d\n", o - GetSize(co_bits), i, log_id(wire), init);
continue;
}
@@ -792,6 +974,10 @@ struct XAigerWriter
f << it.second;
log_assert(input_lines.size() == input_bits.size());
+ init_lines.sort();
+ for (auto &it : init_lines)
+ f << it.second;
+
int box_count = 0;
for (auto cell : box_list)
f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name));
@@ -802,6 +988,12 @@ struct XAigerWriter
for (auto &it : output_lines)
f << it.second;
log_assert(output_lines.size() == output_bits.size());
+ if (omode && output_bits.empty())
+ f << "output " << output_lines.size() << " 0 $__dummy__\n";
+
+ latch_lines.sort();
+ for (auto &it : latch_lines)
+ f << it.second;
wire_lines.sort();
for (auto &it : wire_lines)
@@ -823,6 +1015,10 @@ struct XAigerBackend : public Backend {
log(" -ascii\n");
log(" write ASCII version of AIGER format\n");
log("\n");
+ log(" -zinit\n");
+ log(" convert FFs to zero-initialized FFs, adding additional inputs for\n");
+ log(" uninitialized FFs.\n");
+ log("\n");
log(" -map <filename>\n");
log(" write an extra file with port and latch symbols\n");
log("\n");
@@ -833,6 +1029,7 @@ struct XAigerBackend : public Backend {
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool ascii_mode = false;
+ bool zinit_mode = false;
bool verbose_map = false;
std::string map_filename;
@@ -845,6 +1042,10 @@ struct XAigerBackend : public Backend {
ascii_mode = true;
continue;
}
+ if (args[argidx] == "-zinit") {
+ zinit_mode = true;
+ continue;
+ }
if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
map_filename = args[++argidx];
continue;
@@ -863,7 +1064,7 @@ struct XAigerBackend : public Backend {
if (top_module == nullptr)
log_error("Can't find top module in current design!\n");
- XAigerWriter writer(top_module);
+ XAigerWriter writer(top_module, zinit_mode);
writer.write_aiger(*f, ascii_mode);
if (!map_filename.empty()) {