3、开发流程入门:FPGA设计流程与第一个工程

各位同学,欢迎来到第三章。这一章咱们要动真格的了。

前面两章我们聊了FPGA是什么、能干什么。但光说不练假把式,今天我们就来走一遍完整的FPGA开发流程。从设计到下载,每一步我都会结合自己的经验来讲。

嗯,先给你看一张图,这是我画的一个FPGA开发流程框架。你把它印在脑子里,后面每一步都会对应到这张图上。

FPGA开发流程框架 设计 RTL编码/原理图 综合 逻辑综合/网表 实现 布局布线/映射 下载 烧录/配置 设计阶段 • 编写Verilog/VHDL代码 • 功能仿真验证 综合阶段 • 将RTL转为门级网表 • 检查资源利用率 实现阶段 • 布局布线(PAR) • 时序分析/约束 下载阶段 • 生成bitstream • 烧录到FPGA 迭代调试 核心思想:设计→综合→实现→下载,每一步都可能需要回头修改

这张图我画了好几次才满意。你仔细看,它是个闭环——不是走完就完事了,经常要回头改。

3.1 FPGA设计流程:四步走

FPGA开发说白了就四个步骤:设计 → 综合 → 实现 → 下载。我当年刚入行时,以为写代码就是全部,结果被综合报错折磨得够呛。后来才明白,每一步都有它的门道。

3.1.1 设计(Design Entry)

这是第一步,也是你最需要花心思的一步。

  • 编写RTL代码:用Verilog或VHDL描述你的逻辑功能。我个人习惯用Verilog,简洁明了。
  • 原理图输入:有些老工程师喜欢画原理图,但说实话,复杂项目还是代码靠谱。
  • 功能仿真:写代码后先跑一遍仿真,看看波形对不对。这一步能省下后面大量调试时间。
我的经验:写代码前先画个时序图。把输入输出波形画清楚,再动手写。这样能避免很多逻辑错误。

3.1.2 综合(Synthesis)

综合就是把你的Verilog代码翻译成FPGA能理解的“门级网表”。

你想想看,你写了个 assign led = ~btn;,综合工具会把它变成查找表(LUT)和触发器(FF)的组合。

我曾经遇到过一个坑:写了一个很大的组合逻辑,综合后资源爆了。后来拆成流水线,才解决问题。所以综合报告一定要看,尤其是资源利用率。

3.1.3 实现(Implementation)

实现包含三个子步骤:

  1. 映射(Map):把门级网表映射到FPGA的具体资源上。
  2. 布局布线(Place & Route):决定每个逻辑单元放在芯片的哪个位置,怎么连线。
  3. 时序分析(Timing Analysis):检查你的设计能不能跑在目标频率上。
注意:布局布线这一步很耗时。如果时序不满足,你可能需要回去改代码,或者调整约束。我曾经为了一个100MHz的时钟,来回折腾了三天。

3.1.4 下载(Download)

最后一步,生成比特流文件(.bit或.mcs),通过下载器烧到FPGA里。

嗯,这里要注意:下载前一定要确认板子供电正常、JTAG线接对了。我第一次下载时,线没插紧,折腾了半小时才发现。

3.2 Lattice Diamond软件安装与界面介绍

我们课程用的是Lattice的FPGA,所以配套软件是Diamond。这个软件我用了好几年,从3.0版本到现在的3.12,界面变化不大。

3.2.1 安装要点

  • 版本选择:建议用3.11或3.12,比较稳定。
  • 安装路径:不要有中文和空格。我见过有人装在“Program Files (x86)”里,结果license死活认不到。
  • License配置:安装后要配置license文件。环境变量 LM_LICENSE_FILE 指向你的license文件路径。
避坑指南:我曾经因为杀毒软件拦截了license服务,导致软件打不开。安装时最好关掉杀毒软件。

3.2.2 界面布局

Diamond的界面分为几个区域:

区域 功能 我的建议
左侧:文件列表 显示工程文件、源文件、约束文件 把文件分好文件夹,别全堆在根目录
中间:编辑区 代码编辑、原理图查看 字体调大一点,保护眼睛
下方:输出窗口 显示综合、实现、下载的日志 养成看日志的习惯,错误信息都在这里
右侧:进程视图 显示当前执行的任务进度 双击可以重新运行某一步

3.3 第一个工程:点亮LED

好了,理论说完了,咱们来动手。第一个工程永远是点亮LED,这是硬件界的“Hello World”。

3.3.1 创建工程

  1. 打开Diamond,点击 File → New → Project
  2. 输入工程名,比如 led_test,选择保存路径。
  3. 选择器件型号。我们用的是Lattice MachXO2系列,具体型号看板子上的丝印。
  4. 点击Finish,工程就建好了。

3.3.2 编写代码

新建一个Verilog文件,命名为 led_top.v。输入以下代码:

module led_top (
    input  wire clk,      // 板载时钟,比如12MHz
    input  wire rst_n,    // 复位,低有效
    output reg  led       // LED输出
);

// 分频计数器,让LED闪烁
reg [23:0] cnt;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        cnt <= 24'd0;
    else
        cnt <= cnt + 1'b1;
end

// 取最高位驱动LED
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        led <= 1'b0;
    else
        led <= cnt[23];  // 约0.7秒闪烁一次(12MHz时钟)
end

endmodule

这段代码很简单:用计数器分频,把最高位输出到LED。这样LED就会以大约0.7秒的频率闪烁。

关键点:cnt[23] 在12MHz时钟下,翻转频率约为 12MHz / 2^24 ≈ 0.7Hz。如果你板子时钟不同,记得调整位数。

3.3.3 综合与实现

  1. 在进程视图中双击 Synthesize Design,开始综合。
  2. 综合完成后,双击 Map DesignPlace & Route
  3. 每一步完成后,检查输出窗口有没有错误或警告。

我习惯在综合后先看一眼资源报告。如果LUT用得太多了,说明代码可能有问题。

3.3.4 下载到板子

  1. 连接下载器(比如FTDI或Lattice专用下载线)到板子。
  2. 点击 Tools → Programmer,打开下载工具。
  3. 选择生成的bit文件(通常在 impl/ 目录下)。
  4. 点击 Program,等待进度条走完。
常见问题:如果下载失败,先检查JTAG线序。VCC、GND、TMS、TCK、TDI、TDO,六根线一根都不能错。我见过有人把TMS和TCK接反了,折腾了一下午。

3.3.5 验证结果

下载成功后,板子上的LED应该开始闪烁了。如果不亮,别慌:

  • 检查LED是否共阳还是共阴,代码里的极性对不对。
  • 检查复位引脚是否拉高(如果rst_n是高有效,代码要改)。
  • 用示波器或逻辑分析仪看看时钟有没有进来。

我记得第一次点亮LED时,板子没反应。后来发现是复位引脚没接上拉电阻。嗯,这种小问题最磨人。

3.4 本章小结

这一章我们走完了FPGA开发的完整流程。从设计到下载,每一步都有它的意义。你可能会觉得点亮一个LED太简单了,但相信我,这个流程会贯穿你所有的FPGA项目。

Diamond软件虽然不如Vivado那么花哨,但胜在轻量、稳定。用习惯了你会发现,它其实很顺手。

下一章我们会深入Verilog语法,开始写更复杂的逻辑。但今天,先享受一下LED闪烁的成就感吧。


公众号:蓝海资料掘金营,微信deep3321