2. FPGA项目工程结构解析

在 Quartus Prime 中新建一个工程时,软件会自动生成一套目录与文件体系。很多初学者习惯把所有 .v、.qsf、.sdc 文件都堆在工程根目录下,工程一旦超过十几个模块就会变得难以维护。理解工程目录的组织逻辑,是让项目从"能跑"走向"可维护、可复用、可交付"的第一步。

一、Quartus 工程的三类核心文件

一个典型的 Quartus Prime 工程,其文件可以按职责划分为三大类:源文件、约束文件和工程管理文件。它们各自承担不同的角色,混放会导致版本管理混乱。

  • 源文件:包括 Verilog/VHDL 设计文件(.v/.sv/.vhd)、Testbench 文件、以及 IP 核生成的 .qip/.ip 文件。它们是"设计本身"。
  • 约束文件:包括引脚与时序约束 .qsf、时钟约束 .sdc、以及物理约束 .qpf 等。它们描述"设计如何映射到具体器件"。
  • 工程管理文件:.qpf(工程文件)、.qsf(设置文件)、.sof/.pof(下载文件)、db/、incremental_db/ 等编译产物。它们由工具生成,通常不纳入版本控制。

关键区分点在于:源文件和约束文件是"人写的",工程管理文件是"工具生成的"。前者需要纳入 Git 管理,后者应通过 .gitignore 排除。

二、推荐的工程目录组织

对于中小规模项目,推荐采用如下目录结构,把"人写的"和"工具生成的"物理隔离:

my_fpga_project/
├── rtl/              # 所有 RTL 源文件
│   ├── top.v
│   ├── uart_tx.v
│   └── uart_rx.v
├── tb/               # Testbench 文件
│   └── tb_uart.v
├── ip/               # IP 核相关文件
│   ├── pll_50m_to_100m.ip
│   └── fifo_256x8.ip
├── constr/           # 约束文件
│   ├── top.qsf
│   └── top.sdc
├── sim/              # 仿真脚本与波形
├── doc/              # 设计文档
└── quartus_prj/      # Quartus 工程与编译产物
    ├── my_fpga.qpf
    ├── my_fpga.qsf
    ├── db/
    └── output_files/

这种布局的核心思想是:rtl/、tb/、ip/、constr/ 是"设计资产",quartus_prj/ 是"构建产物"。当需要迁移工程或做代码评审时,只需关注前四个目录。

三、源文件管理:模块划分与命名

源文件管理的关键是"一个文件一个模块"。例如 UART 设计应拆分为 uart_tx.v、uart_rx.v、uart_top.v,而不是全部塞进一个文件。这样做的好处是:

  1. 综合时增量编译只重编改动模块,缩短编译时间;
  2. 模块可被其他工程直接复用;
  3. Git diff 时改动范围清晰。

命名上建议采用"功能_方向"的约定,如 uart_tx、spi_master、fifo_sync。顶层模块统一命名为 top.v,便于约束文件与工程设置统一引用。

四、IP 核与约束文件的分类管理

IP 核在 Quartus 中通过 IP Catalog 生成,会产生 .ip 文件(参数描述)和 .qip 文件(文件列表)。.qip 必须被加入工程,否则综合时找不到 IP 的底层文件。建议把 IP 相关文件统一放在 ip/ 目录,并在 .qsf 中用相对路径引用,避免绝对路径导致工程迁移失败。

约束文件分为两类:引脚约束(在 .qsf 中以 set_location_assignment 形式存在)和时序约束(在 .sdc 中以 create_clock、set_input_delay 等形式存在)。两者职责不同,建议分开管理:.qsf 由 Quartus 自动维护,.sdc 由设计者手写。下面这张图展示了工程中各类文件之间的引用关系与数据流向。

Quartus 工程文件引用关系与编译数据流 设计资产(纳入版本控制) rtl/ top.v / uart_tx.v tb/ tb_uart.v ip/ pll.ip / fifo.qip constr/ top.qsf / top.sdc 源文件 + 约束文件 = 完整设计描述 .qip 必须加入工程,否则 IP 底层文件缺失 .sdc 手写维护,.qsf 由工具自动更新 Quartus 编译流程 Analysis → Synthesis → Fitter → STA → Assembler 构建产物(.gitignore 排除) quartus_prj/ .qpf / .qsf db/ 增量编译数据库 output_files/ .sof / .pof / .rpt sim/ 波形 / 仿真脚本 编译产物可随时重新生成 .sof 用于下载到 FPGA .rpt 用于查看资源与时序报告 下载与验证 Programmer → .sof → FPGA 配置 输入 生成 约束 设计资产与构建产物物理隔离,是工程可维护性的基础

五、.qsf 与 .sdc 的分工

很多初学者会混淆 .qsf 和 .sdc。简单来说:.qsf 管"物理位置",.sdc 管"时间关系"。例如把 LED 接到 PIN_A10,写在 .qsf 中:

set_location_assignment PIN_A10 -to led[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to led[0]

而声明 50MHz 时钟并约束其抖动,写在 .sdc 中:

create_clock -name clk_50m -period 20.000 [get_ports clk]
derive_pll_clocks
derive_clock_uncertainty

注意 .sdc 中的 period 单位是 ns,20.000 对应 50MHz。如果时钟是 100MHz,则应写 10.000。这个数值直接决定时序分析是否通过,写错会导致 STA 报告出现大量违例。

六、工程迁移与版本控制要点

当需要把工程从一台电脑迁移到另一台时,最容易出问题的是绝对路径。Quartus 的 .qsf 中如果出现类似 D:/project/rtl/top.v 的绝对路径,换机器后就会找不到文件。解决办法是在 .qsf 中统一使用相对路径,例如 ../rtl/top.v。

版本控制方面,建议 .gitignore 至少包含以下内容:

quartus_prj/db/
quartus_prj/incremental_db/
quartus_prj/output_files/
*.sof
*.pof
*.rpt

而 rtl/、tb/、ip/、constr/ 以及 .qpf、.qsf 应全部纳入 Git。这样团队成员拉取代码后,只需在 Quartus 中打开 .qpf,即可完整还原工程。

实践建议:新建工程时,先在磁盘上手工创建 rtl/、tb/、ip/、constr/ 四个目录,再在 Quartus 中通过 Add Files 逐个添加源文件。不要使用 Quartus 默认的"所有文件放根目录"方式,否则后期整理成本很高。
常见错误:把 .qip 文件遗漏在工程之外。IP 核生成后,.qip 记录了该 IP 所需的全部底层文件列表,如果未加入工程,综合时会报"module not found"或"file not found"。检查方法是打开 .qsf,确认存在 set_global_assignment -name QIP_FILE ip/xxx.qip 这一行。

总结来看,工程结构解析的核心不是记住目录名字,而是建立"设计资产 vs 构建产物"的分离意识,以及"源文件、约束文件、IP 文件各司其职"的分类习惯。做到这两点,工程规模再大也不会失控。