【问题标题】:Subtleties of Non Blocking Assignments非阻塞分配的微妙之处
【发布时间】:2017-12-19 05:05:34
【问题描述】:

在此示例中,非阻塞赋值传播到连续赋值。这会导致任何执行范例吗?请详细说明这段代码 - 可能的错误,如何将其删除以及良好的编码风格。

  always @(posedge clk)
        dff1 <= f(x);

    assign fsm_in = f(dff1);
    assign fsm_out = fsm_state;

    always @(fsm_in)
        fsm_state <= g(fsm_in);

【问题讨论】:

  • f 和 g 是任意表达式,就像数学模型一样,即 f(x) = x2 - x + 1;

标签: verilog nonblocking


【解决方案1】:

您的代码很好,尽管我同意 Greg 的观点,即在组合过程中使用阻塞赋值更好。

在你的 cmets 上:

简单来说,调度器包含 5 个队列(SV 有 17 个),但是 您只对其中 2 个感兴趣:active event queuenonblocking assignment update queue。在给定的仿真周期中, 模拟器处理活动事件队列,然后进行非阻塞更新 队列。通常,这将创建更多事件,并且模拟器循环 以预定的顺序围绕队列,直到没有更多事件发生 这个模拟时间。然后模拟器移动到下一个时间 事件被安排(例如在下一个时钟边沿)。

假设“同时”发生 4 件事:fsm_state 发生了变化, 是f(x) 的更改,您的两个NBA 任务都已执行。据,直到...为止 就模拟器而言,这4条语句是同一个执行的 模拟循环,但顺序未定义。 “一次”的定义是 相当复杂,但假设它们都是由于时钟沿而发生的, 语句之间没有排序依赖关系。模拟器通常是 单线程,所以它实际上会以不同的方式执行 4 个语句 真实次,但它知道所有 4 次预计会同时发生 模拟时间。

fsm_statef(dff1) 上的更改为 update events,并添加到 调度程序的active event queue

两个 NBA 的 RHS 立即评估,LHS 更新是 添加到nonblocking assignment update queue

模拟器现在看到一个队列,上面有 4 个事件。它执行两个活动 事件优先,以未定义的顺序,所以 fsm_infsm_out 得到他们的新 价值观。如果没有更多活动事件,则执行这两个 非阻塞更新,以未定义的顺序,所以 dff1fsm_state 现在得到 他们的新价值观。

在您的情况下,模拟周期尚未完成,因为更改 fsm_in 也是一个更新事件,这会触发评估/执行 对fsm_in 敏感的always 块。这是evaluation event。 sim执行always块,立即读取新值 fsm_in,并将fsm_state的更新添加到NBA任务更新中 队列。如果没有活动事件,则执行分配,并且 fsm_state 获得了新的价值。

此过程一直持续到此模拟周期中不再有事件,并且 如果将来安排了某些事情,则模拟器会提前时间。

您可以从 Verilog LRM 的第 5 节中获得所有这些信息,但它不会 很有意义。所有的语言都是在标准化后期移植的 处理和使用(VHDL)术语在 LRM 的其他地方没有使用。它 也都以匹配 Verilog-XL 的行为的方式添加,并且 专门记录特定于 XL 的非确定性,所以不要指望 太多了。 NBA 直到 1992 年才被添加到语言中,我 思考。不要为 SV LRM 烦恼;还有更多的队列,并且 普通文本已更改,只是增加了另一层混乱。

Cliff Cummings 在他的一篇论文中有一个简化的描述(关于 非阻塞赋值),但请仔细阅读。我很确定 活动事件队列的描述不正确(用于 RHS 评估 NBA)。如果他是对的,那会引起各种各样的问题;他大概 从早期版本的 LRM 中获得描述。

最好的办法是查找有关 VHDL delta 周期的任何文本。这些 很容易理解,他们工作,并且一直在做,他们有 多年来潜入 Verilog。细节不同,但你不 需要知道比增量周期更多的知识。

【讨论】:

    【解决方案2】:

    首先:最佳实践是对寄存器进行非阻塞分配,对组合逻辑进行阻塞分配。我建议看一下这篇论文:Nonblocking Assignments in Verilog Synthesis, Coding, Styles That Kill!,Clifford E. Cummings。 § 11 涵盖组合逻辑。该论文的指南适用于 IEEE Std 1364-1995,并且在今天仍然完全适用; Verilog 和 SystemVerilog。

    也就是说,给定的代码可以正常工作,因为您有一个简单的条件。它也可能会正确合成(基于 Cliff 的页面)。

    如果您使用糟糕的编码风格和更复杂的设计,您可能会遇到问题。有关示例,请参阅Cliff's paper。糟糕的编码风格也会让其他人更难阅读[1]。可读的代码是你想要教授和同事的东西。一个理想的 linting 工具也会标记它。最好让自己养成编写优质代码的习惯。

    1 : 如果您真的不希望其他人阅读您的代码,请参阅 IEEE std 1800-2012 § 34

    【讨论】:

    • 我同意在组合过程中使用阻塞分配是“最佳实践”,但这当然只是一个指导方针。您总是可以使用 NBA 编写组合逻辑,而 VHDL 设计人员一直都在这样做。当然,如果您开始使用临时变量来保存中间值,您必须了解 NBA 实际做了什么,以及值何时更新。在 VHDL 中,您使用一个变量来确保立即更新;在 Verilog 中,您使用阻塞分配。存在 Verilog 的“指南”是因为语言没有明确说明 - 如果您理解该语言,则可以忽略它们。
    【解决方案3】:

    我建议您始终对时钟驱动信号使用非阻塞,对组合逻辑使用阻塞(如果是 RTL)。我使用了许多合成器,如果您不按照我的建议使用分配,它们会显示错误。还有其他 linting 工具也会显示错误。 我同意 Greg 的观点,为了获得更好的可读性代码,您应该遵循本指南。

    【讨论】:

    • 我从未见过合成失败,因为它不了解 NBA,甚至没有听说过。这不太可能,因为他们致力于模板识别,这也意味着他们无法处理大量的 VHDL 代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    相关资源
    最近更新 更多