hierarchy: Resolve SV wildcard port connections
authorDavid Shah <dave@ds0.me>
Fri, 22 Nov 2019 09:04:54 +0000 (09:04 +0000)
committerDavid Shah <dave@ds0.me>
Sun, 2 Feb 2020 16:12:33 +0000 (16:12 +0000)
Signed-off-by: David Shah <dave@ds0.me>
frontends/verilog/verilog_parser.y
passes/hierarchy/hierarchy.cc

index cb413e13af100ea0880d7c41ef3513a9c426f2c5..5ec8e66a6e624c435df5764187c94cc84fa5f0a5 100644 (file)
@@ -1582,7 +1582,7 @@ cell_port:
                free_attr($1);
        } |
        attr TOK_AUTOCONNECT_ALL {
-               astbuf2->attributes[ID(autoconnect)] = AstNode::mkconst_int(1, false);
+               astbuf2->attributes[ID(implicit_port_conns)] = AstNode::mkconst_int(1, false);
        };
 
 always_comb_or_latch:
index d8a628448ffcabd0166300489cb021b4e6b986cd..0704c26512efbae2c18c58a4fba14946ba62ca76 100644 (file)
@@ -548,6 +548,19 @@ RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod)
        return NULL;
 }
 
+// Find a matching wire for an implicit port connection; traversing generate block scope
+RTLIL::Wire *find_implicit_port_wire(Module *module, Cell *cell, const std::string& port)
+{
+       const std::string &cellname = cell->name.str();
+       size_t idx = cellname.size();
+       while ((idx = cellname.find_last_of('.', idx-1)) != std::string::npos) {
+               Wire *found = module->wire(cellname.substr(0, idx+1) + port.substr(1));
+               if (found != nullptr)
+                       return found;
+       }
+       return module->wire(port);
+}
+
 struct HierarchyPass : public Pass {
        HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
        void help() YS_OVERRIDE
@@ -970,6 +983,55 @@ struct HierarchyPass : public Pass {
                        }
                }
 
+               // Process SV implicit port connections
+               std::set<Module*> blackbox_derivatives;
+               std::vector<Module*> design_modules = design->modules();
+
+               for (auto module : design_modules)
+               {
+                       for (auto cell : module->cells())
+                       {
+                               if (!cell->get_bool_attribute(ID(implicit_port_conns)))
+                                       continue;
+                               Module *m = design->module(cell->type);
+
+                               if (m == nullptr)
+                                       log_error("Cell %s.%s (%s) has implicit port connections but the module it instantiates is unknown.\n",
+                                                       RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
+
+                               // Need accurate port widths for error checking; so must derive blackboxes with dynamic port widths
+                               if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
+                                       IdString new_m_name = m->derive(design, cell->parameters, true);
+                                       if (new_m_name.empty())
+                                               continue;
+                                       if (new_m_name != m->name) {
+                                               m = design->module(new_m_name);
+                                               blackbox_derivatives.insert(m);
+                                       }
+                               }
+
+                               auto old_connections = cell->connections();
+                               for (auto wire : m->wires()) {
+                                       // Find ports of the module that aren't explicitly connected
+                                       if (!wire->port_input && !wire->port_output)
+                                               continue;
+                                       if (old_connections.count(wire->name))
+                                               continue;
+                                       // Make sure a wire of correct name exists in the parent
+                                       Wire* parent_wire = find_implicit_port_wire(module, cell, wire->name.str());
+                                       if (parent_wire == nullptr)
+                                               log_error("No matching wire for implicit port connection `%s' of cell %s.%s (%s).\n",
+                                                               RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
+                                       if (parent_wire->width != wire->width)
+                                               log_error("Width mismatch between wire (%d bits) and port (%d bits) for implicit port connection `%s' of cell %s.%s (%s).\n",
+                                                               parent_wire->width, wire->width,
+                                                               RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
+                                       cell->setPort(wire->name, parent_wire);
+                               }
+                               cell->attributes.erase(ID(implicit_port_conns));
+                       }
+               }
+
                if (!nodefaults)
                {
                        dict<IdString, dict<IdString, Const>> defaults_db;
@@ -1000,9 +1062,6 @@ struct HierarchyPass : public Pass {
                                }
                }
 
-               std::set<Module*> blackbox_derivatives;
-               std::vector<Module*> design_modules = design->modules();
-
                for (auto module : design_modules)
                {
                        pool<Wire*> wand_wor_index;