4. Quartus工程管理

在Quartus Prime中,一个可交付的FPGA工程远不止一个.qpf文件。真正决定工程能否被团队复用、能否稳定复现、能否在同一套RTL上产出多个SKU的,是工程目录结构、版本控制策略、参数化机制与多配置管理这四件事的组合。本节围绕这四点展开,并给出可直接落地的目录模板与配置示例。

一、工程目录结构:把“可编译”升级为“可交付”

Quartus默认把.qpf、.qsf、.sof、数据库目录db/、增量编译目录incremental_db/混放在同一层。这种结构在单人调试时无碍,但一旦进入版本控制,就会把大量二进制中间产物提交进仓库,导致仓库膨胀、冲突频发。推荐采用“源码与产物分离”的目录结构:

prj_uart_bridge/
├── rtl/                 # 可综合RTL,按功能分子目录
│   ├── core/
│   └── periph/
├── ip/                  # 生成的IP核(.ip/.qip/.v)
├── constr/              # 约束文件
│   ├── pin.sdc
│   └── timing.sdc
├── sim/                 # 仿真testbench与脚本
├── scripts/             # 编译、烧录、回归脚本
├── cfg/                 # 多配置参数文件
│   ├── sku_a.tcl
│   └── sku_b.tcl
├── output/              # 编译产物(不入库)
│   ├── sof/
│   └── rbf/
└── doc/                 # 寄存器手册、接口说明

关键原则有三条:其一,db/、incremental_db/、output/、*.qws、*.sof、*.rbf一律写入.gitignore,只保留源码、约束、脚本与IP描述文件;其二,.qsf中所有路径使用相对路径,避免换机器后路径失效;其三,IP核只提交.ip与.qip,不提交其生成的HDL副本,由qsys-generate或quartus_ipgenerate在编译时重建。

二、版本控制:让每次编译都可追溯

Quartus工程入库时,建议把.qpf、.qsf、.sdc、.ip、RTL与脚本全部纳入Git。为便于追溯“哪个commit对应哪版bit流”,可在编译脚本中自动写入版本信息:

# scripts/build.tcl
set rev [exec git rev-parse --short HEAD]
set_property LAST_COMPILATION_REVISION $rev [get_current_revision]

这样在output/目录中生成的.sof即可与Git提交号一一对应。对于多人协作,.qsf是冲突高发文件,建议按功能拆分为多个.qsf片段(如pin.qsf、timing.qsf),通过source方式在主.qsf中引用,减少同一文件的并发修改。

三、参数化工程:一套RTL,多种形态

参数化是Quartus工程复用的核心手段,常见有三层:Verilog参数、IP参数、Tcl脚本参数。以UART桥接器为例,波特率、FIFO深度、数据位宽均可参数化:

module uart_bridge #(
    parameter CLK_FREQ = 50_000_000,
    parameter BAUD     = 115200,
    parameter FIFO_DEPTH = 16
)(
    input  wire clk,
    input  wire rst_n,
    input  wire rx,
    output wire tx
);
    localparam BAUD_DIV = CLK_FREQ / BAUD;
    // ...
endmodule

在工程层面,通过.qsf中的VERILOG_MACRO或Tcl的set_global_assignment把参数注入顶层:

set_global_assignment -name VERILOG_MACRO "BAUD=115200"
set_global_assignment -name VERILOG_MACRO "FIFO_DEPTH=16"

这样同一份RTL即可通过不同宏定义生成不同配置,无需复制源码。

四、多配置管理:Revision与Tcl脚本协同

Quartus的Revision机制允许在同一工程下维护多个编译配置,每个Revision拥有独立的.qsf设置、引脚约束与编译结果。典型做法是:主工程.qpf下建立sku_a、sku_b两个Revision,分别对应不同封装或不同外设组合。切换与编译可通过Tcl脚本自动化:

# cfg/sku_a.tcl
set_current_revision sku_a
set_global_assignment -name FAMILY "Cyclone IV E"
set_global_assignment -name DEVICE EP4CE10F17C8
set_global_assignment -name VERILOG_MACRO "SKU=A"
source constr/pin_sku_a.sdc

执行quartus_sh -t cfg/sku_a.tcl即可完成配置切换,再调用quartus_map、quartus_fit、quartus_asm完成全流程编译。多配置管理的价值在于:同一套RTL、同一套约束框架,通过Revision与宏参数组合,产出多个SKU的bit流,且每个SKU的编译结果独立存放、互不干扰。

建议把每个Revision的编译产物输出到output/<revision>/子目录,避免不同SKU的.sof互相覆盖。
Quartus工程管理四要素关系图 工程目录结构 rtl/ → 可综合源码 ip/ → IP描述文件 constr/ → SDC约束 scripts/ → 编译脚本 cfg/ → 多配置Tcl output/ → 产物(不入库) doc/ → 接口文档 源码与产物分离 版本控制 Git 管理源码+约束+脚本 .gitignore 排除 db/ output/ 编译时写入 commit 号 .qsf 按功能拆分减少冲突 参数化工程 Verilog parameter VERILOG_MACRO 宏注入 IP 参数化配置 一套RTL → 多种形态 多配置管理(Revision + Tcl) Revision: sku_a DEVICE: EP4CE10F17C8 MACRO: SKU=A pin_sku_a.sdc Revision: sku_b DEVICE: EP4CE15F17C8 MACRO: SKU=B pin_sku_b.sdc quartus_sh -t cfg/sku_x.tcl → map → fit → asm → output/<rev>/ sku_a.sof rev: a1b2c3d sku_b.sof rev: e4f5g6h 关键实践要点 .gitignore 必须排除:db/、incremental_db/、output/、*.qws、*.sof、*.rbf、*.pof .qsf 中所有路径使用相对路径,IP 只提交 .ip/.qip,编译时自动重建 参数注入优先级:Tcl set_global_assignment > .qsf VERILOG_MACRO > RTL 默认值 每个 Revision 独立输出目录,编译脚本自动写入 Git commit 号实现可追溯 切换 Revision 后必须重新执行 map/fit/asm,不可复用其他 Revision 的中间数据库

五、落地检查清单

在工程交付前,建议逐项核对:.gitignore是否覆盖全部中间产物;.qsf是否全部使用相对路径;IP是否只保留描述文件;每个Revision是否有独立的Tcl配置脚本;编译脚本是否自动写入版本号;output/是否按Revision分目录。完成这六项,工程即从“能编译”升级为“可交付、可复现、可扩展”。

注意:切换Revision后,Quartus不会自动清除上一Revision的编译数据库。若直接复用db/,可能导致引脚分配或时序约束串扰。建议在Tcl脚本中显式执行execute_module -tool map前先清理对应Revision的db/目录,或使用quartus_sh --clean。