Assertion for parameterized module instances

Thank you for your great support.

I have a scenario, where there is a module named exp, with default defined parameter value. Now at the time of instantiation of that module exp, user/developer should only pass the default value of the parameter (of module exp) and not any other value. If someone try to instantiate the module with any value apart from the default defined parameter value(in the module exp) then assertion should fire to kill the simulation. I used below code for this assertion, but not sure if this is the best way to handle this?

module exp #(WIDTH=10) (input bit a);
  initial begin
    $display("WIDTH = %d",WIDTH);
    ap_wh: assert(WIDTH == 10); 
  end
endmodule : exp

module top();
    exp #(.WIDTH(10)) exp_i1 (.a(1'b1));
    exp #(.WIDTH(15)) exp_i2 (.a(1'b1));
    exp #(.WIDTH(20)) exp_i3 (.a(1'b1));
    initial begin
      $finish();
    end
endmodule : top

This works as expected and below is the output,

Output as below,

tool> run
WIDTH = 10
WIDTH = 15
toolsim: *E,ASRT (./assertion.sv,4): (time 0 FS) Assertion top.exp_i2.ap_wh has failed
WIDTH = 20
toolsim: *E,ASRT (./assertion.sv,4): (time 0 FS) Assertion top.exp_i3.ap_wh has failed
Simulation complete via $finish(1) at time 0 FS + 0
./assertion.sv:13 $finish();
tool> exit

Thanking you.

Best regards,
Mega

In reply to megamind:

Seems very strange to declare a parameter and not allow it to be overwritten—that is their whole point. There is a localparam construct that cannot be overwritten.

But if you really have some reason to code you parameter this way, you can use the $fatal system task to end the simulation as the action block of your assertion, to you can use a generate block $fatal to end at elaboration.

module exp #(WIDTH=10) (input bit a);
  initial begin
    $display("WIDTH = %d",WIDTH);
  end
// this is a generate-if
 if (WIDTH == 10) $fatal(0,"Width != 10");
endmodule : exp

In reply to dave_59:

Thank you Dave, below code you shared(one correction != 10), worked better than mine,

module exp #(WIDTH=10) (input bit a);
  initial begin
    $display("WIDTH = %d",WIDTH);
  end
 //this is a generate-if
 if (WIDTH != 10) $fatal(0,"Width != 10");
endmodule : exp

Further, I did not understood one thing here,

// this is a generate-if
if (WIDTH == 10) $fatal(0,“Width != 10”);

What do you mean by this? when we keep outside of initial begin , is that generate-if ? how that works ? do you have some good link which I can refer for both localparams and generate.

In reply to megamind:

Further, I did not understood one thing here,
// this is a generate-if
if (WIDTH == 10) $fatal(0,“Width != 10”);
What do you mean by this? when we keep outside of initial begin , is that generate-if ? how that works ? do you have some good link which I can refer for both localparams and generate.

The $fatal() here is an elaboration system task (Section 20.11 of the SystemVerilog standard). These tasks are subtly different than similar runtime tasks, in that they occur (as the name implies) at elaboration time instead of runtime. They are very useful for implementing parameter value checking as Dave’s example shows, and as it appears you’re desiring. We use them extensively in our designs for this purpose - checking the validity of (sets) of parameter values.

In reply to megamind:

When using if, case, or for outside of a procedural block, they are considered generate statements. See section 27. Generate constructs in the IEEE 1800-2017 SystemVerilog LRM

Some example of localparams. Only WIDTH may be overridden

module exp #(int WIDTH=10, localparam real HALFWIDTH = WIDTH/2.0) (input bit a);
localparam real THIRDWIDTH =WIDTH/3.0;
parameter int DOUBLEWIDTH =WIDTH*2; // considered the same a localparam when parameters
                                    // are in the module header
  initial begin
    $display("WIDTH = %d",WIDTH);
  end
 //this is a generate-if
 if (WIDTH != 10) $fatal(0,"Width != 10");
endmodule : exp

In reply to dave_59:

Thank you Dave and Mark.