由於筆者在自己設計CRC模塊時遇到很多問題,在網上並未找到一篇具有實際指導意義的文章,在經過多次模擬修改再模擬之後得到了正確的結果,故願意在本文中為大家提供整個設計流程供大家快速完成設計。本文章主要針對具體的實際應用給出一套親測可行的實現辦法,給出設計代碼並提供模擬結果,供各位參考。 一.CRC概述 ...
由於筆者在自己設計CRC模塊時遇到很多問題,在網上並未找到一篇具有實際指導意義的文章,在經過多次模擬修改再模擬之後得到了正確的結果,故願意在本文中為大家提供整個設計流程供大家快速完成設計。本文章主要針對具體的實際應用給出一套親測可行的實現辦法,給出設計代碼並提供模擬結果,供各位參考。
一.CRC概述
CRC(Cyclic Redundancy Check),迴圈冗餘校驗,是一種數字通信中的常用查錯校驗碼。其特征是信息段和校驗欄位的長度可以任意選定。
校驗方法為發送方對信息數據執行約定好除數的二進位除法計算,並將得到的餘數附在幀的後面,發送給接收方;接收方也執行類似的演算法,兩側對比結果的餘數,相同則說明接收信息完整且正確,以保證數據傳輸的正確性和完整性。
具體來講,在K位信息碼後再拼接R位的校驗碼,整個編碼長度為N(=K+R)位,因此,這種編碼也叫(N,K)碼。對於一個給定的(N,K)碼,可以證明存在一個最高次冪為N-K=R的多項式G(x)。根據G(x)可以生成K位信息的校驗碼,而G(x)叫做這個CRC碼的生成多項式。
校驗碼的具體生成過程為:假設要發送的信息用多項式C(X)表示,將C(x)左移R位(可表示成C(x)2R),這樣C(x)的右邊就會空出R位,這就是校驗碼的位置。用 C(x)2R 除以生成多項式G(x)得到的餘數就是校驗碼FCS(Frame Check Series)。
任意一個由二進位位串組成的代碼都可以和一個繫數僅為‘0’和‘1’取值的多項式一一對應。例如:代碼1010111對應的多項式為x6+x4+x2+x+1,而多項式為x5+x3+x2+x+1對應的代碼101111。
CRC校驗根據所採用的生成多項式不同分為很多不同的標準,常見的有:
名稱 生成多項式 簡記式 應用舉例
CRC-4 x4+x+1 3 ITU G.704
CRC-8 x8+x5+x4+1 31 DS18B20
CRC-12 x12+x11+x3+x2+x+1 0x80F
CRC-16 x16+x15+x2+1 0x8005 IBM SDLC
CRC-ITU(CCITT) x16+x12+x5+1 0x1021 ISO HDLC, ITU
CRC-32 x32+x26+x23+...+x2+x+1 0x04C11DB7 ZIP, RAR
CRC-32c x32+x28+x27+...+x8+x6+1 0x1EDC6F41 SCTP
說明:簡記式最高位應為1,此處都省略了;
二.實現方法
本文章所要講的標準為CRC-ITU(CCITT-Xmodem),即生成多項式為0x1021
0x1021 = 0x11021 = 1,0001,0000,0010,0001
在此提供一個線上計算CRC校驗網站,方便進行驗證
https://www.lammertbies.nl/comm/info/crc-calculation.html
源代碼根據需求在源碼網站進行生成,後根據自己的需求進行修改,模擬驗證;
現提供生成源碼的步驟:
STEP1: http://outputlogic.com/?page_id=321
STEP2: 根據實際需求選擇輸入數據位寬和輸出校驗碼位寬,CRC校驗標準為自定義或者可選的幾種;
STEP3: 若選擇User defined,則進入第二頁選擇自定義的多項式,本模擬採用CCITT標準,即生成多項式為x16+x12+x5+1,此處只需要選中1,x5,x12即可,因為x16為1是預設的;
STEP4: 對生成的Verilog或者VHDL語言代碼進行修改,應用到實際當中;
三.實際應用模擬
現基於筆者實際應用場景進行一個具體的CRC校驗設計與模擬,其中,always 模塊里的CRC校驗計算過程不需要理解,若需要理解,可以下載該網站給出的文章(下載代碼會附)
A Practical Parallel CRC Generation Method
常用的CRC校驗方法有直接計算二進位除法,查表法,具體計算原理見下鏈接
https://blog.csdn.net/xing414736597/article/details/78693781
代碼如下:
module CRC(
input clk,//輸入時鐘
input reset,//總體複位信號
input crc_en,//選擇是否進行下一步CRC運算
input [63:0] data_in,//輸入數據為64位
output [15:0] crc_out//輸出數據即CRC校驗結果為16位
);
reg [15:0] lfsr_q,lfsr_c;
wire reset;
assign crc_out = lfsr_c;
always @(*) begin
lfsr_c[0] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[10] ^ lfsr_q[15] ^ data_in[0] ^ data_in[4] ^ data_in[8] ^ data_in[11] ^ data_in[12] ^ data_in[19] ^ data_in[20] ^ data_in[22] ^ data_in[26] ^ data_in[27] ^ data_in[28] ^ data_in[32] ^ data_in[33] ^ data_in[35] ^ data_in[42] ^ data_in[48] ^ data_in[49] ^ data_in[51] ^ data_in[52] ^ data_in[55] ^ data_in[56] ^ data_in[58] ^ data_in[63];
lfsr_c[1] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[11] ^ data_in[1] ^ data_in[5] ^ data_in[9] ^ data_in[12] ^ data_in[13] ^ data_in[20] ^ data_in[21] ^ data_in[23] ^ data_in[27] ^ data_in[28] ^ data_in[29] ^ data_in[33] ^ data_in[34] ^ data_in[36] ^ data_in[43] ^ data_in[49] ^ data_in[50] ^ data_in[52] ^ data_in[53] ^ data_in[56] ^ data_in[57] ^ data_in[59];
lfsr_c[2] = lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[12] ^ data_in[2] ^ data_in[6] ^ data_in[10] ^ data_in[13] ^ data_in[14] ^ data_in[21] ^ data_in[22] ^ data_in[24] ^ data_in[28] ^ data_in[29] ^ data_in[30] ^ data_in[34] ^ data_in[35] ^ data_in[37] ^ data_in[44] ^ data_in[50] ^ data_in[51] ^ data_in[53] ^ data_in[54] ^ data_in[57] ^ data_in[58] ^ data_in[60];
lfsr_c[3] = lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[13] ^ data_in[3] ^ data_in[7] ^ data_in[11] ^ data_in[14] ^ data_in[15] ^ data_in[22] ^ data_in[23] ^ data_in[25] ^ data_in[29] ^ data_in[30] ^ data_in[31] ^ data_in[35] ^ data_in[36] ^ data_in[38] ^ data_in[45] ^ data_in[51] ^ data_in[52] ^ data_in[54] ^ data_in[55] ^ data_in[58] ^ data_in[59] ^ data_in[61];
lfsr_c[4] = lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[14] ^ data_in[4] ^ data_in[8] ^ data_in[12] ^ data_in[15] ^ data_in[16] ^ data_in[23] ^ data_in[24] ^ data_in[26] ^ data_in[30] ^ data_in[31] ^ data_in[32] ^ data_in[36] ^ data_in[37] ^ data_in[39] ^ data_in[46] ^ data_in[52] ^ data_in[53] ^ data_in[55] ^ data_in[56] ^ data_in[59] ^ data_in[60] ^ data_in[62];
lfsr_c[5] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[12] ^ lfsr_q[13] ^ data_in[0] ^ data_in[4] ^ data_in[5] ^ data_in[8] ^ data_in[9] ^ data_in[11] ^ data_in[12] ^ data_in[13] ^ data_in[16] ^ data_in[17] ^ data_in[19] ^ data_in[20] ^ data_in[22] ^ data_in[24] ^ data_in[25] ^ data_in[26] ^ data_in[28] ^ data_in[31] ^ data_in[35] ^ data_in[37] ^ data_in[38] ^ data_in[40] ^ data_in[42] ^ data_in[47] ^ data_in[48] ^ data_in[49] ^ data_in[51] ^ data_in[52] ^ data_in[53] ^ data_in[54] ^ data_in[55] ^ data_in[57] ^ data_in[58] ^ data_in[60] ^ data_in[61];
lfsr_c[6] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[13] ^ lfsr_q[14] ^ data_in[1] ^ data_in[5] ^ data_in[6] ^ data_in[9] ^ data_in[10] ^ data_in[12] ^ data_in[13] ^ data_in[14] ^ data_in[17] ^ data_in[18] ^ data_in[20] ^ data_in[21] ^ data_in[23] ^ data_in[25] ^ data_in[26] ^ data_in[27] ^ data_in[29] ^ data_in[32] ^ data_in[36] ^ data_in[38] ^ data_in[39] ^ data_in[41] ^ data_in[43] ^ data_in[48] ^ data_in[49] ^ data_in[50] ^ data_in[52] ^ data_in[53] ^ data_in[54] ^ data_in[55] ^ data_in[56] ^ data_in[58] ^ data_in[59] ^ data_in[61] ^ data_in[62];
lfsr_c[7] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[2] ^ data_in[6] ^ data_in[7] ^ data_in[10] ^ data_in[11] ^ data_in[13] ^ data_in[14] ^ data_in[15] ^ data_in[18] ^ data_in[19] ^ data_in[21] ^ data_in[22] ^ data_in[24] ^ data_in[26] ^ data_in[27] ^ data_in[28] ^ data_in[30] ^ data_in[33] ^ data_in[37] ^ data_in[39] ^ data_in[40] ^ data_in[42] ^ data_in[44] ^ data_in[49] ^ data_in[50] ^ data_in[51] ^ data_in[53] ^ data_in[54] ^ data_in[55] ^ data_in[56] ^ data_in[57] ^ data_in[59] ^ data_in[60] ^ data_in[62] ^ data_in[63];
lfsr_c[8] = lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[15] ^ data_in[3] ^ data_in[7] ^ data_in[8] ^ data_in[11] ^ data_in[12] ^ data_in[14] ^ data_in[15] ^ data_in[16] ^ data_in[19] ^ data_in[20] ^ data_in[22] ^ data_in[23] ^ data_in[25] ^ data_in[27] ^ data_in[28] ^ data_in[29] ^ data_in[31] ^ data_in[34] ^ data_in[38] ^ data_in[40] ^ data_in[41] ^ data_in[43] ^ data_in[45] ^ data_in[50] ^ data_in[51] ^ data_in[52] ^ data_in[54] ^ data_in[55] ^ data_in[56] ^ data_in[57] ^ data_in[58] ^ data_in[60] ^ data_in[61] ^ data_in[63];
lfsr_c[9] = lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[13] ^ lfsr_q[14] ^ data_in[4] ^ data_in[8] ^ data_in[9] ^ data_in[12] ^ data_in[13] ^ data_in[15] ^ data_in[16] ^ data_in[17] ^ data_in[20] ^ data_in[21] ^ data_in[23] ^ data_in[24] ^ data_in[26] ^ data_in[28] ^ data_in[29] ^ data_in[30] ^ data_in[32] ^ data_in[35] ^ data_in[39] ^ data_in[41] ^ data_in[42] ^ data_in[44] ^ data_in[46] ^ data_in[51] ^ data_in[52] ^ data_in[53] ^ data_in[55] ^ data_in[56] ^ data_in[57] ^ data_in[58] ^ data_in[59] ^ data_in[61] ^ data_in[62];
lfsr_c[10] = lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[5] ^ data_in[9] ^ data_in[10] ^ data_in[13] ^ data_in[14] ^ data_in[16] ^ data_in[17] ^ data_in[18] ^ data_in[21] ^ data_in[22] ^ data_in[24] ^ data_in[25] ^ data_in[27] ^ data_in[29] ^ data_in[30] ^ data_in[31] ^ data_in[33] ^ data_in[36] ^ data_in[40] ^ data_in[42] ^ data_in[43] ^ data_in[45] ^ data_in[47] ^ data_in[52] ^ data_in[53] ^ data_in[54] ^ data_in[56] ^ data_in[57] ^ data_in[58] ^ data_in[59] ^ data_in[60] ^ data_in[62] ^ data_in[63];
lfsr_c[11] = lfsr_q[0] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[15] ^ data_in[6] ^ data_in[10] ^ data_in[11] ^ data_in[14] ^ data_in[15] ^ data_in[17] ^ data_in[18] ^ data_in[19] ^ data_in[22] ^ data_in[23] ^ data_in[25] ^ data_in[26] ^ data_in[28] ^ data_in[30] ^ data_in[31] ^ data_in[32] ^ data_in[34] ^ data_in[37] ^ data_in[41] ^ data_in[43] ^ data_in[44] ^ data_in[46] ^ data_in[48] ^ data_in[53] ^ data_in[54] ^ data_in[55] ^ data_in[57] ^ data_in[58] ^ data_in[59] ^ data_in[60] ^ data_in[61] ^ data_in[63];
lfsr_c[12] = lfsr_q[0] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[6] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[0] ^ data_in[4] ^ data_in[7] ^ data_in[8] ^ data_in[15] ^ data_in[16] ^ data_in[18] ^ data_in[22] ^ data_in[23] ^ data_in[24] ^ data_in[28] ^ data_in[29] ^ data_in[31] ^ data_in[38] ^ data_in[44] ^ data_in[45] ^ data_in[47] ^ data_in[48] ^ data_in[51] ^ data_in[52] ^ data_in[54] ^ data_in[59] ^ data_in[60] ^ data_in[61] ^ data_in[62] ^ data_in[63];
lfsr_c[13] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[7] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[1] ^ data_in[5] ^ data_in[8] ^ data_in[9] ^ data_in[16] ^ data_in[17] ^ data_in[19] ^ data_in[23] ^ data_in[24] ^ data_in[25] ^ data_in[29] ^ data_in[30] ^ data_in[32] ^ data_in[39] ^ data_in[45] ^ data_in[46] ^ data_in[48] ^ data_in[49] ^ data_in[52] ^ data_in[53] ^ data_in[55] ^ data_in[60] ^ data_in[61] ^ data_in[62] ^ data_in[63];
lfsr_c[14] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[8] ^ lfsr_q[13] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[2] ^ data_in[6] ^ data_in[9] ^ data_in[10] ^ data_in[17] ^ data_in[18] ^ data_in[20] ^ data_in[24] ^ data_in[25] ^ data_in[26] ^ data_in[30] ^ data_in[31] ^ data_in[33] ^ data_in[40] ^ data_in[46] ^ data_in[47] ^ data_in[49] ^ data_in[50] ^ data_in[53] ^ data_in[54] ^ data_in[56] ^ data_in[61] ^ data_in[62] ^ data_in[63];
lfsr_c[15] = lfsr_q[0] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[9] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[3] ^ data_in[7] ^ data_in[10] ^ data_in[11] ^ data_in[18] ^ data_in[19] ^ data_in[21] ^ data_in[25] ^ data_in[26] ^ data_in[27] ^ data_in[31] ^ data_in[32] ^ data_in[34] ^ data_in[41] ^ data_in[47] ^ data_in[48] ^ data_in[50] ^ data_in[51] ^ data_in[54] ^ data_in[55] ^ data_in[57] ^ data_in[62] ^ data_in[63];
end
//此段代碼為CRC具體的計算過程,基於LFSR(線性反饋移位寄存器);
always @(posedge clk, negedge reset) begin
if(!reset) begin
lfsr_q <= {16{1'b0}}; //CCITT_XModem初始值為16‘h0;其他協議根據具體情況修改;
end
else begin
lfsr_q <= crc_en ? lfsr_c : lfsr_q;//此處crc_en設為0,只計算一次即輸出CRC校驗結果,否則會持續不斷進行運算
end
end
endmodule
編寫testbench文件對該模塊進行模擬:
module crc_simul;
reg [63:0] data_in;
reg crc_en;
reg reset;
reg clk;
wire [15:0] crc_out;
crc uut(
.data_in(data_in),
.crc_en(crc_en),
.crc_out(crc_out),
.reset(reset),
.clk(clk)
);
initial begin
data_in = 64'd0;
crc_en = 1'b0;
reset=1'b0;
clk = 1'b0;
#9;
reset=1'b1;
#200;
data_in = {8'hFF,8'hFF,8'hAA,8'h55,8'h00,8'h01,16'h13EC};//結果應為3DC3;
#500;
data_in = {8'hFF,8'hFF,8'hAA,8'h55,8'h00,8'h01,16'h01F4};//結果應為CBEB;
end
always #1 clk = ~clk;
endmodule
模擬結果如下
可以驗證,模擬結果正確,在實際應用中也可以正確運行;