如何在硬件中实现Verilog“始终”语句?


8

Verilog always语句,即

always @(/* condition */)
    /* block of code */

block of code只要condition满足就执行。这样的always模块如何在硬件中实现?


我认为这很大程度上取决于什么block of code是...
m.Alin

1
以及病情是否posedge x正好x
贾斯汀

@贾斯汀:让我们假设没有posedge
Randomblue

Answers:


16

首先,请注意,并非所有Verilog设计都是可综合的。通常,只能在要以硬件实现的设计中使用构造的非常具体的子集。

出现的一个重要限制是每个reg变量最多只能在一个always语句中分配给它。换句话说,regs对always块有亲和力。

always通常可以使用以下类型的块。

always @(*) begin
    // combinational
end

always @(posedge clk) begin
    // sequential
end

在前一种情况下,*表示只要该块中使用的任何信号发生变化,都应执行该块,或者等效地,该块应连续执行。因此,reg将对组合always块具有亲和力的s 实现为使用组合逻辑(即门)从其他信号计算出的信号。

always另一方面,与后一种类型的块具有亲和力的寄存器是D触发器的输出,这些触发器在的上升沿clk(如果negedge使用下降沿,则为时钟)提供时钟。触发器的输入再次由来自其他信号的组合逻辑来计算。

考虑以下一些人为设计的示例。

reg out, out_n;
always @(*) begin
    out_n = !out;
end
always @(posedge clk) begin
    out <= !out;
end

在这里,out_n与第一个always块相关联,out与第二个相关联。out_n将使用一个将驱动out_n和从其驱动的非门实现out(请注意,这是一个纯粹的组合逻辑)。另一方面,out将由时钟驱动的触发器驱动clk。触发器的输入将再次由的“非”门计算out(由上述触发器驱动)。优化的合成器将结合两个NOT门,并使用一个NOT门和一个触发器。

根据可用的硬件,可以使用其他类型的构造。例如,如果触发器具有异步复位,则以下结构也是可合成的。

always @(posedge clk or posedge rst) begin
    if (rst)
        // reset
    else
        // sequential
end

谢谢。关于*,我认为它指示了只要该块中的任何信号发生变化(与设计相反),都应执行该
Randomblue

@Randomblue,您是对的,我将解决问题。但是请注意,两者在行为上是等效的。
avakar

真正; 很公平!
Randomblue

2

一个always块被通常用于描述触发器,锁存器,或多路复用器。该代码将通过触发器,锁存器或多路复用器实现。

在FPGA中,触发器和锁存器通常只是通用寄存器设备的两种不同配置。多路复用器将由一个或多个通用逻辑元件(LUT)构成。

通常,使用Verilog进行设计有两种方法:

  1. 根据门和寄存器可视化所需的逻辑,然后弄清楚如何在Verilog中对其进行描述。FPGA供应商或综合工具供应商的综合指南书为您可能要使用的最常见结构提供了样板。

  2. 只需编写Verilog,不必担心基础硬件的外观。但是,即使这样做,您仍然必须知道什么是可合成的,什么是不可合成的。同样,您将查看工具供应商提供的样板并使其适应您的应用程序。

编辑

对于您的问题,Avakar的答案是一个更好的答案,但这激发了有关Xilinx和Altera之间区别的一些有趣的讨论,因此我不会删除它。


“触发器和锁存器通常只是两个不同的配置”是吗?我希望可以使用LUT来实现闩锁(请注意,如果LUT不是无干扰的)。
avakar 2012年

@avakar,我知道在所有Xilinx FPGA(或至少所有远程的FPGA)中,锁存器都使用与触发器相同的硬件,在配置位流中仅相差一个位。我不确定其他品牌。
凯文·卡斯卡特

嗯 一些较旧的Altera设计具有反馈路径,该路径将允许使用LUT来实现锁存器。看起来在更新的设计中根本可能需要主要布线来实现锁存器。但是,这并不奇怪,因为在现代RTL设计中,很少需要实际的锁存器(而不是触发器)。
凯文·卡斯卡特

@avakar,我对Xilinx更为熟悉,其中的寄存器设备可以配置为触发器或锁存器。如果在Altera或其他供应商中无法做到这一点,它将使“不要使用锁存器设计”的一般建议更加强大。
Photon

@KevinCathcart和Photon:我知道,我对Xilinx并不熟悉,仅对Altera Cyclone系列没有专门的锁存电路。
avakar 2012年

0

如前所述,并非所有的块都是可以综合的。综合工具还可以接受某些模块,但是它们产生的结果与模拟器所产生的结果有所不同。

首先从敏感度列表开始。通常的规则是,它必须仅包含边缘检测结构(通常对可能的组合进行有限的选择),或者必须包含(可能通过使用*或systemverilog的always_comb)用作该块输入的每个信号。我们将前者称为组合块,而将后者称为顺序块。通常,如果您仅在组合块中包括一部分输入,则综合工具只会忽略您,并像指定了完整列表一样工作(创建模拟/合成不匹配)

第二次封锁与无封锁分配。在组合块中,差异并不重要,但在顺序块中,差异非常重要。

在顺序块中,非阻塞分配相当直接地对寄存器建模,而阻塞分配模型变量(根据设置和读取的顺序,可能隐含或不隐含寄存器)。通常,仅在同一块中读取在顺序块中使用阻塞分配的“ reg”集,并且不应在同一“ reg”上混合阻塞和非阻塞分配。

将阻塞分配和非阻塞分配混合到同一项目可能会导致综合失败。在一个块中进行块分配并在另一个块中进行读取可能会导致仿真/合成不匹配(甚至可能在不同的模拟运行之间甚至不匹配)。

现在我们有了一些基本规则,可以考虑编译器如何将代码转换为逻辑。

第一步是展开所有循环。这意味着循环必须具有可以在综合时确定的最大迭代次数,否则您将遇到综合失败。

然后,该工具可以分析该块的控制流并将其转换为数据流。每个变量成为一个或多个信号。每个if语句或类似构造都将成为一个或多个多路复用器,用于选择实际使用的结果集。

然后,该工具可能会尝试并应用一些优化。

在quartus中,通过进入“工具->网络列表查看器-> rtl查看器”,可以在构建项目后看到此过程的结果。

在根据抽象逻辑元素生成此结构表示之后,该工具将继续将那些抽象元素映射到芯片实际拥有的资源上。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.