refactor(interface): share port resolution paths

This commit is contained in:
Jose Tejada 2026-05-10 17:08:35 +02:00
parent 39072cd452
commit 2228e31a6a
6 changed files with 122 additions and 69 deletions

View File

@ -21,8 +21,11 @@
# include "Module.h" # include "Module.h"
# include "PGate.h" # include "PGate.h"
# include "PModport.h"
# include "PWire.h" # include "PWire.h"
# include "parse_api.h"
# include "ivl_assert.h" # include "ivl_assert.h"
# include <iostream>
using namespace std; using namespace std;
@ -33,6 +36,50 @@ Module::port_t::port_t()
{ {
} }
bool resolve_interface_formal_port(const LineInfo*li, Design*des,
const Module::port_t*port,
interface_formal_port_t&res,
bool emit_errors)
{
ivl_assert(*li, port);
ivl_assert(*li, port->is_interface_port());
res = interface_formal_port_t();
map<perm_string,Module*>::const_iterator mod =
pform_modules.find(port->interface_type);
if (mod == pform_modules.end() || !mod->second->is_interface) {
if (emit_errors) {
cerr << li->get_fileline() << ": error: Interface port "
<< port->name << " uses unknown interface type `"
<< port->interface_type << "'." << endl;
des->errors += 1;
}
return false;
}
res.module = mod->second;
if (port->modport_name.str()) {
map<perm_string,PModport*>::const_iterator mp =
mod->second->modports.find(port->modport_name);
if (mp == mod->second->modports.end()) {
if (emit_errors) {
cerr << li->get_fileline() << ": error: Interface port "
<< port->name << " uses unknown modport `"
<< port->modport_name << "' of interface `"
<< port->interface_type << "'." << endl;
des->errors += 1;
}
return false;
}
res.modport = mp->second;
}
return true;
}
/* n is a permallocated string. */ /* n is a permallocated string. */
Module::Module(LexicalScope*parent, perm_string n) Module::Module(LexicalScope*parent, perm_string n)
: PScopeExtra(n, parent) : PScopeExtra(n, parent)

View File

@ -43,6 +43,7 @@ class PFunction;
class PWire; class PWire;
class PProcess; class PProcess;
class Design; class Design;
class LineInfo;
class NetScope; class NetScope;
/* /*
@ -197,4 +198,16 @@ class Module : public PScopeExtra, public PNamedItem {
Module& operator= (const Module&); Module& operator= (const Module&);
}; };
struct interface_formal_port_t {
interface_formal_port_t() : module(0), modport(0) { }
const Module*module;
const PModport*modport;
};
extern bool resolve_interface_formal_port(const LineInfo*li, Design*des,
const Module::port_t*port,
interface_formal_port_t&res,
bool emit_errors);
#endif /* IVL_Module_H */ #endif /* IVL_Module_H */

View File

@ -300,24 +300,8 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
continue; continue;
if (pp->is_interface_port()) { if (pp->is_interface_port()) {
map<perm_string,Module*>::const_iterator mod = interface_formal_port_t formal;
pform_modules.find(pp->interface_type); resolve_interface_formal_port(this, des, pp, formal, true);
if (mod == pform_modules.end() || !mod->second->is_interface) {
cerr << get_fileline() << ": error: Interface port "
<< pp->name << " uses unknown interface type `"
<< pp->interface_type << "'." << endl;
des->errors += 1;
continue;
}
if (pp->modport_name.str() &&
mod->second->modports.find(pp->modport_name) == mod->second->modports.end()) {
cerr << get_fileline() << ": error: Interface port "
<< pp->name << " uses unknown modport `"
<< pp->modport_name << "' of interface `"
<< pp->interface_type << "'." << endl;
des->errors += 1;
}
continue; continue;
} }

View File

@ -1325,6 +1325,48 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod,
return true; return true;
} }
struct interface_actual_scope_t {
interface_actual_scope_t() : scope(0), modport(0) { }
NetScope*scope;
const PModport*modport;
perm_string display_name;
};
static bool resolve_interface_actual_scope(const PExpr*actual,
NetScope*parent_scope,
Design*des,
interface_actual_scope_t&res)
{
res = interface_actual_scope_t();
const PEIdent*actual_ident = dynamic_cast<const PEIdent*>(actual);
if (!actual_ident || actual_ident->path().package ||
actual_ident->path().name.size() != 1 ||
!actual_ident->path().name.front().index.empty()) {
return false;
}
res.display_name = actual_ident->path().name.front().name;
symbol_search_results sr;
symbol_search(actual, des, parent_scope, actual_ident->path(),
actual_ident->lexical_pos(), &sr);
res.scope = sr.scope;
if (sr.through_interface_alias())
res.modport = sr.interface_alias_modport;
else if (NetScope*child = parent_scope->child(hname_t(res.display_name)))
res.scope = child;
else if (const NetScope::interface_port_alias_t*alias =
parent_scope->find_interface_port_alias(res.display_name)) {
res.scope = alias->actual_scope;
res.modport = alias->modport;
}
return true;
}
bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, bool PGModule::bind_interface_ports_(Design*des, const Module*rmod,
NetScope*parent_scope, NetScope*parent_scope,
NetScope*instance_scope, NetScope*instance_scope,
@ -1347,10 +1389,8 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod,
continue; continue;
} }
const PEIdent*actual_ident = dynamic_cast<const PEIdent*>(pins[idx]); interface_actual_scope_t actual;
if (!actual_ident || actual_ident->path().package || if (!resolve_interface_actual_scope(pins[idx], parent_scope, des, actual)) {
actual_ident->path().name.size() != 1 ||
!actual_ident->path().name.front().index.empty()) {
cerr << pins[idx]->get_fileline() << ": error: Interface port `" cerr << pins[idx]->get_fileline() << ": error: Interface port `"
<< port->name << "' must be connected to a simple " << port->name << "' must be connected to a simple "
"interface instance name." << endl; "interface instance name." << endl;
@ -1359,19 +1399,7 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod,
continue; continue;
} }
perm_string actual_name = actual_ident->path().name.front().name; if (!actual.scope || !actual.scope->is_interface()) {
NetScope*actual_scope = parent_scope->child(hname_t(actual_name));
const PModport*actual_modport = 0;
if (!actual_scope) {
const NetScope::interface_port_alias_t*actual_alias =
parent_scope->find_interface_port_alias(actual_name);
if (actual_alias) {
actual_scope = actual_alias->actual_scope;
actual_modport = actual_alias->modport;
}
}
if (!actual_scope || !actual_scope->is_interface()) {
cerr << pins[idx]->get_fileline() << ": error: Actual for " cerr << pins[idx]->get_fileline() << ": error: Actual for "
"interface port `" << port->name "interface port `" << port->name
<< "' is not an interface instance." << endl; << "' is not an interface instance." << endl;
@ -1380,40 +1408,35 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod,
continue; continue;
} }
if (actual_scope->module_name() != port->interface_type) { interface_formal_port_t formal;
resolve_interface_formal_port(pins[idx], des, port, formal, false);
if (!formal.module)
continue;
if (actual.scope->module_name() != formal.module->mod_name()) {
cerr << pins[idx]->get_fileline() << ": error: Interface port `" cerr << pins[idx]->get_fileline() << ": error: Interface port `"
<< port->name << "' expects interface type `" << port->name << "' expects interface type `"
<< port->interface_type << "' but actual `" << actual_name << port->interface_type << "' but actual `" << actual.display_name
<< "' has type `" << actual_scope->module_name() << "'." << endl; << "' has type `" << actual.scope->module_name() << "'." << endl;
des->errors += 1; des->errors += 1;
flag = false; flag = false;
continue; continue;
} }
map<perm_string,Module*>::const_iterator mod = if (actual.modport && formal.modport &&
pform_modules.find(port->interface_type); actual.modport->name() != formal.modport->name()) {
const PModport*formal_modport = 0;
if (port->modport_name.str() && mod != pform_modules.end()) {
map<perm_string,PModport*>::const_iterator mp =
mod->second->modports.find(port->modport_name);
if (mp != mod->second->modports.end())
formal_modport = mp->second;
}
if (actual_modport && formal_modport &&
actual_modport->name() != formal_modport->name()) {
cerr << pins[idx]->get_fileline() << ": error: Interface port `" cerr << pins[idx]->get_fileline() << ": error: Interface port `"
<< port->name << "' cannot forward actual `" << actual_name << port->name << "' cannot forward actual `" << actual.display_name
<< "' restricted by modport `" << actual_modport->name() << "' restricted by modport `" << actual.modport->name()
<< "' to formal modport `" << formal_modport->name() << "' to formal modport `" << formal.modport->name()
<< "'." << endl; << "'." << endl;
des->errors += 1; des->errors += 1;
flag = false; flag = false;
continue; continue;
} }
const PModport*modport = formal_modport? formal_modport : actual_modport; const PModport*modport = formal.modport? formal.modport : actual.modport;
instance_scope->add_interface_port_alias(port->name, actual_scope, instance_scope->add_interface_port_alias(port->name, actual.scope,
modport); modport);
} }

View File

@ -831,18 +831,6 @@ NetScope::find_interface_port_alias(perm_string formal_name) const
return &cur->second; return &cur->second;
} }
NetScope* NetScope::find_interface_port_alias_scope(perm_string formal_name) const
{
const interface_port_alias_t*cur = find_interface_port_alias(formal_name);
return cur? cur->actual_scope : 0;
}
const PModport* NetScope::find_interface_port_modport(perm_string formal_name) const
{
const interface_port_alias_t*cur = find_interface_port_alias(formal_name);
return cur? cur->modport : 0;
}
/* Helper function to see if the given scope is defined in a class and if /* Helper function to see if the given scope is defined in a class and if
* so return the class scope. */ * so return the class scope. */
const NetScope* NetScope::get_class_scope() const const NetScope* NetScope::get_class_scope() const

View File

@ -1061,8 +1061,6 @@ class NetScope : public Definitions, public Attrib {
NetScope*actual_scope, NetScope*actual_scope,
const PModport*modport); const PModport*modport);
const interface_port_alias_t* find_interface_port_alias(perm_string formal_name) const; const interface_port_alias_t* find_interface_port_alias(perm_string formal_name) const;
NetScope* find_interface_port_alias_scope(perm_string formal_name) const;
const PModport* find_interface_port_modport(perm_string formal_name) const;
/* A helper function to find the enclosing class scope. */ /* A helper function to find the enclosing class scope. */
const NetScope* get_class_scope() const; const NetScope* get_class_scope() const;