flatten: preserve original object names via hdlname attribute.
authorwhitequark <whitequark@whitequark.org>
Thu, 4 Jun 2020 10:46:54 +0000 (10:46 +0000)
committerwhitequark <whitequark@whitequark.org>
Mon, 8 Jun 2020 20:19:41 +0000 (20:19 +0000)
README.md
kernel/rtlil.cc
kernel/rtlil.h
manual/CHAPTER_Overview.tex
passes/techmap/flatten.cc

index 770c624591bd045d582f12ed5ca2819c79bfdddc..203a292d1b903588863d79dc127eac8415ca5ab8 100644 (file)
--- a/README.md
+++ b/README.md
@@ -309,7 +309,9 @@ Verilog Attributes and non-standard features
   that have ports with a width that depends on a parameter.
 
 - The ``hdlname`` attribute is used by some passes to document the original
-  (HDL) name of a module when renaming a module.
+  (HDL) name of a module when renaming a module. It should contain a single
+  name, or, when describing a hierarchical name in a flattened design, multiple
+  names separated by a single space character.
 
 - The ``keep`` attribute on cells and wires is used to mark objects that should
   never be removed by the optimizer. This is used for example for cells that
index 335c484566c79218143aa66f87382a31a92e307e..b876862c823a93b91a4cba01faa91133819146eb 100644 (file)
@@ -339,6 +339,22 @@ pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const
        return data;
 }
 
+void RTLIL::AttrObject::set_hdlname_attribute(const vector<string> &hierarchy)
+{
+       string attrval;
+       for (const auto &ident : hierarchy) {
+               if (!attrval.empty())
+                       attrval += " ";
+               attrval += ident;
+       }
+       set_string_attribute(ID::hdlname, attrval);
+}
+
+vector<string> RTLIL::AttrObject::get_hdlname_attribute() const
+{
+       return split_tokens(get_string_attribute(ID::hdlname), " ");
+}
+
 bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
 {
        if (full_selection)
index 86b4e25b6bfe5d0353b2af6b76c59948d6893a64..f751bdce4f9f8448d7d13ef82b2d2b3b6c4046ee 100644 (file)
@@ -682,6 +682,9 @@ struct RTLIL::AttrObject
        std::string get_src_attribute() const {
                return get_string_attribute(ID::src);
        }
+
+       void set_hdlname_attribute(const vector<string> &hierarchy);
+       vector<string> get_hdlname_attribute() const;
 };
 
 struct RTLIL::SigChunk
index ac0f48e47aa9664a44c4ddb29164758261afd2f2..83cfa5cc46092a380a66567d40475e6d25a6b0af 100644 (file)
@@ -193,6 +193,13 @@ Violating these rules results in a runtime error.
 
 All RTLIL identifiers are case sensitive.
 
+Some transformations, such as flattening, may have to change identifiers provided by the user
+to avoid name collisions. When that happens, attribute ``{\tt hdlname}`` is attached to the object
+with the changed identifier. This attribute contains one name (if emitted directly by the frontend,
+or is a result of disambiguation) or multiple names separated by spaces (if a result of flattening).
+All names specified in the ``{\tt hdlname}`` attribute are public and do not include the leading
+``\textbackslash``.
+
 \subsection{RTLIL::Design and RTLIL::Module}
 
 The RTLIL::Design object is basically just a container for RTLIL::Module objects. In addition to
index e913b3059611b8e7a29ddca9d5d0fb091e121843..a2794541a05b2e5a08a505dc2b0ce6e038564bf8 100644 (file)
@@ -47,10 +47,21 @@ IdString map_name(RTLIL::Cell *cell, T *object)
 }
 
 template<class T>
-void map_attributes(RTLIL::Cell *cell, T *object)
+void map_attributes(RTLIL::Cell *cell, T *object, IdString orig_object_name)
 {
-       if (object->attributes.count(ID::src))
+       if (object->has_attribute(ID::src))
                object->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+
+       // Preserve original names via the hdlname attribute, but only for objects with a fully public name.
+       if (cell->name[0] == '\\' && (object->has_attribute(ID::hdlname) || orig_object_name[0] == '\\')) {
+               std::vector<std::string> hierarchy;
+               if (object->has_attribute(ID::hdlname))
+                       hierarchy = object->get_hdlname_attribute();
+               else
+                       hierarchy.push_back(orig_object_name.str().substr(1));
+               hierarchy.insert(hierarchy.begin(), cell->name.str().substr(1));
+               object->set_hdlname_attribute(hierarchy);
+       }
 }
 
 void map_sigspec(const dict<RTLIL::Wire*, RTLIL::Wire*> &map, RTLIL::SigSpec &sig, RTLIL::Module *into = nullptr)
@@ -81,7 +92,7 @@ struct FlattenWorker
                dict<IdString, IdString> memory_map;
                for (auto &tpl_memory_it : tpl->memories) {
                        RTLIL::Memory *new_memory = module->addMemory(map_name(cell, tpl_memory_it.second), tpl_memory_it.second);
-                       map_attributes(cell, new_memory);
+                       map_attributes(cell, new_memory, tpl_memory_it.second->name);
                        memory_map[tpl_memory_it.first] = new_memory->name;
                        design->select(module, new_memory);
                }
@@ -111,14 +122,14 @@ struct FlattenWorker
                                new_wire->port_id = false;
                        }
 
-                       map_attributes(cell, new_wire);
+                       map_attributes(cell, new_wire, tpl_wire->name);
                        wire_map[tpl_wire] = new_wire;
                        design->select(module, new_wire);
                }
 
                for (auto tpl_cell : tpl->cells()) {
                        RTLIL::Cell *new_cell = module->addCell(map_name(cell, tpl_cell), tpl_cell);
-                       map_attributes(cell, new_cell);
+                       map_attributes(cell, new_cell, tpl_cell->name);
                        if (new_cell->type.in(ID($memrd), ID($memwr), ID($meminit))) {
                                IdString memid = new_cell->getParam(ID::MEMID).decode_string();
                                new_cell->setParam(ID::MEMID, Const(memory_map.at(memid).str()));