先说下LFSR,中文叫线性反馈移位寄存器,英文的全称是了linear feedback shift register,这个其实是由SR—>FSR—>LFSR逐步发展出来的,SR也就是移位寄存器,这个我们都很熟悉,串并转换里经常用,网上找个图:



也就是数据挨个从左到右(从右到左)的移出,右边移出一位左边就空出一位,空出的这一位大部分情况下默认补0,如果这一位我们通过某个函数来计算,这个函数的输入就是寄存器组中已有的这些数,函数的输出填到左边空出的这一位,通过这种方式我们就进一步得到了反馈寄存器,也就是FSR,它可以源源不断的进行输出,贴个图:



再进一步,如果这个反馈函数,是一个线性的函数呢?这里略微补充下线性函数的定义,就是满足f(ax+by)=af(x)+bf(y)这样的函数,典型的就是f=ax+b,而LFSR的反馈函数定义如下:



其中的加法是异或(XOR),乘法是与(AND),Ifsr的反馈函数也满足:



所以LFSR是一个线性反馈移位寄存器,上面式子:\(s_{n+k}=c_1 s_{n+k-1} \oplus c_2 s_{n+k-2} \oplus \cdots \oplus c_k s_n\),\(c_1\) \(c_2\)...我们称为系数,值为0或者为1,为1就是表示该位置的值参与计算,参与计算的位也叫抽头,相应的为0就是不参与计算。而寄存器里最开始的的所有值我们称为初始值,也叫种子,基于抽头,我们可以得出一个叫反馈多项式的东西,它就是根据抽头所在的寄存器位置,给多项式定义幂次,举个例子:



上图的LFSR级数为16,抽头位置为16 14 13 11,注意图里的位置1并不表示抽头,而是说这里是一个输入,是之前那些值经过反馈函数给返回来的,因为这是反馈移位寄存器,这一位必须要有,所以必须为1,你也可以理解为X^0,也就是1,数学上表达就是:

1*X^16 + 0*X^15 + 1*X^14 + 1*X^13 + 0*X^12 + 1*X^11 + 0*X^10 + 0*X^9 + 0*X^8 + 0*X^7 + 0*X^6 + 0*X^5 + 0*X^4 + 0*X^3 + 0*X^2 + 0*X^1 + X^0

等价于:

X^16 + X^14 + X^13 + X^11 + 1

对应的2进制就是:

10110100000000001

一共17位,但是LFSR的表达式最高位都为1,默认省略不写,也就是:

0110100000000001

对应的16进制值是0x6801

LFSR的基础介绍的差不多了,我们再说LFSR常见的两种形式:

  • Fibonacci LFSRs 斐波那契型
  • Galois LFSRs 伽罗瓦型

    Fibonacci LFSRs就是多到1,就是多个抽头位置的值一起异或,生成的结果给到左边空出的那一位,而Galois LFSRs则是抽头位置前一级寄存器的值和输出寄存器的值异或后给到抽头位置的寄存器,贴张图:

好,介绍到这里,我们就开始说CRC,CRC, 全称Cyclic Redundancy Check,中文循环冗余校验,它的原理其实是模2除法的运算,模2除法就是异或运算,要校验的原始数据就是被除数,除数就是一组选定的特殊数据,也就是多项式的2进制表达式,它俩除下来的余数补到原始数据的后面,而接收端收到数据后,会再去执行模2的除法,因为余数已经补上去了,所以接收方计算时,应该是正好能整除的,也就是余数为0。举个例子吧:



图里被除数是10000011,除数是1001,多项式就是X^3+1,0x01(最高位默认为1不写),图里我们看到它计算的时候是在原始数据10000011后面补了3个0,因为在多项式除法里,余数的最高次幂一定是小于除数最高次项,除数最高次为3,也就是4位,那余数最高次为2,也就是3位,所以是预留3位。换个角度想,补3个0,也就是把原始数据左移了3位,其实就是给后面把余数补上去时候,预先留的位置,虽然不知道余数是多少,但是余数的位数,一定数小于除数的位数。好,现在我们把余数补上去,再算一遍:



余数正好是0,证明数据没有问题。我们可以找个工具验证一下:



结果和我们的一致,没有问题。

好了说了这么多,那CRC这种模2运算,和LFSR有啥关系?到目前为止,我们看到了LFSR是异或运算,CRC的模2除法也是异或运算,我们回看上面CRC计算步骤时,会发现,除的过程其实就是被除数左移,和除数异或的过程,具体逻辑是,判断被除数MSB(最高位)是否为1,如果是的话就进行异或操作,然后余数左移1位,再在右边补上和原始被除数相对应的位的值,形成新的被除数,如果MSB为0,则直接左移,同样补上原始被除数相对应的位的值,一直到被除数MSB为1为止,前面我们说过多项式最高位一定是1,所以每当我们进行异或操作时,余数的高位一定是0,所以不管怎么说,我们都会左移,也就是每次余数肯定会左移一位,文字描述很繁琐,还是贴个图:



文字描述下上图的计算过程,首先,被除数开始是1000_0011,右边补3个0预留余数位置,除数是1001,当前被除数MSB为1,在第四位商1进行异或,得到余数0001,也就是新的被除数,新的被除数MSB为0(一定为0),继续补数。补上面原始被除数相对应位的数,也就是0,同时左移1位,把为0的MSB给丢掉,这时新的被除数为0010,MSB还不是1,继续操作上一步,得新的被除数0100,还是不行,继续,得1001,这下满足了,就进行异或操作,重复以上部分,最终得余数001,也就是我们想要的结果。这个运算过程,是怎么转化成lfsr的呢,我先贴个图出来:



这个lfsr图,c3 c2 c1 c0其实就是上面我们说lfsr线性函数里的抽头,对应的就是除数1001,最高位寄存器其实就是MSB,当MSB为1时,就进行异或并把值移入LSB寄存器,否则就只是左移没有异或,最终当输入都移完了,寄存里最终的值其实就是余数,也就是我们要的CRC,我们发现其实lfsr寄存器状态并不是每一步和模2除法的余数都能对上,因为模2除法是一次异或4位,lfsr是流水1bit操作的,这里有个很核心的其实我们没有讲,就是为什么crc转换出来的lfsr是张这样的,为什么这样就正好是最后的余数,这个涉及到M位多项式除法运算的计算推导,实话说我自己还没弄懂推导出来,实在是笨和懒了。。。下次再补上。最后再贴几个代码吧:

以下我根据10G eth里的64b66b多项式写的代码,我详细的列出了运算的步骤:

/***************************************************************************
Fibonacci style (example for 64b66b scrambler, 0x8000000001) DIN (LSB first)
|
V
(+)<---------------------------(+)<-----------------------------.
| ^ |
| .----. .----. .----. | .----. .----. .----. |
+->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--'
| '----' '----' '----' '----' '----' '----'
V
DOUT bit width 64 58
value[pos]
data_out[0] = data_in[0] ^ state[57] ^ state[38] mask 000.......001[0] 1[57]0000....1[38].....0
data_out[1] = data_in[1] ^ state[56] ^ state[37] 000......01[1]0 01[56]0000....1[37]....0
data_out[2] = data_in[2] ^ state[55] ^ state[36] 000......1[2]00 001[55]0000....1[36]...0 DIN (LSB first)
|
V
(+)<---------------------------(+)<-----------------------------.
| ^ |
| .----. .----. .----. | .----. .----. .----. |
+->| 57 |->| 56 |->...->| 19 |-+->| 18 |->...->| 1 |->| 0 |--'
| '----' '----' '----' '----' '----' '----'
V
DOUT
bit width 64 58
value[pos]
data_out[0] = data_in[0] ^ state[19] ^ state[0] mask 00.......1[0] 00000....1[19]....1[0]
data_out[1] = data_in[1] ^ state[20] ^ state[1] 00......1[1]0 00000....1[20]....1[1]0
data_out[2] = data_in[2] ^ state[21] ^ state[2] 00......1[2]00 00000....1[21]....1[2]00
.................
data_out[38]= data_in[38] ^ state[57] ^ state[38] 00..1[38]..000 1[57]0000...1[38]...000 data_out[39]= data_in[39] ^ data_out[0] ^ state[39] = data_in[39] ^ data_in[0] ^ state[19] ^ state[0] ^ state[39] 00..1[39]..001[0] 00000...1[39]..1[19]..001[0] ***************************************************************************/ module eth10G_64b66b_scrambler (
input wire [63:0] data_in,
input wire [57:0] state_in,
output reg [63:0] data_out,
output reg [57:0] state_out
); localparam POLY = 58'h8000000001;//x58 + x39 + 1 // integer i;
// always @(*) begin
// state_out = state_in;
// for(i = 0; i < 64; i = i + 1) begin
// state_out = {state_out[56:0], data_in[i] ^ state_out[57] ^ state_out[38]};
// data_out[i] = state_out[0];
// end
// end integer i;
always @(*) begin
state_out = state_in;
for(i = 0; i < 64; i = i + 1) begin
state_out = {data_in[i] ^ state_out[0] ^ state_out[19],state_out[57:1]};
data_out[i] = state_out[57];
end
end endmodule

下面这个是解扰:

/*****************************************************************************
Fibonacci feed-forward style (example for 64b66b descrambler, 0x8000000001) DIN (LSB first)
|
| .----. .----. .----. .----. .----. .----.
+->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--.
| '----' '----' '----' | '----' '----' '----' |
| V |
(+)<---------------------------(+)------------------------------'
|
V
DOUT DIN (LSB first)
|
| .----. .----. .----. .----. .----. .----.
+->| 57 |->| 56 |->...->| 19 |-+->| 18 |->...->| 1 |->| 0 |--.
| '----' '----' '----' | '----' '----' '----' |
| V |
(+)<---------------------------(+)------------------------------'
|
V
DOUT bit width 64 58
value[pos]
data_out[0] = data_in[0] ^ state[19] ^ state[0] mask 00.......1[0] 00000....1[19]....1[0]
data_out[1] = data_in[1] ^ state[20] ^ state[1] 00......1[1]0 00000....1[20]....1[1]0
data_out[2] = data_in[2] ^ state[21] ^ state[2] 00......1[2]00 00000....1[21]....1[2]00
.................
data_out[38]= data_in[38] ^ state[57] ^ state[38] 00..1[38]..000 1[57]0000...1[38]...000 data_out[39]= data_in[39] ^ data_in[0] ^ state[39] = 00..1[39]..001[0] 00000...1[39]..00
data_out[40]= data_in[40] ^ data_in[1] ^ state[40] = 00..1[40]..01[1]0 00000...1[39]..00
...........
data_out[57]= data_in[57] ^ data_in[18] ^ state[57] = 1[57]0..1[18]..000 1[57]0000.....00
data_out[58]= data_in[58] ^ data_in[19] ^ data_in[0] = 1[58]0..1[19]..001[0] 00000.....00 从这里开始,state不参与了,也就是说state的掩码都是0
...........
data_out[63]= data_in[63] ^ data_in[24] ^ data_in[5] = 1[63]0..1[24]..1[5]00000 00000.....00 state[0] = state[1];
state[1] = state[2];
state[2] = state[3];
.....
state[56] = state[57];
state[57] = data_in[0]; *****************************************************************************/ module eth10G_64b66b_descrambler (
input wire [63:0] data_in,
input wire [57:0] state_in,
output reg [63:0] data_out,
output reg [57:0] state_out
); localparam POLY = 58'h8000000001;//x58 + x39 + 1 integer i;
always @(*) begin
state_out = state_in;
for(i = 0; i < 64; i = i + 1) begin
data_out[i] = data_in[i] ^ state_out[19] ^ state_out[0];
state_out = {data_in[i], state_out[57:1]};
end
end endmodule

使用for语句,代码看着就很简单。

同理,CRC32的运算也是类似:

module crc32(
input wire [63:0] data_in,
input wire [31:0] state_in,
// output wire [63:0] data_out,
output wire [31:0] crc_out
);
//x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
localparam POLY = 32'hEDB88320; //reverse 32'h04c11db7
function [31:0] state_out (input data, input [31:0] state_in);
integer i;
begin
for (i = 31; i >= 0; i = i - 1) begin
if (i==31)
state_out[i] = data ^ state_in[0];
else if (POLY[i])
state_out[i] = state_out[31] ^ state_in[i+1];
else
state_out[i] = state_in[i+1];
end
end
endfunction integer i;
reg [31:0] state_nxt;
assign crc_out = state_nxt;
always @(*) begin
state_nxt = state_in;
for(i = 0; i < 64; i = i + 1) begin
state_nxt = state_out (data_in[i], state_nxt);
end
end endmodule

它实现了64位数据的crc32计算,其实就是把1位的运算展开迭代了64次,也可以理解为串转并的过程,代价就是当进数位宽很大时,组合逻辑过长,频率高时序就过不了,lfsr常见的地方是生成随机序列,还有一些校验的地方,比如xilinx一些通信类的IP,example design里会用到PRBS,这个叫pseudo—Random Binary Sequence,叫伪随机2进制序列,这个其实就是基于LFSR做的。

参:

CRC和LFSR的更多相关文章

  1. BLE直接Data channel抓包方法汇总

    之前一致在做一些有关与BLE安全研究的“基础设施建设”工作,我们知道,在BLE进入跳频之后,所有的固定标志都会消失,但是是不是意味着没办法了?不是的.我会提出一些恢复出来的方法. 首先,前导码分析,B ...

  2. Verilog语言实现并行(循环冗余码)CRC校验

    1 前言 (1)    什么是CRC校验? CRC即循环冗余校验码:是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定.循环冗余检查(CRC)是一种数据传输检错功能, ...

  3. FPGA实现CRC编码

    首先CRC应用的主要场景: 在数据通信中要求数据的高度可靠性,但实际上由于信道不理想或者噪声干扰都会导致数据的误码率 那么对于信道不理想产生的影响可以用均衡的方法进行改善或者消除,而噪声干扰的数据误码 ...

  4. CRC校验原理和verilog实现方法(二)

    1 前言 在 前面的博客  CRC校验原理和verilog实现方法(一)  中,介绍了CRC校验的原理和手动计算过程.本文说一下我在学习CRC校验FPGA实现的一点心得体会. 2 线性反馈移位寄存器 ...

  5. CRC、反码求和校验 原理分析

    3月份开始从客户端转后台,算是幸运的进入全栈工程师的修炼阶段.这段时间一边是老项目的客户端加服务器两边的维护和交接,一边是新项目加加加班赶工,期间最长经历了连续工作三天只睡了四五个小时的煎熬,人生也算 ...

  6. 循环冗余码crc

    待编码的有效信息组多项式:M(x) 生成多项式(产生校验码的多项式):G(x) 余数多项式:R(x) 商:Q(x) 生成多项式是四次的,所以某个多项式除以生成多项式的余式肯定是三次的,所以要加四位00 ...

  7. CRC循环冗余校验码总结(转)

    转自 http://blog.csdn.net/u012993936/article/details/45337069 一.CRC简介 先在此说明下什么是CRC:循环冗余码校验 英文名称为Cyclic ...

  8. 文档:网络通讯包结构(crc校验,加解密)

    一直想把这个流程整理一下. 包结构: 包 对(datacrc+protoID+dataSize)组成的byte[] 进行crc计算而得到 对(数据内容)进行crc计算而得到 协议号 数据内容的字节长度 ...

  9. 报文解析及CRC类

    /// <summary> /// 报文解析转换类 /// </summary> public class DatagramConvert { public static En ...

  10. 校验码(海明校验,CRC冗余校验,奇偶校验)

    循环冗余校验码 CRC码利用生成多项式为k个数据位产生r个校验位进行编码,其编码长度为n=k+r所以又称 (n,k)码. CRC码广泛应用于数据通信领域和磁介质存储系统中. CRC理论非常复杂,一般书 ...

随机推荐

  1. 新一代 Kaldi: 支持 JavaScript 进行本地语音识别和语音合成啦!

    简介 新一代 Kaldi 部署框架 sherpa-onnx 支持的编程语言 API 大家庭中, 最近增加了一个新成员: JavaScript. 为了方便大家查看,我们把目前所有支持的编程语言汇总成如下 ...

  2. 二叉树 红黑树 B树 B+树 理解

    小史是一个应届生,虽然学的是电子专业,但是自己业余时间看了很多互联网与编程方面的书,一心想进 BAT 互联网公司. 话说两个多月前,小史通过了 A 厂的一面,两个多月后的今天,小史终于等到了 A 厂的 ...

  3. MySQL数据库Binlog解析工具--binlog2sql

    概述作为DBA,binlog2sql是一项必须掌握的工具.binlog2sql是一个开源的Python开发的MySQL Binlog解析工具,能够将Binlog解析为原始的SQL,也支持将Binlog ...

  4. JDK 17 新特性

    同学们,Oracle 宣布,从 JDK 17 开始,后面的 JDK 都全部免费提供啦!!! 是的,你没有看错,Oracle 这次良心了,发大招了,Java 17+ 可以免费使用了,包括商用,更详细的条 ...

  5. GB28181实现H265 H264摄像头 Web端无插件直播

    介绍 目前安防监控行业,基本所有的摄像头都支持H264编码,但是已经有部分摄像头开始支持H265,并且支持H265的摄像机已经越来越多.H265相比H264有着很多优势,是压缩更高,网络传输消耗的带宽 ...

  6. linux之makefile

    目录 linux之makefile 模板 每个.c编译成.o再链接在一起 每个.c文件各自编译链接成可执行文件 linux之makefile 学习 https://www.cnblogs.com/pa ...

  7. iOS5.2.1被拒

    转载请注明出处!!! 注明:应用已经上线,正在和一些已经上架的人探讨那些文件是必需的. 自从十九大之后,p2p类应用审核越发严格.经常出现好久不能上线,一直被拒的现象.近期我们公司上架一款新的应用就出 ...

  8. 智投助手发布更新v0

    智投助手发布更新v0.0.2 本次更新的主要内容有 在"数据维护"界面中添加了"打开数据目录"按钮,点击后可以打开数据文件所在的位置,方便备份数据. 在&quo ...

  9. 产品二期,从GPT5规划开始

    背景简介 楼里App一期开发完成,开始进行二期的网站开发,想以此需求作为驱动,探索整个流程对于人工智能的使用. 从规划和设计开始,一直到二期网站开发完成,所有核心环节和任务都先参考主流大模型和AI工具 ...

  10. 不卷参数卷应用,OPPO用致善定义AI手机

    24年,全球智能手机会有一个转折点:市场整体大盘温和回暖,华为强势回归,市场格局很有可能会被改写.更重要的是,AI大模型将在智能终端落地,这将会开启智能手机的新产业周期:变数增加. 什么样的手机,能成 ...