FPGA功能设计说明书:把模糊需求翻译成可验证行为的那张纸 简介《FPGA功能设计说明书》是一份面向FPGA研发团队的标准化Word文档模板用于编制功能设计阶段的说明文档帮助设计人员、项目经理和评审人员围绕算法、架构、接口等核心要素达成一致。压缩包内仅含一份 Word 文档33KB内容为可直接编辑的模板预置了封面、修改历史、目录以及“概述”“功能描述”“测试计划”“参考资料”四大章节其中“概述”细分为目的、功能概述、参考源、术语表“功能描述”进一步列出使用的算法、设计架构、与其他部分之间的接口等小节并涵盖数字信号处理、高速数据传输、接口控制等典型功能结构完整适合作为团队开发文档的统一蓝本。目前已有860人学习下载FPGA项目组可以在立项或设计评审前快速生成规范文档减少因描述不一致造成的沟通和返工成本。借助模板中的术语表和参考源模块团队还能统一专业术语口径并轻松填写各模块的算法说明、RTL架构、接口协议及测试计划为后续仿真验证和系统集成提供可追溯的设计依据。1. FPGA功能设计说明书把模糊需求翻译成可验证行为的那张纸FPGA功能设计说明书听起来像评审才用得上的文档实际上是最省时间的调试工具。接手过一个用Verilog写的图像采集模拟项目需求邮件里只有一句话把Sensor数据存进DDR3。代码写了一版又一版联调时才发现前端模块用高电平表示帧有效后端模块按低电平判断接口一接上就丢帧。后来先把所有功能行为写成FPGA功能设计说明书再动RTL返工明显减少。这份文档的价值是把模糊需求翻译成接口、状态机、时序、寄存器这些可逐条核对的行为描述。FPGA开发、驱动对接、技术负责人三类人分别能从接口表、寄存器表、资源预算三个角度读到关键信息。2. FPGA功能设计说明书卡在需求与RTL之间三种文档、三类读者、六个必答问题2.1 规格书、功能设计说明书、详细设计文档三层文档的分工边界好多团队的文档管理是断层的上游有一份需求说明下游直接就是代码中间没有一张纸描述FPGA内部打算怎么行为。这会产生两种翻车现场一种是RTL编码者各自按理解实现集成时接口对不上凭联调一遍遍试错另一种是硬着头皮一上来就写详细设计文档把流水级、寄存器级微架构全部写死需求一改整个文档作废从此团队不再信任文档连该写的也不写了。常见做法是维护三层递进的文档。需求规格说明书回答系统要做什么是黑盒视角读者主要是系统工程师功能设计说明书回答FPGA内部怎么划分模块、信号怎么走、行为时序是什么是灰盒视角读者覆盖架构、RTL、验证和驱动工程师详细设计文档回答每个模块的RTL怎么实现是白盒视角读者基本只有该模块的编码和维护者。功能设计说明书的价值在于把前者的做什么翻译成后者的怎么行为它不碰微架构但必须覆盖接口、状态、时序、时钟复位、资源预算这些能支撑整条开发链的维度。文档回答的问题视角典型读者变更频率需求规格说明书系统要做什么黑盒系统工程师低频功能设计说明书模块怎么划分、行为与时序是什么灰盒架构、RTL、验证、驱动中频详细设计文档模块内部怎么实现白盒模块编码与维护者高频在真实项目里我习惯按一个功能模块一页组织功能设计说明书每个主要模块占一页页内固定四个板块——功能概述、接口信号表、行为描述、异常处理。每页控制在横向一屏能读完的篇幅评审时一页页过没过完的章节不允许进入编码阶段。这个规则同时约束了模块划分粒度某个模块的功能页超过一屏就该继续拆某个模块连两个接口都没有就该考虑合并进相邻模块。2.2 三类读者和各自的阅读路径说明书不是只给编码者看的功能设计说明书经常被误写成给RTL编码者的手册通篇讲状态机寄存器表却只有两行。真正拿到这份文档的人至少有三类阅读路径完全不同RTL编码者从接口信号表和状态机章节开始关心位宽、时钟域、转移条件验证工程师从功能编号清单和异常处理表开始关心哪些场景需要造用例驱动工程师直接翻寄存器表和中断行为关心偏移地址、访问属性、清零方式技术负责人则直奔时钟复位与资源预算章节关心能不能在当前器件上收敛时序、资源够不够放。读者最先打开的两个章节说明书写不好时的后果RTL编码者接口信号表、状态机与时序模块边界对不上靠联调赌验证工程师功能清单、异常处理表测试覆盖不了真实场景驱动工程师寄存器表、中断与复位流程驱动按猜测编程跑不通技术负责人时钟结构、资源与时序预算选型错误后期换器件因此写每一章之前先想清楚这一章给谁用再决定信息粒度。接口表写给RTL和验证就一定要带时钟域和有效电平寄存器表写给驱动就一定要带位域和复位值异常表写给验证就一定要写到可判定的触发条件。为读者定粒度是说明书不变成废纸的前提。2.3 六个必答问题与文档章节映射写正文前的自检清单写正文前我习惯先对着六个问题自检一次每个问题对应说明书里的固定章节。六个问题都落到文档且能互相引用骨架就算立住了。第一功能清单核心路径和旁路功能分别是什么对应功能编号清单章节。第二接口定义对内对外有哪些信号位宽、方向、有效电平、时钟域分别是什么对应接口信号表章节。第三行为时序关键路径的输入输出延迟、握手时序、帧或字对齐方式如何对应状态机与关键时序章节。第四状态与异常有哪些稳定状态异常进入哪个状态、如何恢复对应异常处理表章节。第五时钟复位时钟域如何组织、复位如何同步、哪些信号跨时钟域对应时钟与复位章节。第六资源与约束资源占用预估、时序目标、引脚约束需求对应资源与时序预算章节。这六个问题和章节的映射关系可以直接做成文档开头的导航表评审时逐项打勾能显著减少章节写得漂亮但内容没对齐需求的情况。接下来两章就按这个骨架讲接口表、寄存器表、状态机、时钟复位和异常处理的具体落笔方式。3. 搭出功能设计说明书的骨架模块划分、接口信号表与寄存器表怎么落笔3.1 顶层模块划分的两种思路先划数据流再单独拎出控制顶层模块划分最忌一上来就按功能堆模块堆到二十个文档维护成本直接失控。我惯用的顺序是先画数据流主干从输入接口到处理再到存储与输出接口把链路划成若干段然后把这些链路中与控制、配置、状态上报相关的部分单独拎出来形成一个控制平面最后逐段检查时钟域归属凡是跨域的信号单独标注为后文的跨时钟域清单留好位置。以一套典型的图像采集模拟项目为例顶层会分成五个模块Sensor输入接口、图像预处理、存储器控制器封装、配置管理寄存器堆、上位机接口。模块清单在文档里直接给一张表列五个字段模块名、职责、时钟域、主要对外接口、依赖的其它模块。模块名职责时钟域主要对外接口依赖模块sensor_ifSensor时序解析与数据对齐clk_pixpix_data、pix_valid无img_pre预处理与帧格式转换clk_sysframe_valid、frame_datasensor_ifmem_wrapDDR读写封装与FIFO管理clk_memwr_cmd、rd_dataimg_precfg_reg寄存器堆与配置桥接clk_sys配置总线无host_if与上位机命令交互clk_sysuart收发cfg_reg模块划分粒度有一条经验标准一个模块的功能页超过横向一屏就继续拆一个模块只有输入没有输出就检查是不是漏了接口一个模块同时被三个以上模块依赖时要考虑是不是该拆出公共子模块。粒度合适时说明书的章节结构会和代码的目录结构大体对齐评审才好逐模块对照。3.2 接口信号表七个字段一列都不能少少一个就埋一个雷接口信号表是功能设计说明书里被引用最多的部分RTL拿它查位宽和时钟域验证拿它写激励驱动拿它确认电平极性。我一般固定用七个字段信号名、方向、位宽、所属时钟域、有效电平或时序关系、功能说明、来源去向模块。多一个字段嫌累赘少一个字段大概率出问题。局部示例信号名方向位宽时钟域有效电平/时序功能说明来源/去向pix_clk输入1—上升沿采样Sensor像素时钟外部引脚pix_data输入16pix_clk与pix_valid同时有效Bayer原始数据sensor_if→img_prepix_valid输入1pix_clk高有效像素有效标志sensor_if→img_preframe_sync输入1pix_clk高有效一个周期帧起始标志sensor_if→img_preddr_wr_ready输入1clk_mem高有效写通道可接收新请求mem_wrap→img_pre写这张表要注意两点。一是所属时钟域必须写跨时钟域信号要在该行后标注同步方式比如两级触发器同步或经异步FIFO否则后文时钟与复位章节会无从引用。二是有效电平/时序禁止写正常时拉高这种描述要写成高有效一个周期下降沿后数据有效这类可判定表述。提示接口表定稿后再动RTL顶层顺序反了就会两头改改完文档改代码改完代码又觉得文档不对。接口表定稿后我习惯用脚本把它转录成Verilog头文件或SystemVerilog包的信号定义让RTL从同一份定义里引用而不是各写各的。手动转录也可以但转录完要逐行评审一次重点查位宽和方向这两项最容易在转录时被看走眼。3.3 寄存器地址表驱动工程师最依赖的一页写不好就返工寄存器表是说明书里最容易写坏的部分。常见的坏法有两种一种只有地址和名字没有位域、复位值、访问属性另一种把寄存器表写成了内存映射表地址排得整齐但每个位的含义只有作者自己知道。驱动工程师拿到这两种表要么不敢写代码要么写出来是错的。我建议每行寄存器至少包含六项偏移地址、寄存器名、位域定义、访问属性、复位值、功能说明。访问属性用行业通行的简写RO只读、RW读写、W1C写1清零、RC读后清零、WO只写。位域定义写成[bit]加含义保留位要明确标注写无效读返回0。示例偏移地址寄存器名位域定义属性复位值说明0x00CTRL[1] soft_rst [0] enRW0x00总控制寄存器0x04STATUS[1] fifo_ovf [0] busyRO0x00状态寄存器0x08FRAME_CNT[31:0] 帧计数RC0x00读后自动清零0x0CBUF_ADDR[31:0] 起始地址RW0x00采集数据存放地址属性字段最容易被忽略的是W1C和RC的副作用W1C意味着软件写0不会清除标志RC意味着读操作本身会改变寄存器状态这两条不写清楚驱动联调时一定会来回折腾。寄存器表后还要留一段专门描述中断行为中断源在哪个状态置位、经过哪条路径上报、软件如何清除、清除是否有时序要求驱动写中断处理看的就是这段。最后提一个管理习惯寄存器章节表头固定写寄存器版本和变更日期表尾放变更记录每条写明版本、变更内容、影响范围。寄存器表改版走和代码一样的评审流程改完必须通知驱动侧不能只丢一个新文件过去这是血泪经验换来的。4. 把行为边界写死状态机、时钟复位与异常处理在文档里的落地写法4.1 状态机文档化用状态-事件表代替大段叙述功能设计说明书里的状态机描述最怕两种写法。一种只画一张状态转移图箭头旁边写满收到数据后等待完成这类带解释空间的话不同人读出来的条件粒度不一样另一种写五百字叙述状态之间谁触发谁要读者自己脑补。这两种都会让编码者写出不一致的逻辑到验证阶段才暴露。可靠的做法是状态-事件表加转移条件。每个转移一行条件写成可判定的逻辑表达式能对应到接口信号表里的某个信号。示例当前状态转移条件下一状态进入下一状态时的动作IDLEstart1且fifo_empty1RUN拉高busy使能数据通路RUNframe_cnt 预设值且fifo_ovf0DONE拉低busy置位frame_doneRUNfifo_ovf1ABORT拉低busy置位fifo_ovf标志ABORT软件写clr1IDLE清空FIFO复位帧计数这个表有两条硬约束。第一转移条件里出现的每个信号都要能在接口信号表或数据通路内部信号清单里找到找不到说明条件写虚了。第二每个状态必须写明进入该状态时的动作以及在该状态内部持续维持的输出逻辑是哪些。这两类动作要分开列编码者才知道哪些输出进状态转移分支、哪些输出进默认分支避免把持续动作误写成一次性动作。状态机的编码方式比如用one-hot还是二进制属于详细设计文档的范畴功能设计说明书不用写。说明书要管的是行为什么条件下离开当前状态、离开时做什么、进去后维持什么这三件事写清楚编码方式留给实现者自己决定。4.2 时钟与复位三个必须在文档里定死的决策时钟复位章节不需要长但三个决策必须定死写不清楚的后果往往是综合后时序不收敛或者跨时钟域仿真随机失败。第一个是时钟来源与频率列一张时钟域清单包含频率、来源外部引脚、PLL锁相环、接口恢复时钟、服务的主要模块。第二个是复位策略建议直接写明异步复位、同步释放并给出复位同步器的位置每个时钟域入口放一个同步器复位释放沿与目标时钟上升沿对齐。第三个是跨时钟域信号清单逐信号写清楚同步手段单bit控制信号用两级触发器多bit数据用异步FIFO慢变多bit信号用握手计数器跨域用格雷码。信号名源时钟域目标时钟域同步方式风险等级frame_syncclk_pixclk_sys两级触发器低buf_addrclk_sysclk_mem异步FIFO中fifo_depthclk_memclk_sys格雷码计数高注意复位域清单必须与时钟域清单一一对应每个时钟域都要有明确的复位信号来源。评审时拿这两张表逐模块核对专门抓模块例化了全局复位却绕过同步器的隐患。写这张表时要顺带把需求侧的假设写进去哪个时钟是输入参考、哪个PLL输出允许失锁、参考时钟丢失时系统行为如何。需求假设不写验证阶段会出现时钟抖动超规格导致功能异常却没人能回答这算不算缺陷的争论。4.3 异常与边界场景把不会发生写进文档也是内容只写正常路径的说明书评审时很容易被一句话问倒如果FIFO满了怎么办与其现场拍脑袋不如在文档里固定一张异常处理表把能预见的非正常场景全部列出来。表格三列异常场景、系统行为、恢复方式。异常场景系统行为恢复方式Sensor输出分辨率切换检测到参数跳变暂停采集并置位cfg_err驱动重新初始化SensorDDR写FIFO达到高水位拉低写使能缓存剩余数据水位回落后自动恢复配置接口访问保留地址向总线返回错误响应不产生内部副作用无需人工干预复位释放时输入信号未稳定复位同步器保证先进入确定状态无需人工干预写异常表有一个原则不确定的行为不要留白。先写成待确认在评审时专项讨论并补全比留白安全得多。留白的危害在于两个人会各自猜一种行为等集成时才发现猜得不一样返工成本远高于评审时多花半小时。异常表写完后验证工程师可以直接从表中抽取边界用例这比从叙述文字里找场景可靠得多也能避免说明书写了但测试没覆盖的脱节。5. FPGA功能设计说明书常见问题排查五个坑的现象、原因与对策5.1 接口信号表与顶层例化各写各的仿真通过联调挂现象文档里pix_data是16位RTL顶层例化写成12位各模块独立仿真都通过一集成就报位宽不匹配重新综合加联调整整浪费一天。原因信号表是文档作者手工维护的顶层是编码者手工写的两边没有强制对应关系改位宽时往往只改了一处另一处留着旧值不变。解决把接口信号表当作唯一事实来源。先定表再写代码定稿后用脚本生成头文件或包定义RTL直接包含它。如果项目里代码已经存在反过来从顶层文件生成信号清单与文档逐项比对差异项单独列进评审。这个习惯能消除一多半接口类返工。5.2 状态机只画图不写条件两个编码者实现出两种行为现象两个开发者看同一张状态转移图一个把超时判在RUN状态内部另一个把超时做成独立分支测试结果对不上验证组花两天定位才找到差异来源。原因图形化表达对转移条件没有约束箭头上的简练描述在不同人眼里语义不同。超时到底指计数超过多少、使能条件是什么图上不写理解就分叉。解决强制用状态-事件表条件必须写到信号级。把超时写成timeout_cnt 1024且timeout_en1把数据准备好写成data_valid1且fifo_empty0。编码开始前拿这张表做一次内部评审逐条确认条件里的信号都能在信号表里找到。5.3 复位策略只写电平不写释放时序跨时钟域逻辑莫名跑飞现象文档写了异步复位、低有效编码者随手在模块内直接用全局复位复位释放时跨时钟域寄存器状态不确定仿真偶尔出现跑飞重新跑一遍又通过表现为典型时序玄学。原因复位策略只回答了电平没回答时序没说复位同步器放哪里也没说释放沿怎么对齐编码者只能按自己的习惯处理。解决文档写清楚三件事每个时钟域一个复位同步器释放沿对齐目标时钟上升沿提供一张与时钟域清单一一对应的复位域清单。评审时逐模块核对每个复位信号是否经过同步器这类跑飞大多能提前暴露。5.4 寄存器表改版不记版本驱动按旧地址读写半天没反应现象新版本把CTRL的使能位从bit0挪到bit1文档表格更新了但版本号没动驱动照旧写bit0配置半天不生效现象表现为写进去了好像没写。原因寄存器表是功能设计说明书里变更最频繁的部分没有版本记录和变更历史下游读者无法判断自己手里的表是不是最新的。解决寄存器表表头固定写寄存器版本和适用日期表尾加变更记录每条写明版本、变更内容、影响范围。改版走和代码一样的评审流程改完主动通知驱动侧更新寄存器头文件并确认驱动侧同步别只丢一个新文件过去。5.5 评审只看目录不看行为描述关键时序问题没人算过现象评审会开一小时大家翻了一遍文档提的全是格式和错别字意见真正关键的输入延迟、握手时序没人动笔核对到项目后期时序不收敛才回头改需求。原因评审没有清单默认文档是走形式注意力放在排版而不是行为正确性上行为章节反而没人深究。解决给评审配一张按章节的检查清单。状态机章节问每个转移条件是否对应信号表是否有不可达状态进入动作与持续动作是否区分时钟复位章节问每个时钟域是否都有复位域跨时钟域信号是否逐条列出并标注同步方式异常处理章节问FIFO满、访问越界、参考时钟丢失有没有行为描述清单逐项过完评审结论才允许签同意。6. 让功能设计说明书真正被用起来三条进阶使用习惯与一次模拟验收文档写完不叫完成被持续使用才叫完成。三条进阶做法是性价比最高的投入第一条是给功能编号。每个功能需求从FR-01开始编号验收行为写在编号旁边验证用例用TC编号回指功能编号形成需求到用例的追踪链。需求变更时顺着编号能找到所有受影响的模块页和验证用例改动影响一目了然。第二条是文档与代码同库管理。功能设计说明书的源文件放进和RTL同一个版本库提交代码涉及接口、寄存器或状态机变更时提交说明里必须带上文档修订记录。这一条能挡住代码改了文档没改的脱节问题。第三条是编码前做一次模拟验收。请一个没参与设计的新同事只依据说明书实现一个最小的旁路模块比如配置寄存器的读写通路。他照着文档做出来的模块能通过自测说明信息粒度够如果他频繁追问这里到底什么意思说明还有含糊点立即补掉。我那个图像采集模拟项目动RTL前做了这次验收结果发现状态机表少了两个异常恢复条件当场补掉省了之后整整一周的联调返工。这条教训我踩过不止一次写文档时总觉得这里大家都懂但大家都懂恰恰是最靠不住的假设。功能设计说明书里含糊的地方最后都会变成联调现场的口头沟通然后再变成下一轮返工。把行为写到信号级把待确认提前摊开文档才真正值钱。希望帮到你。本文还有配套的精品资源点击获取