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

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

相关推荐
Wishell201518 小时前
FPGA教程系列-CRC校验初识
信号
赋能大师兄22 天前
物理信道、信号、映射的介绍
信号·映射·物理信道
阿巴~阿巴~1 个月前
Linux 信号的保存机制
linux·服务器·信号·信号集·信号保存
程序猿编码1 个月前
轻量级却实用:sigtrace 如何靠 ptrace 实现 Linux 信号的捕获与阻断(C/C++代码实现)
linux·c语言·c++·信号·捕获·ptrace
NiKo_W2 个月前
Linux 信号
linux·内核·信号
egoist20232 个月前
[linux仓库]信号快速认识[进程信号·壹]
linux·c语言·信号处理·信号·前后台进程
轩情吖2 个月前
Qt常用控件之QTextEdit
开发语言·c++·qt·信号·qtextedit·多行输入框·桌面级开发
DreamLife☼3 个月前
Qt 中的 Q_OBJECT 宏详解 —— 从源码到底层机制的全面剖析
qt·信号·qml·q_object··rtti·运行时类型信息
yong99903 个月前
MATLAB中对不同类型的雷达信号进行仿真
信号