【问题标题】:Evaluation Event Scheduling - Verilog Stratified Event Queue评估事件调度 - Verilog 分层事件队列
【发布时间】:2014-04-02 14:53:09
【问题描述】:

我正在尝试在 Python 中实现一个简单的基于事件的 Verilog 模拟器,但实际上我很难在规范中找到一些细节(IEEE 1364-2005 第 11 节)。

假设我刚刚在 clk 上执行了一个更新事件,它现在获得了新值 1(之前为 0)。根据规范,这需要我为敏感进程安排“评估事件”。

我是否必须将always @(posedge clk) 块的评估安排为活动或非活动事件?我猜后者是正确的?

或者实际上,更笼统地说。基本上所有事件都安排为非活动事件,但以下例外:

  • 非阻塞分配更新为非阻塞分配事件
  • 作为活动事件的连续分配

非常感谢!

【问题讨论】:

  • 暂时搁置一下,但以下博客文章及其前辈对于 Verilog 和 VHDL 中的调度很有趣...sigasi.com/content/vhdls-crown-jewel
  • 出于好奇,您的项目目标是什么?如果您尝试使用 Python 进行 FPGA 开发,我假设您已经看过 myHDLcocotb
  • @Chiggs MyHDL 和我的关系实际上很不好 ;-) 所以我试图复制它,但采用不同的方法(更少的魔法和更多面向用户的对象)
  • @Alex 因此,您正在尝试简化 MyHDL 并因此查看 Verilog 调度。有趣:-)

标签: python verilog fpga hdl


【解决方案1】:

默认情况下,一切都在 Active 区域中运行。例外情况是:

  • #0 个阻止分配位于非活动区域
  • 非阻塞分配位于 NBA 地区
  • $monitor、$strobe 和 PLI/VPI 位于 Monitor 区域

我们可以通过在任何现有模拟器中运行以下命令来证明@ 发生在活动区域​​:

int x; 
initial begin 
   $monitor("From    $monitor: x is %0d",x); 
   #0 x = 5; // inactive event 
   x = 3; // active event (after inactive event)
   #1; // go to next time stamp
   fork
     #0 x = 7; // inactive event 
     x = 11; // active event 
   join
   #0 fork // inactive region
     #0 x = 2; // inactive event 
     x = 5; // active event 
     x <= 4; // NBA event 
   join
end 
// active event region
always @* $display("From @* $display: x is %0d",x); 

输出:

从@* $display: x 是 3 从 $monitor: x 是 3 从@* $display: x 是 11 从@* $display: x 是 7 从@* $display: x 是 5 从@* $display: x 是 2 从@* $display: x 是 4 从 $monitor: x 是 4

显示报告的次数多于监控次数。这排除了 @ 在 Monitor 或 Future 区域中的累积。显示正在报告每个事件区域。每个事件区域只能循环回活动区域。因此,@ 必须在 Active 区域中处理,并且每个更新变量 x 的区域都会触发新的 Active 区域事件。

这也可以通过查看 Verilog 的历史来证明。不幸的是,这没有很好的记录。我是通过 80 年代末 90 年代初使用/开发 verilog 的人了解到的。总的解释是:在 IEEE Std 1364-1995、@ 早于这两个区域之前,将 Inactive 和 NBA 区域添加到 Verilog。添加这些区域是为了向非确定性模拟器添加确定性。

always @(posedge clk) pipe0 = in;
always @(posedge clk) pipe1 = pipe0; // unpredictable, non-deterministic order
always @(posedge clk) #0 pipe0 = in; // Inactive region added some determinism
always @(posedge clk) pipe1 = pipe0; 
always @(posedge clk) #0 pipe0 = in; // But was fragile
always @(posedge clk) #0 pipe1 = pipe0; // unpredictable order again
always @(posedge clk) pipe2 = pipe1; 
always @(posedge clk) pipe0 <= in; 
always @(posedge clk) pipe1 <= pipe0; 
always @(posedge clk) pipe2 <= pipe1; // NBA region fixed it 
 ...
always @(posedge clk) pipeN <= pipeM; //             and made it scalable



根据 cmets 的反馈进行澄清

事件被激活,而不是移动。激活的 NBA 事件进入if (E is an update event) 的真实条件,修改对象并安排新的评估事件(在下次进入Active 区域时处理)。一旦所有的activated 事件都完成了,调度就会回到while 循环的顶部。 NBA 区域仅分配值,评估实际上是在较早的 Active 区域阶段完成的。
从您的示例中:
module TEST;
   reg test = 0;
   reg test2 = 0;
   reg clk = 0;

   initial begin
      clk <= 1;
      test <= 1;
   end

   always @(posedge clk) begin
      test2 <= test;
   end
endmodule

while 循环的每次迭代都将如下所示:

迭代:0
  Active: 非活动:
  NBA:
      clk = clk$tmp
      测试 = 测试$tmp
迭代:1
  活动:
  非活动:
  NBA: Active: 非活动:
  NBA:
迭代:3
  Active: 非活动:
  NBA:
      测试2 = 测试2$tmp
迭代:4
  活动:
  非活动:
  NBA:  下一个模拟周期

【讨论】:

  • 非常感谢您的回答!但我并不完全相信this example 并与之苦苦挣扎。如果按照您描述的方式处理事件,那么 test2 的结果应该是不可预测的?
  • 这个例子是确定性的。 NBA 区域在返回活动区域之前分配所有计划的非阻塞值。 @(posedge clk) 阻止 test2 &lt;= test 在调度程序中排队。 #@wait 推迟评估。 &lt;= 在 Active 地区进行评估,但其分配被推迟到 NBA 地区。示例x=1;y=3;z&lt;=x+y;x=7 z 将被分配 4。
  • @Alex,我已经扩展了我的答案,解释了你的测试用例。
  • 原始示例是确定性的。请参阅 EDA playground here 上的代码,并注意 GPLCver 的行为与其他模拟器有何不同。 NBA to clk 发生后,Verilog 可能会或可能不会立即触发时钟始终阻塞。
  • 您的原始问题:正如@Greg 所说,@ 事件将安排在活动区域​​。但是,您不能对该事件和其他现有活动事件的评估顺序做出任何假设。这就解释了为什么您在此评论部分中的示例是不确定的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-11
  • 1970-01-01
  • 2012-10-25
  • 2012-07-10
相关资源
最近更新 更多