第三讲:硬件描述语言基础(Verilog)——模块化设计、组合逻辑与时序逻辑、仿真与Testbench编写
说实话,Verilog 这门语言,你把它当软件学就完了。我见过太多新手,上来就写 C 语言的思维,结果综合出来的电路一塌糊涂。这一讲,咱们就聊聊 Verilog 的核心三块:模块化怎么搭、组合和时序怎么分、仿真怎么写。
3.1 模块化设计——把大电路拆成小积木
模块化,说白了就是“分而治之”。一个复杂的 Zynq 系统,你不可能在一个文件里写完所有逻辑。我个人的习惯是:每个功能块一个模块,顶层只做连线。
举个例子,一个简单的计数器模块:
module counter #(
parameter WIDTH = 8
)(
input wire clk,
input wire rst_n,
input wire en,
output reg [WIDTH-1:0] count
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= 0;
else if (en)
count <= count + 1;
end
endmodule
你看,这个模块只做一件事:计数。输入输出清清楚楚。我在项目中遇到过有人把 SPI 控制器、UART、GPIO 全写在一个模块里,结果调试时改一处崩三处。模块化设计,就是让你能“各个击破”。
wire 和 reg 明确区分。输入用 wire,输出用 reg(如果是时序逻辑)。这样读代码的人一眼就知道信号流向。
3.2 组合逻辑 vs 时序逻辑——本质区别在哪?
很多初学者搞不清这两个概念。我换个说法:组合逻辑是“纯电路”,输入一变,输出立刻变,没有记忆。时序逻辑是“带寄存器的电路”,只在时钟沿更新,有记忆能力。
组合逻辑:
assign sum = a + b; // 只要 a 或 b 变,sum 立刻变
时序逻辑:
always @(posedge clk) begin
sum_reg <= a + b; // 只在时钟上升沿更新
end
嗯,这里要注意:组合逻辑用 assign 或 always @(*),时序逻辑用 always @(posedge clk)。千万别混用。我曾经见过有人把组合逻辑写在 always @(posedge clk) 里,结果综合出来一堆奇怪的锁存器。
if 或 case 没有覆盖所有分支,会综合出锁存器(latch)。我曾经因为这个原因,一个简单的译码器多花了半天时间排查。解决办法:要么补全所有分支,要么给默认值。
3.3 仿真与 Testbench 编写——不仿真就上板?你胆子真大
我刚开始做 FPGA 时,也是写完代码直接烧录。结果呢?板子冒烟了(夸张说法,但确实烧坏过一片)。后来我养成了习惯:先写 Testbench,再写设计代码。这叫“测试驱动开发”。
一个标准的 Testbench 长这样:
`timescale 1ns / 1ps
module tb_counter;
// 信号声明
reg clk;
reg rst_n;
reg en;
wire [7:0] count;
// 实例化被测试模块
counter #(
.WIDTH(8)
) uut (
.clk (clk),
.rst_n (rst_n),
.en (en),
.count (count)
);
// 时钟生成
initial begin
clk = 0;
forever #5 clk = ~clk; // 100MHz 时钟
end
// 测试激励
initial begin
// 初始化
rst_n = 0;
en = 0;
#20;
rst_n = 1;
#10;
en = 1;
#200;
en = 0;
#50;
$finish;
end
// 波形监控
initial begin
$monitor("time=%0t, count=%d", $time, count);
end
endmodule
你看,Testbench 没有端口,它自己产生时钟、复位、激励,然后观察输出。我个人习惯用 $monitor 打印关键信号,用波形查看器看时序细节。
3.4 知识体系总览
下面这张图,是我自己总结的 Verilog 基础学习路线。你照着这个顺序学,不会走弯路。
3.5 实战建议
最后,给你几个我踩过坑后的建议:
- 代码风格统一:我习惯用下划线命名法(如
data_valid),模块名大写开头(如UartCtrl)。团队协作时,风格比能力重要。 - 仿真覆盖率:别只测正常情况。测一下复位释放瞬间、时钟抖动、输入毛刺。我吃过这个亏。
- 版本管理:Verilog 代码一定要用 Git。我见过有人把
final_v2、final_v3_final这种文件名传遍全组,太可怕了。
tb_模块名.v。这样找起来方便,别人接手也清楚。
好了,这一讲就到这里。记住:Verilog 不是软件,是硬件描述。你写的是电路,不是程序。多仿真、多思考、多动手,慢慢就有感觉了。
可可精品资料库