From 39072cd4523da6dc4536bfec1d599188cbc5b41b Mon Sep 17 00:00:00 2001 From: Jose Tejada Date: Sun, 10 May 2026 16:34:21 +0200 Subject: [PATCH] feat(interface): broaden interface port binding --- elaborate.cc | 48 ++++++++++++------- ...warding_restrict_fail-iverilog-stderr.gold | 3 ++ ...onal_unconnected_fail-iverilog-stderr.gold | 2 + ...ted_missing_type_fail-iverilog-stderr.gold | 2 + .../ivltests/sv_interface_port_forwarding.v | 41 ++++++++++++++++ ..._interface_port_forwarding_restrict_fail.v | 31 ++++++++++++ .../sv_interface_port_plain_ansi_regression.v | 29 +++++++++++ .../ivltests/sv_interface_port_positional.v | 33 +++++++++++++ ...terface_port_positional_unconnected_fail.v | 19 ++++++++ ...v_interface_port_typedef_ansi_regression.v | 31 ++++++++++++ .../sv_interface_port_unmodported_basic.v | 40 ++++++++++++++++ ...rface_port_unmodported_missing_type_fail.v | 11 +++++ ivtest/ivltests/sv_interface_port_wildcard.v | 33 +++++++++++++ ivtest/regress-vvp.list | 9 ++++ .../sv_interface_port_forwarding.json | 5 ++ ...terface_port_forwarding_restrict_fail.json | 6 +++ ..._interface_port_plain_ansi_regression.json | 5 ++ .../sv_interface_port_positional.json | 5 ++ ...face_port_positional_unconnected_fail.json | 6 +++ ...nterface_port_typedef_ansi_regression.json | 5 ++ .../sv_interface_port_unmodported_basic.json | 5 ++ ...ce_port_unmodported_missing_type_fail.json | 6 +++ .../vvp_tests/sv_interface_port_wildcard.json | 5 ++ parse.y | 13 ++++- 24 files changed, 374 insertions(+), 19 deletions(-) create mode 100644 ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold create mode 100644 ivtest/ivltests/sv_interface_port_forwarding.v create mode 100644 ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_plain_ansi_regression.v create mode 100644 ivtest/ivltests/sv_interface_port_positional.v create mode 100644 ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_typedef_ansi_regression.v create mode 100644 ivtest/ivltests/sv_interface_port_unmodported_basic.v create mode 100644 ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_wildcard.v create mode 100644 ivtest/vvp_tests/sv_interface_port_forwarding.json create mode 100644 ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json create mode 100644 ivtest/vvp_tests/sv_interface_port_positional.json create mode 100644 ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json create mode 100644 ivtest/vvp_tests/sv_interface_port_unmodported_basic.json create mode 100644 ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_wildcard.json diff --git a/elaborate.cc b/elaborate.cc index 8c12940d1..bd6354164 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -51,6 +51,7 @@ # include "netscalar.h" # include "netclass.h" # include "netmisc.h" +# include "PModport.h" # include "util.h" # include "parse_api.h" # include "compiler.h" @@ -1261,12 +1262,14 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, if (pins_[idx].name[0] == '*') { for (unsigned j = 0 ; j < nexp ; j += 1) { if (rmod->ports[j] && !pins[j] && !pins_is_explicitly_not_connected[j]) { - pins_fromwc[j] = true; pform_name_t path_; path_.push_back(name_component_t(rmod->ports[j]->name)); symbol_search_results sr; symbol_search(this, des, scope, path_, UINT_MAX, &sr); - if (sr.net != 0) { + if (sr.net != 0 || + (rmod->ports[j]->is_interface_port() && + sr.scope != 0 && sr.scope->is_interface())) { + pins_fromwc[j] = true; pins[j] = new PEIdent(rmod->ports[j]->name, UINT_MAX, true); pins[j]->set_lineno(get_lineno()); pins[j]->set_file(get_file()); @@ -1326,7 +1329,7 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, NetScope*parent_scope, NetScope*instance_scope, const vector&pins, - const vector&pins_fromwc) const + const vector&) const { bool flag = true; @@ -1335,15 +1338,6 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, if (!port || !port->is_interface_port()) continue; - if (pins_fromwc[idx]) { - cerr << get_fileline() << ": sorry: Wildcard connection " - "to interface port `" << port->name - << "' is not yet supported." << endl; - des->errors += 1; - flag = false; - continue; - } - if (!pins[idx]) { cerr << get_fileline() << ": error: Interface port `" << port->name << "' of module " << rmod->mod_name() @@ -1367,8 +1361,15 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, perm_string actual_name = actual_ident->path().name.front().name; NetScope*actual_scope = parent_scope->child(hname_t(actual_name)); - if (!actual_scope) - actual_scope = parent_scope->find_interface_port_alias_scope(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 " @@ -1391,14 +1392,27 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, map::const_iterator mod = pform_modules.find(port->interface_type); - const PModport*modport = 0; - if (mod != pform_modules.end()) { + const PModport*formal_modport = 0; + if (port->modport_name.str() && mod != pform_modules.end()) { map::const_iterator mp = mod->second->modports.find(port->modport_name); if (mp != mod->second->modports.end()) - modport = mp->second; + formal_modport = mp->second; } + if (actual_modport && formal_modport && + actual_modport->name() != formal_modport->name()) { + cerr << pins[idx]->get_fileline() << ": error: Interface port `" + << port->name << "' cannot forward actual `" << actual_name + << "' restricted by modport `" << actual_modport->name() + << "' to formal modport `" << formal_modport->name() + << "'." << endl; + des->errors += 1; + flag = false; + continue; + } + + const PModport*modport = formal_modport? formal_modport : actual_modport; instance_scope->add_interface_port_alias(port->name, actual_scope, modport); } diff --git a/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold new file mode 100644 index 000000000..90758da05 --- /dev/null +++ b/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold @@ -0,0 +1,3 @@ +ivltests/sv_interface_port_forwarding_restrict_fail.v:23: error: Interface member `hidden' is not listed in modport `consumer'. +ivltests/sv_interface_port_forwarding_restrict_fail.v:23: error: Unable to elaborate r-value: bus.hidden +2 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold new file mode 100644 index 000000000..8fc0533db --- /dev/null +++ b/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_positional_unconnected_fail.v:7: error: Interface port `bus' of module bus_user is not connected. +Elaboration failed diff --git a/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold new file mode 100644 index 000000000..24caf2d27 --- /dev/null +++ b/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_unmodported_missing_type_fail.v:7: error: Interface port bus uses unknown interface type `missing_if'. +1 error(s) during elaboration. diff --git a/ivtest/ivltests/sv_interface_port_forwarding.v b/ivtest/ivltests/sv_interface_port_forwarding.v new file mode 100644 index 000000000..9fb52a87b --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_forwarding.v @@ -0,0 +1,41 @@ +// This tests forwarding an interface-typed formal port to a child +// module while preserving the parent-facing modport view. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + + assign bus.value = 1'b1; + parent dut(.bus(bus)); + + initial begin + #1; + if (bus.mirror !== 1'b1) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module parent( + bus_if.consumer bus +); + child u_child(.bus(bus)); +endmodule + +module child( + bus_if bus +); + assign bus.mirror = bus.value; +endmodule + +interface bus_if (); + logic value; + logic mirror; + logic hidden; + + modport consumer(input value, output mirror); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v b/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v new file mode 100644 index 000000000..79a1ced9f --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v @@ -0,0 +1,31 @@ +// This tests that forwarding an interface formal cannot widen access +// beyond the parent-facing modport restriction. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + parent dut(.bus(bus)); +endmodule + +module parent( + bus_if.consumer bus +); + child u_child(.bus(bus)); +endmodule + +module child( + bus_if bus +); + logic sample; + + assign sample = bus.hidden; +endmodule + +interface bus_if (); + logic value; + logic hidden; + + modport consumer(input value); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_plain_ansi_regression.v b/ivtest/ivltests/sv_interface_port_plain_ansi_regression.v new file mode 100644 index 000000000..30ab169a2 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_plain_ansi_regression.v @@ -0,0 +1,29 @@ +// This protects ordinary partial ANSI port parsing near interface +// formal grammar. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + logic [3:0] value; + logic [3:0] result; + + plain dut(value, result); + + initial begin + value = 4'ha; + #1; + if (result !== 4'ha) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module plain( + input logic [3:0] value, + output logic [3:0] result +); + assign result = value; +endmodule diff --git a/ivtest/ivltests/sv_interface_port_positional.v b/ivtest/ivltests/sv_interface_port_positional.v new file mode 100644 index 000000000..d0cb7d057 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_positional.v @@ -0,0 +1,33 @@ +// This tests positional binding of an interface-typed module port. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + + assign bus.value = 1'b1; + bus_user dut(bus); + + initial begin + #1; + if (bus.sample !== 1'b1) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module bus_user( + bus_if.consumer bus +); + assign bus.sample = bus.value; +endmodule + +interface bus_if (); + logic value; + logic sample; + + modport consumer(input value, output sample); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v b/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v new file mode 100644 index 000000000..5b9627b52 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v @@ -0,0 +1,19 @@ +// This tests rejection of an unconnected positional interface port. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_user dut(); +endmodule + +module bus_user( + bus_if.consumer bus +); +endmodule + +interface bus_if (); + logic value; + + modport consumer(input value); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_typedef_ansi_regression.v b/ivtest/ivltests/sv_interface_port_typedef_ansi_regression.v new file mode 100644 index 000000000..0fc169015 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_typedef_ansi_regression.v @@ -0,0 +1,31 @@ +// This protects typedef-based ANSI ports from being interpreted as +// interface-typed formals. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +typedef logic [3:0] nibble_t; + +module test; + nibble_t value; + nibble_t result; + + typed dut(value, result); + + initial begin + value = 4'h6; + #1; + if (result !== 4'h6) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module typed( + input nibble_t value, + output nibble_t result +); + assign result = value; +endmodule diff --git a/ivtest/ivltests/sv_interface_port_unmodported_basic.v b/ivtest/ivltests/sv_interface_port_unmodported_basic.v new file mode 100644 index 000000000..c8bad7778 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_unmodported_basic.v @@ -0,0 +1,40 @@ +// This tests a concrete interface-typed module port without an explicit +// modport restriction. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + logic [7:0] lhs; + logic [7:0] rhs; + + bus_if bus(); + + add_if dut(.bus(bus)); + + assign bus.lhs = lhs; + assign bus.rhs = rhs; + + initial begin + lhs = 8'd9; + rhs = 8'd4; + #1; + if (bus.sum !== 9'd13) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module add_if( + bus_if bus +); + assign bus.sum = bus.lhs + bus.rhs; +endmodule + +interface bus_if (); + logic [7:0] lhs; + logic [7:0] rhs; + logic [8:0] sum; +endinterface diff --git a/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v b/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v new file mode 100644 index 000000000..b02bb3985 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v @@ -0,0 +1,11 @@ +// This tests the diagnostic path for an unmodported interface-typed +// module port whose interface type name is not declared. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module bus_user( + missing_if bus +); + initial $display("FAILED"); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_wildcard.v b/ivtest/ivltests/sv_interface_port_wildcard.v new file mode 100644 index 000000000..e13630fb6 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_wildcard.v @@ -0,0 +1,33 @@ +// This tests wildcard binding of an interface-typed module port. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + + assign bus.value = 1'b1; + bus_user dut(.*); + + initial begin + #1; + if (bus.sample !== 1'b1) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module bus_user( + bus_if.consumer bus +); + assign bus.sample = bus.value; +endmodule + +interface bus_if (); + logic value; + logic sample; + + modport consumer(input value, output sample); +endinterface diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 22f0917b6..638d8877f 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -276,6 +276,15 @@ sv_interface_port_non_interface_actual_fail vvp_tests/sv_interface_port_non_inte sv_interface_port_wrong_type_fail vvp_tests/sv_interface_port_wrong_type_fail.json sv_interface_port_modport_input_write_fail vvp_tests/sv_interface_port_modport_input_write_fail.json sv_interface_port_unlisted_member_fail vvp_tests/sv_interface_port_unlisted_member_fail.json +sv_interface_port_unmodported_basic vvp_tests/sv_interface_port_unmodported_basic.json +sv_interface_port_unmodported_missing_type_fail vvp_tests/sv_interface_port_unmodported_missing_type_fail.json +sv_interface_port_forwarding vvp_tests/sv_interface_port_forwarding.json +sv_interface_port_forwarding_restrict_fail vvp_tests/sv_interface_port_forwarding_restrict_fail.json +sv_interface_port_positional vvp_tests/sv_interface_port_positional.json +sv_interface_port_positional_unconnected_fail vvp_tests/sv_interface_port_positional_unconnected_fail.json +sv_interface_port_wildcard vvp_tests/sv_interface_port_wildcard.json +sv_interface_port_plain_ansi_regression vvp_tests/sv_interface_port_plain_ansi_regression.json +sv_interface_port_typedef_ansi_regression vvp_tests/sv_interface_port_typedef_ansi_regression.json sv_literals vvp_tests/sv_literals.json sv_mixed_assign1 vvp_tests/sv_mixed_assign1.json sv_mixed_assign2 vvp_tests/sv_mixed_assign2.json diff --git a/ivtest/vvp_tests/sv_interface_port_forwarding.json b/ivtest/vvp_tests/sv_interface_port_forwarding.json new file mode 100644 index 000000000..5983d5d82 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_forwarding.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_forwarding.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json b/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json new file mode 100644 index 000000000..4e26953b8 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_forwarding_restrict_fail.v", + "gold" : "sv_interface_port_forwarding_restrict_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json b/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json new file mode 100644 index 000000000..56b84fc13 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_plain_ansi_regression.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_positional.json b/ivtest/vvp_tests/sv_interface_port_positional.json new file mode 100644 index 000000000..66f253f1d --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_positional.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_positional.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json b/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json new file mode 100644 index 000000000..07880369e --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_positional_unconnected_fail.v", + "gold" : "sv_interface_port_positional_unconnected_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json b/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json new file mode 100644 index 000000000..7b7d719a6 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_typedef_ansi_regression.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json b/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json new file mode 100644 index 000000000..01423ed0a --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_unmodported_basic.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json b/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json new file mode 100644 index 000000000..d00e41cec --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_unmodported_missing_type_fail.v", + "gold" : "sv_interface_port_unmodported_missing_type_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_wildcard.json b/ivtest/vvp_tests/sv_interface_port_wildcard.json new file mode 100644 index 000000000..d34e83b0e --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_wildcard.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_wildcard.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/parse.y b/parse.y index 99949e7ee..3257e7761 100644 --- a/parse.y +++ b/parse.y @@ -468,11 +468,13 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, pform_requires_sv(loc, "Interface port declaration"); Module::port_t *port = pform_module_interface_port_reference( - loc, lex_strings.make(type), lex_strings.make(modport), + loc, lex_strings.make(type), + modport ? lex_strings.make(modport) : perm_string(), lex_strings.make(id)); delete[] type; - delete[] modport; + if (modport) + delete[] modport; delete[] id; pform_module_define_interface_port(loc, port, attributes); @@ -4658,6 +4660,9 @@ port_declaration | attribute_list_opt IDENTIFIER '.' IDENTIFIER IDENTIFIER { $$ = module_declare_interface_port(@5, $2, $4, $5, $1); } + | attribute_list_opt IDENTIFIER IDENTIFIER + { $$ = module_declare_interface_port(@3, $2, 0, $3, $1); + } | attribute_list_opt net_type_or_var data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt { pform_requires_sv(@4, "Partial ANSI port declaration"); $$ = module_declare_port(@4, $4, port_declaration_context.port_type, @@ -5755,6 +5760,10 @@ port { $$ = module_declare_interface_port(@4, $1, $3, $4, 0); } + | IDENTIFIER IDENTIFIER + { $$ = module_declare_interface_port(@2, $1, 0, $2, 0); + } + /* This syntax attaches an external name to the port reference so that the caller can bind by name to non-trivial port references. The port_t object gets its PWire from the