Compare commits

...

7 Commits

Author SHA1 Message Date
Lofty 99f4e37e0b
Merge dcb8cc1d98 into ed5d122174 2026-04-21 17:21:50 +02:00
Lofty ed5d122174
Merge pull request #5793 from YosysHQ/lofty/abc-refactor-4
read/write_xaiger2: further cleanup [sc-269]
2026-04-21 12:13:42 +00:00
N. Engelhardt 2da90a5ad6
Merge pull request #5819 from YosysHQ/xprop_ignore_scopeinfo
xprop: ignore $scopeinfo cells
2026-04-21 09:31:44 +00:00
N. Engelhardt 240f7030b2 xprop: ignore $scopeinfo cells 2026-04-21 10:52:50 +02:00
Lofty 6d715784cd read_xaiger2: further cleanup 2026-04-08 11:08:59 +01:00
Lofty f09afcf581 write_xaiger2: further cleanup 2026-04-08 11:08:44 +01:00
Lofty dcb8cc1d98 abc: remove -fast (again) 2026-03-30 15:22:10 +01:00
4 changed files with 97 additions and 106 deletions

View File

@ -21,6 +21,9 @@
// - gracefully handling inout ports (an error message probably)
// - undriven wires
// - zero-width operands
// - decide how to unify this with cellaigs
// - break up Index into something smaller
// - (C++20) remove snprintf-into-std::ostream weirdness
#include "kernel/register.h"
#include "kernel/newcelltypes.h"
@ -179,6 +182,9 @@ struct Index {
} else {
// AigMaker::node2index
// In XAIGER, the ordering of inputs is used to distinguish between AND
// and XOR gates. AND gates have their first input literal be larger
// than their second, and vice-versa for XORs.
if (a < b) std::swap(a, b);
auto pair = std::make_pair(a, b);
@ -531,7 +537,7 @@ struct Index {
Design *design = index.design;
auto &minfo = leaf_minfo(index);
if (!minfo.suboffsets.count(cell))
log_error("Reached unsupport cell %s (%s in %s)\n", log_id(cell->type), log_id(cell), log_id(cell->module));
log_error("Reached unsupported cell %s (%s in %s)\n", log_id(cell->type), log_id(cell), log_id(cell->module));
Module *def = design->module(cell->type);
log_assert(def);
levels.push_back(Level(index.modules.at(def), cell));
@ -550,13 +556,13 @@ struct Index {
{
std::string ret;
bool first = true;
for (auto pair : levels) {
for (auto [minfo, cell] : levels) {
if (!first)
ret += ".";
if (!pair.second)
ret += RTLIL::unescape_id(pair.first.module->name);
if (!cell)
ret += RTLIL::unescape_id(minfo.module->name);
else
ret += RTLIL::unescape_id(pair.second->name);
ret += RTLIL::unescape_id(cell->name);
first = false;
}
return ret;
@ -565,8 +571,8 @@ struct Index {
int hash() const
{
int hash = 0;
for (auto pair : levels)
hash += (uintptr_t) pair.second;
for (auto [_, cell] : levels)
hash += (uintptr_t) cell;
return hash;
}
@ -575,9 +581,12 @@ struct Index {
if (levels.size() != other.levels.size())
return false;
for (int i = 0; i < levels.size(); i++)
if (levels[i].second != other.levels[i].second)
for (int i = 0; i < levels.size(); i++) {
auto* cell = levels[i].second;
auto* other_cell = other.levels[i].second;
if (cell != other_cell)
return false;
}
return true;
}
@ -740,6 +749,9 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
nands++;
lit_counter += 2;
// In XAIGER, the ordering of inputs is used to distinguish between AND
// and XOR gates. AND gates have their first input literal be larger
// than their second, and vice-versa for XORs.
if (a < b) std::swap(a, b);
encode(out - a);
encode(a - b);
@ -756,7 +768,7 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
log_assert(lit_counter == (Lit) (ninputs + nlatches + nands) * 2 + 2);
char buf[128];
snprintf(buf, sizeof(buf) - 1, "aig %08d %08d %08d %08d %08d\n",
snprintf(buf, sizeof(buf), "aig %08d %08d %08d %08d %08d\n",
ninputs + nlatches + nands, ninputs, nlatches, noutputs, nands);
f->write(buf, strlen(buf));
}
@ -773,8 +785,9 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
log_assert(w);
if (w->port_input && !w->port_output)
for (int i = 0; i < w->width; i++) {
pi_literal(SigBit(w, i)) = lit_counter;
inputs.push_back(SigBit(w, i));
auto bit = SigBit(w, i);
pi_literal(bit) = lit_counter;
inputs.push_back(bit);
lit_counter += 2;
ninputs++;
}
@ -791,7 +804,7 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
for (auto bit : SigSpec(w)) {
(void) bit;
char buf[16];
snprintf(buf, sizeof(buf) - 1, "%08d\n", 0);
snprintf(buf, sizeof(buf), "%08d\n", 0);
f->write(buf, strlen(buf));
noutputs++;
}
@ -804,16 +817,19 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
for (auto w : top->wires())
if (w->port_output) {
for (auto bit : SigSpec(w))
// Each call to eval_po eventually reaches emit_gate and
// encode which writes to f.
outputs.push_back({bit, eval_po(bit)});
}
auto data_end = f->tellp();
// revisit header and the list of outputs
f->seekp(file_start);
write_header();
for (auto pair : outputs) {
for (auto [_, po] : outputs) {
char buf[16];
snprintf(buf, sizeof(buf) - 1, "%08d\n", pair.second);
snprintf(buf, sizeof(buf), "%08d\n", po);
f->write(buf, strlen(buf));
}
// double check we arrived at the same offset for the
@ -822,12 +838,13 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
f->seekp(data_end);
int i = 0;
for (auto pair : outputs) {
if (SigSpec(pair.first).is_wire()) {
for (auto [bit, _] : outputs) {
if (SigSpec(bit).is_wire()) {
// primary output symbol
char buf[32];
snprintf(buf, sizeof(buf) - 1, "o%d ", i);
snprintf(buf, sizeof(buf), "o%d ", i);
f->write(buf, strlen(buf));
std::string name = RTLIL::unescape_id(pair.first.wire->name);
std::string name = RTLIL::unescape_id(bit.wire->name);
f->write(name.data(), name.size());
f->put('\n');
}
@ -836,8 +853,9 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
i = 0;
for (auto bit : inputs) {
if (SigSpec(bit).is_wire()) {
// primary input symbol
char buf[32];
snprintf(buf, sizeof(buf) - 1, "i%d ", i);
snprintf(buf, sizeof(buf), "i%d ", i);
f->write(buf, strlen(buf));
std::string name = RTLIL::unescape_id(bit.wire->name);
f->write(name.data(), name.size());
@ -1242,29 +1260,29 @@ struct XAigerWriter : AigerWriter {
reset_counters();
for (auto w : top->wires())
if (w->port_input && !w->port_output)
for (int i = 0; i < w->width; i++)
ensure_pi(SigBit(w, i));
if (w->port_input && !w->port_output)
for (int i = 0; i < w->width; i++)
ensure_pi(SigBit(w, i));
int proper_po_num = 0;
for (auto w : top->wires())
if (w->port_output)
proper_po_num += w->width;
if (w->port_output)
proper_po_num += w->width;
prep_boxes(proper_po_num);
for (auto w : top->wires())
if (w->port_output)
for (int i = 0; i < w->width; i++) {
// When a module output is directly driven by an opaque box, we
// don't emit it to the mapping file to aid re-integration, but we
// do emit a proper PO.
if (map_file.is_open() && !driven_by_opaque_box.count(SigBit(w, i))) {
map_file << "po " << proper_pos_counter << " " << i
<< " " << w->name.c_str() << "\n";
}
proper_pos_counter++;
pos.push_back(std::make_pair(SigBit(w, i), HierCursor{}));
}
if (w->port_output)
for (int i = 0; i < w->width; i++) {
// When a module output is directly driven by an opaque box, we
// don't emit it to the mapping file to aid re-integration, but we
// do emit a proper PO.
if (map_file.is_open() && !driven_by_opaque_box.count(SigBit(w, i))) {
map_file << "po " << proper_pos_counter << " " << i
<< " " << w->name.c_str() << "\n";
}
proper_pos_counter++;
pos.push_back(std::make_pair(SigBit(w, i), HierCursor{}));
}
this->f = f;
// start with the header
@ -1274,7 +1292,7 @@ struct XAigerWriter : AigerWriter {
// insert padding where output literals will go (once known)
for (auto _ : pos) {
char buf[16];
snprintf(buf, sizeof(buf) - 1, "%08d\n", 0);
snprintf(buf, sizeof(buf), "%08d\n", 0);
f->write(buf, strlen(buf));
}
auto data_start = f->tellp();
@ -1291,35 +1309,36 @@ struct XAigerWriter : AigerWriter {
write_header();
for (auto lit : outlits) {
char buf[16];
snprintf(buf, sizeof(buf) - 1, "%08d\n", lit);
snprintf(buf, sizeof(buf), "%08d\n", lit);
f->write(buf, strlen(buf));
}
// double check we arrived at the same offset for the
// main data section
log_assert(data_start == f->tellp());
// extensions
// XAIGER extensions
f->seekp(0, std::ios::end);
f->put('c');
f->put('c'); // 'c': comment (marks beginning of extensions)
// insert empty 'r' and 's' sections (abc crashes if we provide 'a' without those)
f->put('r');
write_be32(*f, 4);
write_be32(*f, 0);
f->put('s');
write_be32(*f, 4);
write_be32(*f, 0);
f->put('r'); // 'r': register classes
write_be32(*f, 4); // length in bytes
write_be32(*f, 0); // no register classes
f->put('h');
f->put('s'); // 's': register initial values
write_be32(*f, 4); // length in bytes
write_be32(*f, 0); // no register initial values
f->put('h'); // 'h': hierarchy information
// TODO: get rid of std::string copy
std::string h_buffer_str = h_buffer.str();
write_be32(*f, h_buffer_str.size());
f->write(h_buffer_str.data(), h_buffer_str.size());
write_be32(*f, h_buffer_str.size()); // length in bytes
f->write(h_buffer_str.data(), h_buffer_str.size()); // data
#if 1
f->put('a');
write_be32(*f, 0); // size to be filled later
f->put('a'); // 'a': additional AIG (used for holes)
write_be32(*f, 0); // length in bytes (to be filled later)
auto holes_aiger_start = f->tellp();
{
AigerWriter holes_writer;
@ -1331,7 +1350,7 @@ struct XAigerWriter : AigerWriter {
auto holes_aiger_size = f->tellp() - holes_aiger_start;
f->seekp(holes_aiger_start, std::ios::beg);
f->seekp(-4, std::ios::cur);
write_be32(*f, holes_aiger_size);
write_be32(*f, holes_aiger_size); // length in bytes
#endif
f->seekp(0, std::ios::end);

View File

@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
uint32_t read_be32(std::istream &f) {
return ((uint32_t) f.get() << 24) |
((uint32_t) f.get() << 16) |
((uint32_t) f.get() << 16) |
((uint32_t) f.get() << 8) | (uint32_t) f.get();
}
@ -80,9 +80,9 @@ struct Xaiger2Frontend : public Frontend {
extra_args(f, filename, args, argidx, true);
if (map_filename.empty())
log_error("A '-map2' argument required\n");
log_error("A '-map2' argument is required\n");
if (module_name.empty())
log_error("A '-module_name' argument required\n");
log_error("A '-module_name' argument is required\n");
Module *module = design->module(module_name);
if (!module)
@ -128,10 +128,10 @@ struct Xaiger2Frontend : public Frontend {
int woffset;
std::string name;
if (!(map_file >> pi_idx >> woffset >> name))
log_error("Bad map file (1)\n");
log_error("Bad map file: couldn't read 'pi' line\n");
int lit = (2 * pi_idx) + 2;
if (lit < 0 || lit >= (int) bits.size())
log_error("Bad map file (2)\n");
log_error("Bad map file: primary input literal out of range\n");
Wire *w = module->wire(name);
if (!w || woffset < 0 || woffset >= w->width)
log_error("Map file references non-existent signal bit %s[%d]\n",
@ -141,9 +141,9 @@ struct Xaiger2Frontend : public Frontend {
int box_seq;
std::string name;
if (!(map_file >> box_seq >> name))
log_error("Bad map file (20)\n");
log_error("Bad map file: couldn't read 'box' line\n");
if (box_seq < 0)
log_error("Bad map file (21)\n");
log_error("Bad map file: box out of range\n");
Cell *box = module->cell(RTLIL::escape_id(name));
if (!box)
@ -158,7 +158,7 @@ struct Xaiger2Frontend : public Frontend {
}
if (!def)
log_error("Bad map file (22)\n");
log_error("Bad map file: no module found for box type '%s'\n", log_id(box->type));
if (box_seq >= (int) boxes.size()) {
boxes.resize(box_seq + 1);
@ -403,15 +403,15 @@ struct Xaiger2Frontend : public Frontend {
int woffset;
std::string name;
if (!(map_file >> po_idx >> woffset >> name))
log_error("Bad map file (3)\n");
log_error("Bad map file: couldn't read 'po' line\n");
po_idx += co_counter;
if (po_idx < 0 || po_idx >= (int) outputs.size())
log_error("Bad map file (4)\n");
log_error("Bad map file: primary output index out of range\n");
int lit = outputs[po_idx];
if (lit < 0 || lit >= (int) bits.size())
log_error("Bad map file (5)\n");
log_error("Bad map file: primary output literal out of range\n");
if (bits[lit] == RTLIL::Sm)
log_error("Bad map file (6)\n");
log_error("Bad map file: primary output literal is a marker\n");
Wire *w = module->wire(name);
if (!w || woffset < 0 || woffset >= w->width)
log_error("Map file references non-existent signal bit %s[%d]\n",
@ -423,15 +423,15 @@ struct Xaiger2Frontend : public Frontend {
std::string box_name;
std::string box_port;
if (!(map_file >> po_idx >> poffset >> box_name >> box_port))
log_error("Bad map file (7)\n");
log_error("Bad map file: couldn't read 'pseudopo' line\n");
po_idx += co_counter;
if (po_idx < 0 || po_idx >= (int) outputs.size())
log_error("Bad map file (8)\n");
log_error("Bad map file: pseudo primary output index out of range\n");
int lit = outputs[po_idx];
if (lit < 0 || lit >= (int) bits.size())
log_error("Bad map file (9)\n");
log_error("Bad map file: pseudo primary output literal out of range\n");
if (bits[lit] == RTLIL::Sm)
log_error("Bad map file (10)\n");
log_error("Bad map file: pseudo primary output literal is a marker\n");
Cell *cell = module->cell(box_name);
if (!cell || !cell->hasPort(box_port))
log_error("Map file references non-existent box port %s/%s\n",

View File

@ -463,6 +463,10 @@ struct XpropWorker
return;
}
if (cell->type.in(ID($scopeinfo))) {
return;
}
log_warning("Unhandled cell %s (%s) during maybe-x marking\n", log_id(cell), log_id(cell->type));
mark_outputs_maybe_x(cell);
}

View File

@ -35,12 +35,6 @@
#define ABC_COMMAND_SOP "strash; &get -n; &fraig -x; &put; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
#define ABC_COMMAND_DFL "strash; &get -n; &fraig -x; &put; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
#define ABC_FAST_COMMAND_SOP "strash; dretime; cover {I} {P}"
#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/newcelltypes.h"
@ -132,7 +126,6 @@ struct AbcConfig
std::vector<std::string> dont_use_cells;
bool cleanup = true;
bool keepff = false;
bool fast_mode = false;
bool show_tempdir = false;
bool sop_mode = false;
bool abc_dress = false;
@ -1053,16 +1046,15 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
for (int this_cost : config.lut_costs)
if (this_cost != config.lut_costs.front())
all_luts_cost_same = false;
abc_script += config.fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
if (all_luts_cost_same && !config.fast_mode)
abc_script += ABC_COMMAND_LUT;
if (all_luts_cost_same)
abc_script += "; lutpack -S 1";
} else if (!config.liberty_files.empty() || !config.genlib_files.empty())
abc_script += config.constr_file.empty() ?
(config.fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (config.fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
abc_script += config.constr_file.empty() ? ABC_COMMAND_LIB : ABC_COMMAND_CTR;
else if (config.sop_mode)
abc_script += config.fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
abc_script += ABC_COMMAND_SOP;
else
abc_script += config.fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
abc_script += ABC_COMMAND_DFL;
if (config.script_file.empty() && !config.delay_target.empty())
for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
@ -1887,25 +1879,6 @@ struct AbcPass : public Pass {
log(" otherwise:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_DFL));
log("\n");
log(" -fast\n");
log(" use different default scripts that are slightly faster (at the cost\n");
log(" of output quality):\n");
log("\n");
log(" for -liberty/-genlib without -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LIB));
log("\n");
log(" for -liberty/-genlib with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR));
log("\n");
log(" for -lut/-luts:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT));
log("\n");
log(" for -sop:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_SOP));
log("\n");
log(" otherwise:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_DFL));
log("\n");
log(" -liberty <file>\n");
log(" generate netlists for the specified cell library (using the liberty\n");
log(" file format).\n");
@ -2063,7 +2036,6 @@ struct AbcPass : public Pass {
config.abc_dress = design->scratchpad_get_bool("abc.dress", false);
g_arg = design->scratchpad_get_string("abc.g", g_arg);
config.fast_mode = design->scratchpad_get_bool("abc.fast", false);
bool dff_mode = design->scratchpad_get_bool("abc.dff", false);
std::string clk_str;
if (design->scratchpad.count("abc.clk")) {
@ -2172,10 +2144,6 @@ struct AbcPass : public Pass {
g_arg_from_cmd = true;
continue;
}
if (arg == "-fast") {
config.fast_mode = true;
continue;
}
if (arg == "-dff") {
dff_mode = true;
continue;