diff --git a/ivtest/ivltests/always_comb_void_func.v b/ivtest/ivltests/always_comb_void_func.v new file mode 100644 index 000000000..0272393b9 --- /dev/null +++ b/ivtest/ivltests/always_comb_void_func.v @@ -0,0 +1,51 @@ +// Check that variables referenced in a void function contribute to the +// sensitivity list of a always_comb block. + +module top; + logic passed; + logic [7:0] value; + integer counter; + + function automatic void count(bit what); + counter = 0; + for (integer i = 0; i < $bits(value); i++) begin + if (value[i] == what) + counter += 1; + end + endfunction + + always_comb begin + count(1'b1); + end + + initial begin + passed = 1'b1; + + value = 8'b0000_0000; + #1; + if (counter !== 0) begin + $display("Expected 0, got %d", counter); + passed = 1'b0; + end + + value = 8'b0011_1100; + #1; + if (counter !== 4) begin + $display("Expected 4, got %d", counter); + passed = 1'b0; + end + + value = 8'b1011_1101; + #1; + if (counter !== 6) begin + $display("Expected 6, got %d", counter); + passed = 1'b0; + end + + if (passed) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 168f4b82c..a0eb42a2f 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -76,6 +76,7 @@ always_comb_fail4 CE,-g2005-sv ivltests always_comb_no_sens nornal,-g2005-sv ivltests gold=always_comb_no_sens.gold always_comb_rfunc nornal,-g2005-sv ivltests always_comb_trig normal,-g2005-sv ivltests +always_comb_void_func normal,-g2005-sv ivltests always_comb_warn normal,-g2005-sv ivltests gold=always_comb_warn.gold always_ff normal,-g2005-sv ivltests always_ff_fail CE,-g2005-sv ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index abb56ce33..87407d155 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -69,6 +69,7 @@ # Verilog 95 does not support automatic tasks or functions. always_comb_rfunc CE ivltests +always_comb_void_func CE ivltests automatic_error11 CE ivltests automatic_error12 CE ivltests automatic_error13 CE ivltests diff --git a/net_nex_input.cc b/net_nex_input.cc index 7d68229ef..8c45056c8 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -255,6 +255,30 @@ NexusSet* NetETernary::nex_input(bool rem_out, bool always_sens, bool nested_fun return result; } +// Get the contribution of a function call in a always_comb block +static void func_always_sens(NetFuncDef *func, NexusSet *result, + bool rem_out, bool nested_func) +{ + // Avoid recursive function calls. + static set func_set; + if (!nested_func) + func_set.clear(); + + if (!func_set.insert(func).second) + return; + + std::unique_ptr tmp(func->proc()->nex_input(rem_out, true, true)); + // Remove the function inputs + std::unique_ptr in(new NexusSet); + for (unsigned idx = 0; idx < func->port_count(); idx++) { + NetNet *net = func->port(idx); + assert(net->pin_count() == 1); + in->add(net->pin(0).nexus(), 0, net->vector_width()); + } + tmp->rem(*in); + result->add(*tmp); +} + NexusSet* NetEUFunc::nex_input(bool rem_out, bool always_sens, bool nested_func) const { NexusSet*result = new NexusSet; @@ -265,31 +289,8 @@ NexusSet* NetEUFunc::nex_input(bool rem_out, bool always_sens, bool nested_func) delete tmp; } - if (always_sens) { - NetFuncDef*func = func_->func_def(); - - // Avoid recursive function calls. - static set func_set; - if (!nested_func) - func_set.clear(); - - if (!func_set.insert(func).second) - return result; - - NexusSet*tmp = func->proc()->nex_input(rem_out, always_sens, true); - // Remove the function inputs - NexusSet*in = new NexusSet; - for (unsigned idx = 0 ; idx < func->port_count() ; idx += 1) { - NetNet*net = func->port(idx); - assert(net->pin_count() == 1); - in->add(net->pin(0).nexus(), 0, net->vector_width()); - } - tmp->rem(*in); - delete in; - - result->add(*tmp); - delete tmp; - } + if (always_sens) + func_always_sens(func_->func_def(), result, rem_out, nested_func); return result; } @@ -613,9 +614,18 @@ NexusSet* NetSTask::nex_input(bool rem_out, bool always_sens, bool nested_func) * parameters to consider, because the compiler already removed them * and converted them to blocking assignments. */ -NexusSet* NetUTask::nex_input(bool, bool, bool) const +NexusSet* NetUTask::nex_input(bool rem_out, bool always_sens, bool nested_func) const { - return new NexusSet; + NexusSet *result = new NexusSet; + + /* + * Let the contents of void functions contribute to the sensitivity list + * of always_comb blocks + */ + if (always_sens && task_->type() == NetScope::FUNC) + func_always_sens(task_->func_def(), result, rem_out, nested_func); + + return result; } NexusSet* NetWhile::nex_input(bool rem_out, bool always_sens, bool nested_func) const