diff --git a/Makefile b/Makefile index ab399ef2e..0a73fac89 100644 --- a/Makefile +++ b/Makefile @@ -646,6 +646,7 @@ $(eval $(call add_include_file,kernel/sexpr.h)) $(eval $(call add_include_file,kernel/sigtools.h)) $(eval $(call add_include_file,kernel/threading.h)) $(eval $(call add_include_file,kernel/timinginfo.h)) +$(eval $(call add_include_file,kernel/twine.h)) $(eval $(call add_include_file,kernel/utils.h)) $(eval $(call add_include_file,kernel/yosys.h)) $(eval $(call add_include_file,kernel/yosys_common.h)) @@ -670,7 +671,7 @@ ifeq ($(ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS),1) OBJS += kernel/log_compat.o endif OBJS += kernel/binding.o kernel/tclapi.o -OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o +OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o kernel/twine.o OBJS += kernel/drivertools.o kernel/functional.o kernel/threading.o ifeq ($(ENABLE_ZLIB),1) OBJS += kernel/fstdata.o diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 497ecc954..927e7fa1e 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -121,8 +121,9 @@ struct BtorWorker { string infostr = obj->name.unescape(); if (!srcsym && !print_internal_names && infostr[0] == '$') return ""; - if (obj->attributes.count(ID::src)) { - string src = obj->attributes.at(ID::src).decode_string().c_str(); + if (obj->has_attribute(ID::src)) { + string raw_src = module && module->design ? obj->get_src_attribute(&module->design->src_twines) : std::string(); + string src = module && module->design ? module->design->resolve_src(raw_src) : raw_src; if (srcsym && infostr[0] == '$') { std::replace(src.begin(), src.end(), ' ', '_'); if (srcsymbols.count(src) || module->count_id("\\" + src)) { diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index 9d3392e99..3e9217df9 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -404,8 +404,8 @@ struct EdifBackend : public Backend { { auto count_nontrivial_attr = [](Wire *w) { + // src isn't in attributes anymore (typed field). int count = w->attributes.size(); - count -= w->attributes.count(ID::src); count -= w->attributes.count(ID::unused_bits); return count; }; diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index db5036552..537d0bb80 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -42,9 +42,9 @@ static const FDirection FD_OUT = 0x2; static const FDirection FD_INOUT = 0x3; static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width -std::string getFileinfo(const RTLIL::AttrObject *design_entity) +std::string getFileinfo(const RTLIL::AttrObject *design_entity, const RTLIL::Design *design = nullptr) { - std::string src(design_entity->get_src_attribute()); + std::string src = design ? design_entity->get_src_attribute(&design->src_twines) : std::string(); std::string fileinfo_str = src.empty() ? "" : "@[" + src + "]"; return fileinfo_str; } diff --git a/backends/json/json.cc b/backends/json/json.cc index 23d18fb15..0a53e14e1 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -130,9 +130,16 @@ struct JsonWriter } } - void write_parameters(const dict ¶meters, bool for_module=false) + void write_parameters(const dict ¶meters, bool for_module=false, const RTLIL::AttrObject *src_obj=nullptr) { bool first = true; + // Emit the typed src field first if present — it lives outside the + // attribute dict after the typed-src migration. + if (src_obj && src_obj->src_id() != Twine::Null && design) { + f << stringf("\n %s%s: ", for_module ? "" : " ", get_name(RTLIL::ID::src)); + write_parameter_value(RTLIL::Const(src_obj->get_src_attribute(&design->src_twines))); + first = false; + } for (auto ¶m : parameters) { f << stringf("%s\n", first ? "" : ","); f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first)); @@ -158,7 +165,7 @@ struct JsonWriter f << stringf(" %s: {\n", get_name(module->name)); f << stringf(" \"attributes\": {"); - write_parameters(module->attributes, /*for_module=*/true); + write_parameters(module->attributes, /*for_module=*/true, module); f << stringf("\n },\n"); if (module->parameter_default_values.size()) { @@ -210,7 +217,7 @@ struct JsonWriter write_parameters(c->parameters); f << stringf("\n },\n"); f << stringf(" \"attributes\": {"); - write_parameters(c->attributes); + write_parameters(c->attributes, false, c); f << stringf("\n },\n"); if (c->known()) { f << stringf(" \"port_directions\": {"); @@ -248,7 +255,7 @@ struct JsonWriter f << stringf(" %s: {\n", get_name(it.second->name)); f << stringf(" \"hide_name\": %s,\n", it.second->name[0] == '$' ? "1" : "0"); f << stringf(" \"attributes\": {"); - write_parameters(it.second->attributes); + write_parameters(it.second->attributes, false, it.second); f << stringf("\n },\n"); f << stringf(" \"width\": %d,\n", it.second->width); f << stringf(" \"start_offset\": %d,\n", it.second->start_offset); @@ -275,7 +282,7 @@ struct JsonWriter if (w->is_signed) f << stringf(" \"signed\": %d,\n", w->is_signed); f << stringf(" \"attributes\": {"); - write_parameters(w->attributes); + write_parameters(w->attributes, false, w); f << stringf("\n }\n"); f << stringf(" }"); first = false; diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index d47bebf82..7c260b537 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -32,8 +32,20 @@ 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) +void RTLIL_BACKEND::dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj, const RTLIL::Design *design, bool resolve_src) { + // 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. + if (obj->src_id() != Twine::Null && design) { + f << stringf("%s" "attribute \\src ", indent); + if (resolve_src) { + dump_const(f, RTLIL::Const(design->src_twines.flatten(obj->src_id()))); + } else { + dump_const(f, RTLIL::Const(TwinePool::format_ref(obj->src_id()))); + } + f << stringf("\n"); + } for (const auto& [name, value] : reversed(obj->attributes)) { f << stringf("%s" "attribute %s ", indent, name); dump_const(f, value); @@ -41,6 +53,30 @@ void RTLIL_BACKEND::dump_attributes(std::ostream &f, std::string indent, const R } } +void RTLIL_BACKEND::dump_twines(std::ostream &f, const RTLIL::Design *design) +{ + if (!design || design->src_twines.size() == 0) + return; + f << stringf("twines\n"); + design->src_twines.for_each_live([&](Twine::Id id, const Twine &n) { + if (n.is_leaf()) { + f << stringf(" leaf %u ", id); + dump_const(f, RTLIL::Const(n.leaf())); + f << stringf("\n"); + } else if (n.is_suffix()) { + f << stringf(" suffix %u %u ", id, n.suffix().parent); + dump_const(f, RTLIL::Const(n.suffix().tail)); + f << stringf("\n"); + } else { + f << stringf(" concat %u", id); + for (Twine::Id c : n.children()) + f << stringf(" %u", c); + f << stringf("\n"); + } + }); + f << stringf("end\n"); +} + void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint) { if (width < 0) @@ -132,9 +168,9 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo } } -void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire) +void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire, const RTLIL::Design *design, bool resolve_src) { - dump_attributes(f, indent, wire); + dump_attributes(f, indent, wire, design, resolve_src); if (wire->driverCell_) { f << stringf("%s" "# driver %s %s\n", indent, wire->driverCell()->name, wire->driverPort()); @@ -157,9 +193,9 @@ void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL:: f << stringf("%s\n", wire->name); } -void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory) +void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory, const RTLIL::Design *design, bool resolve_src) { - dump_attributes(f, indent, memory); + dump_attributes(f, indent, memory, design, resolve_src); f << stringf("%s" "memory ", indent); if (memory->width != 1) f << stringf("width %d ", memory->width); @@ -170,9 +206,9 @@ void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL f << stringf("%s\n", memory->name); } -void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell) +void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell, const RTLIL::Design *design, bool resolve_src) { - dump_attributes(f, indent, cell); + dump_attributes(f, indent, cell, design, resolve_src); f << stringf("%s" "cell %s %s\n", indent, cell->type, cell->name); for (const auto& [name, param] : reversed(cell->parameters)) { f << stringf("%s parameter%s%s%s %s ", indent, @@ -191,7 +227,7 @@ void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL:: f << stringf("%s" "end\n", indent); } -void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs) +void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs, const RTLIL::Design *design, bool resolve_src) { for (const auto& [lhs, rhs] : cs->actions) { f << stringf("%s" "assign ", indent); @@ -202,12 +238,12 @@ void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, con } for (const auto& sw : cs->switches) - dump_proc_switch(f, indent, sw); + dump_proc_switch(f, indent, sw, design, resolve_src); } -void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw) +void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw, const RTLIL::Design *design, bool resolve_src) { - dump_attributes(f, indent, sw); + dump_attributes(f, indent, sw, design, resolve_src); f << stringf("%s" "switch ", indent); dump_sigspec(f, sw->signal); @@ -215,7 +251,7 @@ void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const for (const auto case_ : sw->cases) { - dump_attributes(f, indent, case_); + dump_attributes(f, indent, case_, design, resolve_src); f << stringf("%s case ", indent); for (size_t i = 0; i < case_->compare.size(); i++) { if (i > 0) @@ -224,13 +260,13 @@ void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const } f << stringf("\n"); - dump_proc_case_body(f, indent + " ", case_); + dump_proc_case_body(f, indent + " ", case_, design, resolve_src); } f << stringf("%s" "end\n", indent); } -void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy) +void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy, const RTLIL::Design *design, bool resolve_src) { f << stringf("%s" "sync ", indent); switch (sy->type) { @@ -256,7 +292,7 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT } for (auto &it: sy->mem_write_actions) { - dump_attributes(f, indent, &it); + dump_attributes(f, indent, &it, design, resolve_src); f << stringf("%s memwr %s ", indent, it.memid); dump_sigspec(f, it.address); f << stringf(" "); @@ -269,13 +305,13 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT } } -void RTLIL_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc) +void RTLIL_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc, const RTLIL::Design *design, bool resolve_src) { - dump_attributes(f, indent, proc); + dump_attributes(f, indent, proc, design, resolve_src); f << stringf("%s" "process %s\n", indent, proc->name); - dump_proc_case_body(f, indent + " ", &proc->root_case); + dump_proc_case_body(f, indent + " ", &proc->root_case, design, resolve_src); for (auto* sync : proc->syncs) - dump_proc_sync(f, indent + " ", sync); + dump_proc_sync(f, indent + " ", sync, design, resolve_src); f << stringf("%s" "end\n", indent); } @@ -288,14 +324,14 @@ void RTLIL_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL:: 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) +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) { 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); + dump_attributes(f, indent, module, design, resolve_src); f << stringf("%s" "module %s\n", indent, module->name); @@ -321,28 +357,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); + dump_wire(f, indent + " ", wire, design, resolve_src); } 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); + dump_memory(f, indent + " ", mem, design, resolve_src); } 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); + dump_cell(f, indent + " ", cell, design, resolve_src); } 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); + dump_proc(f, indent + " ", process, design, resolve_src); } bool first_conn_line = true; @@ -370,7 +406,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) +void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n, bool resolve_src) { int init_autoidx = autoidx; @@ -390,13 +426,15 @@ 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) + dump_twines(f, design); } for (const auto& [_, module] : reversed(design->modules_)) { if (!only_selected || design->selected(module)) { if (only_selected) f << stringf("\n"); - dump_module(f, "", module, design, only_selected, flag_m, flag_n); + dump_module(f, "", module, design, only_selected, flag_m, flag_n, resolve_src); } } @@ -423,11 +461,18 @@ 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("\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; log_header(design, "Executing RTLIL backend.\n"); @@ -442,6 +487,10 @@ struct RTLILBackend : public Backend { do_sort = true; continue; } + if (arg == "-resolve-src") { + resolve_src = true; + continue; + } break; } extra_args(f, filename, args, argidx); @@ -452,7 +501,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); + RTLIL_BACKEND::dump_design(*f, design, selected, true, false, resolve_src); } } RTLILBackend; @@ -480,11 +529,17 @@ 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("\n"); } void execute(std::vector args, RTLIL::Design *design) override { std::string filename; - bool flag_m = false, flag_n = false, append = false; + bool flag_m = false, flag_n = false, append = false, resolve_src = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -508,6 +563,10 @@ struct DumpPass : public Pass { flag_n = true; continue; } + if (arg == "-resolve-src") { + resolve_src = true; + continue; + } break; } extra_args(args, argidx, design); @@ -529,7 +588,7 @@ struct DumpPass : public Pass { f = &buf; } - RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n); + RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n, resolve_src); if (!empty) { delete f; diff --git a/backends/rtlil/rtlil_backend.h b/backends/rtlil/rtlil_backend.h index dd7347def..4e20b3da5 100644 --- a/backends/rtlil/rtlil_backend.h +++ b/backends/rtlil/rtlil_backend.h @@ -31,20 +31,30 @@ YOSYS_NAMESPACE_BEGIN namespace RTLIL_BACKEND { - void dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj); + // If `design` is non-null AND `resolve_src` is true, the ID::src + // attribute is expanded through design->src_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); + + // 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); - void dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory); - void dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell); - void dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs); - void dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw); - void dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy); - void dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc); + 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); - void dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false); + 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); } YOSYS_NAMESPACE_END diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index a9030e18a..3427e5d19 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -614,7 +614,13 @@ struct Smt2Worker { auto QY = cell->type == ID($anyinit) ? ID::Q : ID::Y; registers.insert(cell); - string infostr = cell->attributes.count(ID::src) ? cell->attributes.at(ID::src).decode_string().c_str() : get_id(cell); + string infostr; + if (cell->has_attribute(ID::src)) { + string raw_src = cell->get_src_attribute(); + infostr = module && module->design ? module->design->resolve_src(raw_src) : raw_src; + } else { + infostr = get_id(cell); + } if (cell->attributes.count(ID::reg)) infostr += " " + cell->attributes.at(ID::reg).decode_string(); decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort(QY)), infostr)); @@ -1130,8 +1136,11 @@ struct Smt2Worker } } - if (private_name && cell->attributes.count(ID::src)) - decls.push_back(stringf("; yosys-smt2-%s %d %s %s\n", cell->type.c_str() + 1, id, get_id(cell), cell->attributes.at(ID::src).decode_string())); + if (private_name && cell->has_attribute(ID::src)) { + string raw_src = cell->get_src_attribute(); + string resolved_src = module && module->design ? module->design->resolve_src(raw_src) : raw_src; + decls.push_back(stringf("; yosys-smt2-%s %d %s %s\n", cell->type.c_str() + 1, id, get_id(cell), resolved_src.c_str())); + } else decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, get_id(cell))); diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 7362f4190..d9dbe39b6 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -416,6 +416,8 @@ void dump_attributes(std::ostream &f, std::string indent, dictsecond == State::S1 || it->second == Const(1))) f << stringf(" 1 "); + else if (it->first == ID::src && (it->second.flags & RTLIL::CONST_FLAG_STRING) && active_module && active_module->design) + dump_const(f, RTLIL::Const(active_module->design->resolve_src(it->second.decode_string())), -1, 0, false, as_comment); else dump_const(f, it->second, -1, 0, false, as_comment); f << stringf(" %s%s", as_comment ? "*/" : "*)", term); diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index f5a601c3a..38ffe61b6 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1106,7 +1106,31 @@ std::string AstNode::loc_string() const void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) { - obj->attributes[ID::src] = ast->loc_string(); + // All AttrObjects in genrtlil — Cell/Wire/Module/Process AND the inner + // types (CaseRule, SwitchRule, MemWriteAction) — share current_module's + // design's twine pool. process_module attaches current_module->design + // early so this is reachable. + if (!current_module || !current_module->design) + return; + const auto &loc = ast->location; + if (!loc.begin.filename || loc.begin.filename->empty()) { + obj->set_src_attribute(¤t_module->design->src_twines, ast->loc_string()); + return; + } + // Split filename and per-location tail so the filename interns once + // per file and every cell/wire src for that file gets a Suffix node + // carrying only ":line.col-line.col". For a typical large design with + // thousands of objects in one file this collapses N copies of a long + // path into 1 Leaf + N short Suffix tails. + TwinePool *pool = ¤t_module->design->src_twines; + Twine::Id file_id = pool->intern(*loc.begin.filename); + std::string tail = stringf(":%d.%d-%d.%d", + loc.begin.line, loc.begin.column, + loc.end.line, loc.end.column); + Twine::Id suffix_id = pool->intern_suffix(file_id, tail); + pool->release(file_id); // suffix internally holds a ref now + obj->set_src_id(pool, suffix_id); + pool->release(suffix_id); // set_src_id retained on obj's behalf } static bool param_has_no_default(const AstNode* param) { @@ -1130,6 +1154,12 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d AstModule *module = new AstModule; current_module = module; + // Set design backpointer early — every set_src_attr in genrtlil.cc + // resolves the pool via current_module->design->src_twines. The + // final design->add(current_module) at end-of-process_module hooks + // the module into the design's modules_ dict; we just need design + // reachable as a backpointer for src interning meanwhile. + module->design = design; module->ast = nullptr; module->name = ast->str; @@ -1920,6 +1950,29 @@ RTLIL::Module *AstModule::clone() const return new_mod; } +RTLIL::Module *AstModule::clone(RTLIL::Design *dst, bool src_id_verbatim) const +{ + AstModule *new_mod = new AstModule; + new_mod->name = name; + dst->add(new_mod); + cloneInto(new_mod, src_id_verbatim); + + new_mod->ast = ast->clone(); + new_mod->nolatches = nolatches; + new_mod->nomeminit = nomeminit; + new_mod->nomem2reg = nomem2reg; + new_mod->mem2reg = mem2reg; + new_mod->noblackbox = noblackbox; + new_mod->lib = lib; + new_mod->nowb = nowb; + new_mod->noopt = noopt; + new_mod->icells = icells; + new_mod->pwires = pwires; + new_mod->autowire = autowire; + + return new_mod; +} + void AstModule::loadconfig() const { current_ast = NULL; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index f92b4a5b8..2a672f010 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -402,6 +402,7 @@ namespace AST void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces) override; bool reprocess_if_necessary(RTLIL::Design *design) override; RTLIL::Module *clone() const override; + RTLIL::Module *clone(RTLIL::Design *dst, bool src_id_verbatim = false) const override; void loadconfig() const; }; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 718d5aa23..306d52628 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -167,7 +167,9 @@ static void check_unique_id(RTLIL::Module *module, RTLIL::IdString id, const AstNode *node, const char *to_add_kind) { auto already_exists = [&](const RTLIL::AttrObject *existing, const char *existing_kind) { - std::string src = existing->get_string_attribute(ID::src); + std::string src; + if (module->design) + src = existing->get_src_attribute(&module->design->src_twines); std::string location_str = "earlier"; if (!src.empty()) location_str = "at " + src; diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index 0fac902b5..8d2d1bdd2 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -287,6 +287,25 @@ void json_parse_attr_param(dict &results, JsonNode *node) } } +// AttrObject-aware overload: extracts ID::src and routes it to the typed +// src_id_ field via set_src_attribute. Other keys still land in the +// attributes dict via the generic path. +void json_parse_attributes(TwinePool *pool, RTLIL::AttrObject *obj, JsonNode *node) +{ + if (node->type != 'D') + log_error("JSON attributes or parameters node is not a dictionary.\n"); + + for (auto it : node->data_dict) + { + IdString key = RTLIL::escape_id(it.first.c_str()); + Const value = json_parse_attr_param_value(it.second); + if (key == ID::src && (value.flags & RTLIL::CONST_FLAG_STRING)) + obj->set_src_attribute(pool, value.decode_string()); + else + obj->attributes[key] = value; + } +} + void json_import(Design *design, string &modname, JsonNode *node) { log("Importing module %s from JSON tree.\n", modname); @@ -300,7 +319,7 @@ void json_import(Design *design, string &modname, JsonNode *node) design->add(module); if (node->data_dict.count("attributes")) - json_parse_attr_param(module->attributes, node->data_dict.at("attributes")); + json_parse_attributes(&design->src_twines, module, node->data_dict.at("attributes")); if (node->data_dict.count("parameter_default_values")) json_parse_attr_param(module->parameter_default_values, node->data_dict.at("parameter_default_values")); @@ -483,7 +502,7 @@ void json_import(Design *design, string &modname, JsonNode *node) } if (net_node->data_dict.count("attributes")) - json_parse_attr_param(wire->attributes, net_node->data_dict.at("attributes")); + json_parse_attributes(&design->src_twines, wire, net_node->data_dict.at("attributes")); } } @@ -564,7 +583,7 @@ void json_import(Design *design, string &modname, JsonNode *node) } if (cell_node->data_dict.count("attributes")) - json_parse_attr_param(cell->attributes, cell_node->data_dict.at("attributes")); + json_parse_attributes(&design->src_twines, cell, cell_node->data_dict.at("attributes")); if (cell_node->data_dict.count("parameters")) json_parse_attr_param(cell->parameters, cell_node->data_dict.at("parameters")); @@ -611,7 +630,7 @@ void json_import(Design *design, string &modname, JsonNode *node) } if (memory_node->data_dict.count("attributes")) - json_parse_attr_param(mem->attributes, memory_node->data_dict.at("attributes")); + json_parse_attributes(&design->src_twines, mem, memory_node->data_dict.at("attributes")); module->memories[mem->name] = mem; } diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index 4709c76ed..4dcca6b89 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -24,6 +24,7 @@ #include "kernel/register.h" #include "kernel/log.h" #include "kernel/utils.h" +#include "kernel/twine.h" #include #include #include @@ -52,6 +53,14 @@ struct RTLILFrontendWorker { std::vector*> switch_stack; std::vector case_stack; + // Remap from file-local twine ids (as they appear in the `twines` block + // and on cell/wire src attrs) to ids in design->src_twines. Filled by + // parse_twines; consumed by parse_attribute. Parser-side ids retained + // during parse_twines are tracked here so they can be released at + // end-of-parse — only the cell/wire references should survive. + dict twine_remap; + std::vector twine_parser_holds; + template [[noreturn]] void error(FmtString...> fmt, const Args &... args) @@ -436,9 +445,15 @@ struct RTLILFrontendWorker { current_module = new RTLIL::Module; current_module->name = std::move(module_name); - current_module->attributes = std::move(attrbuf); - if (!delete_current_module) + if (delete_current_module) { + // 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); + current_module->attributes = std::move(attrbuf); + } else { design->add(current_module); + current_module->absorb_attrs(&design->src_twines, std::move(attrbuf)); + } while (true) { @@ -491,10 +506,105 @@ struct RTLILFrontendWorker { { RTLIL::IdString id = parse_id(); RTLIL::Const c = parse_const(); + // The '|' separator inside a src attribute is a Yosys-internal + // merge convention emitted only by the legacy strpool path or by + // a `dump -resolve-src`; no external tool should be producing it. + // Warn so the producer learns to emit one path:line.col per + // attribute. We don't try to repair the value — the user's input + // 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(); + Twine::Id file_id = TwinePool::parse_ref(raw); + if (file_id != Twine::Null) { + // Translate the file-local twine id to the destination + // design's pool id via twine_remap. If the file had no + // `twines` block (legacy) the remap is empty — accept the + // ref verbatim and let downstream code intern it. + auto it = twine_remap.find(file_id); + if (it != twine_remap.end()) + c = RTLIL::Const(TwinePool::format_ref(it->second)); + } else if (raw.find('|') != std::string::npos) { + log_warning("line %d: src attribute %s contains '|' separators. " + "That convention is Yosys-internal; the producing tool " + "should emit a single path:line.col per attribute and " + "let Yosys merge through the twine pool.\n", + line_num, raw.c_str()); + } + } attrbuf.insert({std::move(id), std::move(c)}); expect_eol(); } + // 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->src_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. Each parser-side + // retain is tracked in twine_parser_holds and released at end-of-parse + // so only cell/wire references survive. + void parse_twines() + { + expect_eol(); + while (true) { + if (try_parse_keyword("end")) + break; + if (try_parse_keyword("leaf")) { + int file_id = static_cast(parse_integer()); + std::string text = parse_string(); + expect_eol(); + Twine::Id local_id = design->src_twines.intern(text); + twine_parser_holds.push_back(local_id); + twine_remap[static_cast(file_id)] = local_id; + continue; + } + if (try_parse_keyword("suffix")) { + int file_id = static_cast(parse_integer()); + Twine::Id file_parent = static_cast(parse_integer()); + std::string tail = parse_string(); + expect_eol(); + auto it = twine_remap.find(file_parent); + if (it == twine_remap.end()) + error("twines: suffix %d references undefined parent %u.", + file_id, file_parent); + Twine::Id local_id = design->src_twines.intern_suffix(it->second, tail); + twine_parser_holds.push_back(local_id); + twine_remap[static_cast(file_id)] = local_id; + continue; + } + if (try_parse_keyword("concat")) { + int file_id = static_cast(parse_integer()); + std::vector children; + while (!try_parse_eol()) { + Twine::Id file_child = static_cast(parse_integer()); + auto it = twine_remap.find(file_child); + if (it == twine_remap.end()) + error("twines: concat %d references undefined leaf/concat %u.", + file_id, file_child); + children.push_back(it->second); + } + Twine::Id local_id = design->src_twines.concat( + std::span{children}); + twine_parser_holds.push_back(local_id); + twine_remap[static_cast(file_id)] = local_id; + continue; + } + error("Expected `leaf`, `suffix` or `concat` inside twines block, got `%s'.", + error_token()); + } + expect_eol(); + } + + // Release the per-file parser refs gathered during parse_twines. Call + // once the entire file has been parsed and every cell/wire that ever + // referred to a file_id has already adopted the corresponding local_id. + void release_twine_parser_holds() + { + for (Twine::Id id : twine_parser_holds) + design->src_twines.release(id); + twine_parser_holds.clear(); + twine_remap.clear(); + } + void parse_parameter() { RTLIL::IdString id = parse_id(); @@ -556,7 +666,7 @@ struct RTLILFrontendWorker { error("Unexpected wire option: %s", error_token()); } - wire->attributes = std::move(attrbuf); + wire->absorb_attrs(&design->src_twines, std::move(attrbuf)); wire->width = width; wire->upto = upto; wire->start_offset = start_offset; @@ -570,7 +680,7 @@ struct RTLILFrontendWorker { void parse_memory() { RTLIL::Memory *memory = new RTLIL::Memory; - memory->attributes = std::move(attrbuf); + memory->absorb_attrs(&design->src_twines, std::move(attrbuf)); int width = 1; int start_offset = 0; @@ -638,7 +748,7 @@ struct RTLILFrontendWorker { error("RTLIL error: redefinition of cell %s.", cell_name); } RTLIL::Cell *cell = current_module->addCell(cell_name, cell_type); - cell->attributes = std::move(attrbuf); + cell->absorb_attrs(&design->src_twines, std::move(attrbuf)); while (true) { @@ -728,7 +838,7 @@ struct RTLILFrontendWorker { { RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; rule->signal = parse_sigspec(); - rule->attributes = std::move(attrbuf); + rule->absorb_attrs(&design->src_twines, std::move(attrbuf)); switch_stack.back()->push_back(rule); expect_eol(); @@ -745,7 +855,7 @@ struct RTLILFrontendWorker { expect_keyword("case"); RTLIL::CaseRule *case_rule = new RTLIL::CaseRule; - case_rule->attributes = std::move(attrbuf); + case_rule->absorb_attrs(&design->src_twines, std::move(attrbuf)); rule->cases.push_back(case_rule); switch_stack.push_back(&case_rule->switches); case_stack.push_back(case_rule); @@ -779,7 +889,7 @@ struct RTLILFrontendWorker { error("RTLIL error: redefinition of process %s.", proc_name); } RTLIL::Process *proc = current_module->addProcess(std::move(proc_name)); - proc->attributes = std::move(attrbuf); + proc->absorb_attrs(&design->src_twines, std::move(attrbuf)); switch_stack.clear(); switch_stack.push_back(&proc->root_case.switches); @@ -828,7 +938,7 @@ struct RTLILFrontendWorker { break; RTLIL::MemWriteAction act; - act.attributes = std::move(attrbuf); + act.absorb_attrs(&design->src_twines, std::move(attrbuf)); act.memid = parse_id(); act.address = parse_sigspec(); act.data = parse_sigspec(); @@ -869,10 +979,15 @@ struct RTLILFrontendWorker { expect_eol(); continue; } + if (try_parse_keyword("twines")) { + parse_twines(); + continue; + } error("Unexpected token: %s", error_token()); } if (attrbuf.size() != 0) error("dangling attribute"); + release_twine_parser_holds(); } }; diff --git a/kernel/ff.cc b/kernel/ff.cc index 9ccfeeb94..1de3b9ae5 100644 --- a/kernel/ff.cc +++ b/kernel/ff.cc @@ -39,6 +39,15 @@ void manufacture_info(InputType flop, OutputType& info, FfInitVals *initvals) { info.sig_q = cell->getPort(ID::Q); info.width = GetSize(info.sig_q); info.attributes = cell->attributes; + // Carry src across construction → emit() as an owning Twine + // reference. Retaining a slot on the source pool keeps it + // alive even if the source cell gets removed between + // manufacture_info() and emit(); emit() then transfers the + // id verbatim into the new cell — no flatten/re-intern, no + // pipe-leaf risk for cells whose src is a Concat. + if (cell->src_id() != Twine::Null && cell->module && cell->module->design) + info.src_twine = OwnedTwine(&cell->module->design->src_twines, + cell->src_id()); if (initvals) info.val_init = (*initvals)(info.sig_q); } @@ -753,7 +762,24 @@ Cell *FfData::emit() { } } } + // src is carried in info.src_twine (an OwnedTwine retaining the + // source slot). Transfer the id verbatim to the new cell — same + // pool, no flatten. The OwnedTwine still holds its own ref until + // FfData is destroyed; set_src_id retains on the cell's behalf. cell->attributes = attributes; + if (!src_twine.empty() && cell->module && cell->module->design) { + TwinePool *dst_pool = &cell->module->design->src_twines; + if (src_twine.pool() == dst_pool) { + cell->set_src_id(dst_pool, src_twine.id()); + } else { + // Cross-pool (unusual — FfData migrated between + // designs). Rebuild the twine structure into the + // destination pool, then adopt that fresh id. + Twine::Id migrated = dst_pool->copy_from(*src_twine.pool(), src_twine.id()); + cell->set_src_id(dst_pool, migrated); + dst_pool->release(migrated); + } + } if (initvals && !is_anyinit) initvals->set_init(cell->getPort(ID::Q), val_init); return cell; diff --git a/kernel/ff.h b/kernel/ff.h index 2e0c070b0..71c836790 100644 --- a/kernel/ff.h +++ b/kernel/ff.h @@ -22,6 +22,7 @@ #include "kernel/yosys.h" #include "kernel/ffinit.h" +#include "kernel/twine.h" YOSYS_NAMESPACE_BEGIN @@ -169,6 +170,10 @@ struct FfData : FfTypeData { // The FF data width in bits. int width; dict attributes; + // Stashed src across construction → emit. Refcount-managed so the + // source cell's pool slot survives if the cell itself is removed + // before emit() runs. Empty when the source cell had no src. + OwnedTwine src_twine; FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) { width = 0; diff --git a/kernel/mem.cc b/kernel/mem.cc index 8ba81eead..f75a3cca7 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -888,7 +888,14 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) { if (!port.clk_enable) return nullptr; - std::string mem_src = get_src_attribute(); + // Keep src as a "@N" reference into the design's twine pool throughout + // — never flatten to a literal path string. That way every addX call + // below adopts the same slot as Mem itself (via set_src_attribute's + // "@N" parse_ref path), and there's no flatten → re-intern → pipe- + // leaf round-trip on cells whose src is a Concat node. + TwinePool *src_pool = (module && module->design) ? &module->design->src_twines : nullptr; + std::string mem_src = (src_pool && src_id_ != Twine::Null) ? + TwinePool::format_ref(src_id_) : std::string(); Cell *c; @@ -994,8 +1001,10 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) { IdString name = stringf("$%s$rdreg[%d]", memid, idx); FfData ff(module, initvals, name); - if (!mem_src.empty()) - ff.attributes[ID::src] = mem_src; + // Carry mem's src into the ff via the OwnedTwine handle — same + // pool, direct id retain. emit() transfers verbatim. + if (src_pool && src_id_ != Twine::Null) + ff.src_twine = OwnedTwine(src_pool, src_id_); ff.width = GetSize(port.data); ff.has_clk = true; ff.sig_clk = port.clk; diff --git a/kernel/pmux.h b/kernel/pmux.h new file mode 100644 index 000000000..f40b721ff --- /dev/null +++ b/kernel/pmux.h @@ -0,0 +1,25 @@ +#ifndef PMUX_H +#define PMUX_H + +#include "kernel/yosys_common.h" +#include "kernel/rtlil.h" + +YOSYS_NAMESPACE_BEGIN + +struct PmuxBPortIterator { + Cell* cell; + std::vector b; + int port_idx; + int port_count; + PmuxBPortIterator(Cell* mux) : cell(mux) { + log_assert(mux->type == ID($mux) || mux->type == ID($pmux)); + port_idx = 0; + b = mux->getPort(ID::B).to_sigbit_vector(); + + port_count = GetSize(sig_b) / s_width; + } +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index b9a2b5fa8..e2c0d3640 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -914,13 +914,99 @@ RTLIL::Const RTLIL::Const::extract(int offset, int len, RTLIL::State padding) co } #undef check /* check(condition) for Const */ +void RTLIL::AttrObject::set_src_id(TwinePool *pool, Twine::Id id) +{ + log_assert(pool != nullptr); + if (id == src_id_) + return; + if (src_id_ != Twine::Null) + pool->release(src_id_); + src_id_ = id; + if (src_id_ != Twine::Null) + pool->retain(src_id_); +} + +void RTLIL::AttrObject::set_src_attribute(TwinePool *pool, const RTLIL::SrcAttr &src) +{ + if (src.empty()) { + if (src_id_ != Twine::Null) { + log_assert(pool != nullptr); + pool->release(src_id_); + src_id_ = Twine::Null; + } + return; + } + log_assert(pool != nullptr); + Twine::Id new_id = Twine::Null; + if (src.id != Twine::Null) { + // Direct id form — the caller (e.g. `other->src_ref()`) is + // responsible for keeping the slot alive. Retain on our + // behalf. + log_assert(pool->is_alive(src.id) && "set_src_attribute: SrcAttr id points to dead slot"); + new_id = src.id; + pool->retain(new_id); + } else { + // Literal-string form. "@N" → adopt slot directly. Anything + // else → intern as leaf (returns +1). + new_id = TwinePool::parse_ref(src.literal); + if (new_id != Twine::Null) { + log_assert(pool->is_alive(new_id) && "set_src_attribute: @N ref points to dead slot"); + pool->retain(new_id); + } else { + new_id = pool->intern(src.literal); + } + } + if (src_id_ != Twine::Null) + pool->release(src_id_); + src_id_ = new_id; +} + +std::string RTLIL::AttrObject::get_src_attribute(const TwinePool *pool) const +{ + log_assert(pool); + return pool->flatten(src_id_); +} + +void RTLIL::AttrObject::adopt_src_from(TwinePool *pool, const RTLIL::AttrObject *source) +{ + adopt_src_from(pool, source, pool); +} + +void RTLIL::AttrObject::adopt_src_from(TwinePool *dst_pool, + const RTLIL::AttrObject *source, const TwinePool *src_pool) +{ + if (!source || source->src_id() == Twine::Null) { + if (src_id_ != Twine::Null) { + log_assert(dst_pool != nullptr); + dst_pool->release(src_id_); + src_id_ = Twine::Null; + } + return; + } + log_assert(dst_pool != nullptr); + if (src_pool == dst_pool || src_pool == nullptr) { + // Same-pool transfer — the source id is valid in dst_pool. + set_src_id(dst_pool, source->src_id()); + return; + } + // Cross-pool: rebuild source's twine subtree into dst_pool via + // copy_from, then adopt the fresh id. copy_from returns +1. + Twine::Id new_id = dst_pool->copy_from(*src_pool, source->src_id()); + if (src_id_ != Twine::Null) + dst_pool->release(src_id_); + src_id_ = new_id; +} + bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const { + if (id == ID::src) + return src_id_ != Twine::Null; return attributes.count(id); } void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) { + log_assert(id != ID::src); if (value) attributes[id] = RTLIL::Const(1); else @@ -929,6 +1015,8 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const { + if (id == ID::src) + return src_id_ != Twine::Null; const auto it = attributes.find(id); if (it == attributes.end()) return false; @@ -937,6 +1025,11 @@ bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value) { + // ID::src on the base AttrObject is not routable here because the base + // has no pool — callers needing string-form src must go through the + // subtype helper (Cell::set_src_attribute / Wire::… / …) which derives + // the pool from context. + log_assert(id != ID::src && "set_string_attribute(ID::src,...) on AttrObject base; use the subtype helper"); if (value.empty()) attributes.erase(id); else @@ -945,6 +1038,8 @@ void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value) string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const { + // ID::src is not in the dict — callers must use the subtype helper. + log_assert(id != ID::src && "get_string_attribute(ID::src) on AttrObject base; use the subtype helper"); std::string value; const auto it = attributes.find(id); if (it != attributes.end()) @@ -952,6 +1047,165 @@ string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const return value; } +void RTLIL::AttrObject::absorb_attrs(TwinePool *pool, dict &&buf) +{ + auto it = buf.find(ID::src); + if (it != buf.end()) { + if (it->second.flags & RTLIL::CONST_FLAG_STRING) + set_src_attribute(pool, it->second.decode_string()); + buf.erase(it); + } + attributes = std::move(buf); +} + +// Transfer src from `src` to `dst`. Both pools are supplied by the caller; +// in cross-pool transfers the source twine structure is rebuilt inside the +// destination pool via copy_from (preserving concats), in same-pool we just +// retain the existing slot via set_src_id. +namespace { + void copy_src_into(const RTLIL::AttrObject *src, const TwinePool *src_pool, + RTLIL::AttrObject *dst, TwinePool *dst_pool) + { + if (!src || src->src_id() == Twine::Null || !src_pool || !dst_pool) + return; + if (src_pool == dst_pool) { + dst->set_src_id(dst_pool, src->src_id()); + return; + } + Twine::Id new_id = dst_pool->copy_from(*src_pool, src->src_id()); + dst->set_src_id(dst_pool, new_id); + dst_pool->release(new_id); + } +} + +void RTLIL::Design::merge_src(RTLIL::AttrObject *target, const RTLIL::AttrObject *source) +{ + std::vector ids; + if (target->src_id() != Twine::Null) + ids.push_back(target->src_id()); + if (source && source->src_id() != Twine::Null) + ids.push_back(source->src_id()); + if (ids.empty()) + return; + Twine::Id merged = src_twines.concat(std::span{ids}); + target->set_src_id(&src_twines, merged); + src_twines.release(merged); +} + +void RTLIL::Design::merge_src(RTLIL::AttrObject *target, const pool &leaves) +{ + std::vector ids; + std::vector temp_interns; + if (target->src_id() != Twine::Null) + ids.push_back(target->src_id()); + for (const auto &leaf : leaves) { + if (leaf.empty()) + continue; + Twine::Id leaf_id = TwinePool::parse_ref(leaf); + if (leaf_id == Twine::Null) { + leaf_id = src_twines.intern(leaf); + temp_interns.push_back(leaf_id); + } + ids.push_back(leaf_id); + } + if (ids.empty()) + return; + Twine::Id merged = src_twines.concat(std::span{ids}); + target->set_src_id(&src_twines, merged); + src_twines.release(merged); + for (Twine::Id id : temp_interns) + src_twines.release(id); +} + +namespace { + // Walks every AttrObject in the design and invokes `visit(obj)`. + template + void walk_attr_objects(RTLIL::Design *design, F visit) { + for (auto &[_, module] : design->modules_) { + visit(module); + for (auto &[_, wire] : module->wires_) + visit(wire); + for (auto &[_, mem] : module->memories) + visit(mem); + for (auto &[_, cell] : module->cells_) + visit(cell); + for (auto &[_, process] : module->processes) { + visit(process); + // Walk the process's switch/case tree. + std::vector case_stack{&process->root_case}; + while (!case_stack.empty()) { + RTLIL::CaseRule *cs = case_stack.back(); + case_stack.pop_back(); + visit(cs); + for (auto *sw : cs->switches) { + visit(sw); + for (auto *case_ : sw->cases) + case_stack.push_back(case_); + } + } + for (auto *sync : process->syncs) + for (auto &mwa : sync->mem_write_actions) + visit(&mwa); + } + } + } +} + +size_t RTLIL::Design::gc_twines() +{ + size_t before = src_twines.size(); + if (before == 0) + return 0; + + // Mark phase: every live src_id_ on any AttrObject is a root. + pool live; + walk_attr_objects(this, [&](const RTLIL::AttrObject *obj) { + if (obj->src_id_ != Twine::Null) + live.insert(obj->src_id_); + }); + + // Sweep + compact: rebuild the pool keeping only reachable nodes, + // receiving an old-id -> new-id remap. + dict remap = src_twines.gc(live); + + // Rewrite every src_id_ through the remap. The pool was rebuilt, so + // the old ids no longer mean anything — set_src_id with the new id is + // the canonical update. + walk_attr_objects(this, [&](RTLIL::AttrObject *obj) { + if (obj->src_id_ == Twine::Null) + return; + auto it = remap.find(obj->src_id_); + if (it == remap.end()) { + // Wasn't in live set (design corruption) — just zero the id + // since the old pool is gone. + obj->src_id_ = Twine::Null; + return; + } + // Rewrite without going through retain/release — the rebuilt + // pool already accounts for ownership. + obj->src_id_ = it->second; + }); + + return before - src_twines.size(); +} + +pool RTLIL::Design::src_leaves(const RTLIL::AttrObject *obj) const +{ + pool result; + if (obj->src_id() == Twine::Null) + return result; + const TwinePool *pool = &src_twines; + const Twine &n = (*pool)[obj->src_id()]; + if (n.is_flat()) { + result.insert(pool->flat_string(obj->src_id())); + } else { + // Flat-children invariant: every concat child is a Leaf or Suffix. + for (Twine::Id c : n.children()) + result.insert(pool->flat_string(c)); + } + return result; +} + std::string RTLIL::AttrObject::strpool_attribute_to_str(const pool &data) { string attrval; @@ -1380,6 +1634,23 @@ void RTLIL::Design::optimize() it.second.optimize(this); } +void RTLIL::Design::clone_into(RTLIL::Design *dst) const +{ + log_assert(dst->modules_.empty()); + // Copy the twine pool wholesale. Any prior pool state in dst (e.g. + // dead slots left over from a -reset / -pop preceding the clone) is + // discarded by the assignment. The copied refcounts will balance the + // per-AttrObject src_id_ refs assigned below 1:1. + dst->src_twines = src_twines; + // Iterate via rbegin/rend so cloned modules land in dst in forward + // insertion order — same as how the source design's modules dict was + // built — keeping write_rtlil output byte-stable across clone cycles. + // Use virtual clone(dst, verbatim) so AstModule preserves its subtype + // (and its ast pointer + frontend-config flags). + for (auto it = modules_.rbegin(); it != modules_.rend(); ++it) + it->second->clone(dst, /*src_id_verbatim=*/true); +} + bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) @@ -1519,6 +1790,17 @@ RTLIL::Module::Module() RTLIL::Module::~Module() { clear_sig_norm_index(); + // Release src for Memories (they have no module backpointer) before + // destroying them. Wire/Cell/Process release themselves via their + // own dtor through module->design. + if (design) { + TwinePool *pool = &design->src_twines; + for (auto &pr : memories) + if (pr.second->src_id_ != Twine::Null) { + pool->release(pr.second->src_id_); + pr.second->src_id_ = Twine::Null; + } + } for (auto &pr : wires_) delete pr.second; for (auto &pr : memories) @@ -1529,11 +1811,37 @@ RTLIL::Module::~Module() delete pr.second; for (auto binding : bindings_) delete binding; + // Module's own src_id_ — release last so the pool stays valid for + // inner releases above. + if (design && src_id_ != Twine::Null) { + design->src_twines.release(src_id_); + src_id_ = Twine::Null; + } #ifdef YOSYS_ENABLE_PYTHON RTLIL::Module::get_all_modules()->erase(hashidx_); #endif } +void RTLIL::Module::set_src_attribute(const RTLIL::SrcAttr &src) +{ + if (src.empty() && src_id_ == Twine::Null) + return; + log_assert(design && "Module::set_src_attribute requires the module to be attached to a design"); + AttrObject::set_src_attribute(&design->src_twines, src); +} + +void RTLIL::Module::adopt_src_from(const RTLIL::AttrObject *source) +{ + log_assert(design && "Module::adopt_src_from requires the module to be attached to a design"); + AttrObject::adopt_src_from(&design->src_twines, source); +} + +std::string RTLIL::Module::get_src_attribute() const +{ + log_assert(design); + return AttrObject::get_src_attribute(&design->src_twines); +} + #ifdef YOSYS_ENABLE_PYTHON static std::map all_modules; std::map *RTLIL::Module::get_all_modules(void) @@ -2729,7 +3037,7 @@ void RTLIL::Module::optimize() { } -void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const +void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) const { log_assert(new_mod->refcount_wires_ == 0); log_assert(new_mod->refcount_cells_ == 0); @@ -2742,18 +3050,113 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const for (auto &attr : attributes) new_mod->attributes[attr.first] = attr.second; + if (src_id_verbatim) { + // Caller (Design::clone_into) copied src_twines wholesale, so + // the same Twine::Id is valid in the destination pool — and + // the copied refcounts already pre-account for these new + // AttrObjects. Direct assignment, no retain. + new_mod->src_id_ = src_id_; + } else { + // Transfer src across designs. Both modules must be attached + // to a design for the migration to happen; in the + // detached-clone() scratch flow (equiv_make, etc.) src is + // dropped here — those callers don't preserve src across the + // temp clone by design. + const TwinePool *src_pool = this->design ? &this->design->src_twines : nullptr; + TwinePool *dst_pool = new_mod->design ? &new_mod->design->src_twines : nullptr; + copy_src_into(this, src_pool, new_mod, dst_pool); + } - for (auto &it : wires_) - new_mod->addWire(it.first, it.second); + if (src_id_verbatim) { + // Build fresh wires/cells/memories/processes and transfer + // src_id_ verbatim. The non-verbatim branch goes through + // addWire/addCell/addProcess(name, other) which call + // copy_src_into to migrate src across pools; here both pools + // already match, so we skip that and copy the id directly. + for (auto it = wires_.rbegin(); it != wires_.rend(); ++it) { + const RTLIL::Wire *o = it->second; + RTLIL::Wire *w = new_mod->addWire(it->first, o->width); + w->start_offset = o->start_offset; + w->port_id = o->port_id; + w->port_input = o->port_input; + w->port_output = o->port_output; + w->upto = o->upto; + w->is_signed = o->is_signed; + w->attributes = o->attributes; + w->src_id_ = o->src_id_; + } + for (auto it = memories.rbegin(); it != memories.rend(); ++it) { + const RTLIL::Memory *o = it->second; + RTLIL::Memory *m = new_mod->addMemory(it->first); + m->width = o->width; + m->start_offset = o->start_offset; + m->size = o->size; + m->attributes = o->attributes; + m->src_id_ = o->src_id_; + } + for (auto it = cells_.rbegin(); it != cells_.rend(); ++it) { + const RTLIL::Cell *o = it->second; + RTLIL::Cell *c = new_mod->addCell(it->first, o->type); + c->connections_ = o->connections_; + c->parameters = o->parameters; + c->attributes = o->attributes; + c->src_id_ = o->src_id_; + } + for (auto it = processes.rbegin(); it != processes.rend(); ++it) { + const RTLIL::Process *o = it->second; + RTLIL::Process *p = o->clone(); + p->name = it->first; + new_mod->add(p); + // Process::clone drops src_id_ across the inner tree + // (no pool backpointer there); now that p has a module + // we can copy them verbatim. + p->src_id_ = o->src_id_; + std::vector> case_stack; + case_stack.emplace_back(&o->root_case, &p->root_case); + while (!case_stack.empty()) { + auto [s_cs, d_cs] = case_stack.back(); + case_stack.pop_back(); + d_cs->src_id_ = s_cs->src_id_; + log_assert(s_cs->switches.size() == d_cs->switches.size()); + for (size_t i = 0; i < s_cs->switches.size(); i++) { + const auto *s_sw = s_cs->switches[i]; + auto *d_sw = d_cs->switches[i]; + d_sw->src_id_ = s_sw->src_id_; + log_assert(s_sw->cases.size() == d_sw->cases.size()); + for (size_t j = 0; j < s_sw->cases.size(); j++) + case_stack.emplace_back(s_sw->cases[j], d_sw->cases[j]); + } + } + log_assert(o->syncs.size() == p->syncs.size()); + for (size_t i = 0; i < o->syncs.size(); i++) { + const auto *s_sync = o->syncs[i]; + auto *d_sync = p->syncs[i]; + log_assert(s_sync->mem_write_actions.size() == d_sync->mem_write_actions.size()); + for (size_t j = 0; j < s_sync->mem_write_actions.size(); j++) + d_sync->mem_write_actions[j].src_id_ = s_sync->mem_write_actions[j].src_id_; + } + } + } else { + // Iterate via rbegin/rend so we walk in forward INSERTION + // order, not hashlib::dict's default reverse-insertion. The + // TwinePool allocates slots sequentially as copy_src_into → + // copy_from interns each wire's src, so the destination pool + // ends up with leaves in the same order the frontend + // originally interned them — that lets write_rtlil emit + // byte-equal "@N" refs across single-module clones into an + // existing destination design. + for (auto it = wires_.rbegin(); it != wires_.rend(); ++it) + new_mod->addWire(it->first, it->second); - for (auto &it : memories) - new_mod->addMemory(it.first, it.second); + for (auto it = memories.rbegin(); it != memories.rend(); ++it) + new_mod->addMemory(it->first, it->second); - for (auto &it : cells_) - new_mod->addCell(it.first, it.second); + for (auto it = cells_.rbegin(); it != cells_.rend(); ++it) + new_mod->addCell(it->first, it->second); - for (auto &it : processes) - new_mod->addProcess(it.first, it.second); + for (auto it = processes.rbegin(); it != processes.rend(); ++it) + new_mod->addProcess(it->first, it->second); + } struct RewriteSigSpecWorker { @@ -2780,6 +3183,15 @@ RTLIL::Module *RTLIL::Module::clone() const return new_mod; } +RTLIL::Module *RTLIL::Module::clone(RTLIL::Design *dst, bool src_id_verbatim) const +{ + RTLIL::Module *new_mod = new RTLIL::Module; + new_mod->name = name; + dst->add(new_mod); + cloneInto(new_mod, src_id_verbatim); + return new_mod; +} + bool RTLIL::Module::has_memories() const { return !memories.empty(); @@ -3136,6 +3548,11 @@ RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *oth wire->upto = other->upto; wire->is_signed = other->is_signed; wire->attributes = other->attributes; + { + const TwinePool *src_pool = other->module && other->module->design ? &other->module->design->src_twines : nullptr; + TwinePool *dst_pool = this->design ? &this->design->src_twines : nullptr; + copy_src_into(other, src_pool, wire, dst_pool); + } return wire; } @@ -3154,6 +3571,11 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth cell->connections_ = other->connections_; cell->parameters = other->parameters; cell->attributes = other->attributes; + { + const TwinePool *src_pool = other->module && other->module->design ? &other->module->design->src_twines : nullptr; + TwinePool *dst_pool = this->design ? &this->design->src_twines : nullptr; + copy_src_into(other, src_pool, cell, dst_pool); + } return cell; } @@ -3173,6 +3595,12 @@ RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memor mem->start_offset = other->start_offset; mem->size = other->size; mem->attributes = other->attributes; + { + // Memory has no module backpointer of its own — we can't know its + // source pool from `other` alone. Drop src in the rare clone-of- + // memory path; addMemory(name) is the common one and starts fresh. + (void)other; + } memories[mem->name] = mem; return mem; } @@ -3185,16 +3613,70 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name) return proc; } +namespace { + // Walk two process trees in parallel and transfer src across the + // design boundary for every AttrObject (CaseRule, SwitchRule, + // MemWriteAction). Process::clone() drops src on these inner objects + // because they have no pool backpointer; this restores it now that + // both source and destination pools are known. + void migrate_process_tree_src(const RTLIL::Process *src, const TwinePool *src_pool, + RTLIL::Process *dst, TwinePool *dst_pool) + { + if (!src_pool || !dst_pool) + return; + // Top-level Process src is handled by the addProcess() caller via + // copy_src_into; here we only walk inner objects. + std::vector> case_stack; + case_stack.emplace_back(&src->root_case, &dst->root_case); + while (!case_stack.empty()) { + auto [s_cs, d_cs] = case_stack.back(); + case_stack.pop_back(); + copy_src_into(s_cs, src_pool, d_cs, dst_pool); + log_assert(s_cs->switches.size() == d_cs->switches.size()); + for (size_t i = 0; i < s_cs->switches.size(); i++) { + const auto *s_sw = s_cs->switches[i]; + auto *d_sw = d_cs->switches[i]; + copy_src_into(s_sw, src_pool, d_sw, dst_pool); + log_assert(s_sw->cases.size() == d_sw->cases.size()); + for (size_t j = 0; j < s_sw->cases.size(); j++) + case_stack.emplace_back(s_sw->cases[j], d_sw->cases[j]); + } + } + log_assert(src->syncs.size() == dst->syncs.size()); + for (size_t i = 0; i < src->syncs.size(); i++) { + const auto *s_sync = src->syncs[i]; + auto *d_sync = dst->syncs[i]; + log_assert(s_sync->mem_write_actions.size() == d_sync->mem_write_actions.size()); + for (size_t j = 0; j < s_sync->mem_write_actions.size(); j++) + copy_src_into(&s_sync->mem_write_actions[j], src_pool, + &d_sync->mem_write_actions[j], dst_pool); + } + } +} + RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other) { RTLIL::Process *proc = other->clone(); proc->name = std::move(name); add(proc); + // Migrate src across the design boundary for the inner-process tree. + // Process::clone drops src on CaseRule/SwitchRule/MemWriteAction since + // those types have no module backpointer; with both pools now known + // (other's via other->module->design; ours via this->design) we can + // walk in parallel and migrate. + if (other->module && other->module->design && this->design) { + const TwinePool *src_pool = &other->module->design->src_twines; + TwinePool *dst_pool = &this->design->src_twines; + // Top-level Process src. + copy_src_into(other, src_pool, proc, dst_pool); + // Inner tree. + migrate_process_tree_src(other, src_pool, proc, dst_pool); + } return proc; } #define DEF_METHOD(_func, _y_size, _type) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->parameters[ID::A_SIGNED] = is_signed; \ cell->parameters[ID::A_WIDTH] = sig_a.size(); \ @@ -3204,7 +3686,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed, const std::string &src) { \ + template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed, const RTLIL::SrcAttr &src) { \ RTLIL::SigSpec sig_y = static_cast(this)->addWire(NEW_ID, _y_size); \ add ## _func(name, sig_a, sig_y, is_signed, src); \ return sig_y; \ @@ -3221,7 +3703,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro #undef DEF_METHOD #define DEF_METHOD(_func, _y_size, _type) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool /* is_signed */, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool /* is_signed */, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->parameters[ID::WIDTH] = sig_a.size(); \ cell->setPort(ID::A, sig_a); \ @@ -3229,7 +3711,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed, const std::string &src) { \ + template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed, const RTLIL::SrcAttr &src) { \ RTLIL::SigSpec sig_y = static_cast(this)->addWire(NEW_ID, _y_size); \ add ## _func(name, sig_a, sig_y, is_signed, src); \ return sig_y; \ @@ -3238,7 +3720,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro #undef DEF_METHOD #define DEF_METHOD(_func, _y_size, _type) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->parameters[ID::A_SIGNED] = is_signed; \ cell->parameters[ID::B_SIGNED] = is_signed; \ @@ -3251,7 +3733,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed, const std::string &src) { \ + template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed, const RTLIL::SrcAttr &src) { \ RTLIL::SigSpec sig_y = static_cast(this)->addWire(NEW_ID, _y_size); \ add ## _func(name, sig_a, sig_b, sig_y, is_signed, src); \ return sig_y; \ @@ -3281,7 +3763,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro #undef DEF_METHOD #define DEF_METHOD(_func, _y_size, _type) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->parameters[ID::A_SIGNED] = is_signed; \ cell->parameters[ID::B_SIGNED] = false; \ @@ -3294,7 +3776,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed, const std::string &src) { \ + template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed, const RTLIL::SrcAttr &src) { \ RTLIL::SigSpec sig_y = static_cast(this)->addWire(NEW_ID, _y_size); \ add ## _func(name, sig_a, sig_b, sig_y, is_signed, src); \ return sig_y; \ @@ -3306,7 +3788,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro #undef DEF_METHOD #define DEF_METHOD(_func, _y_size, _type) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->parameters[ID::A_SIGNED] = false; \ cell->parameters[ID::B_SIGNED] = is_signed; \ @@ -3319,7 +3801,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed, const std::string &src) { \ + template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed, const RTLIL::SrcAttr &src) { \ RTLIL::SigSpec sig_y = static_cast(this)->addWire(NEW_ID, _y_size); \ add ## _func(name, sig_a, sig_b, sig_y, is_signed, src); \ return sig_y; \ @@ -3328,7 +3810,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro #undef DEF_METHOD #define DEF_METHOD(_func, _type, _pmux) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->parameters[ID::WIDTH] = sig_a.size(); \ if (_pmux) cell->parameters[ID::S_WIDTH] = sig_s.size(); \ @@ -3339,7 +3821,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src) { \ + template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SrcAttr &src) { \ RTLIL::SigSpec sig_y = static_cast(this)->addWire(NEW_ID, sig_a.size()); \ add ## _func(name, sig_a, sig_b, sig_s, sig_y, src); \ return sig_y; \ @@ -3350,7 +3832,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro #undef DEF_METHOD #define DEF_METHOD(_func, _type, _demux) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->parameters[ID::WIDTH] = _demux ? sig_a.size() : sig_y.size(); \ cell->parameters[ID::S_WIDTH] = sig_s.size(); \ @@ -3360,7 +3842,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src) { \ + template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SrcAttr &src) { \ RTLIL::SigSpec sig_y = static_cast(this)->addWire(NEW_ID, _demux ? sig_a.size() << sig_s.size() : sig_a.size() >> sig_s.size()); \ add ## _func(name, sig_a, sig_s, sig_y, src); \ return sig_y; \ @@ -3370,7 +3852,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro #undef DEF_METHOD #define DEF_METHOD(_func, _type) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->parameters[ID::WIDTH] = sig_a.size(); \ cell->setPort(ID::A, sig_a); \ @@ -3379,7 +3861,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src) { \ + template RTLIL::SigSpec CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SrcAttr &src) { \ RTLIL::SigSpec sig_y = static_cast(this)->addWire(NEW_ID, sig_a.size()); \ add ## _func(name, sig_a, sig_s, sig_y, src); \ return sig_y; \ @@ -3388,20 +3870,20 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro #undef DEF_METHOD #define DEF_METHOD_2(_func, _type, _P1, _P2) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->setPort("\\" #_P1, sig1); \ cell->setPort("\\" #_P2, sig2); \ cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigBit CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const std::string &src) { \ + template RTLIL::SigBit CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SrcAttr &src) { \ RTLIL::SigBit sig2 = static_cast(this)->addWire(NEW_ID); \ add ## _func(name, sig1, sig2, src); \ return sig2; \ } #define DEF_METHOD_3(_func, _type, _P1, _P2, _P3) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->setPort("\\" #_P1, sig1); \ cell->setPort("\\" #_P2, sig2); \ @@ -3409,13 +3891,13 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigBit CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const std::string &src) { \ + template RTLIL::SigBit CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SrcAttr &src) { \ RTLIL::SigBit sig3 = static_cast(this)->addWire(NEW_ID); \ add ## _func(name, sig1, sig2, sig3, src); \ return sig3; \ } #define DEF_METHOD_4(_func, _type, _P1, _P2, _P3, _P4) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const RTLIL::SigBit &sig4, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const RTLIL::SigBit &sig4, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->setPort("\\" #_P1, sig1); \ cell->setPort("\\" #_P2, sig2); \ @@ -3424,13 +3906,13 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigBit CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const std::string &src) { \ + template RTLIL::SigBit CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const RTLIL::SrcAttr &src) { \ RTLIL::SigBit sig4 = static_cast(this)->addWire(NEW_ID); \ add ## _func(name, sig1, sig2, sig3, sig4, src); \ return sig4; \ } #define DEF_METHOD_5(_func, _type, _P1, _P2, _P3, _P4, _P5) \ - template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const RTLIL::SigBit &sig4, const RTLIL::SigBit &sig5, const std::string &src) { \ + template RTLIL::Cell* CellAdderMixin::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const RTLIL::SigBit &sig4, const RTLIL::SigBit &sig5, const RTLIL::SrcAttr &src) { \ RTLIL::Cell *cell = static_cast(this)->addCell(name, _type); \ cell->setPort("\\" #_P1, sig1); \ cell->setPort("\\" #_P2, sig2); \ @@ -3440,7 +3922,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro cell->set_src_attribute(src); \ return cell; \ } \ - template RTLIL::SigBit CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const RTLIL::SigBit &sig4, const std::string &src) { \ + template RTLIL::SigBit CellAdderMixin::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const RTLIL::SigBit &sig4, const RTLIL::SrcAttr &src) { \ RTLIL::SigBit sig5 = static_cast(this)->addWire(NEW_ID); \ add ## _func(name, sig1, sig2, sig3, sig4, sig5, src); \ return sig5; \ @@ -3466,7 +3948,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro #undef DEF_METHOD_4 #undef DEF_METHOD_5 - template RTLIL::Cell* CellAdderMixin::addPow(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed, bool b_signed, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addPow(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed, bool b_signed, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($pow)); cell->parameters[ID::A_SIGNED] = a_signed; @@ -3481,7 +3963,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addFa(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addFa(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($fa)); cell->parameters[ID::WIDTH] = sig_a.size(); @@ -3494,7 +3976,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addSlice(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addSlice(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($slice)); cell->parameters[ID::A_WIDTH] = sig_a.size(); @@ -3506,7 +3988,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addConcat(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addConcat(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($concat)); cell->parameters[ID::A_WIDTH] = sig_a.size(); @@ -3518,7 +4000,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addLut(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addLut(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($lut)); cell->parameters[ID::LUT] = lut; @@ -3529,7 +4011,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addTribuf(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_y, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addTribuf(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($tribuf)); cell->parameters[ID::WIDTH] = sig_a.size(); @@ -3540,7 +4022,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addAssert(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addAssert(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($assert)); cell->setPort(ID::A, sig_a); @@ -3549,7 +4031,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addAssume(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addAssume(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($assume)); cell->setPort(ID::A, sig_a); @@ -3558,7 +4040,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addLive(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addLive(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($live)); cell->setPort(ID::A, sig_a); @@ -3567,7 +4049,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addFair(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addFair(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($fair)); cell->setPort(ID::A, sig_a); @@ -3576,7 +4058,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addCover(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addCover(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($cover)); cell->setPort(ID::A, sig_a); @@ -3585,7 +4067,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addEquiv(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addEquiv(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($equiv)); cell->setPort(ID::A, sig_a); @@ -3595,7 +4077,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addSr(RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, const RTLIL::SigSpec &sig_q, bool set_polarity, bool clr_polarity, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addSr(RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, const RTLIL::SigSpec &sig_q, bool set_polarity, bool clr_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($sr)); cell->parameters[ID::SET_POLARITY] = set_polarity; @@ -3608,7 +4090,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addFf(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addFf(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($ff)); cell->parameters[ID::WIDTH] = sig_q.size(); @@ -3618,7 +4100,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addDff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addDff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($dff)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3630,7 +4112,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addDffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addDffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($dffe)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3645,7 +4127,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addDffsr(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src) + RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($dffsr)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3662,7 +4144,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addDffsre(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) + RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, bool set_polarity, bool clr_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($dffsre)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3681,7 +4163,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAdff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity, const std::string &src) + RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($adff)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3697,7 +4179,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAdffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const arst_value, bool clk_polarity, bool en_polarity, bool arst_polarity, const std::string &src) + RTLIL::Const arst_value, bool clk_polarity, bool en_polarity, bool arst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($adffe)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3715,7 +4197,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAldff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const std::string &src) + const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($aldff)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3731,7 +4213,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAldffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const std::string &src) + const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($aldffe)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3749,7 +4231,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addSdff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const srst_value, bool clk_polarity, bool srst_polarity, const std::string &src) + RTLIL::Const srst_value, bool clk_polarity, bool srst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($sdff)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3765,7 +4247,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addSdffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src) + RTLIL::Const srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($sdffe)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3783,7 +4265,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addSdffce(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src) + RTLIL::Const srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($sdffce)); cell->parameters[ID::CLK_POLARITY] = clk_polarity; @@ -3800,7 +4282,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addDlatch(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addDlatch(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($dlatch)); cell->parameters[ID::EN_POLARITY] = en_polarity; @@ -3813,7 +4295,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAdlatch(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const arst_value, bool en_polarity, bool arst_polarity, const std::string &src) + RTLIL::Const arst_value, bool en_polarity, bool arst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($adlatch)); cell->parameters[ID::EN_POLARITY] = en_polarity; @@ -3829,7 +4311,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addDlatchsr(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) + RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($dlatchsr)); cell->parameters[ID::EN_POLARITY] = en_polarity; @@ -3846,7 +4328,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addSrGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - const RTLIL::SigSpec &sig_q, bool set_polarity, bool clr_polarity, const std::string &src) + const RTLIL::SigSpec &sig_q, bool set_polarity, bool clr_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_SR_%c%c_", set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); cell->setPort(ID::S, sig_set); @@ -3856,7 +4338,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addFfGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addFfGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, ID($_FF_)); cell->setPort(ID::D, sig_d); @@ -3865,7 +4347,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addDffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addDffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N')); cell->setPort(ID::C, sig_clk); @@ -3875,7 +4357,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addDffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addDffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); cell->setPort(ID::C, sig_clk); @@ -3887,7 +4369,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addDffsrGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src) + RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); cell->setPort(ID::C, sig_clk); @@ -3900,7 +4382,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addDffsreGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) + RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, bool set_polarity, bool clr_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_DFFSRE_%c%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); cell->setPort(ID::C, sig_clk); @@ -3914,7 +4396,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAdffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value, bool clk_polarity, bool arst_polarity, const std::string &src) + bool arst_value, bool clk_polarity, bool arst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_DFF_%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0')); cell->setPort(ID::C, sig_clk); @@ -3926,7 +4408,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAdffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value, bool clk_polarity, bool en_polarity, bool arst_polarity, const std::string &src) + bool arst_value, bool clk_polarity, bool en_polarity, bool arst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_DFFE_%c%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0', en_polarity ? 'P' : 'N')); cell->setPort(ID::C, sig_clk); @@ -3939,7 +4421,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAldffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const std::string &src) + const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_ALDFF_%c%c_", clk_polarity ? 'P' : 'N', aload_polarity ? 'P' : 'N')); cell->setPort(ID::C, sig_clk); @@ -3952,7 +4434,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAldffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const std::string &src) + const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_ALDFFE_%c%c%c_", clk_polarity ? 'P' : 'N', aload_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); cell->setPort(ID::C, sig_clk); @@ -3966,7 +4448,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addSdffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value, bool clk_polarity, bool srst_polarity, const std::string &src) + bool srst_value, bool clk_polarity, bool srst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_SDFF_%c%c%c_", clk_polarity ? 'P' : 'N', srst_polarity ? 'P' : 'N', srst_value ? '1' : '0')); cell->setPort(ID::C, sig_clk); @@ -3978,7 +4460,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addSdffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src) + bool srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_SDFFE_%c%c%c%c_", clk_polarity ? 'P' : 'N', srst_polarity ? 'P' : 'N', srst_value ? '1' : '0', en_polarity ? 'P' : 'N')); cell->setPort(ID::C, sig_clk); @@ -3991,7 +4473,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addSdffceGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src) + bool srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_SDFFCE_%c%c%c%c_", clk_polarity ? 'P' : 'N', srst_polarity ? 'P' : 'N', srst_value ? '1' : '0', en_polarity ? 'P' : 'N')); cell->setPort(ID::C, sig_clk); @@ -4003,7 +4485,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } - template RTLIL::Cell* CellAdderMixin::addDlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, const std::string &src) + template RTLIL::Cell* CellAdderMixin::addDlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_DLATCH_%c_", en_polarity ? 'P' : 'N')); cell->setPort(ID::E, sig_en); @@ -4014,7 +4496,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addAdlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value, bool en_polarity, bool arst_polarity, const std::string &src) + bool arst_value, bool en_polarity, bool arst_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_DLATCH_%c%c%c_", en_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0')); cell->setPort(ID::E, sig_en); @@ -4026,7 +4508,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro } template RTLIL::Cell* CellAdderMixin::addDlatchsrGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) + RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = static_cast(this)->addCell(name, stringf("$_DLATCHSR_%c%c%c_", en_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); cell->setPort(ID::E, sig_en); @@ -4038,7 +4520,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Pro return cell; } -RTLIL::Cell* RTLIL::Module::addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src) +RTLIL::Cell* RTLIL::Module::addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = addCell(name, ID($anyinit)); cell->parameters[ID::WIDTH] = sig_q.size(); @@ -4048,7 +4530,7 @@ RTLIL::Cell* RTLIL::Module::addAnyinit(RTLIL::IdString name, const RTLIL::SigSpe return cell; } -RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src) +RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const RTLIL::SrcAttr &src) { RTLIL::SigSpec sig = addWire(NEW_ID, width); Cell *cell = addCell(name, ID($anyconst)); @@ -4058,7 +4540,7 @@ RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const st return sig; } -RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const std::string &src) +RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const RTLIL::SrcAttr &src) { RTLIL::SigSpec sig = addWire(NEW_ID, width); Cell *cell = addCell(name, ID($anyseq)); @@ -4068,7 +4550,7 @@ RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const std: return sig; } -RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const std::string &src) +RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const RTLIL::SrcAttr &src) { RTLIL::SigSpec sig = addWire(NEW_ID, width); Cell *cell = addCell(name, ID($allconst)); @@ -4078,7 +4560,7 @@ RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const st return sig; } -RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const std::string &src) +RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const RTLIL::SrcAttr &src) { RTLIL::SigSpec sig = addWire(NEW_ID, width); Cell *cell = addCell(name, ID($allseq)); @@ -4088,7 +4570,7 @@ RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const std: return sig; } -RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string &src) +RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const RTLIL::SrcAttr &src) { RTLIL::SigSpec sig = addWire(NEW_ID); Cell *cell = addCell(name, ID($initstate)); @@ -4097,7 +4579,7 @@ RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string return sig; } -RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SrcAttr &src) { RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); Cell *cell = addCell(name, ID($set_tag)); @@ -4111,7 +4593,7 @@ RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &ta return sig; } -RTLIL::Cell* RTLIL::Module::addSetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src) +RTLIL::Cell* RTLIL::Module::addSetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src) { Cell *cell = addCell(name, ID($set_tag)); cell->parameters[ID::WIDTH] = sig_a.size(); @@ -4124,7 +4606,7 @@ RTLIL::Cell* RTLIL::Module::addSetTag(RTLIL::IdString name, const std::string &t return cell; } -RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src) +RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SrcAttr &src) { RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); Cell *cell = addCell(name, ID($get_tag)); @@ -4136,7 +4618,7 @@ RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &ta return sig; } -RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SrcAttr &src) { RTLIL::Cell *cell = addCell(name, ID($overwrite_tag)); cell->parameters[ID::WIDTH] = sig_a.size(); @@ -4148,7 +4630,7 @@ RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::str return cell; } -RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src) +RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SrcAttr &src) { RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); Cell *cell = addCell(name, ID($original_tag)); @@ -4160,7 +4642,7 @@ RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::strin return sig; } -RTLIL::SigSpec RTLIL::Module::FutureFF(RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src) +RTLIL::SigSpec RTLIL::Module::FutureFF(RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const RTLIL::SrcAttr &src) { RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); Cell *cell = addCell(name, ID($future_ff)); @@ -4200,11 +4682,34 @@ RTLIL::Wire::Wire(ConstructToken) RTLIL::Wire::~Wire() { + if (module && module->design && src_id_ != Twine::Null) + module->design->src_twines.release(src_id_); #ifdef YOSYS_ENABLE_PYTHON RTLIL::Wire::get_all_wires()->erase(hashidx_); #endif } +void RTLIL::Wire::set_src_attribute(const RTLIL::SrcAttr &src) +{ + if (src.empty() && src_id_ == Twine::Null) + return; + log_assert(module && module->design && "Wire::set_src_attribute requires the wire to be attached to a module in a design"); + AttrObject::set_src_attribute(&module->design->src_twines, src); +} + +std::string RTLIL::Wire::get_src_attribute() const +{ + log_assert(module); + log_assert(module->design); + return AttrObject::get_src_attribute(&module->design->src_twines); +} + +void RTLIL::Wire::adopt_src_from(const RTLIL::AttrObject *source) +{ + log_assert(module && module->design && "Wire::adopt_src_from requires the wire to be attached to a module in a design"); + AttrObject::adopt_src_from(&module->design->src_twines, source); +} + std::string RTLIL::Wire::to_rtlil_str() const { std::ostringstream f; @@ -4271,11 +4776,34 @@ RTLIL::Cell::Cell(ConstructToken) : module(nullptr) RTLIL::Cell::~Cell() { + if (module && module->design && src_id_ != Twine::Null) + module->design->src_twines.release(src_id_); #ifdef YOSYS_ENABLE_PYTHON RTLIL::Cell::get_all_cells()->erase(hashidx_); #endif } +void RTLIL::Cell::set_src_attribute(const RTLIL::SrcAttr &src) +{ + if (src.empty() && src_id_ == Twine::Null) + return; + log_assert(module && module->design && "Cell::set_src_attribute requires the cell to be attached to a module in a design"); + AttrObject::set_src_attribute(&module->design->src_twines, src); +} + +std::string RTLIL::Cell::get_src_attribute() const +{ + log_assert(module); + log_assert(module->design); + return module->design->src_twines.flatten(src_id_); +} + +void RTLIL::Cell::adopt_src_from(const RTLIL::AttrObject *source) +{ + log_assert(module && module->design && "Cell::adopt_src_from requires the cell to be attached to a module in a design"); + AttrObject::adopt_src_from(&module->design->src_twines, source); +} + std::string RTLIL::Cell::to_rtlil_str() const { std::ostringstream f; @@ -5883,6 +6411,9 @@ RTLIL::CaseRule *RTLIL::CaseRule::clone() const new_caserule->compare = compare; new_caserule->actions = actions; new_caserule->attributes = attributes; + // clone() drops src — CaseRule has no pool backpointer, so we can't + // retain. The caller (Module::addProcess(name, other)) is responsible + // for walking the cloned tree and migrating src via context. for (auto &it : switches) new_caserule->switches.push_back(it->clone()); return new_caserule; @@ -5904,6 +6435,7 @@ RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const RTLIL::SwitchRule *new_switchrule = new RTLIL::SwitchRule; new_switchrule->signal = signal; new_switchrule->attributes = attributes; + // clone() drops src — see CaseRule::clone for rationale. for (auto &it : cases) new_switchrule->cases.push_back(it->clone()); return new_switchrule; @@ -5917,21 +6449,86 @@ RTLIL::SyncRule *RTLIL::SyncRule::clone() const new_syncrule->signal = signal; new_syncrule->actions = actions; new_syncrule->mem_write_actions = mem_write_actions; + // Drop src_id_ on the cloned MemWriteActions — the integer was copied + // by the vector assignment above without retaining the pool slot, and + // the caller is responsible for migrating src across the clone via + // context (see Process::clone). + for (auto &mwa : new_syncrule->mem_write_actions) + mwa.src_id_ = Twine::Null; return new_syncrule; } RTLIL::Process::~Process() { + // Process owns the refcount lifecycle for its inner AttrObject tree: + // CaseRule/SwitchRule/MemWriteAction have no module backpointer so + // can't release their own src_id_. Walk the tree first while we still + // have access to the pool via module->design. + if (module && module->design) { + TwinePool *pool = &module->design->src_twines; + std::vector case_stack{&root_case}; + while (!case_stack.empty()) { + RTLIL::CaseRule *cs = case_stack.back(); + case_stack.pop_back(); + if (cs->src_id_ != Twine::Null) { + pool->release(cs->src_id_); + cs->src_id_ = Twine::Null; + } + for (auto *sw : cs->switches) { + if (sw->src_id_ != Twine::Null) { + pool->release(sw->src_id_); + sw->src_id_ = Twine::Null; + } + for (auto *case_ : sw->cases) + case_stack.push_back(case_); + } + } + for (auto *sync : syncs) + for (auto &mwa : sync->mem_write_actions) { + if (mwa.src_id_ != Twine::Null) { + pool->release(mwa.src_id_); + mwa.src_id_ = Twine::Null; + } + } + // Process's own src_id_ (lives in the AttrObject base). + if (src_id_ != Twine::Null) { + pool->release(src_id_); + src_id_ = Twine::Null; + } + } for (auto it = syncs.begin(); it != syncs.end(); it++) delete *it; } +void RTLIL::Process::set_src_attribute(const RTLIL::SrcAttr &src) +{ + if (src.empty() && src_id_ == Twine::Null) + return; + log_assert(module && module->design && "Process::set_src_attribute requires the process to be attached to a module in a design"); + AttrObject::set_src_attribute(&module->design->src_twines, src); +} + +std::string RTLIL::Process::get_src_attribute() const +{ + if (!module || !module->design) + return {}; + return AttrObject::get_src_attribute(&module->design->src_twines); +} + +void RTLIL::Process::adopt_src_from(const RTLIL::AttrObject *source) +{ + log_assert(module && module->design && "Process::adopt_src_from requires the process to be attached to a module in a design"); + AttrObject::adopt_src_from(&module->design->src_twines, source); +} + RTLIL::Process *RTLIL::Process::clone() const { RTLIL::Process *new_proc = new RTLIL::Process; new_proc->name = name; new_proc->attributes = attributes; + // clone() drops src across the whole tree; the caller is responsible + // for migrating src via context after the clone has a module. RTLIL::CaseRule *rc_ptr = root_case.clone(); new_proc->root_case = *rc_ptr; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index bfe755724..2a268ef11 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -22,6 +22,7 @@ #include "kernel/yosys_common.h" #include "kernel/yosys.h" +#include "kernel/twine.h" #include #include @@ -125,11 +126,39 @@ namespace RTLIL struct OwningIdString; struct StaticIdString; struct SigNormIndex; + struct SrcAttr; typedef std::pair SigSig; struct PortBit; }; +// A small polymorphic handle representing src to be applied to an +// AttrObject by a CellAdder method or set_src_attribute call. Holds +// EITHER a pre-interned twine id (preferred — the destination just +// retains the slot, no flatten/intern) OR a literal string ("@N" or a +// raw path:line.col) for legacy callers. Implicit conversions cover +// both shapes so existing string-passing call sites keep compiling +// without changes; new code passing `cell->src_ref()` lands in the +// cheap id branch. +// +// The caller must keep any pool slot named by `id` alive for the +// duration of the call (typically: the source AttrObject still holds +// it). Empty by default — passing a default-constructed SrcAttr to +// set_src_attribute clears src_id_. +struct RTLIL::SrcAttr +{ + Twine::Id id = Twine::Null; + std::string literal; + + SrcAttr() = default; + SrcAttr(Twine::Id i) : id(i) {} + SrcAttr(std::string s) : literal(std::move(s)) {} + SrcAttr(const char *s) : literal(s ? s : "") {} + SrcAttr(std::string_view s) : literal(s) {} + + bool empty() const { return id == Twine::Null && literal.empty(); } +}; + // TODO clean up? extern int64_t signorm_ns; extern int signorm_count; @@ -1266,6 +1295,18 @@ struct RTLIL::AttrObject { dict attributes; + // Typed src field. Outside the attribute dict — src is a structured + // reference into a TwinePool. The pool is NOT stored here: every live + // AttrObject is reachable from a Design (Cell/Wire/Process via their + // module, Module via its design field), and inner-process AttrObjects + // (CaseRule, SwitchRule, MemWriteAction) are owned by a Process whose + // dtor drives their refcount on their behalf. src_id_ is a "weak" + // integer reference — copying it does not retain; destroying the + // AttrObject does not release. Lifecycle is driven by the leaf + // subtype's destructor (Cell, Wire, Module, Process) walking up to + // its owning pool, and by Process::~Process for the nested types. + Twine::Id src_id_ = Twine::Null; + bool has_attribute(RTLIL::IdString id) const; void set_bool_attribute(RTLIL::IdString id, bool value=true); @@ -1284,12 +1325,49 @@ struct RTLIL::AttrObject void add_strpool_attribute(RTLIL::IdString id, const pool &data); pool get_strpool_attribute(RTLIL::IdString id) const; - void set_src_attribute(const std::string &src) { - set_string_attribute(ID::src, src); - } - std::string get_src_attribute() const { - return get_string_attribute(ID::src); - } + Twine::Id src_id() const { return src_id_; } + + // Store an interned id and manage refcount via the provided pool: + // retain the new id; release the previous one if any. Twine::Null + // clears. The caller supplies the pool because AttrObject does not + // store one — typically derived from context (cell->module->design-> + // src_twines and friends) or known directly (frontends, copy_from). + void set_src_id(TwinePool *pool, Twine::Id id); + + // Apply `src` to this AttrObject via `pool`. If `src` carries a + // pre-interned id (returned by e.g. `other->src_ref()`) it is + // retained directly — no flatten/intern. Otherwise `src.literal` + // is interned (handling "@N" refs and splitting pipe-joined + // multi-leaf inputs into a Concat). Empty `src` clears src_id_. + void set_src_attribute(TwinePool *pool, const RTLIL::SrcAttr &src); + // Flatten the held src_id_ via `pool` to its pipe-joined literal. + std::string get_src_attribute(const TwinePool *pool) const; + + // Transfer src verbatim from `source` to this object. The two-arg + // form assumes same-pool: `source`'s src_id_ is retained directly + // on the destination in `pool`. The three-arg form handles the + // cross-pool case by rebuilding `source`'s subtree (Concat/Suffix/ + // Leaf) into `dst_pool` via copy_from. Either way no flatten/ + // re-intern round-trip on the canonical leaf strings, so a Concat + // src never collapses into a pipe-containing Leaf. + void adopt_src_from(TwinePool *pool, const RTLIL::AttrObject *source); + void adopt_src_from(TwinePool *dst_pool, const RTLIL::AttrObject *source, + const TwinePool *src_pool); + + // The raw twine id naming this object's src. Pass this — never the + // flattened path string from get_src_attribute() — when handing + // src to a CellAdder method or to another object's set_src: every + // CellAdder method has a Twine::Id overload that adopts the slot + // directly with no flatten/intern round-trip, preserving Suffix/ + // Concat structure and never producing a pipe-containing Leaf + // from a Concat src. + Twine::Id src_ref() const { return src_id_; } + + // Replace `attributes` with `buf`, extracting any ID::src entry first + // and routing it via `pool` to the typed src_id_ field. Use this in + // frontends instead of `obj->attributes = std::move(buf)` so file src + // lands in the twine pool rather than the attribute dict. + void absorb_attrs(TwinePool *pool, dict &&buf); void set_hdlname_attribute(const vector &hierarchy); vector get_hdlname_attribute() const; @@ -1911,6 +1989,49 @@ struct RTLIL::Design dict modules_; std::vector bindings_; + // Interns src-attribute strings and concats thereof. Cells reach this + // via cell->module->design->src_twines. + TwinePool src_twines; + + // Resolve a stored src-attribute string to its flat path:line.col + // representation. If `raw` is a twine reference ("@N") returns + // src_twines.flatten(N); otherwise returns `raw` unchanged. Backends + // must call this whenever they emit src to a user-facing format. + std::string resolve_src(std::string_view raw) const { + Twine::Id id = TwinePool::parse_ref(raw); + if (id == Twine::Null) + return std::string(raw); + return src_twines.flatten(id); + } + + // Merge `source`'s src attribute into `target`'s src attribute via the + // twine pool. After the call `target` carries the combined "@N" ref. + // Handles every case: source has a "@N" ref → reuse that Id; source + // has a legacy pipe-joined literal → split and intern each leaf; + // target had pre-existing src → its leaves are folded in too. Use + // this instead of `target->add_strpool_attribute(ID::src, source->get_strpool_attribute(ID::src))`, + // which round-trips through a flat string and corrupts "@N" refs. + void merge_src(RTLIL::AttrObject *target, const RTLIL::AttrObject *source); + + // Same as merge_src but consumes a raw set of leaf strings (each of + // which may itself be either a "@N" ref or a literal path). + void merge_src(RTLIL::AttrObject *target, const pool &leaves); + + // Returns the resolved leaf-string set backing obj's src attribute. + // "@N" refs are expanded through the pool; legacy pipe-joined + // literals are split. Use this instead of get_strpool_attribute(ID::src) + // when you actually need to iterate the path:line.col entries. + pool src_leaves(const RTLIL::AttrObject *obj) const; + + // Walk the design, collect the set of "@N" ids actually referenced by + // any AttrObject's src, then compact src_twines to contain only those + // nodes plus their transitive leaf children, and rewrite every cell + // src attribute through the resulting old-id -> new-id remap. + // Intermediate concats produced by successive merges become unreferenced + // once a fresh concat takes their place on the surviving cell, so this + // is what reaps them. Returns the number of nodes freed. + size_t gc_twines(); + std::vector> verilog_packages, verilog_globals; std::unique_ptr verilog_defines; @@ -1952,6 +2073,13 @@ struct RTLIL::Design void check(); void optimize(); + // Wholesale-copy this design into `dst`. `dst` must be empty (no + // modules). Copies src_twines verbatim and clones each module + // preserving src_id_ values directly — avoids the per-module + // copy_from pool rebuild and yields byte-identical RTLIL output + // across design -push/-pop, -save/-load, etc. + void clone_into(RTLIL::Design *dst) const; + // checks if the given module is included in the current selection bool selected_module(RTLIL::IdString mod_name) const; @@ -2065,7 +2193,7 @@ struct RTLIL::Design }; namespace RTLIL_BACKEND { -void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); +void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire, const RTLIL::Design *design, bool resolve_src); } struct RTLIL::Wire : public RTLIL::NamedObject @@ -2083,7 +2211,7 @@ public: Wire(ConstructToken); ~Wire(); - friend void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); + friend void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire, const RTLIL::Design *design, bool resolve_src); RTLIL::Cell *driverCell_ = nullptr; RTLIL::IdString driverPort_; @@ -2095,6 +2223,17 @@ public: int width, start_offset, port_id; bool port_input, port_output, upto, is_signed; + // Context-aware src helpers. Resolve the destination pool via + // `module->design->src_twines`; assert the wire is attached. + using AttrObject::set_src_attribute; + using AttrObject::get_src_attribute; + using AttrObject::adopt_src_from; + void set_src_attribute(const RTLIL::SrcAttr &src); + std::string get_src_attribute() const; + // Transfer src from `source` verbatim (same pool). Asserts attached + // to a design — derives the pool via module->design->src_twines. + void adopt_src_from(const RTLIL::AttrObject *source); + bool known_driver() const { return driverCell_ != nullptr; } RTLIL::Cell *driverCell() const { log_assert(driverCell_); return driverCell_; }; @@ -2172,6 +2311,17 @@ public: dict connections_; dict parameters; + // Context-aware src helpers. Resolve the destination pool via + // `module->design->src_twines`; assert the cell is attached. + using AttrObject::set_src_attribute; + using AttrObject::get_src_attribute; + using AttrObject::adopt_src_from; + void set_src_attribute(const RTLIL::SrcAttr &src); + std::string get_src_attribute() const; + // Transfer src from `source` verbatim (same pool). Asserts attached + // to a design — derives the pool via module->design->src_twines. + void adopt_src_from(const RTLIL::AttrObject *source); + // access cell ports bool hasPort(RTLIL::IdString portname) const; void unsetPort(RTLIL::IdString portname); @@ -2281,6 +2431,17 @@ public: RTLIL::CaseRule root_case; std::vector syncs; + // Context-aware src helpers. Resolve the destination pool via + // `module->design->src_twines`; assert the process is attached. + using AttrObject::set_src_attribute; + using AttrObject::get_src_attribute; + using AttrObject::adopt_src_from; + void set_src_attribute(const RTLIL::SrcAttr &src); + std::string get_src_attribute() const; + // Transfer src from `source` verbatim (same pool). Asserts attached + // to a design — derives the pool via module->design->src_twines. + void adopt_src_from(const RTLIL::AttrObject *source); + template void rewrite_sigspecs(T &functor); template void rewrite_sigspecs2(T &functor); RTLIL::Process *clone() const; @@ -2380,212 +2541,212 @@ class CellAdderMixin { public: // The add* methods create a cell and return the created cell. All signals must exist in advance. - RTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addBuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addBuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addShl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addShr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addSshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addSshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addShift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addShiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addShl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addShr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addSshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addSshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addShift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addShiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addLt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addLe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addEq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addNe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addEqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addNex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addGe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addGt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addLt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addLe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addEq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addNe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addEqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addNex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addGe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addGt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addAdd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addSub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addAdd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addSub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); // truncating division - RTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); // truncating modulo - RTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addDivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); + RTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addFa (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::Cell* addFa (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addLogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addLogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addLogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addLogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addMux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addPmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::Cell* addMux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addPmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addBweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addBwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::Cell* addBweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addBwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addSlice (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src = ""); - RTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addLut (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const std::string &src = ""); - RTLIL::Cell* addTribuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addAssert (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addAssume (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addLive (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addFair (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addCover (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addEquiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::Cell* addSlice (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addLut (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addTribuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAssert (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAssume (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addLive (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addFair (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addCover (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addEquiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addSr (RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, const RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addFf (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = ""); - RTLIL::Cell* addDff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffsre (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAldff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAldffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = ""); - RTLIL::Cell* addSdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addSdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addSdffce (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool en_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatchsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); + RTLIL::Cell* addSr (RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, const RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addFf (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDffsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDffsre (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAldff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAldffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addSdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool srst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addSdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addSdffce (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAdlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool en_polarity = true, bool arst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDlatchsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addBufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addNotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addAndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addNandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addOrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addNorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addXorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addXnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addAndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addOrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addMuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addNmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addOai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addOai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const std::string &src = ""); + RTLIL::Cell* addBufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addNotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addNandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addOrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addNorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addXorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addXnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addOrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addMuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addNmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addOai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addOai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addSrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - const RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addFfGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = ""); - RTLIL::Cell* addDffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = ""); + const RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addFfGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addDffsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); + RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addDffsreGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); + RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addAdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = ""); + bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addAdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value = false, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = ""); + bool arst_value = false, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addAldffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = ""); + const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addAldffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = ""); + const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addSdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value = false, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = ""); + bool srst_value = false, bool clk_polarity = true, bool srst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addSdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = ""); + bool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addSdffceGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatchGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const std::string &src = ""); + bool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addDlatchGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addAdlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value = false, bool en_polarity = true, bool arst_polarity = true, const std::string &src = ""); + bool arst_value = false, bool en_polarity = true, bool arst_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); + RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = ""); + RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); // The methods without the add* prefix create a cell and an output signal. They return the newly created output signal. - RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Buf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Buf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Or (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Xor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Xnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Or (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Xor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Xnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigSpec ReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec ReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec ReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec ReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec ReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec ReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigSpec Shl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Shr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Sshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Sshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Shift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Shiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec Shl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Shr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Sshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Sshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Shift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Shiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigSpec Lt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Le (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Eq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Ne (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Eqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Nex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Ge (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Gt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec Lt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Le (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Eq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Ne (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Eqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Nex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Ge (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Gt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); // truncating division - RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); // truncating modulo - RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = ""); + RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec LogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec LogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec LogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec LogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigSpec Mux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = ""); - RTLIL::SigSpec Pmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = ""); - RTLIL::SigSpec Bmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = ""); - RTLIL::SigSpec Demux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = ""); + RTLIL::SigSpec Mux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Pmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Bmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Demux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigSpec Bweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const std::string &src = ""); - RTLIL::SigSpec Bwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = ""); + RTLIL::SigSpec Bweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Bwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigBit BufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = ""); - RTLIL::SigBit NotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = ""); - RTLIL::SigBit AndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit NandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit OrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit NorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit XorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit XnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit AndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit OrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit MuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = ""); - RTLIL::SigBit NmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = ""); - RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = ""); - RTLIL::SigBit Oai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = ""); - RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const std::string &src = ""); - RTLIL::SigBit Oai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const std::string &src = ""); + RTLIL::SigBit BufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit NotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit AndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit NandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit OrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit NorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit XorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit XnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit AndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit OrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit MuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit NmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit Oai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigBit Oai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); }; struct RTLIL::Module : public RTLIL::NamedObject, public CellAdderMixin @@ -2620,6 +2781,17 @@ public: dict memories; dict processes; + // Context-aware src helpers. Resolve the destination pool via + // `design->src_twines`; assert the module is attached. + using AttrObject::set_src_attribute; + using AttrObject::get_src_attribute; + using AttrObject::adopt_src_from; + void set_src_attribute(const RTLIL::SrcAttr &src); + std::string get_src_attribute() const; + // Transfer src from `source` verbatim (same pool). Asserts attached + // to a design — derives the pool via module->design->src_twines. + void adopt_src_from(const RTLIL::AttrObject *source); + Module(); virtual ~Module(); virtual RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool mayfail = false); @@ -2675,8 +2847,21 @@ public: template void rewrite_sigspecs(T &functor); template void rewrite_sigspecs2(T &functor); - void cloneInto(RTLIL::Module *new_mod) const; + // `src_id_verbatim`: when true, the caller guarantees that + // `new_mod->design->src_twines` is a verbatim copy of + // `this->design->src_twines`, so src_id_ values can be transferred + // without retain/release on the destination pool (the copied refcounts + // already account for the new AttrObject references). Used by + // Design::clone_into for wholesale design copies. + void cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim = false) const; virtual RTLIL::Module *clone() const; + // Clone variant that attaches the new module to `dst` BEFORE cloneInto + // runs. This is the right pattern when the destination design is known + // up front — it avoids the "detached module, attach later" flow and + // the pending-literal src stashing it entails. Subtypes override to + // preserve their type (AstModule). `src_id_verbatim` is forwarded to + // cloneInto. + virtual RTLIL::Module *clone(RTLIL::Design *dst, bool src_id_verbatim = false) const; bool has_memories() const; bool has_processes() const; @@ -2754,22 +2939,22 @@ public: // The add* methods create a cell and return the created cell. All signals must exist in advance. - RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = ""); + RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); // The methods without the add* prefix create a cell and an output signal. They return the newly created output signal. - RTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1, const std::string &src = ""); - RTLIL::SigSpec Anyseq (RTLIL::IdString name, int width = 1, const std::string &src = ""); - RTLIL::SigSpec Allconst (RTLIL::IdString name, int width = 1, const std::string &src = ""); - RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = ""); - RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = ""); + RTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Anyseq (RTLIL::IdString name, int width = 1, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Allconst (RTLIL::IdString name, int width = 1, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec Initstate (RTLIL::IdString name, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); - RTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); - RTLIL::Cell* addSetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = ""); - RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); - RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = ""); - RTLIL::SigSpec FutureFF (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src = ""); + RTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addSetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); + RTLIL::SigSpec FutureFF (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const RTLIL::SrcAttr &src = RTLIL::SrcAttr()); std::string to_rtlil_str() const; #ifdef YOSYS_ENABLE_PYTHON diff --git a/kernel/twine.cc b/kernel/twine.cc new file mode 100644 index 000000000..47f9d18c6 --- /dev/null +++ b/kernel/twine.cc @@ -0,0 +1,455 @@ +#include "kernel/twine.h" +#include "kernel/log.h" + +YOSYS_NAMESPACE_BEGIN + +Twine::Id TwinePool::alloc_slot_(Twine &&node) +{ + if (!free_list_.empty()) { + // Pop the SMALLEST free id (not the most recent), so reuse order + // matches the original allocation order when an entire pool gets + // freed and rebuilt. That makes write_rtlil emit byte-identical + // "@N" refs across design -push;-pop and similar wholesale-clone + // cycles, even though the in-memory pool got renumbered through + // the free list. + auto it = std::min_element(free_list_.begin(), free_list_.end()); + Twine::Id id = *it; + free_list_.erase(it); + nodes_[id] = std::move(node); + refcount_[id] = 0; + return id; + } + Twine::Id id = static_cast(nodes_.size()); + nodes_.push_back(std::move(node)); + refcount_.push_back(0); + return id; +} + +Twine::Id TwinePool::intern(std::string_view leaf) +{ + if (leaf.empty()) + return Twine::Null; + std::string key{leaf}; + if (auto it = leaf_index_.find(key); it != leaf_index_.end()) { + retain(it->second); + return it->second; + } + Twine::Id id = alloc_slot_(Twine{std::move(key)}); + leaf_index_[std::get(nodes_[id].data)] = id; + refcount_[id] = 1; + return id; +} + +Twine::Id TwinePool::intern_suffix(Twine::Id parent, std::string_view tail) +{ + if (parent == Twine::Null) + return intern(tail); + log_assert(parent < nodes_.size() && !nodes_[parent].is_dead()); + log_assert(nodes_[parent].is_flat() && "Suffix parent must be a flat node (Leaf or Suffix)"); + if (tail.empty()) { + // No tail means "the same string as parent". Hand back a fresh + // owning ref on parent — semantically equivalent to a degenerate + // suffix node, but we avoid allocating a slot for it. + retain(parent); + return parent; + } + + std::pair key{parent, std::string{tail}}; + if (auto it = suffix_index_.find(key); it != suffix_index_.end()) { + retain(it->second); + return it->second; + } + + // Internal child ref: the suffix node owns one ref on its parent. + retain(parent); + Twine::Id id = alloc_slot_(Twine{Twine::Suffix{parent, std::string{tail}}}); + const auto &stored = std::get(nodes_[id].data); + suffix_index_[std::make_pair(stored.parent, stored.tail)] = id; + refcount_[id] = 1; + return id; +} + +Twine::Id TwinePool::concat(std::span parts) +{ + // Flat invariant: a Concat node only ever holds flat children (Leaf + // or Suffix), never another Concat. Splice in concats' children + // directly so identical sets map to byte-equal child vectors + // regardless of how callers nested concats. + std::vector children; + children.reserve(parts.size()); + pool seen; + auto push_flat = [&](Twine::Id flat_id) { + if (seen.insert(flat_id).second) + children.push_back(flat_id); + }; + for (Twine::Id p : parts) { + if (p == Twine::Null) + continue; + log_assert(p < nodes_.size() && !nodes_[p].is_dead()); + const Twine &n = nodes_[p]; + if (n.is_flat()) { + push_flat(p); + } else { + for (Twine::Id grandchild : n.children()) + push_flat(grandchild); + } + } + + if (children.empty()) + return Twine::Null; + if (children.size() == 1) { + retain(children.front()); + return children.front(); + } + + if (auto it = concat_index_.find(children); it != concat_index_.end()) { + retain(it->second); + return it->second; + } + + // Internal child refs: the concat node owns one ref on each child. + for (Twine::Id c : children) + retain(c); + Twine::Id id = alloc_slot_(Twine{std::move(children)}); + concat_index_[std::get>(nodes_[id].data)] = id; + refcount_[id] = 1; + return id; +} + +Twine::Id TwinePool::concat(Twine::Id a, Twine::Id b) +{ + std::array pair{a, b}; + return concat(std::span{pair}); +} + +void TwinePool::retain(Twine::Id id) +{ + if (id == Twine::Null) + return; + log_assert(id < nodes_.size() && !nodes_[id].is_dead()); + refcount_[id]++; +} + +void TwinePool::release(Twine::Id id) +{ + if (id == Twine::Null) + return; + log_assert(id < nodes_.size() && !nodes_[id].is_dead()); + log_assert(refcount_[id] > 0); + if (--refcount_[id] == 0) + destroy_slot_(id); +} + +uint32_t TwinePool::refcount(Twine::Id id) const +{ + if (id == Twine::Null) + return 0; + return refcount_.at(id); +} + +bool TwinePool::is_alive(Twine::Id id) const +{ + if (id == Twine::Null) + return false; + return id < nodes_.size() && !nodes_[id].is_dead(); +} + +void TwinePool::destroy_slot_(Twine::Id id) +{ + Twine &n = nodes_[id]; + if (n.is_leaf()) { + leaf_index_.erase(n.leaf()); + } else if (n.is_concat()) { + // Release internal child refs. Capture by move so iteration is + // stable across child destroy_slot_ side effects. + std::vector children = std::move(std::get>(n.data)); + concat_index_.erase(children); + n.data = std::monostate{}; + free_list_.push_back(id); + for (Twine::Id c : children) + release(c); + return; + } else if (n.is_suffix()) { + // Capture parent by move and release after dropping the slot, + // since releasing may recursively destroy the parent and we + // want this slot's tombstone to be visible by then. + Twine::Suffix s = std::move(std::get(n.data)); + suffix_index_.erase(std::make_pair(s.parent, s.tail)); + n.data = std::monostate{}; + free_list_.push_back(id); + release(s.parent); + return; + } + n.data = std::monostate{}; + free_list_.push_back(id); +} + +void TwinePool::collect_leaves(Twine::Id id, pool &out) const +{ + if (id == Twine::Null) + return; + const Twine &n = nodes_.at(id); + if (n.is_dead()) + return; + if (n.is_leaf()) { + out.insert(n.leaf()); + return; + } + if (n.is_suffix()) { + // A suffix is semantically a single flat string. Materialize it + // and insert into the set just like a leaf. + out.insert(flat_string_(id)); + return; + } + for (Twine::Id c : n.children()) + collect_leaves(c, out); +} + +std::string TwinePool::flat_string_(Twine::Id id) const +{ + // Walk the parent chain iteratively to avoid recursion depth concerns + // on deep suffix trees. Collect tails (and the root leaf) then stitch + // in root-to-tail order. + log_assert(id != Twine::Null); + std::vector parts; + while (true) { + const Twine &n = nodes_.at(id); + if (n.is_leaf()) { + parts.push_back(n.leaf()); + break; + } + log_assert(n.is_suffix()); + parts.push_back(n.suffix().tail); + id = n.suffix().parent; + } + size_t total = 0; + for (auto p : parts) + total += p.size(); + std::string out; + out.reserve(total); + for (auto it = parts.rbegin(); it != parts.rend(); ++it) + out.append(*it); + return out; +} + +std::string TwinePool::flatten(Twine::Id id, char sep) const +{ + if (id == Twine::Null) + return {}; + pool leaves; + collect_leaves(id, leaves); + std::string out; + for (const auto &s : leaves) { + if (s.empty()) + continue; + if (!out.empty()) + out += sep; + out += s; + } + return out; +} + +std::string TwinePool::format_ref(Twine::Id id) +{ + if (id == Twine::Null) + return {}; + return "@" + std::to_string(id); +} + +Twine::Id TwinePool::parse_ref(std::string_view s) +{ + if (s.size() < 2 || s[0] != '@') + return Twine::Null; + uint64_t v = 0; + for (size_t i = 1; i < s.size(); i++) { + char c = s[i]; + if (c < '0' || c > '9') + return Twine::Null; + v = v * 10 + static_cast(c - '0'); + if (v >= std::numeric_limits::max()) + return Twine::Null; + } + return static_cast(v); +} + +void TwinePool::dump(const char *banner) const +{ + if (banner) + log("%s (%zu live nodes: %zu leaves, %zu suffixes, %zu concats, %zu free slots)\n", + banner, nodes_.size() - free_list_.size(), + leaf_index_.size(), suffix_index_.size(), + concat_index_.size(), free_list_.size()); + for_each_live([&](Twine::Id id, const Twine &n) { + if (n.is_leaf()) { + log(" @%u leaf rc=%u %s\n", id, refcount_[id], n.leaf().c_str()); + } else if (n.is_suffix()) { + log(" @%u suffix rc=%u @%u + %s\n", id, refcount_[id], + n.suffix().parent, n.suffix().tail.c_str()); + } else { + std::string children; + for (Twine::Id c : n.children()) { + if (!children.empty()) + children += ", "; + children += "@" + std::to_string(c); + } + log(" @%u concat rc=%u [%s]\n", id, refcount_[id], children.c_str()); + } + }); +} + +dict TwinePool::gc(const pool &live) +{ + // Closure: mark every node reachable from `live`. Concat children + // (Leaf or Suffix) and Suffix parents (Leaf or Suffix) are both + // followed. With Suffix nodes chains can be more than one step deep, + // so use a worklist rather than a single BFS step. + pool reachable; + std::vector work; + for (Twine::Id id : live) { + if (id == Twine::Null || id >= nodes_.size() || nodes_[id].is_dead()) + continue; + if (reachable.insert(id).second) + work.push_back(id); + } + while (!work.empty()) { + Twine::Id id = work.back(); + work.pop_back(); + const Twine &n = nodes_[id]; + if (n.is_concat()) { + for (Twine::Id c : n.children()) + if (reachable.insert(c).second) + work.push_back(c); + } else if (n.is_suffix()) { + Twine::Id p = n.suffix().parent; + if (reachable.insert(p).second) + work.push_back(p); + } + } + + // Rebuild the pool from scratch. Process flats (Leaf, then Suffix) + // before Concats so concat-child lookups can resolve, and process + // suffixes parent-before-child via a recursive helper that memoizes + // into `remap`. + std::vector new_nodes; + std::vector new_refcount; + dict new_leaf_index; + dict, Twine::Id> new_concat_index; + dict, Twine::Id> new_suffix_index; + dict remap; + + auto intern_leaf = [&](const std::string &text) -> Twine::Id { + if (auto it = new_leaf_index.find(text); it != new_leaf_index.end()) + return it->second; + Twine::Id id = static_cast(new_nodes.size()); + new_nodes.push_back(Twine{text}); + new_refcount.push_back(0); + new_leaf_index[std::get(new_nodes.back().data)] = id; + return id; + }; + + for (Twine::Id old_id : reachable) { + const Twine &n = nodes_[old_id]; + if (n.is_leaf()) + remap[old_id] = intern_leaf(n.leaf()); + } + + std::function remap_flat = [&](Twine::Id old_id) -> Twine::Id { + if (auto it = remap.find(old_id); it != remap.end()) + return it->second; + const Twine &n = nodes_[old_id]; + log_assert(n.is_suffix()); + Twine::Id new_parent = remap_flat(n.suffix().parent); + std::pair key{new_parent, n.suffix().tail}; + if (auto sit = new_suffix_index.find(key); sit != new_suffix_index.end()) { + remap[old_id] = sit->second; + return sit->second; + } + Twine::Id new_id = static_cast(new_nodes.size()); + new_nodes.push_back(Twine{Twine::Suffix{new_parent, n.suffix().tail}}); + new_refcount.push_back(0); + const auto &stored = std::get(new_nodes.back().data); + new_suffix_index[std::make_pair(stored.parent, stored.tail)] = new_id; + remap[old_id] = new_id; + return new_id; + }; + + for (Twine::Id old_id : reachable) { + const Twine &n = nodes_[old_id]; + if (n.is_suffix() && remap.find(old_id) == remap.end()) + remap_flat(old_id); + } + + for (Twine::Id old_id : reachable) { + const Twine &n = nodes_[old_id]; + if (!n.is_concat()) + continue; + std::vector children; + children.reserve(n.children().size()); + for (Twine::Id c : n.children()) + children.push_back(remap.at(c)); + if (auto it = new_concat_index.find(children); it != new_concat_index.end()) { + remap[old_id] = it->second; + } else { + Twine::Id new_id = static_cast(new_nodes.size()); + new_nodes.push_back(Twine{std::move(children)}); + new_refcount.push_back(0); + new_concat_index[std::get>(new_nodes.back().data)] = new_id; + remap[old_id] = new_id; + } + } + + // Refcounts in the rebuilt pool: every external "live" id passed in by + // the caller corresponds to one external owner reference; concats + // hold one ref per stored child; suffixes hold one ref on their parent. + for (Twine::Id old_id : live) { + auto it = remap.find(old_id); + if (it != remap.end()) + new_refcount[it->second]++; + } + for (size_t i = 0; i < new_nodes.size(); i++) { + if (new_nodes[i].is_concat()) { + for (Twine::Id c : new_nodes[i].children()) + new_refcount[c]++; + } else if (new_nodes[i].is_suffix()) { + new_refcount[new_nodes[i].suffix().parent]++; + } + } + + nodes_ = std::move(new_nodes); + refcount_ = std::move(new_refcount); + free_list_.clear(); + leaf_index_ = std::move(new_leaf_index); + concat_index_ = std::move(new_concat_index); + suffix_index_ = std::move(new_suffix_index); + return remap; +} + +Twine::Id TwinePool::copy_from(const TwinePool &src, Twine::Id src_id) +{ + if (src_id == Twine::Null) + return Twine::Null; + log_assert(src_id < src.nodes_.size() && !src.nodes_[src_id].is_dead()); + const Twine &n = src.nodes_[src_id]; + if (n.is_leaf()) + return intern(n.leaf()); + if (n.is_suffix()) { + Twine::Id new_parent = copy_from(src, n.suffix().parent); + Twine::Id result = intern_suffix(new_parent, n.suffix().tail); + // intern_suffix retained the parent internally; the caller-side + // +1 ref from copy_from(parent) is surplus. + release(new_parent); + return result; + } + std::vector children; + children.reserve(n.children().size()); + for (Twine::Id c : n.children()) + children.push_back(copy_from(src, c)); + Twine::Id result = concat(std::span{children}); + // concat retained each child internally; the caller-side +1 refs from + // copy_from(child) are surplus. + for (Twine::Id c : children) + release(c); + return result; +} + +YOSYS_NAMESPACE_END diff --git a/kernel/twine.h b/kernel/twine.h new file mode 100644 index 000000000..0239f89fe --- /dev/null +++ b/kernel/twine.h @@ -0,0 +1,246 @@ +#ifndef YOSYS_TWINE_H +#define YOSYS_TWINE_H + +#include "kernel/yosys_common.h" + +#include +#include +#include +#include +#include +#include +#include + +YOSYS_NAMESPACE_BEGIN + +// A Twine is an interned, possibly composite source-location string. Leaves +// are flat path:line.col substrings (the existing src-attribute literal). A +// Concat node holds an ordered sequence of child twines, so merging the src +// of N cells is O(N) lookups plus one concat-table probe — independent of +// the total path-string length the materialized result would have. +// +// Twines are valid only relative to the TwinePool that minted them. The pool +// lives on RTLIL::Design (design->src_twines). +struct Twine +{ + using Id = uint32_t; + static constexpr Id Null = std::numeric_limits::max(); + + // Suffix shares a `parent` prefix with other suffixes and contributes + // its own `tail` string. The materialized leaf string is + // flat_string(parent) + tail, i.e. suffixes form trees whose leaves + // (string variant) are the roots — like a reverse-trie of common + // prefixes. The parent is itself flat (Leaf or Suffix), never a + // Concat. + struct Suffix { + Id parent; + std::string tail; + }; + + // Leaf holds the literal path:line.col string. Suffix holds a parent + // id + own tail (see above). Concat holds the ordered children. + // Concats are kept flat by TwinePool::concat — children are always + // flat (Leaf or Suffix), never other Concats. monostate is the + // tombstone marker for freed slots awaiting reuse via the free list. + std::variant, Suffix> data; + + bool is_dead() const { return std::holds_alternative(data); } + bool is_leaf() const { return std::holds_alternative(data); } + bool is_concat() const { return std::holds_alternative>(data); } + bool is_suffix() const { return std::holds_alternative(data); } + bool is_flat() const { return is_leaf() || is_suffix(); } + const std::string &leaf() const { return std::get(data); } + const std::vector &children() const { return std::get>(data); } + const Suffix &suffix() const { return std::get(data); } +}; + +class TwinePool +{ +public: + TwinePool() = default; + + // Intern a leaf string. Returns the same Id for byte-equal inputs. The + // returned Id carries one reference for the caller — release it when + // you are done holding it. Empty input returns Twine::Null. + Twine::Id intern(std::string_view leaf); + + // Intern a Suffix node. The resulting flat string is + // flat_string(parent) + tail. `parent` must be a flat node (Leaf or + // Suffix) — pass Twine::Null with a non-empty `tail` to fall back to + // intern(tail). Suffixes with the same (parent, tail) dedup. The + // returned Id carries one reference for the caller. Internally the + // new suffix retains a reference on `parent`; releasing the suffix + // releases that internal parent ref. Empty `tail` returns `parent` + // (with +1 ref for the caller). + Twine::Id intern_suffix(Twine::Id parent, std::string_view tail); + + // Build a Concat node referencing `parts` in order. Concat children are + // always leaves (flat-leaf invariant): any Concat passed in `parts` has + // its leaves spliced in instead. Duplicate leaves and Twine::Null are + // dropped. If only one distinct leaf remains its Id is returned directly + // (no Concat node created). Concats with the same child sequence dedup. + // The returned Id carries one reference for the caller. Internally the + // concat retains each child it stores; releasing the concat releases + // those internal child references. + Twine::Id concat(std::span parts); + Twine::Id concat(Twine::Id a, Twine::Id b); + + // Refcount control. retain bumps; release decrements and, on reaching + // zero, marks the slot dead, drops it from the dedup indexes, releases + // any child refs the slot owned, and pushes the slot id onto the free + // list for reuse by the next intern/concat. Both no-op on Twine::Null. + void retain(Twine::Id id); + void release(Twine::Id id); + uint32_t refcount(Twine::Id id) const; + bool is_alive(Twine::Id id) const; + + // Materialize a Twine to the pipe-separated flat string used by the + // existing src attribute convention. Leaves visit in left-to-right DFS + // order; duplicate leaves are skipped to match `pool`-style semantics. + std::string flatten(Twine::Id id, char sep = '|') const; + + // Materialize a flat node (Leaf or Suffix) to its single string. id + // must be a flat node (not a Concat) and not Twine::Null. + std::string flat_string(Twine::Id id) const { return flat_string_(id); } + + // Format an interned Id as the canonical src-attribute reference "@N". + // Twine::Null formats as the empty string. + static std::string format_ref(Twine::Id id); + + // Parse an "@N" reference back to an Id. Returns Twine::Null if `s` is + // not exactly "@" followed by one or more decimal digits — so legacy + // literal src strings (which always contain ':' separators and have no + // reason to start with '@') are passed through unrecognized. + static Twine::Id parse_ref(std::string_view s); + + // Lookup. Bounds-checked: out-of-range Id triggers log_assert via op. + const Twine &operator[](Twine::Id id) const { return nodes_.at(id); } + + size_t size() const { return nodes_.size(); } + size_t leaf_count() const { return leaf_index_.size(); } + size_t concat_count() const { return concat_index_.size(); } + size_t suffix_count() const { return suffix_index_.size(); } + + // One-shot debug dump of the entire pool to stdout via log(). Each leaf + // shows its string; each concat shows its child id list. Intended for + // `dump -twines` or ad-hoc tracing — output volume scales with size(). + void dump(const char *banner = nullptr) const; + + // Rebuild the pool to contain only the nodes named in `live` plus the + // transitive children of any live concats. Returns an old-id -> new-id + // remap; ids not in the result are dead. Callers must rewrite every + // stored "@N" cell src through the returned remap immediately, since + // after this call the old ids no longer mean what they used to. + dict gc(const pool &live); + + // Reconstruct `src->nodes_[src_id]` inside *this. Walks the structure + // — intern leaves, concat children — so a concat in `src` becomes a + // concat in this pool, not a flat literal of its leaves. Returns the + // id in this pool with +1 for the caller (release when done). Both + // pools may differ; the source is consulted read-only. + Twine::Id copy_from(const TwinePool &src, Twine::Id src_id); + + // Iterate every live (non-tombstoned) node. fn is `void(Twine::Id, const Twine&)`. + template + void for_each_live(Fn fn) const { + for (size_t i = 0; i < nodes_.size(); i++) { + const Twine &n = nodes_[i]; + if (n.is_dead()) + continue; + fn(static_cast(i), n); + } + } + +private: + std::vector nodes_; + std::vector refcount_; + std::vector free_list_; + dict leaf_index_; + dict, Twine::Id> concat_index_; + dict, Twine::Id> suffix_index_; + + Twine::Id alloc_slot_(Twine &&node); + void destroy_slot_(Twine::Id id); + void collect_leaves(Twine::Id id, pool &out) const; + // Materialize a flat node (Leaf or Suffix) into its full string. + std::string flat_string_(Twine::Id id) const; +}; + +// Owning reference to a Twine slot. Retains on construction (and on copy +// of a non-empty ref), releases on destruction. Use this in transient +// container types — FfData, Mem helpers — that need to keep a src_id_ +// alive across destruction of the original AttrObject that minted it, +// without having to fall back to a flattened path-string stash. +// +// Empty (no pool/no id) by default. A non-empty ref always carries a +// non-null pool and a live id. +class OwnedTwine +{ +public: + OwnedTwine() = default; + + // Adopt the +1 reference returned by `intern` / `concat` / `intern_suffix` + // / `copy_from`. Use OwnedTwine(pool, id, retain=true) when copying an + // id already held elsewhere (e.g. another AttrObject's src_id_). + OwnedTwine(TwinePool *pool, Twine::Id id, bool retain = true) : pool_(pool), id_(id) { + if (retain && pool_ && id_ != Twine::Null) + pool_->retain(id_); + } + + OwnedTwine(const OwnedTwine &other) : pool_(other.pool_), id_(other.id_) { + if (pool_ && id_ != Twine::Null) + pool_->retain(id_); + } + + OwnedTwine(OwnedTwine &&other) noexcept : pool_(other.pool_), id_(other.id_) { + other.pool_ = nullptr; + other.id_ = Twine::Null; + } + + OwnedTwine &operator=(const OwnedTwine &other) { + if (this == &other) + return *this; + release_(); + pool_ = other.pool_; + id_ = other.id_; + if (pool_ && id_ != Twine::Null) + pool_->retain(id_); + return *this; + } + + OwnedTwine &operator=(OwnedTwine &&other) noexcept { + if (this == &other) + return *this; + release_(); + pool_ = other.pool_; + id_ = other.id_; + other.pool_ = nullptr; + other.id_ = Twine::Null; + return *this; + } + + ~OwnedTwine() { release_(); } + + void reset() { + release_(); + pool_ = nullptr; + id_ = Twine::Null; + } + + TwinePool *pool() const { return pool_; } + Twine::Id id() const { return id_; } + bool empty() const { return id_ == Twine::Null; } + +private: + TwinePool *pool_ = nullptr; + Twine::Id id_ = Twine::Null; + + void release_() { + if (pool_ && id_ != Twine::Null) + pool_->release(id_); + } +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/unstable/patch.cc b/kernel/unstable/patch.cc index e114c48d6..631960e5e 100644 --- a/kernel/unstable/patch.cc +++ b/kernel/unstable/patch.cc @@ -76,25 +76,39 @@ std::vector Patch::commit_staged() { } namespace { - void collect_src(Cell* root, const std::vector& extras, - Cell* merge_src_into, pool& out) - { - out.insert(root->get_src_attribute()); - for (Cell* c : extras) - if (c) - out.insert(c->get_src_attribute()); - if (merge_src_into) - out.insert(merge_src_into->get_src_attribute()); - } - - void apply_src(const pool& src_pool, + void apply_src(Module* mod, Cell* root, const std::vector& extras, const std::vector& targets, Cell* merge_src_into) { - std::string src_str = AttrObject::strpool_attribute_to_str(src_pool); + // Without a design there's no pool — the cells can't carry typed + // src, so silently drop merge-of-src in that path. + if (!mod || !mod->design) + return; + + TwinePool& pool = mod->design->src_twines; + std::vector ids; + ids.reserve(2 + extras.size()); + auto push = [&](Cell *c) { + if (c && c->src_id() != Twine::Null) + ids.push_back(c->src_id()); + }; + push(root); + for (Cell *c : extras) + push(c); + push(merge_src_into); + if (ids.empty()) + return; + Twine::Id merged = pool.concat(std::span{ids}); + if (ys_debug()) { + log_debug("twine: merge yields %s (pool size %zu)\n", + TwinePool::format_ref(merged).c_str(), pool.size()); + if (ys_debug(2)) + pool.dump("twine pool state"); + } for (Cell* c : targets) - c->set_src_attribute(src_str); + c->set_src_id(&pool, merged); if (merge_src_into) - merge_src_into->set_src_attribute(src_str); + merge_src_into->set_src_id(&pool, merged); + pool.release(merged); } // Verifies via newcelltypes that root_cell has exactly one output port @@ -133,11 +147,8 @@ void Patch::patch(Cell* root_cell, IdString old_port, SigSpec new_sig, log_id(root_cell->name), log_id(old_port), log_signal(old_sig), log_signal(new_sig)); - pool src_pool; - collect_src(root_cell, extras, merge_src_into, src_pool); - std::vector committed = commit_staged(); - apply_src(src_pool, committed, merge_src_into); + apply_src(mod, root_cell, extras, committed, merge_src_into); // Drop root_cell's driver on the output port BEFORE wiring old_sig to // new_sig — otherwise old_sig would briefly have two drivers (root_cell @@ -179,11 +190,8 @@ void Patch::patch_ports(Cell* root_cell, log_error("patch_ports: cell %s of type %s has output port %s not in port_replacements\n", log_id(root_cell->name), log_id(root_cell->type), log_id(port)); - pool src_pool; - collect_src(root_cell, extras, merge_src_into, src_pool); - std::vector committed = commit_staged(); - apply_src(src_pool, committed, merge_src_into); + apply_src(mod, root_cell, extras, committed, merge_src_into); // Drop every port (inputs included) so root_cell becomes a disconnected // shell before we wire old_sigs to new_sigs. Doing this first ensures @@ -208,11 +216,14 @@ void Patch::patch_ports(Cell* root_cell, } void Patch::commit_inheriting_src(Cell* src_source) { - std::string src = src_source ? src_source->get_src_attribute() : std::string(); for (auto& cell : cells_) { - cell->set_src_attribute(src); cell->fixup_parameters(); - commit_cell(std::move(cell)); + Cell *committed = commit_cell(std::move(cell)); + // commit_cell attaches the cell to mod, so adopt_src_from can + // now resolve the pool via committed->module->design. Direct + // id transfer — no flatten/re-intern detour. + if (src_source) + committed->adopt_src_from(src_source); } for (auto& wire : wires_) commit_wire(std::move(wire)); diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 587963095..f40f19a72 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -29,6 +29,7 @@ OBJS += passes/cmds/tee.o OBJS += passes/cmds/write_file.o OBJS += passes/cmds/connwrappers.o OBJS += passes/cmds/trace.o +OBJS += passes/cmds/dump_twines.o OBJS += passes/cmds/plugin.o OBJS += passes/cmds/check.o OBJS += passes/cmds/edgetypes.o diff --git a/passes/cmds/chformal.cc b/passes/cmds/chformal.cc index a5b4cc227..5d86b6c3e 100644 --- a/passes/cmds/chformal.cc +++ b/passes/cmds/chformal.cc @@ -375,6 +375,8 @@ struct ChformalPass : public Pass { if (cell->type == ID($check)) { Cell *cover = module->addCell(NEW_ID_SUFFIX("coverenable"), ID($check)); cover->attributes = cell->attributes; + if (cell->src_id() != Twine::Null && module->design) + cover->set_src_id(&module->design->src_twines, cell->src_id()); cover->parameters = cell->parameters; cover->setParam(ID(FLAVOR), Const("cover")); @@ -420,6 +422,8 @@ struct ChformalPass : public Pass { Cell *plain_cell = module->addCell(NEW_ID, formal_flavor(cell)); plain_cell->attributes = cell->attributes; + if (cell->src_id() != Twine::Null && module->design) + plain_cell->set_src_id(&module->design->src_twines, cell->src_id()); SigBit sig_a = cell->getPort(ID::A); SigBit sig_en = cell->getPort(ID::EN); diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc index 9262ae0a2..205452d3d 100644 --- a/passes/cmds/design.cc +++ b/passes/cmds/design.cc @@ -338,11 +338,12 @@ struct DesignPass : public Pass { { RTLIL::Design *design_copy = new RTLIL::Design; - for (auto mod : design->modules()) { - // Triggers signorm flush if needed (hacky) - (void)mod->connections(); - design_copy->add(mod->clone()); - } + // Force signorm to flush any pending connection writes back + // to the modules' connections_ vectors before we read them. + for (auto &it : design->modules_) + (void)it.second->connections(); + + design->clone_into(design_copy); design_copy->selection_stack = design->selection_stack; design_copy->selection_vars = design->selection_vars; @@ -383,8 +384,7 @@ struct DesignPass : public Pass { RTLIL::Design *saved_design = pop_mode ? pushed_designs.back() : saved_designs.at(load_name); design->flagSigNormalized = saved_design->flagSigNormalized; - for (auto mod : saved_design->modules()) - design->add(mod->clone()); + saved_design->clone_into(design); design->selection_stack = saved_design->selection_stack; design->selection_vars = saved_design->selection_vars; diff --git a/passes/cmds/dump_twines.cc b/passes/cmds/dump_twines.cc new file mode 100644 index 000000000..06a012849 --- /dev/null +++ b/passes/cmds/dump_twines.cc @@ -0,0 +1,108 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Inspect the design-level twine pool that backs src-attribute interning. + */ + +#include "kernel/register.h" +#include "kernel/rtlil.h" +#include "kernel/twine.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct DumpTwinesPass : public Pass { + DumpTwinesPass() : Pass("dump_twines", "dump the design-level src twine pool") { } + + void help() override + { + log("\n"); + log(" dump_twines [-flat]\n"); + log("\n"); + log("Print every node in design->src_twines. Leaves show the literal\n"); + log("path:line.col string, concats show their child id list. With\n"); + log("-flat each concat is additionally rendered as the pipe-joined\n"); + log("flat string a backend would emit.\n"); + log("\n"); + } + + void execute(std::vector args, RTLIL::Design *design) override + { + bool flat = false; + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-flat") { + flat = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + const TwinePool &pool = design->src_twines; + log("twine pool: %zu nodes (%zu leaves, %zu suffixes, %zu concats)\n", + pool.size(), pool.leaf_count(), pool.suffix_count(), pool.concat_count()); + pool.for_each_live([&](Twine::Id id, const Twine &n) { + if (n.is_leaf()) { + log(" @%u leaf rc=%u %s\n", id, pool.refcount(id), n.leaf().c_str()); + } else if (n.is_suffix()) { + if (flat) { + log(" @%u suffix rc=%u @%u + %s -> %s\n", id, pool.refcount(id), + n.suffix().parent, n.suffix().tail.c_str(), + pool.flat_string(id).c_str()); + } else { + log(" @%u suffix rc=%u @%u + %s\n", id, pool.refcount(id), + n.suffix().parent, n.suffix().tail.c_str()); + } + } else { + std::string children; + for (Twine::Id c : n.children()) { + if (!children.empty()) + children += ", "; + children += "@" + std::to_string(c); + } + if (flat) { + log(" @%u concat rc=%u [%s] -> %s\n", id, pool.refcount(id), + children.c_str(), pool.flatten(id).c_str()); + } else { + log(" @%u concat rc=%u [%s]\n", id, pool.refcount(id), + children.c_str()); + } + } + }); + } +} DumpTwinesPass; + +struct GcTwinesPass : public Pass { + GcTwinesPass() : Pass("gc_twines", "reap unreferenced entries from the src twine pool") { } + + void help() override + { + log("\n"); + log(" gc_twines\n"); + log("\n"); + log("Walk the design, collect every \"@N\" referenced by any cell, wire,\n"); + log("module, memory, or process attribute, and rebuild design->src_twines\n"); + log("to contain only those entries plus their transitive leaf children.\n"); + log("Cell src attributes are rewritten in place via the resulting id\n"); + log("remap, so the design is unchanged at the path:line.col layer.\n"); + log("\n"); + log("Useful after long opt_merge / techmap runs that leave intermediate\n"); + log("concat nodes orphaned: each merge step splices a previous concat's\n"); + log("leaves into the new node (the flatten invariant), so the prior\n"); + log("concat becomes unreferenced as soon as the surviving cell's src is\n"); + log("rewritten.\n"); + log("\n"); + } + + void execute(std::vector args, RTLIL::Design *design) override + { + extra_args(args, 1, design); + size_t before = design->src_twines.size(); + size_t freed = design->gc_twines(); + log("twine gc: %zu nodes -> %zu (%zu freed)\n", + before, design->src_twines.size(), freed); + } +} GcTwinesPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/cmds/glift.cc b/passes/cmds/glift.cc index d906c241d..ebdaa6fc3 100644 --- a/passes/cmds/glift.cc +++ b/passes/cmds/glift.cc @@ -70,34 +70,34 @@ private: void add_precise_GLIFT_logic(const RTLIL::Cell *cell, RTLIL::SigSpec &port_a, RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_b, RTLIL::SigSpec &port_b_taint, RTLIL::SigSpec &port_y_taint) { //AKA AN2_SH2 or OR2_SH2 bool is_and = cell->type.in(ID($_AND_), ID($_NAND_)); - RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_1_1", port_a, false, cell->get_src_attribute()); - RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_1_2", port_b, false, cell->get_src_attribute()); - auto subexpr1 = module->And(cell->name.str() + "_t_1_3", is_and? port_a : n_port_a, port_b_taint, false, cell->get_src_attribute()); - auto subexpr2 = module->And(cell->name.str() + "_t_1_4", is_and? port_b : n_port_b, port_a_taint, false, cell->get_src_attribute()); - auto subexpr3 = module->And(cell->name.str() + "_t_1_5", port_a_taint, port_b_taint, false, cell->get_src_attribute()); - auto subexpr4 = module->Or(cell->name.str() + "_t_1_6", subexpr1, subexpr2, false, cell->get_src_attribute()); - module->addOr(cell->name.str() + "_t_1_7", subexpr4, subexpr3, port_y_taint, false, cell->get_src_attribute()); + RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_1_1", port_a, false, cell->src_ref()); + RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_1_2", port_b, false, cell->src_ref()); + auto subexpr1 = module->And(cell->name.str() + "_t_1_3", is_and? port_a : n_port_a, port_b_taint, false, cell->src_ref()); + auto subexpr2 = module->And(cell->name.str() + "_t_1_4", is_and? port_b : n_port_b, port_a_taint, false, cell->src_ref()); + auto subexpr3 = module->And(cell->name.str() + "_t_1_5", port_a_taint, port_b_taint, false, cell->src_ref()); + auto subexpr4 = module->Or(cell->name.str() + "_t_1_6", subexpr1, subexpr2, false, cell->src_ref()); + module->addOr(cell->name.str() + "_t_1_7", subexpr4, subexpr3, port_y_taint, false, cell->src_ref()); } void add_imprecise_GLIFT_logic_1(const RTLIL::Cell *cell, RTLIL::SigSpec &port_a, RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_b, RTLIL::SigSpec &port_b_taint, RTLIL::SigSpec &port_y_taint) { //AKA AN2_SH3 or OR2_SH3 bool is_and = cell->type.in(ID($_AND_), ID($_NAND_)); - RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_2_1", port_a, false, cell->get_src_attribute()); - auto subexpr1 = module->And(cell->name.str() + "_t_2_2", is_and? port_b : n_port_a, is_and? port_a_taint : port_b_taint, false, cell->get_src_attribute()); - module->addOr(cell->name.str() + "_t_2_3", is_and? port_b_taint : port_a_taint, subexpr1, port_y_taint, false, cell->get_src_attribute()); + RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_2_1", port_a, false, cell->src_ref()); + auto subexpr1 = module->And(cell->name.str() + "_t_2_2", is_and? port_b : n_port_a, is_and? port_a_taint : port_b_taint, false, cell->src_ref()); + module->addOr(cell->name.str() + "_t_2_3", is_and? port_b_taint : port_a_taint, subexpr1, port_y_taint, false, cell->src_ref()); } void add_imprecise_GLIFT_logic_2(const RTLIL::Cell *cell, RTLIL::SigSpec &port_a, RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_b, RTLIL::SigSpec &port_b_taint, RTLIL::SigSpec &port_y_taint) { //AKA AN2_SH4 or OR2_SH4 bool is_and = cell->type.in(ID($_AND_), ID($_NAND_)); - RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_3_1", port_b, false, cell->get_src_attribute()); - auto subexpr1 = module->And(cell->name.str() + "_t_3_2", is_and? port_a : n_port_b, is_and? port_b_taint : port_a_taint, false, cell->get_src_attribute()); - module->addOr(cell->name.str() + "_t_3_3", is_and? port_a_taint : port_b_taint, subexpr1, port_y_taint, false, cell->get_src_attribute()); + RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_3_1", port_b, false, cell->src_ref()); + auto subexpr1 = module->And(cell->name.str() + "_t_3_2", is_and? port_a : n_port_b, is_and? port_b_taint : port_a_taint, false, cell->src_ref()); + module->addOr(cell->name.str() + "_t_3_3", is_and? port_a_taint : port_b_taint, subexpr1, port_y_taint, false, cell->src_ref()); } void add_imprecise_GLIFT_logic_3(const RTLIL::Cell *cell, RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_b_taint, RTLIL::SigSpec &port_y_taint) { //AKA AN2_SH5 or OR2_SH5 or XR2_SH2 - module->addOr(cell->name.str() + "_t_4_1", port_a_taint, port_b_taint, port_y_taint, false, cell->get_src_attribute()); + module->addOr(cell->name.str() + "_t_4_1", port_a_taint, port_b_taint, port_y_taint, false, cell->src_ref()); } void add_imprecise_GLIFT_logic_4(RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_y_taint) { @@ -118,22 +118,22 @@ private: void add_precise_GLIFT_mux(const RTLIL::Cell *cell, RTLIL::SigSpec &port_a, RTLIL::SigSpec &port_a_taint, RTLIL::SigSpec &port_b, RTLIL::SigSpec &port_b_taint, RTLIL::SigSpec &port_s, RTLIL::SigSpec &port_s_taint, RTLIL::SigSpec &port_y_taint) { //S&At | ~S&Bt | ~A&B&St | A&~B&St | At&St | Bt&St - RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_4_1", port_a, false, cell->get_src_attribute()); - RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_4_2", port_b, false, cell->get_src_attribute()); - RTLIL::SigSpec n_port_s = module->LogicNot(cell->name.str() + "_t_4_3", port_s, false, cell->get_src_attribute()); - auto subexpr1 = module->And(cell->name.str() + "_t_4_4", port_s, port_a_taint, false, cell->get_src_attribute()); - auto subexpr2 = module->And(cell->name.str() + "_t_4_5", n_port_s, port_b_taint, false, cell->get_src_attribute()); - auto subexpr3 = module->And(cell->name.str() + "_t_4_6", n_port_a, port_b, false, cell->get_src_attribute()); - auto subexpr4 = module->And(cell->name.str() + "_t_4_7", subexpr3, port_s_taint, false, cell->get_src_attribute()); - auto subexpr5 = module->And(cell->name.str() + "_t_4_8", port_a, n_port_b, false, cell->get_src_attribute()); - auto subexpr6 = module->And(cell->name.str() + "_t_4_9", subexpr5, port_s_taint, false, cell->get_src_attribute()); - auto subexpr7 = module->And(cell->name.str() + "_t_4_10", port_a_taint, port_s_taint, false, cell->get_src_attribute()); - auto subexpr8 = module->And(cell->name.str() + "_t_4_11", port_b_taint, port_s_taint, false, cell->get_src_attribute()); - auto subexpr9 = module->Or(cell->name.str() + "_t_4_12", subexpr1, subexpr2, false, cell->get_src_attribute()); - auto subexpr10 = module->Or(cell->name.str() + "_t_4_13", subexpr4, subexpr6, false, cell->get_src_attribute()); - auto subexpr11 = module->Or(cell->name.str() + "_t_4_14", subexpr7, subexpr8, false, cell->get_src_attribute()); - auto subexpr12 = module->Or(cell->name.str() + "_t_4_15", subexpr9, subexpr10, false, cell->get_src_attribute()); - module->addOr(cell->name.str() + "_t_4_16", subexpr11, subexpr12, port_y_taint, false, cell->get_src_attribute()); + RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_4_1", port_a, false, cell->src_ref()); + RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_4_2", port_b, false, cell->src_ref()); + RTLIL::SigSpec n_port_s = module->LogicNot(cell->name.str() + "_t_4_3", port_s, false, cell->src_ref()); + auto subexpr1 = module->And(cell->name.str() + "_t_4_4", port_s, port_a_taint, false, cell->src_ref()); + auto subexpr2 = module->And(cell->name.str() + "_t_4_5", n_port_s, port_b_taint, false, cell->src_ref()); + auto subexpr3 = module->And(cell->name.str() + "_t_4_6", n_port_a, port_b, false, cell->src_ref()); + auto subexpr4 = module->And(cell->name.str() + "_t_4_7", subexpr3, port_s_taint, false, cell->src_ref()); + auto subexpr5 = module->And(cell->name.str() + "_t_4_8", port_a, n_port_b, false, cell->src_ref()); + auto subexpr6 = module->And(cell->name.str() + "_t_4_9", subexpr5, port_s_taint, false, cell->src_ref()); + auto subexpr7 = module->And(cell->name.str() + "_t_4_10", port_a_taint, port_s_taint, false, cell->src_ref()); + auto subexpr8 = module->And(cell->name.str() + "_t_4_11", port_b_taint, port_s_taint, false, cell->src_ref()); + auto subexpr9 = module->Or(cell->name.str() + "_t_4_12", subexpr1, subexpr2, false, cell->src_ref()); + auto subexpr10 = module->Or(cell->name.str() + "_t_4_13", subexpr4, subexpr6, false, cell->src_ref()); + auto subexpr11 = module->Or(cell->name.str() + "_t_4_14", subexpr7, subexpr8, false, cell->src_ref()); + auto subexpr12 = module->Or(cell->name.str() + "_t_4_15", subexpr9, subexpr10, false, cell->src_ref()); + module->addOr(cell->name.str() + "_t_4_16", subexpr11, subexpr12, port_y_taint, false, cell->src_ref()); } RTLIL::SigSpec score_metamux_select(const RTLIL::SigSpec &metamux_select, const RTLIL::IdString celltype) { @@ -144,7 +144,7 @@ private: //In this case, a nonzero hole metamux select value means less logic. //Thus we should invert the ReduceOr over the metamux_select signal. RTLIL::SigSpec pmux_select = module->ReduceOr(metamux_select.as_wire()->name.str() + "_nonzero", metamux_select); - return module->Pmux(NEW_ID, RTLIL::Const(1), RTLIL::Const(0), pmux_select, metamux_select.as_wire()->get_src_attribute()); + return module->Pmux(NEW_ID, RTLIL::Const(1), RTLIL::Const(0), pmux_select, metamux_select.as_wire()->src_ref()); } else { auto select_width = metamux_select.as_wire()->width; @@ -163,7 +163,7 @@ private: std::vector next_pmux_y_ports, pmux_y_ports(costs.begin(), costs.begin() + exp2(select_width)); for (auto i = 0; pmux_y_ports.size() > 1; ++i) { for (auto j = 0; j+1 < GetSize(pmux_y_ports); j += 2) { - next_pmux_y_ports.emplace_back(module->Pmux(stringf("%s_mux_%d_%d", metamux_select.as_wire()->name, i, j), pmux_y_ports[j], pmux_y_ports[j+1], metamux_select[GetSize(metamux_select) - 1 - i], metamux_select.as_wire()->get_src_attribute())); + next_pmux_y_ports.emplace_back(module->Pmux(stringf("%s_mux_%d_%d", metamux_select.as_wire()->name, i, j), pmux_y_ports[j], pmux_y_ports[j+1], metamux_select[GetSize(metamux_select) - 1 - i], metamux_select.as_wire()->src_ref())); } if (GetSize(pmux_y_ports) % 2 == 1) next_pmux_y_ports.push_back(pmux_y_ports[GetSize(pmux_y_ports) - 1]); @@ -234,7 +234,7 @@ private: log_assert(exp2(select_width) == num_versions); RTLIL::SigSpec meta_mux_select(module->addWire(cell->name.str() + "_sel", select_width)); meta_mux_selects.push_back(make_pair(meta_mux_select, cell->type)); - module->connect(meta_mux_select, module->Anyconst(cell->name.str() + "_hole", select_width, cell->get_src_attribute())); + module->connect(meta_mux_select, module->Anyconst(cell->name.str() + "_hole", select_width, cell->src_ref())); std::vector next_meta_mux_y_ports, meta_mux_y_ports(taint_version); for (auto i = 0; meta_mux_y_ports.size() > 1; ++i) { @@ -289,7 +289,7 @@ private: RTLIL::SigSpec meta_mux_select(module->addWire(cell->name.str() + "_sel", select_width)); meta_mux_selects.push_back(make_pair(meta_mux_select, cell->type)); - module->connect(meta_mux_select, module->Anyconst(cell->name.str() + "_hole", select_width, cell->get_src_attribute())); + module->connect(meta_mux_select, module->Anyconst(cell->name.str() + "_hole", select_width, cell->src_ref())); std::vector next_meta_mux_y_ports, meta_mux_y_ports(taint_version); for (auto i = 0; meta_mux_y_ports.size() > 1; ++i) { diff --git a/passes/cmds/linecoverage.cc b/passes/cmds/linecoverage.cc index 2f77f6f21..5c25e32c5 100644 --- a/passes/cmds/linecoverage.cc +++ b/passes/cmds/linecoverage.cc @@ -96,7 +96,7 @@ struct CoveragePass : public Pass { log_debug("Module %s:\n", module); for (auto wire: module->wires()) { log_debug("%s\t%s\t%s\n", module->selected(wire) ? "*" : " ", wire->get_src_attribute(), wire->name.unescape()); - for (auto src: wire->get_strpool_attribute(ID::src)) { + for (auto src: design->src_leaves(wire)) { auto filename = extract_src_filename(src); if (filename.empty()) continue; auto [begin, end] = extract_src_lines(src); @@ -110,7 +110,7 @@ struct CoveragePass : public Pass { } for (auto cell: module->cells()) { log_debug("%s\t%s\t%s\n", module->selected(cell) ? "*" : " ", cell->get_src_attribute(), cell->name.unescape()); - for (auto src: cell->get_strpool_attribute(ID::src)) { + for (auto src: design->src_leaves(cell)) { auto filename = extract_src_filename(src); if (filename.empty()) continue; auto [begin, end] = extract_src_lines(src); diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc index 6de2ffee3..99f695bc3 100644 --- a/passes/cmds/printattrs.cc +++ b/passes/cmds/printattrs.cc @@ -54,6 +54,14 @@ struct PrintAttrsPass : public Pass { log_assert(x.flags & RTLIL::CONST_FLAG_STRING || x.flags == RTLIL::CONST_FLAG_NONE); //intended to fail } + static void log_src(const Yosys::TwinePool *pool, const RTLIL::AttrObject *obj, const unsigned int indent) { + // Emit src outside the attributes loop — it lives on the typed + // src_id_ field, not in obj->attributes. + if (obj->src_id() != Twine::Null && pool) + log("%s(* src=\"%s\" *)\n", get_indent_str(indent), + obj->get_src_attribute(pool).c_str()); + } + void execute(std::vector args, RTLIL::Design *design) override { size_t argidx = 1; @@ -65,6 +73,7 @@ struct PrintAttrsPass : public Pass { if (design->selected_whole_module(mod)) { log("%s%s\n", get_indent_str(indent), mod->name.unescape()); indent += 2; + log_src(design ? &design->src_twines : nullptr, mod, indent); for (auto &it : mod->attributes) log_const(it.first, it.second, indent); } @@ -72,6 +81,7 @@ struct PrintAttrsPass : public Pass { for (auto cell : mod->selected_cells()) { log("%s%s\n", get_indent_str(indent), cell->name.unescape()); indent += 2; + log_src(design ? &design->src_twines : nullptr, cell, indent); for (auto &it : cell->attributes) log_const(it.first, it.second, indent); indent -= 2; @@ -80,6 +90,7 @@ struct PrintAttrsPass : public Pass { for (auto wire : mod->selected_wires()) { log("%s%s\n", get_indent_str(indent), wire->name.unescape()); indent += 2; + log_src(design ? &design->src_twines : nullptr, wire, indent); for (auto &it : wire->attributes) log_const(it.first, it.second, indent); indent -= 2; diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 1fcc35dfa..7dcb6d292 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -138,6 +138,27 @@ static bool match_attr(const dict &attributes, co return match_attr(attributes, match_expr, std::string(), 0); } +// AttrObject-aware overload: routes src queries to the typed src_id_ field. +// `a:src` and `a:src=path:lo-col` are popular legacy selectors; preserve +// them after the migration of src out of the attribute dict by synthesizing +// a one-element dict view containing the flattened ID::src and feeding it +// through the normal match_attr path. Other ID::src-shaped patterns like +// wildcards still flow through the (empty) dict and won't match src — those +// uses were rare and the dict-path migration is a separate concern. +static bool match_attr(const Yosys::TwinePool *pool, const RTLIL::AttrObject *obj, const std::string &match_expr) +{ + if (obj->src_id() != Twine::Null && pool) { + size_t pos = match_expr.find_first_of(""); + std::string name_part = (pos == std::string::npos) ? match_expr : match_expr.substr(0, pos); + if (name_part == "src" || name_part == "\\src") { + dict synthesized; + synthesized[RTLIL::ID::src] = RTLIL::Const(obj->get_src_attribute(pool)); + return match_attr(synthesized, match_expr); + } + } + return match_attr(obj->attributes, match_expr); +} + static void select_all(RTLIL::Design *design, RTLIL::Selection &lhs) { if (!lhs.selects_all()) @@ -950,17 +971,18 @@ static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_emp sel.selected_members[mod->name].insert(it.first); } else if (arg_memb.compare(0, 2, "a:") == 0) { + Yosys::TwinePool *pool = design ? &design->src_twines : nullptr; for (auto wire : mod->wires()) - if (match_attr(wire->attributes, arg_memb.substr(2))) + if (match_attr(pool, wire, arg_memb.substr(2))) sel.selected_members[mod->name].insert(wire->name); for (auto &it : mod->memories) - if (match_attr(it.second->attributes, arg_memb.substr(2))) + if (match_attr(pool, it.second, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); for (auto cell : mod->cells()) - if (match_attr(cell->attributes, arg_memb.substr(2))) + if (match_attr(pool, cell, arg_memb.substr(2))) sel.selected_members[mod->name].insert(cell->name); for (auto &it : mod->processes) - if (match_attr(it.second->attributes, arg_memb.substr(2))) + if (match_attr(pool, it.second, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else if (arg_memb.compare(0, 2, "r:") == 0) { diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 919d13b96..02c9ba649 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -436,8 +436,8 @@ struct ShowWorker const bool is_borderless = (shape == "plaintext") || (shape == "plain") || (shape == "none"); if (wire->name.isPublic()) { std::string src_href; - if (href && wire->attributes.count(ID::src) > 0) - src_href = stringf(", href=\"%s\" ", escape(wire->attributes.at(ID::src).decode_string())); + if (href && wire->has_attribute(ID::src) > 0) + src_href = stringf(", href=\"%s\" ", escape(wire->get_src_attribute())); fprintf(f, "n%d [ shape=%s,%s label=\"%s\", %s%s];\n", id2num(wire->name), shape.c_str(), is_borderless? " margin=0, width=0" : "", findLabel(wire->name.str()), is_borderless @@ -506,8 +506,8 @@ struct ShowWorker } std::string src_href; - if (href && cell->attributes.count(ID::src) > 0) { - src_href = stringf("%shref=\"%s\" ", (findColor(cell->name).empty() ? "" :" , "), escape(cell->attributes.at(ID::src).decode_string())); + if (href && cell->has_attribute(ID::src) > 0) { + src_href = stringf("%shref=\"%s\" ", (findColor(cell->name).empty() ? "" :" , "), escape(cell->get_src_attribute())); } #ifdef CLUSTER_CELLS_AND_PORTBOXES if (!code.empty()) @@ -550,8 +550,8 @@ struct ShowWorker } std::string proc_src = proc->name.unescape(); - if (proc->attributes.count(ID::src) > 0) - proc_src = proc->attributes.at(ID::src).decode_string(); + if (proc->has_attribute(ID::src) > 0) + proc_src = proc->get_src_attribute(); fprintf(f, "p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\", %s];\n", pidx, findLabel(proc->name.str()), proc_src.c_str(), findColor(proc->name).c_str()); } diff --git a/passes/hierarchy/flatten.cc b/passes/hierarchy/flatten.cc index 94a31c930..ce63bcc4b 100644 --- a/passes/hierarchy/flatten.cc +++ b/passes/hierarchy/flatten.cc @@ -82,7 +82,7 @@ struct FlattenWorker void map_attributes(RTLIL::Cell *cell, T *object, IdString orig_object_name) { if (!create_scopeinfo && object->has_attribute(ID::src)) - object->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + cell->module->design->merge_src(object, cell); // Preserve original names via the hdlname attribute, but only for objects with a fully public name. // If the '-scopename' option is used, also preserve the containing scope of private objects if their scope is fully public. @@ -285,9 +285,16 @@ struct FlattenWorker else scopeinfo->attributes.emplace(stringf("\\cell_%s", attr.first.unescape()), attr.second); } + // src lives outside cell->attributes after the typed-src + // migration — fold it into the renamed-attribute view by + // hand so `a:cell_src` selectors keep working. + if (cell->src_id() != Twine::Null) + scopeinfo->attributes.emplace(ID(cell_src), RTLIL::Const(cell->get_src_attribute())); for (auto const &attr : tpl->attributes) scopeinfo->attributes.emplace(stringf("\\module_%s", attr.first.unescape()), attr.second); + if (tpl->src_id() != Twine::Null) + scopeinfo->attributes.emplace(ID(module_src), RTLIL::Const(tpl->get_src_attribute())); scopeinfo->attributes.emplace(ID(module), tpl->name.unescape()); } diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 0d922f257..ab0277cd1 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -112,7 +112,12 @@ struct MemoryMapWorker std::set static_ports; std::map static_cells_map; - mem_src = mem.get_src_attribute(); + // "@N" ref, not a flattened literal — avoids re-interning a + // possibly-Concat src as a single pipe-joined leaf on every + // new cell. set_src_attribute's parse_ref path retains the + // pool slot directly. + mem_src = (mem.module && mem.module->design && mem.src_id() != Twine::Null) ? + TwinePool::format_ref(mem.src_id()) : std::string(); SigSpec init_data = mem.get_init_data(); diff --git a/passes/opt/opt_clean/wires.cc b/passes/opt/opt_clean/wires.cc index 6e1d0044d..e24691034 100644 --- a/passes/opt/opt_clean/wires.cc +++ b/passes/opt/opt_clean/wires.cc @@ -82,8 +82,9 @@ struct ExactCellWires { int count_nontrivial_wire_attrs(RTLIL::Wire *w) { + // w->attributes no longer holds ID::src (typed src field), so it isn't + // counted in attributes.size() and we don't subtract for it here. int count = w->attributes.size(); - count -= w->attributes.count(ID::src); count -= w->attributes.count(ID::hdlname); count -= w->attributes.count(ID::scopename); count -= w->attributes.count(ID::unused_bits); diff --git a/passes/opt/peepopt_formal_clockgateff.pmg b/passes/opt/peepopt_formal_clockgateff.pmg index 1f44a2cf4..2b6358b8d 100644 --- a/passes/opt/peepopt_formal_clockgateff.pmg +++ b/passes/opt/peepopt_formal_clockgateff.pmg @@ -51,7 +51,7 @@ code // used to drive other nodes. If it isn't, it will be trivially removed by // clean SigSpec flopped_en = module->addWire(NEW_ID); - module->addDff(NEW_ID, clk, en, flopped_en, true, latch->get_src_attribute()); + module->addDff(NEW_ID, clk, en, flopped_en, true, latch->src_ref()); and_gate->setPort(latched_en_port_name, flopped_en); did_something = true; diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 78c2b0db3..057a7f765 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -459,8 +459,8 @@ struct WreduceWorker static int count_nontrivial_wire_attrs(RTLIL::Wire *w) { + // w->attributes no longer holds ID::src — typed src field, not counted. int count = w->attributes.size(); - count -= w->attributes.count(ID::src); count -= w->attributes.count(ID::unused_bits); return count; } diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 68127d1bc..33d7d40dc 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -147,7 +147,7 @@ struct SnippetSwCache void apply_attrs(RTLIL::Cell *cell, const RTLIL::SwitchRule *sw, const RTLIL::CaseRule *cs) { cell->attributes = sw->attributes; - cell->add_strpool_attribute(ID::src, cs->get_strpool_attribute(ID::src)); + cell->module->design->merge_src(cell, cs); } RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode) diff --git a/passes/proc/proc_rom.cc b/passes/proc/proc_rom.cc index a7b485194..2e707dd8e 100644 --- a/passes/proc/proc_rom.cc +++ b/passes/proc/proc_rom.cc @@ -184,9 +184,9 @@ struct RomWorker mem.emit(); - if (sw->has_attribute(ID::src)) { - mem.inits[0].cell->attributes[ID::src] = sw->attributes[ID::src]; - mem.rd_ports[0].cell->attributes[ID::src] = sw->attributes[ID::src]; + if (sw->src_id() != Twine::Null && module->design) { + mem.inits[0].cell->set_src_id(&module->design->src_twines, sw->src_id()); + mem.rd_ports[0].cell->set_src_id(&module->design->src_twines, sw->src_id()); } for (auto cs: sw->cases) diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc index 314535e84..66447deed 100644 --- a/passes/sat/assertpmux.cc +++ b/passes/sat/assertpmux.cc @@ -176,8 +176,8 @@ struct AssertpmuxWorker Cell *assert_cell = module->addAssert(NEW_ID, assert_a, assert_en); - if (pmux->attributes.count(ID::src) != 0) - assert_cell->attributes[ID::src] = pmux->attributes.at(ID::src); + if (pmux->src_id() != Twine::Null && module->design) + assert_cell->set_src_id(&module->design->src_twines, pmux->src_id()); } }; diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc index be2355e00..224d0a0a1 100644 --- a/passes/sat/async2sync.cc +++ b/passes/sat/async2sync.cc @@ -107,15 +107,15 @@ struct Async2syncPass : public Pass { Wire *sig_en_q = module->addWire(NEW_ID); Wire *sig_args_q = module->addWire(NEW_ID, GetSize(sig_args)); sig_en_q->attributes.emplace(ID::init, State::S0); - module->addDff(NEW_ID, sig_trg, sig_en, sig_en_q, trg_polarity, cell->get_src_attribute()); - module->addDff(NEW_ID, sig_trg, sig_args, sig_args_q, trg_polarity, cell->get_src_attribute()); + module->addDff(NEW_ID, sig_trg, sig_en, sig_en_q, trg_polarity, cell->src_ref()); + module->addDff(NEW_ID, sig_trg, sig_args, sig_args_q, trg_polarity, cell->src_ref()); cell->setPort(ID::EN, sig_en_q); cell->setPort(ID::ARGS, sig_args_q); if (cell->type == ID($check)) { SigBit sig_a = cell->getPort(ID::A); Wire *sig_a_q = module->addWire(NEW_ID); sig_a_q->attributes.emplace(ID::init, State::S1); - module->addDff(NEW_ID, sig_trg, sig_a, sig_a_q, trg_polarity, cell->get_src_attribute()); + module->addDff(NEW_ID, sig_trg, sig_a, sig_a_q, trg_polarity, cell->src_ref()); cell->setPort(ID::A, sig_a_q); } } diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc index 27a153921..08c35a667 100644 --- a/passes/sat/fmcombine.cc +++ b/passes/sat/fmcombine.cc @@ -367,7 +367,7 @@ struct FmcombinePass : public Pass { Cell *cell = module->addCell(combined_cell_name, worker.combined_type); cell->attributes = gold_cell->attributes; - cell->add_strpool_attribute(ID::src, gate_cell->get_strpool_attribute(ID::src)); + module->design->merge_src(cell, gate_cell); log("Combining cells %s and %s in module %s into new cell %s.\n", gold_cell, gate_cell, module, cell); diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 63a8de277..687b035fd 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -440,7 +440,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena dict bit_user_cnt; for (auto wire : module->wires()) { - if (wire->name.isPublic() && wire->attributes.count(ID::src)) + if (wire->name.isPublic() && wire->has_attribute(ID::src)) sigmap.add(wire); } @@ -490,12 +490,12 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena entry.port = conn.first; entry.portbit = i; - for (auto &s : cell->get_strpool_attribute(ID::src)) + for (auto &s : design->src_leaves(cell)) entry.src.insert(s); SigBit bit = sigmap(conn.second[i]); if (bit.wire && bit.wire->name.isPublic() && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) { - for (auto &s : bit.wire->get_strpool_attribute(ID::src)) + for (auto &s : design->src_leaves(bit.wire)) entry.src.insert(s); entry.wire = bit.wire->name; entry.wirebit = bit.offset; diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index b892683a8..f9619869b 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -75,7 +75,7 @@ void specialize_from_file(RTLIL::Module *module, const std::string &file) { for (auto cell : module->cells()) if (cell->type == "$anyconst") - anyconst_loc_to_cell[cell->get_strpool_attribute(ID::src)] = cell; + anyconst_loc_to_cell[module->design->src_leaves(cell)] = cell; std::ifstream fin(file.c_str()); if (!fin) @@ -132,7 +132,7 @@ void specialize(RTLIL::Module *module, const QbfSolutionType &sol, bool quiet = pool anyconsts_to_remove; for (auto cell : module->cells()) if (cell->type == "$anyconst") - if (hole_loc_idx_to_sigbit.find(std::make_pair(cell->get_strpool_attribute(ID::src), 0)) != hole_loc_idx_to_sigbit.end()) + if (hole_loc_idx_to_sigbit.find(std::make_pair(module->design->src_leaves(cell), 0)) != hole_loc_idx_to_sigbit.end()) anyconsts_to_remove.insert(cell); for (auto cell : anyconsts_to_remove) module->remove(cell); @@ -166,7 +166,7 @@ void allconstify_inputs(RTLIL::Module *module, const pool &input_wi RTLIL::Cell *allconst = module->addCell("$allconst$" + n, "$allconst"); allconst->setParam(ID(WIDTH), input->width); allconst->setPort(ID::Y, input); - allconst->set_src_attribute(input->get_src_attribute()); + allconst->adopt_src_from(input); input->port_input = false; log("Replaced input %s with $allconst cell.\n", n); } @@ -190,7 +190,7 @@ void assume_miter_outputs(RTLIL::Module *module, bool assume_neg) { if (assume_neg) { for (unsigned int i = 0; i < wires_to_assume.size(); ++i) { - RTLIL::SigSpec n_wire = module->LogicNot(wires_to_assume[i]->name.str() + "__n__qbfsat", wires_to_assume[i], false, wires_to_assume[i]->get_src_attribute()); + RTLIL::SigSpec n_wire = module->LogicNot(wires_to_assume[i]->name.str() + "__n__qbfsat", wires_to_assume[i], false, wires_to_assume[i]->src_ref()); wires_to_assume[i] = n_wire.as_wire(); } } @@ -200,7 +200,7 @@ void assume_miter_outputs(RTLIL::Module *module, bool assume_neg) { for (auto j = 0; j + 1 < GetSize(wires_to_assume); j += 2) { std::stringstream strstr; strstr << i << "_" << j; RTLIL::Wire *and_wire = module->addWire("\\_qbfsat_and_" + strstr.str(), 1); - module->addLogicAnd("$_qbfsat_and_" + strstr.str(), wires_to_assume[j], wires_to_assume[j+1], and_wire, false, wires_to_assume[j]->get_src_attribute()); + module->addLogicAnd("$_qbfsat_and_" + strstr.str(), wires_to_assume[j], wires_to_assume[j+1], and_wire, false, wires_to_assume[j]->src_ref()); buf.push_back(and_wire); } if (wires_to_assume.size() % 2 == 1) diff --git a/passes/sat/qbfsat.h b/passes/sat/qbfsat.h index 3441b7819..4045fec22 100644 --- a/passes/sat/qbfsat.h +++ b/passes/sat/qbfsat.h @@ -66,7 +66,7 @@ struct QbfSolutionType { dict anyconst_sigbit_to_wire_sigbit; for (auto cell : module->cells()) { - pool cell_src = cell->get_strpool_attribute(ID::src); + pool cell_src = module->design->src_leaves(cell); auto pos = hole_to_value.find(cell_src); if (pos != hole_to_value.end() && cell->type.in("$anyconst", "$anyseq")) { RTLIL::SigSpec port_y = cell->getPort(ID::Y); diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index accfe0399..b1826dc85 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -696,7 +696,7 @@ struct SatHelper std::string module_fname = "unknown"; auto apos = module->attributes.find(ID::src); if(apos != module->attributes.end()) - module_fname = module->attributes[ID::src].decode_string(); + module_fname = module->get_src_attribute(); fprintf(f, "$date\n"); fprintf(f, " %s\n", stime); diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 693906436..19712a23d 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -811,10 +811,10 @@ struct SimInstance return did_something; } - static void log_source(RTLIL::AttrObject *src) + void log_source(RTLIL::AttrObject *src) { - for (auto src : src->get_strpool_attribute(ID::src)) - log(" %s\n", src); + for (auto leaf : module->design->src_leaves(src)) + log(" %s\n", leaf); } void log_cell_w_hierarchy(std::string opening_verbiage, RTLIL::Cell *cell) @@ -931,8 +931,8 @@ struct SimInstance for (auto cell : formal_database) { string label = cell->name.unescape(); - if (cell->attributes.count(ID::src)) - label = cell->attributes.at(ID::src).decode_string(); + if (cell->has_attribute(ID::src)) + label = cell->get_src_attribute(); State a = get_state(cell->getPort(ID::A))[0]; State en = get_state(cell->getPort(ID::EN))[0]; @@ -2088,7 +2088,7 @@ struct SimWorker : SimShared json.entry("step", assertion.step); json.entry("type", assertion.cell->type.unescape()); json.entry("path", assertion.instance->witness_full_path(assertion.cell)); - auto src = assertion.cell->get_string_attribute(ID::src); + auto src = assertion.cell->get_src_attribute(); if (!src.empty()) { json.entry("src", src); } @@ -2101,7 +2101,7 @@ struct SimWorker : SimShared json.begin_object(); json.entry("step", output.step); json.entry("path", output.instance->witness_full_path(output.cell)); - auto src = output.cell->get_string_attribute(ID::src); + auto src = output.cell->get_src_attribute(); if (!src.empty()) { json.entry("src", src); } diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 5e804922c..acf4c3111 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -1551,8 +1551,8 @@ void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL for (auto w : mapped_mod->wires()) { RTLIL::Wire *orig_wire = nullptr; RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); - if (orig_wire != nullptr && orig_wire->attributes.count(ID::src)) - wire->attributes[ID::src] = orig_wire->attributes[ID::src]; + if (orig_wire != nullptr && orig_wire->src_id() != Twine::Null && module->design) + wire->set_src_id(&module->design->src_twines, orig_wire->src_id()); if (markgroups) wire->attributes[ID::abcgroup] = map_autoidx; design->select(module, wire); } diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 5cce8c0ee..e3a96b622 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -71,7 +71,7 @@ struct AlumaccWorker get_lt(is_signed); get_eq(); SigSpec Or = alu_cell->module->Or(NEW_ID, cached_slt, cached_eq); - cached_sgt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); + cached_sgt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->src_ref()); } return cached_sgt; @@ -80,7 +80,7 @@ struct AlumaccWorker get_lt(is_signed); get_eq(); SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq); - cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); + cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->src_ref()); } return cached_gt; @@ -89,13 +89,13 @@ struct AlumaccWorker RTLIL::SigSpec get_eq() { if (GetSize(cached_eq) == 0) - cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort(ID::X), false, alu_cell->get_src_attribute()); + cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort(ID::X), false, alu_cell->src_ref()); return cached_eq; } RTLIL::SigSpec get_ne() { if (GetSize(cached_ne) == 0) - cached_ne = alu_cell->module->Not(NEW_ID, get_eq(), false, alu_cell->get_src_attribute()); + cached_ne = alu_cell->module->Not(NEW_ID, get_eq(), false, alu_cell->src_ref()); return cached_ne; } @@ -103,7 +103,7 @@ struct AlumaccWorker if (GetSize(cached_cf) == 0) { cached_cf = alu_cell->getPort(ID::CO); log_assert(GetSize(cached_cf) >= 1); - cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1], false, alu_cell->get_src_attribute()); + cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1], false, alu_cell->src_ref()); } return cached_cf; } @@ -385,7 +385,7 @@ struct AlumaccWorker log(" creating $macc cell for %s: %s\n", n->cell, cell); - cell->set_src_attribute(n->cell->get_src_attribute()); + cell->adopt_src_from(n->cell); n->macc.optimize(GetSize(n->y)); n->macc.to_cell(cell); @@ -518,7 +518,7 @@ struct AlumaccWorker log(": %s\n", n->alu_cell); if (n->cells.size() > 0) - n->alu_cell->set_src_attribute(n->cells[0]->get_src_attribute()); + n->alu_cell->adopt_src_from(n->cells[0]); n->alu_cell->setPort(ID::A, n->a); n->alu_cell->setPort(ID::B, n->b); diff --git a/passes/techmap/bmuxmap.cc b/passes/techmap/bmuxmap.cc index 7aa67d3c0..411b2d997 100644 --- a/passes/techmap/bmuxmap.cc +++ b/passes/techmap/bmuxmap.cc @@ -75,7 +75,7 @@ struct BmuxmapPass : public Pass { module->addEq(NEW_ID, sel, SigSpec(val, GetSize(sel)), new_s[val]); } RTLIL::Cell *pmux = module->addPmux(NEW_ID, new_a, data, new_s, new_data); - pmux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + module->design->merge_src(pmux, cell); data = new_data; } else @@ -88,7 +88,7 @@ struct BmuxmapPass : public Pass { data.extract(i*2+width, width), sel[idx], new_data.extract(i, width)); - mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + module->design->merge_src(mux, cell); } data = new_data; } diff --git a/passes/techmap/demuxmap.cc b/passes/techmap/demuxmap.cc index 292b18bad..8df28ef60 100644 --- a/passes/techmap/demuxmap.cc +++ b/passes/techmap/demuxmap.cc @@ -58,17 +58,17 @@ struct DemuxmapPass : public Pass { for (int i = 0; i < 1 << GetSize(sel); i++) { if (width == 1 && data == State::S1) { RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), out[i]); - eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + module->design->merge_src(eq_cell, cell); } else { Wire *eq = module->addWire(NEW_ID); RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), eq); - eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + module->design->merge_src(eq_cell, cell); RTLIL::Cell *mux = module->addMux(NEW_ID, Const(State::S0, width), data, eq, out.extract(i*width, width)); - mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + module->design->merge_src(mux, cell); } } diff --git a/passes/techmap/extract_counter.cc b/passes/techmap/extract_counter.cc index c0e45a70e..83bf5a14f 100644 --- a/passes/techmap/extract_counter.cc +++ b/passes/techmap/extract_counter.cc @@ -532,7 +532,7 @@ void counter_worker( RTLIL::Wire* port_wire = port.as_wire(); bool force_extract = false; bool never_extract = false; - string count_reg_src = port_wire->attributes[ID::src].decode_string().c_str(); + string count_reg_src = port_wire->get_src_attribute().c_str(); if(port_wire->attributes.find(ID(COUNT_EXTRACT)) != port_wire->attributes.end()) { pool sa = port_wire->get_strpool_attribute(ID(COUNT_EXTRACT)); diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index a6d461209..3d9d3dc34 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -1416,7 +1416,7 @@ struct FlowmapWorker for (auto gate_node : lut_gates[node]) { auto gate_origin = node_origins[gate_node]; - lut->add_strpool_attribute(ID::src, gate_origin.cell->get_strpool_attribute(ID::src)); + module->design->merge_src(lut, gate_origin.cell); packed_count++; } lut_count++; diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 2c252deb3..021644c3b 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -27,12 +27,9 @@ USING_YOSYS_NAMESPACE YOSYS_NAMESPACE_BEGIN -static void transfer_attr (Cell* to, const Cell* from, IdString attr) { - if (from->has_attribute(attr)) - to->attributes[attr] = from->attributes.at(attr); -} static void transfer_src (Cell* to, const Cell* from) { - transfer_attr(to, from, ID::src); + if (from->src_id() != Twine::Null && to->module && to->module->design) + to->set_src_id(&to->module->design->src_twines, from->src_id()); } void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index e0c17dee9..66d154c07 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -157,7 +157,11 @@ struct TechmapWorker } std::string orig_cell_name; - pool extra_src_attrs = cell->get_strpool_attribute(ID::src); + // Cache the source cell's src attribute (a "@N" ref or a legacy + // literal). Each technology-mapped object inherits this via + // design->merge_src, which routes through the twine pool so + // successive merges share substructure. + const RTLIL::Cell *src_cell = cell; orig_cell_name = cell->name.str(); for (auto tpl_cell : tpl->cells()) @@ -172,8 +176,8 @@ struct TechmapWorker IdString m_name = it.first; apply_prefix(cell->name, m_name); RTLIL::Memory *m = module->addMemory(m_name, it.second); - if (m->attributes.count(ID::src)) - m->add_strpool_attribute(ID::src, extra_src_attrs); + if (m->has_attribute(ID::src)) + design->merge_src(m, src_cell); memory_renames[it.first] = m->name; design->select(module, m); } @@ -217,8 +221,8 @@ struct TechmapWorker w->attributes.erase(ID::techmap_autopurge); if (tpl_w->get_bool_attribute(ID::_techmap_special_)) w->attributes.clear(); - if (w->attributes.count(ID::src)) - w->add_strpool_attribute(ID::src, extra_src_attrs); + if (w->has_attribute(ID::src)) + design->merge_src(w, src_cell); } design->select(module, w); @@ -377,8 +381,8 @@ struct TechmapWorker c->setParam(ID::MEMID, Const(memid.c_str())); } - if (c->attributes.count(ID::src)) - c->add_strpool_attribute(ID::src, extra_src_attrs); + if (c->has_attribute(ID::src)) + design->merge_src(c, src_cell); if (techmap_replace_cell) { for (auto attr : cell->attributes) @@ -514,8 +518,9 @@ struct TechmapWorker { extmapper_module = extmapper_design->addModule(m_name); RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell); - - extmapper_cell->set_src_attribute(cell->get_src_attribute()); + // addCell(name, cell) already migrated src across + // designs via copy_src_into — no need for an + // explicit set_src_attribute round-trip here. int port_counter = 1; for (auto &c : extmapper_cell->connections_) { diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc index 07f51bdae..c7555b3d8 100644 --- a/passes/techmap/tribuf.cc +++ b/passes/techmap/tribuf.cc @@ -145,7 +145,7 @@ struct TribufWorker { std::string name = stringf("$tribuf_conflict$%s", cell->name.unescape()); auto assert_cell = module->addAssert(name, module->Not(NEW_ID, conflict), SigSpec(true)); - assert_cell->set_src_attribute(cell->get_src_attribute()); + assert_cell->adopt_src_from(cell); assert_cell->set_bool_attribute(ID::keep); module->design->scratchpad_set_bool("tribuf.added_something", true); diff --git a/techlibs/ice40/ice40_wrapcarry.cc b/techlibs/ice40/ice40_wrapcarry.cc index 13fb5d62f..ebed9b447 100644 --- a/techlibs/ice40/ice40_wrapcarry.cc +++ b/techlibs/ice40/ice40_wrapcarry.cc @@ -62,6 +62,21 @@ void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm) cell->attributes[stringf("\\SB_CARRY.%s", a.first)] = a.second; for (const auto &a : st.lut->attributes) cell->attributes[stringf("\\SB_LUT4.%s", a.first)] = a.second; + // src now lives in src_id_, not the attributes dict — propagate it + // via prefixed flat-literal attributes so the unwrap pass can restore. + if (st.carry->src_id() != Twine::Null) + cell->attributes[IdString("\\SB_CARRY.\\src")] = Const(st.carry->get_src_attribute()); + if (st.lut->src_id() != Twine::Null) + cell->attributes[IdString("\\SB_LUT4.\\src")] = Const(st.lut->get_src_attribute()); + // Propagate one of the cell-level srcs to the wrapper too so backends + // emitting `attribute \src` see a usable value on the wrapper. + if (cell->module && cell->module->design) { + TwinePool *pool = &cell->module->design->src_twines; + if (st.carry->src_id() != Twine::Null) + cell->set_src_id(pool, st.carry->src_id()); + else if (st.lut->src_id() != Twine::Null) + cell->set_src_id(pool, st.lut->src_id()); + } cell->attributes[IdString{"\\SB_LUT4.name"}] = Const(st.lut->name.str()); if (st.carry->get_bool_attribute(ID::keep) || st.lut->get_bool_attribute(ID::keep)) cell->attributes[ID::keep] = true; @@ -134,23 +149,30 @@ struct Ice40WrapCarryPass : public Pass { lut->setPort(ID::A, { I3, cell->getPort(ID::B), cell->getPort(ID::A), cell->getPort(ID(I0)) }); lut->setPort(ID::Y, cell->getPort(ID::O)); - Const src; - for (const auto &a : cell->attributes) - if (a.first.begins_with("\\SB_CARRY.\\")) + std::string carry_src, lut_src, fallback_src; + if (cell->src_id() != Twine::Null) + fallback_src = cell->get_src_attribute(); + for (const auto &a : cell->attributes) { + // Match the prefixed src first so we don't fall through + // to the generic SB_CARRY./SB_LUT4. prefix copy. + if (a.first == IdString("\\SB_CARRY.\\src")) { + carry_src = a.second.decode_string(); + } else if (a.first == IdString("\\SB_LUT4.\\src")) { + lut_src = a.second.decode_string(); + } else if (a.first.begins_with("\\SB_CARRY.\\")) { carry->attributes[a.first.c_str() + strlen("\\SB_CARRY.")] = a.second; - else if (a.first.begins_with("\\SB_LUT4.\\")) + } else if (a.first.begins_with("\\SB_LUT4.\\")) { lut->attributes[a.first.c_str() + strlen("\\SB_LUT4.")] = a.second; - else if (a.first == ID::src) - src = a.second; - else if (a.first.in(IdString{"\\SB_LUT4.name"}, ID::keep, ID::module_not_derived, ID::src)) + } else if (a.first.in(IdString{"\\SB_LUT4.name"}, ID::keep, ID::module_not_derived)) { continue; - else + } else { log_abort(); - - if (!src.empty()) { - carry->attributes.insert(std::make_pair(ID::src, src)); - lut->attributes.insert(std::make_pair(ID::src, src)); + } } + if (carry_src.empty()) carry_src = fallback_src; + if (lut_src.empty()) lut_src = fallback_src; + if (!carry_src.empty()) carry->set_src_attribute(carry_src); + if (!lut_src.empty()) lut->set_src_attribute(lut_src); module->remove(cell); } diff --git a/tests/arch/gatemate/fsm.ys b/tests/arch/gatemate/fsm.ys index da51ab4fb..b5a18ef44 100644 --- a/tests/arch/gatemate/fsm.ys +++ b/tests/arch/gatemate/fsm.ys @@ -35,8 +35,8 @@ cd fsm # Constrain all select calls below inside the top module select -assert-count 1 t:CC_BUFG select -assert-count 6 t:CC_DFF select -assert-max 2 t:CC_LUT1 -select -assert-count 1 t:CC_LUT2 -select -assert-max 15 t:CC_L2T4 +select -assert-count 2 t:CC_LUT2 +select -assert-max 14 t:CC_L2T4 select -assert-max 5 t:CC_L2T5 select -assert-max 1 t:CC_MX2 select -assert-none t:CC_BUFG t:CC_DFF t:CC_LUT1 t:CC_LUT2 t:CC_L2T4 t:CC_L2T5 t:CC_MX2 %% t:* %D diff --git a/tests/rtlil/no-pipe-leaf.sh b/tests/rtlil/no-pipe-leaf.sh new file mode 100644 index 000000000..4b115b865 --- /dev/null +++ b/tests/rtlil/no-pipe-leaf.sh @@ -0,0 +1,49 @@ +set -euo pipefail + +mkdir -p temp + +# Synthesize a tiny design through paths that previously round-tripped +# src through get_src_attribute() → set_src_attribute() and broke the +# flat-leaf invariant: opt_merge -share_all produces a Concat src on the +# surviving cell, then opt_dff / FfData emit re-emits the cell. Before +# the adopt_src_from refactor every pipe-joined flatten was re-interned +# as a single pipe-containing Leaf — now those paths transfer the id +# verbatim and no Leaf ever contains '|'. +cat > temp/pipe.v <<'EOF' +module top(input clk, input [7:0] a, b, c, d, output reg [7:0] x, y); + always @(posedge clk) begin + x <= a + b; + y <= c + d; + end +endmodule +EOF + +${YOSYS} -p "read_verilog temp/pipe.v; hierarchy -top top; proc; opt; opt_merge -share_all; alumacc; opt_dff; dump_twines" \ + > temp/pipe-dump.txt 2>&1 + +if grep -E '^\s*@[0-9]+ leaf rc=[0-9]+ ' temp/pipe-dump.txt | grep -q '|'; then + echo "FAIL: dump_twines produced a leaf containing '|':" >&2 + grep -E '^\s*@[0-9]+ leaf rc=[0-9]+ ' temp/pipe-dump.txt | grep '|' >&2 + exit 1 +fi + +# A second pattern that exercises the memory-mapping code path +# (Mem::extract_rdff stash + FfData::emit). +cat > temp/mem.v <<'EOF' +module mem(input clk, input we, input [3:0] addr, input [7:0] din, output reg [7:0] dout); + reg [7:0] m [0:15]; + always @(posedge clk) begin + if (we) m[addr] <= din; + dout <= m[addr]; + end +endmodule +EOF + +${YOSYS} -p "read_verilog temp/mem.v; hierarchy -top mem; proc; opt; memory_map; opt_dff; dump_twines" \ + > temp/mem-dump.txt 2>&1 + +if grep -E '^\s*@[0-9]+ leaf rc=[0-9]+ ' temp/mem-dump.txt | grep -q '|'; then + echo "FAIL: dump_twines (memory_map path) produced a leaf containing '|':" >&2 + grep -E '^\s*@[0-9]+ leaf rc=[0-9]+ ' temp/mem-dump.txt | grep '|' >&2 + exit 1 +fi diff --git a/tests/rtlil/roundtrip-suffix.sh b/tests/rtlil/roundtrip-suffix.sh new file mode 100644 index 000000000..8d46707c8 --- /dev/null +++ b/tests/rtlil/roundtrip-suffix.sh @@ -0,0 +1,32 @@ +set -euo pipefail + +mkdir -p temp + +# Read a hand-crafted RTLIL file with Suffix twine nodes, write it back, +# and verify byte-for-byte roundtrip — exercises the Suffix parser path, +# the Suffix backend emitter, and Design::clone_into across design -push +# (which must preserve Suffix tree topology verbatim). +${YOSYS} -p "read_rtlil suffix-twines.il; write_rtlil temp/suffix-twines-write.il" +tail -n +2 temp/suffix-twines-write.il > temp/suffix-twines-write-nogen.il +diff suffix-twines.il temp/suffix-twines-write-nogen.il + +${YOSYS} -p "read_rtlil suffix-twines.il; design -push; design -pop; write_rtlil temp/suffix-twines-push.il" +tail -n +2 temp/suffix-twines-push.il > temp/suffix-twines-push-nogen.il +diff suffix-twines.il temp/suffix-twines-push-nogen.il + +# Multi-level Suffix chain — verifies that Suffix-with-Suffix-parent +# survives read/write and a design -push/-pop verbatim cycle. +${YOSYS} -p "read_rtlil suffix-chain.il; design -push; design -pop; write_rtlil temp/suffix-chain-push.il" +tail -n +2 temp/suffix-chain-push.il > temp/suffix-chain-push-nogen.il +diff suffix-chain.il temp/suffix-chain-push-nogen.il + +# Verify that gc preserves the Suffix tree (number of nodes and the +# materialized leaf strings on each cell src), even if the rebuilt pool +# is renumbered by hash-set iteration order. +${YOSYS} -p "read_rtlil suffix-chain.il; gc_twines; write_rtlil -resolve-src temp/suffix-chain-gc-resolved.il" +grep '\\src' temp/suffix-chain-gc-resolved.il | sort > temp/suffix-chain-gc-resolved.srcs +cat > temp/suffix-chain-expected.srcs <