FPGA教程系列-CRC硬件加速原理深度解析

FPGA教程系列-CRC硬件加速原理深度解析

CRC硬件加速原理

依然开头放上原文,https://mp.weixin.qq.com/s/NGQEtskEjkjMzhiwMcY7Sw

表驱动

应该跟查找表差不多,从表中读出数据。

位到字节的转换,简单的想就是把一位看成一个字节,虽然是个类比的办法,还是不太容易理解,需要反复的琢磨。

重点是:

  • 新的最高位只跟当前最高字节的前两位有关系
  • 再下一个最高位只跟当前最高字节的前三位有关系
  • 总之,第 k 次循环的最高位,只取决于当前最高字节的前 k 位

换一句话说,如果以前8位一个字节来输入的话,进行8次"长除法"的运算结果,只跟这8位有关,那么,根据这8位做出一个查找表,包含了所有的情况,也就是256个结果,可以根据这8位是什么快速的查找结果,然后进行异或,相当于速度提升了8倍。

当然,上述情况成立的前提是XOR 可以提前合并。

不要在那傻傻地循环8次了。因为最高那个字节已经包含了接下来8步所有的操作指令。我们直接看着这个字节,一步到位,把这一连串的XOR变换一次性加上去。

verilog 复制代码
原始状态:
+----------+------------------------+
| Top Byte |      Remaining 24 bits |
+----+-----+-----------+------------+
     |                 |
     | 1. Top Byte     | 2. 剩下的字节左移
     |    只用来       |    空出右边位置
     |    查索引       |
     v                 v
+----------+      +------------------------+----------+
|   TABLE  |      | Remaining 24 bits      | New Data |  <-- 新进来的字节
+----+-----+      +-----------+------------+-----+----+
     |                        |                  ^
     | 查出 "超级修正值"        |                  |
     +------------------------+                  |
             |                                   |
             v            (进行 XOR)              |
      +------------------------------------------+
      |        FINAL REGISTER RESULT             |
      +------------------------------------------+

CRC硬件算法优化

1、结尾 :零字节本身异或进寄存器(X ^ 0 = X)不会改变值,它们唯一的作用是提供"移位次数",把真实数据的最后几位"推"到最高字节去查表。

2、开头 :开头几个字节主要是为了把初始数据装进寄存器。如果寄存器本来为零,就是简单的移入;如果寄存器非零,初始值会在装入过程中"混合"(异或)一下这些字节,但核心动作还是装入。

数学上的优化:

verilog 复制代码
r = ((r << 8) | *p++) ^ t[(r >> 24) & 0xFF];
可以转换为:
r = (r << 8) ^ (*p++) ^ t[(r >> 24) & 0xFF]; //本质上就是全异或操作
最终转换为
r=0; while (len--) r = (r<<8) ^ t[(r >> 24) ^ *p++];

既然数据最终都要异或到最高位才能决定查表索引,不如提前把当前输入的数据字节(*p)与寄存器的最高字节(r >> 24)进行异或

文章里说两个表,应该是在时间维度上的不一样,真实物理世界上应该是一个表。

  • 旧算法(Augmented) :数据D从最右边(第 0 字节)进入。

    • 它要经过 4 次移位才能到达最左边(第 3 字节)去触发计算。
    • 旧表处理的是"位于最左边"的情况。
  • 新算法(Direct) :数据D刚进来,还没移位呢,我们就想直接查表算它的最终影响。

    • 如果你想建立一个表,由"位于最右边的数据D"直接查出"它在 4 次移位后对寄存器的贡献"。
    • 那么这个表的内容,确实应该等于 Standard_Table[D] 再经过某种反向推导或者预移位。
    • 在这个理论视角下,表是不一样的。

原来的算法是"人(数据)走到了门口(最高位)才查票(查表)";现在的算法是"人还在最后排队,但我把他的票直接传送到门口,和正在出门的人的票混在一起查"。检票处的数据库(表)没变,只是送票的方式变了。

CRC的硬件特性

总体来说,没有太多的疑问。

反射,是为了为了迁就硬件,软件实现通常不选择"把每个输入字节都翻转一遍"(效率太低),而是选择"翻转整个世界"。

  • 初始值(Init Value)

    • 通常设为 0xFFFFFFFF 而不是 0。
    • 原因:如果初始值为 0,那么消息开头的一连串 0 字节不会让寄存器发生变化(因为 0 ^ 0 = 0)。设置非零初始值可以消除这个"盲区",让开头的 0 也能被检测到。
  • 最终异或(Final XOR Value)

    • 在计算结束后,将结果再异或一个常数(如 0xFFFFFFFF)。
    • 原因:历史遗留的标准约定,或者是为了取反结果。

Rocksoft™ 模型

参数 含义 示例 (CRC-32 标准)
WIDTH 位宽 32
POLY 生成多项式 (省略最高位) 04C11DB7
INIT 寄存器初始值 FFFFFFFF
REFIN 输入字节是否反射 True (适配硬件)
REFOUT 输出结果是否反射 True
XOROUT 结果最终异或值 FFFFFFFF
CHECK 校验值 (输入"123456789"的结果) CBF43926

具体还是以原文为主,这里主要是对原文的一些个人理解,也许有失偏颇,但暂时也只能理解到这里了。

相关推荐
SunkingYang2 天前
QT程序怎么接收MFC通过sendmessage发送的信号
qt·mfc·信号·事件·sendmessage·接收消息
悄悄敲敲敲10 天前
Linux:信号(二)
linux·操作系统·信号
Wishell201519 天前
FPGA教程系列-8B10B编码
信号
Wishell201522 天前
FPGA教程系列-CRC校验初识
信号
赋能大师兄1 个月前
物理信道、信号、映射的介绍
信号·映射·物理信道
阿巴~阿巴~2 个月前
Linux 信号的保存机制
linux·服务器·信号·信号集·信号保存
程序猿编码2 个月前
轻量级却实用:sigtrace 如何靠 ptrace 实现 Linux 信号的捕获与阻断(C/C++代码实现)
linux·c语言·c++·信号·捕获·ptrace
NiKo_W2 个月前
Linux 信号
linux·内核·信号
egoist20233 个月前
[linux仓库]信号快速认识[进程信号·壹]
linux·c语言·信号处理·信号·前后台进程