利用Xilinx HLS实现LDPC译码器
1. 概述
采用Xilinx HLS快速实现的部分并行,全流水的LDPC译码器。
- 环境:Vivado HLS 2018.2
- 码字:IEEE 802.16e 2/3A
- 算法:Min-Sum Algorithm
- 代码:https://github.com/cea-wind/hls_ldpc_dec/
- 器件:xc7k160
使用方法:
1. 从GitHub上clone代码
2. 在终端运行命令
vivado_hls -f run_hls.tcl
3. 打开vivado hls GUI,找到生成的工程,打开即可
2. 码字和算法
为简单起见,采用了IEEE 802.16e标准中的2/3A码率的码字,并选择1536的码长作为具体的验证举例。该LDPC码是准循环码,每个循环子矩阵的行重为1。其校验矩阵可以用母矩阵表示为
译码算法原理可参考https://www.cnblogs.com/sea-wind2/p/4282640.html,或者直接参考其实现https://www.cnblogs.com/sea-wind2/p/4268408.html。(写得均不好,不建议参考)
译码算法采用修正因子为0.8125的最小和算法,为了简便起见,没有设置满足校验方程跳出的判断。具体可参考Git repo中的MATLAB代码,但该MATLAB代码并没有做量化。
3. 设计思路
为了体现FPGA的优势,此处采用了部分并行全流水的设计。其中部分并行指设计同时开始多个行更新和列更新,全流水指行更新和列更新采用的流水线设计可以做到一个时钟周期完成一行或一列数据的更新。
校验矩阵中有80个不为0的循环矩阵,将其分别存储在不同的BRAM上,一个周期内可访问80个循环矩阵中的任意一个数据。因此在进行行更新时,可以同时更新8行,列更新时,可以同时更新24列。按此进行并行设计。
行更新采用了全流水设计,其核心在于求最小值和次小值,可以参考https://www.cnblogs.com/sea-wind/p/8384596.html的内容。实现结构类似
列更新采用了全流水设计,利用加法即可,较为简单。
由于之前写过一份FPGA代码,因此行更新和列更新的HLS代码Verilog风格较重。
4. 分析
4.1 Simulation
通过Run C/RTL cosimulaiton,可以校验生成的RTL代码仿真是否正确。校验得知RTL simulation结果和C结果一致,在main函数指定的case下仿真通过。仿真过程中可以dump信号波形,完成仿真后可打开波形进行进一步查看。
4.2 Perference
HLS结果如下图所示,预计频率在250MHz以上。完一次译码(50次迭代)需要10020个周期。
具体耗时细节如下图,读取解调后软信息需要约1539个周期,输出结果需要约1026个周期,译码迭代需要7450个周期。
行更新需要的理论时间为64个clk,列更新也是如此。因此完成一次行列更新需要128个clock(行列不做流水的理论下限),综合结果表示latency为149个周期,效率已经极高了。关于数据读取和写回,由于设计中没有做特别优化,此处不做考虑。
上述结果表明,HLS综合结果从效率和频率上看都极其优异。
4.3 Resource
(似乎2018.2的综合策略发生了变化,利用了大量register且资源评估时未作优化,因此该阶段资源评估不准确,采用2016.3结果)
信息的存储占用了大量的资源,共有80块用于存储中间信息,24块存储输入的对数似然比,结果和分析一致。而行更新和列更新消耗了大量的逻辑资源。
行更新和列更新具体资源细节如下图所示
以列更新为例,列更新过程中,列重为3的更新有1个4-in的11bit加法,3个2-in的8bit减法,6次比较和3个3-to-1MUX。预计占用资源为3×11+3×8+6×3+3×8=97个LUT,加上地址控制等,其综合结果资源耗费合理。
因此HLS的综合结果资源占用也在合理范围内。
5. 优化
- 优化输入输出设计
- 加入停止条件
- 优化bram的使用,包括输入信息的存储和输出信息的存储
- 已经有两年没有接触LDPC了,Xilinx HLS也基本没用过,如有建议还请留言指正