
1. 为什么要在PDS里折腾ADF网表加密做FPGA项目交付的同行大概都遇到过这种场景方案验收通过了客户要拿走工程做二次开发但核心算法模块是你花了几个月调出来的直接给源码等于把家底全交出去。早些年大家的做法比较粗暴要么把关键模块做成硬核要么干脆不给源文件只给比特流但前者灵活性太差后者客户没法做系统级集成。紫光同创的PDS开发环境提供了一条中间路线——把指定模块综合成ADF网表文件再对网表做加密处理客户拿到的是加密后的网表能参与整个工程的布局布线但看不到内部RTL逻辑。这个思路和Intel FPGA的XAPP523文档里讲的网表加密交付模式本质是一回事只是各家工具链的实现细节不同。紫光同创的PDSPango Design Suite在国内中小规模FPGA项目里用得越来越多尤其是Logos和Titan系列性价比摆在那里。但PDS的文档相对精简ADF网表加密这块的实操资料散落在各种论坛帖子和FAE的零散回复里没有一个完整的、能直接照着做的流程。我前后在两个量产项目里踩过这个流程的坑从网表生成、加密选项配置、到客户侧集成验证中间遇到的问题不少这里把整个链路梳理一遍。这篇文章面向的是已经有一定FPGA开发基础、正在做项目交付或者准备做IP保护的工程师。如果你刚入门建议先把PDS的综合和布局布线流程跑通再来看这块不然容易卡在工具操作层面。全文会围绕ADF网表的生成、加密配置、集成方法、以及实际项目中遇到的典型问题展开每个步骤都会说明为什么这么做以及不做会出什么问题。2. ADF网表加密的整体设计思路2.1 为什么选网表加密而不是其他方案FPGA项目的IP保护手段大致有这么几种源码交付加许可证、比特流锁定、硬核化、以及网表加密。源码交付加许可证的方式最弱客户拿到源码后改个模块名你根本不知道。比特流锁定只能保护最终配置文件客户没法做系统级集成。硬核化成本太高而且一旦流片就不能改。网表加密是在综合之后、布局布线之前做文章客户拿到的是加密后的网表文件能参与后续流程但无法逆向出RTL。紫光同创PDS的ADF网表格式本质上是一种中间表示它保留了模块的端口信息和时序约束但把内部逻辑转换成了工具可识别的网表结构。加密后的ADF文件在PDS里可以正常参与综合后的布局布线但用文本编辑器打开是一堆密文。这个方案的核心优势在于客户能完成完整的工程集成和时序收敛你保护了核心算法双方的需求都满足了。注意ADF网表加密保护的是RTL级逻辑不是比特流。客户如果有足够的耐心和资源理论上仍然可以通过比特流反向工程来推测部分逻辑但这个门槛极高对于绝大多数商业项目来说已经足够了。2.2 加密粒度的选择模块级还是工程级PDS支持对整个工程做网表加密也支持只对指定模块做加密。我的建议是只加密核心模块不要把整个工程都加密。原因很简单客户需要在自己的顶层里实例化你的模块如果整个工程都被加密了客户没法做引脚分配和时序约束的调整。模块级加密的粒度控制更灵活你只需要把包含核心算法的那个模块或者那几个模块单独综合成ADF网表然后在客户侧工程里以黑盒形式例化。具体操作上你需要在PDS里为需要加密的模块单独创建一个综合任务综合选项里勾选生成ADF网表。综合完成后PDS会输出一个.adf文件和一个配套的端口描述文件。端口描述文件很重要客户侧需要用它来例化你的加密模块没有这个文件客户不知道你的模块端口长什么样。2.3 加密密钥的管理策略PDS的ADF加密支持密钥保护也就是说你可以给网表文件设置一个密码客户在集成时需要输入正确的密码才能正常使用。这个密码的管理是个容易被忽视的环节。我见过有团队把密码写在邮件里发给客户结果邮件被转发了好几手密码等于公开了。比较稳妥的做法是密码通过独立的安全渠道传递比如电话确认加加密邮件双重验证或者直接在现场调试时输入。另外PDS的加密选项里有一个“是否允许客户查看端口信息”的开关。如果你勾选了允许查看客户不需要密码就能看到模块的端口列表但看不到内部逻辑。如果你不勾选客户连端口都看不到必须输入密码后才能例化。这个选项根据你和客户的信任程度来定。一般来说端口信息本身不涉及核心算法允许查看能减少客户集成时的沟通成本。3. PDS环境下ADF网表生成与加密的完整实操3.1 环境准备与工程配置先确认你的PDS版本。ADF网表加密功能在PDS 2022.1之后的版本里比较稳定早期版本有一些已知的bug比如加密后的网表在客户侧综合时报端口不匹配。我实测下来2023.1和2024.1这两个版本比较稳。安装PDS的时候注意勾选“Pango Design Suite”下的所有组件特别是“Netlist Encryption”相关的选项有些精简安装包默认不装这个模块。工程配置方面你需要为待加密模块单独建一个PDS工程而不是在原有的大工程里直接操作。这样做的好处是综合选项可以独立配置不会影响其他模块。新建工程时器件型号要和客户最终使用的型号一致因为不同型号的FPGA在网表映射时资源结构不同型号不匹配会导致客户侧布局布线失败。# 创建独立工程的TCL脚本示例 create_project -name secure_module -dir ./secure_module_prj -part PGL22G-6MBG324 add_files -fileset sources_1 ./src/core_algorithm.v add_files -fileset sources_1 ./src/core_algorithm_top.v set_property top core_algorithm_top [current_fileset]这段TCL脚本创建了一个针对PGL22G器件的工程把核心算法模块加进去。器件型号根据你的实际项目替换PGL22G是Logos系列里比较常用的一款。注意top模块要设成你准备加密的那个模块不要设成整个系统的顶层。3.2 综合选项的关键配置综合配置是ADF网表生成的核心环节。在PDS的GUI里右键综合任务选择“Synthesis Settings”在弹出的对话框里找到“Netlist Output”选项卡。这里有几个关键选项Generate ADF Netlist必须勾选这是生成ADF文件的前提。Encrypt Netlist勾选后才会对生成的ADF文件做加密处理。Encryption Key设置加密密码建议用12位以上的混合字符不要用纯数字。Port Visibility选择“Visible”或“Hidden”决定客户是否需要密码才能看到端口信息。Optimization Level建议选“Area”或“Balanced”不要选“Speed”。因为网表加密后客户侧还要做布局布线如果你在综合阶段就把时序压得太紧客户侧可能无法收敛。提示Optimization Level选Speed会导致综合器做更激进的时序优化生成的网表在客户侧布局布线时可能因为资源映射方式不同而出现时序违例。选Area或Balanced给客户留出调整余量。综合完成后在工程目录的/synthesis/文件夹下会生成.adf文件和.ports文件。.ports文件是端口描述客户侧例化时需要参考。如果加密时选了Hidden模式.ports文件本身也是加密的客户需要输入密码才能查看。3.3 加密参数的详细说明与选择依据PDS的ADF加密底层用的是AES-128算法这是业界标准的对称加密方案安全性足够。加密模式是PCBCPropagating Cipher Block Chaining这种模式的特点是前一个数据块的加密结果会影响后一个数据块的加密过程即使两个模块的网表内容有部分相同加密后的密文也完全不同。这个特性对于防止差分分析很有用。密钥的生成方式有两种手动输入和自动生成。手动输入适合你需要把密码告诉客户的情况自动生成适合你只给客户加密后的网表、密码通过其他渠道传递的情况。我一般建议手动输入因为自动生成的密钥是一串随机字符客户输入时容易出错而且一旦丢失就无法恢复。加密强度方面PDS没有提供可选的密钥长度固定是AES-128。这个强度对于商业IP保护足够了暴力破解的计算量在现有硬件条件下不现实。但要注意密钥的保管比加密算法本身更重要。我见过有团队把密钥存在工程目录的文本文件里结果整个工程打包发给客户时忘了删密钥直接泄露。3.4 客户侧集成方法与验证步骤客户拿到加密后的ADF网表和端口描述文件后需要在自己的PDS工程里做集成。具体步骤是在客户工程的源文件列表里添加ADF网表文件然后在顶层模块里例化这个网表模块。例化的语法和普通模块一样端口名和位宽参考.ports文件。// 客户侧顶层例化加密网表的示例 module customer_top ( input wire clk, input wire rst_n, input wire [15:0] data_in, output wire [31:0] data_out ); // 例化加密后的核心算法模块 core_algorithm_top u_core ( .clk (clk), .rst_n (rst_n), .data_in (data_in), .data_out (data_out) ); endmodule客户侧综合时PDS会自动识别ADF网表文件并调用相应的解密流程。如果加密时设置了密码客户需要在综合设置里输入密码或者在TCL脚本里通过set_property命令传入。验证阶段建议客户先跑一遍综合和布局布线确认时序收敛然后再上板测试功能。注意客户侧的PDS版本必须和你生成网表时的版本一致或者更高。低版本PDS无法识别高版本生成的ADF网表会报“unsupported netlist format”错误。这个坑我在项目里遇到过客户用的是2022.1我这边是2023.1结果客户死活综合不过去后来统一升级到2023.1才解决。4. 实际项目中遇到的典型问题与排查方法4.1 网表生成失败常见原因与解决网表生成失败最常见的原因是RTL代码里使用了不可综合的语法。比如initial块里的延时语句、real类型变量、或者某些SystemVerilog的高级特性。PDS的综合器对可综合子集的支持比Vivado和Quartus要保守一些有些在Vivado里能综合的写法在PDS里会报错。排查方法是先在不加密的情况下跑一遍综合确认RTL本身没有问题。如果普通综合能过加密综合报错那问题出在加密选项配置上。检查一下是否勾选了“Generate ADF Netlist”但没勾选“Encrypt Netlist”或者密钥里包含了特殊字符导致解析失败。另一个常见问题是模块端口里包含了inout信号。ADF网表对inout端口的支持有限如果核心模块有三态接口建议在综合前把inout拆成独立的input和output然后在顶层做三态控制。这个改动不影响功能但能让网表生成顺利通过。4.2 客户侧综合报端口不匹配这个问题通常是因为.ports文件和实际网表的端口信息不一致。原因可能是你在生成网表后修改了RTL代码但没有重新生成网表或者客户侧例化时端口名拼写错误。排查方法是让客户把.ports文件里的端口列表和例化代码逐行对照确认端口名、位宽、方向都一致。还有一种情况是客户侧工程里同时存在同名的RTL模块和ADF网表模块PDS在综合时优先使用了RTL模块导致端口不匹配。解决方法是把同名的RTL文件从工程里移除只保留ADF网表文件。4.3 加密网表在布局布线阶段报资源冲突这个问题的根源通常是器件型号不匹配。你在生成网表时选的器件型号和客户实际使用的型号不一致导致网表里的资源映射方式和客户侧的资源结构对不上。比如你按PGL22G生成了网表客户用的是PGL25G两者的LUT结构和BRAM数量不同布局布线时就会报资源冲突。解决方法是确保生成网表时的器件型号和客户最终使用的型号完全一致。如果客户还没确定最终型号建议等型号确定后再生成网表。另外如果客户侧工程里已经有一些模块占用了大量资源留给加密网表的资源可能不够这种情况下需要客户调整资源分配或者换更大容量的器件。4.4 时序收敛困难的调试思路加密网表在客户侧布局布线时时序收敛难度比普通RTL要大。因为网表已经是综合后的结果客户侧的布局布线工具无法对网表内部逻辑做优化只能调整网表模块和其他模块之间的布线。如果网表内部的逻辑级数太深客户侧很难通过布局布线来改善时序。调试思路是先在生成网表时把综合的Optimization Level设成Area让综合器尽量用面积换时序余量。然后在客户侧把加密网表模块的布局约束设成“Spread”或者“Region”给布局器更大的调整空间。如果还是收敛不了可能需要你在生成网表前对RTL做流水线优化降低关键路径的逻辑级数。问题现象可能原因排查方法解决方案网表生成失败RTL含不可综合语法先跑普通综合修改RTL移除不可综合语法客户侧端口不匹配.ports文件与网表不一致逐行对照端口列表重新生成网表或修正例化代码布局布线资源冲突器件型号不匹配确认双方器件型号统一器件型号后重新生成时序收敛困难网表内部逻辑级数太深查看时序报告的关键路径优化RTL流水线或调整布局约束4.5 密钥丢失或错误的应急处理密钥丢失是个很尴尬的问题。PDS的ADF加密没有提供密钥恢复机制一旦忘记密码加密后的网表就废了只能重新生成。所以我的建议是密钥生成后立即在安全的地方备份比如公司的密码管理工具或者保险柜。不要存在工程目录里不要通过普通邮件发送。如果客户输入密码错误PDS会报“decryption failed”错误。这时候需要确认客户输入的密码和你设置的是否完全一致注意大小写和特殊字符。有些客户在复制粘贴密码时会带入空格导致解密失败。建议让客户手动输入密码不要复制粘贴。5. 一些实操心得与避坑建议5.1 网表加密不是万能的ADF网表加密能保护RTL逻辑不被直接查看但它不能阻止客户通过比特流反向工程来推测逻辑功能。对于绝大多数商业项目来说反向工程的门槛和成本远高于自主研发所以网表加密已经足够。但如果你的IP价值极高比如涉及国防或者金融安全建议考虑硬核化或者更高级的保护方案。另外网表加密后的模块在客户侧无法被仿真。客户只能做综合后的时序仿真无法做RTL级的功能仿真。这个限制在项目初期就要和客户沟通清楚避免客户以为拿到网表后还能像普通RTL一样仿真。5.2 版本管理要严格PDS的ADF网表格式在不同版本之间可能有变化。你生成网表时用的PDS版本和客户集成时用的版本必须一致或者客户版本更高。我建议在交付网表时附上一份说明文档写明生成网表所用的PDS版本号、器件型号、加密选项配置。客户拿到后先确认自己的PDS版本是否匹配不匹配的话先升级再集成。5.3 端口描述文件的交付方式.ports文件是客户例化的依据交付方式要注意安全。如果加密时选了Hidden模式.ports文件本身也是加密的客户需要密码才能查看。如果选了Visible模式.ports文件是明文的可以直接发给客户。我一般建议选Visible模式因为端口信息本身不涉及核心算法让客户直接看到端口列表能减少沟通成本。5.4 测试验证要覆盖边界条件加密网表在客户侧集成后测试验证要覆盖边界条件。比如输入数据的极值、时钟频率的上下限、复位信号的时序等。因为网表内部的逻辑已经被综合器优化过某些在RTL仿真中不会出现的问题可能在网表集成后暴露出来。建议客户在集成后先跑一遍完整的回归测试确认功能正常后再上板。5.5 和客户明确责任边界网表加密交付模式下你和客户的责任边界要明确。你负责网表的功能正确性和加密安全性客户负责集成后的时序收敛和系统级验证。如果客户集成后出现时序问题你需要提供网表内部的时序报告和关键路径信息但客户侧的布局布线调整需要客户自己完成。这个边界在合同或者技术协议里要写清楚避免后期扯皮。6. 加密网表的后续扩展与维护6.1 网表版本升级的处理如果你的核心算法有更新需要重新生成加密网表并交付给客户。这时候要注意版本兼容性新网表的端口列表如果和旧网表不一致客户侧的例化代码需要同步修改。建议在算法更新时尽量保持端口列表不变只更新内部逻辑。如果必须改端口提前和客户沟通给客户留出修改例化代码的时间。6.2 多客户交付的密钥管理如果你把同一个加密网表交付给多个客户每个客户使用不同的密钥是个好习惯。这样即使某个客户的密钥泄露不会影响其他客户的安全。PDS支持为同一个网表生成多个不同密钥的加密版本你只需要在生成网表时修改密钥重新生成即可。虽然多花一点时间但安全性提升明显。6.3 网表加密与工程管理的结合在实际项目中加密网表的生成和管理应该纳入工程管理流程。建议在版本控制系统中单独建一个目录存放加密网表和对应的端口描述文件每次生成网表时记录生成时间、PDS版本、器件型号、密钥指纹不是密钥本身等信息。这样在客户反馈问题时能快速定位是哪个版本的网表。我在实际项目里踩过最大的坑是客户侧PDS版本不匹配导致综合失败排查了半天才发现是版本问题。后来我在交付网表时都会附上一份检查清单让客户先确认PDS版本、器件型号、加密选项这三个关键信息确认无误后再开始集成。这个习惯帮我省了很多来回沟通的时间。另外密钥管理一定要用独立的密码管理工具不要图省事存在工程目录里我见过太多因为密钥泄露导致IP保护失效的案例了。