FPGA开发入门----1. Mux的三种写法,RTL的认知大提升!

1A、门电路的Verilog代码之与门。

1B、门电路的Verilog代码之或门。

1C、门电路的Verilog代码之非门----这次是一个4位数据的NOT操作!

2A、多路选择器的多种写法之一。

2B、多路选择器的多种写法之二。

2C、多路选择器的多种写法之三。

3、Mux的三种写法,RTL的认知大提升!

----Mux毫无疑问是一个组合逻辑电路,竟然可以使用Always来表达Mux的行为!!

----从根上破除了一个错误认知,以为always就是时序逻辑,不用always就是组合逻辑。

----实际上,用了always的电路可以是组合逻辑(如Mux)。不用always的电路也可能是时序逻辑!

----换一个说法,不适用always并不必然意味着组合逻辑电路。它仍然可以通过实例化其它时序模块来构成时序逻辑电路。

----判断一个电路时组合电路还是时序电路,最终要看它综合出的网表中是否包含存储元件(触发器/锁存器),而不是看代码中是否出现了always关键字。

----写RTL代码,不光要理解代码的含义,还要有一根弦就是它会被综合成实际的电路以及电路的行为,这就是所谓的硬件思维。

----Always电路可以时组合逻辑(如Mux)。但正如上面的2C中的RTL代码注释,如果always {begin...end}之间的case没有罗列完整且没有default的话,则代码会被综合为时序逻辑电路!罗列完整则被综合为组合逻辑电路!

----在不带时钟的always语句中,如果if-else的覆盖不完整,或者case的覆盖不完整且没有default兜底,则最终综合的结果是锁存器latch!!!

----在最终综合结果之前,也可以通过RTL Schematic来查看RTL对应的原理图,也是锁存器Latch!!

----从这个例子也可以看出,RTL代码不是纯逻辑,它是要综合成【标准单元(standard cell)】然后被制造出来的。RTL综合直到生成FPGA的位流文件,或者RTL综合直到生成ASIC的版图GDS文件,和纯RTL的仿真获取纯逻辑的结果,是不一样的。还是前面说的,要有所谓的硬件思维。硬件思维是怎么练出来呢,在芯片得知识里泡得久了就练出来了。

4、再总结提升:

使用always不必然意味着时序逻辑电路。 它也可以用来描述组合逻辑电路。
不使用always不必然意味着组合逻辑电路。 它仍然可以通过实例化其他时序模块来构成时序逻辑电路。

下面通过具体的例子详细解释这两个结论。

4-1. 使用 always 不一定是时序逻辑。

always本身只是一个过程块,它告诉综合工具:"这里的代码需要重复执行"。最终生成组合逻辑还是时序逻辑,关键在于敏感列表和块内的描述方式。

4-1-A. 用 always 描述组合逻辑。

当always块用于描述组合逻辑时,它必须是电平敏感的。这意味着每当输入信号的电平发生变化时,块内的逻辑就会重新计算。

现代推荐写法(Verilog-2001及以后):

// 使用 @(*) 自动推断所有输入信号,这是最安全、最推荐的组合逻辑写法

always @(*) begin

if (sel == 1'b1)

y = a;

else

y = b;

end

这里的 @(*) 告诉综合工具:"请自动找出这个always块中所有被读取的信号,并把它们都加入敏感列表"。这样,a, b, sel 中任何一个变化,y 的值都会被更新。这综合出来就是一个2选1的多路选择器,是纯粹的组合逻辑。

重要陷阱:不完整的条件赋值会产生锁存器

如果在用always描述组合逻辑时,if-else或case语句没有覆盖所有可能的分支,导致在某些条件下输出没有被赋值,综合工具就会认为你需要"记住"上一次的值,从而推断出一个锁存器。

// 错误示例:会产生锁存器

always @(*) begin

if (en) begin

y = d;

end

// 如果 en 为 0,y 没有被赋值,综合器会推断出锁存器来保持 y 的值

end

锁存器是时序元件,所以这个always块最终产生了时序逻辑,但这通常是设计失误。

4-1-B. 用 always 描述时序逻辑。

当always块用于描述时序逻辑时,它必须是边沿敏感的。这意味着它只在时钟信号的上升沿或下降沿(或复位信号的边沿)被触发。

// 典型的D触发器描述

always @(posedge clk) begin

q <= d; // 注意:时序逻辑推荐使用非阻塞赋值 <=

end

这里的 posedge clk 指定了只有在clk信号从0变到1的瞬间,q才会被赋值为d。在两个时钟沿之间,无论d如何变化,q都保持不变。这就是典型的时序逻辑,它具有"记忆"功能。

4-2. 不使用 always 不一定是组合逻辑

一个模块是否是时序电路,取决于它最终是否包含了存储元件(如触发器、锁存器)。always只是创建这些元件的一种方式,但不是唯一方式。

4-2-A. 通过实例化时序模块

你可以设计一个没有任何always语句的顶层模块,但它仍然是一个复杂的时序系统,因为它实例化了很多包含always的子模块。

// top_module.v - 这个模块里没有 always

module top_module (

input clk,

input rst_n,

input data_in,

output reg data_out

);

// 实例化一个已经存在的时序模块(例如,一个移位寄存器)

// my_shift_reg 内部肯定使用了 always @(posedge clk)

my_shift_reg u_shift_reg (

.clk (clk),

.rst_n (rst_n),

.din (data_in),

.dout (data_out)

);

endmodule

top_module本身没有always,但因为它包含了my_shift_reg这个时序模块,所以整个top_module的行为是时序的。

4-2-B. 使用门级原语构建

在非常底层的描述中,你可以用基本的门级原语(如nand, nor)来搭建一个锁存器或触发器,这同样不需要always语句。

// 用两个或非门搭建一个SR锁存器

module sr_latch_nor (output q, output q_bar, input s, input r);

nor #1 g1 (q, q_bar, s);

nor #1 g2 (q_bar, q, r);

endmodule

这个sr_latch_nor模块没有always,但它无疑是一个时序元件。

4-3. 再总结提升:

always是一个语法工具,而不是逻辑类型的定义符。 它既能生成组合逻辑,也能生成时序逻辑,关键在于你怎么用它(敏感列表和代码完整性)。

判断一个电路是组合还是时序,最终要看它综合出的网表中是否包含存储元件(触发器/锁存器),而不是看代码中是否出现了always关键字。

因此,理解Verilog代码背后的硬件意图,远比记住语法规则本身更重要。

<<<<<<<<完>>>>>>>>

文末附一副封面图。

摘要:本文系统阐述了Verilog硬件描述语言的关键概念,重点解析了组合逻辑与时序逻辑的本质区别。首先介绍了基本门电路(与门、或门、非门)的实现方法,然后通过多路选择器的三种写法展示了RTL设计的灵活性。核心观点指出:always语句既可描述组合逻辑(电平敏感),也可实现时序逻辑(边沿触发);而判断电路性质的关键在于综合后是否包含存储元件(触发器/锁存器),而非代码形式。特别强调硬件思维的重要性,提醒设计者注意不完整条件语句可能意外生成锁存器的问题,建议通过RTL原理图验证设计意图,避免常见的认知误区。

相关推荐
XINVRY-FPGA20 小时前
XCVP1802-2MSILSVC4072 AMD Xilinx Versal Premium Adaptive SoC FPGA
人工智能·嵌入式硬件·fpga开发·数据挖掘·云计算·硬件工程·fpga
9527华安2 天前
国产安路FPGA开发设计培训课程,提供开发板+工程源码+视频教程+技术支持
fpga开发·fpga·安路·视频教程·培训·安路fpga
UVM_ERROR2 天前
硬件设计实战:解决Valid单拍采样失效问题(附非阻塞赋值与时序对齐核心要点)
驱动开发·fpga开发·github·芯片
brave and determined2 天前
可编程逻辑器件学习(day36):从沙粒到智能核心:芯片设计、制造与封装的万字全景解析
fpga开发·制造·verilog·fpga·芯片设计·硬件设计·芯片制造
步达硬件2 天前
【FPGA】FPGA开发流程
fpga开发
我爱C编程3 天前
【仿真测试】基于FPGA的完整16QAM通信链路实现,含频偏锁定,帧同步,定时点,Viterbi译码,信道,误码统计
fpga开发·16qam·帧同步·卷积编码·viterbi译码·维特比译码·频偏锁定
s09071364 天前
ZYNQ DMA to UDP 数据传输系统设计文档
网络协议·fpga开发·udp
燎原星火*4 天前
QSPI IP核 基本参数
fpga开发
XINVRY-FPGA4 天前
XCVU9P-2FLGC2104I Xilinx AMD Virtex UltraScale+ FPGA
嵌入式硬件·机器学习·计算机视觉·fpga开发·硬件工程·dsp开发·fpga