From: Rupert Swarbrick Date: Tue, 26 May 2020 16:46:10 +0000 (+0100) Subject: Move interface expansion in hierarchy.cc into a helper class X-Git-Tag: yosys-0.10~130 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e2c9580024563be385ac9e892a978be3384990a8;p=yosys.git Move interface expansion in hierarchy.cc into a helper class There should be no functional change, but this splits up the control flow across functions, using class fields to hold the state that's being tracked. The result should be a bit easier to read. This is part of work to add bind support, but I'm doing some refactoring in the hierarchy pass to make the code a bit easier to work with. The idea is that (eventually) the IFExpander object will hold all the logic for expanding interfaces, and then other code can do bind insertion. --- diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 2ea0d4061..dadae04a4 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -156,6 +156,168 @@ std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) { return basicType; } +// A helper struct for expanding a module's interface connections in expand_module +struct IFExpander +{ + IFExpander (RTLIL::Design &design, RTLIL::Module &m) + : module(m), has_interfaces_not_found(false) + { + // Keep track of all derived interfaces available in the current + // module in 'interfaces_in_module': + for (auto cell : module.cells()) { + if(!cell->get_bool_attribute(ID::is_interface)) + continue; + + interfaces_in_module[cell->name] = design.module(cell->type); + } + } + + RTLIL::Module &module; + dict interfaces_in_module; + + bool has_interfaces_not_found; + std::vector connections_to_remove; + std::vector connections_to_add_name; + std::vector connections_to_add_signal; + dict interfaces_to_add_to_submodule; + dict modports_used_in_submodule; + + // Reset the per-cell state + void start_cell() + { + has_interfaces_not_found = false; + connections_to_remove.clear(); + connections_to_add_name.clear(); + connections_to_add_signal.clear(); + interfaces_to_add_to_submodule.clear(); + modports_used_in_submodule.clear(); + } + + // Set has_interfaces_not_found if there are pending interfaces that + // haven't been found yet (and might be found in the future). Print a + // warning if we've already gone over all the cells in the module. + void on_missing_interface(RTLIL::IdString interface_name) + { + // If there are cells that haven't yet been processed, maybe + // we'll find this interface in the future. + if (module.get_bool_attribute(ID::cells_not_processed)) { + has_interfaces_not_found = true; + return; + } + + // Otherwise, we have already gone over all cells in this + // module and the interface has still not been found. Warn + // about it and don't set has_interfaces_not_found (to avoid a + // loop). + log_warning("Could not find interface instance for `%s' in `%s'\n", + log_id(interface_name), log_id(&module)); + } + + // Handle an interface connection from the module + void on_interface(RTLIL::Module &submodule, + RTLIL::IdString conn_name, + const RTLIL::SigSpec &conn_signals) + { + // Check if the connected wire is a potential interface in the parent module + std::string interface_name_str = conn_signals.bits()[0].wire->name.str(); + // Strip the prefix '$dummywireforinterface' from the dummy wire to get the name + interface_name_str.replace(0,23,""); + interface_name_str = "\\" + interface_name_str; + RTLIL::IdString interface_name = interface_name_str; + + // If 'interfaces' in the cell have not be been handled yet, we aren't + // ready to derive the sub-module either + if (!module.get_bool_attribute(ID::interfaces_replaced_in_module)) { + on_missing_interface(interface_name); + return; + } + + // Check if the interface instance is present in module. Interface + // instances may either have the plain name or the name appended with + // '_inst_from_top_dummy'. Check for both of them here + int nexactmatch = interfaces_in_module.count(interface_name) > 0; + std::string interface_name_str2 = interface_name_str + "_inst_from_top_dummy"; + RTLIL::IdString interface_name2 = interface_name_str2; + int nmatch2 = interfaces_in_module.count(interface_name2) > 0; + + // If we can't find either name, this is a missing interface. + if (! (nexactmatch || nmatch2)) { + on_missing_interface(interface_name); + return; + } + + if (nexactmatch != 0) // Choose the one with the plain name if it exists + interface_name2 = interface_name; + + RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name2); + + // Go over all wires in interface, and add replacements to lists. + for (auto mod_wire : mod_replace_ports->wires()) { + std::string signal_name1 = conn_name.str() + "." + log_id(mod_wire->name); + std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire); + connections_to_add_name.push_back(RTLIL::IdString(signal_name1)); + if(module.wire(signal_name2) == nullptr) { + log_error("Could not find signal '%s' in '%s'\n", + signal_name2.c_str(), log_id(module.name)); + } + else { + RTLIL::Wire *wire_in_parent = module.wire(signal_name2); + connections_to_add_signal.push_back(wire_in_parent); + } + } + connections_to_remove.push_back(conn_name); + interfaces_to_add_to_submodule[conn_name] = interfaces_in_module.at(interface_name2); + + // Find if the sub-module has set a modport for the current interface + // connection. Add any modports to a dict which will be passed to + // AstModule::derive + string modport_name = submodule.wire(conn_name)->get_string_attribute(ID::interface_modport); + if (!modport_name.empty()) { + modports_used_in_submodule[conn_name] = "\\" + modport_name; + } + } + + // Handle a single connection from the module, making a note to expand + // it if it's an interface connection. + void on_connection(RTLIL::Module &submodule, + RTLIL::IdString conn_name, + const RTLIL::SigSpec &conn_signals) + { + // Check if the connection is present as an interface in the sub-module's port list + const RTLIL::Wire *wire = submodule.wire(conn_name); + if (!wire || !wire->get_bool_attribute(ID::is_interface)) + return; + + // If the connection looks like an interface, handle it. + const auto &bits = conn_signals.bits(); + if (bits.size() == 1 && bits[0].wire->get_bool_attribute(ID::is_interface)) + on_interface(submodule, conn_name, conn_signals); + } + + // Iterate over the connections in a cell, tracking any interface + // connections + void visit_connections(const RTLIL::Cell &cell, + RTLIL::Module &submodule) + { + for (const auto &conn : cell.connections()) { + on_connection(submodule, conn.first, conn.second); + } + } + + // Add/remove connections to the cell as necessary, replacing any SV + // interface port connection with the individual signal connections. + void rewrite_interface_connections(RTLIL::Cell &cell) const + { + for(unsigned int i=0;i &libdirs) { bool did_something = false; @@ -173,23 +335,11 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } } - // Always keep track of all derived interfaces available in the current module in 'interfaces_in_module': - dict interfaces_in_module; - for (auto cell : module->cells()) - { - if(cell->get_bool_attribute(ID::is_interface)) { - RTLIL::Module *intf_module = design->module(cell->type); - interfaces_in_module[cell->name] = intf_module; - } - } + IFExpander if_expander(*design, *module); for (auto cell : module->cells()) { - bool has_interfaces_not_found = false; - - std::vector connections_to_remove; - std::vector connections_to_add_name; - std::vector connections_to_add_signal; + if_expander.start_cell(); if (cell->type.begins_with("$array:")) { int pos[3]; @@ -202,10 +352,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check array_cells[cell] = std::pair(idx, num); cell->type = cell->type.substr(pos_type + 1); } - dict interfaces_to_add_to_submodule; - dict modports_used_in_submodule; - if (design->module(cell->type) == nullptr) + RTLIL::Module *mod = design->module(cell->type); + if (mod == nullptr) { if (design->module("$abstract" + cell->type.str()) != nullptr) { @@ -243,77 +392,15 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check continue; loaded_module: - if (design->module(cell->type) == nullptr) + mod = design->module(cell->type); + if (mod == nullptr) log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str()); did_something = true; } else { - RTLIL::Module *mod = design->module(cell->type); - - // Go over all connections and see if any of them are SV interfaces. If they are, then add the replacements to - // some lists, so that the ports for sub-modules can be replaced further down: - for (auto &conn : cell->connections()) { - if(mod->wire(conn.first) != nullptr && mod->wire(conn.first)->get_bool_attribute(ID::is_interface)) { // Check if the connection is present as an interface in the sub-module's port list - if(conn.second.bits().size() == 1 && conn.second.bits()[0].wire->get_bool_attribute(ID::is_interface)) { // Check if the connected wire is a potential interface in the parent module - std::string interface_name_str = conn.second.bits()[0].wire->name.str(); - interface_name_str.replace(0,23,""); // Strip the prefix '$dummywireforinterface' from the dummy wire to get the name - interface_name_str = "\\" + interface_name_str; - RTLIL::IdString interface_name = interface_name_str; - bool not_found_interface = false; - if(module->get_bool_attribute(ID::interfaces_replaced_in_module)) { // If 'interfaces' in the cell have not be been handled yet, there is no need to derive the sub-module either - // Check if the interface instance is present in module: - // Interface instances may either have the plain name or the name appended with '_inst_from_top_dummy'. - // Check for both of them here - int nexactmatch = interfaces_in_module.count(interface_name) > 0; - std::string interface_name_str2 = interface_name_str + "_inst_from_top_dummy"; - RTLIL::IdString interface_name2 = interface_name_str2; - int nmatch2 = interfaces_in_module.count(interface_name2) > 0; - if (nexactmatch > 0 || nmatch2 > 0) { - if (nexactmatch != 0) // Choose the one with the plain name if it exists - interface_name2 = interface_name; - RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name2); - for (auto mod_wire : mod_replace_ports->wires()) { // Go over all wires in interface, and add replacements to lists. - std::string signal_name1 = conn.first.str() + "." + log_id(mod_wire->name); - std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire); - connections_to_add_name.push_back(RTLIL::IdString(signal_name1)); - if(module->wire(signal_name2) == nullptr) { - log_error("Could not find signal '%s' in '%s'\n", signal_name2.c_str(), log_id(module->name)); - } - else { - RTLIL::Wire *wire_in_parent = module->wire(signal_name2); - connections_to_add_signal.push_back(wire_in_parent); - } - } - connections_to_remove.push_back(conn.first); - interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name2); - - // Find if the sub-module has set a modport for the current - // interface connection. Add any modports to a dict which will - // be passed to AstModule::derive - string modport_name = mod->wire(conn.first)->get_string_attribute(ID::interface_modport); - if (!modport_name.empty()) { - modports_used_in_submodule[conn.first] = "\\" + modport_name; - } - } - else not_found_interface = true; - } - else not_found_interface = true; - // If the interface instance has not already been derived in the module, we cannot complete at this stage. Set "has_interfaces_not_found" - // which will delay the expansion of this cell: - if (not_found_interface) { - // If we have already gone over all cells in this module, and the interface has still not been found - flag it as an error: - if(!(module->get_bool_attribute(ID::cells_not_processed))) { - log_warning("Could not find interface instance for `%s' in `%s'\n", log_id(interface_name), log_id(module)); - } - else { - // Only set has_interfaces_not_found if it would be possible to find them, since otherwiser we will end up in an infinite loop: - has_interfaces_not_found = true; - } - } - } - } - } - // + // Go over all connections and check if any of them are SV + // interfaces. + if_expander.visit_connections(*cell, *mod); if (flag_check || flag_simcheck) { @@ -340,9 +427,13 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } } - RTLIL::Module *mod = design->module(cell->type); - if (design->module(cell->type)->get_blackbox_attribute()) { + // If we make it out of the if/else block above without leaving + // this iteration, mod will equal design->module(cell->type) and + // will be non-null. + log_assert(mod); + + if (mod->get_blackbox_attribute()) { if (flag_simcheck) log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n", cell->type.c_str(), module->name.c_str(), cell->name.c_str()); @@ -350,23 +441,18 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } // If interface instances not yet found, skip cell for now, and say we did something, so that we will return back here: - if(has_interfaces_not_found) { + if(if_expander.has_interfaces_not_found) { did_something = true; // waiting for interfaces to be handled continue; } - // Do the actual replacements of the SV interface port connection with the individual signal connections: - for(unsigned int i=0;iconnections_[connections_to_add_name[i]] = connections_to_add_signal[i]; - } - // Remove the connection for the interface itself: - for(unsigned int i=0;iconnections_.erase(connections_to_remove[i]); - } + if_expander.rewrite_interface_connections(*cell); // If there are no overridden parameters AND not interfaces, then we can use the existing module instance as the type // for the cell: - if (cell->parameters.size() == 0 && (interfaces_to_add_to_submodule.size() == 0 || !(cell->get_bool_attribute(ID::module_not_derived)))) { + if (cell->parameters.size() == 0 && + (if_expander.interfaces_to_add_to_submodule.size() == 0 || + !(cell->get_bool_attribute(ID::module_not_derived)))) { // If the cell being processed is an the interface instance itself, go down to "handle_interface_instance:", // so that the signals of the interface are added to the parent module. if (mod->get_bool_attribute(ID::is_interface)) { @@ -375,7 +461,10 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check continue; } - cell->type = mod->derive(design, cell->parameters, interfaces_to_add_to_submodule, modports_used_in_submodule); + cell->type = mod->derive(design, + cell->parameters, + if_expander.interfaces_to_add_to_submodule, + if_expander.modports_used_in_submodule); cell->parameters.clear(); did_something = true; @@ -386,7 +475,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check if (mod->get_bool_attribute(ID::is_interface) && cell->get_bool_attribute(ID::module_not_derived)) { cell->set_bool_attribute(ID::is_interface); RTLIL::Module *derived_module = design->module(cell->type); - interfaces_in_module[cell->name] = derived_module; + if_expander.interfaces_in_module[cell->name] = derived_module; did_something = true; } // We clear 'module_not_derived' such that we will not rederive the cell again (needed when there are interfaces connected to the cell) @@ -399,8 +488,8 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check // If any interface instances or interface ports were found in the module, we need to rederive it completely: - if ((interfaces_in_module.size() > 0 || has_interface_ports) && !module->get_bool_attribute(ID::interfaces_replaced_in_module)) { - module->reprocess_module(design, interfaces_in_module); + if ((if_expander.interfaces_in_module.size() > 0 || has_interface_ports) && !module->get_bool_attribute(ID::interfaces_replaced_in_module)) { + module->reprocess_module(design, if_expander.interfaces_in_module); return did_something; }