mirror of https://github.com/YosysHQ/yosys.git
verilog: Support void functions
The difference between void functions and tasks is that always_comb's implicit sensitivity list behaves as if functions were inlined, but ignores signals read only in tasks. This only matters for event based simulation, and for synthesis we can treat a void function like a task.
This commit is contained in:
parent
61da330a38
commit
fb1c2be76b
|
@ -276,6 +276,7 @@ TIME_SCALE_SUFFIX [munpf]?s
|
|||
"byte" { SV_KEYWORD(TOK_BYTE); }
|
||||
"shortint" { SV_KEYWORD(TOK_SHORTINT); }
|
||||
"longint" { SV_KEYWORD(TOK_LONGINT); }
|
||||
"void" { SV_KEYWORD(TOK_VOID); }
|
||||
|
||||
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||
"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||
|
|
|
@ -372,7 +372,7 @@ static void rewriteGenForDeclInit(AstNode *loop)
|
|||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
|
||||
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
|
||||
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_UNIQUE0 TOK_PRIORITY
|
||||
%token TOK_STRUCT TOK_PACKED TOK_UNSIGNED TOK_INT TOK_BYTE TOK_SHORTINT TOK_LONGINT TOK_UNION
|
||||
%token TOK_STRUCT TOK_PACKED TOK_UNSIGNED TOK_INT TOK_BYTE TOK_SHORTINT TOK_LONGINT TOK_VOID TOK_UNION
|
||||
%token TOK_BIT_OR_ASSIGN TOK_BIT_AND_ASSIGN TOK_BIT_XOR_ASSIGN TOK_ADD_ASSIGN
|
||||
%token TOK_SUB_ASSIGN TOK_DIV_ASSIGN TOK_MOD_ASSIGN TOK_MUL_ASSIGN
|
||||
%token TOK_SHL_ASSIGN TOK_SHR_ASSIGN TOK_SSHL_ASSIGN TOK_SSHR_ASSIGN
|
||||
|
@ -1020,6 +1020,23 @@ task_func_decl:
|
|||
current_function_or_task = NULL;
|
||||
ast_stack.pop_back();
|
||||
} |
|
||||
attr TOK_FUNCTION opt_automatic TOK_VOID TOK_ID {
|
||||
// The difference between void functions and tasks is that
|
||||
// always_comb's implicit sensitivity list behaves as if functions were
|
||||
// inlined, but ignores signals read only in tasks. This only matters
|
||||
// for event based simulation, and for synthesis we can treat a void
|
||||
// function like a task.
|
||||
current_function_or_task = new AstNode(AST_TASK);
|
||||
current_function_or_task->str = *$5;
|
||||
append_attr(current_function_or_task, $1);
|
||||
ast_stack.back()->children.push_back(current_function_or_task);
|
||||
ast_stack.push_back(current_function_or_task);
|
||||
current_function_or_task_port_id = 1;
|
||||
delete $5;
|
||||
} task_func_args_opt ';' task_func_body TOK_ENDFUNCTION {
|
||||
current_function_or_task = NULL;
|
||||
ast_stack.pop_back();
|
||||
} |
|
||||
attr TOK_FUNCTION opt_automatic func_return_type TOK_ID {
|
||||
current_function_or_task = new AstNode(AST_FUNCTION);
|
||||
current_function_or_task->str = *$5;
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
read_verilog -sv <<EOF
|
||||
module top_func(input [7:0] a, output [7:0] b);
|
||||
function automatic void clear_b; b = 0; endfunction
|
||||
function automatic void increment_b; b += a; endfunction
|
||||
always_comb begin
|
||||
clear_b;
|
||||
increment_b;
|
||||
increment_b;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module top_task(input [7:0] a, output [7:0] b);
|
||||
task automatic clear_b; b = 0; endtask
|
||||
task automatic increment_b; b += a; endtask
|
||||
always_comb begin
|
||||
clear_b;
|
||||
increment_b;
|
||||
increment_b;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module top_inline(input [7:0] a, output [7:0] b);
|
||||
always_comb begin
|
||||
b = 0;
|
||||
b += a;
|
||||
b += a;
|
||||
end
|
||||
endmodule
|
||||
EOF
|
||||
|
||||
prep
|
||||
|
||||
miter -equiv -flatten -make_assert top_inline top_task miter_task
|
||||
sat -verify -prove-asserts miter_task
|
||||
|
||||
miter -equiv -flatten -make_assert top_inline top_func miter_func
|
||||
sat -verify -prove-asserts miter_func
|
Loading…
Reference in New Issue