Verilog 中的 Concurrent Always 块
Concurrent Always blocks in Verilog
我对一些看起来完全正常的 verilog 风格但对我来说相当危险的代码感到困惑(我是 Verilog 的新手)。它总是关于并发总是阻塞 and/or 分配。这是一个例子:
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;
所以这里我们有两个并发的 always-blocks。第一个(在模块 "ram" 中)对时钟做出反应并且 'reg a_wr' 为高电平。在第二个中,此 'reg' 设置为 0,几步后再次设置为 1。为什么这不会导致模块 "ram" 的任意行为(因为第一个块不会等到第二个块完成)?
这正是 verilog 中存在非阻塞赋值的原因。
Verilog 调度由每个增量周期的几个桶组成。粗略的非阻塞分配在单独的调度桶中执行 after 阻塞分配。
因此,在您的情况下,您有两件事:
always @(posedge clk)
if (wreg)
...
和
always @(posedge clk)
wreg <= 0;
...
在模拟中,第一个块将使用 'wreg' 的值,因为它在执行非阻塞桶之前存在,可能 1
.
第二个块会调度将非阻塞桶中的wreg更新为0,还没有执行。所以,没有冲突。
因此您可以保证在模拟过程中获得一致的结果。
我对一些看起来完全正常的 verilog 风格但对我来说相当危险的代码感到困惑(我是 Verilog 的新手)。它总是关于并发总是阻塞 and/or 分配。这是一个例子:
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;
所以这里我们有两个并发的 always-blocks。第一个(在模块 "ram" 中)对时钟做出反应并且 'reg a_wr' 为高电平。在第二个中,此 'reg' 设置为 0,几步后再次设置为 1。为什么这不会导致模块 "ram" 的任意行为(因为第一个块不会等到第二个块完成)?
这正是 verilog 中存在非阻塞赋值的原因。
Verilog 调度由每个增量周期的几个桶组成。粗略的非阻塞分配在单独的调度桶中执行 after 阻塞分配。
因此,在您的情况下,您有两件事:
always @(posedge clk)
if (wreg)
...
和
always @(posedge clk)
wreg <= 0;
...
在模拟中,第一个块将使用 'wreg' 的值,因为它在执行非阻塞桶之前存在,可能 1
.
第二个块会调度将非阻塞桶中的wreg更新为0,还没有执行。所以,没有冲突。
因此您可以保证在模拟过程中获得一致的结果。