1

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)?

user2224350
  • 2,262
  • 5
  • 28
  • 54
  • *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 https://stackoverflow.com/questions/15718192/verilog-sequence-of-non-blocking-assignments – Eugene Sh. Aug 08 '17 at 16:51
  • Sorry just a typo – user2224350 Aug 08 '17 at 17:19

1 Answers1

1

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.

Serge
  • 11,616
  • 3
  • 18
  • 28
  • So the if (wreg)-block is executed one cycle after wreg is set to 1 in the second always-block, right? – user2224350 Aug 08 '17 at 19:53
  • it is the same simulation cycle but different buckets within the same cycle. – Serge Aug 08 '17 at 19:55
  • But, lets say we start with wreg = 0 and in the first cycle wreg is set to 1: 1. cycle: [1. if(wreg) is false, 2. wreg<=0, wreg<=1] 2. cycle: [1. if(wreg) is true, 2. wreg<=0, ... ] Is this correct? Then the if(wreg)-block would be delayed to the event which causes wreg<=1 – user2224350 Aug 08 '17 at 20:08
  • yes. it is correct. This how the flopped design works in silicon. The second statement represents the flop on wreg. – Serge Aug 08 '17 at 22:00