Skip to content

Commit b7d09cd

Browse files
committed
write_xaiger2: emit "y" identity + map2 src for std-cell origin tracking
Enables `\src` source-location provenance through the abc9/std-cell mapping path. write_xaiger2 now emits: - a "y" identity extension in the xaig (each AIG object maps to itself) so ABC seeds per-object origin tracking; - "src <obj_id> <src_value>" lines in the map2 file so read_xaiger2 -sc_mapping can translate propagated origin object-ids back to \src strings. Mechanism mirrors backends/aiger/xaiger.cc: an RAII SrcGuard threads the current RTL cell's \src through impl_op's recursive decomposition, emit_gate tags each new AIG object, and the "y"/src sections are written in XAigerWriter::write. Validated end-to-end on a combinational design (sky130_fd_sc_hd): write_xaiger2 -> abc_new (ABC &nf with &origins) -> read_xaiger2 yields \src on 100% of mapped std cells, including multi-source merging (e.g. "comb.v:3.26-3.31|comb.v:3.16-3.21"). Depends on the ABC-side origin tracking (berkeley-abc/abc#487) and the AIGER "M"-skip reader fix. Scoped to combinational designs; see TODO(boxes) notes for the sequential/box object-numbering follow-up. Co-developed-by: Claude Code v2.1.195 (claude-opus-4-8)
1 parent bd21c18 commit b7d09cd

1 file changed

Lines changed: 55 additions & 0 deletions

File tree

backends/aiger2/aiger.cc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ struct Index {
7878

7979
dict<Module *, ModuleInfo> modules;
8080

81+
// \src-provenance tracking for the "y" identity extension / map2 src lines.
82+
// current_src is the \src of the RTL cell currently being decomposed in
83+
// impl_op (save/restored across recursion via an RAII guard). emit_gate
84+
// records it against the new AIG object id.
85+
dict<int, std::string> aig_obj_src;
86+
std::string current_src;
87+
8188
int index_wires(ModuleInfo &info, RTLIL::Module *m)
8289
{
8390
int sum = 0;
@@ -258,8 +265,24 @@ struct Index {
258265
return lits.front();
259266
}
260267

268+
// RAII helper: restores current_src on scope exit (impl_op has many
269+
// early returns and recurses into visit()).
270+
struct SrcGuard {
271+
std::string &slot;
272+
std::string saved;
273+
SrcGuard(std::string &slot) : slot(slot), saved(slot) {}
274+
~SrcGuard() { slot = saved; }
275+
};
276+
261277
Lit impl_op(HierCursor &cursor, Cell *cell, IdString oport, int obit)
262278
{
279+
SrcGuard src_guard(current_src);
280+
{
281+
std::string s = cell->get_string_attribute(ID::src);
282+
if (!s.empty())
283+
current_src = s;
284+
}
285+
263286
if (cell->type.in(REDUCE_OPS, LOGIC_OPS, CMP_OPS) && obit != 0) {
264287
return CFALSE;
265288
} else if (cell->type.in(CMP_OPS)) {
@@ -715,6 +738,11 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
715738
nands++;
716739
lit_counter += 2;
717740

741+
// Record the \src of the RTL cell this AND object came from, keyed
742+
// by object id (literal >> 1), for the "y"/map2 src-provenance flow.
743+
if (!current_src.empty())
744+
aig_obj_src[out >> 1] = current_src;
745+
718746
if (a < b) std::swap(a, b);
719747
encode(out - a);
720748
encode(a - b);
@@ -1258,6 +1286,15 @@ struct XAigerWriter : AigerWriter {
12581286
for (auto &pair : pos)
12591287
outlits.push_back(eval_po(pair.first, &pair.second));
12601288

1289+
// Emit map2 'src' lines now that all AIG objects (and their recorded
1290+
// \src) exist. Goes after the 'po' lines written above; map_file is
1291+
// not written again after this point.
1292+
// TODO(boxes): object ids here are the flat combinational AIG ids;
1293+
// box/hierarchy renumbering on read-back is not accounted for.
1294+
if (map_file.is_open())
1295+
for (auto &it : aig_obj_src)
1296+
map_file << "src " << it.first << " " << it.second << "\n";
1297+
12611298
// revisit header and the list of outputs
12621299
f->seekp(0);
12631300
ninputs = pis.size();
@@ -1309,6 +1346,24 @@ struct XAigerWriter : AigerWriter {
13091346
#endif
13101347
f->seekp(0, std::ios::end);
13111348

1349+
// Write "y" extension: identity mapping so ABC can seed per-object
1350+
// origin tracking (each AIG object maps to itself). Mirrors the old
1351+
// writer backends/aiger/xaiger.cc (the section length is BE32, the
1352+
// payload ints are written raw/native-endian as ABC's reader expects).
1353+
// n_objs counts all AIG vars including const0: lit_counter/2 at this
1354+
// point (const0 = var 0, then PIs and ANDs).
1355+
// TODO(boxes): assumes the flat combinational object numbering; box /
1356+
// hierarchy renumbering is not handled here.
1357+
{
1358+
int n_objs = lit_counter / 2;
1359+
f->put('y');
1360+
write_be32(*f, 4 * n_objs);
1361+
for (int i = 0; i < n_objs; i++) {
1362+
uint32_t lit = 2 * i;
1363+
f->write(reinterpret_cast<const char *>(&lit), sizeof(lit));
1364+
}
1365+
}
1366+
13121367
if (mapping_prep) {
13131368
std::vector<Cell *> to_remove_cells;
13141369
for (auto cell : top->cells())

0 commit comments

Comments
 (0)