大家好,欢迎来到IT知识分享网。
目录
理论解读
CRC应用
CRC即循环冗余校验码(Cyclic Redundancy Check):是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。
CRC算法参数解读
- NAME:参数模型名称。
- WIDTH:宽度,即CRC比特数。
- POLY:生成项的简写,以16进制表示。例如:CRC-32即是0x04C11DB7,忽略了最高位的”1″,即完整的生成项是0x104C11DB7。
- INIT:这是算法开始时寄存器(crc)的初始化预置值,十六进制表示。
- REFIN:待测数据的每个字节是否按位反转,True或False。
- REFOUT:在计算后之后,异或输出之前,整个数据是否按位反转,True或False。
- XOROUT:计算结果与此参数异或后得到最终的CRC值。
常见CRC参数模型
设计实战
校招编程题
(2021乐鑫科技数字IC提前批代码编程)
- 用Verilog实现CRC-8的串行计算,G(D)=D8+D2+D+1,计算流程如下图所示:
分类
串行输入、并行计算、串行输出
- 手算
CRC校验码就是两个数相除的余数,而且余数位数要正好比除数少一位,即使MSB为0。
对于数据11’0100’10 01,指定多项式为x8+x2+x+1,则除数为1_0000_0111。首先要将数据左移8bit(校验码的位数)
- 计算器
- 代码
module crc_8( input clk, input rst, input data_in, input data_valid, input crc_start, output reg crc_out, output reg crc_valid ); reg [7:0] lfsr_q; reg [7:0] lfsr_c; always @(*)begin lfsr_c[0] = lfsr_q[7] ^ data_in; lfsr_c[1] = lfsr_q[0] ^ lfsr_q[7] ^ data_in; lfsr_c[2] = lfsr_q[1] ^ lfsr_q[7] ^ data_in; lfsr_c[3] = lfsr_q[2]; lfsr_c[4] = lfsr_q[3]; lfsr_c[5] = lfsr_q[4]; lfsr_c[6] = lfsr_q[5]; lfsr_c[7] = lfsr_q[6]; end always @ (posedge clk)begin if(rst) begin lfsr_q <= {
8{
1'b0}}; end else begin lfsr_q <= data_valid ? lfsr_c : lfsr_q; end end reg [2:0] count; always @ (posedge clk) begin if(rst) begin crc_out <= 0; count <= 0; end else begin if(data_valid) begin crc_out <= data_in; crc_valid <= 1'b0; end else if(crc_start)begin count <= count + 1'b1; crc_out <= lfsr_q[7-count]; crc_valid <= 1'b1; end else begin crc_valid <= 1'b0; end end end endmodule
- 仿真结果
串行计算、串行输出(线性移位寄存器)
- 代码
module CRC_8( input clk, input rst, input data_in, input data_valid, input crc_start, output reg crc_out, output reg crc_valid ); reg [7:0] crc_reg; always @ (posedge clk)begin if(rst) begin crc_reg <= 8'h00; end else begin if(data_valid) begin crc_reg <= next_crc(data_in, crc_reg); end end end reg [2:0] count; always @ (posedge clk)begin if(rst) begin crc_out <= 0; count <= 0; end else begin if(data_valid) begin crc_out <= data_in; crc_valid <= 1'b0; end else if(crc_start)begin count <= count + 1'b1; crc_out <= crc_reg[7-count]; crc_valid <= 1'b1; end else begin crc_valid <= 1'b0; end end end function [7:0] next_crc; input data_in; input [7:0] current_crc; begin next_crc = {
current_crc[6:0],1'b0} ^ ({
8{
current_crc[7]^data_in}} & (8'h07)); end endfunction endmodule
- 结果
- 原理图
LSFR线性移位寄存器(并转串)(并行计算)
- 背景知识
首先得了解LFSR,线性反馈移位寄存器简称LFSR,用于产生可重复的伪随机序列,也可用来实现CRC校验。LFSR主要由触发器(寄存器)、异或门以及反馈线路组成。
通常推荐伽罗瓦LFSR,如图所示,对于二进制来说,gn 到g0的各个系数表示这条支路是否存在,1为存在,0则不存在。各个寄存器储存着上一次CRC校验运算的结果,寄存器的输出即为CRC的值。
- 代码
//CRC=x16+x12+x5+x0 module CRC_GenSerial( input clk, input rst_n, output reg [15:0] crc ); reg [31:θ] data_parallel; reg data_serial; reg [5:0] cnt; parameter source_data=32'h96E32077; //并转串 always@(posedge clk or negedge rst_n) begin if(!rst_n)begin cnt <= 0; data_parallel <= source_data; data_serial <= 0; end else if(cnt<32) begin cnt<=cnt+1; data_serial <= data_parallel[31]; data_parallel <= data_parallel<<1; end else begin cnt<=33; data_serial <= 0; data_parallel <= 0; end end always @(posedge clk or negedge rst_n)begin if(!rst_n)begin crc<=0; end else if(cnt<=32)begin crc[D] <= crc[15]^data_serial; crc[4:1] <= crc[3:0]; crc[5] <= crc[4]^crc[15]^data_serial; crc[11:6] <= crc[10:5]; crc[12] <= crc[11]^crc[15]^data_serial; crc[15:13] <= crc[14:12]; end else begin crc<=crc; end end endmodule
- 原理图
- 代码仿真
USB3 EMI设计
- 目的:用于电磁干扰(Electro-Magnetic Interference,EMI)抑制的 LSFR(线性反馈移位寄存器)多项式在标准中具体用于生成扰码(scrambling)。扰码的目的是为了均匀频谱,减少在固定频率上的辐射,从而降低电磁干扰。
- 具体实现:用于数据扰码的 LSFR 多项式是一个特定的序列,它用于生成伪随机二进制序列,这个序列与传输的数据进行异或操作,以实现数据的扰动。这种扰码有助于减少信号的周期性,从而降低对周围设备的电磁干扰。
- 多项式: G ( X ) = x 16 + x 5 + x 4 + x 3 + 1 G(X) =x^{16} + x^5 + x^4 + x^3 + 1 G(X)=x16+x5+x4+x3+1
- 原理图
–
模二除
- 背景知识
CRC校验中的运算不是普通的运算,称为“模2运算” - 模2加法和减法都是异或运算,例子如下:
1010+0110=1100,1010-0110=1100 - 模2乘法的定义:
0×0=0,0×1=0,1×0=0,1×1=1。 1011×101=其中横线之间的累加过程,采用的是2进制加法,不进位。
- 模2除法,其实也是异或运算: 0/1=0,1/1=1。 1011/101=10,余数为100(补了2个0)。
- 代码
module CRC_Gen( input clk, input rst_n, input [7:0] data, input data_valid, output reg [15:0] crc ); reg [23:0] temp=0; parameter polynomial=17b1_8001_0060_0810_0081; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin crc <= 0; temp <= {
data,16'b0};//复位时,将初始数据放入寄存器 end else if(data valid)begin if(temp[23]) temp[23:7] <= temp[23:7] ^ polynomial; else if(temp[22]) temp[22:6] <= temp[22:6] ^ polynomial; else if(temp[21]) temp[21:5i <= temp[21:5i ^ polynomial; else if(temp[20]) temp[20:4j <= temp[20:4] ^ polynomial; else if(temp[19]) temp[19:3] <= temp[19:3i ^ polynomial; else if(temp[18]) temp[18:2] <= temp[18:2] ^ polynomial; else if(temp[17]) temp[17:1j <= temp[17:1] ^ polynomial; else if(temp[16]) temp[16:oj <= temp[16:0] ^ polynomial; else begin crc<=temp[15:0]; end end endmodule
总结——串行、并行计算的本质
在第一段代码中,LFSR(线性反馈移位寄存器)的计算是在 always @(*) 块内部进行的。这里使用了组合逻辑的方式,并不受时钟信号的影响,因此是在数据信号变化时立即触发的,是并行计算的。每次数据信号 data_in 变化时,都会立即计算出 lfsr_c 寄存器的值,不需要等待时钟信号的上升沿。因此,LFSR 寄存器的更新是在数据信号变化时立即完成的,是并行计算的。
在第二段代码中,next_crc 函数是在 always @(posedge clk) 块内部被调用的,因此它的计算是在时钟的上升沿触发时进行的,这导致了计算是串行执行的。每个时钟周期,next_crc 函数都会被调用一次,并且在时钟的边沿执行。因此,整个 CRC 寄存器的更新是在时钟周期内完成的,是串行计算的。
从异或门调用的个数来看,串行计算要少得多
参考链接
- CRC(循环冗余校验)在线计算
- FPGA手撕代码——CRC校验码的多种Verilog实现方式
- CRC校验原理和推导过程及Verilog实现(一文讲透)
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/118980.html








