verilogsystem-verilogxilinxvivado

`$display` cannot display right value in vivado


`timescale 1ns / 1ps
module factorial(
input  i_n,
output reg  res,
input  i_clk
    );
integer j;
initial
begin:a
for (j=1;j<=i_n;j=j+1)begin
res<=res*j;
end

res<='d3;
$display("res is %f",res);//as res is 'd3,should display 3.0
end
endmodule

module u_f;
reg  i_n;
wire  res;
reg i_clk;
initial
begin
i_n<=3;
i_clk=1'b0;
end

 always 
 begin
 #10 i_clk<=~i_clk;
 end
factorial  u2(
    .i_n(i_n),
    .i_clk(i_clk),
    .res(res)
    );
   
endmodule

Above verilog script output:

Time resolution is 1 ps
res is 0.000000

The correct output should be res is 3.000000 but display res is 0.000000,where is the problem?


Solution

  • The output of 0.000 is correct. res has not be initialized so its value is X and the %f casts the print to floating-point which becomes 0.000.

    res<='d3; is a non-blocking assignment (NBA). It does not updated res immediately. It schedules res to be assigned to 3 at the end of the time-step. $display("res is %f",res); will print res current value; not its scheduled value.

    Using blocking assignment (ie: res='d3) will make $display("res is %f",res); print 3.00000.

    Alternatively you can use keep the non-blocking and replaces $display with $strobe. $strobe is similar to $display but prints after the NBA.

    res<='d3;
    $stobe("res is %f from strobe",res);
    $display("res is %f from display",res);
    

    Outputs: (display is printed before strobe even though strobe was scheduled first)

    res is 0.000000 from display
    res is 3.000000 from strobe
    

    FYI this initial block and for-loop will not work as you intend:

    initial begin:a
      for (j=1;j<=i_n;j=j+1)begin
        res<=res*j;
      end
    end