CRC:输入序列对某个表达式求余数,或者认为一系列数据求异或的过程。
CRC校验
CRC原理
CRC实现非常简单,但想要真正掌握CRC算法原理,就必须清楚地了解有限域的运算规则,知道CRC就是有限域中的除法余数,并且清楚如何将串行CRC转换为并行CRC,此时才能设计出使用的CRC电路。
如果不想深究理论,可以简单掌握CRC的Verilog/VHDL在线生成工具的使用即可。
网址:
- CRC代码生成工具:https://www.easics.com/webtools/crctool
- CRC(循环冗余校验)在线计算:http://www.ip33.com/crc.html
实现
由上述CRC代码生成工具可以得到一份关于CRC的Verilog或者VHDL源码。
源码如下:
module CRC16_D8;// polynomial: x^16 + x^12 + x^5 + 1// data width: 8// convention: the first serial bit is D[7]function [15:0] nextCRC16_D8;input [7:0] Data;input [15:0] crc;reg [7:0] d;reg [15:0] c;reg [15:0] newcrc;begind = Data;c = crc;newcrc[0] = d[4] ^ d[0] ^ c[8] ^ c[12];newcrc[1] = d[5] ^ d[1] ^ c[9] ^ c[13];newcrc[2] = d[6] ^ d[2] ^ c[10] ^ c[14];newcrc[3] = d[7] ^ d[3] ^ c[11] ^ c[15];newcrc[4] = d[4] ^ c[12];newcrc[5] = d[5] ^ d[4] ^ d[0] ^ c[8] ^ c[12] ^ c[13];newcrc[6] = d[6] ^ d[5] ^ d[1] ^ c[9] ^ c[13] ^ c[14];newcrc[7] = d[7] ^ d[6] ^ d[2] ^ c[10] ^ c[14] ^ c[15];newcrc[8] = d[7] ^ d[3] ^ c[0] ^ c[11] ^ c[15];newcrc[9] = d[4] ^ c[1] ^ c[12];newcrc[10] = d[5] ^ c[2] ^ c[13];newcrc[11] = d[6] ^ c[3] ^ c[14];newcrc[12] = d[7] ^ d[4] ^ d[0] ^ c[4] ^ c[8] ^ c[12] ^ c[15];newcrc[13] = d[5] ^ d[1] ^ c[5] ^ c[9] ^ c[13];newcrc[14] = d[6] ^ d[2] ^ c[6] ^ c[10] ^ c[14];newcrc[15] = d[7] ^ d[3] ^ c[7] ^ c[11] ^ c[15];nextCRC16_D8 = newcrc;endendfunction
endmodule
将上述代码重新封装如下,即可实现CRC校验功能。
RTL:
module CRC16D8(input i_clk,input i_rst_n,input [7:0] i_handle_data,input i_crc_init,input i_crc_en,output [15:0] o_crc_result
);reg [15:0] r_crc_result;always @(posedge i_clk or negedge i_rst_n)beginif(!i_rst_n)r_crc_result <= 16'hffff;else if(i_crc_init)r_crc_result <= 16'hffff;else if(i_crc_en)r_crc_result <= nextCRC16D8(i_handle_data,r_crc_result);elser_crc_result <= r_crc_result;endassign o_crc_result = r_crc_result ^ 16'hffff;function [15:0] nextCRC16D8;input [7:0] i_handle_data;input [15:0] i_crc_result;reg [7:0] d;reg [15:0] c;reg [15:0] r_new_crc;begind = i_handle_data;c = i_crc_result;r_new_crc[0] = d[4] ^ d[0] ^ c[8] ^ c[12];r_new_crc[1] = d[5] ^ d[1] ^ c[9] ^ c[13];r_new_crc[2] = d[6] ^ d[2] ^ c[10] ^ c[14];r_new_crc[3] = d[7] ^ d[3] ^ c[11] ^ c[15];r_new_crc[4] = d[4] ^ c[12];r_new_crc[5] = d[5] ^ d[4] ^ d[0] ^ c[8] ^ c[12] ^ c[13];r_new_crc[6] = d[6] ^ d[5] ^ d[1] ^ c[9] ^ c[13] ^ c[14];r_new_crc[7] = d[7] ^ d[6] ^ d[2] ^ c[10] ^ c[14] ^ c[15];r_new_crc[8] = d[7] ^ d[3] ^ c[0] ^ c[11] ^ c[15];r_new_crc[9] = d[4] ^ c[1] ^ c[12];r_new_crc[10] = d[5] ^ c[2] ^ c[13];r_new_crc[11] = d[6] ^ c[3] ^ c[14];r_new_crc[12] = d[7] ^ d[4] ^ d[0] ^ c[4] ^ c[8] ^ c[12] ^ c[15];r_new_crc[13] = d[5] ^ d[1] ^ c[5] ^ c[9] ^ c[13];r_new_crc[14] = d[6] ^ d[2] ^ c[6] ^ c[10] ^ c[14];r_new_crc[15] = d[7] ^ d[3] ^ c[7] ^ c[11] ^ c[15];nextCRC16D8 = r_new_crc;end
endfunction
TestBench:
`timescale 1ns / 1ps
`define clk_period 40// polynomial: x^16 + x^12 + x^5 + 1
module CRC16D8TB;reg i_clk;reg i_rst_n;reg [7:0] i_handle_data;reg i_crc_init;reg i_crc_en;wire [15:0] o_crc_result;CRC16D8 u_CRC16D8(.i_clk ( i_clk ),.i_rst_n ( i_rst_n ),.i_handle_data ( i_handle_data ),.i_crc_init ( i_crc_init ),.i_crc_en ( i_crc_en ),.o_crc_result ( o_crc_result )
);initial i_clk = 1;always#(`clk_period / 2) i_clk = ~i_clk ;initial begini_rst_n = 1'b0;i_handle_data = 8'd0;i_crc_en = 1'b0;i_crc_init = 1'b0;#(`clk_period *5 + 1);i_rst_n = 1'b1;i_crc_init = 1'b1;#(`clk_period * 10);i_crc_init = 1'b0;#(`clk_period);CRCFrame;#(`clk_period *10);$stop;endtask CRCFrame;beginCRCByte(8'h7e);CRCByte(8'h19);CRCByte(8'h00);CRCByte(8'he3);CRCByte(8'hb3);CRCByte(8'h9e);CRCByte(8'h28);CRCByte(8'hd3);CRCByte(8'h07);CRCByte(8'h3e);CRCByte(8'hf0);end endtasktask CRCByte;input [7:0] i_tx_data;begini_handle_data = i_tx_data; i_crc_en = 1'b1;#(`clk_period );i_crc_en = 1'b0;# 500;endendtask
总结
上文,CRC校验模块,在实际的工程中,使用的很多。本文中参考CRC校验原理,注重版权,侵删。
本文长期更新,如果你有好的想法和建议,欢迎在本文底部留言。另外也欢迎其他Verilog语言学习者与我共同交流,有任何疑问可以到本博客“评论专区”提出,我必知无不言,言无不尽。
日期:2021-9-3;
网址:https://blog.csdn.net/ZipingPan/article/details/120081322.