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