Merge pull request #1445 from larsclausen/procedural-block-prefix-label
Support prefix labels on procedural blocks
This commit is contained in:
commit
31d1850bc8
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// Check that different prefix and post-begin labels are rejected.
|
||||
|
||||
module test;
|
||||
initial LABEL_A: begin : LABEL_B
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// Check that matching prefix and post-begin labels are rejected.
|
||||
|
||||
module test;
|
||||
initial LABEL: begin : LABEL
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// Check that different prefix and post-fork labels are rejected.
|
||||
|
||||
module test;
|
||||
initial LABEL_A: fork : LABEL_B
|
||||
join
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// Check that matching prefix and post-fork labels are rejected.
|
||||
|
||||
module test;
|
||||
initial LABEL: fork : LABEL
|
||||
join
|
||||
endmodule
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "br_gh1321.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_block_prefix_label.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_block_prefix_name_diff_fail.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_block_prefix_name_same_fail.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_fork_prefix_name_diff_fail.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_fork_prefix_name_same_fail.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_type_identifier_block_prefix_label_name.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_type_identifier_fork_prefix_label_name.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
153
parse.y
153
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<named_pexpr_t> *attributes,
|
||||
PBlock::BL_TYPE block_type)
|
||||
{
|
||||
std::unique_ptr<char[]> prefix_label_ptr(prefix_label);
|
||||
std::unique_ptr<char[]> 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<char[]> name_ptr(raw_name);
|
||||
std::unique_ptr<procedural_item_list_t> 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*>*statement_list;
|
||||
struct procedural_item_list_t *procedural_item_list;
|
||||
|
||||
struct {
|
||||
char *label;
|
||||
std::list<named_pexpr_t> *attributes;
|
||||
} block_prefix;
|
||||
|
||||
decl_assignment_t*decl_assignment;
|
||||
std::list<decl_assignment_t*>*decl_assignments;
|
||||
|
||||
|
|
@ -1046,6 +1116,8 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
|
|||
%type <procedural_item_list> block_item_or_statement_list_opt
|
||||
%type <procedural_item_list> tf_item_or_statement_list
|
||||
%type <procedural_item_list> tf_item_or_statement_list_opt
|
||||
%type <block_prefix> block_prefix_opt
|
||||
%type <text> sequential_block_start parallel_block_start
|
||||
|
||||
%type <statement> 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<procedural_item_list_t> 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<procedural_item_list_t> 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 ';'
|
||||
|
|
|
|||
Loading…
Reference in New Issue