I think I may be mis-understanding how the initial
block works in Verilog.
I have the following bit of code driving hardware sprites:
// horizontal and vertical screen position of letters
logic signed [CORDW-1:0] spr_x[SPR_CNT];
logic signed [CORDW-1:0] spr_y;
initial begin
spr_x[0] = 20;
spr_x[1] = spr_x[0] + 30;
spr_x[2] = spr_x[1] + 30;
spr_x[3] = spr_x[2] + 30;
spr_x[4] = spr_x[3] + 30;
spr_y = 100;
...
end
always_comb begin
spr_y = 16'd100;
spr_x[0] = 20;
spr_x[1] = spr_x[0] + 30;
spr_x[2] = spr_x[1] + 30;
spr_x[3] = spr_x[2] + 30;
//spr_x[4] = spr_x[3] + 30;
...
end
genvar m; // for looping over sprite instances
generate for (m = 0; m < SPR_CNT; m = m + 1) begin : sprite_gen
sprite spr0 (
.i_reset_n(i_reset_n),
.i_clock(i_pixel_clock),
.i_spr_y(spr_y),
.i_spr_x(spr_x[m]),
);
end endgenerate
I was under the impression that values assigned inside the initial
block would stick because they are assigned to logic
types which keep their values.
In the example above though my last sprite (index 4) does not display at the correct x position because the spr_x
value is not refreshed in always_comb
.
I'm surely missing or misunderstanding something here.
Do not use an initial
block to drive variables for a synthesis build. Doing so results in unpredictable behavior. Use parameter
or localparam
to make the assignments instead.
The post has multiple drivers (driven in two processes) on spr_x at t=0. Its not clear which process will win.
In simulation, the always_comb
block gets called at t=0. Its not possible to know which process (initial
or always_comb
) executes first.
Declaring a 2nd variable spr_x_comb to drive spr_x using parameter
or localparam
, because they are set during elaboration prior to t=0 in simulation.
Use variable spr_x_comb to fan into the generate
block.
Get rid of the assignments to spr_x in the initial
block.
Generally, do not set values of variables in an initial
block for synthesis workflows. Define parameter
and localparam
statements to make these types of assignments.