C语言与FPGA(verilog)开发流程对比
前言
嵌入式行业会除了使用CPU/MCU外,经常会用到FPGA做一些并行计算、图像处理、数字信号处理等加速计算。CPU上运行软件通常使用C语言编程,FPGA上使用verilog编程,verilog虽然是类C语言,但是底层原理是截然不同的,verilog语言是一种硬件描述语言,描述电路连接关系。本文从开发流程、执行流程、时钟生成方式等方面对比C语言和verilog语言之间的差异。
特性维度 | C语言开发 | FPGA Verilog开发 | 核心差异焦点 |
---|---|---|---|
设计思维 | 软件思维 关注算法逻辑和流程控制,通过指令序列描述问题求解步骤。 | 硬件思维 描述电路结构、功能和行为,代码直接对应物理硬件连接和时序。 | 抽象对象不同 |
开发流程 | 编辑 → 预编译 → 编译 → 汇编 → 链接 → 在CPU上执行 | 编写HDL代码 → 功能仿真 → 综合 → 布局布线 → 时序分析 → 生成比特流 → 烧录到FPGA | 目标产物不同 |
执行方式 | 串行执行 指令在CPU中按顺序逐条执行,依赖程序计数器。 | 并行执行 所有电路模块一旦上电同时工作,独立运作。 | 根本性的执行模型差异 |
时钟处理 | 隐含时钟 由CPU硬件产生,对程序员透明,开发者通常无需直接关心时钟驱动。 | 显式时钟 需手动编写时钟信号(如 clk )作为同步时序逻辑的驱动源,严格设计时序。 | 对时钟的掌控程度不同 |
资源管理 | 动态管理 通过操作系统申请和管理内存等资源,关注内存泄漏、碎片等问题。 | 静态映射 直接映射为硬件资源(LUT、触发器、BRAM等),需精打细算,设计固定后无法动态改变。 | 资源的分配和使用方式截然不同 |
验证与调试 | 调试器(GDB)、打印语句、逻辑分析仪、软件测试框架 | 仿真(如ModelSim、Vivado Simulator)、Testbench、逻辑分析仪(ILA)、波形查看 | 工具和方法差异大 |
算法实现特点 | 擅长复杂数学运算、浮点、循环迭代、递归等控制密集型任务 | 擅长并行处理、流水线、定点运算、数据流处理、实时性要求高的任务 | 各有擅长的领域 |
🧠 设计思维与抽象层级
- C语言 是软件编程语言,核心是算法和顺序逻辑。你编写的是指令序列,告诉CPU“一步一步做什么”。它运行在已有的通用硬件(如CPU)之上,不直接关心底层硬件如何实现这些操作。
- Verilog 是硬件描述语言,核心是描述电路的结构和行为。你编写代码时,是在“定义”或“连接”硬件模块(如寄存器、加法器、状态机),描述的是“有什么电路”以及“电路如何工作”。它最终会直接映射为具体的硬件电路。
🔄 开发流程与目标产物
-
C程序的开发流程(以嵌入式为例):编写代码 → 编译 → 链接 → 生成机器码 → 烧录到目标CPU执行。最终产物是存储在存储器中的指令序列,CPU通过取指、译码、执行来运行它。
-
FPGA/Verilog的开发流程则更为复杂:
1、编写HDL代码:用Verilog描述硬件功能。
2、 功能仿真(前仿真):使用测试平台(Testbench)模拟验证逻辑功能的正确性,不涉及时序延迟。
3、综合:将HDL代码转换为由基本门电路、触发器、存储器等组成的门级网表。这是一个关键步骤,决定了如何用硬件资源实现你的设计。
4、布局布线:将网表中的逻辑单元映射到FPGA芯片上特定的物理资源(如CLB、IOB),并连接它们。
5、时序分析:分析建立/保持时间等时序参数,确保在目标时钟频率下能稳定工作。
6、生成比特流文件:生成包含配置信息的文件。
7、烧录:将比特流文件下载到FPGA中,配置其内部结构,形成专用的数字电路。
⚡ 执行方式与时钟概念
- C语言:程序在CPU上串行(顺序)执行。CPU的时钟是固有的,由硬件晶体振荡器产生,对程序员通常是“透明”的,你一般不需要在代码中直接生成或管理时钟信号。
- Verilog: 并行执行:这是最本质的区别。一旦上电,FPGA内部的所有电路模块同时工作,而不是一条一条地执行指令。 显式时钟:在Verilog中,时钟信号是需要你手动编写和管理的核心要素之一。时序逻辑电路(如触发器)的行为严格依赖于时钟边沿(上升沿或下降沿)。
💾 资源观念
- C语言:资源(如内存)通常由操作系统或运行时环境动态管理。你可以申请和释放内存,关注点更多在算法效率和内存使用上,而非硬件资源的绝对数量和物理连接。
- Verilog:代码直接映射为固定的硬件资源,如查找表(LUT)、触发器(FF)、块RAM(BRAM)、DSP单元等。你必须密切关注资源的使用情况,优化代码以减少资源消耗或适应特定型号FPGA的资源限制,设计完成后硬件结构就固定了。
🐞 验证与调试
-
C程序:常用调试器(如GDB)、打印语句、逻辑分析仪(抓取实际硬件信号)等进行调试。
-
Verilog:
1、 仿真至关重要:尤其是功能仿真,通过编写Testbench(测试平台)来模拟输入信号并观察输出波形,验证逻辑正确性。
2、 硬件调试:生成比特流并烧录到FPGA后,会使用逻辑分析仪(如ChipScope、SignalTap)来抓取FPGA内部的真实信号进行调试。
🧮 算法实现的思路
- 用C语言实现算法:更直接,侧重于算法的逻辑步骤和数学表达,可以方便地使用浮点数、复杂循环、递归等。
- 用Verilog实现算法:需要思考如何用硬件电路来实现数学运算或逻辑功能。这常常涉及: 并行化:将任务分解为多个可同时处理的硬件模块。 流水线:插入寄存器打拍,提高吞吐量。 资源复用:在时间上共享同一个硬件单元以提高利用率。 数值精度:更多采用定点数而非浮点数来节省资源。 查找表:用ROM存储预计算结果,以空间换时间。
一些复杂计算(如求余、迭代)在FPGA中实现起来可能更困难,需要转化为其擅长的操作(如加法、移位、查表)。
🚀 应用场景与选择建议
了解差异是为了更好地选择和应用。
- 倾向于选择C语言(CPU/MCU) when:
- 任务复杂,控制逻辑繁多。
- 算法包含大量顺序操作、复杂决策分支。
- 需要与操作系统、文件系统、网络协议栈等复杂软件生态交互。
- 开发速度和要求快速迭代,对功耗和成本敏感。
- 倾向于选择Verilog/FPGA when:
- 高性能并行处理:需要同时处理大量数据或并行执行多个任务。
- 确定性低延迟:信号处理、实时控制等要求响应时间极度可预测。
- 接口扩展和协议实现:需要实现特定或自定义的接口标准。
- ASIC原型验证:FPGA常用于芯片设计的功能验证。
- 混合架构(如Zynq, Cyclone V SoC):许多现代FPGA(如Xilinx Zynq、Intel Cyclone V SoC)集成了ARM处理器和FPGA可编程逻辑。这允许C语言运行在处理器上处理复杂逻辑和操作系统,Verilog实现加速器和高速接口,两者通过高速总线通信,协同工作。