在 verilog 中顺序或同时执行
Execution in verilog sequentially or concurrently
我是 verilog 的新手,发现 verilog 的执行很棘手。在verilog程序中如何执行。假设我有 2 个模块和一个测试平台-
module module1(clock,A,B,C);
input A,B,clock;
output C;
assign c=A+B;
endmodule
module module2(clock,A,B,C);
input A,B,clock;
output C;
assign C=A-B;
endmodule
module testbench;
reg A,B,clock;
wire C;
module1 m1(clock,A,B,C);
module2 m2(clock,A,B,C);
initial
clock=1'b0;
always
#4 clock=~clock;
endmodule
我了解所有初始块都在 0.But 时间开始,这些初始块然后按顺序执行,即如果初始块有多行,它们将按顺序或同时执行。另外,模块执行是如何进行的? module1
会先开始,因为它出现在测试平台中的 module2
之前,然后完全完成,然后 module2
开始,或者两者 运行 同时开始。当时钟在 4 秒后发生变化时会发生什么情况,如果时钟发生变化,模块 运行 会在两者之间停止,还是会完成之前的执行,然后使用新时钟重新开始?
在 verilog 中,模块的实例化 意味着向您的电路板添加 物理硬件。
模块只不过是并发工作的小硬件块。每个模块都可以有一些过程块、连续赋值语句或两者兼而有之。
每个过程块同时执行,类似适用于连续赋值语句。
我指的是:
Procedural blocks: initial, always etc. blocks.
Continuous assignment: assign, force etc.
因此,无论您以何种顺序 实例化模块,都将在并行 中工作。
时间戳的概念来了。每个 timestamp 包含活动、非活动和 NBA 区域。参考这里的图:
对于每个时间戳,所有 实例都在每个区域 中检查。如果要在 module1
中执行任何执行,那么它会并行完成,其他模块比方说 module2
也会被检查。如果模块之间存在某种依赖关系,那么它们会再次执行。
在这里,在您的示例中,c
是 单线 ,并且两个模块的 输出 ,这会生成一个模块之间的race around condition,这当然不好。
从硬件角度思考。两个或多个不同的硬件块可以具有相同的输入,但不能具有相同的输出。因此,输出线 必须不同 .
module testbench;
reg A,B,clock;
wire C1,C2; // different wires
module1 m1(clock,A,B,C1);
module2 m2(clock,A,B,C2);
initial clock=1'b0;
always #4 clock=~clock;
endmodule
另外,这里模块有连续赋值,所以有没有时钟的影响。不,模块 也在时钟 之间 运行。只是在这些时间戳中没有计划的事件。
正如我们现在所知,所有程序块都是并行执行的。但是程序块中的内容是顺序执行的。为了使 中的内容并发 ,使用 fork..join
构造。例如:
initial
begin
a<=0;
#5;
b<=1; // b is assigned at 5ns
end
initial
fork
a<=0;
#5;
b<=1; // b is assigned at 0ns
join
有关详细信息,请参阅 Verilog Procedural Blocks, Concurrent and Sequential Statements 个站点。
从模拟的角度思考这个问题的另一种方式
您设计中的所有 initial、always 和连续 assign 语句都执行从时间 0 开始并发。它们是否在不同的模块中并不重要——它们都是并发的。精化步骤将所有模块实例展平。剩下的就是那些模块内部事物的层次名称。
现在,除非您 运行 在大规模并行 CPU 上模拟(本质上是 运行 在真正的合成硬件上模拟),否则实际上 运行 所有在并发的这些进程中,软件模拟器必须选择一个进程先进行。你不能完全相信它会选择哪一个。
这就是 Verilog 算法的作用。它将在时间 0 调度到 运行 的所有内容放入事件队列(活动队列),并开始执行每个进程。它执行每个进程直到它完成,或者它必须阻塞等待一些延迟或信号改变。如果进程必须阻塞,它将被挂起并放入另一个队列。然后当前队列中的下一个进程开始执行,这些步骤不断重复,直到当前队列为空。
然后调度算法选择另一个队列成为活动队列,如果该队列被调度有一些延迟,则提前时间。
我是 verilog 的新手,发现 verilog 的执行很棘手。在verilog程序中如何执行。假设我有 2 个模块和一个测试平台-
module module1(clock,A,B,C);
input A,B,clock;
output C;
assign c=A+B;
endmodule
module module2(clock,A,B,C);
input A,B,clock;
output C;
assign C=A-B;
endmodule
module testbench;
reg A,B,clock;
wire C;
module1 m1(clock,A,B,C);
module2 m2(clock,A,B,C);
initial
clock=1'b0;
always
#4 clock=~clock;
endmodule
我了解所有初始块都在 0.But 时间开始,这些初始块然后按顺序执行,即如果初始块有多行,它们将按顺序或同时执行。另外,模块执行是如何进行的? module1
会先开始,因为它出现在测试平台中的 module2
之前,然后完全完成,然后 module2
开始,或者两者 运行 同时开始。当时钟在 4 秒后发生变化时会发生什么情况,如果时钟发生变化,模块 运行 会在两者之间停止,还是会完成之前的执行,然后使用新时钟重新开始?
在 verilog 中,模块的实例化 意味着向您的电路板添加 物理硬件。
模块只不过是并发工作的小硬件块。每个模块都可以有一些过程块、连续赋值语句或两者兼而有之。
每个过程块同时执行,类似适用于连续赋值语句。
我指的是:
Procedural blocks: initial, always etc. blocks.
Continuous assignment: assign, force etc.
因此,无论您以何种顺序 实例化模块,都将在并行 中工作。
时间戳的概念来了。每个 timestamp 包含活动、非活动和 NBA 区域。参考这里的图:
对于每个时间戳,所有 实例都在每个区域 中检查。如果要在 module1
中执行任何执行,那么它会并行完成,其他模块比方说 module2
也会被检查。如果模块之间存在某种依赖关系,那么它们会再次执行。
在这里,在您的示例中,c
是 单线 ,并且两个模块的 输出 ,这会生成一个模块之间的race around condition,这当然不好。
从硬件角度思考。两个或多个不同的硬件块可以具有相同的输入,但不能具有相同的输出。因此,输出线 必须不同 .
module testbench;
reg A,B,clock;
wire C1,C2; // different wires
module1 m1(clock,A,B,C1);
module2 m2(clock,A,B,C2);
initial clock=1'b0;
always #4 clock=~clock;
endmodule
另外,这里模块有连续赋值,所以有没有时钟的影响。不,模块 也在时钟 之间 运行。只是在这些时间戳中没有计划的事件。
正如我们现在所知,所有程序块都是并行执行的。但是程序块中的内容是顺序执行的。为了使 中的内容并发 ,使用 fork..join
构造。例如:
initial
begin
a<=0;
#5;
b<=1; // b is assigned at 5ns
end
initial
fork
a<=0;
#5;
b<=1; // b is assigned at 0ns
join
有关详细信息,请参阅 Verilog Procedural Blocks, Concurrent and Sequential Statements 个站点。
从模拟的角度思考这个问题的另一种方式
您设计中的所有 initial、always 和连续 assign 语句都执行从时间 0 开始并发。它们是否在不同的模块中并不重要——它们都是并发的。精化步骤将所有模块实例展平。剩下的就是那些模块内部事物的层次名称。
现在,除非您 运行 在大规模并行 CPU 上模拟(本质上是 运行 在真正的合成硬件上模拟),否则实际上 运行 所有在并发的这些进程中,软件模拟器必须选择一个进程先进行。你不能完全相信它会选择哪一个。
这就是 Verilog 算法的作用。它将在时间 0 调度到 运行 的所有内容放入事件队列(活动队列),并开始执行每个进程。它执行每个进程直到它完成,或者它必须阻塞等待一些延迟或信号改变。如果进程必须阻塞,它将被挂起并放入另一个队列。然后当前队列中的下一个进程开始执行,这些步骤不断重复,直到当前队列为空。
然后调度算法选择另一个队列成为活动队列,如果该队列被调度有一些延迟,则提前时间。