1
votes

I stumpled a few times about some code which seems to be perfectly normal verilog-style but looks rather dangerous to me (I'm new to Verilog). It's always about concurrent always-blocks and/or assignments. Here is an example:

module some(input clk_i);

..
    module ram(
          input   wire                a_clk,
          input   wire                a_wr,
          input   wire    [ADDR-1:0]  a_addr,
          input   wire    [DATA-1:0]  a_din,
          output  reg     [DATA-1:0]  a_dout,
    );

    reg [DATA-1:0] mem [(2**ADDR)-1:0];


    always @(posedge a_clk) begin
          a_dout      <= mem[a_addr];
          if(a_wr) begin
              a_dout      <= a_din;
              mem[a_addr] <= a_din;
          end
    end

    endmodule
..

reg wrmem=1'b0;
reg[ADDR-1:0] memaddr;
reg[DATA-1:0] d_in;


ram mem(.a_clk(clk_i),.a_wr(wrmem),.a_addr(memaddr),.a_din(d_in),.a_dout(memout));

..

always @(posedge clk_i) begin
    wrmem <= 1'b0;
        ...
        if(..) begin
            d_in <= sth.
            memaddr <= some address
            wrmem <= 1b'1;
    end
end

endmodule;  

So here we have two concurrent always-blocks. The first (in module "ram") reacts to a clock and 'reg a_wr' being high. In the second one this 'reg' is set to 0 and a few steps later to 1 again. Why does this not lead to arbitrary behaviour of the module "ram" (since the first block doesnt wait until the seconde one finishes)?

1
In the second one this 'reg' is set to 0 and a few steps later to 1 again - where? I see two different names wrmem and wrem. Anyway, looks like duplicate of stackoverflow.com/questions/15718192/…Eugene Sh.
Sorry just a typouser2224350

1 Answers

1
votes

This exactly the reason for non-blocking assignments do exist in verilog.

Verilog scheduling consist of several buckets per delta cycle. Roughly non-blocking assignments are executed in a separate scheduling bucket after blocking assignments.

So, in your case you have 2 things:

always @(posedge clk) 
    if (wreg)
       ...

and

always @(posedge clk)
    wreg <= 0;
    ...

in simulation the first block will use the value of 'wreg' as it existed before the non-blocking bucket is executed, probably 1.

the second block will schedule the update of the wreg to 0 in the non-blocking bucket, not executed yet. So, there is no conflict.

Therefore you are guaranteed to have consistent results during the simulation.