mirror of https://github.com/YosysHQ/yosys.git
twine: fix replayability, reduce TwineSearch usage
This commit is contained in:
parent
e9eb3889b7
commit
7c73fd62e4
|
|
@ -79,6 +79,7 @@ struct BtorWorker
|
|||
dict<SigBit, bool> initbits;
|
||||
pool<Wire*> statewires;
|
||||
pool<string> srcsymbols;
|
||||
TwineSearch src_search;
|
||||
vector<Mem> memories;
|
||||
dict<Cell*, Mem*> mem_cells;
|
||||
|
||||
|
|
@ -125,11 +126,11 @@ struct BtorWorker
|
|||
string src = module && module->design ? module->design->get_src_attribute(obj) : std::string();
|
||||
if (srcsym && infostr[0] == '$') {
|
||||
std::replace(src.begin(), src.end(), ' ', '_');
|
||||
TwineRef src_ref = TwineSearch(&module->design->twines).find(src);
|
||||
TwineRef src_ref = src_search.find(src);
|
||||
if (srcsymbols.count(src) || src_ref != Twine::Null) {
|
||||
for (int i = 1;; i++) {
|
||||
string s = stringf("%s-%d", src, i);
|
||||
TwineRef s_ref = TwineSearch(&module->design->twines).find(s);
|
||||
TwineRef s_ref = src_search.find(s);
|
||||
if (!srcsymbols.count(s) && s_ref == Twine::Null) {
|
||||
src = s;
|
||||
break;
|
||||
|
|
@ -153,11 +154,11 @@ struct BtorWorker
|
|||
string src = module && module->design ? module->design->get_src_attribute(mem) : std::string();
|
||||
if (srcsym && infostr[0] == '$') {
|
||||
std::replace(src.begin(), src.end(), ' ', '_');
|
||||
TwineRef src_ref = TwineSearch(&module->design->twines).find(src);
|
||||
TwineRef src_ref = src_search.find(src);
|
||||
if (srcsymbols.count(src) || src_ref != Twine::Null) {
|
||||
for (int i = 1;; i++) {
|
||||
string s = stringf("%s-%d", src, i);
|
||||
TwineRef s_ref = TwineSearch(&module->design->twines).find(s);
|
||||
TwineRef s_ref = src_search.find(s);
|
||||
if (!srcsymbols.count(s) && s_ref == Twine::Null) {
|
||||
src = s;
|
||||
break;
|
||||
|
|
@ -1193,7 +1194,7 @@ struct BtorWorker
|
|||
}
|
||||
|
||||
BtorWorker(std::ostream &f, RTLIL::Module *module, bool verbose, bool single_bad, bool cover_mode, bool print_internal_names, string info_filename, string ywmap_filename) :
|
||||
f(f), sigmap(module), module(module), verbose(verbose), single_bad(single_bad), cover_mode(cover_mode), print_internal_names(print_internal_names), info_filename(info_filename)
|
||||
f(f), sigmap(module), module(module), verbose(verbose), single_bad(single_bad), cover_mode(cover_mode), print_internal_names(print_internal_names), src_search(&module->design->twines), info_filename(info_filename)
|
||||
{
|
||||
if (!info_filename.empty())
|
||||
infof("name %s\n", module);
|
||||
|
|
|
|||
|
|
@ -138,8 +138,6 @@ struct JsonWriter
|
|||
void write_parameters(const dict<IdString, Const> ¶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 && design && design->obj_src_id(src_obj) != Twine::Null) {
|
||||
f << stringf("\n %s%s: ", for_module ? "" : " ", get_name(RTLIL::ID::src));
|
||||
write_parameter_value(RTLIL::Const(design->get_src_attribute(src_obj)));
|
||||
|
|
|
|||
|
|
@ -34,9 +34,6 @@ YOSYS_NAMESPACE_BEGIN
|
|||
|
||||
void RTLIL_BACKEND::dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj, const RTLIL::Design *design, bool stringify)
|
||||
{
|
||||
// Emit the typed src field first. It is not stored in obj->attributes
|
||||
// — the dict no longer holds ID::src under any circumstance. Backends
|
||||
// that want to materialize the pipe-joined literal pass stringify.
|
||||
if (design && design->obj_src_id(obj) != Twine::Null) {
|
||||
TwineRef id = design->obj_src_id(obj);
|
||||
f << stringf("%s" "attribute \\src ", indent);
|
||||
|
|
|
|||
|
|
@ -269,13 +269,14 @@ end_of_header:
|
|||
else
|
||||
log_abort();
|
||||
|
||||
RTLIL::Wire* n0 = module->wire(TwineSearch(&design->twines).find(stringf("$aiger%d$0", aiger_autoidx)));
|
||||
RTLIL::Wire* n0 = aiger_wires.count(0) ? aiger_wires.at(0) : nullptr;
|
||||
if (n0)
|
||||
module->connect(n0, State::S0);
|
||||
|
||||
// Parse footer (symbol table, comments, etc.)
|
||||
unsigned l1;
|
||||
std::string s;
|
||||
TwineSearch search(&design->twines);
|
||||
for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
|
||||
if (c == 'i' || c == 'l' || c == 'o' || c == 'b') {
|
||||
f.ignore(1);
|
||||
|
|
@ -294,7 +295,7 @@ end_of_header:
|
|||
log_assert(l1 < latches.size());
|
||||
wire = latches[l1];
|
||||
} else if (c == 'o') {
|
||||
wire = module->wire(TwineSearch(&design->twines).find(escaped_s.str()));
|
||||
wire = module->wire(search.find(escaped_s.str()));
|
||||
log_assert(l1 < outputs.size());
|
||||
if (wire) {
|
||||
// Could have been renamed by a latch
|
||||
|
|
@ -307,7 +308,7 @@ end_of_header:
|
|||
wire = bad_properties[l1];
|
||||
} else log_abort();
|
||||
|
||||
module->rename(wire, design->twines.add(std::string{escaped_s.str()}));
|
||||
module->rename(wire, intern_name(escaped_s.str(), search));
|
||||
}
|
||||
else if (c == 'j' || c == 'f') {
|
||||
// TODO
|
||||
|
|
@ -346,25 +347,28 @@ RTLIL::Wire* AigerReader::createWireIfNotExists(RTLIL::Module *module, unsigned
|
|||
{
|
||||
const unsigned variable = literal >> 1;
|
||||
const bool invert = literal & 1;
|
||||
if (auto it = aiger_wires.find(literal); it != aiger_wires.end())
|
||||
return it->second;
|
||||
RTLIL::IdString wire_name(stringf("$aiger%d$%d%s", aiger_autoidx, variable, invert ? "b" : ""));
|
||||
RTLIL::Wire *wire = module->wire(TwineSearch(&design->twines).find(wire_name.str()));
|
||||
if (wire) return wire;
|
||||
log_debug2("Creating %s\n", wire_name.c_str());
|
||||
wire = module->addWire(design->twines.add(std::string{wire_name.str()}));
|
||||
RTLIL::Wire *wire = module->addWire(design->twines.add(std::string{wire_name.str()}));
|
||||
wire->port_input = wire->port_output = false;
|
||||
aiger_wires[literal] = wire;
|
||||
if (!invert) return wire;
|
||||
RTLIL::IdString wire_inv_name(stringf("$aiger%d$%d", aiger_autoidx, variable));
|
||||
RTLIL::Wire *wire_inv = module->wire(TwineSearch(&design->twines).find(wire_inv_name.str()));
|
||||
if (wire_inv) {
|
||||
if (module->cell(TwineSearch(&design->twines).find(wire_inv_name.str()))) return wire;
|
||||
const unsigned base_literal = variable << 1;
|
||||
RTLIL::Wire *wire_inv;
|
||||
if (auto it = aiger_wires.find(base_literal); it != aiger_wires.end()) {
|
||||
wire_inv = it->second;
|
||||
}
|
||||
else {
|
||||
RTLIL::IdString wire_inv_name(stringf("$aiger%d$%d", aiger_autoidx, variable));
|
||||
log_debug2("Creating %s\n", wire_inv_name.c_str());
|
||||
wire_inv = module->addWire(design->twines.add(std::string{wire_inv_name.str()}));
|
||||
wire_inv->port_input = wire_inv->port_output = false;
|
||||
aiger_wires[base_literal] = wire_inv;
|
||||
}
|
||||
|
||||
log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
|
||||
log_debug2("Creating %s = ~$aiger%d$%d\n", wire_name.c_str(), aiger_autoidx, variable);
|
||||
module->addNotGate(Twine{stringf("$not$aiger%d$%d", aiger_autoidx, variable)}, wire_inv, wire);
|
||||
|
||||
return wire;
|
||||
|
|
@ -402,7 +406,7 @@ void AigerReader::parse_xaiger()
|
|||
else
|
||||
log_abort();
|
||||
|
||||
RTLIL::Wire* n0 = module->wire(TwineSearch(&design->twines).find(stringf("$aiger%d$0", aiger_autoidx)));
|
||||
RTLIL::Wire* n0 = aiger_wires.count(0) ? aiger_wires.at(0) : nullptr;
|
||||
if (n0)
|
||||
module->connect(n0, State::S0);
|
||||
|
||||
|
|
@ -422,11 +426,12 @@ void AigerReader::parse_xaiger()
|
|||
uint32_t lutSize = parse_xaiger_literal(f);
|
||||
log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize);
|
||||
ConstEvalAig ce(module);
|
||||
TwineSearch search(&design->twines);
|
||||
for (unsigned i = 0; i < lutNum; ++i) {
|
||||
uint32_t rootNodeID = parse_xaiger_literal(f);
|
||||
uint32_t cutLeavesM = parse_xaiger_literal(f);
|
||||
log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM);
|
||||
RTLIL::Wire *output_sig = module->wire(TwineSearch(&design->twines).find(stringf("$aiger%d$%d", aiger_autoidx, rootNodeID)));
|
||||
RTLIL::Wire *output_sig = module->wire(search.find(stringf("$aiger%d$%d", aiger_autoidx, rootNodeID)));
|
||||
log_assert(output_sig);
|
||||
uint32_t nodeID;
|
||||
RTLIL::SigSpec input_sig;
|
||||
|
|
@ -437,7 +442,7 @@ void AigerReader::parse_xaiger()
|
|||
log_debug("\tLUT '$lut$aiger%d$%d' input %d is constant!\n", aiger_autoidx, rootNodeID, cutLeavesM);
|
||||
continue;
|
||||
}
|
||||
RTLIL::Wire *wire = module->wire(TwineSearch(&design->twines).find(stringf("$aiger%d$%d", aiger_autoidx, nodeID)));
|
||||
RTLIL::Wire *wire = module->wire(search.find(stringf("$aiger%d$%d", aiger_autoidx, nodeID)));
|
||||
log_assert(wire);
|
||||
input_sig.append(wire);
|
||||
}
|
||||
|
|
@ -456,7 +461,7 @@ void AigerReader::parse_xaiger()
|
|||
log_assert(o.wire == nullptr);
|
||||
lut_mask.set(gray, o.data);
|
||||
}
|
||||
RTLIL::Cell *output_cell = module->cell(TwineSearch(&design->twines).find(stringf("$and$aiger%d$%d", aiger_autoidx, rootNodeID)));
|
||||
RTLIL::Cell *output_cell = module->cell(search.find(stringf("$and$aiger%d$%d", aiger_autoidx, rootNodeID)));
|
||||
log_assert(output_cell);
|
||||
module->remove(output_cell);
|
||||
module->addLut(Twine{stringf("$lut$aiger%d$%d", aiger_autoidx, rootNodeID)}, input_sig, output_sig, std::move(lut_mask));
|
||||
|
|
@ -772,6 +777,21 @@ void AigerReader::parse_aiger_binary()
|
|||
}
|
||||
}
|
||||
|
||||
// add(std::string) always interns a fresh leaf, but an equal-content name may
|
||||
// already exist in the pool as a NEW_TWINE suffix (auto-generated names share a
|
||||
// prefix leaf). Reuse that ref so every wire/cell with the same name string is
|
||||
// keyed by a single canonical ref; otherwise leaf-vs-suffix refs diverge and
|
||||
// module->wire()/cell() lookups miss.
|
||||
TwineRef AigerReader::intern_name(const std::string &escaped, TwineSearch &search)
|
||||
{
|
||||
TwineRef existing = search.find(escaped);
|
||||
if (existing != Twine::Null)
|
||||
return existing;
|
||||
TwineRef ref = design->twines.add(std::string{escaped});
|
||||
search.insert(ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
void AigerReader::post_process()
|
||||
{
|
||||
unsigned ci_count = 0, co_count = 0;
|
||||
|
|
@ -816,6 +836,7 @@ void AigerReader::post_process()
|
|||
std::ifstream mf(map_filename);
|
||||
std::string type, symbol;
|
||||
int variable, index;
|
||||
TwineSearch search(&design->twines);
|
||||
while (mf >> type >> variable >> index >> symbol) {
|
||||
RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
|
||||
if (type == "input") {
|
||||
|
|
@ -830,9 +851,9 @@ void AigerReader::post_process()
|
|||
// Cope with the fact that a CI might be identical
|
||||
// to a PI (necessary due to ABC); in those cases
|
||||
// simply connect the latter to the former
|
||||
existing = module->wire(TwineSearch(&design->twines).find(escaped_s.str()));
|
||||
existing = module->wire(search.find(escaped_s.str()));
|
||||
if (!existing)
|
||||
module->rename(wire, design->twines.add(std::string{escaped_s.str()}));
|
||||
module->rename(wire, intern_name(escaped_s.str(), search));
|
||||
else {
|
||||
wire->port_input = false;
|
||||
module->connect(wire, existing);
|
||||
|
|
@ -841,9 +862,9 @@ void AigerReader::post_process()
|
|||
}
|
||||
else {
|
||||
RTLIL::IdString indexed_name = stringf("%s[%d]", escaped_s, index);
|
||||
existing = module->wire(TwineSearch(&design->twines).find(indexed_name.str()));
|
||||
existing = module->wire(search.find(indexed_name.str()));
|
||||
if (!existing)
|
||||
module->rename(wire, design->twines.add(std::string{indexed_name.str()}));
|
||||
module->rename(wire, intern_name(indexed_name.str(), search));
|
||||
else {
|
||||
module->connect(wire, existing);
|
||||
wire->port_input = false;
|
||||
|
|
@ -875,9 +896,9 @@ void AigerReader::post_process()
|
|||
// Cope with the fact that a CO might be identical
|
||||
// to a PO (necessary due to ABC); in those cases
|
||||
// simply connect the latter to the former
|
||||
existing = module->wire(TwineSearch(&design->twines).find(escaped_s.str()));
|
||||
existing = module->wire(search.find(escaped_s.str()));
|
||||
if (!existing)
|
||||
module->rename(wire, design->twines.add(std::string{escaped_s.str()}));
|
||||
module->rename(wire, intern_name(escaped_s.str(), search));
|
||||
else {
|
||||
wire->port_output = false;
|
||||
existing->port_output = true;
|
||||
|
|
@ -888,9 +909,9 @@ void AigerReader::post_process()
|
|||
}
|
||||
else {
|
||||
RTLIL::IdString indexed_name = stringf("%s[%d]", escaped_s, index);
|
||||
existing = module->wire(TwineSearch(&design->twines).find(indexed_name.str()));
|
||||
existing = module->wire(search.find(indexed_name.str()));
|
||||
if (!existing)
|
||||
module->rename(wire, design->twines.add(std::string{indexed_name.str()}));
|
||||
module->rename(wire, intern_name(indexed_name.str(), search));
|
||||
else {
|
||||
wire->port_output = false;
|
||||
existing->port_output = true;
|
||||
|
|
@ -912,17 +933,18 @@ void AigerReader::post_process()
|
|||
}
|
||||
}
|
||||
else if (type == "box") {
|
||||
RTLIL::Cell* cell = module->cell(TwineSearch(&design->twines).find(stringf("$box%d", variable)));
|
||||
RTLIL::Cell* cell = module->cell(search.find(stringf("$box%d", variable)));
|
||||
if (!cell)
|
||||
log_debug("Box %d (%s) no longer exists.\n", variable, log_id(escaped_s));
|
||||
else
|
||||
module->rename(cell, design->twines.add(std::string{escaped_s.str()}));
|
||||
module->rename(cell, intern_name(escaped_s.str(), search));
|
||||
}
|
||||
else
|
||||
log_error("Symbol type '%s' not recognised.\n", type);
|
||||
}
|
||||
}
|
||||
|
||||
TwineSearch wp_search(&design->twines);
|
||||
for (auto &wp : wideports_cache) {
|
||||
auto name = wp.first;
|
||||
int min = wp.second.first;
|
||||
|
|
@ -930,30 +952,33 @@ void AigerReader::post_process()
|
|||
if (min == 0 && max == 0)
|
||||
continue;
|
||||
|
||||
RTLIL::Wire *wire = module->wire(TwineSearch(&design->twines).find(name.str()));
|
||||
if (wire)
|
||||
module->rename(wire, design->twines.add(std::string{RTLIL::escape_id(stringf("%s[%d]", name.str(), 0))}));
|
||||
RTLIL::Wire *wire = module->wire(wp_search.find(name.str()));
|
||||
if (wire) {
|
||||
TwineRef renamed = design->twines.add(std::string{RTLIL::escape_id(stringf("%s[%d]", name.str(), 0))});
|
||||
wp_search.insert(renamed);
|
||||
module->rename(wire, renamed);
|
||||
}
|
||||
|
||||
// Do not make ports with a mix of input/output into
|
||||
// wide ports
|
||||
bool port_input = false, port_output = false;
|
||||
for (int i = min; i <= max; i++) {
|
||||
RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
|
||||
RTLIL::Wire *other_wire = module->wire(TwineSearch(&design->twines).find(other_name.str()));
|
||||
RTLIL::Wire *other_wire = module->wire(wp_search.find(other_name.str()));
|
||||
if (other_wire) {
|
||||
port_input = port_input || other_wire->port_input;
|
||||
port_output = port_output || other_wire->port_output;
|
||||
}
|
||||
}
|
||||
|
||||
wire = module->addWire(design->twines.add(std::string{name.str()}), max-min+1);
|
||||
wire = module->addWire(intern_name(name.str(), wp_search), max-min+1);
|
||||
wire->start_offset = min;
|
||||
wire->port_input = port_input;
|
||||
wire->port_output = port_output;
|
||||
|
||||
for (int i = min; i <= max; i++) {
|
||||
RTLIL::IdString other_name = stringf("%s[%d]", name, i);
|
||||
RTLIL::Wire *other_wire = module->wire(TwineSearch(&design->twines).find(other_name.str()));
|
||||
RTLIL::Wire *other_wire = module->wire(wp_search.find(other_name.str()));
|
||||
if (other_wire) {
|
||||
other_wire->port_input = false;
|
||||
other_wire->port_output = false;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ struct AigerReader
|
|||
std::vector<RTLIL::Wire*> bad_properties;
|
||||
std::vector<RTLIL::Cell*> boxes;
|
||||
std::vector<int> mergeability, initial_state;
|
||||
dict<unsigned, RTLIL::Wire*> aiger_wires;
|
||||
|
||||
AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports);
|
||||
void parse_aiger();
|
||||
|
|
@ -54,6 +55,7 @@ struct AigerReader
|
|||
void parse_aiger_binary();
|
||||
void post_process();
|
||||
|
||||
TwineRef intern_name(const std::string &escaped, TwineSearch &search);
|
||||
RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ struct Xaiger2Frontend : public Frontend {
|
|||
log_error("Bad map file: primary output literal out of range\n");
|
||||
if (bits[lit] == RTLIL::Sm)
|
||||
log_error("Bad map file: primary output literal is a marker\n");
|
||||
Wire *w = module->wire(TwineSearch(&design->twines).find(name));
|
||||
Wire *w = module->wire(search.find(name));
|
||||
if (!w || woffset < 0 || woffset >= w->width)
|
||||
log_error("Map file references non-existent signal bit %s[%d]\n",
|
||||
name.c_str(), woffset);
|
||||
|
|
@ -434,8 +434,8 @@ struct Xaiger2Frontend : public Frontend {
|
|||
log_error("Bad map file: pseudo primary output literal out of range\n");
|
||||
if (bits[lit] == RTLIL::Sm)
|
||||
log_error("Bad map file: pseudo primary output literal is a marker\n");
|
||||
Cell *cell = module->cell(TwineSearch(&design->twines).find(box_name));
|
||||
auto box_port_ref = TwineSearch(&design->twines).find(box_port);
|
||||
Cell *cell = module->cell(search.find(box_name));
|
||||
auto box_port_ref = search.find(box_port);
|
||||
if (!cell || !cell->hasPort(box_port_ref))
|
||||
log_error("Map file references non-existent box port %s/%s\n",
|
||||
box_name.c_str(), box_port.c_str());
|
||||
|
|
|
|||
|
|
@ -1106,10 +1106,6 @@ std::string AstNode::loc_string() const
|
|||
|
||||
void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
|
||||
{
|
||||
// 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;
|
||||
|
|
@ -1152,11 +1148,6 @@ 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->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;
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
|
||||
Module *module = new RTLIL::Module;
|
||||
module->design = design;
|
||||
module->meta_->name = design->twines.add(Twine{RTLIL::escape_id(modname)});
|
||||
module->meta_->name = design->twines.add(RTLIL::escape_id(modname));
|
||||
|
||||
if (design->module(module->meta_->name))
|
||||
log_error("Re-definition of module %s.\n", design->twines.str(module->meta_->name));
|
||||
|
|
@ -327,6 +327,8 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
|
||||
dict<int, SigBit> signal_bits;
|
||||
|
||||
dict<IdString, Wire*> wire_cache;
|
||||
|
||||
if (node->data_dict.count("ports"))
|
||||
{
|
||||
JsonNode *ports_node = node->data_dict.at("ports");
|
||||
|
|
@ -357,10 +359,12 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
if (port_bits_node->type != 'A')
|
||||
log_error("JSON port node '%s' has non-array bits attribute.\n", port_name.unescape());
|
||||
|
||||
Wire *port_wire = module->wire(TwineSearch(&design->twines).find(port_name.str()));
|
||||
Wire *port_wire = wire_cache.count(port_name) ? wire_cache.at(port_name) : nullptr;
|
||||
|
||||
if (port_wire == nullptr)
|
||||
port_wire = module->addWire(Twine{port_name.str()}, GetSize(port_bits_node->data_array));
|
||||
if (port_wire == nullptr) {
|
||||
port_wire = module->addWire(design->twines.add(port_name.str()), GetSize(port_bits_node->data_array));
|
||||
wire_cache[port_name] = port_wire;
|
||||
}
|
||||
|
||||
if (port_node->data_dict.count("upto") != 0) {
|
||||
JsonNode *val = port_node->data_dict.at("upto");
|
||||
|
|
@ -455,10 +459,12 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
if (bits_node->type != 'A')
|
||||
log_error("JSON netname node '%s' has non-array bits attribute.\n", net_name.unescape());
|
||||
|
||||
Wire *wire = module->wire(TwineSearch(&design->twines).find(net_name.str()));
|
||||
Wire *wire = wire_cache.count(net_name) ? wire_cache.at(net_name) : nullptr;
|
||||
|
||||
if (wire == nullptr)
|
||||
wire = module->addWire(Twine{net_name.str()}, GetSize(bits_node->data_array));
|
||||
if (wire == nullptr) {
|
||||
wire = module->addWire(design->twines.add(net_name.str()), GetSize(bits_node->data_array));
|
||||
wire_cache[net_name] = wire;
|
||||
}
|
||||
|
||||
if (net_node->data_dict.count("upto") != 0) {
|
||||
JsonNode *val = net_node->data_dict.at("upto");
|
||||
|
|
@ -532,7 +538,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
|
||||
IdString cell_type = RTLIL::escape_id(type_node->data_string.c_str());
|
||||
|
||||
Cell *cell = module->addCell(Twine{cell_name.str()}, Twine{cell_type.str()});
|
||||
Cell *cell = module->addCell(design->twines.add(cell_name.str()), design->twines.add(cell_type.str()));
|
||||
|
||||
if (cell_node->data_dict.count("connections") == 0)
|
||||
log_error("JSON cells node '%s' has no connections attribute.\n", cell_name.unescape());
|
||||
|
|
@ -580,7 +586,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
|
||||
}
|
||||
|
||||
cell->setPort(design->twines.add(Twine{conn_name.str()}), sig);
|
||||
cell->setPort(design->twines.add(conn_name.str()), sig);
|
||||
}
|
||||
|
||||
if (cell_node->data_dict.count("attributes"))
|
||||
|
|
@ -604,7 +610,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
JsonNode *memory_node = memory_node_it.second;
|
||||
|
||||
RTLIL::Memory *mem = new RTLIL::Memory;
|
||||
mem->meta_->name = design->twines.add(Twine{memory_name.str()});
|
||||
mem->meta_->name = design->twines.add(memory_name.str());
|
||||
mem->module = module;
|
||||
|
||||
if (memory_node->type != 'D')
|
||||
|
|
|
|||
|
|
@ -50,26 +50,14 @@ struct RTLILFrontendWorker {
|
|||
|
||||
RTLIL::Module *current_module;
|
||||
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
|
||||
// A resolved "@N" src reference, carried from parse_attribute to the
|
||||
// object's absorb_attrs site so it lands on the object without being
|
||||
// flattened into a fresh leaf.
|
||||
|
||||
TwineRef pending_src = Twine::Null;
|
||||
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
|
||||
std::vector<RTLIL::CaseRule*> 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->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<size_t, TwineRef> twine_remap;
|
||||
std::vector<TwineRef> twine_parser_holds;
|
||||
|
||||
// Raw twines-block node descriptors keyed by file-local id. The block may
|
||||
// list a node before its children (the writer emits in pool-index order,
|
||||
// and free-list slot reuse can place a parent at a lower index than a
|
||||
// child), so descriptors are collected first and materialized on demand in
|
||||
// dependency order via materialize_file_twine.
|
||||
struct TwineDesc {
|
||||
enum Kind { Leaf, Suffix, Concat } kind;
|
||||
std::string text;
|
||||
|
|
@ -481,8 +469,6 @@ struct RTLILFrontendWorker {
|
|||
current_module->design = design;
|
||||
current_module->meta_->name = module_name;
|
||||
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);
|
||||
pending_src = Twine::Null;
|
||||
current_module->attributes = std::move(attrbuf);
|
||||
|
|
@ -543,18 +529,9 @@ 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();
|
||||
if (!raw.empty() && raw[0] == '@') {
|
||||
// Compact "@N" reference into the `twines` block: carry the
|
||||
// resolved twine straight to the object (set after its
|
||||
// absorb_attrs) so its structure is preserved, not flattened.
|
||||
size_t file_id = 0;
|
||||
auto [ptr, ec] = std::from_chars(raw.data() + 1, raw.data() + raw.size(), file_id);
|
||||
if (ec != std::errc() || ptr != raw.data() + raw.size())
|
||||
|
|
@ -591,10 +568,7 @@ struct RTLILFrontendWorker {
|
|||
base = TwineRef(id);
|
||||
} else {
|
||||
auto it = twine_remap.find(id);
|
||||
if (it == twine_remap.end())
|
||||
base = materialize_file_twine(id);
|
||||
else
|
||||
base = it->second;
|
||||
base = (it == twine_remap.end()) ? materialize_file_twine(id) : it->second;
|
||||
}
|
||||
return twine_tag(base, is_public);
|
||||
}
|
||||
|
|
@ -708,21 +682,17 @@ struct RTLILFrontendWorker {
|
|||
error("Expected `leaf`, `suffix` or `concat` inside twines block, got `%s'.",
|
||||
error_token());
|
||||
}
|
||||
std::vector<size_t> ordered_ids;
|
||||
ordered_ids.reserve(twine_descs.size());
|
||||
for (auto &it : twine_descs)
|
||||
materialize_file_twine(it.first);
|
||||
ordered_ids.push_back(it.first);
|
||||
std::sort(ordered_ids.begin(), ordered_ids.end());
|
||||
for (size_t id : ordered_ids)
|
||||
materialize_file_twine(id);
|
||||
twine_descs.clear();
|
||||
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()
|
||||
{
|
||||
twine_parser_holds.clear();
|
||||
twine_remap.clear();
|
||||
}
|
||||
|
||||
void parse_parameter()
|
||||
{
|
||||
RTLIL::IdString id = parse_id();
|
||||
|
|
@ -1080,9 +1050,6 @@ struct RTLILFrontendWorker {
|
|||
act.enable = parse_sigspec();
|
||||
act.priority_mask = parse_const();
|
||||
rule->mem_write_actions.push_back(act);
|
||||
// meta_idx_ is a weak ref — drop ours so the pushed copy
|
||||
// in the vector is the sole holder. Process::~Process
|
||||
// walks the tree to actually release.
|
||||
act.meta_ = nullptr;
|
||||
expect_eol();
|
||||
}
|
||||
|
|
@ -1126,7 +1093,9 @@ struct RTLILFrontendWorker {
|
|||
}
|
||||
if (attrbuf.size() != 0)
|
||||
error("dangling attribute");
|
||||
release_twine_parser_holds();
|
||||
|
||||
twine_parser_holds.clear();
|
||||
twine_remap.clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -39,12 +39,6 @@ void manufacture_info(InputType flop, OutputType& info, FfInitVals *initvals) {
|
|||
info.sig_q = cell->getPort(TW::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 = cell->src_id();
|
||||
if (initvals)
|
||||
|
|
@ -762,7 +756,6 @@ 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;
|
||||
|
|
|
|||
|
|
@ -172,8 +172,9 @@ struct FfData : FfTypeData {
|
|||
dict<IdString, Const> 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.
|
||||
TwineRef src_twine;
|
||||
// before emit() runs. Null when the source cell had no src (default
|
||||
// TwineRef() is index 0, a valid constid, so it must be Null here).
|
||||
TwineRef src_twine = Twine::Null;
|
||||
|
||||
FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) {
|
||||
width = 0;
|
||||
|
|
|
|||
|
|
@ -887,7 +887,6 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
|
|||
return nullptr;
|
||||
|
||||
// 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.
|
||||
|
|
@ -998,7 +997,6 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
|
|||
|
||||
IdString name = stringf("$%s$rdreg[%d]", memid, idx);
|
||||
FfData ff(module, initvals, name);
|
||||
// Carry mem's src into the ff via the OwnedTwine handle — same
|
||||
// pool, direct id retain. emit() transfers verbatim.
|
||||
ff.src_twine = mem_src;
|
||||
ff.width = GetSize(port.data);
|
||||
|
|
|
|||
|
|
@ -953,7 +953,6 @@ bool RTLIL::AttrObject::get_bool_attribute(IdString id) const
|
|||
void RTLIL::AttrObject::set_string_attribute(IdString id, string value)
|
||||
{
|
||||
// ID::src on the base AttrObject is not routable here because the base
|
||||
// has no Design context — callers needing string-form src must go
|
||||
// through the subtype helper (Cell::set_src_attribute / Wire::… / …)
|
||||
// which derives the design from context.
|
||||
log_assert(id != ID::src && "set_string_attribute(ID::src,...) on AttrObject base; use the subtype helper");
|
||||
|
|
@ -965,7 +964,6 @@ void RTLIL::AttrObject::set_string_attribute(IdString id, string value)
|
|||
|
||||
string RTLIL::AttrObject::get_string_attribute(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);
|
||||
|
|
@ -1821,22 +1819,22 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules(RTLIL::SelectPartial
|
|||
switch (boxes)
|
||||
{
|
||||
case RTLIL::SB_UNBOXED_WARN:
|
||||
log_warning("Ignoring boxed module %s.\n", twines.str(it.first).c_str());
|
||||
log_warning("Ignoring boxed module %s.\n", log_id(it.second));
|
||||
break;
|
||||
case RTLIL::SB_EXCL_BB_WARN:
|
||||
log_warning("Ignoring blackbox module %s.\n", twines.str(it.first).c_str());
|
||||
log_warning("Ignoring blackbox module %s.\n", log_id(it.second));
|
||||
break;
|
||||
case RTLIL::SB_UNBOXED_ERR:
|
||||
log_error("Unsupported boxed module %s.\n", twines.str(it.first).c_str());
|
||||
log_error("Unsupported boxed module %s.\n", log_id(it.second));
|
||||
break;
|
||||
case RTLIL::SB_EXCL_BB_ERR:
|
||||
log_error("Unsupported blackbox module %s.\n", twines.str(it.first).c_str());
|
||||
log_error("Unsupported blackbox module %s.\n", log_id(it.second));
|
||||
break;
|
||||
case RTLIL::SB_UNBOXED_CMDERR:
|
||||
log_cmd_error("Unsupported boxed module %s.\n", twines.str(it.first).c_str());
|
||||
log_cmd_error("Unsupported boxed module %s.\n", log_id(it.second));
|
||||
break;
|
||||
case RTLIL::SB_EXCL_BB_CMDERR:
|
||||
log_cmd_error("Unsupported blackbox module %s.\n", twines.str(it.first).c_str());
|
||||
log_cmd_error("Unsupported blackbox module %s.\n", log_id(it.second));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -1845,13 +1843,13 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules(RTLIL::SelectPartial
|
|||
switch(partials)
|
||||
{
|
||||
case RTLIL::SELECT_WHOLE_WARN:
|
||||
log_warning("Ignoring partially selected module %s.\n", twines.str(it.first).c_str());
|
||||
log_warning("Ignoring partially selected module %s.\n", log_id(it.second));
|
||||
break;
|
||||
case RTLIL::SELECT_WHOLE_ERR:
|
||||
log_error("Unsupported partially selected module %s.\n", twines.str(it.first).c_str());
|
||||
log_error("Unsupported partially selected module %s.\n", log_id(it.second));
|
||||
break;
|
||||
case RTLIL::SELECT_WHOLE_CMDERR:
|
||||
log_cmd_error("Unsupported partially selected module %s.\n", twines.str(it.first).c_str());
|
||||
log_cmd_error("Unsupported partially selected module %s.\n", log_id(it.second));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -1893,7 +1891,6 @@ RTLIL::Module::~Module()
|
|||
delete pr.second;
|
||||
for (auto binding : bindings_)
|
||||
delete binding;
|
||||
// Module's own src — release last so the pool stays valid for
|
||||
// inner releases above.
|
||||
if (design)
|
||||
design->obj_release_src(this);
|
||||
|
|
@ -3172,7 +3169,6 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) cons
|
|||
// 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.
|
||||
if (this->design && new_mod->design)
|
||||
copy_src_into(this, this->design, new_mod, new_mod->design);
|
||||
|
|
@ -3189,7 +3185,6 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) cons
|
|||
return;
|
||||
// Preserve name already set by addWire/addCell (in dst's pool).
|
||||
TwineRef saved_name = dst_obj->meta_ ? dst_obj->meta_->name : Twine::Null;
|
||||
// Recycle old meta slot (no field releases — name's retain lives on).
|
||||
if (dst_obj->meta_) {
|
||||
dst_obj->meta_->name = Twine::Null;
|
||||
dst_obj->meta_->src = Twine::Null;
|
||||
|
|
@ -3274,7 +3269,6 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) cons
|
|||
// 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.
|
||||
// Re-intern each wire/cell name from the source design's pool into
|
||||
|
|
@ -3472,7 +3466,6 @@ void RTLIL::Module::add(RTLIL::Process *process)
|
|||
processes[process->meta_->name] = process;
|
||||
process->module = this;
|
||||
// Propagate module back-pointer to every CaseRule/SwitchRule in the
|
||||
// root case tree and every MemWriteAction in the sync rules — so the
|
||||
// per-Design src meta vector can be resolved from any inner-process
|
||||
// AttrObject via `module->design` after attach.
|
||||
process->root_case.setModuleRecursive(this);
|
||||
|
|
@ -3853,7 +3846,6 @@ RTLIL::Memory *RTLIL::Module::addMemory(TwineRef name, const RTLIL::Memory *othe
|
|||
mem->size = other->size;
|
||||
mem->attributes = other->attributes;
|
||||
{
|
||||
// Clone path drops src for now — caller responsible for migrating
|
||||
// src across the design boundary if needed. addMemory(name) is the
|
||||
// common case.
|
||||
(void)other;
|
||||
|
|
@ -6783,7 +6775,6 @@ 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)
|
||||
|
|
@ -6807,7 +6798,6 @@ 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;
|
||||
|
|
@ -6821,7 +6811,6 @@ RTLIL::SyncRule *RTLIL::SyncRule::clone() const
|
|||
new_syncrule->signal = signal;
|
||||
new_syncrule->actions = actions;
|
||||
new_syncrule->mem_write_actions = mem_write_actions;
|
||||
// Drop meta_idx_ on the cloned MemWriteActions — the integer was
|
||||
// copied by the vector assignment above without registering with
|
||||
// any pool; the caller is responsible for migrating src across the
|
||||
// clone via context (see Process::clone).
|
||||
|
|
@ -6974,7 +6963,6 @@ void RTLIL::Memory::absorb_attrs(dict<IdString, RTLIL::Const> &&buf)
|
|||
module->design->absorb_attrs(this, std::move(buf));
|
||||
}
|
||||
|
||||
// CaseRule / SwitchRule / MemWriteAction src helpers — all delegate to
|
||||
// module->design->obj_* via the back-pointer added in the earlier commit.
|
||||
TwineRef RTLIL::CaseRule::src_id() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -555,12 +555,16 @@ struct RTLIL::IdString
|
|||
|
||||
// often one needs to check if a given IdString is part of a list (for example a list
|
||||
// of cell types). the following functions helps with that.
|
||||
// Constrained to 2+ args so a single argument always resolves to a concrete
|
||||
// overload below; otherwise a single argument matching none of them (e.g. a
|
||||
// TwineRef) would re-match this template and recurse infinitely.
|
||||
template<typename... Args>
|
||||
bool in(const Args &... args) const {
|
||||
bool in(const Args &... args) const requires (sizeof...(Args) != 1) {
|
||||
return (... || in(args));
|
||||
}
|
||||
|
||||
bool in(IdString rhs) const { return *this == rhs; }
|
||||
inline bool in(TwineRef rhs) const;
|
||||
bool in(const char *rhs) const { return *this == rhs; }
|
||||
bool in(const std::string &rhs) const { return *this == rhs; }
|
||||
inline bool in(const pool<IdString> &rhs) const;
|
||||
|
|
@ -600,6 +604,8 @@ inline bool operator==(TwineRef a, RTLIL::IdString b) {
|
|||
}
|
||||
inline bool operator==(RTLIL::IdString a, TwineRef b) { return b == a; }
|
||||
|
||||
inline bool RTLIL::IdString::in(TwineRef rhs) const { return *this == rhs; }
|
||||
|
||||
struct RTLIL::OwningIdString : public RTLIL::IdString {
|
||||
inline OwningIdString() { }
|
||||
inline OwningIdString(const OwningIdString &str) : IdString(str) { get_reference(); }
|
||||
|
|
@ -1402,7 +1408,6 @@ inline bool operator!=(RTLIL::IdString lhs, const RTLIL::NameMasqBase<Derived> &
|
|||
|
||||
// Read-only masquerade for Wire::name. Reads materialise the TwineRef in
|
||||
// the owning Design's twines pool into a temporary IdString. Writes are
|
||||
// intentionally unsupported — use Module::rename(wire, new_name) instead.
|
||||
// Defined before Wire so it can be used as a [[no_unique_address]] member.
|
||||
struct RTLIL::WireNameMasq : RTLIL::NameMasqBase<RTLIL::WireNameMasq> {
|
||||
WireNameMasq() = default;
|
||||
|
|
@ -2194,7 +2199,6 @@ struct RTLIL::Design
|
|||
|
||||
// Wholesale-copy this design into `dst`. `dst` must be empty (no
|
||||
// modules). Copies 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;
|
||||
|
|
@ -2325,7 +2329,6 @@ private:
|
|||
friend struct RTLIL::Patch;
|
||||
public:
|
||||
// Shadows NamedObject::name. Reads materialise via twines; writes
|
||||
// are a compile error — use Module::rename(wire, new_name) instead.
|
||||
[[no_unique_address]] RTLIL::WireNameMasq name;
|
||||
|
||||
Hasher::hash_t hashidx_;
|
||||
|
|
@ -2395,7 +2398,6 @@ struct RTLIL::Memory : public RTLIL::AttrObject
|
|||
Memory();
|
||||
~Memory();
|
||||
|
||||
// Back-pointer to the owning module — same role as Cell::module /
|
||||
// Wire::module. Set by Module::addMemory / the frontends that
|
||||
// construct Memory free-standing before attaching to a module.
|
||||
// Lets Memory's src access resolve uniformly via module->design.
|
||||
|
|
@ -2436,7 +2438,6 @@ private:
|
|||
bool bufnorm_handle_setPort(TwineRef portname, RTLIL::SigSpec &signal, dict<TwineRef, RTLIL::SigSpec>::iterator conn_it);
|
||||
public:
|
||||
// Shadows NamedObject::name. Reads materialise via twines; writes
|
||||
// are a compile error — use Module::rename(cell, new_name) instead.
|
||||
[[no_unique_address]] RTLIL::CellNameMasq name;
|
||||
|
||||
Hasher::hash_t hashidx_;
|
||||
|
|
@ -2525,7 +2526,6 @@ struct RTLIL::CaseRule : public RTLIL::AttrObject
|
|||
|
||||
// Walk the whole CaseRule subtree (this case, every switch, every
|
||||
// nested case, every MemWriteAction inside this process's sync rules
|
||||
// — those are reached through Process, not here) and set `module` on
|
||||
// each. Idempotent.
|
||||
void setModuleRecursive(RTLIL::Module *m);
|
||||
|
||||
|
|
@ -2706,7 +2706,6 @@ inline Hasher RTLIL::SigBit::hash_into(Hasher h) const {
|
|||
inline Hasher RTLIL::SigBit::hash_top() const {
|
||||
Hasher h;
|
||||
if (wire) {
|
||||
// Use the wire's name (TwineRef) directly — avoids IdString materialisation.
|
||||
TwineRef name = wire->meta_ ? wire->meta_->name : Twine::Null;
|
||||
h.eat(name);
|
||||
h.eat(offset);
|
||||
|
|
@ -3075,7 +3074,6 @@ public:
|
|||
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.
|
||||
|
|
@ -3104,7 +3102,6 @@ public:
|
|||
return design->selected_member(meta_->name, member->meta_->name);
|
||||
}
|
||||
|
||||
// Primary (fast) overloads — key directly into the dict.
|
||||
RTLIL::Wire* wire(TwineRef id) {
|
||||
auto it = wires_.find(id);
|
||||
return it == wires_.end() ? nullptr : it->second;
|
||||
|
|
|
|||
|
|
@ -1172,7 +1172,6 @@ bool RTLIL::Cell::bufnorm_handle_setPort(TwineRef portname, SigSpec &signal, dic
|
|||
}
|
||||
|
||||
auto dir = port_dir(portname);
|
||||
// Fast path: connecting a full driverless wire to an output port — everything else
|
||||
// goes through the bufnorm queues and is handled during the next bufNormalize call
|
||||
if ((dir == RTLIL::PD_OUTPUT || dir == RTLIL::PD_INOUT) && signal.is_wire()) {
|
||||
Wire *w = signal.as_wire();
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@ void twine_prepopulate() {
|
|||
// log_assert(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;
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ struct TW {
|
|||
};
|
||||
|
||||
#define TW(id) ((size_t)std::integral_constant<int, lookup_well_known_id(#id)>::value)
|
||||
// #define TW(name) TW::lookup(#name)
|
||||
|
||||
struct Twine {
|
||||
static constexpr TwineRef Null = std::numeric_limits<size_t>::max();
|
||||
|
|
@ -120,19 +119,31 @@ struct Twine {
|
|||
auto operator<=>(const Suffix&) const = default;
|
||||
};
|
||||
|
||||
struct AutoPrefix {
|
||||
|
||||
struct AutoSuffix {
|
||||
const std::string *prefix;
|
||||
std::string tail;
|
||||
auto operator<=>(const AutoPrefix&) const = default;
|
||||
auto operator<=>(const AutoSuffix&) const = default;
|
||||
};
|
||||
|
||||
std::variant<std::monostate, std::string, std::vector<TwineRef>, Suffix, AutoPrefix> data;
|
||||
std::variant<
|
||||
// Unused slot
|
||||
std::monostate,
|
||||
// "leaf", regular deduplicated string
|
||||
std::string,
|
||||
// "concat", for src only, requires concatenating character convention - '|' for src attributes, others for others in the future
|
||||
std::vector<TwineRef>,
|
||||
// "suffix", deduplicates shared prefixes
|
||||
Suffix,
|
||||
// transient suffix constructed with NEW_TWINE and NEW_TWINE_SUFFIX
|
||||
// turned into a regular Suffix when added to a TwinePool
|
||||
AutoSuffix> data;
|
||||
|
||||
bool is_dead() const { return std::holds_alternative<std::monostate>(data); }
|
||||
bool is_leaf() const { return std::holds_alternative<std::string>(data); }
|
||||
bool is_concat() const { return std::holds_alternative<std::vector<TwineRef>>(data); }
|
||||
bool is_suffix() const { return std::holds_alternative<Suffix>(data); }
|
||||
bool is_auto_prefix() const { return std::holds_alternative<AutoPrefix>(data); }
|
||||
bool is_auto_prefix() const { return std::holds_alternative<AutoSuffix>(data); }
|
||||
bool is_flat() const { return is_leaf() || is_suffix(); }
|
||||
const std::string &leaf() const { return std::get<std::string>(data); }
|
||||
const std::vector<TwineRef> &children() const { return std::get<std::vector<TwineRef>>(data); }
|
||||
|
|
@ -150,7 +161,6 @@ struct TwineHash {
|
|||
|
||||
size_t operator()(const Twine& t) const noexcept;
|
||||
size_t operator()(TwineRef ref) const noexcept;
|
||||
// size_t operator()(std::string_view v) const noexcept;
|
||||
};
|
||||
|
||||
struct TwineEq {
|
||||
|
|
@ -161,8 +171,6 @@ struct TwineEq {
|
|||
bool operator()(TwineRef a, TwineRef b) const noexcept;
|
||||
bool operator()(TwineRef a, const Twine& b) const noexcept;
|
||||
bool operator()(const Twine& a, TwineRef b) const noexcept;
|
||||
// bool operator()(TwineRef a, std::string_view b) const noexcept;
|
||||
// bool operator()(std::string_view a, TwineRef b) const noexcept;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -365,12 +373,8 @@ struct TwinePool {
|
|||
return ref;
|
||||
}
|
||||
|
||||
// Interns a structural Twine verbatim and returns the handle. Leaf content
|
||||
// is stored as-is — callers holding an escaped string must strip the '\'
|
||||
// and tag publicity themselves (or use the add(std::string) overload).
|
||||
// Suffix names inherit the prefix handle's publicity.
|
||||
TwineRef add(Twine t) {
|
||||
if (auto *ap = std::get_if<Twine::AutoPrefix>(&t.data)) {
|
||||
if (auto *ap = std::get_if<Twine::AutoSuffix>(&t.data)) {
|
||||
TwineRef pref = add_inner(Twine{*ap->prefix});
|
||||
return add_inner(Twine{Twine::Suffix{pref, std::move(ap->tail)}});
|
||||
}
|
||||
|
|
@ -612,7 +616,7 @@ struct DeepTwineEq {
|
|||
// Required by unordered_set to handle hash collisions between two TwineRefs.
|
||||
bool operator()(TwineRef a, TwineRef b) const {
|
||||
if (a == b) return true; // Index or structural equality shortcut
|
||||
std::string fb = flatten(b);
|
||||
std::string fb = pool->unescaped_str(b);
|
||||
return (*this)(a, std::string_view(fb));
|
||||
}
|
||||
|
||||
|
|
@ -660,7 +664,7 @@ struct TwineChildPool {
|
|||
|
||||
// Local analog of TwinePool::add; see there for the convention.
|
||||
TwineRef add(Twine t) {
|
||||
if (auto *ap = std::get_if<Twine::AutoPrefix>(&t.data)) {
|
||||
if (auto *ap = std::get_if<Twine::AutoSuffix>(&t.data)) {
|
||||
TwineRef pref = add_inner(Twine{*ap->prefix});
|
||||
return add_inner(Twine{Twine::Suffix{pref, std::move(ap->tail)}});
|
||||
}
|
||||
|
|
@ -731,6 +735,11 @@ struct TwineSearch {
|
|||
index.insert(STATIC_TWINE_END + idx);
|
||||
}
|
||||
}
|
||||
// Keep a hoisted search current after adding a ref to the pool, so the
|
||||
// search need not be rebuilt (O(pool)) between finds in a loop.
|
||||
void insert(TwineRef ref) {
|
||||
index.insert(twine_untag(ref));
|
||||
}
|
||||
// Escaped-name aware. Resolves both statics and locals by content.
|
||||
TwineRef find(std::string_view sv) const {
|
||||
bool is_public = !sv.empty() && sv[0] == '\\';
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ namespace {
|
|||
void apply_src(Module* mod, Cell* root, const std::vector<Cell*>& extras,
|
||||
const std::vector<Cell*>& targets, Cell* merge_src_into)
|
||||
{
|
||||
// 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;
|
||||
|
|
@ -205,7 +204,6 @@ void Patch::patch(Cell* root_cell, TwineRef old_port, SigSpec new_sig,
|
|||
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
|
||||
// and new_sig) which signorm flags as conflicting.
|
||||
root_cell->unsetPort(old_port);
|
||||
|
||||
|
|
@ -213,7 +211,6 @@ void Patch::patch(Cell* root_cell, TwineRef old_port, SigSpec new_sig,
|
|||
map->add(old_sig, new_sig);
|
||||
mod->connect_incremental(old_sig, new_sig);
|
||||
|
||||
// Remove root cell only — no input-cone walk.
|
||||
mod->remove(root_cell);
|
||||
}
|
||||
|
||||
|
|
@ -277,7 +274,6 @@ void Patch::commit_inheriting_src(Cell* src_source) {
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// No virtual methods — subclasses cannot be dispatched through a Patch pointer.
|
||||
struct RTLIL::Patch : public CellAdderMixin<RTLIL::Patch>
|
||||
{
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ public:
|
|||
|
||||
|
||||
// ---------------------------------------------------
|
||||
// BitGrouper — partition output bits by a per-bit key
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
// Many passes that split a multi-bit cell or word-level FF into smaller
|
||||
|
|
|
|||
|
|
@ -305,12 +305,12 @@ RTLIL::IdString new_id_suffix(std::string_view file, int line, std::string_view
|
|||
#define NEW_ID_SUFFIX(suffix) \
|
||||
YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)
|
||||
#define NEW_TWINE \
|
||||
YOSYS_NAMESPACE_PREFIX Twine{YOSYS_NAMESPACE_PREFIX Twine::AutoPrefix{[](std::string_view func) -> const std::string * { \
|
||||
YOSYS_NAMESPACE_PREFIX Twine{YOSYS_NAMESPACE_PREFIX Twine::AutoSuffix{[](std::string_view func) -> const std::string * { \
|
||||
static std::unique_ptr<const std::string> prefix(YOSYS_NAMESPACE_PREFIX create_id_prefix(__FILE__, __LINE__, func)); \
|
||||
return prefix.get(); \
|
||||
}(__FUNCTION__), std::to_string(YOSYS_NAMESPACE_PREFIX autoidx++)}}
|
||||
#define NEW_TWINE_SUFFIX(suffix) \
|
||||
YOSYS_NAMESPACE_PREFIX Twine{YOSYS_NAMESPACE_PREFIX Twine::AutoPrefix{[](std::string_view func) -> const std::string * { \
|
||||
YOSYS_NAMESPACE_PREFIX Twine{YOSYS_NAMESPACE_PREFIX Twine::AutoSuffix{[](std::string_view func) -> const std::string * { \
|
||||
static std::unique_ptr<const std::string> prefix(YOSYS_NAMESPACE_PREFIX create_id_prefix(__FILE__, __LINE__, func)); \
|
||||
return prefix.get(); \
|
||||
}(__FUNCTION__), std::string(suffix) + "$" + std::to_string(YOSYS_NAMESPACE_PREFIX autoidx++)}}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ endif
|
|||
OBJS += passes/cmds/add.o
|
||||
OBJS += passes/cmds/delete.o
|
||||
OBJS += passes/cmds/design.o
|
||||
OBJS += passes/cmds/dump_twines.o
|
||||
OBJS += passes/cmds/design_equal.o
|
||||
OBJS += passes/cmds/select.o
|
||||
OBJS += passes/cmds/show.o
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ struct PrintAttrsPass : public Pass {
|
|||
}
|
||||
|
||||
static void log_src(const RTLIL::Design *design, const RTLIL::AttrObject *obj, const unsigned int indent) {
|
||||
// Emit src outside the attributes loop — it lives on the typed
|
||||
// meta-vector slot, not in obj->attributes.
|
||||
if (design && design->obj_src_id(obj) != Twine::Null)
|
||||
log("%s(* src=\"%s\" *)\n", get_indent_str(indent),
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@ static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, co
|
|||
// 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 RTLIL::Design *design, const RTLIL::AttrObject *obj, const std::string &match_expr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ struct SplitcellsWorker
|
|||
std::string s = cell->name.str() + (slice_msb == slice_lsb ?
|
||||
stringf("%c%d%c", format[0], slice_lsb, format[1]) :
|
||||
stringf("%c%d%c%d%c", format[0], slice_msb, format[2], slice_lsb, format[1]));
|
||||
TwineRef slice_name = module->uniquify(module->design->twines.add(Twine{s}));
|
||||
TwineRef slice_name = module->uniquify(module->design->twines.add(std::move(s)));
|
||||
|
||||
Cell *slice = module->addCell(slice_name, cell);
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ struct SplitcellsWorker
|
|||
if (slice->hasParam(ID::WIDTH))
|
||||
slice->setParam(ID::WIDTH, GetSize(slice->getPort(TW::Y)));
|
||||
|
||||
log(" slice %d: %s => %s\n", i, slice_name, log_signal(slice->getPort(TW::Y)));
|
||||
log(" slice %d: %s => %s\n", i, module->design->twines.str(slice_name).c_str(), log_signal(slice->getPort(TW::Y)));
|
||||
}
|
||||
|
||||
module->remove(cell);
|
||||
|
|
@ -162,11 +162,11 @@ struct SplitcellsWorker
|
|||
int slice_msb = slices[i]-1;
|
||||
int slice_lsb = slices[i-1];
|
||||
|
||||
TwinePool twines = module->design->twines;
|
||||
TwinePool &twines = module->design->twines;
|
||||
std::string s = cell->name.str() + (slice_msb == slice_lsb ?
|
||||
stringf("%c%d%c", format[0], slice_lsb, format[1]) :
|
||||
stringf("%c%d%c%d%c", format[0], slice_msb, format[2], slice_lsb, format[1]));
|
||||
TwineRef slice_name = module->uniquify(twines.add(Twine{s}));
|
||||
TwineRef slice_name = module->uniquify(twines.add(std::move(s)));
|
||||
|
||||
Cell *slice = module->addCell(slice_name, cell);
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ struct SplitnetsWorker
|
|||
if (format.size() > 1)
|
||||
new_wire_name += format.substr(1, 1);
|
||||
|
||||
RTLIL::Wire *new_wire = module->addWire(module->uniquify(module->design->twines.add(Twine{new_wire_name})), width);
|
||||
RTLIL::Wire *new_wire = module->addWire(module->uniquify(module->design->twines.add(std::move(new_wire_name))), width);
|
||||
new_wire->port_id = wire->port_id ? wire->port_id + offset : 0;
|
||||
new_wire->port_input = wire->port_input;
|
||||
new_wire->port_output = wire->port_output;
|
||||
|
|
|
|||
|
|
@ -56,8 +56,9 @@ struct EquivAddPass : public Pass {
|
|||
|
||||
if (GetSize(args) == 4 && args[1] == "-cell")
|
||||
{
|
||||
Cell *gold_cell = module->cell(TwineSearch(&design->twines).find(RTLIL::escape_id(args[2])));
|
||||
Cell *gate_cell = module->cell(TwineSearch(&design->twines).find(RTLIL::escape_id(args[3])));
|
||||
TwineSearch search(&design->twines);
|
||||
Cell *gold_cell = module->cell(search.find(RTLIL::escape_id(args[2])));
|
||||
Cell *gate_cell = module->cell(search.find(RTLIL::escape_id(args[3])));
|
||||
|
||||
if (gold_cell == nullptr) {
|
||||
if (try_mode) {
|
||||
|
|
|
|||
|
|
@ -154,10 +154,11 @@ struct EquivMakeWorker
|
|||
// list of cells without added $equiv cells
|
||||
auto cells_list = equiv_mod->cells().to_vector();
|
||||
|
||||
TwineSearch search(&equiv_mod->design->twines);
|
||||
for (auto id : wire_names)
|
||||
{
|
||||
TwineRef gold_id = TwineSearch(&equiv_mod->design->twines).find(id.str() + "_gold");
|
||||
TwineRef gate_id = TwineSearch(&equiv_mod->design->twines).find(id.str() + "_gate");
|
||||
TwineRef gold_id = search.find(id.str() + "_gold");
|
||||
TwineRef gate_id = search.find(id.str() + "_gate");
|
||||
|
||||
Wire *gold_wire = equiv_mod->wire(gold_id);
|
||||
Wire *gate_wire = equiv_mod->wire(gate_id);
|
||||
|
|
@ -331,10 +332,11 @@ struct EquivMakeWorker
|
|||
{
|
||||
SigMap assign_map(equiv_mod);
|
||||
|
||||
TwineSearch search(&equiv_mod->design->twines);
|
||||
for (auto id : cell_names)
|
||||
{
|
||||
TwineRef gold_id = TwineSearch(&equiv_mod->design->twines).find(id.str() + "_gold");
|
||||
TwineRef gate_id = TwineSearch(&equiv_mod->design->twines).find(id.str() + "_gate");
|
||||
TwineRef gold_id = search.find(id.str() + "_gold");
|
||||
TwineRef gate_id = search.find(id.str() + "_gate");
|
||||
|
||||
Cell *gold_cell = equiv_mod->cell(gold_id);
|
||||
Cell *gate_cell = equiv_mod->cell(gate_id);
|
||||
|
|
@ -380,7 +382,7 @@ struct EquivMakeWorker
|
|||
}
|
||||
|
||||
equiv_mod->remove(gate_cell);
|
||||
equiv_mod->rename(gold_cell, TwineSearch(&equiv_mod->design->twines).find(id.str()));
|
||||
equiv_mod->rename(gold_cell, search.find(id.str()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -492,9 +494,10 @@ struct EquivMakePass : public Pass {
|
|||
if (argidx+3 != args.size())
|
||||
log_cmd_error("Invalid number of arguments.\n");
|
||||
|
||||
worker.gold_mod = design->module(TwineSearch(&design->twines).find(RTLIL::escape_id(args[argidx])));
|
||||
worker.gate_mod = design->module(TwineSearch(&design->twines).find(RTLIL::escape_id(args[argidx+1])));
|
||||
worker.equiv_mod = design->module(TwineSearch(&design->twines).find(RTLIL::escape_id(args[argidx+2])));
|
||||
TwineSearch search(&design->twines);
|
||||
worker.gold_mod = design->module(search.find(RTLIL::escape_id(args[argidx])));
|
||||
worker.gate_mod = design->module(search.find(RTLIL::escape_id(args[argidx+1])));
|
||||
worker.equiv_mod = design->module(search.find(RTLIL::escape_id(args[argidx+2])));
|
||||
|
||||
if (worker.gold_mod == nullptr)
|
||||
log_cmd_error("Can't find gold module %s.\n", args[argidx]);
|
||||
|
|
|
|||
|
|
@ -156,17 +156,20 @@ struct EquivMiterWorker
|
|||
|
||||
struct RewriteSigSpecWorker {
|
||||
RTLIL::Module * mod;
|
||||
TwineSearch *search;
|
||||
void operator()(SigSpec &sig) {
|
||||
vector<SigChunk> chunks = sig.chunks();
|
||||
for (auto &c : chunks)
|
||||
if (c.wire != NULL)
|
||||
c.wire = mod->wire(TwineSearch(&mod->design->twines).find(c.wire->name.str()));
|
||||
c.wire = mod->wire(search->find(c.wire->name.str()));
|
||||
sig = chunks;
|
||||
}
|
||||
};
|
||||
|
||||
RewriteSigSpecWorker rewriteSigSpecWorker;
|
||||
TwineSearch rewrite_search(&miter_module->design->twines);
|
||||
rewriteSigSpecWorker.mod = miter_module;
|
||||
rewriteSigSpecWorker.search = &rewrite_search;
|
||||
miter_module->rewrite_sigspecs(rewriteSigSpecWorker);
|
||||
|
||||
// find undriven or unused wires
|
||||
|
|
|
|||
|
|
@ -48,46 +48,61 @@ struct module_ptr_compare {
|
|||
}
|
||||
};
|
||||
|
||||
IdString concat_name(RTLIL::Cell *cell, IdString const &object_name, const std::string &separator = ".")
|
||||
// Split an object's escaped name into the shared per-instance prefix and the
|
||||
// remaining tail; prefix + tail is the flattened escaped name. flatten_cell
|
||||
// interns the prefix once and shares it via a Suffix node (like techmap's
|
||||
// apply_prefix_ref) instead of storing a full leaf string per object.
|
||||
std::pair<std::string, std::string> hier_name_parts(RTLIL::Cell *cell, std::string_view object_name_view, const std::string &separator)
|
||||
{
|
||||
std::string_view object_name_view(object_name.c_str());
|
||||
if (object_name_view[0] == '\\'){
|
||||
return concat_views(cell->name.str(), separator, object_name_view.substr(1));
|
||||
}
|
||||
if (!object_name_view.empty() && object_name_view[0] == '\\')
|
||||
return {cell->name.str() + separator, std::string(object_name_view.substr(1))};
|
||||
|
||||
constexpr std::string_view prefix = "$flatten";
|
||||
if (object_name_view.substr(0, prefix.size()) == prefix){
|
||||
if (object_name_view.substr(0, prefix.size()) == prefix)
|
||||
object_name_view.remove_prefix(prefix.size());
|
||||
}
|
||||
return concat_views(prefix, cell->name.str(), separator, object_name_view);
|
||||
return {"$flatten" + cell->name.str() + separator, std::string(object_name_view)};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TwineRef map_name(RTLIL::Cell *cell, T *object, const std::string &separator = ".")
|
||||
std::string concat_name(RTLIL::Cell *cell, std::string_view object_name_view, const std::string &separator = ".")
|
||||
{
|
||||
return cell->module->uniquify(cell->module->design->twines.add(Twine{concat_name(cell, object->name, separator).str()}));
|
||||
auto [prefix, tail] = hier_name_parts(cell, object_name_view, separator);
|
||||
return prefix + tail;
|
||||
}
|
||||
|
||||
// Specialization for Memory
|
||||
template<>
|
||||
TwineRef map_name<RTLIL::Memory>(RTLIL::Cell *cell, RTLIL::Memory *object, const std::string &separator)
|
||||
// Build the flattened name of a template object, given the instance's already
|
||||
// interned public/private prefix leaves. A name like "\a.b.c.w" is stored as
|
||||
// nested Suffix nodes Suffix{Suffix{Suffix{"\a.", "b."}, "c."}, "w"}. When the
|
||||
// template was itself flattened earlier its names are already such Suffixes, so
|
||||
// flattening instance "u" re-prefixes only the innermost leaf ("\a." -> "\u.a.")
|
||||
// and reuses the rest, yielding "\u.a.b.c.w" while keeping "b.", "c.", "w"
|
||||
// shared -- rather than materialising "a.b.c.w" as one fresh tail per object.
|
||||
TwineRef remap_flattened_name(RTLIL::Design *design, TwineRef obj_ref,
|
||||
TwineRef pub_prefix_ref, TwineRef priv_prefix_ref, dict<TwineRef, TwineRef> &memo)
|
||||
{
|
||||
auto design = cell->module->design;
|
||||
std::string obj_name(design->twines.str(object->meta_->name));
|
||||
IdString obj_name_id(obj_name);
|
||||
std::string mapped_name = concat_name(cell, obj_name_id, separator).str();
|
||||
return cell->module->uniquify(design->twines.add(Twine{mapped_name}));
|
||||
}
|
||||
if (auto it = memo.find(obj_ref); it != memo.end())
|
||||
return it->second;
|
||||
|
||||
// Specialization for Process
|
||||
template<>
|
||||
TwineRef map_name<RTLIL::Process>(RTLIL::Cell *cell, RTLIL::Process *object, const std::string &separator)
|
||||
{
|
||||
auto design = cell->module->design;
|
||||
std::string obj_name(design->twines.str(object->meta_->name));
|
||||
IdString obj_name_id(obj_name);
|
||||
std::string mapped_name = concat_name(cell, obj_name_id, separator).str();
|
||||
return cell->module->uniquify(design->twines.add(Twine{mapped_name}));
|
||||
const Twine &node = design->twines[obj_ref];
|
||||
TwineRef result;
|
||||
if (node.is_suffix()) {
|
||||
const Twine::Suffix &sfx = node.suffix();
|
||||
TwineRef prefix = remap_flattened_name(design, twine_tag(sfx.prefix, obj_ref.is_public()),
|
||||
pub_prefix_ref, priv_prefix_ref, memo);
|
||||
result = design->twines.add(Twine{Twine::Suffix{prefix, sfx.tail}});
|
||||
} else {
|
||||
std::string escaped = design->twines.str(obj_ref);
|
||||
std::string_view obj = escaped;
|
||||
if (!obj.empty() && obj[0] == '\\') {
|
||||
result = design->twines.add(Twine{Twine::Suffix{pub_prefix_ref, std::string(obj.substr(1))}});
|
||||
} else {
|
||||
constexpr std::string_view flatten_prefix = "$flatten";
|
||||
if (obj.substr(0, flatten_prefix.size()) == flatten_prefix)
|
||||
obj.remove_prefix(flatten_prefix.size());
|
||||
result = design->twines.add(Twine{Twine::Suffix{priv_prefix_ref, std::string(obj)}});
|
||||
}
|
||||
}
|
||||
memo[obj_ref] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
void map_sigspec(const dict<RTLIL::Wire*, RTLIL::Wire*> &map, RTLIL::SigSpec &sig, RTLIL::Module *into = nullptr)
|
||||
|
|
@ -152,15 +167,22 @@ struct FlattenWorker
|
|||
}
|
||||
}
|
||||
|
||||
void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, SigMap &sigmap, std::vector<RTLIL::Cell*> &new_cells, const std::string &separator)
|
||||
void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, SigMap &sigmap, std::vector<RTLIL::Cell*> &new_cells, const std::string &separator, const dict<std::string, RTLIL::Wire*> &hier_wires)
|
||||
{
|
||||
// Copy the contents of the flattened cell
|
||||
|
||||
dict<TwineRef, TwineRef> memory_map;
|
||||
TwineRef pub_prefix_ref = design->twines.add(cell->name.str() + separator);
|
||||
TwineRef priv_prefix_ref = design->twines.add("$flatten" + cell->name.str() + separator);
|
||||
dict<TwineRef, TwineRef> remap_memo;
|
||||
auto make_name = [&](TwineRef obj_ref) -> TwineRef {
|
||||
return module->uniquify(remap_flattened_name(design, obj_ref, pub_prefix_ref, priv_prefix_ref, remap_memo));
|
||||
};
|
||||
|
||||
dict<std::string, TwineRef> memory_map;
|
||||
for (auto &tpl_memory_it : tpl->memories) {
|
||||
RTLIL::Memory *new_memory = module->addMemory(map_name(cell, tpl_memory_it.second, separator), tpl_memory_it.second);
|
||||
RTLIL::Memory *new_memory = module->addMemory(make_name(tpl_memory_it.second->meta_->name), tpl_memory_it.second);
|
||||
map_attributes(cell, new_memory, design->twines.str(tpl_memory_it.second->meta_->name));
|
||||
memory_map[tpl_memory_it.first] = new_memory->meta_->name;
|
||||
memory_map[design->twines.str(tpl_memory_it.first)] = new_memory->meta_->name;
|
||||
design->select(module, new_memory);
|
||||
}
|
||||
|
||||
|
|
@ -172,8 +194,9 @@ struct FlattenWorker
|
|||
|
||||
RTLIL::Wire *new_wire = nullptr;
|
||||
if (tpl_wire->name[0] == '\\') {
|
||||
std::string wire_name = concat_name(cell, tpl_wire->name, separator).str();
|
||||
RTLIL::Wire *hier_wire = module->wire(TwineSearch(&design->twines).find(wire_name));
|
||||
std::string wire_name = concat_name(cell, tpl_wire->name.str(), separator);
|
||||
auto hwit = hier_wires.find(wire_name);
|
||||
RTLIL::Wire *hier_wire = (hwit != hier_wires.end()) ? hwit->second : nullptr;
|
||||
if (hier_wire != nullptr && hier_wire->get_bool_attribute(ID::hierconn)) {
|
||||
hier_wire->attributes.erase(ID::hierconn);
|
||||
if (GetSize(hier_wire) < GetSize(tpl_wire)) {
|
||||
|
|
@ -185,7 +208,7 @@ struct FlattenWorker
|
|||
}
|
||||
}
|
||||
if (new_wire == nullptr) {
|
||||
new_wire = module->addWire(map_name(cell, tpl_wire, separator), tpl_wire);
|
||||
new_wire = module->addWire(make_name(tpl_wire->name.ref()), tpl_wire);
|
||||
new_wire->port_input = new_wire->port_output = false;
|
||||
new_wire->port_id = false;
|
||||
}
|
||||
|
|
@ -196,12 +219,11 @@ struct FlattenWorker
|
|||
}
|
||||
|
||||
for (auto &tpl_proc_it : tpl->processes) {
|
||||
RTLIL::Process *new_proc = module->addProcess(map_name(cell, tpl_proc_it.second, separator), tpl_proc_it.second);
|
||||
RTLIL::Process *new_proc = module->addProcess(make_name(tpl_proc_it.second->meta_->name), tpl_proc_it.second);
|
||||
map_attributes(cell, new_proc, design->twines.str(tpl_proc_it.second->meta_->name));
|
||||
for (auto new_proc_sync : new_proc->syncs)
|
||||
for (auto &memwr_action : new_proc_sync->mem_write_actions) {
|
||||
TwineRef old_memid_ref = TwineSearch(&design->twines).find(memwr_action.memid.str());
|
||||
memwr_action.memid = design->twines.str(memory_map.at(old_memid_ref));
|
||||
memwr_action.memid = design->twines.str(memory_map.at(memwr_action.memid.str()));
|
||||
}
|
||||
auto rewriter = [&](RTLIL::SigSpec &sig) { map_sigspec(wire_map, sig); };
|
||||
new_proc->rewrite_sigspecs(rewriter);
|
||||
|
|
@ -211,15 +233,14 @@ struct FlattenWorker
|
|||
for (auto tpl_cell : tpl->cells()) {
|
||||
if (tpl_cell->type.in(TW($input_port), TW($output_port), TW($public)))
|
||||
continue;
|
||||
RTLIL::Cell *new_cell = module->addCell(map_name(cell, tpl_cell, separator), tpl_cell);
|
||||
RTLIL::Cell *new_cell = module->addCell(make_name(tpl_cell->name.ref()), tpl_cell);
|
||||
map_attributes(cell, new_cell, tpl_cell->name);
|
||||
if (new_cell->has_memid()) {
|
||||
IdString memid = new_cell->getParam(ID::MEMID).decode_string();
|
||||
TwineRef memid_ref = TwineSearch(&design->twines).find(memid.str());
|
||||
new_cell->setParam(ID::MEMID, Const(design->twines.str(memory_map.at(memid_ref))));
|
||||
new_cell->setParam(ID::MEMID, Const(design->twines.str(memory_map.at(memid.str()))));
|
||||
} else if (new_cell->is_mem_cell()) {
|
||||
IdString memid = new_cell->getParam(ID::MEMID).decode_string();
|
||||
new_cell->setParam(ID::MEMID, Const(concat_name(cell, memid, separator).str()));
|
||||
new_cell->setParam(ID::MEMID, Const(concat_name(cell, memid.str(), separator)));
|
||||
}
|
||||
auto rewriter = [&](RTLIL::SigSpec &sig) { map_sigspec(wire_map, sig); };
|
||||
new_cell->rewrite_sigspecs(rewriter);
|
||||
|
|
@ -319,7 +340,6 @@ struct FlattenWorker
|
|||
scopeinfo->attributes.emplace(stringf("\\cell_%s", RTLIL::unescape_id(attr.first).c_str()), 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()));
|
||||
|
|
@ -335,7 +355,7 @@ struct FlattenWorker
|
|||
module->remove(cell);
|
||||
|
||||
if (scopeinfo != nullptr)
|
||||
module->rename(scopeinfo, design->twines.add(Twine{cell_name.str()}));
|
||||
module->rename(scopeinfo, design->twines.add(cell_name.str()));
|
||||
}
|
||||
|
||||
void flatten_module(RTLIL::Design *design, RTLIL::Module *module, pool<RTLIL::Module*> &used_modules, const std::string &separator)
|
||||
|
|
@ -344,6 +364,15 @@ struct FlattenWorker
|
|||
return;
|
||||
|
||||
SigMap sigmap(module);
|
||||
|
||||
// hierconn wires are connection points pre-created in `module`; flatten
|
||||
// reuses them by hierarchical name. Index them once instead of doing a
|
||||
// pool-wide content search per template wire.
|
||||
dict<std::string, RTLIL::Wire*> hier_wires;
|
||||
for (auto wire : module->wires())
|
||||
if (wire->get_bool_attribute(ID::hierconn))
|
||||
hier_wires[wire->name.str()] = wire;
|
||||
|
||||
std::vector<RTLIL::Cell*> worklist = module->selected_cells();
|
||||
while (!worklist.empty())
|
||||
{
|
||||
|
|
@ -368,7 +397,7 @@ struct FlattenWorker
|
|||
// If a design is fully selected and has a top module defined, topological sorting ensures that all cells
|
||||
// added during flattening are black boxes, and flattening is finished in one pass. However, when flattening
|
||||
// individual modules, this isn't the case, and the newly added cells might have to be flattened further.
|
||||
flatten_cell(design, module, cell, tpl, sigmap, worklist, separator);
|
||||
flatten_cell(design, module, cell, tpl, sigmap, worklist, separator, hier_wires);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ struct MemoryMapWorker
|
|||
std::set<int> static_ports;
|
||||
std::map<int, RTLIL::SigSpec> static_cells_map;
|
||||
|
||||
// "@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.
|
||||
|
|
|
|||
|
|
@ -406,7 +406,6 @@ struct OptMergePass : public Pass {
|
|||
ct.cell_types.erase(TW($anyconst));
|
||||
ct.cell_types.erase(TW($allseq));
|
||||
ct.cell_types.erase(TW($allconst));
|
||||
// Synthetic driver cells signorm creates for module ports — must
|
||||
// never be folded into one another, otherwise distinct ports collapse.
|
||||
ct.cell_types.erase(TW($input_port));
|
||||
ct.cell_types.erase(TW($output_port));
|
||||
|
|
|
|||
|
|
@ -461,7 +461,6 @@ 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::unused_bits);
|
||||
return count;
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ struct SimInstance
|
|||
Module *mod = module->design->module(cell->type_impl);
|
||||
|
||||
if (mod != nullptr) {
|
||||
dirty_children.insert(new SimInstance(shared, scope + "." + cell->module->design->twines.str(cell->meta_->name), mod, cell, this));
|
||||
dirty_children.insert(new SimInstance(shared, scope + "." + cell->module->design->twines.unescaped_str(cell->meta_->name), mod, cell, this));
|
||||
}
|
||||
|
||||
for (auto &port : cell->connections()) {
|
||||
|
|
|
|||
|
|
@ -294,14 +294,17 @@ RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit:
|
|||
auto &tw = needle->design->twines;
|
||||
|
||||
// create new cell
|
||||
RTLIL::Cell *cell = haystack->addCell(Twine{stringf("$extract$%s$%d", needle->name, autoidx++)}, Twine{needle->name.str()});
|
||||
RTLIL::Cell *cell = haystack->addCell(haystack->design->twines.add(stringf("$extract$%s$%d", needle->name, autoidx++)), haystack->design->twines.add(needle->name.str()));
|
||||
|
||||
// create cell ports
|
||||
// create cell ports. Port names come from the needle (map) pool; translate
|
||||
// them into the haystack pool so the new cell's ports are keyed by the same
|
||||
// refs as the referenced module in the haystack design.
|
||||
for (auto wire : needle->wires()) {
|
||||
if (wire->port_id > 0) {
|
||||
TwineRef portname = haystack->design->twines.add(tw.str(wire->meta_->name));
|
||||
for (int i = 0; i < wire->width; i++)
|
||||
sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<TwineRef, int>(wire->meta_->name, i));
|
||||
cell->setPort(wire->meta_->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width));
|
||||
sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<TwineRef, int>(portname, i));
|
||||
cell->setPort(portname, RTLIL::SigSpec(RTLIL::State::Sz, wire->width));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -628,7 +631,7 @@ struct ExtractPass : public Pass {
|
|||
if (!mine_mode)
|
||||
for (auto module : map->modules()) {
|
||||
SubCircuit::Graph mod_graph;
|
||||
std::string graph_name = "needle_" + design->twines.unescaped_str(module->name);
|
||||
std::string graph_name = "needle_" + map->twines.unescaped_str(module->name);
|
||||
log("Creating needle graph %s.\n", graph_name);
|
||||
if (module2graph(mod_graph, module, constports)) {
|
||||
solver.addGraph(graph_name, mod_graph);
|
||||
|
|
@ -656,8 +659,8 @@ struct ExtractPass : public Pass {
|
|||
|
||||
for (auto needle : needle_list)
|
||||
for (auto &haystack_it : haystack_map) {
|
||||
log("Solving for %s in %s.\n", ("needle_" + design->twines.unescaped_str(needle->name)), haystack_it.first);
|
||||
solver.solve(results, "needle_" + design->twines.unescaped_str(needle->name), haystack_it.first, false);
|
||||
log("Solving for %s in %s.\n", ("needle_" + map->twines.unescaped_str(needle->name)), haystack_it.first);
|
||||
solver.solve(results, "needle_" + map->twines.unescaped_str(needle->name), haystack_it.first, false);
|
||||
}
|
||||
log("Found %d matches.\n", GetSize(results));
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ struct MuxcoverWorker
|
|||
return true;
|
||||
}
|
||||
char port_name[3] = {'\\', *path, 0};
|
||||
return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(tree.muxes.at(bit)->module->design->twines.add(Twine{std::string(port_name)}))), path+1, false);
|
||||
return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(tree.muxes.at(bit)->module->design->twines.add(std::string(port_name)))), path+1, false);
|
||||
} else {
|
||||
ret_bit = bit;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -535,7 +535,6 @@ struct TechmapWorker
|
|||
extmapper_module = extmapper_design->addModule(extmapper_design->twines.add(std::string{m_name}));
|
||||
RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type.ref(), cell);
|
||||
// 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;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ 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());
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ import gen_tests_makefile
|
|||
|
||||
gen_tests_makefile.generate_autotest("*.v", "",
|
||||
"""if grep -Eq 'expect-(wr-ports|rd-ports|rd-clk)' $@; then \\
|
||||
$(YOSYS) -f verilog -qp "proc; opt; memory -nomap; dump -outfile $(@:.v=).dmp t:\\$$mem_v2" $@; \\
|
||||
$(YOSYS) -f verilog -qp "proc; opt; memory -nomap; dump -readable -outfile $(@:.v=).dmp t:\\$$mem_v2" $@; \\
|
||||
python3 validate.py $@ $(@:.v=).dmp; \\
|
||||
fi""")
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
autoidx 1
|
||||
twines
|
||||
leaf 0 "/home/emil/repo/"
|
||||
suffix 1 0 "foo/"
|
||||
suffix 2 1 "bar.v"
|
||||
suffix 3 2 ":10.1-10.5"
|
||||
suffix 4 2 ":11.1-11.5"
|
||||
leaf 1009 "/home/emil/repo/"
|
||||
suffix 1010 1009 "foo/"
|
||||
suffix 1011 1010 "bar.v"
|
||||
suffix 1012 1011 ":10.1-10.5"
|
||||
suffix 1013 1011 ":11.1-11.5"
|
||||
end
|
||||
module \chain
|
||||
attribute \src "@3"
|
||||
attribute \src "@1012" # /home/emil/repo/foo/bar.v:10.1-10.5
|
||||
wire input 1 \a
|
||||
attribute \src "@4"
|
||||
attribute \src "@1013" # /home/emil/repo/foo/bar.v:11.1-11.5
|
||||
wire output 2 \b
|
||||
connect \b \a
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
autoidx 1
|
||||
twines
|
||||
leaf 0 "everything.v"
|
||||
suffix 1 0 ":1.1-1.10"
|
||||
suffix 2 0 ":2.5-2.8"
|
||||
concat 3 1 2
|
||||
leaf 1009 "everything.v"
|
||||
suffix 1010 1009 ":1.1-1.10"
|
||||
suffix 1011 1009 ":2.5-2.8"
|
||||
concat 1012 1010 1011
|
||||
leaf 1013 "tiny"
|
||||
end
|
||||
attribute \src "@3"
|
||||
module \tiny
|
||||
attribute \src "@1"
|
||||
attribute \src "@1012" # everything.v:1.1-1.10|everything.v:2.5-2.8
|
||||
module $pub@1013 # \tiny
|
||||
attribute \src "@1010" # everything.v:1.1-1.10
|
||||
wire input 1 \a
|
||||
attribute \src "@2"
|
||||
attribute \src "@1011" # everything.v:2.5-2.8
|
||||
wire output 2 \b
|
||||
connect \b \a
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue