案例 · 卷积码 FEC

AI 实现 Viterbi 译码器的 FPGA 资源优化

一台生成好的译码器,交给 AI 去缩小它的 FPGA 占用。AI 把逻辑砍掉约 65%, 又靠把微架构搭对,守住了满速时钟。

AlgoSilicon 工程团队 · 2026

软判决 Viterbi 译码器,是几乎每一条 Wi-Fi、LTE 与卫星链路里的前向纠错。真正难的不是译码, 是怎么把它塞进一颗便宜的小 FPGA,或者在一颗芯片上多塞几路。说到底,这是一个 FPGA 资源优化问题: 在够用的前提下,尽量少花查找表、触发器和 Block RAM。这一篇,讲的是把这个问题交给 AI 来做。

这台译码器,先由我们的"算法到硅"流程从 Python 算法生成成 Verilog。接下来 AI 在它上面跑的, 就是一个 FPGA 工程师会跑的优化循环:读利用率和时序报告,挑一个杠杆,量结果,分清对错,认死路, 再把每一次改动都逐比特验回去。

Viterbi 译码器到底在做什么

先把它讲清楚,不然后面省的是什么、难在哪,都说不明白。想象一张分层的路网图:每一层有若干个路口, 你要找一条从头走到尾、总代价最小的路。每个路口只留下"到这里最划算的那条进来的路",其它的当场扔掉。 走到终点,再顺着这些留下来的路倒着走回去,整条最优路径就读出来了。Viterbi 干的就是这件事。

放回通信里:卷积码在发送端给每个比特掺进冗余,接收端拿到的是一串带噪声的软采样。译码器要从这串噪声里 反推出最可能被发出去的那一串比特,这叫最大似然译码。

那张"路网"叫网格(trellis)。约束长度 K=7,就是 64 个状态、64 个路口。每一拍,每个状态都做一次 加-比-选(ACS):把分支度量加上去,比较两条汇入的路径,留下更优的那条,记下选了谁。一拍下来, 就是 64 个 ACS 蝶形加 64 个判决。

每一拍"选了谁"都要存起来。攒够一个窗口(大约 5×(K-1) 拍)之后,从当前最优状态沿着这些选择往回走 这段窗口,就把译出来的比特一个一个读出来。这一步叫回溯(traceback)。

网格上的状态随时间展开,标出最优幸存路径与回溯方向;下方是加-比-选蝶形:两个路径度量各加分支度量,比较留更小的作为新路径度量并给出判决位
上:网格与回溯;下:每个状态、每一拍跑的加-比-选。

为什么省资源这么难

最直白的做法,是给 64 个状态各造一套 ACS 引擎,64 套并排铺开、一拍算完。又快又简单,但又大又费。 更别扭的是,它大多数时候在空转:应用要的吞吐,远低于 FPGA 跑得动的时钟。

更硬的一道坎在 ACS 本身。新的路径度量,要用到上一拍刚算出来的那一个,这是一个反馈环(recurrence)。 反馈环的麻烦在于:你没法靠加流水线把一条慢路径切短,因为下一拍就要用这一拍的结果,硬插一级寄存器 只会让它转得更慢。所以"折叠能省面积"和"折叠之后还能不能守住时钟",根本是两回事,这正是这件事难的地方。

幸存路径和回溯还要占内存,而且每拍要并行读出一大片路径度量,读端口的压力是实打实的成本。

上:64 套 ACS 引擎并行,又大又只用到约三分之一,因为要的吞吐远低于时钟;下:ACS 反馈环,新路径度量依赖上一拍,往环里插流水寄存器只会让它转得更慢
上:64 套并行引擎,大多数时候空转。下:ACS 是一个反馈环,加流水寄存器也切不短。

那为什么还敢折?因为应用根本不需要满速。802.11a 的最高数据率也就 54 Mbps,而一个满速 Viterbi 在 160 MHz 上 每拍出一个比特,差不多 160 Mbps,比标准要的快了将近三倍。这多出来的时钟就是机会:把计算分时复用, 让一套引擎跑几拍、轮流算完所有状态,而不是铺成满并行的一大片。只要吞吐还在 54 Mbps 之上,省下的全是面积。 难点只剩一个:折下去的同时,能不能不丢时钟。

AI 的第一个杠杆:折叠

折叠就是这种分时复用:把一套加-比-选运算引擎分几拍轮流复用,而不是为每个网格状态各造一套。AI 一折, 面积就掉下来:在一颗低成本的 Zynq-7010 上,K=7 的核从折 1 到折 8、查找表从 1,918 降到 681,省下约 65%。

K=7 的核在 Zynq-7010 上从折 1 到折 8,查找表从 1,918 降到 681,约砍掉 65%,而时钟一路守在 147 到 160 MHz,二折守住满速 160
AI 折叠:逻辑砍掉约 65%,时钟守住。折叠花的是面积,不是时钟。

但 AI 顺手量了一下时钟,发现掉了。它没有停在这。

AI 的诊断:折叠不等于掉时钟

AI 翻到那条关键路径,把掉的时钟定位清楚:跟折叠本身关系不大,是读取的微架构没搭对。折叠之后, 每一拍要读分数存储里不同的一片,最顺手的做法是用相位计数器去索引一个多路选择器, 可这个相位计数器就压在了通往反馈环的读取路径上,把时钟卡住了。

改之前相位计数器索引路径度量读取(一个多路选择器),把时钟卡在 147 MHz;改之后固定抽头加每相位旋转的 bank,把相位计数器从读取路径上拿走,到 160 MHz
同一个路径度量存储,只改读取方式。左边相位计数器索引读取、卡住时钟,右边固定抽头加旋转的 bank 把它挪开。

问题不在折叠,在这个读取怎么搭。换个搭法,时钟就回来了。

AI 换上对的微架构

AI 把读取改成旋转方式:读一个永远不动的固定抽头,让 bank 每相位自己旋转一格,把下一片转到面前。 相位计数器从那条很宽的读取路径上撤了下来,只去选分支度量。AI 再量一遍,同样是二折,从 147 提到约 160 MHz, 逻辑面积持平,触发器还少了几个。

整条优化路上,结构性的微架构改动把折叠后的时钟重新拉回约 160 MHz,单靠折叠不行
同一条路上,换对微架构把时钟抬了回来,单靠折叠不行。

背后有一条普适道理:折叠任何一个二输入蝶形,都会逼出一次躲不掉的数据重排。能选的只是在哪儿为它买单, AI 把它放在了免费的地方。

AI 还动了几个微架构杠杆

把折叠做高效,靠的不是一招,是 AI 一路试出来的一串微架构选择:拆掉共享的大选择器、改成每路本地选择, 扇出塌下来,深码率下折 8 一下提了 23%;把挡在反馈环前的分支度量加法树流水化挪出去,深码率回到满速档; 再在低码率下收窄内部定点位数,比折叠更省面积,还顺手把时钟抬高。

三个微架构杠杆:每路分支度量选择(扇出塌下来,深码率折 8 +23%)、分支度量流水化(把加法树挪出反馈环,深码率回满速)、位宽收窄(更少的位、更短的路径,-12% LUT 还把时钟抬高)
另外三个微架构杠杆,各自的实测收益。

AI 也会认死路

AI 还试过第三种方案:双缓冲乒乓。真做出来、综合、布局布线,不是嘴上说说。结果比旋转读取还更大,慢了约 27 MHz, 于是 AI 回退了它。这个负面结果不是浪费,正是它让最终的数字可信。AI 在这里像个工程师,不是一个代码生成器。

一次重排,三个买单的地方:索引读取(面积最省,折 4 及以上取胜)、旋转读(折 2 免费、已部署之选)、双缓冲乒乓(重排加全宽 mux,又大又慢,实测慢约 27 MHz,已回退)
把死路放回全局:折叠的重排有三个买单的地方,双缓冲乒乓买得最贵、又从未取胜。

一份资源菜单,落地在真接收机里

AI 产出的不是一个点,是一份资源菜单:折叠越浅越快越大,折叠越深越小越慢。802.11a 要的 54 Mbps, 折 1、折 2 都越得过;折 4、折 8 更小更慢,留给那些慢速、可以在一颗芯片上多塞几路的信道。每个点都验证过。

同一台 K=7 译码器在 Zynq-7010 上铺成一份逻辑对吞吐的资源菜单:折 1 为 1,918 LUT / 160 Mbps,折 2 为 1,368 / 80,折 4 为 980 / 37,折 8 为 681 / 18,折 1 与折 2 在 54 Mbps 线之上
同一台译码器,一份资源菜单。折 1、折 2 越过 54 Mbps 线;折 4、折 8 留给慢速、可多塞几路的信道。

部署的二折版被放进一台完整的 802.11a 接收机,喂的是原始采样,八种调制编码方式全部零比特错误地恢复出了载荷。

这就是怎么用 AI 做资源优化

落地的配置很小、也很确切:一台二折译码器守住了完整引擎的时钟,只占折叠引擎的面积,跑在一颗低成本的 Zynq-7010 上,1,368 个查找表、零 DSP。比这台译码器更值钱的,是这套循环:AI 读懂物理约束, 把掉时钟分清是折叠还是微架构;把那次躲不掉的重排放到免费的地方;做出、量过、再回退一条死路; 并把每一次改动都对着参考逐比特验证。真正能复用的,是这套循环,不是这一台译码器。

AI 资源优化循环:读利用率和时序报告、定位瓶颈、换对的微架构、逐比特验证,再换下一个杠杆继续循环
真正能复用的:读报告、定位瓶颈、换微架构、逐比特验证,再循环。

更完整的技术细节,包括 RTL 微架构图、跨约束长度与码率的实测折叠/时钟/资源表、以及验证链路, 见技术报告(英文)。

了解 Viterbi 译码器 IP

跨约束长度、码率与折叠因子的实测时钟与资源数据都在产品页上。或者直接和我们谈一台为你的链路预算定制的译码器。

Viterbi 译码器产品