1

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.

techdude
  • 1,334
  • 20
  • 29

1 Answers1

2

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.

dave_59
  • 39,096
  • 3
  • 24
  • 63
  • Yeah 3 is not something I use personally because it makes it deliciously easy to get stuff out of sync. @(*) is just included for completeness, but always_comb would be the preferred option of the two. – techdude Jan 18 '20 at 02:52
  • In this application the function is a true constant function, so 2 is probably the best option as it requires no duplication of functionality. – techdude Jan 18 '20 at 02:54