system-verilogcadence

Function optional parameters not in sensitivity list when called from assign


I think I've figured out why this happens, but I would like to confirm it, and to see if there is a better solution.

Consider the following module which has a function where the default for one of the parameters is bound to some register inside the module:

module m;
  reg a, b;
  wire out;
  function f1 (input x, input y = b);
    f1 = x & y;
  endfunction :f1

  // ...
  assign out = f1(a);
endmodule

The issue that I'm seeing (which wasn't easy to track down) is that in this case, the sensitivity list of the assignment only has a. So if b changes, and then a changes, out will be properly updated. However, if a changes, and then b changes, because b isn't in the sensitivity list for the assignment of out, out will not be updated and will still be set to the old value.

Is there a preferred way to add b to the sensitivity list so out will be updated when it changes?

I see a few possible options:

  1. Just explicitly add the second argument: f1(a, b)
  2. Use a continuous assignment block always_comb out = f1(a) or always @(*) out=f1(a)
  3. Use an explicit sensitivity list always @(a, b) out = f1(a)

Personally I think option 1 is the best (even though it would replicate the optional parameters every location it is called), but I'm curious if there are other explanations, or if there is a better solution.


Solution

  • Option 1 defeats the default argument feature. You would have to make sure nobody supplies a default in the declaration so you don't run into this problem again.

    Option 3 is a not an option anymore as you discovered—it is a nightmare to debug.

    The always_comb construct was specifically designed for this kind of coding style. In fact, people wanted to write functions with no inputs or outputs simply as a code structuring mechanism making the code easier to manage.

    always_comb begin
              phase_one_stuff;
              phase_two_stuff;
              if (mode==A)
                   mode_A_stuff;
              else
                   mode_B_stuff;
              phase_three_stuff;
           end
    

    Do not use @(*) in SystemVerilog. always_comb replaces it and has the benefit of dealing with time 0 initial values that @(*) may not be sensitive to.