Verilog always
语句,即
always @(/* condition */)
/* block of code */
block of code
只要condition
满足就执行。这样的always
模块如何在硬件中实现?
posedge x
正好x
posedge
。
Verilog always
语句,即
always @(/* condition */)
/* block of code */
block of code
只要condition
满足就执行。这样的always
模块如何在硬件中实现?
posedge x
正好x
posedge
。
Answers:
首先,请注意,并非所有Verilog设计都是可综合的。通常,只能在要以硬件实现的设计中使用构造的非常具体的子集。
出现的一个重要限制是每个reg
变量最多只能在一个always
语句中分配给它。换句话说,reg
s对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
*
,我认为它指示了只要该块中的任何信号发生变化(与设计相反),都应执行该块。
一个always
块被通常用于描述触发器,锁存器,或多路复用器。该代码将通过触发器,锁存器或多路复用器实现。
在FPGA中,触发器和锁存器通常只是通用寄存器设备的两种不同配置。多路复用器将由一个或多个通用逻辑元件(LUT)构成。
通常,使用Verilog进行设计有两种方法:
根据门和寄存器可视化所需的逻辑,然后弄清楚如何在Verilog中对其进行描述。FPGA供应商或综合工具供应商的综合指南书为您可能要使用的最常见结构提供了样板。
只需编写Verilog,不必担心基础硬件的外观。但是,即使这样做,您仍然必须知道什么是可合成的,什么是不可合成的。同样,您将查看工具供应商提供的样板并使其适应您的应用程序。
编辑
对于您的问题,Avakar的答案是一个更好的答案,但这激发了有关Xilinx和Altera之间区别的一些有趣的讨论,因此我不会删除它。
如前所述,并非所有的块都是可以综合的。综合工具还可以接受某些模块,但是它们产生的结果与模拟器所产生的结果有所不同。
首先从敏感度列表开始。通常的规则是,它必须仅包含边缘检测结构(通常对可能的组合进行有限的选择),或者必须包含(可能通过使用*或systemverilog的always_comb)用作该块输入的每个信号。我们将前者称为组合块,而将后者称为顺序块。通常,如果您仅在组合块中包括一部分输入,则综合工具只会忽略您,并像指定了完整列表一样工作(创建模拟/合成不匹配)
第二次封锁与无封锁分配。在组合块中,差异并不重要,但在顺序块中,差异非常重要。
在顺序块中,非阻塞分配相当直接地对寄存器建模,而阻塞分配模型变量(根据设置和读取的顺序,可能隐含或不隐含寄存器)。通常,仅在同一块中读取在顺序块中使用阻塞分配的“ reg”集,并且不应在同一“ reg”上混合阻塞和非阻塞分配。
将阻塞分配和非阻塞分配混合到同一项目可能会导致综合失败。在一个块中进行块分配并在另一个块中进行读取可能会导致仿真/合成不匹配(甚至可能在不同的模拟运行之间甚至不匹配)。
现在我们有了一些基本规则,可以考虑编译器如何将代码转换为逻辑。
第一步是展开所有循环。这意味着循环必须具有可以在综合时确定的最大迭代次数,否则您将遇到综合失败。
然后,该工具可以分析该块的控制流并将其转换为数据流。每个变量成为一个或多个信号。每个if语句或类似构造都将成为一个或多个多路复用器,用于选择实际使用的结果集。
然后,该工具可能会尝试并应用一些优化。
在quartus中,通过进入“工具->网络列表查看器-> rtl查看器”,可以在构建项目后看到此过程的结果。
在根据抽象逻辑元素生成此结构表示之后,该工具将继续将那些抽象元素映射到芯片实际拥有的资源上。
block of code
是...