
简介这是一套面向FPGA工程师与数字电路学习者的Verilog HDL源码合集资料规模可观共355个文件涵盖.v源码、.sv系统Verilog、.cpp辅助程序、.inc包含文件、.sh脚本及少量文档压缩包仅3.31MB便于快速下载与查阅。内容按功能模块分类组织覆盖基本逻辑门、组合逻辑、时序逻辑、数据通路、通信协议SPI/I2C/UART、数字信号处理、存储器、微处理器与常用IP核等工程场景也有AES-256、RS译码、 scrambler等算法实现适合从入门到进阶的开发者按需取用。已有376人学习下载说明其在FPGA学习者中有一定参考价值。通过对这些源码的仿真、综合与移植练习读者可以理解Verilog语法在真实工程中的用法掌握模块化设计思路并为后续自主搭建FPGA项目提供可直接复用的代码基础。 搞FPGA这行最痛苦的不是不会写代码而是很多常用模块根本没必要从零造轮子。可每次真到用的时候翻遍整个硬盘也找不到之前调通的UART、SPI、DDR控制器、图像缩放这些工程文件最后只能硬着头皮重新写一遍。我整理过一份数量不小的Verilog HDL源代码库按功能分门别类归纳过基本上覆盖了从接口协议到算法加速、从基础组件到图像处理的常见场景。这篇博文就把这套整理思路、代码分类结构、挑选代码复用时的实操要点和一些踩过的坑一次性讲清楚适合正在入门FPGA的开发者也适合想把手头代码管理得更系统的工程师。1. 为什么要整理这样一份FPGA代码库1.1 从“东一块西一块”到系统化积累很多FPGA工程师跟我以前一样代码存在三个地方公司电脑、个人笔记本、移动硬盘的某个角落。每次写新项目先翻找旧工程找到了就复制粘贴找不到就重新写。这种模式最大的问题是你根本不知道自己的“资产”到底有多少更别说哪些代码已经验证过、哪些只是半成品。整理代码库这件事本质上不是整理文件而是把过去几年碎片化的工程经验重新做一次归档。举个实际例子我原先写过很多次UART收发模块但每次写法都不一样——有的用状态机有的用计数器有的带FIFO有的直接寄存器缓存。当我把它们统一放到一个目录下对比着看才发现不同写法适用的场景确实不同简单调试用计数器版本就够高速连续传输必须上FIFO。这种“横向对比”带来的认知提升是单独写任何一个版本都得不到的。1.2 分门别类的整体思路与适用人群这份代码库的整理逻辑并不复杂就按功能域分文件夹每个文件夹下再按模块拆分子目录。核心目的只有一个当项目需要某个功能时我能快速定位到可参考的代码。适用人群其实比想象中广。刚入门FPGA的同学不需要买一堆开发板教程直接啃现成代码、跑仿真、看波形比什么教程都快做项目的工程师可以把验证过的模块直接拿来做原型验证省掉前期最耗时的调试阶段甚至做算法的人也能在这份库里找到Cordic、FIR滤波、FFT这些数学运算的硬件实现作为参考。收录的代码来源很杂有自己写的有从开源项目里扒的也有从书籍光盘里提取的但每份我都至少跑过仿真或者上板验证过。2. 资源库的目录结构与代码分类思路2.1 基础组件类从计数器到FIFO第一个大类是基础组件这相当于FPGA开发的“地基”。计数器、分频器、边沿检测、按键消抖、数码管驱动、LED流水灯这些看似简单的模块其实藏着很多细节。以分频器为例很多人认为是“用计数器数到N就翻转”但工程上还得考虑占空比是不是50%、分频系数是奇数还是偶数、要不要做时钟使能而不是直接生成衍生时钟。直接分频得到的时钟在时序约束里很难处理更好的做法是生成时钟使能信号让所有逻辑还是跑在全局时钟上。代码库里我把这类知识沉淀下来每个模块都备注了适用场景和坑点比如“奇数分频如何做到50%占空比”“异步复位同步释放为什么必须做”。FIFO是另一个重点。异步FIFO几乎是跨时钟域数据交换的标准方案但Verilog手写异步FIFO要考虑格雷码转换、空满信号生成、读写指针同步等多级问题一不小心就出亚稳态。代码库里我保留了一个参数化程度比较高的异步FIFO深度、位宽都可以通过参数调整还带仿真用的读写监测任务方便直接集成到验证环境里。2.2 接口协议类从UART到PCIe这一块是代码库的重头戏也是复用价值最高的部分。常见的低速接口UART、SPI、I2C、CAN高速接口LVDS、MIPI、PCIe、Ethernet基本都有对应代码。低速接口里最推荐留一份完整UART代码因为它是验证逻辑最方便的手段之一。我保留的版本包含发送FIFO、接收FIFO、波特率自动检测三个子模块配合状态机实现帧解析可以直接用于上位机通信或者调试日志输出。SPI接口我单独留了主机和从机两个版本参数化时钟极性和相位适配不同外设比如ADC、DAC、Flash。高速接口这部分很多是厂家IP比如PCIe、MIPI在Xilinx和IntelAltera平台都是IP核方式提供Verilog代码本身不能跨平台直接用。但代码库里我会保留IP核的例化模板和配置说明因为IP核的接口时序复杂每次从零配置又麻烦又容易错。这类注释文档甚至比代码本身更宝贵。LVDS接收这部分我在代码库里专门保留了一个基于Xilinx原语ISERDES的接收模块。硬件上用LVDS传输图像数据需要通过ISERDES把串行数据转成并行。这里牵扯到位对齐、训练序列、时钟域转换等问题代码量不大但理解起来需要时间。我把完整的约束写法、时序要求、调试步骤都写在注释里拿来即用基本没问题。FMC通信那个场景项目里用STM32H743和FPGA通过FMC总线对接核心是把STM32的FMC总线时序和FPGA内部寄存器读写逻辑对齐。FMC地址线和数据线复用还需要根据STM32端的访问类型产生对应的读写时序FPGA侧用状态机响应即可。代码库里我放了一份带详细注释的FMC从机接口逻辑包括地址译码、读写时序生成、寄存器映射拿来改改就能用。2.3 算法加速类滤波、变换与数学运算FPGA做算法加速是一个深水区但也有很多高频使用的模块值得整理。这个分类下我分了三块数字信号处理基础运算、滤波与变换、控制算法。数字信号处理基础运算里最核心的是Cordic算法。这个算法能通过迭代旋转计算三角函数、双曲函数、开方等在FPGA里实现时不需要乘法器只用移位和加法非常适合硬件实现。代码库里我保留了Cordic的两种模式——旋转模式和向量模式参数化迭代次数和位宽并给出了精度对比测试结果。实测下来迭代16次精度能达到小数点后四位左右基本满足工程需求。滤波与变换这部分FIR滤波器、IIR滤波器、FFT变换是不可回避的。FPGA做FIR滤波有几种实现方式直接型、转置型、分布式算法DA各有优劣。直接型结构简单但消耗乘法器多DA算法用查找表替代乘法器适合系数固定的场景。代码库我保留了两种实现并有资源占用对比数据方便按需选择。FFT这块我建议直接用Xilinx或者Altera的IP核自己写FFT性价比不高但与之配套的位宽截取、缩放策略、帧同步处理这些逻辑才是实际工程里的关键。控制算法里卡尔曼滤波FPGA实现是比较有代表性的一个。卡尔曼滤波涉及矩阵运算、浮点转定点、状态更新、协方差更新硬件实现复杂度不算低。我整理了一个一维卡尔曼滤波的定点实现版本输入噪声协方差、测量噪声协方差做成可调参数配合仿真数据验证滤波效果。代码里详细注释了每个矩阵运算的硬件映射方式适合做传感器数据融合或者导航算法时参考。2.4 图像与信号处理类图像处理在FPGA领域几乎成了一个专门方向因为FPGA的并行架构在做像素级处理时优势非常明显。代码库里我收集整理了完整的图像采集、预处理、显示输出链路。图像采集接口方面最常见的是MIPI CSI-2和DVP并口。MIPI这部分我保留了Xilinx MIPI CSI-2 RX子系统的配置流程和例化模板因为MIPI协议分层复杂除非有特殊需求一般不建议从零写物理层。DVP并口相对简单用PCLK做同步时钟HSYNC和VSYNC做行列同步数据线逐像素传输代码直接写寄存器控制即可。代码库里的DVP采集模块支持8位和10位数据位宽还带坏点校正和自动白平衡接口方便接CMOS sensor。预处理阶段我保留了大量常用算法灰度转换、中值滤波、高斯滤波、Sobel边缘检测、图像二值化、形态学开闭运算这些都能在FPGA上用流水线结构实现处理一帧图像只需要微秒级延迟。关键问题是行缓冲的设计——图像处理需要访问当前像素的上下左右邻域FPGA里用行缓存Line Buffer解决通过多个RAM拼接实现二维窗口滑动。我用的方案是Shift RAM结构也就是用多个移位寄存器组拼出3x3或者5x5窗口不用反复读写DDR。这个模块可复用性极高后续做任何图像滤波都能直接调用。上板实测结果Sobel边缘检测在1080p分辨率下单帧处理时间能够控制在3ms以内实时性远好于CPU实现。显示输出方面我保留了HDMI、VGA、LCD并口三种输出接口代码。HDMI相关代码重点在解决像素时钟生成和TMDS编码上我用了Xilinx的HDMI IP和配套的像素时钟PLL配置避免了自己写TMDS编码的麻烦。VGA接口的时序相对固定代码量小适合入门学习。LCD并口驱动则带RGB接口支持SPI初始化配置和背光控制逻辑。3. 真正从资源库挑代码时的实操要点3.1 不要迷信“能用”先看时钟和复位从代码库里拿代码复用最忌讳的就是直接综合下载。Verilog代码和C语言不一样C语言只要逻辑正确就能在任意平台上跑出相同结果但硬件代码的可移植性受太多因素影响芯片制造商、具体型号、开发工具版本、约束文件改一个条件就得重新验证。时钟方案是最先要看的地方。原始代码用PLL产生100MHz时钟但你的板子主时钟只有50MHz那PLL配置必须重新生成如果原代码用的是全局时钟而你集成后直接用了某个引脚输出的时钟那么时序收敛基本没戏。改代码之前先在方案层面把时钟树画清楚——系统有哪些时钟域、哪些模块在哪个时钟域下工作、跨时钟域的信号做了同步没有。复位逻辑同样关键。很多开源代码用的异步复位置复位信号后所有寄存器立刻清零。这里我强烈建议同步一下外部复位信号进来后先经过两级寄存器同步再分别生成每个时钟域的复位信号配合“异步复位同步释放”的方式防止复位释放时刻产生亚稳态。代码库里我基本每份代码都加了这样的复位同步模块复用的时候直接带上就行。3.2 参数化设计才是好东西在FPGA代码复用这件事上参数化设计带来的收益是长远的。使用parameter或者localparam定义模块的位宽、深度、计数上限这样在例化时只用修改参数就能适配新的需求。举一个具体例子。我代码库里的UART模块定义了几个关键参数系统时钟频率、波特率、数据位宽、校验位。在不同项目里系统时钟可能是50MHz也可能100MHz波特率也可能从9600到921600但核心代码一行都不用改只调整参数就行。SPI模块则是把CPOL/CPHA、时钟分频系数、数据帧长度全部参数化。FIFO定义了深度和数据位宽参数IP核用不上的场景能直接用这个替代。设计参数化模块时有个经验不要把所有参数都暴露出来否则调用的人会迷失在参数堆里。只暴露必须由使用场景决定的参数比如时钟频率、位宽、深度内部计算用的中间值用localparam在模块内部定义。这样保持了模块接口的简洁又能保证复用时的灵活性。3.3 仿真文件和测试平台是关键代码库里的Verilog模块再好如果没有对应的仿真文件和测试平台复用效率立刻减半。很多下载来的代码只有纯RTL文件没有testbench你根本不知道激励怎么加、期望输出是什么等于让你盲写一遍验证环境白白浪费了复用的初衷。我的代码库里几乎每个模块都配套了对应的testbench。testbench不是简单给几个信号初始化然后跑几个周期而是要有明确的功能覆盖正常输入下的功能验证、边界条件的异常输入、跨时钟域场景下的数据完整性检查一般都会做。UART模块的testbench会发送几帧随机数据同时启动接收自动对比收发内容是否一致。异步FIFO的testbench会模拟读写时钟频率不一致的情况检查会不会丢数据或者读空。有这些仿真文件拿到代码后能立刻跑仿真、看波形、确认功能。跑仿真的工具我用过Vivado Simulator、ModelSim和Verilator个人最推荐ModelSim或者Questa的免费版轻量、启动快、波形调试方便。新版本Vivado自带的仿真器也够用但启动速度偏慢做小模块验证时不太爽利。3.4 关于版权和代码来源整理代码库版权问题必须留意。我在代码库里存储的来源主要有三类一是自己独立完成的代码二是开源项目里带MIT、Apache等宽松许可证的代码三是书籍或教程附带的代码。开源代码的使用核心是保留原许可证声明。如果你把复用的代码用来做商用产品必须逐份确认许可证类型GPL类许可证在使用不当的情况下可能有传染风险。我用了一个简单方法处理代码库根目录放一个README.md里面列出每份代码的来源、许可证类型、当初从哪下载的、适用场景。这样不管自己用还是给别人参考都能快速查证。4. 常见问题与排查技巧实录4.1 代码能编译但行为不对这是整理代码库之后最常遇到的问题。RTL代码能综合、能布局布线、能不报错但上板之后功能就是不对。这类问题在FPGA调试中占比极高。我遇到过的一个案例是这样一个情况从代码库里拿了一个PWM输出模块仿真的时候波形完全正确但上板后示波器观察输出没有信号。排查到最后发现PWM输出引脚复用了板卡上同一引脚连接了两个外设IO标准还不一样驱动能力不足导致输出被拉低。这种问题不是代码逻辑错误而是硬件平台约束不匹配。所以代码移植上来第一步必须逐一核对引脚约束、IO电平标准、驱动能力选项跟硬件原理图一个个对过再烧写。不考虑硬件问题的情况行为不对还有一个常见原因是时序违约。综合实现报告里如果出现了负的建立时间余量或者保持时间余量那么行为出错几乎是必然的。这时优先做三件事第一确认时钟约束有没有写对创建时钟、生成时钟、伪路径、最大延迟这些约束是否齐全第二检查跨时钟域信号有没有用同步器或者异步FIFO第三看关键路径延迟尝试用流水线切断组合逻辑链。这一套排查逻辑在很多项目里都适用。4.2 跨时钟域处理不当代码库里的模块组合到一块儿之后最大的隐患往往是跨时钟域问题。单个模块看起来都正常但模块A在100MHz时钟域、模块B在75MHz时钟域AD之间的信号传输没有做同步处理就会有概率性错误而且这种错误极难复现。跨时钟域处理的几个标准手段必须熟练单bit电平信号用两级同步器单bit脉冲信号用脉冲同步器或者在目标时钟域做展宽后再同步多bit数据总线根据需求用异步FIFO或者握手机制。调试跨时钟域问题重点不只是“怎么改代码”而是“怎么发现”这个问题。我现在的做法是在RTL代码里就把所有跨时钟域接口单独抽成一个个小模块同时配合CDC验证工具或者静态检查在早期阶段就把问题暴露出来而不是等板卡出问题后在示波器上慢慢猜。4.3 资源评估与控制从代码库拿模块做系统集成时资源评估是必须提前做的功课。不同芯片的资源差异极大低端CPLD可能只有几百个逻辑单元高端FPGA有上百万逻辑单元、几千个DSP Slice同一段代码放到不同芯片上完全会有不同结果。评估资源的直接方法是“综合一次看报告”但更快的估算法是看几个关键指标的占用逻辑单元、寄存器、BRAM、DSP Slice。以图像处理链路为例3x3窗口的Sobel算子大致消耗两三百个逻辑单元和若干行缓冲BRAMCordic迭代模块大概每个迭代级消耗三四十个逻辑单元DSP Slice被乘法器大量消耗FIR滤波器的抽头数直接决定DSP占用。通过这种估算方式在项目启动阶段就能判断目标芯片够不够用避免在选型后才发现容量不足。4.4 常见问题速查表我把几个高频问题整理成一个速查表方便复用代码时快速对照现象可能原因排查方式综合报错找不到信号模块例化时端口名不匹配对比例化模板与定义逐端口检查时序约束报告大量违例时钟约束缺失或错误重新生成时钟约束核对PLL配置上板无输出引脚约束不对或IO标准问题对照原理图检查引脚和电压域信号偶发跳变跨时钟域未同步加同步器或异步FIFO仿真正常上板异常异步复位时序或输入毛刺检查复位同步对异步输入打拍FIFO数据读空/写满异常空满信号生成逻辑错误检查格雷码转换和指针同步这张表基本覆盖了我实际工作中大约七成FPGA调试问题遇到现象可以先对号入座快速定位比从头开始看代码高效得多。5. 这份代码库还能怎么用5.1 串联起完整的学习路径对于初学者来说这份分类代码库的价值不止是“抄代码”更是建立硬件设计思维方式的一条路径。建议按这个顺序走先看基础组件理解时序逻辑、组合逻辑、状态机这些基本概念然后跑接口协议模块学习如何与外设交互接着做算法模块体会FPGA并行架构带来的加速效果最后做图像处理把前面积累的东西串成一条完整链路。每个阶段我都建议做两个动作第一把模块的testbench自己写一遍不要用现成的强迫自己理解输入输出关系第二修改原模块的参数或者增加一个小功能比如给UART加一个奇偶校验错误计数给FIFO增加Almost Full信号让模块变成自己的东西。5.2 快速原型验证我最近一个项目做毫米波雷达的数据采集处理算法团队给的MATLAB模型还没定稿但他们希望FPGA团队能先出一版可以跑通的硬件原型。这种场景下不可能从零分模块开发。我直接从代码库里找到LVDS接收模块、异步FIFO、FFT接口逻辑、UART发送模块按照算法需求稍作参数调整半天时间就把数据通路搭出来了。这套流程能达到这样的效率一个重要原因是代码库里现成模块的接口风格相对统一组合起来不需要大量胶水逻辑。整理的时候我就有意统一了模块接口规范全局信号clk、rst_n放前面配置参数用parameter数据接口用s_axis/m_axis风格命名。这样新模块集成进来不需要反复适配接口风格。5.3 从Verilog向SystemVerilog迁移近两年新项目我已经逐步从Verilog迁移到SystemVerilog一方面是大厂IP基本都是SV另一方面SV的interface、struct、enum等语法确实能让代码简洁不少。代码库里的Verilog模块作为迁移起点很有帮助因为SV兼容Verilog语法在同一工程里可以混用。迁移过程中我总结了一个有效步骤先改testbench用SV的类、约束、覆盖率写出来的测试平台效率和可读性提升明显然后把新写的模块用SV旧模块先保持Verilog通过interface做连接最后等所有模块验证完毕再逐步把核心模块重写为SV。这种渐进式迁移在不影响项目进度的前提下实现了“边用边学”的效果。最后再分享一个我个人的使用习惯代码库不是收藏夹不能只存不用。我每年会做一次大清理把“仿真验证过且项目真正用上”的模块放进“verified”目录把“只写过还没验证”的放进“develop”目录已经过时的代码直接删除。这样代码库越来越精简而不是越来越臃肿。如果你也在整理自己的FPGA代码库建议从今天开始先挑三个最近用到的模块分类放好后面再慢慢补全。等积累到一定程度回头看你会发现自己已经拥有了一个比任何教程都宝贵的工程资产。本文还有配套的精品资源点击获取