From 6f1ca02a90a41f66cb5db9ac55b9beafea7716f7 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 16 Jun 2026 12:54:36 +0200 Subject: [PATCH] rtlil_frontend, rtlil_backend: dump statics as strings, comments for src --- backends/rtlil/rtlil_backend.cc | 184 ++++++++++++++++------------ backends/rtlil/rtlil_backend.h | 34 ++---- frontends/rtlil/rtlil_frontend.cc | 195 ++++++++++++++++++++---------- 3 files changed, 252 insertions(+), 161 deletions(-) diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index bdae784fc..c18716ab5 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -32,18 +32,19 @@ USING_YOSYS_NAMESPACE using namespace RTLIL_BACKEND; YOSYS_NAMESPACE_BEGIN -void RTLIL_BACKEND::dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj, const RTLIL::Design *design, bool resolve_src) +void RTLIL_BACKEND::dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj, const RTLIL::Design *design, bool stringify) { // Emit the typed src field first. It is not stored in obj->attributes // — the dict no longer holds ID::src under any circumstance. Backends - // that want to materialize the pipe-joined literal pass resolve_src. + // that want to materialize the pipe-joined literal pass stringify. if (design && design->obj_src_id(obj) != Twine::Null) { TwineRef id = design->obj_src_id(obj); f << stringf("%s" "attribute \\src ", indent); - if (resolve_src) { + if (stringify) { dump_const(f, RTLIL::Const(design->twines.str(id))); } else { dump_const(f, RTLIL::Const(stringf("@%zu", id))); + f << stringf(" # %s", design->twines.str(id).c_str()); } f << stringf("\n"); } @@ -59,7 +60,11 @@ void RTLIL_BACKEND::dump_twines(std::ostream &f, const RTLIL::Design *design) if (!design || design->twines.size() == 0) return; f << stringf("twines\n"); - for (TwineRef id = 0; id < STATIC_TWINE_END; id++) { + std::vector ids; + for (auto it = design->twines.backing.begin(); it != design->twines.backing.end(); ++it) + ids.push_back(STATIC_TWINE_END + design->twines.backing.get_index(it)); + std::sort(ids.begin(), ids.end()); + for (TwineRef id : ids) { const Twine &n = design->twines[id]; if (n.is_leaf()) { f << stringf(" leaf %zu ", id); @@ -141,38 +146,60 @@ void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi } } -void RTLIL_BACKEND::dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint) +static std::string twine_handle(TwineRef ref) +{ + return stringf("%s@%zu", twine_is_public(ref) ? "$pub" : "$priv", (size_t)twine_untag(ref)); +} + +static std::string twine_ref(const RTLIL::Design *design, TwineRef ref, bool stringify) +{ + if (stringify || twine_untag(ref) < STATIC_TWINE_END) + return design->twines.str(ref); + return twine_handle(ref); +} + +static std::string twine_cmt(const RTLIL::Design *design, TwineRef ref, bool stringify) +{ + if (stringify || twine_untag(ref) < STATIC_TWINE_END) + return ""; + return stringf(" # %s", design->twines.str(ref).c_str()); +} + +void RTLIL_BACKEND::dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint, bool stringify) { if (chunk.wire == NULL) { dump_const(f, chunk.data, chunk.width, chunk.offset, autoint); } else { + TwineRef wref = chunk.wire->name.ref(); + std::string name = (stringify || twine_untag(wref) < STATIC_TWINE_END) + ? chunk.wire->name.str() : twine_handle(wref); if (chunk.width == chunk.wire->width && chunk.offset == 0) - f << stringf("%s", chunk.wire->name); + f << name; else if (chunk.width == 1) - f << stringf("%s [%d]", chunk.wire->name, chunk.offset); + f << stringf("%s [%d]", name.c_str(), chunk.offset); else - f << stringf("%s [%d:%d]", chunk.wire->name, chunk.offset+chunk.width-1, chunk.offset); + f << stringf("%s [%d:%d]", name.c_str(), chunk.offset+chunk.width-1, chunk.offset); } } -void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint) +void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint, bool stringify) { if (sig.is_chunk()) { - dump_sigchunk(f, sig.as_chunk(), autoint); + dump_sigchunk(f, sig.as_chunk(), autoint, stringify); } else { f << stringf("{ "); auto chunks = sig.chunks(); for (const auto& chunk : reversed(chunks)) { - dump_sigchunk(f, chunk, false); + dump_sigchunk(f, chunk, false, stringify); f << stringf(" "); } f << stringf("}"); } } -void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire, const RTLIL::Design *design, bool resolve_src) +void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire, const RTLIL::Design *design, bool stringify) { - dump_attributes(f, indent, wire, design, resolve_src); + dump_attributes(f, indent, wire, design, stringify); if (wire->driverCell_) { f << stringf("%s" "# driver %s %s\n", indent, wire->driverCell()->name, wire->driverPort()); @@ -192,12 +219,12 @@ void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL:: f << stringf("inout %d ", wire->port_id); if (wire->is_signed) f << stringf("signed "); - f << stringf("%s\n", wire->name); + f << twine_ref(design, wire->name.ref(), stringify) << twine_cmt(design, wire->name.ref(), stringify) << "\n"; } -void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory, const RTLIL::Design *design, bool resolve_src) +void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory, const RTLIL::Design *design, bool stringify) { - dump_attributes(f, indent, memory, design, resolve_src); + dump_attributes(f, indent, memory, design, stringify); f << stringf("%s" "memory ", indent); if (memory->width != 1) f << stringf("width %d ", memory->width); @@ -205,13 +232,15 @@ void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL f << stringf("size %d ", memory->size); if (memory->start_offset != 0) f << stringf("offset %d ", memory->start_offset); - f << stringf("%s\n", design->twines.str(memory->meta_->name).c_str()); + f << twine_ref(design, memory->meta_->name, stringify) << twine_cmt(design, memory->meta_->name, stringify) << "\n"; } -void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell, const RTLIL::Design *design, bool resolve_src) +void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell, const RTLIL::Design *design, bool stringify) { - dump_attributes(f, indent, cell, design, resolve_src); - f << stringf("%s" "cell %s %s\n", indent, cell->type.str(), cell->name.str()); + dump_attributes(f, indent, cell, design, stringify); + f << stringf("%s" "cell ", indent); + f << twine_ref(design, cell->type.ref(), stringify) << " " << twine_ref(design, cell->name.ref(), stringify) + << twine_cmt(design, cell->type.ref(), stringify) << twine_cmt(design, cell->name.ref(), stringify) << "\n"; for (const auto& [name, param] : reversed(cell->parameters)) { f << stringf("%s parameter%s%s%s %s ", indent, (param.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", @@ -222,53 +251,54 @@ void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL:: f << stringf("\n"); } for (const auto& [port, sig] : reversed(cell->connections_)) { - f << stringf("%s connect %s ", indent, design->twines.unescaped_str(port)); - dump_sigspec(f, sig); - f << stringf("\n"); + f << stringf("%s connect ", indent); + f << twine_ref(design, port, stringify) << " "; + dump_sigspec(f, sig, true, stringify); + f << twine_cmt(design, port, stringify) << "\n"; } f << stringf("%s" "end\n", indent); } -void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs, const RTLIL::Design *design, bool resolve_src) +void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs, const RTLIL::Design *design, bool stringify) { for (const auto& [lhs, rhs] : cs->actions) { f << stringf("%s" "assign ", indent); - dump_sigspec(f, lhs); + dump_sigspec(f, lhs, true, stringify); f << stringf(" "); - dump_sigspec(f, rhs); + dump_sigspec(f, rhs, true, stringify); f << stringf("\n"); } for (const auto& sw : cs->switches) - dump_proc_switch(f, indent, sw, design, resolve_src); + dump_proc_switch(f, indent, sw, design, stringify); } -void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw, const RTLIL::Design *design, bool resolve_src) +void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw, const RTLIL::Design *design, bool stringify) { - dump_attributes(f, indent, sw, design, resolve_src); + dump_attributes(f, indent, sw, design, stringify); f << stringf("%s" "switch ", indent); - dump_sigspec(f, sw->signal); + dump_sigspec(f, sw->signal, true, stringify); f << stringf("\n"); for (const auto case_ : sw->cases) { - dump_attributes(f, indent, case_, design, resolve_src); + dump_attributes(f, indent, case_, design, stringify); f << stringf("%s case ", indent); for (size_t i = 0; i < case_->compare.size(); i++) { if (i > 0) f << stringf(" , "); - dump_sigspec(f, case_->compare[i]); + dump_sigspec(f, case_->compare[i], true, stringify); } f << stringf("\n"); - dump_proc_case_body(f, indent + " ", case_, design, resolve_src); + dump_proc_case_body(f, indent + " ", case_, design, stringify); } f << stringf("%s" "end\n", indent); } -void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy, const RTLIL::Design *design, bool resolve_src) +void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy, const RTLIL::Design *design, bool stringify) { f << stringf("%s" "sync ", indent); switch (sy->type) { @@ -277,7 +307,7 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT if (0) case RTLIL::STp: f << stringf("posedge "); if (0) case RTLIL::STn: f << stringf("negedge "); if (0) case RTLIL::STe: f << stringf("edge "); - dump_sigspec(f, sy->signal); + dump_sigspec(f, sy->signal, true, stringify); f << stringf("\n"); break; case RTLIL::STa: f << stringf("always\n"); break; @@ -287,55 +317,57 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT for (const auto& [lhs, rhs] : sy->actions) { f << stringf("%s update ", indent); - dump_sigspec(f, lhs); + dump_sigspec(f, lhs, true, stringify); f << stringf(" "); - dump_sigspec(f, rhs); + dump_sigspec(f, rhs, true, stringify); f << stringf("\n"); } for (auto &it: sy->mem_write_actions) { - dump_attributes(f, indent, &it, design, resolve_src); + dump_attributes(f, indent, &it, design, stringify); f << stringf("%s memwr %s ", indent, it.memid); - dump_sigspec(f, it.address); + dump_sigspec(f, it.address, true, stringify); f << stringf(" "); - dump_sigspec(f, it.data); + dump_sigspec(f, it.data, true, stringify); f << stringf(" "); - dump_sigspec(f, it.enable); + dump_sigspec(f, it.enable, true, stringify); f << stringf(" "); dump_const(f, it.priority_mask); f << stringf("\n"); } } -void RTLIL_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc, const RTLIL::Design *design, bool resolve_src) +void RTLIL_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc, const RTLIL::Design *design, bool stringify) { - dump_attributes(f, indent, proc, design, resolve_src); - f << stringf("%s" "process %s\n", indent, design->twines.str(proc->meta_->name).c_str()); - dump_proc_case_body(f, indent + " ", &proc->root_case, design, resolve_src); + dump_attributes(f, indent, proc, design, stringify); + f << stringf("%s" "process ", indent); + f << twine_ref(design, proc->meta_->name, stringify) << twine_cmt(design, proc->meta_->name, stringify) << "\n"; + dump_proc_case_body(f, indent + " ", &proc->root_case, design, stringify); for (auto* sync : proc->syncs) - dump_proc_sync(f, indent + " ", sync, design, resolve_src); + dump_proc_sync(f, indent + " ", sync, design, stringify); f << stringf("%s" "end\n", indent); } -void RTLIL_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) +void RTLIL_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right, bool stringify) { f << stringf("%s" "connect ", indent); - dump_sigspec(f, left); + dump_sigspec(f, left, true, stringify); f << stringf(" "); - dump_sigspec(f, right); + dump_sigspec(f, right, true, stringify); f << stringf("\n"); } -void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n, bool resolve_src) +void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n, bool stringify) { bool print_header = flag_m || module->is_selected_whole(); bool print_body = !flag_n || !module->is_selected_whole(); if (print_header) { - dump_attributes(f, indent, module, design, resolve_src); + dump_attributes(f, indent, module, design, stringify); - f << stringf("%s" "module %s\n", indent, design->twines.str(module->meta_->name).c_str()); + f << stringf("%s" "module ", indent); + f << twine_ref(design, module->meta_->name, stringify) << twine_cmt(design, module->meta_->name, stringify) << "\n"; if (!module->avail_parameters.empty()) { if (only_selected) @@ -359,28 +391,28 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu if (!only_selected || design->selected(module, wire)) { if (only_selected) f << stringf("\n"); - dump_wire(f, indent + " ", wire, design, resolve_src); + dump_wire(f, indent + " ", wire, design, stringify); } for (const auto& [_, mem] : reversed(module->memories)) if (!only_selected || design->selected(module, mem)) { if (only_selected) f << stringf("\n"); - dump_memory(f, indent + " ", mem, design, resolve_src); + dump_memory(f, indent + " ", mem, design, stringify); } for (const auto& [_, cell] : reversed(module->cells_)) if (!only_selected || design->selected(module, cell)) { if (only_selected) f << stringf("\n"); - dump_cell(f, indent + " ", cell, design, resolve_src); + dump_cell(f, indent + " ", cell, design, stringify); } for (const auto& [_, process] : reversed(module->processes)) if (!only_selected || design->selected(module, process)) { if (only_selected) f << stringf("\n"); - dump_proc(f, indent + " ", process, design, resolve_src); + dump_proc(f, indent + " ", process, design, stringify); } bool first_conn_line = true; @@ -398,7 +430,7 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu if (show_conn) { if (only_selected && first_conn_line) f << stringf("\n"); - dump_conn(f, indent + " ", lhs, rhs); + dump_conn(f, indent + " ", lhs, rhs, stringify); first_conn_line = false; } } @@ -408,7 +440,7 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu f << stringf("%s" "end\n", indent); } -void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n, bool resolve_src) +void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n, bool stringify) { int init_autoidx = autoidx; @@ -428,7 +460,7 @@ void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl if (only_selected) f << stringf("\n"); f << stringf("autoidx %d\n", autoidx); - if (!resolve_src) + if (!stringify) dump_twines(f, design); } @@ -436,7 +468,7 @@ void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl if (!only_selected || design->selected_module(module->meta_->name)) { if (only_selected) f << stringf("\n"); - dump_module(f, "", module, design, only_selected, flag_m, flag_n, resolve_src); + dump_module(f, "", module, design, only_selected, flag_m, flag_n, stringify); } } @@ -463,18 +495,16 @@ struct RTLILBackend : public Backend { log(" -sort\n"); log(" sort design in-place (used to be default).\n"); log("\n"); - log(" -resolve-src\n"); - log(" expand twine references in src attributes inline. Without\n"); - log(" this flag the design-level twine pool is emitted as a\n"); - log(" `twines` header block and cell src attributes keep their\n"); - log(" compact \"@N\" reference form.\n"); + log(" -readable\n"); + log(" lose information for more readable files.\n"); + log(" Breaks perfect replayability.\n"); log("\n"); } void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { bool selected = false; bool do_sort = false; - bool resolve_src = false; + bool stringify = false; log_header(design, "Executing RTLIL backend.\n"); @@ -489,8 +519,8 @@ struct RTLILBackend : public Backend { do_sort = true; continue; } - if (arg == "-resolve-src") { - resolve_src = true; + if (arg == "-readable") { + stringify = true; continue; } break; @@ -503,7 +533,7 @@ struct RTLILBackend : public Backend { design->sort(); *f << stringf("# Generated by %s\n", yosys_maybe_version()); - RTLIL_BACKEND::dump_design(*f, design, selected, true, false, resolve_src); + RTLIL_BACKEND::dump_design(*f, design, selected, true, false, stringify); } } RTLILBackend; @@ -531,17 +561,15 @@ struct DumpPass : public Pass { log(" -a \n"); log(" like -outfile but append instead of overwrite\n"); log("\n"); - log(" -resolve-src\n"); - log(" expand twine references in src attributes inline. Without\n"); - log(" this flag the design-level twine pool is emitted as a\n"); - log(" `twines` header block and cell src attributes keep their\n"); - log(" compact \"@N\" reference form.\n"); + log(" -readable\n"); + log(" lose information for more readable files.\n"); + log(" Breaks perfect replayability.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { std::string filename; - bool flag_m = false, flag_n = false, append = false, resolve_src = false; + bool flag_m = false, flag_n = false, append = false, stringify = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -565,8 +593,8 @@ struct DumpPass : public Pass { flag_n = true; continue; } - if (arg == "-resolve-src") { - resolve_src = true; + if (arg == "-readable") { + stringify = true; continue; } break; @@ -590,7 +618,7 @@ struct DumpPass : public Pass { f = &buf; } - RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n, resolve_src); + RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n, stringify); if (!empty) { delete f; diff --git a/backends/rtlil/rtlil_backend.h b/backends/rtlil/rtlil_backend.h index 83cd7dd92..3c38e3748 100644 --- a/backends/rtlil/rtlil_backend.h +++ b/backends/rtlil/rtlil_backend.h @@ -31,30 +31,22 @@ YOSYS_NAMESPACE_BEGIN namespace RTLIL_BACKEND { - // If `design` is non-null AND `resolve_src` is true, the ID::src - // attribute is expanded through design->twines so the emitted - // value is the flat path:line.col string. Otherwise the stored value - // is written verbatim — including any "@N" twine references, which - // the matching `twines` header block emitted by dump_design lets the - // parser reconstruct on load. - void dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj, const RTLIL::Design *design = nullptr, bool resolve_src = false); + void dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj, const RTLIL::Design *design = nullptr, bool stringify = false); - // Emit the design-level twine pool as a top-level `twines` block. - // Skipped if the pool is empty. void dump_twines(std::ostream &f, const RTLIL::Design *design); void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true); - void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true); - void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true); - void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire, const RTLIL::Design *design = nullptr, bool resolve_src = false); - void dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory, const RTLIL::Design *design = nullptr, bool resolve_src = false); - void dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell, const RTLIL::Design *design = nullptr, bool resolve_src = false); - void dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs, const RTLIL::Design *design = nullptr, bool resolve_src = false); - void dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw, const RTLIL::Design *design = nullptr, bool resolve_src = false); - void dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy, const RTLIL::Design *design = nullptr, bool resolve_src = false); - void dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc, const RTLIL::Design *design = nullptr, bool resolve_src = false); - void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right); - void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false, bool resolve_src = false); - void dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false, bool resolve_src = false); + void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true, bool stringify = true); + void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true, bool stringify = true); + void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire, const RTLIL::Design *design = nullptr, bool stringify = false); + void dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory, const RTLIL::Design *design = nullptr, bool stringify = false); + void dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell, const RTLIL::Design *design = nullptr, bool stringify = false); + void dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs, const RTLIL::Design *design = nullptr, bool stringify = false); + void dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw, const RTLIL::Design *design = nullptr, bool stringify = false); + void dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy, const RTLIL::Design *design = nullptr, bool stringify = false); + void dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc, const RTLIL::Design *design = nullptr, bool stringify = false); + void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right, bool stringify = true); + void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false, bool stringify = false); + void dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false, bool stringify = false); } YOSYS_NAMESPACE_END diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index fbe4d605d..3f9483780 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -50,6 +50,10 @@ struct RTLILFrontendWorker { RTLIL::Module *current_module; dict attrbuf; + // A resolved "@N" src reference, carried from parse_attribute to the + // object's absorb_attrs site so it lands on the object without being + // flattened into a fresh leaf. + TwineRef pending_src = Twine::Null; std::vector*> switch_stack; std::vector case_stack; @@ -355,6 +359,16 @@ struct RTLILFrontendWorker { parts.push_back(parse_sigspec()); for (auto it = parts.rbegin(); it != parts.rend(); ++it) sig.append(std::move(*it)); + } else if (std::optional handle = try_parse_twine_handle()) { + TwineRef ref = *handle; + RTLIL::Wire *wire = current_module->wire(ref); + if (wire == nullptr) { + if (flag_legalize) + wire = legalize_wire(RTLIL::IdString(design->twines.str(ref))); + else + error("Wire %s not found.", design->twines.str(ref).c_str()); + } + sig = RTLIL::SigSpec(wire); } else { // We could add a special path for parsing IdStrings that must already exist, // as here. @@ -426,7 +440,7 @@ struct RTLILFrontendWorker { void parse_module() { - TwineRef module_name = design->twines.add(parse_id()); + TwineRef module_name = parse_twine(); expect_eol(); bool delete_current_module = false; @@ -453,10 +467,12 @@ struct RTLILFrontendWorker { // Module is about to be discarded — drop its src attribute // rather than push it into a pool we'll never reach. attrbuf.erase(ID::src); + pending_src = Twine::Null; current_module->attributes = std::move(attrbuf); } else { design->add(current_module); current_module->absorb_attrs(std::move(attrbuf)); + flush_src(current_module); } while (true) @@ -518,6 +534,18 @@ struct RTLILFrontendWorker { // is wrong and silently interning it would hide that. if (id == RTLIL::ID::src && (c.flags & RTLIL::CONST_FLAG_STRING)) { std::string raw = c.decode_string(); + if (!raw.empty() && raw[0] == '@') { + // Compact "@N" reference into the `twines` block: carry the + // resolved twine straight to the object (set after its + // absorb_attrs) so its structure is preserved, not flattened. + size_t file_id = 0; + auto [ptr, ec] = std::from_chars(raw.data() + 1, raw.data() + raw.size(), file_id); + if (ec != std::errc() || ptr != raw.data() + raw.size()) + error("Malformed src twine reference %s at line %d", raw.c_str(), line_num); + pending_src = resolve_file_twine(file_id); + expect_eol(); + return; + } if (raw.find('|') != std::string::npos) { log_warning("line %d: src attribute %s contains '|' separators. " "That convention is Yosys-internal; the producing tool " @@ -530,14 +558,79 @@ struct RTLILFrontendWorker { expect_eol(); } + // Apply a pending "@N" src reference to the object just built from attrbuf. + void flush_src(RTLIL::AttrObject *obj) + { + if (pending_src != Twine::Null) { + design->set_src_attribute(obj, pending_src); + pending_src = Twine::Null; + } + } + // Parses a `twines` ... `end` block. Builds twine_remap so subsequent // cell/wire src "@N" references (which use file-local ids) translate // to ids in design->twines. The destination pool may already be // non-empty (multi-file load) — interned/concated nodes are dedup'd // against the existing pool by the pool itself. + // Static ids are universal: a file id below STATIC_TWINE_END denotes the + // same prepopulated twine in every pool, so it maps to itself and is + // never emitted in the `twines` block. + // Resolve a numeric content id from the twines block (a node's own id, or + // a suffix/concat child). Statics are universal — an id below + // STATIC_TWINE_END denotes the same prepopulated twine in every pool; + // locals are remapped per file. Publicity (for $pub@/$priv@ handles) + // travels separately and is reapplied here. Object-use statics never reach + // this path: they are written as escaped names and interned by content. + TwineRef resolve_file_twine(size_t id, bool is_public = false) + { + TwineRef base; + if (id < STATIC_TWINE_END) { + base = TwineRef(id); + } else { + auto it = twine_remap.find(id); + if (it == twine_remap.end()) + error("Unknown twine reference @%zu at line %d", id, line_num); + base = it->second; + } + return twine_tag(base, is_public); + } + + // Parse a "$pub@N"/"$priv@N" twine handle into a resolved, retagged ref. + // Returns nullopt (consuming nothing) if the next token is not a handle. + std::optional try_parse_twine_handle() + { + bool is_public; + if (line.substr(0, 5) == "$pub@") + is_public = true, line = line.substr(5); + else if (line.substr(0, 6) == "$priv@") + is_public = false, line = line.substr(6); + else + return std::nullopt; + return resolve_file_twine(parse_integer(), is_public); + } + + // A twine-typed token at a definition site: a $pub@/$priv@ reference into + // the twines table, or an escaped identifier interned into the pool. + std::optional try_parse_twine() + { + if (std::optional handle = try_parse_twine_handle()) + return handle; + std::optional id = try_parse_id(); + if (!id) + return std::nullopt; + return design->twines.add(std::move(*id)); + } + + TwineRef parse_twine() + { + std::optional t = try_parse_twine(); + if (!t) + error("Expected twine reference or ID, got `%s'.", error_token()); + return *t; + } + void parse_twines() { - dict file_twines; expect_eol(); while (true) { if (try_parse_keyword("end")) @@ -546,7 +639,7 @@ struct RTLILFrontendWorker { size_t file_id = parse_integer(); std::string text = parse_string(); expect_eol(); - file_twines[file_id] = Twine{text}; + twine_remap[file_id] = design->twines.add(Twine{text}); continue; } if (try_parse_keyword("suffix")) { @@ -554,30 +647,21 @@ struct RTLILFrontendWorker { size_t file_parent = parse_integer(); std::string tail = parse_string(); expect_eol(); - if (twine_remap.count(file_parent) == 0) - error("Unknown parent twine @%zu for suffix at line %d", file_parent, line_num); - file_twines[file_id] = Twine{Twine::Suffix{twine_remap[file_parent], tail}}; + twine_remap[file_id] = design->twines.add(Twine{Twine::Suffix{resolve_file_twine(file_parent), tail}}); continue; } if (try_parse_keyword("concat")) { size_t file_id = parse_integer(); std::vector children; - while (!try_parse_eol()) { - size_t child_id = parse_integer(); - if (twine_remap.count(child_id) == 0) - error("Unknown child twine @%zu for concat at line %d", child_id, line_num); - children.push_back(twine_remap[child_id]); - } - file_twines[file_id] = Twine{children}; + while (!try_parse_eol()) + children.push_back(resolve_file_twine(parse_integer())); + twine_remap[file_id] = design->twines.add(Twine{children}); continue; } error("Expected `leaf`, `suffix` or `concat` inside twines block, got `%s'.", error_token()); } expect_eol(); - for (auto &p : file_twines) { - twine_remap[p.first] = design->twines.add(std::move(p.second)); - } } // Release the per-file parser refs gathered during parse_twines. Call @@ -613,18 +697,16 @@ struct RTLILFrontendWorker { while (true) { - std::optional id = try_parse_id(); - if (id) { - TwineRef wire_name = design->twines.lookup(*id); - if (wire_name == Twine::Null) - wire_name = design->twines.add(std::move(*id)); + std::optional name = try_parse_twine(); + if (name) { + TwineRef wire_name = *name; if (current_module->wire(wire_name) != nullptr) { if (flag_legalize) { - log("Legalizing redefinition of wire %s.\n", *id); + log("Legalizing redefinition of wire %s.\n", design->twines.str(wire_name).c_str()); pool wires = {current_module->wire(wire_name)}; current_module->remove(wires); } else - error("RTLIL error: redefinition of wire %s.", *id); + error("RTLIL error: redefinition of wire %s.", design->twines.str(wire_name).c_str()); } wire = current_module->addWire(wire_name); break; @@ -654,6 +736,7 @@ struct RTLILFrontendWorker { } wire->absorb_attrs(std::move(attrbuf)); + flush_src(wire); wire->width = width; wire->upto = upto; wire->start_offset = start_offset; @@ -669,6 +752,7 @@ struct RTLILFrontendWorker { RTLIL::Memory *memory = new RTLIL::Memory; memory->module = current_module; memory->absorb_attrs(std::move(attrbuf)); + flush_src(memory); int width = 1; int start_offset = 0; @@ -676,17 +760,15 @@ struct RTLILFrontendWorker { TwineRef mem_name = Twine::Null; while (true) { - std::optional id = try_parse_id(); - if (id.has_value()) { - mem_name = design->twines.lookup(id->str()); - if (mem_name == Twine::Null) - mem_name = design->twines.add(Twine{id->str()}); + std::optional name = try_parse_twine(); + if (name.has_value()) { + mem_name = *name; if (current_module->memories.count(mem_name) != 0) { if (flag_legalize) { - log("Legalizing redefinition of memory %s.\n", *id); + log("Legalizing redefinition of memory %s.\n", design->twines.str(mem_name).c_str()); current_module->remove(current_module->memories.at(mem_name)); } else - error("RTLIL error: redefinition of memory %s.", *id); + error("RTLIL error: redefinition of memory %s.", design->twines.str(mem_name).c_str()); } memory->meta_->name = mem_name; break; @@ -722,37 +804,27 @@ struct RTLILFrontendWorker { void parse_cell() { - RTLIL::IdString cell_type = parse_id(); - std::string cell_name_str = parse_id(); + TwineRef cell_type_ref = parse_twine(); + TwineRef cell_name_ref = parse_twine(); expect_eol(); - TwineRef cell_name_ref = design->twines.lookup(cell_name_str); - if (cell_name_ref == Twine::Null) - cell_name_ref = design->twines.add(Twine{cell_name_str}); - if (current_module->cell(cell_name_ref) != nullptr) { if (flag_legalize) { + std::string base = design->twines.str(cell_name_ref); std::string new_name_str; int suffix = 1; do { - new_name_str = cell_name_str + "_" + std::to_string(suffix); - TwineRef test_ref = design->twines.lookup(new_name_str); - if (test_ref == Twine::Null) - test_ref = design->twines.add(Twine{new_name_str}); + new_name_str = base + "_" + std::to_string(suffix); + cell_name_ref = design->twines.add(std::string(new_name_str)); ++suffix; - if (current_module->cell(test_ref) == nullptr) - break; - } while (true); - log("Legalizing redefinition of cell %s by renaming to %s.\n", cell_name_str, new_name_str); - cell_name_str = new_name_str; - cell_name_ref = design->twines.lookup(cell_name_str); - if (cell_name_ref == Twine::Null) - cell_name_ref = design->twines.add(Twine{cell_name_str}); + } while (current_module->cell(cell_name_ref) != nullptr); + log("Legalizing redefinition of cell %s by renaming to %s.\n", base.c_str(), new_name_str.c_str()); } else - error("RTLIL error: redefinition of cell %s.", cell_name_str); + error("RTLIL error: redefinition of cell %s.", design->twines.str(cell_name_ref).c_str()); } - RTLIL::Cell *cell = current_module->addCell(cell_name_ref, design->twines.add(Twine{cell_type.str()})); + RTLIL::Cell *cell = current_module->addCell(cell_name_ref, cell_type_ref); cell->absorb_attrs(std::move(attrbuf)); + flush_src(cell); while (true) { @@ -778,13 +850,12 @@ struct RTLILFrontendWorker { cell->parameters.insert({std::move(param_name), std::move(val)}); expect_eol(); } else if (try_parse_keyword("connect")) { - std::string port_name_str = parse_id(); - TwineRef port_name = design->twines.add(Twine{port_name_str}); + TwineRef port_name = parse_twine(); if (cell->hasPort(port_name)) { if (flag_legalize) - log("Legalizing redefinition of cell port %s.", port_name_str); + log("Legalizing redefinition of cell port %s.", design->twines.str(port_name).c_str()); else - error("RTLIL error: redefinition of cell port %s.", port_name_str); + error("RTLIL error: redefinition of cell port %s.", design->twines.str(port_name).c_str()); } cell->setPort(port_name, parse_sigspec()); if (flag_legalize) @@ -845,6 +916,7 @@ struct RTLILFrontendWorker { rule->module = current_module; rule->signal = parse_sigspec(); rule->absorb_attrs(std::move(attrbuf)); + flush_src(rule); switch_stack.back()->push_back(rule); expect_eol(); @@ -863,6 +935,7 @@ struct RTLILFrontendWorker { RTLIL::CaseRule *case_rule = new RTLIL::CaseRule; case_rule->module = current_module; case_rule->absorb_attrs(std::move(attrbuf)); + flush_src(case_rule); rule->cases.push_back(case_rule); switch_stack.push_back(&case_rule->switches); case_stack.push_back(case_rule); @@ -885,22 +958,19 @@ struct RTLILFrontendWorker { void parse_process() { - std::string proc_name_str = parse_id(); + TwineRef proc_name = parse_twine(); expect_eol(); - TwineRef proc_name = design->twines.lookup(proc_name_str); - if (proc_name == Twine::Null) - proc_name = design->twines.add(Twine{proc_name_str}); - if (current_module->processes.count(proc_name) != 0) { if (flag_legalize) { - log("Legalizing redefinition of process %s.\n", proc_name_str); + log("Legalizing redefinition of process %s.\n", design->twines.str(proc_name).c_str()); current_module->remove(current_module->processes.at(proc_name)); } else - error("RTLIL error: redefinition of process %s.", proc_name_str); + error("RTLIL error: redefinition of process %s.", design->twines.str(proc_name).c_str()); } - RTLIL::Process *proc = current_module->addProcess(Twine{proc_name_str}); + RTLIL::Process *proc = current_module->addProcess(proc_name); proc->absorb_attrs(std::move(attrbuf)); + flush_src(proc); switch_stack.clear(); switch_stack.push_back(&proc->root_case.switches); @@ -951,6 +1021,7 @@ struct RTLILFrontendWorker { RTLIL::MemWriteAction act; act.module = current_module; design->absorb_attrs(&act, std::move(attrbuf)); + flush_src(&act); act.memid = parse_id(); act.address = parse_sigspec(); act.data = parse_sigspec();