Verilog 中的初始块执行顺序



我做了一个计数器模块,但我似乎无法掌握计数器模块和测试平台模块的初始块的执行顺序。

据我所知,我认为在verilog中,初始块将始终首先执行。

在这种情况下,我将执行测试平台模块,我假设initial块 因为testbench_counter将首先执行。

接下来,我认为计数器模块C将被执行,并且x_in的值将更新为temp,而无需在模块C#1延迟。

但是没有#1,或者将initial更改为always@(x_in)我看到了红线。

所以问题是

  1. 计数器模块Cinitial块是否会先执行,甚至在测试平台的initial块之前执行?

  2. 如果我使用always@(x_in),为什么它会起作用?

提前谢谢。

计数器代码

`timescale 1ns/1ns
module counter(x_in,clk,y_out);
input [31:0] x_in;
input clk;
output [31:0] y_out;
reg [31:0] y_out;
reg [31:0] temp;
initial begin
#1 temp=x_in;
end
always@(posedge clk) begin
temp<=temp+1;   
y_out<=temp;
end
endmodule

测试平台代码

`timescale 1ns/1ns
module testbench_conter();
wire [31:0]y_out;
wire [31:0]temp;
reg [31:0]x_in;
reg clk;
counter C(x_in,clk,y_out);
always begin
#5 clk=~clk;
end
initial begin
clk=1'b0; 
x_in=32'd0;
#0
#10000
$stop;
end
endmodule

接下来,我认为计数器模块 C 将被执行......

您思维中的主要缺陷是计数器中的初始语句是在计数器"执行"时执行的。事实并非如此。所有初始语句在程序开始时运行,并且只运行一次。因此,您的两个初始语句形成了一个竞争条件。

通过使用 #1 或always@(x_in),您将分配延迟到 'temp1 直到定义x_in之后。

更好的方法是在计数器中添加一个"负载"信号,该信号在激活时拾取x_in的值。

此外,您的y_out会延迟另一个时钟周期。

通常,可加载计数器如下所示:

always@(posedge clk)
begin
if (load)
y_out <= x_in;
else
y_out <= y_out + 1;   
end

回答您的问题 1:initial块之间绝对有保证的执行顺序。Verilog 模拟以任意不可预测的顺序启动它们。同步的唯一方法是 #delays 和其他等待和延迟语句。

Verilog 保证任何进程块(包括初始块和始终块(的执行都将在等待条件停止,直到满足为止。

Verilog 还保证所有初始块在任何始终之前开始。

在始终块灵敏度列表中指定的任何信号都起着"延迟"语句的作用,导致始终块等待任何信号值更改。之后它将继续执行该块。

因此,回答您的第二个问题,always@(x_in)将等到信号值发生变化。

因此,在您的情况下:

initial begin    << will start execution at time '0' before any always block
clk=1'b0;     << change value of clk from 'x' -> '1' 
x_in=32'd0;   << change value of x_in 'x' -> '0'
#0            << makes absolutely no sense here. It is a special statement
#10000        << pauses execution for 10000 time units
$stop;        << stopps execution
end

当上述初始区块产生时,其他区块开始执行。

initial begin     << starts execution at time 0, befor or after the block above
#1 temp=x_in; << pauses for 1 time unit, then assigns temp
end 

上面的分配发生在第一个初始块等待 #10000 时。

如果使用"始终"块

always @(x_in)
temp = x_in;

当x_in更改并且第一个初始块开始等待时,它将执行分配。当信号被触发时,这个始终块将以相同的周期"0"执行。它与您使用的#1不同。在您的情况下,更改将在周期"1"发生。

最新更新