从原理图到Verilog:用Quartus II 13.1快速上手你的第一个FPGA全加器项目
第一次接触FPGA开发时,很多人会被各种专业术语和复杂的工具链吓退。但事实上,只要掌握正确的学习路径,FPGA开发可以变得直观而有趣。本文将带你从零开始,通过一个经典的全加器项目,体验从原理图设计到Verilog代码的完整开发流程。无论你是电子工程专业的学生,还是对硬件设计感兴趣的开发者,这个项目都能帮助你快速理解FPGA开发的核心概念。
我们将使用Quartus II 13.1这款业界广泛使用的FPGA开发工具,它不仅支持传统的原理图输入方式,还能无缝对接现代硬件描述语言(HDL)开发。通过对比两种设计方法,你会清晰看到Verilog HDL在效率和灵活性上的优势,同时也能理解底层硬件实现的本质。
1. 项目准备与环境配置
在开始之前,确保你已经完成了Quartus II 13.1的安装和基本配置。这个版本虽然不算最新,但对初学者来说足够稳定,且对系统资源要求相对较低。安装过程中有几个关键点需要注意:
- 安装路径:避免包含空格或特殊字符,这可能导致后续仿真工具报错
- License配置:按照官方指引完成授权文件设置
- 驱动安装:确保USB-Blaster下载器驱动正确安装
提示:如果遇到仿真工具ModelSim报错,检查项目路径是否包含空格,这是常见错误源之一。
完成安装后,建议创建一个专门的工作目录,比如FPGA_Projects,所有后续项目都将放在这个目录下。这种组织方式能帮助你保持工作区整洁,也便于项目管理。
2. 原理图设计:从半加器到全加器
2.1 创建半加器原理图
半加器是理解加法器的基础,它能够计算两个1位二进制数的和及进位。在Quartus中创建半加器的步骤如下:
- 新建工程:File → New Project Wizard
- 设置工程名称和存储路径
- 选择目标器件(如Cyclone IV EP4CE6E22C8)
- 创建原理图文件:File → New → Block Diagram/Schematic File
在原理图编辑器中,我们可以通过图形化方式构建半加器电路:
[输入A] ----\ XOR ---- [和S] [输入B] ----/ \ AND ---- [进位Co]具体操作步骤:
- 使用元件库插入XOR和AND门
- 添加输入输出引脚并命名
- 连接各元件形成完整电路
- 保存为
half_adder.bdf并编译
2.2 构建全加器顶层设计
全加器在考虑低位进位的基础上,实现了完整的1位加法功能。利用之前创建好的半加器模块,我们可以像搭积木一样构建全加器:
- 新建原理图文件
- 插入两个半加器模块和一个OR门
- 连接三个输入(A、B、Cin)和两个输出(Sum、Cout)
- 保存为
full_adder.bdf并设置为顶层实体
全加器的逻辑结构可以表示为:
半加器1 (A+B) → 和S1, 进位C1 半加器2 (S1+Cin) → 最终和Sum, 进位C2 OR门 (C1 | C2) → 最终进位Cout这种模块化设计方法展示了FPGA开发的重要理念:复杂系统可以由简单模块组合而成。
3. 功能验证与仿真测试
设计完成后,我们需要验证电路功能是否符合预期。Quartus提供了强大的仿真工具,可以让我们在实际烧录到FPGA前发现问题。
3.1 创建仿真波形文件
- 新建University Program VWF文件
- 添加所有输入输出信号节点
- 设置输入信号的各种组合(共8种可能)
- 运行功能仿真
一个典型的全加器测试向量如下表所示:
| 时间(ns) | A | B | Cin | 预期Sum | 预期Cout |
|---|---|---|---|---|---|
| 0-50 | 0 | 0 | 0 | 0 | 0 |
| 50-100 | 0 | 0 | 1 | 1 | 0 |
| 100-150 | 0 | 1 | 0 | 1 | 0 |
| 150-200 | 0 | 1 | 1 | 0 | 1 |
| 200-250 | 1 | 0 | 0 | 1 | 0 |
| 250-300 | 1 | 0 | 1 | 0 | 1 |
| 300-350 | 1 | 1 | 0 | 0 | 1 |
| 350-400 | 1 | 1 | 1 | 1 | 1 |
3.2 常见仿真问题排查
初学者在进行仿真时经常会遇到以下问题:
- 路径包含空格:Quartus工具链对路径中的空格敏感,建议使用下划线替代
- 输出目录设置错误:确保仿真输出目录位于项目下的simulation文件夹
- 信号未正确添加:检查波形文件中是否包含了所有需要观察的信号
注意:如果仿真结果与预期不符,首先检查原理图连接是否正确,特别是信号命名是否一致。
4. Verilog实现:更高效的硬件描述
虽然原理图设计直观易懂,但在复杂项目中会变得难以维护。Verilog HDL提供了一种更高效的硬件描述方式。
4.1 全加器的Verilog实现
下面是一个完整的全加器Verilog代码示例:
module full_adder( input a, b, cin, output sum, cout ); // 连续赋值方式 assign sum = a ^ b ^ cin; assign cout = (a & b) | (b & cin) | (a & cin); // 或者使用行为级描述 /* always @(*) begin sum = a ^ b ^ cin; cout = (a & b) | (b & cin) | (a & cin); end */ endmodule这段代码简洁地描述了全加器的功能,与原理图实现相比具有明显优势:
- 可读性高:逻辑关系一目了然
- 易于修改:调整逻辑只需修改几行代码
- 可重用性强:模块可以方便地在其他项目中复用
4.2 Verilog设计流程
使用Verilog进行FPGA开发的基本流程如下:
- 创建Verilog源文件(.v)
- 设置为顶层实体
- 编译并查看RTL视图
- 功能仿真(与原理图方式相同)
- 引脚分配和烧录
Verilog的强大之处在于它支持多种抽象级别的设计:
- 门级描述:类似于原理图,直接描述逻辑门连接
- 数据流描述:使用assign语句描述信号关系
- 行为级描述:使用always块描述电路行为
5. 实际硬件验证
设计最终需要在实际FPGA硬件上运行验证。这一阶段有几个关键步骤:
5.1 引脚分配
根据开发板原理图,将设计中的信号映射到具体物理引脚:
- 打开Pin Planner工具
- 为每个端口指定目标引脚号
- 保存并重新编译
典型的引脚分配可能如下:
| 信号名 | 引脚号 | 对应开发板元件 |
|---|---|---|
| a | PIN_AB12 | 开关SW0 |
| b | PIN_AC12 | 开关SW1 |
| cin | PIN_AF14 | 开关SW2 |
| sum | PIN_AE11 | LED灯LEDR0 |
| cout | PIN_AD10 | LED灯LEDR1 |
5.2 程序烧录
完成引脚分配后,就可以将设计烧录到FPGA了:
- 连接USB-Blaster下载器
- 打开Programmer工具
- 选择正确的硬件和.sof文件
- 点击Start开始烧录
烧录成功后,你可以通过拨动开关观察LED灯的变化,验证全加器功能是否正常。这种即时反馈是硬件开发最令人兴奋的部分之一。
6. 两种设计方法对比
通过这个项目,我们体验了原理图和Verilog两种设计方法。下表总结了它们的主要区别:
| 特性 | 原理图设计 | Verilog设计 |
|---|---|---|
| 学习曲线 | 直观,适合初学者 | 需要学习HDL语法 |
| 设计效率 | 简单电路快捷,复杂电路繁琐 | 任何复杂度都高效 |
| 可维护性 | 修改困难 | 易于修改和扩展 |
| 可重用性 | 有限 | 高度可重用 |
| 仿真调试 | 信号追踪直观 | 需要熟悉波形查看工具 |
| 适用场景 | 教学演示,简单组合逻辑 | 实际项目开发,复杂系统 |
在实际项目中,工程师通常会根据具体需求混合使用这两种方法。例如,可以用原理图设计顶层模块连接,而用Verilog实现各个子模块。
7. 进阶学习建议
完成全加器项目后,你可以继续探索以下方向:
- 多位加法器:将多个全加器级联实现4位或8位加法器
- 流水线设计:通过寄存器分割组合逻辑,提高工作频率
- 状态机设计:学习用Verilog实现有限状态机
- IP核使用:调用Quartus内置的乘法器、存储器等IP核
FPGA开发的魅力在于它结合了硬件的高性能和软件的灵活性。掌握从原理图到HDL的设计方法转换,是你成为合格数字设计工程师的重要一步。