今天读到三个移植故事,它们表面上毫无关联,但底层有一条相同的纹路。
第一个故事。Vladimir Varankin 想给自己的 2016 MacBook Pro 装 FreeBSD,但 FreeBSD 没有 Broadcom BCM4350 Wi-Fi 芯片的驱动。Linux 有一个叫 brcmfmac 的驱动,理论上只需要把"胶水代码"从 Linux 翻译到 FreeBSD 就行了。他让 Claude Code 直接干这件事。模块编译通过了,但什么也不干。加载到真实硬件上,内核直接 panic。AI 拼命地在代码里塞 #ifdef __FreeBSD__,补丁越来越大,驱动离能用越来越远。
然后他换了一种做法。他不再让 AI 翻译代码,而是让 AI 阅读 Linux 驱动的源码,写出一份详细的技术规格说明书——十一个章节,从数据结构到固件接口,"精确到比特"。然后用另一个 AI 会话对照源码校验这份规格书,再用第三个会话校验校验的结果。最后,他开了一个全新的项目,只给 AI 这份规格书,让它从零开始为 FreeBSD 写一个全新的驱动。
这次成功了。Wi-Fi 扫描、2.4GHz/5GHz 连接、WPA/WPA2 认证,全部工作。
第二个故事。Colin Leroy 把 Shufflepuck Cafe——一个 1989 年在 Mac 上运行的"3D"空气曲棍球游戏——移植到了 1979 年的 Apple II。Apple II 的 6502 处理器只有 1MHz,没有乘法指令,没有除法指令,显存布局因为隔行扫描而混乱不堪。
在这种硬件上做透视投影是不可能的——除非你不在运行时做。Colin 写了一个查找表生成器,把所有的透视变换预计算成三张查表。对于除法,他发明了一个巧妙的替代:不存储百分比,而是存储"256分比"——这样除以256就变成了把高字节挪到低字节,一条指令搞定。最终那个坐标变换函数占用 612 字节(其中 580 字节是查找表),执行只需 138 个时钟周期。
为了让画面不闪烁,他需要在 CRT 光束扫过屏幕之前画完所有精灵。他把玩家推杆的绘制方式从 AND-mask-OR 改成了 XOR——每个字节省掉 8-10 个时钟周期,同时省掉了 3400 字节的 mask 数据和 136 字节的背景缓冲区。省下来的时间刚好够赢得和光束的赛跑。
声音也一样。原版游戏的音效在远处音调会降低。Colin 没有存储多个采样,而是在播放器里加了一个"减速因子"——在每个占空比周期里浪费额外的时钟周期来降低音调。这让分辨率从差不多 6 比特降到了差不多 5 比特,但对真实硬件来说够用了。
第三个故事。一位叫 dork.dev 的开发者把 Coreboot 移植到了 ThinkPad X270。她从已有的 X280 适配开始——两台机器看起来很相似,X270 没有雷电口,内存是 SODIMM 槽而不是板载。看起来只需要改几个引脚映射就行。
第一次刷入,SeaBIOS 和 GRUB 都启动了——看起来成功了。但 NVMe 硬盘启动不了,Wi-Fi 也消失了。更早时她在焊接芯片夹的时候还弹飞了一颗 0.8×1.6mm 的电容,不得不对着原理图辨认出它是一颗 10μF 0603 6.3V 电容,从 Digikey 下单等快递。
最终的 bug 藏在一个微妙的地方:X280 的 CLKREQ4 引脚悬空,但 X270 的无线网卡把 WiGig 和 WiFi 分成了两个独立的 PCIe 设备,各自需要自己的 CLKREQ。她一直在用 CLKREQ1 给 WiFi,但正确答案是 CLKREQ2。这个偏移顺延到后面所有的时钟请求引脚,像多米诺骨牌一样推倒了 NVMe 和 WiFi。
三个故事的共同点是什么?
它们都是关于翻译的。从 Linux 翻译到 FreeBSD,从 Mac 翻译到 Apple II,从 X280 翻译到 X270。但它们都证明了同一件事:从 A 到 B 的直接翻译几乎不可能成功。
Vladimir 的第一次尝试——让 AI 逐行把 Linux 代码改成 FreeBSD 代码——失败了,因为两个系统的内核抽象不同,不存在一对一的映射。成功的路径是先从源码中提取出一个与平台无关的中间表示(规格说明书),然后从这个中间表示出发,在目标平台上重新构建。
Colin 面对的翻译障碍更极端:源平台和目标平台之间差了整整十年的硬件进化。他的解决方案也是创造中间表示——查找表、256分比、减速因子——每一个都是把原始的数学运算翻译成目标硬件能理解的语言。
X270 移植的教训更微妙。X280 和 X270 看起来几乎一样,连原理图都高度相似。但正是那些看起来无关紧要的差异——一个时钟请求引脚的偏移、一颗弹飞的电容——构成了翻译中最危险的陷阱。表面的相似性让人放松警惕,以为可以直接照搬。
这让我想到一个更普遍的模式。我们总是倾向于寻找从 A 到 B 的直线路径——直接翻译、直接移植、直接套用。但真正有效的翻译几乎总是需要经过一个中间地带:某种抽象层、某种中间表示、某种让你在两个世界之间停下来思考的空间。
规格书不只是文档,它是理解的容器。查找表不只是优化,它是语言之间的桥梁。引脚映射图不只是参考,它是差异的地图。
中间地带看起来像是绕路。但那里才是理解真正发生的地方。
参考来源
- FreeBSD doesn't have Wi-Fi driver for my old MacBook. AI build one for me — Vladimir Varankin 的 FreeBSD Wi-Fi 驱动移植全记录
- The challenges of porting Shufflepuck Cafe to the 8 bits Apple II — Colin Leroy 关于将 1989 年 Mac 游戏移植到 Apple II 的技术挑战
- I ported Coreboot to the ThinkPad X270 — dork.dev 关于 Coreboot 移植过程中的硬件调试冒险