案例 · 卷积码 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 一折, 面积就掉下来:在一颗低成本的 Zynq-7010 上,K=7 的核从折 1 到折 8、查找表从 1,919 降到 681,省下约 65%。

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

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

时钟到底掉在哪里

翻到那条关键路径,把掉的时钟定位清楚:跟折叠本身关系不大,而在于折叠之后共享的分数存储怎么寻址。在最顺手的搭法里,每一拍的选择压在了通往反馈环的关键读取路径上,把时钟卡住了。

改之前:朴素的每拍存储读取把时钟卡住;改之后:经过重构,把每拍的选择挪出关键读取路径,时钟回到满速
同一块分数存储,两种寻址方式。左边的朴素读取卡住时钟,右边经过重构,把每拍的选择挪出关键读取路径。

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

重构以找回时钟

对存储的访问做了一次结构性改动,把每拍的选择挪出那条很宽的读取路径、也挪出了反馈环。同样是二折再量一遍,时钟回到满速,从 147 提到约 160 MHz,逻辑面积基本持平。

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

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

更多结构性改进

把折叠做高效不止一招。后面还有一串结构性改进,每一项都先实测、划算才保留:降低度量选择的扇出、把分支度量的计算挪出反馈环、收窄内部定点位数。在低码率下,这些改进合起来比折叠本身更省面积,还顺手把时钟抬高。

更多结构性改进,每一项都先实测、划算才保留:降低度量选择的扇出、把分支度量的计算挪出反馈环、收窄内部定点位数
更多结构性改进,每一项都先实测再决定保留。

一个被舍弃的方案

AI 还把一个备选方案完整做了出来:综合、布局布线,不是嘴上说说。结果比选定的方案又大又慢,于是回退了它。这个负面结果不是浪费,正是它让最终的数字可信。AI 在这里像个工程师,不是一个代码生成器。

一次数据重排,几种吸收它的方式:一种面积最省、在更深的折叠档取胜,一种在二折免费、就是已部署之选,还有一种代价最高、又从未取胜,已回退
把被舍弃的方案放回全局:在吸收折叠带来的数据重排的几种方式里,这一种代价最高、又从未取胜。

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

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

同一台 K=7 译码器在 Zynq-7010 上铺成一份逻辑对吞吐的资源菜单:折 1 为 1,919 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 接收机,喂的是原始采样,八种调制编码方式全部零比特错误地恢复出了载荷。

可复用的方法

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

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

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

Viterbi 译码器产品