【问题标题】:Confusion regarding usage of event.triggered关于 event.triggered 使用的困惑
【发布时间】:2016-02-25 10:07:07
【问题描述】:

我正在尝试一些在移动到新的模拟时间步之前应该阻塞的代码(类似于在 e 中等待sys.tick_start)。

我尝试编写一个执行此操作的函数:

  task wait_triggered();
    event e;
    `uvm_info("DBG", "Waiting trig", UVM_NONE)
    -> e;
    $display("e.triggered = ", e.triggered);
    wait (!e.triggered);
    `uvm_info("DBG", "Wait trig done", UVM_NONE)
  endtask

它背后的想法是我触发了一些事件,这意味着当控制到达wait(!e.triggered) 的行时,它的triggered 字段将为1。此行应在下一个时间段解除阻塞,此时 triggered 将被清除。

为了测试这一点,我添加了一些其他消耗模拟时间的线程:

fork
  wait_triggered();

  begin
    `uvm_info("DBG", "Doing stuff", UVM_NONE)
    #1;
    `uvm_info("DBG", "Did stuff", UVM_NONE)
  end
join
#1;
$finish(1);

我看到消息 Doing stuffDid stuff,但 Wait trig done 永远不会出现。模拟在到达finish(1) 之前也会停止。一位模拟器告诉我,这是因为没有安排更多活动。

所有模拟器都表现出相同的行为,所以一定有我遗漏的东西。谁能解释发生了什么?

【问题讨论】:

    标签: system-verilog


    【解决方案1】:

    e.triggered 从 1 变为 0 时,wait (!e.triggered); 出现问题。它必须在一个无法安排任何事情的区域发生变化,因此它是在当前时隙结束时发生变化,还是在下一个时隙开始时发生变化是不可观察的。所以wait 将挂起等待当前时隙的结束,而这个时隙永远不会到来。

    我认为最接近您正在寻找的东西是#1step。这阻止了最小的模拟精度时间步长。但我必须相信有更好的方法来编写你想要的代码,而不必知道时间是否在前进。

    【讨论】:

    • 我只是想知道fork...join 已完成,这意味着所有线程都必须完成。那显示器怎么还没到呢?此外,该事件似乎在 NBA 区域触发,此后,模拟跳转到活动区域 $displaywait--triggered 等待整个时间戳。因此,任务必须在1step 延迟后退出。但这似乎没有发生,请您告诉我是否正确并详细说明?
    • 事件驱动模拟的工作方式是任何时序控制#, @wait 都必须通知唤醒,并且永远不会通知wait 声明 e.triggered 从 1 变为 0,因此不评估表达式 !e.triggered。所以调用任务wait_triggered() 的进程挂起,它永远不会完成。所以fork/join 永远不会完成。
    • 在显示的代码中不需要调用uvm_wait_for_nba_region。这就是为什么我强烈建议不要在代码中使用#0、#1、#1step,除非你对 Verilog 的调度算法有很好的理解。 UVM 充满了不必要的#0,使得试图修改行为的人很难确切地知道它在做什么。我也会尽量避免命名事件。通常有更好、更容易维护的编码方式。
    • 哦,现在我明白了。 fork..join 永远不会退出。在相同的时间戳中,e.triggered 必须有从 1 到 0 的转换。在触发事件的时间戳中,wait 语句在e.triggered 中获得1,在随后的时间戳中,它获得0。因此,在 single 时间戳中没有从 1 到 0 的转换,因此它会阻塞。谢谢你的解释。
    • 是的,我也不相信使用 #0#1 或任何其他手动解决方法。它使事情变得容易,但也使它们变得模糊。
    猜你喜欢
    • 1970-01-01
    • 2019-05-17
    • 2020-03-06
    • 2016-03-16
    • 2013-07-27
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多