4、FPGA逻辑设计入门:Verilog/VHDL基础、Block Design流程、IP核集成(如AXI DMA)
好,咱们进入第四章。这一章是FPGA设计的核心入门课。说实话,很多新手一上来就被Verilog语法吓住了,或者被Vivado的Block Design搞得晕头转向。别急,我带你一步步捋清楚。
4.1 Verilog/VHDL基础:硬件描述语言没那么玄乎
先说说语言选择。我个人习惯用Verilog,因为它在工业界更流行,尤其是AMD/Xilinx的生态里。VHDL当然也很好,语法更严谨,但写起来啰嗦一点。你选哪个都行,关键是理解硬件描述语言的本质——它不是写软件,是在画电路。
举个例子,最简单的与门:
// Verilog
module and_gate (
input wire a,
input wire b,
output wire y
);
assign y = a & b;
endmodule
你看,这跟C语言里的if语句完全不是一回事。assign语句对应的是组合逻辑,综合工具会把它映射成真实的LUT(查找表)。我在项目中遇到过有人把Verilog当C写,满屏的always块和for循环,结果综合出来资源爆炸——嗯,这就是没理解硬件思维。
4.2 组合逻辑 vs 时序逻辑
这是FPGA设计里最基础也最容易搞混的概念。说白了:
- 组合逻辑:输出只取决于当前输入,没有记忆功能。比如加法器、多路选择器。
- 时序逻辑:输出还取决于之前的状态,需要时钟驱动。比如计数器、移位寄存器。
写代码时怎么区分?看敏感列表:
// 组合逻辑:always @(*) 或 assign
always @(*) begin
if (sel)
out = a;
else
out = b;
end
// 时序逻辑:always @(posedge clk)
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt <= 8'd0;
else if (en)
cnt <= cnt + 1'b1;
end
注意看,时序逻辑里我用的是非阻塞赋值 <=,组合逻辑用的是阻塞赋值 =。这个区别很重要。我曾经因为混用这两种赋值方式,导致仿真和实际行为不一致,查了整整两天——从那以后我再也不敢乱用了。
4.3 Block Design流程:图形化搭积木
Vivado的Block Design(简称BD)是AMD平台的一大特色。说白了,就是让你像搭积木一样,把各种IP核拖拽连接,自动生成顶层代码。我个人非常喜欢这个流程,尤其是做复杂系统时,省去了大量手写连线的时间。
基本步骤:
- 创建Vivado工程,选择目标芯片(比如Zynq-7000或Versal)。
- 点击「Create Block Design」,给设计取个名字。
- 从IP Catalog里拖出需要的IP核,比如Zynq Processing System、AXI DMA、BRAM Controller等。
- 用鼠标连线:数据走AXI总线,控制走GPIO或中断。
- 右键点击「Validate Design」,检查有没有漏连或冲突。
- 生成顶层HDL文件,然后综合、实现、生成比特流。
4.4 IP核集成:以AXI DMA为例
IP核集成是FPGA设计的重头戏。咱们拿AXI DMA来开刀,这个IP核在高速数据传输里用得特别多。
AXI DMA的作用很简单:它能把数据从内存搬到FPGA逻辑,或者反过来。你想想看,如果没有DMA,CPU得一条一条指令去搬数据,效率极低。有了DMA,CPU只需要告诉它「从地址A搬N个字节到地址B」,然后就可以去干别的事了。
配置AXI DMA时,有几个关键参数:
| 参数 | 说明 | 我的建议 |
|---|---|---|
| Width of Buffer Length Register | 一次传输的最大字节数 | 一般设成14(16KB),够用 |
| Enable Scatter Gather | 是否支持分散聚合模式 | 新手先关掉,用Simple模式 |
| Stream Data Width | 数据位宽,通常32或64位 | 跟你的AXI总线宽度匹配 |
| Allow Unaligned Transfers | 是否允许非对齐传输 | 一般勾上,省得后面出问题 |
集成到BD里后,你还需要写一个简单的控制模块,用来启动DMA传输。代码大概长这样:
// 启动一次DMA读传输
always @(posedge clk) begin
if (start_transfer) begin
// 设置源地址(内存)
axi_dma_0_s2mm_da <= src_addr;
// 设置传输长度
axi_dma_0_s2mm_len <= transfer_len;
// 启动传输
axi_dma_0_s2mm_go <= 1'b1;
end
end
嗯,这里要注意:DMA传输完成后会拉高一个中断信号。你需要在PS端(处理器系统)响应这个中断,或者用轮询方式检查状态寄存器。我个人习惯用中断,因为轮询会浪费CPU时间。
4.5 实战建议:从简单开始
如果你刚开始学FPGA逻辑设计,我的建议是:
- 先写几个简单的Verilog模块,比如计数器、移位寄存器、状态机。别一上来就搞AXI总线。
- 然后用Block Design搭一个最小系统:Zynq PS + AXI GPIO + LED。跑通再说。
- 最后再尝试集成AXI DMA,配合一个简单的数据生成器(比如LFSR)做回环测试。
记住,FPGA设计是个实践活。看十遍教程不如自己跑一遍仿真。我当年学的时候,光是搞懂always块的敏感列表就花了三天——但一旦理解了,后面就顺了。
下一章咱们会深入讲AXI总线的时序和协议,那是连接PS和PL的命脉。准备好了吗?