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<RTLIL::IdString, RTLIL::Module*> interfaces_in_module;
+
+ bool has_interfaces_not_found;
+ std::vector<RTLIL::IdString> connections_to_remove;
+ std::vector<RTLIL::IdString> connections_to_add_name;
+ std::vector<RTLIL::SigSpec> connections_to_add_signal;
+ dict<RTLIL::IdString, RTLIL::Module*> interfaces_to_add_to_submodule;
+ dict<RTLIL::IdString, RTLIL::IdString> 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<connections_to_add_name.size();i++) {
+ cell.connections_[connections_to_add_name[i]] = connections_to_add_signal[i];
+ }
+ // Remove the connection for the interface itself:
+ for(unsigned int i=0;i<connections_to_remove.size();i++) {
+ cell.connections_.erase(connections_to_remove[i]);
+ }
+ }
+};
+
bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
{
bool did_something = false;
}
}
- // Always keep track of all derived interfaces available in the current module in 'interfaces_in_module':
- dict<RTLIL::IdString, RTLIL::Module*> 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<RTLIL::IdString> connections_to_remove;
- std::vector<RTLIL::IdString> connections_to_add_name;
- std::vector<RTLIL::SigSpec> connections_to_add_signal;
+ if_expander.start_cell();
if (cell->type.begins_with("$array:")) {
int pos[3];
array_cells[cell] = std::pair<int, int>(idx, num);
cell->type = cell->type.substr(pos_type + 1);
}
- dict<RTLIL::IdString, RTLIL::Module*> interfaces_to_add_to_submodule;
- dict<RTLIL::IdString, RTLIL::IdString> 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)
{
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)
{
}
}
- 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());
}
// 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;i<connections_to_add_name.size();i++) {
- cell->connections_[connections_to_add_name[i]] = connections_to_add_signal[i];
- }
- // Remove the connection for the interface itself:
- for(unsigned int i=0;i<connections_to_remove.size();i++) {
- cell->connections_.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)) {
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;
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)
// 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;
}