diff --git a/ivtest/ivltests/br_gh1321.v b/ivtest/ivltests/br_gh1321.v new file mode 100644 index 000000000..700deddf4 --- /dev/null +++ b/ivtest/ivltests/br_gh1321.v @@ -0,0 +1,18 @@ +module test; + logic a; + + always_comb begin + my_blk: begin + a = 1'b1; + end + end + + initial begin + #1; + if (a !== 1'b1) begin + $display("FAILED(%0d). Expected 1, got %b", `__LINE__, a); + end else begin + $display("PASSED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_block_prefix_label.v b/ivtest/ivltests/sv_block_prefix_label.v new file mode 100644 index 000000000..98ed3d866 --- /dev/null +++ b/ivtest/ivltests/sv_block_prefix_label.v @@ -0,0 +1,29 @@ +// Check that sequential block prefix labels work. + +module test; + + reg failed; + reg value; + + initial begin + failed = 1'b0; + value = 1'b0; + + BLOCK_LABEL: (* keep = 1 *) begin + value = 1'b1; + disable BLOCK_LABEL; + value = 1'b0; + end : BLOCK_LABEL + + if (value !== 1'b1) begin + $display("FAILED(%0d). Block prefix label did not create a named scope", + `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_block_prefix_name_diff_fail.v b/ivtest/ivltests/sv_block_prefix_name_diff_fail.v new file mode 100644 index 000000000..63c7c83ce --- /dev/null +++ b/ivtest/ivltests/sv_block_prefix_name_diff_fail.v @@ -0,0 +1,6 @@ +// Check that different prefix and post-begin labels are rejected. + +module test; + initial LABEL_A: begin : LABEL_B + end +endmodule diff --git a/ivtest/ivltests/sv_block_prefix_name_same_fail.v b/ivtest/ivltests/sv_block_prefix_name_same_fail.v new file mode 100644 index 000000000..e6b926cc2 --- /dev/null +++ b/ivtest/ivltests/sv_block_prefix_name_same_fail.v @@ -0,0 +1,6 @@ +// Check that matching prefix and post-begin labels are rejected. + +module test; + initial LABEL: begin : LABEL + end +endmodule diff --git a/ivtest/ivltests/sv_fork_prefix_label.v b/ivtest/ivltests/sv_fork_prefix_label.v new file mode 100644 index 000000000..b6b8a8687 --- /dev/null +++ b/ivtest/ivltests/sv_fork_prefix_label.v @@ -0,0 +1,36 @@ +// Check that fork prefix labels work with all join types. + +module test; + + reg failed; + reg [2:0] value; + + initial begin + failed = 1'b0; + value = 3'b000; + + FORK_LABEL: (* keep = 1 *) fork + value[0] = 1'b1; + join : FORK_LABEL + + FORK_ANY_LABEL: (* keep = 1 *) fork + value[1] = 1'b1; + join_any : FORK_ANY_LABEL + + FORK_NONE_LABEL: (* keep = 1 *) fork + value[2] = 1'b1; + join_none : FORK_NONE_LABEL + wait fork; + + if (value !== 3'b111) begin + $display("FAILED(%0d). Fork prefix labels did not execute all blocks", + `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_fork_prefix_name_diff_fail.v b/ivtest/ivltests/sv_fork_prefix_name_diff_fail.v new file mode 100644 index 000000000..ebbbc5f62 --- /dev/null +++ b/ivtest/ivltests/sv_fork_prefix_name_diff_fail.v @@ -0,0 +1,6 @@ +// Check that different prefix and post-fork labels are rejected. + +module test; + initial LABEL_A: fork : LABEL_B + join +endmodule diff --git a/ivtest/ivltests/sv_fork_prefix_name_same_fail.v b/ivtest/ivltests/sv_fork_prefix_name_same_fail.v new file mode 100644 index 000000000..02ecc300d --- /dev/null +++ b/ivtest/ivltests/sv_fork_prefix_name_same_fail.v @@ -0,0 +1,6 @@ +// Check that matching prefix and post-fork labels are rejected. + +module test; + initial LABEL: fork : LABEL + join +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_block_prefix_label_name.v b/ivtest/ivltests/sv_type_identifier_block_prefix_label_name.v new file mode 100644 index 000000000..8dcd78f03 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_block_prefix_label_name.v @@ -0,0 +1,29 @@ +// Check that sequential block prefix labels can shadow type identifiers. + +typedef int T; + +module test; + + reg failed; + reg value; + + initial begin + failed = 1'b0; + value = 1'b0; + + T: begin + value = 1'b1; + end : T + + if (value !== 1'b1) begin + $display("FAILED(%0d). Block prefix label did not hide typedef", + `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_fork_prefix_label_name.v b/ivtest/ivltests/sv_type_identifier_fork_prefix_label_name.v new file mode 100644 index 000000000..7fb891afe --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_fork_prefix_label_name.v @@ -0,0 +1,29 @@ +// Check that fork prefix labels can shadow type identifiers. + +typedef int T; + +module test; + + reg failed; + reg value; + + initial begin + failed = 1'b0; + value = 1'b0; + + T: fork + value = 1'b1; + join : T + + if (value !== 1'b1) begin + $display("FAILED(%0d). Fork prefix label did not hide typedef", + `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 47dcde1e3..35f4ec74f 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -82,6 +82,7 @@ br_gh1256b vvp_tests/br_gh1256b.json br_gh1258a vvp_tests/br_gh1258a.json br_gh1258b vvp_tests/br_gh1258b.json br_gh1286 vvp_tests/br_gh1286.json +br_gh1321 vvp_tests/br_gh1321.json br_gh1323 vvp_tests/br_gh1323.json br_gh1384 vvp_tests/br_gh1384.json br_gh1385 vvp_tests/br_gh1385.json @@ -264,6 +265,9 @@ sv_array_cassign_single_fail1 vvp_tests/sv_array_cassign_single_fail1.json sv_assign_pattern_auto_force_fail vvp_tests/sv_assign_pattern_auto_force_fail.json sv_automatic_2state vvp_tests/sv_automatic_2state.json sv_bad_member_lval_proc_fail vvp_tests/sv_bad_member_lval_proc_fail.json +sv_block_prefix_label vvp_tests/sv_block_prefix_label.json +sv_block_prefix_name_diff_fail vvp_tests/sv_block_prefix_name_diff_fail.json +sv_block_prefix_name_same_fail vvp_tests/sv_block_prefix_name_same_fail.json sv_byte_array_string1 vvp_tests/sv_byte_array_string1.json sv_byte_array_string2 vvp_tests/sv_byte_array_string2.json sv_byte_array_string3 vvp_tests/sv_byte_array_string3.json @@ -320,6 +324,9 @@ sv_default_port_value2 vvp_tests/sv_default_port_value2.json sv_default_port_value3 vvp_tests/sv_default_port_value3.json sv_foreach9 vvp_tests/sv_foreach9.json sv_foreach10 vvp_tests/sv_foreach10.json +sv_fork_prefix_label vvp_tests/sv_fork_prefix_label.json +sv_fork_prefix_name_diff_fail vvp_tests/sv_fork_prefix_name_diff_fail.json +sv_fork_prefix_name_same_fail vvp_tests/sv_fork_prefix_name_same_fail.json sv_interface vvp_tests/sv_interface.json sv_interface_identifier_block_name vvp_tests/sv_interface_identifier_block_name.json sv_interface_identifier_instance_name vvp_tests/sv_interface_identifier_instance_name.json @@ -420,6 +427,7 @@ sv_type_identifier_assert_label vvp_tests/sv_type_identifier_assert_label.json sv_type_identifier_attribute_name vvp_tests/sv_type_identifier_attribute_name.json sv_type_identifier_attribute_target vvp_tests/sv_type_identifier_attribute_target.json sv_type_identifier_block_label_name vvp_tests/sv_type_identifier_block_label_name.json +sv_type_identifier_block_prefix_label_name vvp_tests/sv_type_identifier_block_prefix_label_name.json sv_type_identifier_config_name vvp_tests/sv_type_identifier_config_name.json sv_type_identifier_discipline_name vvp_tests/sv_type_identifier_discipline_name.json sv_type_identifier_discipline_nature_ref vvp_tests/sv_type_identifier_discipline_nature_ref.json @@ -429,6 +437,7 @@ sv_type_identifier_for_name vvp_tests/sv_type_identifier_for_name.json sv_type_identifier_foreach_array_name vvp_tests/sv_type_identifier_foreach_array_name.json sv_type_identifier_foreach_name vvp_tests/sv_type_identifier_foreach_name.json sv_type_identifier_fork_label_name vvp_tests/sv_type_identifier_fork_label_name.json +sv_type_identifier_fork_prefix_label_name vvp_tests/sv_type_identifier_fork_prefix_label_name.json sv_type_identifier_function_name vvp_tests/sv_type_identifier_function_name.json sv_type_identifier_generate_label_name vvp_tests/sv_type_identifier_generate_label_name.json sv_type_identifier_genvar_name vvp_tests/sv_type_identifier_genvar_name.json diff --git a/ivtest/vvp_tests/br_gh1321.json b/ivtest/vvp_tests/br_gh1321.json new file mode 100644 index 000000000..b7ce23ed3 --- /dev/null +++ b/ivtest/vvp_tests/br_gh1321.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "br_gh1321.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_block_prefix_label.json b/ivtest/vvp_tests/sv_block_prefix_label.json new file mode 100644 index 000000000..bc9d4d883 --- /dev/null +++ b/ivtest/vvp_tests/sv_block_prefix_label.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_block_prefix_label.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_block_prefix_name_diff_fail.json b/ivtest/vvp_tests/sv_block_prefix_name_diff_fail.json new file mode 100644 index 000000000..2ad2b8dc8 --- /dev/null +++ b/ivtest/vvp_tests/sv_block_prefix_name_diff_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_block_prefix_name_diff_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_block_prefix_name_same_fail.json b/ivtest/vvp_tests/sv_block_prefix_name_same_fail.json new file mode 100644 index 000000000..3be3de32d --- /dev/null +++ b/ivtest/vvp_tests/sv_block_prefix_name_same_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_block_prefix_name_same_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_fork_prefix_label.json b/ivtest/vvp_tests/sv_fork_prefix_label.json new file mode 100644 index 000000000..95fc062fe --- /dev/null +++ b/ivtest/vvp_tests/sv_fork_prefix_label.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_fork_prefix_label.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "join_any, join_none, and wait fork are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_fork_prefix_name_diff_fail.json b/ivtest/vvp_tests/sv_fork_prefix_name_diff_fail.json new file mode 100644 index 000000000..76b98ee30 --- /dev/null +++ b/ivtest/vvp_tests/sv_fork_prefix_name_diff_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_fork_prefix_name_diff_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_fork_prefix_name_same_fail.json b/ivtest/vvp_tests/sv_fork_prefix_name_same_fail.json new file mode 100644 index 000000000..75ffe2a93 --- /dev/null +++ b/ivtest/vvp_tests/sv_fork_prefix_name_same_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_fork_prefix_name_same_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_block_prefix_label_name.json b/ivtest/vvp_tests/sv_type_identifier_block_prefix_label_name.json new file mode 100644 index 000000000..5db78d208 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_block_prefix_label_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_block_prefix_label_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_fork_prefix_label_name.json b/ivtest/vvp_tests/sv_type_identifier_fork_prefix_label_name.json new file mode 100644 index 000000000..b19d85738 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_fork_prefix_label_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_fork_prefix_label_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/parse.y b/parse.y index 7263b7487..9d4a6b45d 100644 --- a/parse.y +++ b/parse.y @@ -594,6 +594,71 @@ static void procedural_item_list_add_declaration(const YYLTYPE&loc, procedural_item_list_add_ports(list, ports); } +static PBlock *pform_start_block(const YYLTYPE&loc, const char *name, + PBlock::BL_TYPE block_type) +{ + auto block = pform_push_block_scope(loc, name, block_type); + current_block_stack.push(block); + + return block; +} + +static char *pform_start_block_with_labels( + const YYLTYPE&loc, const YYLTYPE&name_loc, + char *prefix_label, char *block_name, + std::list *attributes, + PBlock::BL_TYPE block_type) +{ + std::unique_ptr prefix_label_ptr(prefix_label); + std::unique_ptr block_name_ptr(block_name); + + if (prefix_label_ptr && block_name_ptr) { + yyerror(name_loc, + "error: A block cannot have both a prefix label and a block name."); + } + + const char *name = block_name_ptr ? block_name_ptr.get() + : prefix_label_ptr.get(); + auto block = pform_start_block(loc, name, block_type); + pform_bind_attributes(block->attributes, attributes); + + return block_name_ptr ? block_name_ptr.release() + : prefix_label_ptr.release(); +} + +static PBlock *pform_finish_block(const YYLTYPE&block_loc, + const YYLTYPE&end_loc, const char *type, + char *raw_name, char *end_label, + PBlock::BL_TYPE block_type, + procedural_item_list_t *raw_items) +{ + std::unique_ptr name_ptr(raw_name); + std::unique_ptr items(raw_items); + + const char *name = name_ptr.get(); + bool keep_scope = name || items->has_decls; + pform_pop_block_scope(keep_scope); + assert(! current_block_stack.empty()); + auto block = current_block_stack.top(); + current_block_stack.pop(); + + if (keep_scope) { + if (block_type != PBlock::BL_SEQ) + block->set_join_type(block_type); + } else { + delete block; + block = new PBlock(block_type); + FILE_NAME(block, block_loc); + } + + if (items->statements) + block->set_statement(*items->statements); + + check_end_label(end_loc, type, name, end_label); + + return block; +} + static void port_declaration_context_init(void) { port_declaration_context.port_type = NetNet::PINOUT; @@ -756,6 +821,11 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, std::vector*statement_list; struct procedural_item_list_t *procedural_item_list; + struct { + char *label; + std::list *attributes; + } block_prefix; + decl_assignment_t*decl_assignment; std::list*decl_assignments; @@ -1046,6 +1116,8 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type block_item_or_statement_list_opt %type tf_item_or_statement_list %type tf_item_or_statement_list_opt +%type block_prefix_opt +%type sequential_block_start parallel_block_start %type analog_statement @@ -7292,6 +7364,34 @@ subroutine_call } ; +block_prefix_opt + : /* empty */ + { $$.label = nullptr; + $$.attributes = nullptr; + } + | identifier_name ':' attribute_list_opt + { pform_requires_sv(@1, "Block prefix label"); + $$.label = $1; + $$.attributes = $3; + } + ; + +sequential_block_start + : block_prefix_opt K_begin label_opt + { $$ = pform_start_block_with_labels(@2, @3, $1.label, $3, + $1.attributes, PBlock::BL_SEQ); + @$ = @2; + } + ; + +parallel_block_start + : block_prefix_opt K_fork label_opt + { $$ = pform_start_block_with_labels(@2, @3, $1.label, $3, + $1.attributes, PBlock::BL_PAR); + @$ = @2; + } + ; + statement_item /* This is roughly statement_item in the LRM */ /* assign and deassign statements are procedural code to do @@ -7333,29 +7433,12 @@ statement_item /* This is roughly statement_item in the LRM */ the declarations. The scope is popped at the end of the block. */ /* In SystemVerilog an unnamed block can contain variable declarations. */ - | K_begin label_opt - { PBlock*tmp = pform_push_block_scope(@1, $2, PBlock::BL_SEQ); - current_block_stack.push(tmp); - } - block_item_or_statement_list_opt K_end label_opt - { std::unique_ptr items($4); - if (!$2 && items->has_decls) { + | sequential_block_start block_item_or_statement_list_opt K_end label_opt + { if (!$1 && $2->has_decls) { pform_block_decls_requires_sv(); } - bool keep_scope = $2 || items->has_decls; - pform_pop_block_scope(keep_scope); - assert(! current_block_stack.empty()); - auto tmp = current_block_stack.top(); - current_block_stack.pop(); - if (!keep_scope) { - delete tmp; - tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @1); - } - if (items->statements) tmp->set_statement(*items->statements); - check_end_label(@6, "block", $2, $6); - delete[]$2; - $$ = tmp; + $$ = pform_finish_block(@1, @4, "block", $1, $4, + PBlock::BL_SEQ, $2); } /* fork-join blocks are very similar to begin-end blocks. In fact, @@ -7364,31 +7447,11 @@ statement_item /* This is roughly statement_item in the LRM */ code generator can do the right thing. */ /* In SystemVerilog an unnamed block can contain variable declarations. */ - | K_fork label_opt - { PBlock*tmp = pform_push_block_scope(@1, $2, PBlock::BL_PAR); - current_block_stack.push(tmp); - } - block_item_or_statement_list_opt join_keyword label_opt - { std::unique_ptr items($4); - if (!$2 && items->has_decls) { - pform_requires_sv(@4, "Variable declaration in unnamed block"); + | parallel_block_start block_item_or_statement_list_opt join_keyword label_opt + { if (!$1 && $2->has_decls) { + pform_requires_sv(@2, "Variable declaration in unnamed block"); } - bool keep_scope = $2 || items->has_decls; - pform_pop_block_scope(keep_scope); - assert(! current_block_stack.empty()); - auto tmp = current_block_stack.top(); - current_block_stack.pop(); - if (keep_scope) { - tmp->set_join_type($5); - } else { - delete tmp; - tmp = new PBlock($5); - FILE_NAME(tmp, @1); - } - if (items->statements) tmp->set_statement(*items->statements); - check_end_label(@6, "fork", $2, $6); - delete[]$2; - $$ = tmp; + $$ = pform_finish_block(@1, @4, "fork", $1, $4, $3, $2); } | K_disable hierarchy_identifier ';'