ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

紫光同创FPGA adf网表文件与黑匣子设置实战指南

紫光同创FPGA adf网表文件与黑匣子设置实战指南 1. 从一次交付翻车说起为什么adf网表文件和黑匣子值得单独聊前两年接手过一个工业控制板卡的项目主控用的是紫光同创的Logos系列FPGA逻辑规模不大但交付节点卡得很死。项目做到后期客户突然提了一个要求核心算法模块要单独交付源码不能给第三方团队但对方又必须能把整个工程跑起来做系统联调。当时第一反应是给个网表不就完了结果真上手才发现紫光同创PDSPango Design Suite这套工具链里adf网表文件的使用和黑匣子Black Box设置坑比想象中多得多——综合出来的adf文件直接丢进新工程要么找不到模块要么端口对不上要么时序约束全丢编译报错能刷满一屏。这篇就围绕紫光同创FPGA的adf网表文件使用和黑匣子设置这个主题把当时踩过的坑、后来摸索出来的稳定流程以及一些工具文档里不会明说的细节完整梳理一遍。核心关键词包括紫光同创、FPGA、adf网表文件、黑匣子、PDS涉及的操作全部基于PDS工具链。先说清楚这套东西解决什么问题。在FPGA项目协作中经常遇到两种场景一是IP保护自己辛苦写的核心逻辑不想以源码形式交付二是分工开发A团队做算法模块B团队做顶层集成和板级调试两边不想互相暴露全部源码。这时候就需要把某个模块综合成网表文件adf在顶层工程里以黑匣子的形式例化调用。听起来简单但adf网表不是Verilog源码它携带的信息有限端口定义、参数、时序约束这些都需要额外处理稍不注意就会在集成阶段翻车。适合读这篇的人正在用紫光同创PDS做开发、需要做模块化交付或IP保护的工程师刚接触adf网表、被黑匣子报错折腾过的朋友以及想提前了解这套流程、避免项目后期返工的团队负责人。下面按实际操作顺序展开从概念到流程到排错尽量把每个为什么讲透。2. adf网表到底是个什么东西和源码、和edf的区别在哪2.1 adf文件的本质与生成时机adf是紫光同创PDS工具链中综合Synthesis阶段输出的网表文件格式全称可以理解为一种描述逻辑连接关系的中间文件。它和Verilog源码最大的区别在于源码描述的是行为adf描述的是结构——综合器已经把always块、if-else这些行为级描述映射成了LUT、触发器、BRAM、DSP等底层资源的连接关系。所以adf文件里没有可读的逻辑代码只有网表。生成adf的时机很关键。在PDS里综合完成后会自动生成adf位置一般在工程目录下的综合结果文件夹里。但要注意默认综合输出的adf不一定适合直接给别人用因为里面可能包含了综合器自动推断出的一些信息端口命名也可能被优化过。我一般会专门为交付单独跑一次综合并且在综合选项里做一些设置保证输出的网表干净、端口明确。这里有个容易混淆的点adf和edfEDIF网表不是一回事。edf是通用的电子设计交换格式很多工具链都支持adf是紫光同创PDS体系内的格式和PDS的版本、器件系列绑定得比较紧。用PDS打开adf没问题但如果你想跨工具链用那得走edf。实际项目里只要上下游都用PDSadf就够了而且adf对紫光同创器件的适配性更好资源映射更准确。2.2 黑匣子机制工具怎么假装知道这个模块黑匣子的核心思路是顶层工程在综合和实现时遇到一个只有端口定义、没有内部逻辑的模块工具不去管它内部是什么只按照端口连接关系把它当成一个盒子来处理。这个盒子在最终生成比特流时会被adf网表里的实际逻辑替换进去。理解这个机制很重要因为它决定了黑匣子模块的声明方式。你必须在顶层工程里提供一个壳——通常是一个Verilog文件里面只有module声明和端口列表没有内部逻辑。这个壳的端口必须和adf网表里的模块端口完全一致包括端口名、位宽、方向。任何一处对不上工具在链接阶段就会报错。我见过最常见的错误就是端口名大小写不一致或者位宽写错一位。Verilog本身对大小写敏感而adf网表里的端口名是综合时确定的如果你在壳文件里手写端口时打错一个字母编译能过综合但到实现阶段链接网表时就炸了。所以我的习惯是壳文件的端口列表直接从adf网表的端口报告里复制不手写。2.3 为什么不用源码而用网表保护与解耦的双重考量有人会问既然黑匣子这么麻烦为什么不直接给源码两个原因。第一是IP保护核心算法是团队的心血源码交付意味着逻辑完全暴露后续维护和商务上都被动。第二是解耦源码交付后接收方可能改你的代码改出问题还得你背锅网表交付则明确了边界你只对网表功能负责对方怎么集成是对方的事。但网表交付也有代价调试困难。源码可以加ILA、可以单步仿真网表基本是个黑盒出问题只能看端口波形。所以我的经验是交付网表的同时一定要附带一份详细的端口时序说明和仿真模型否则对方集成时会非常痛苦。这一点后面会专门讲。3. 从源码到adf生成网表前的准备工作与综合设置3.1 模块划分哪些逻辑适合做成网表不是所有模块都适合做成adf网表。我的判断标准有三条一是逻辑相对独立对外接口清晰不依赖顶层的大量内部信号二是模块内部不含需要频繁修改的参数因为网表里的参数化能力很弱三是不含厂商特定的IP核除非你确认对方工程里也有同样的IP。举个反例之前有个项目想把一个带PLL的时钟管理模块做成网表结果对方工程里没有对应的PLL IP配置链接时直接报找不到原语。后来改成把PLL留在顶层只把PLL后面的处理逻辑做成网表问题才解决。所以含厂商原语或IP的模块做网表要格外谨慎最好把IP部分剥离出来。另外模块的端口尽量用简单的wire类型避免在端口上直接挂复杂的表达式。网表对端口的处理比较死复杂的端口连接关系容易在链接时出问题。3.2 综合选项里那几个必须改的设置在PDS里对目标模块单独建工程做综合时有几个选项需要特别关注。第一个是综合策略建议选面积优先或默认不要选性能优先因为性能优先会做更多优化可能改变端口或资源映射给后续链接带来不确定性。第二个是保留层次结构Keep Hierarchy这个选项建议打开它能让综合后的网表保留模块的层次端口更清晰链接时不容易出错。第三个是输出文件格式确认勾选adf输出。有些PDS版本默认只输出edf需要手动勾adf。第四个是禁用IO缓冲插入因为网表模块是内部逻辑不需要IO buffer如果综合时插了IO buffer链接到顶层后会多出莫名其妙的端口。还有一个细节综合时的顶层模块名要和交付的模块名一致。如果综合时顶层叫top交付时对方例化的模块叫my_core那链接肯定失败。我一般会在综合前把模块名改成最终交付的名字避免混淆。3.3 生成后的自检端口报告和资源报告怎么看综合完成后别急着把adf丢给别人先自己检查两样东西。第一是端口报告PDS会生成一个端口列表文件里面列出了模块的所有输入输出端口、位宽、方向。把这个报告和你的壳文件端口逐一对照确保完全一致。第二是资源报告看看LUT、寄存器、BRAM的占用情况确认没有异常膨胀——如果资源占用比预期高很多可能是综合策略有问题或者代码里有没预料到的逻辑被推断出来。我还会做一件事用生成的adf单独建一个测试工程把壳文件加进去跑一遍完整流程确认能综合、能实现、能生成比特流。这一步相当于自测能提前发现大部分链接问题。虽然多花半小时但比交付后被对方追着问强得多。4. 黑匣子工程的搭建壳文件、约束和例化方式4.1 壳文件怎么写才不出错壳文件是黑匣子工程的入口写法直接决定链接能否成功。标准写法是module声明加端口列表端口方向和位宽必须和adf网表一致模块内部留空或者只写注释。不要在里面加任何逻辑哪怕是一句assign都不要否则综合器会认为这个模块有实现可能不去链接网表。端口列表的写法建议用ANSI风格每个端口单独一行方便对照。比如module my_core ( input wire clk, input wire rst_n, input wire [15:0] data_in, input wire data_valid, output wire [31:0] data_out, output wire data_ready ); // 黑匣子模块内部逻辑由adf网表提供 endmodule注意端口名要和adf网表里完全一致。如果adf里的端口是data_i而不是data_in那壳文件里也必须写data_i。我一般直接从端口报告里复制粘贴避免手误。还有一个坑有些综合器会把常量端口或未连接端口优化掉导致adf里的端口比源码少。如果发现端口对不上回去检查综合设置确认没有开启会优化端口的选项。4.2 约束文件怎么处理时序约束的传递问题这是黑匣子流程里最容易被忽视的一环。adf网表里不包含时序约束综合时你写的create_clock、set_input_delay这些约束不会跟着网表走。所以顶层工程必须重新对这些端口施加约束否则时序分析就是空的实现结果可能完全不可靠。我的做法是在交付网表时附一份约束模板列出该模块所有端口需要的约束类型和推荐值。比如输入端口相对时钟的setup/hold要求输出端口的最大延迟等。对方在顶层约束文件里把这些约束加上才能保证时序正确。如果模块内部有时钟域交叉或特殊时序要求也要在文档里说明。网表是黑盒对方看不到内部结构只能靠你提供的约束信息来保证时序。这一点如果偷懒后期调试会非常痛苦。4.3 顶层例化位置、命名和参数传递在顶层工程里例化黑匣子模块和例化普通模块写法一样但有几个注意点。第一例化时端口连接建议用命名连接.port_name(signal)不要用位置连接因为位置连接一旦端口顺序有出入就全错而且可读性差。第二如果模块有参数参数传递要谨慎因为网表里的参数在综合时已经固定顶层传参可能不生效甚至导致链接错误。最好的做法是网表模块不带参数需要配置的地方通过端口传入。第三例化的模块名必须和adf网表里的顶层模块名一致。如果adf里模块名是my_core顶层例化时也得用my_core不能改名。有些工程师习惯在例化时改个名字方便区分但这在黑匣子流程里行不通。第四把adf文件和壳文件一起加入工程。PDS里添加文件时adf作为网表文件加入壳文件作为Verilog文件加入工具会自动识别并链接。如果只加壳文件不加adf综合能过但实现时会报找不到模块只加adf不加壳文件综合阶段就找不到模块声明。5. 链接阶段的典型报错与排查链路5.1 端口不匹配从报错信息反推问题链接阶段最常见的报错就是端口不匹配报错信息一般会指出哪个端口对不上是位宽问题还是方向问题。但有时候报错信息很模糊只说module not found或port mismatch不告诉你具体哪个端口。这时候排查思路是先确认模块名一致再逐一对照端口报告和壳文件。我遇到过一次很隐蔽的情况adf里的端口名是data_out[31:0]壳文件里写的是data_out [31:0]中间多了一个空格。Verilog本身对空格不敏感但PDS的网表链接器在解析端口名时把空格也算进去了导致匹配失败。后来把空格去掉就好了。这种问题看报错根本看不出来只能靠仔细比对。还有一个情况是端口方向搞反。比如adf里是output壳文件里写成input综合能过链接时报方向冲突。所以对照端口报告时方向也要逐一确认。5.2 模块找不到文件添加顺序和路径问题module not found这个报错八成是adf文件没加进工程或者加进去了但路径不对。PDS添加网表文件时要确认文件类型选的是网表而不是源码否则工具可能不识别。另外如果adf文件放在工程目录外路径里有中文或空格也可能导致找不到。建议把adf文件复制到工程目录下用相对路径引用。还有一种情况是模块名大小写问题。PDS在Windows下对文件名大小写不敏感但网表内部的模块名是大小写敏感的。如果adf里模块名是My_Core壳文件里写my_core链接时就会找不到。所以模块名统一用小写避免这类问题。5.3 时序违例黑匣子端口的约束缺失时序违例在黑匣子工程里特别常见因为adf网表不带约束顶层如果忘了加端口约束工具就按默认处理结果时序全乱。典型表现是实现后时序报告里黑匣子端口相关的路径全是红色setup或hold违例。解决办法就是前面说的在顶层约束文件里补上端口约束。如果不知道具体约束值可以先按时钟周期的一半估算跑一遍时序分析再根据报告调整。另外黑匣子内部的时序你控制不了但可以通过约束端口的输入输出延迟给内部逻辑留出足够的时序余量。我一般会在约束文件里加一段注释标明这些约束是给黑匣子模块的方便后续维护。如果模块升级约束也要同步更新。6. 交付与协作让对接方少走弯路的几个习惯6.1 交付包里应该包含什么交付adf网表时不要只给一个adf文件。我的标准交付包包含五样东西adf网表文件、壳文件Verilog、端口说明文档、约束模板、以及一个简单的仿真模型如果有条件。端口说明文档里列出每个端口的名称、位宽、方向、功能描述和时序要求约束模板给出推荐的约束写法仿真模型可以让对方在系统仿真时验证接口时序。如果模块有复位要求或初始化序列也要在文档里写清楚。网表是黑盒对方不知道内部复位逻辑如果复位时序不对模块可能根本不工作。这一点在交付时说明白能省掉大量来回沟通。6.2 版本管理adf和源码的对应关系adf网表一旦生成就和当时的源码版本绑定了。如果源码后续有修改必须重新综合生成新的adf不能混用。我习惯在adf文件名里带上版本号和日期比如my_core_v1.2_20240510.adf同时在交付文档里记录对应的源码版本号Git commit ID。这样后续追溯问题时能快速定位到对应的源码。另外PDS的版本也要记录。不同版本的PDS生成的adf可能有兼容性问题如果对方用的PDS版本和你不一样链接时可能报奇怪的错误。最好约定统一使用某个版本的PDS或者提前确认版本兼容性。6.3 联调阶段的配合要点联调阶段是最容易扯皮的时候。对方说你的网表有问题你说对方的集成方式不对。为了避免这种情况我一般会在交付时约定一个简单的验收测试对方用你的网表跑一个最小系统输入已知激励看输出是否符合预期。这个测试通过后再进入系统联调。联调时如果出问题先确认是接口问题还是内部逻辑问题。接口问题看端口波形内部逻辑问题只能你这边配合排查。所以交付时留一个联系方式联调阶段保持沟通比事后互相甩锅强得多。7. 几个容易被忽略的细节和我的实操心得7.1 黑匣子模块的仿真怎么做黑匣子在仿真时是个空模块没有内部逻辑仿真输出全是未知态。所以系统仿真时要么用行为级模型替代黑匣子要么在测试平台里对黑匣子端口做强制驱动。我的做法是交付时附一个行为级仿真模型功能和网表一致但用Verilog写成可综合或可仿真的形式。对方在系统仿真时用这个模型实际实现时用adf网表两边接口一致仿真结果有参考价值。如果模块太复杂行为级模型写起来费劲至少也要提供一个端口时序模型描述输入输出之间的时序关系让对方能验证接口时序。7.2 资源占用和时序的权衡adf网表在链接到顶层后资源占用会和单独综合时略有差异因为顶层会做跨模块优化。有时候单独综合时资源够用链接后却超了。这时候可以尝试调整顶层的综合策略或者把黑匣子模块的边界约束得更明确减少跨模块优化。时序方面黑匣子端口的约束如果给得太紧可能导致顶层其他逻辑时序紧张给得太松又可能掩盖真实问题。我的经验是先按模块单独综合时的时序报告估算端口的时序余量然后在顶层约束里留10%到20%的余量跑一遍实现看报告再微调。7.3 从adf到edf跨工具链的备选方案虽然adf在PDS体系内很好用但如果对接方用的不是PDS或者项目要求通用格式那就得用edf。PDS支持输出edf网表但edf的兼容性和资源映射准确度不如adf。如果必须用edf建议提前和对接方确认工具链版本和器件库避免链接失败。我的建议是只要上下游都用PDS优先用adf如果跨工具链提前做兼容性测试别等到项目后期才发现问题。7.4 一个真实项目的完整时间线最后分享一个真实项目的时间线供参考。项目是工业控制板卡FPGA做电机控制算法。算法模块由A团队开发顶层集成由B团队负责。A团队在项目中期开始准备网表交付第一周做模块划分和综合设置生成adf并自测第二周写壳文件、端口文档和约束模板第三周B团队集成联调发现两个端口位宽不一致修正后通过第四周系统联调补了一条时序约束最终交付。整个过程大约四周其中端口对齐和时序约束花了最多时间。如果重来一次我会在项目初期就约定好端口命名规范和约束模板避免后期返工。另外adf网表的自测环节不能省哪怕多花半天也比交付后被追着改强。这套流程跑顺之后后续几个项目都复用了同样的方法基本没再出过大问题。核心就一句话网表交付不是给个文件就完事端口、约束、文档、自测一个都不能少。
返回列表