板子上有两颗大芯片:一颗 Zynq UltraScale+ RFSoC,旁边一颗 Kintex UltraScale FPGA,中间用八条 高速串行线连起来。上一篇里,AI 用一天把这块空白板子跑到了登录提示符。这一篇是下一步:把第二颗 芯片变成第一颗的”扩展仓”,让一个模块放过去算,用它旁边那四吉字节的内存。整个过程由 AI 在 Python2Verilog 框架下完成,我只在几个关键节点给方向。
本该是件顺手的活。结果撞上了最磨人的那种问题:每一项都量得完美,硬件却一动不动。
一个方向死活不通
这条链路用一种标准的串行编码:接收端盯着一串合法的标记,连续看到足够多,就宣布自己锁定了。一 个方向几乎立刻就锁上了,另一个方向永远锁不上。锁定检测一直在滑动,永远差那么一点。
于是就查,每一步都有干净的结果。厂商自带的例程在仿真里锁定了。自环仿真锁定了,一帧数据逐位精 确。按真实接线连好的跨芯片仿真,两个方向都锁定,逐字节精确。四十万个比特推过仿真导线,标记只 在唯一一个偏移上全部对齐。把好设计和坏设计做布线后对比,逐引脚完全相同。
五关全过,硬件还是老样子。而且物理信号干净得挑不出毛病:眼图张得又大又开,水平约七成八,垂直 约九成四。信号质量无可挑剔,问题恰恰就在于,信号质量根本不是问题所在。电路每一层都查过、都清 白。那这根导线上,到底跑的是什么?
抓到导线上的真实字节
在此之前的所有观察,都是统计出来的数字:一个锁定率、一个合法率、一个通过或失败。问题就出在这 些统计上,因为统计只回答”是”或”否”,把信号本身是什么给藏了起来。所以 AI 加了一个一次性抓取 器,趁链路声称锁定的时候,把导线上连续三个原始字读回来。读回来是这样:
0x6666666666666666
0x9999999999999999
0x6666666666666666
这不是数据。真正的载荷扰码之后该像噪声,而这是 0011 在循环,一个干干净净的方波,一个上面什
么都没驮的自由振荡时钟。
让这件事如此以假乱真的,是一个又小又刁的巧合。一帧是 66 位,66 除以 4 余 2,于是从这一帧到下
一帧,图案正好挪两位,那两位同步头永远落在 01 或 10 上。这俩恰好都是真实同步头能取的合法
值。所以一个纯时钟图案,能满足锁定、满足眼图、满足标记合法率,同时不带一丁点信息。
这一次抓取,比之前所有统计加起来都值钱。它一下堵死了一整类假设:数据通路没有把什么弄坏,因为 这根导线上压根没有数据可弄坏。是别的地方出了问题。
地图是反的
既然导线上跑的是自由振荡的时钟,那就说明没有人在驱动它。AI 回头把通道接线直接量了一遍,只认 两颗芯片上印着的物理名字,不认工具内部的序号,往每条通道上发一个不一样的编码标记,好把它们区 分开。三轮解出全部八条。结果,和所有人一直信着的那份记录,正好相反。
让它活这么久的陷阱在这里。发送端确实在发正确的数据,只是发给了一条没人在听的通道;而所有人盯 着的那个输入,连着一条从未配置的通道,于是自己振荡起来。每一次仿真都照着同一份记录连线。记录 内部自洽,所以每一次仿真都复现了同一个错误连接,然后通过。五层验证彼此一致,是因为它们都读了 同一个共享的错误假设。
有人会理直气壮地问:这八条线不是做过误码率测试吗,七条零误码,怎么会没发现接反?因为那个测试 往每条线上发同一个图案,不管怎么连,每个接收端都能锁定、都读到零误码。它对”谁连着谁”天生是盲 的。每一根铜线确实都好,错的是那张说”谁到谁”的表。
还有个诚实又扎心的细节:那份记录甚至带着一句”已上硅验证”的注记。注记是真的,但它背后的”验证” 只是第一条通道的巧合锁定。没有人回头去翻原理图,因为一个盖着”实测”章的结论,比七十五页 PDF 图 纸让人放心,而跨着那些页手工追八对差分线,恰恰最容易出错。答案其实一直画在原理图上。换到正确 的两条通道重接,链路一次就通,逐字节精确。
第二块芯片成了扩展仓
链路诚实了,剩下的就顺了。前面还有一件要机器来读的活:第二颗芯片旁边那四吉字节内存,没有任何 能用的引脚文件,只有同一份七十五页原理图。AI 把它变成一个几何问题,按词在页面上的位置,把每个 引脚号和它的网络名配成一对,任何配不上两次的都不接受。所有网络零冲突解出,内存第一次上电就通 过了校准。
从此,第二颗芯片对第一颗就是三样东西:一条十吉比特管道、一个算力节点、一块远程内存。每一样都 在真实硬件上验过,不是在仿真里。四分之一兆字节往返,逐字节精确。一个解码器放在第二颗芯片上 跑,软信息跨链路进去、硬判决交回来,和基准模型比对零错误,中间不复位连着来两次仍然零错。往远 端内存写一笔再读回来,完全一致,换一个深地址再来一遍,还是一致。
有一个尾巴值得留着。早先点亮的时候,八条线里有一条测出过几个误码。收官前,AI 把这条线单独泡了 十分钟:六万亿比特,零错误,眼图张开度和其他七条一个水平,之前的误码再没出现。安静的包袱抖在 这里:这条线,正好就是那条反接链路一直在用的线。
留下什么
三条准则写回了框架,成为强制检查,而且它们能推广到这一块板子之外:
锁定不等于数据。一个信号可以满足链路暴露的每一项健康指标,锁定、眼图、合法率,全都满足,却什 么也不带。链路不算通过,除非你解出真实载荷,逐字节核对。
信测量,不信记录。用物理名字去读接线,往每条通道上发一个只可能来自那条通道的信号,把工具的序 号当成方便,不当成事实。
信机器,不信手抄。从图纸上手抄的引脚表是安静错误的来源。用几何方法把它抠出来,要求零冲突,再 让一个下游检查当裁判。
最贵的教训是那条最一般的:当电路每一层都查过、都清白,剩下该怀疑的,就是测量本身。那张反的记 录能活过一整天,只有一个原因,每一次仿真都在老老实实照着它连线。电路从没骗人,骗人的是那张 地图。
备注
- 硬件:一块定制板,把一颗 AMD Zynq UltraScale+ RFSoC(XCZU67DR)和一颗 AMD Kintex UltraScale FPGA(XCKU115)配在一起,用八条高速串行链路相连。
- 链路层、远程算力与远程内存的逻辑,以及全部排查,都由 AI 在 Python2Verilog 框架下完成。文中的 数字,都是在板子上读到的读数,以及同一次会话里工具报告的输出。
- 本文接续《一天,把 Linux 跑上一块 RFSoC 板子》。