FPGA 学习笔记(二):组合逻辑基础——译码器实现
组合逻辑是数字电路的基础。通过 01max2(二选一选择器)和 02decoder_3_8(3-8 译码器)两个小项目,我们来看看 Verilog 的基本描述方式。
1. 2选1多路选择器(max2)
作为 FPGA 设计的“Hello World”,2选1多路选择器(MUX)是理解组合逻辑逻辑和 Verilog 模块化思维的最佳起点。
1.1 设计目标
实现一个逻辑选择器:当选择信号 sel 为 0 时,输出端口 a 的信号;当 sel 为 1 时,输出端口 b 的信号。
1.2 RTL 代码实现 (rtl/max2.v)
在 Verilog 中,一切逻辑都封装在 module 中。以下是标准的模块定义方式:
1 | |
知识点解析:
- 端口声明:现代 Verilog 推荐直接在
module括号内定义input/output及其类型,使代码更简洁。例如input a, output wire out;。对于通过assign语句赋值的输出,通常隐式为wire,但显式声明output wire更清晰;对于在always块中赋值的输出,则需声明为output reg。 - 连续赋值 (
assign):用于描述组合逻辑,它像焊线一样将等号右边的逻辑结果持续“驱动”到左边的wire变量上。 - 三目运算符:
(条件) ? 真值 : 假值,是实现简单选择逻辑的最佳方式。
1.3 仿真验证 (sim/max2_tb.v)
为了验证逻辑是否正确,我们需要编写测试脚本(Testbench)来模拟输入信号。
1 | |
仿真要点总结:
timescale:例如1ns/1ps表示代码中的#1代表 1ns,而仿真器内部计算精度可以达到 1ps。regvswire:在仿真环境中,输入信号通常在initial块中赋值,必须定义为reg类型;而输出信号只是接收反馈,定义为wire。initial块与begin-end:用于书写测试过程,按时间顺序执行。
2. 3-8 译码器(decoder_3_8)
3-8 译码器是组合逻辑中的经典案例,其核心逻辑是将 3 位二进制输入转换为 8 位互斥的输出(独热码)。
2.1 设计目标
根据输入信号 {A2, A1, A0} 的二进制值,选中对应的输出通道(Y0~Y7)。例如当输入为 3'b000 时,Y0 输出为 1,其余输出均为 0。
2.2 RTL 代码实现 (rtl/decoder_3_8.v)
在处理多分支逻辑时,使用 always 块配合 case 语句比 assign 更加直观。
1 | |
这里模块定义可以更加简明一些,我们如果使用总线来代替8个独立的输出信号,就有
1 | |
这种写法在实际工程中更常见,因为:
- 便于参数化扩展
- 便于约束文件绑定
- 易于与总线接口对接
- 更符合综合器优化习惯
知识点解析:
always @(*):组合逻辑的过程描述方式。这里的*是通配符,意味着任何输入信号的变化都会触发块内逻辑的重新计算。reg型变量:在always块中被赋值的信号必须定义为reg类型。需要注意,在组合逻辑中,reg并不代表触发器(Flip-Flop),它仅仅是 Verilog 的语法要求。- 位拼接运算符
{}:将多个独立信号按顺序“捆绑”在一起。这在处理总线或并列的输出端口时非常高效。 - 数值表达方式:Verilog 中数值的格式为
位宽'进制符号数值。8'b0000_0100:8 位二进制数。b代表二进制 (binary)。4'd10:4 位十进制数 10 (等同于4'b1010)。d代表十进制 (decimal)。12'hFAB:12 位十六进制数 FAB (等同于12'b1111_1010_1011)。h代表十六进制 (hexadecimal)。3'o7:3 位八进制数 7 (等同于3'b111)。o代表八进制 (octal)。- 下划线
_仅用于提高可读性,在编译时会被忽略。
case语句:用于根据表达式的值,执行不同的代码块。- 基本语法:
case (表达式) ... endcase。 - 匹配项:每个
case项的表达式必须与case关键字后的表达式类型和位宽匹配。 default:可选,当所有case项都不匹配时执行default后的代码。对于组合逻辑,强烈建议包含default项,以避免产生锁存器(latch)。
- 基本语法:
2.3 仿真验证 (sim/decoder_3_8_tb.v)
通过 Testbench 遍历 000 到 111 的所有组合,验证译码逻辑的正确性。
1 | |
3. 总结
- 赋值选择:在
assign中赋值的变量定义为wire,在always块中赋值的必须定义为reg。 - 灵活性:组合逻辑优先考虑
assign+ 三目运算符;当逻辑复杂(分支多)时,使用always+case更利于维护。 - 验证意识:每一个模块都应对应一个 Testbench,覆盖所有可能的逻辑边界。
FPGA 学习笔记(二):组合逻辑基础——译码器实现
http://blog.556756.xyz/2026/02/24/FPGA/Combinational_Logic/