property p_port_orientation_chk (logic disable_cond, logic rst, logic cond, logic valid, int min_dly=0, max_dly=0, int reg_no, logic port);
I want to use a generate statement to loop through an array of values so that I can check multiple ports without the need to explicitly instantiate N instances. So I’m looking at something like the following:
genvar i;
generate
for (i=0; i<num_ports / 2; i++) begin
portno = expected_port_orientation ? i + num_ports / 2 : i;
ap_p_rt_port_orientation_check_upp_i : assert property (p_port_orientation_chk(disable_chk[portno], rst_n, cond[portno], valid[portno], 0, 1, portno, UPP));
else
`uvm_error($sformatf("ap_p_rt_port_orientation_check_upp_%s", i),$sformatf("%0t : Expected 'b%b Actual 'h%0h", $realtime, UPP, int_var[portno].port_orientation))
end
endgenerate
I’m using the variable portno to facilitate passing parameters to the parametrized property, but the code doesn’t compile and the failure is:
expecting a left parenthesis ('(') [12.1.2][7.1(IEEE)].
pointing to the portno variable (which is an int).
I could clearly substitute the portno value with the expression but it looks tedious and ugly. Is there any other way I could achieve that?
The problem is the code inside the generate loop gets unrolled and expanded into the module where the generate block exists. You wind up with multiple procedural assignments to portno where a procedural statement is not allowed. A generate block is not procedural.
What you can do is declare a parameter inside the loop.
for (genvar i=0; i<num_ports / 2; i++) begin : each_port
parameter int portno = expected_port_orientation ? i + num_ports / 2 : i;
ap_p_rt_port_orientation_check_upp_i : assert property (p_port_orientation_chk(disable_chk[portno], rst_n, cond[portno], valid[portno], 0, 1, portno, UPP));
else
`uvm_error($sformatf("ap_p_rt_port_orientation_check_upp_%s", i),$sformatf("%0t : Expected 'b%b Actual 'h%0h", $realtime, UPP, int_var[portno].port_orientation))
end
It would really help to provide a complete example, at least declarations for all variables used in the example.
I’m guessing expected_port_orientation is a variable that you either set at time 0, or it changes over time. So portno has to be defined as a variable. And just like the parameter, each iteration of the loop creates a local declaration that needs an assignment.
for (genvar i=0; i<num_ports / 2; i++) begin : each_port
int portno;
assign portno = expected_port_orientation ? i + num_ports / 2 : i;
ap_p_rt_port_orientation_check_upp_i : assert property (p_port_orientation_chk(disable_chk[portno], rst_n, cond[portno], valid[portno], 0, 1, portno, UPP));
else
`uvm_error($sformatf("ap_p_rt_port_orientation_check_upp_%s", i),$sformatf("%0t : Expected 'b%b Actual 'h%0h", $realtime, UPP, int_var[portno].port_orientation))
end
BTW, declaring a `define macro inside a loop gives you the false impression that it evaluates each iteration, which is not the case.
I’ve finally adopted your latest solution and it worked. As for the define approach, indeed the macro expansion is going to happen at compilation time , while the generate is going to be unfolded during elaboration AFAIK.
I did not know you could create a variable internal to the generate, I had the impression memory allocation is done at compile time and not at elaboration time, but clearly my understanding was flawed.