碎碎思 · 2022年02月11日

Verilog组合逻辑设计指南

image.png
在描述组合逻辑的RTL时,必须遵循编码和设计指南。设计和编码指南将提高设计性能、可读性和可重用性。本文讨论组合逻辑设计的规范和编码准则。

在实际的FPGA设计中,这些准则用于提高设计的可读性和性能。讨论的关键实践指南是“if-else”和“case”结构的使用以及实际场景,如何推断并行逻辑和优先级逻辑。详细解释了资源共享的具体应用以及描述组合逻辑设计的块分配的使用。本章重点介绍分层事件队列和逻辑分区。

阻塞分配和事件队列的使用

Verilog支持过程块中的两种赋值。这些分配称为阻塞(=)和非阻塞(<=)分配。在描述组合逻辑设计时,始终建议使用阻塞(=)赋值,原因很简单,但本质是作为一名工程师需要理解其背后的基本原理。

为了理解阻塞赋值,让我们了解分层事件队列的概念。根据IEEE1364-2005verilog标准,分层事件队列分为四个主要区域。这些区域被命名为:活动、非活动、NBA和监视器(Active, Inactive, NBA, and Monitor)。

主要的问题是为什么要理解分层事件队列以及它的具体应用?因为名称本身表明分层事件队列用于计算表达式和更新结果。图4.1描述了根据Verilog IEEE 1364-2005标准的分层事件队列。如图4.1所示,Verilog分层事件队列有四个主要区域,如下所述

1、 活动队列,大多数Verilog事件都安排在活动事件队列中。这些事件可以按任何顺序安排,也可以按任何顺序进行评估或更新。活动队列用于更新阻塞赋值、连续赋值、非阻塞赋值的RHS评估(活动队列中未更新NBA的LHS)、$display命令以及更新原语。

2、非活动队列,在非活动队列中更新#0延迟分配。在Verilog中使用#0延迟不是一种好的做法,这一做法使事件调度和排序复杂化。大多数情况下,设计者使用#0延迟分配来愚弄仿真器,以避免竞相条件。

3、NBA队列,此队列中非阻塞赋值的LHS更新。

4、监视器队列它用于评估和更新和strobe命令。所有变量的更新都在当前仿真时间内进行。

如上所述,阻塞赋值在程序内顺序执行。在执行当前语句时,阻塞赋值将阻塞过程中的所有后续语句阻塞的执行
image.png
图4.1 Verilog分层事件队列

赋值始终被视为“一步”过程。在活动事件队列中,计算阻塞赋值的RHS,同时更新阻塞分配的LHS。考虑阻塞分配的示例4.1。

在下一节中,我们将讨论组合逻辑的设计和编码准则,并将继续使用阻塞分配。

不完整的敏感度列表

建议将所有要求的信号和输入纳入组合设计程序块的灵敏度列表中。考虑示例4.2来描述两个输入NAND逻辑的功能。
image.png
示例4.1程序块中的阻塞赋值指定更新。注:阻塞赋值的主要问题是在一个程序块的RHS侧和另一个程序块的LHS侧使用相同的变量。如果两个程序块安排在相同的仿真时间或相同的时钟边缘上,则会在设计中生成竞争条件。这将在后面讨论

在示例4.2中,综合工具忽略灵敏度列表并生成两个输入与非门作为可综合输出,但仿真器忽略输入“b_in”的变化并生成输出波形。这导致仿真和综合不匹配。仿真结果如图4.2所示。
image.png
图4.2不完整的灵敏度列表波形。注意:为避免仿真和综合不匹配,建议使用程序块:always@( * )。根据IEEE1364-2001标准灵敏度列表中的“ * ”将包括所有输入所需信号。

连续赋值与过程赋值

连续赋值:连续赋值用于向网络赋值。它们用于描述组合逻辑功能。这些赋值在活动事件队列中更新,值在计算右侧表达式时更新。使用连续赋值语句时,端口或输出被声明为“wire”。

过程赋值:过程赋值用于为变量reg赋值。这些用于描述组合逻辑和顺序逻辑行为。赋值给reg的输出被保留,直到执行下一个赋值。这些赋值始终用于程序块、初始块以及任务和函数内部。

在程序块中,如果使用了阻塞(=)赋值,则它们将在活动事件队列中更新。所有非阻塞赋值(<=)在活动事件队列中计算,但在非阻塞事件队列中更新。

设计中的组合循环

设计中无意的组合循环对于在实现阶段进行调试和修复非常关键,并且会产生振荡行为。示例4.3描述了设计中的组合循环。

图4.3描述了组合循环的可综合输出。

如上所述,设计中的组合循环是危险和关键的设计错误之一。设计中的组合循环发生在同一信号中,在多个程序块中使用或更新。如果表达式的右侧和左侧存在相同的信号,则设计具有组合循环。

组合循环表现出振荡行为,在更新过程中,它们可能具有竞争条件。考虑示例4.4中所示的设计场景。

在示例4.4中,两个always块同时执行,因此,在更新b值时,会将新值分配给a。这在设计中具有竞争条件。这种设计会因a、b上的事件而产生振荡行为。
image.png
示例4.3设计中的组合循环
image.png
注:建议设计中不应有任何组合循环。为了避免组合循环通过使用时序元件来中断反馈路径

图4.3组合循环结果。
image.png
示例4.4带组合循环的Verilog RTL代码
image.png
示例4.5组合振动引起的振动行为

振荡行为可以从示例4.5中理解。

组合循环不可综合,综合器会为组合循环生成错误或警告。组合循环可能是设计中的潜在危险,因此需要避免。

如上图所示,a上的事件触发块always@(a)并生成输出b。最终,b输入上的更改用于触发另一个always@(b)并生成输出a。因此,这将继续并在设计中显示振荡行为或竞转条件。

解决这个问题的方法是使用寄存器来避免信号的依赖性,从而触发多个always块。可以在组合循环中插入寄存器以更新值。

要避免组合循环,请执行以下操作。使用非阻塞分配和寄存器逻辑来中断组合循环。修改如示例4.6所示。

在示例4.6中,两个always块均在时钟的正边缘触发,并分别将值分配给b、a。虽然两个程序块同时执行,非阻塞分配在NBA队列中排队,因此生成如图4.4所示的结构。
image.png
示例4.6中断组合循环的解决方案
image.png
图4.4避免组合循环的寄存器逻辑

设计中的意外锁存器

建议设计中不应有非预期的锁存器,因为锁存器在激活电平期间起到透明作用,并将数据直接传输到其输出。ASIC/FPGA设计中不建议使用非故意锁存,因为它会在设计测试或DFT期间导致问题。即使在STA期间,定时算法也无法理解是在时钟的正边缘还是在时钟的负边缘采样数据。因此,在大多数情况下,由于设计者的真实意图没有反映在硬件推理中,因此此类路径的STA分析是非常困难的。这将在后面讨论。

考虑下面示例4.7中所示的功能。
image.png
示例4.7 Verilog RTL 缺少“else”条件

在上面的代码中,在else子句期间一样,没有给出关于b_in更新的信息,它推断锁存器并保持b_in的先前值。图示如图4.5所示。If else语句为分配中的a_in和分配中的b_in推断多路复用器,它推断由启用输入c_in控制的正电平敏感锁存器。

如图4.5所示,由于else子句中的赋值中缺少b_in,它生成锁存并保持if子句中先前赋值的值。
image.png
图4.5缺少“else”条件的综合逻辑

锁存器由于if-else中的赋值不完整或由于case语句中包含的条件不完整而被推断。建议设计人员在编写RTL代码时注意这一点。

阻塞赋值的使用

如上所述,阻塞赋值用(=)表示,并在程序块内使用,以描述组合逻辑设计的功能。请读者不要与使用的(=)运算混淆
image.png
示例4.8连续赋值Verilog RTL。注:建议使用全加器执行减法运算。使用2的补码加法执行减法。多个连续赋值语句并行执行连续赋值“‘assign’”。示例4.8使用多个赋值结构来描述设计的功能。
image.png
示例4.9程序块内的阻塞赋值

考虑在程序块中使用阻塞赋值的情况。如果分块分配的顺序不正确,则有可能出现仿真和综合不匹配。

示例4.9,在该示例中,仿真和综合结果中的问题是由于阻塞语句的顺序造成的。除非执行当前语句,否则阻塞赋值将阻止下一个即时语句的执行。鼓励读者只使用阻塞作业,但在使用语句获得真正预期结果时应小心。

上述示例的综合结果如图4.6所示,它生成两条导线。但是,在仿真“y2_out”时,会使用以前的时间戳值“a_in”进行更新。因此导致仿真和综合不匹配。
image.png
图4.6 阻塞赋值的综合结果

使用if-else与case语句

当“case-endcase”中包含所有case条件时,该语句称为”full-case”语句。对于组合设计,case语句应该使用所有的阻塞赋值。

4:1 MUX的综合结果如图4.7所示,并推断出并行逻辑。
image.png
图4.7使用“case”对4:1多路复用器进行并行逻辑推理

多路复用器嵌套或优先级结构

如果使用“if-else”构造来描述组合逻辑,那么综合结果将生成优先级逻辑。建议使用“if-else”结构来描述优先级逻辑。

示例4.10描述了使用嵌套if-else构造的4:1 MUX的功能。
image.png
Example 4.10 Verilog RTL for priority logic

2:4解码器

在描述解码逻辑的功能时,可以使用连续赋值(assign)或“case”结构。两者都将生成并行逻辑。如前面所述,解码器具有并行选择输入并生成并行输出。
image.png
图4.8使用“assign”或“case”的解码逻辑

如果使用“case-endcase”语句描述解码器,它推断出并行逻辑。图4.8(示例4.11)显示了使用“assign”或“case”的解码逻辑的解码器实现的硬件描述。
image.png
示例4.11使用“case-endcase”构造的解码逻辑

4:2编码器

要描述编码器功能,请使用“if-else”构造,因为可以定义优先级。4:2编码器的功能使用“if-else”结构描述,并推断优先级逻辑。示例4.12的综合结果如图4.9所示。
image.png
示例4.12使用“if-else”的优先级逻辑
image.png
图4.9使用if-else’的优先级编码的综合结果

缺少‘Default’的“case”语句

如果“case endcase”表达式中未涵盖所有条件,就会推断设计中的锁存器。如果设计功能中不需要所有情况条件,则建议使用“‘Default’”条款。如果“‘Default’值”缺失,综合器将报告缺失“case”条件的警告,并推断设计中的锁存。
image.png
实例4.13的综合结果如图4.10所示。
image.png
图4.10缺失默认值的综合输出

“使用if-else”进行描述,但由于缺少“else”

如示例所示,4:1 MUX功能使用嵌套的“if else”进行描述,但由于缺少“else”子句,它推断出4:1 MUX具有意外锁存器。建议在RTL代码中的所需位置加入“else”条件,以避免意外锁存器。
image.png
示例4.14缺少“else”的Verilog RTL

对于示例4.14,综合的硬件,如图4.10所示。

与case逻辑相等

可综合设计中使用逻辑等式(=)和逻辑不等式(!=)运算符,而不建议在可综合设计中使用大小写等式(===)和大小写不等式(!==)。

逻辑等式和逻辑不等式运算符

  1. 建议在可综合设计中使用。
  2. 如果操作数中的任何一个具有“x”或“z”值,则最终结果未知(“x”),并导致逻辑比较结果为false。
  3. 如果任何一个操作数具有“x”或“z”值,则比较结果是不确定的。
  4. 考虑比较“a_ in”和“b_in”的例子。在这种情况下,如果操作数中的任何一个为“x”或“z”值,则将执行else子句并推断else子句中指定的逻辑
    image.png

case等式和case不等式运算符

  1. 建议用于非综合设计。
  2. 如果任何一个操作数具有“x”或“z”值,则结果为已知值,结果为true或false。
  3. 如果操作数中的任何一个具有“x”或“z”值,则比较结果是确定的。
  4. 考虑比较“a_in”和“b_in”的例子。在这种情况下,如果操作数中的任意一个为“x”或“z”值,则将执行if子句中的a_in等于b_in,并推断if子句中指定的逻辑
    image.png

算术资源共享

示例4.15,没有资源共享的设计。预期设计功能是设计表4.1所示的组合逻辑。

如图4.11中的综合逻辑所示,它使用三个全加器和两个多路复用器。由于所有加法都是同时执行的,且多路复用器输出依赖于控制信号,因此综合逻辑后运算效率低下。
image.png
示例4.15未使用资源共享概念的Verilog RTL

表4.1功能表说明
image.png
图4.11无资源共享的综合逻辑

使用资源共享

资源共享是ASIC/FPGA设计中用于共享公共资源的有效技术之一。如例4.15所述,加法器同时生成结果,并等待控制信号‘s1_in’或‘s2_in’(例4.16,图4.12)。
image.png
图4.12使用公共资源的综合逻辑
image.png
示例4.16使用资源共享技术的Verilog RTL

多重驱动赋值

如果同一网络(导线)由不同连续赋值语句中的多个表达式驱动,则综合器将报告错误“Multiple Driver Assignment”。同样,如果同一个reg变量由不同always块中的不同表达式驱动,则它也是多重驱动赋值错误。这方面的例外是三态赋值。

考虑一个例子4.17。在本例中,网络y\_tmp由使用多个“assign”编码的两个不同表达式驱动。
image.png
示例4.17具有多重驱动赋值

总结

如本文所述,以下是重要的设计指南

  1. 使用阻塞赋值设计组合逻辑。
  2. 在活动事件队列中计算并更新所有阻塞赋值语句。
  3. 使用“case endcase”推断并行逻辑,使用“if else”推断优先级逻辑
  4. 使用“case endcase”中的所有case条件或“default”,以避免产生意外锁存器。
  5. 使用“always”块灵敏度列表中的所有所需输入或信号。建议这样做是为了避免仿真和综合不匹配。
  6. 使用“assign”时,避免对同一网络使用多个分配,以避免多个驱动程序赋值错误。
  7. 避免使用组合循环,因为它最终会表现出振荡行为。
  8. 涵盖所有“case”条件和“else”条件,因为缺少“case”条件或“else”条件会推断出设计中的意外锁存器。
原文:OpenFPGA
作者:碎碎思

相关文章推荐

更多FPGA技术干货请关注FPGA 的逻辑技术专栏。
推荐阅读
关注数
10516
内容数
513
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息