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 index 05a2a50ec..90758da05 100644 --- a/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold +++ b/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold @@ -1,3 +1,3 @@ -ivltests/sv_interface_port_forwarding_restrict_fail.v:30: error: Interface member `hidden' is not listed in modport `consumer'. -ivltests/sv_interface_port_forwarding_restrict_fail.v:30: error: Unable to elaborate r-value: bus.hidden +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_missing_type_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold new file mode 100644 index 000000000..601207b55 --- /dev/null +++ b/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_missing_type_fail.v:7: error: Interface port bus uses unknown interface type `missing_if'. +1 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 index 4201c3c5e..8fc0533db 100644 --- a/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold +++ b/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold @@ -1,2 +1,2 @@ -ivltests/sv_interface_port_positional_unconnected_fail.v:13: error: Interface port `bus' of module bus_user is not connected. +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 index 58cd1bc81..9fb52a87b 100644 --- a/ivtest/ivltests/sv_interface_port_forwarding.v +++ b/ivtest/ivltests/sv_interface_port_forwarding.v @@ -4,14 +4,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - logic mirror; - logic hidden; - - modport consumer(input value, output mirror); -endinterface - module test; bus_if bus(); @@ -39,3 +31,11 @@ module child( ); 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 index a0fb3ab79..79a1ced9f 100644 --- a/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v +++ b/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v @@ -4,13 +4,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - logic hidden; - - modport consumer(input value); -endinterface - module test; bus_if bus(); parent dut(.bus(bus)); @@ -29,3 +22,10 @@ module child( 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_missing_type_fail.v b/ivtest/ivltests/sv_interface_port_missing_type_fail.v new file mode 100644 index 000000000..df1a5a513 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_missing_type_fail.v @@ -0,0 +1,11 @@ +// This tests the diagnostic path for an 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.consumer bus +); + initial $display("FAILED"); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_positional.v b/ivtest/ivltests/sv_interface_port_positional.v index 8b6d47551..d0cb7d057 100644 --- a/ivtest/ivltests/sv_interface_port_positional.v +++ b/ivtest/ivltests/sv_interface_port_positional.v @@ -3,13 +3,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - logic sample; - - modport consumer(input value, output sample); -endinterface - module test; bus_if bus(); @@ -31,3 +24,10 @@ module bus_user( ); 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 index 90e17871a..5b9627b52 100644 --- a/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v +++ b/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v @@ -3,12 +3,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - - modport consumer(input value); -endinterface - module test; bus_user dut(); endmodule @@ -17,3 +11,9 @@ 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_unmodported_basic.v b/ivtest/ivltests/sv_interface_port_unmodported_basic.v index aa981cf2f..c8bad7778 100644 --- a/ivtest/ivltests/sv_interface_port_unmodported_basic.v +++ b/ivtest/ivltests/sv_interface_port_unmodported_basic.v @@ -4,12 +4,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic [7:0] lhs; - logic [7:0] rhs; - logic [8:0] sum; -endinterface - module test; logic [7:0] lhs; logic [7:0] rhs; @@ -38,3 +32,9 @@ module add_if( ); 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 index 693e702ed..e13630fb6 100644 --- a/ivtest/ivltests/sv_interface_port_wildcard.v +++ b/ivtest/ivltests/sv_interface_port_wildcard.v @@ -3,13 +3,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - logic sample; - - modport consumer(input value, output sample); -endinterface - module test; bus_if bus(); @@ -31,3 +24,10 @@ module bus_user( ); 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 9fd43c39b..d205e357e 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -270,12 +270,14 @@ sv_foreach9 vvp_tests/sv_foreach9.json sv_foreach10 vvp_tests/sv_foreach10.json sv_interface vvp_tests/sv_interface.json sv_interface_port_basic vvp_tests/sv_interface_port_basic.json +sv_interface_port_missing_type_fail vvp_tests/sv_interface_port_missing_type_fail.json sv_interface_port_missing_modport_fail vvp_tests/sv_interface_port_missing_modport_fail.json sv_interface_port_non_interface_actual_fail vvp_tests/sv_interface_port_non_interface_actual_fail.json 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 diff --git a/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json b/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json new file mode 100644 index 000000000..bc986c918 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_missing_type_fail.v", + "gold" : "sv_interface_port_missing_type_fail", + "iverilog-args" : [ "-g2005-sv" ] +} 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..e35cde0c3 --- /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" : [ "-g2005-sv" ] +} diff --git a/lexor.lex b/lexor.lex index 97e07560c..0e0c2646c 100644 --- a/lexor.lex +++ b/lexor.lex @@ -120,6 +120,8 @@ static list keyword_mask_stack; static int comment_enter; static bool in_module = false; static bool in_UDP = false; +static bool in_module_port_list = false; +static bool module_port_list_start = false; bool in_celldefine = false; UCDriveType uc_drive = UCD_NONE; static int ts_state = 0; @@ -139,6 +141,12 @@ void lex_in_package_scope(PPackage*pkg) in_package_scope = pkg; } +void lex_in_module_port_list(bool flag) +{ + in_module_port_list = flag; + module_port_list_start = flag; +} + %} %x CCOMMENT @@ -160,6 +168,7 @@ void lex_in_package_scope(PPackage*pkg) %x REAL_SCALE W [ \t\b\f\r]+ +ID [a-zA-Z_][a-zA-Z0-9$_]* S [afpnumkKMGT] @@ -335,7 +344,7 @@ TU [munpf] "z0" { return K_edge_descriptor; } "z1" { return K_edge_descriptor; } -[a-zA-Z_][a-zA-Z0-9$_]* { +{ID} { int rc = lexor_keyword_code(yytext, yyleng); switch (rc) { case IDENTIFIER: @@ -434,6 +443,22 @@ TU [munpf] } } + if (rc == IDENTIFIER && gn_system_verilog() && + in_module_port_list && module_port_list_start) { + char save_ch = *yy_c_buf_p; + *yy_c_buf_p = yy_hold_char; + const char*cp = yy_c_buf_p; + while (*cp == ' ' || *cp == '\t' || *cp == '\b' || + *cp == '\f' || *cp == '\r' || *cp == '\n') + cp += 1; + if (*cp == '.' || isalpha(static_cast(*cp)) || + *cp == '_' || *cp == '\\') + rc = INTERFACE_IDENTIFIER; + *yy_c_buf_p = save_ch; + } + + if (in_module_port_list) + module_port_list_start = false; return rc; } @@ -906,7 +931,16 @@ TU [munpf] `{W} { VLerror(yylloc, "error: Stray tic (`) here. Perhaps you put white " "space between the tic and preprocessor directive?"); } -. { return yytext[0]; } +. { + if (in_module_port_list) { + if (yytext[0] == '(' || yytext[0] == ',') + module_port_list_start = true; + else if (yytext[0] != ')' && yytext[0] != '[' && + yytext[0] != ']' && yytext[0] != ':') + module_port_list_start = false; + } + return yytext[0]; +} /* Final catchall. something got lost or mishandled. */ /* XXX Should we tell the user something about the lexical state? */ diff --git a/parse.y b/parse.y index 792454140..aa6fc0a97 100644 --- a/parse.y +++ b/parse.y @@ -4781,9 +4781,11 @@ module port_declaration_context_init(); } module_package_import_list_opt module_parameter_port_list_opt + { lex_in_module_port_list(true); } module_port_list_opt + { lex_in_module_port_list(false); } module_attribute_foreign ';' - { pform_module_set_ports($8); } + { pform_module_set_ports($9); } timeunits_declaration_opt { pform_set_scope_timescale(@2); } module_item_list_opt @@ -4806,16 +4808,16 @@ module } // Check that program/endprogram and module/endmodule // keywords match. - if ($2 != $15) { + if ($2 != $17) { switch ($2) { case K_module: - yyerror(@15, "error: module not closed by endmodule."); + yyerror(@17, "error: module not closed by endmodule."); break; case K_program: - yyerror(@15, "error: program not closed by endprogram."); + yyerror(@17, "error: program not closed by endprogram."); break; case K_interface: - yyerror(@15, "error: interface not closed by endinterface."); + yyerror(@17, "error: interface not closed by endinterface."); break; default: break; @@ -4831,13 +4833,13 @@ module // module. switch ($2) { case K_module: - check_end_label(@17, "module", $4, $17); + check_end_label(@19, "module", $4, $19); break; case K_program: - check_end_label(@17, "program", $4, $17); + check_end_label(@19, "program", $4, $19); break; case K_interface: - check_end_label(@17, "interface", $4, $17); + check_end_label(@19, "interface", $4, $19); break; default: break; diff --git a/parse_misc.h b/parse_misc.h index b669a9af0..a9eb7d19b 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -83,6 +83,13 @@ extern UCDriveType uc_drive; */ extern void lex_in_package_scope(PPackage*pkg); +/* + * The parser signals when the lexor is scanning a module/interface/program + * port list so that ambiguous SystemVerilog interface formals can be + * tokenized without depending on declaration order. + */ +extern void lex_in_module_port_list(bool flag); + /* * Test if this identifier is a type identifier in the current * context. The pform code needs to help the lexor here because the