Verilog“总是”语句是如何在硬件中实现的?

电器工程 验证日志
2022-01-08 03:20:24

Verilogalways语句,即

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

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

3个回答

首先,请注意并非所有 Verilog 设计都是可综合的。通常,只有非常特定的结构子集可以用于要在硬件中实现的设计。

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

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

always @(*) begin
    // combinational
end

always @(posedge clk) begin
    // sequential
end

在前一种情况下,*表示只要块中使用的任何信号发生变化,就应该执行该块,或者等效地,该块应该连续执行。因此,reg与组合块具有相似性的 salways被实现为使用组合逻辑(即门)从其他信号计算的信号。

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(由上述触发器驱动)。优化合成器将结合两个非门并使用一个非门和一个触发器。

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

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

always块通常用于描述触发器、锁存器或多路复用器该代码将使用触发器、锁存器或多路复用器来实现。

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

一般来说,使用 Verilog 进行设计有两种方法:

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

  2. 只需编写 Verilog,不用担心底层硬件是什么样子。然而,即使你这样做了,你仍然必须知道什么是可合成的,什么是不可合成的。因此,您将再次查看工具供应商提供的样板文件,并将其调整到您的应用程序中。

编辑

Avakar 的回答对您的问题来说要好得多,但这引发了一些关于 Xilinx 和 Altera 之间差异的有趣讨论,所以我不会删除它。

如前所述,并非所有块总是可合成的。还有一些模块可以被综合工具接受,但会产生与模拟器产生的结果不同的结果。

首先是敏感列表。通常的规则是它必须要么只包含边缘检测结构(并且通常有有限的可能组合选择),要么它必须包含(可能通过使用 * 或 systemverilog 的 always_comb)每个用作块输入的信号。我们称前者为顺序块,后者为组合块。通常,如果您在组合模块中仅包含输入的子集,综合工具将忽略您并表现得好像已指定完整列表(创建模拟/综合不匹配)

第二个阻塞与无阻塞分配。在组合块中,差异并不重要,但在顺序块中却很重要。

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

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

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

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

然后该工具可以分析块的控制流并将其转换为数据流。每个变量变成一个或多个信号。每个 if 语句或类似的构造都成为一个或多个多路复用器,选择实际使用哪一组结果。如果一个变量从一个组合总是块的一次运行到下一次保持它的值,那么将生成一个寄存器来保持该值。

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

在 quartus 中,您可以在构建项目后进入“tools->netlist viewers->rtl viewer”查看此过程的结果。

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