生活随笔
收集整理的這篇文章主要介紹了
CRC校验算法的Verilog实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、 文章簡述
CRC算法在通訊和數據傳輸領域中有著廣泛的應用,關于CRC的原理本文檔不做闡述,本文檔將將重點放在Verilog CRC代碼生成工具的使用和如何修改代碼使其滿足我們的要求兩個方面來CRC算法Verilog實現的進行講解。本教程包含以下方面的內容:
1.CRC類型簡介
2.CRC參數簡介
3.crc-gen代碼生產工具的使用
4.CRC 校驗代碼的移植
5.CRC校驗代碼的測試
二、 CRC算法中參數的簡介
2.1 CRC類型
簡單來講,CRC分為CRC-4、CRC-5、CRC-6、CRC-7、CRC-8、CRC-16、CRC-32;但是又可以進行更細節的分類,如圖1所示,同樣是CRC-8卻有四種不同的計算方法,如CRC-8、CRC-8/ITU、CRC-8/ROHC、CRC-8/MAXIM。因此在進行CRC檢驗時,要根據實際情況進行選擇,并且在雙方進行通訊時,校驗方式務必一致。
圖1 CRC類型圖
2.2 CRC參數:
從圖1中可以看出,每一種CRC都有多個參數,這個參數用來確定檢驗算法具體如何實現,如圖2所示。
圖2 CRC參數圖
CRC Name:CRC算法的名稱,也是在CRC校驗使用過程中很重要的參數,使用時通訊雙方使用同一種檢驗方式進行檢驗、對比才有意義
CRC Width:CRC輸出結果的位寬,與CRC名稱中的-X相對應。
CRC Poly:該參數是CRC校驗的核心參數,它與CRC校驗公式有關。例如:CRC-5/ITC的公式為x5+x4+x2+1,該公式等效為x5×1+x4×1+x3×0+x2×1+x1×0+x0×1,二進制表示其階數關系:10101(必須去掉最高階數),二進制的10101等于十六進行的0x15。同理其他檢驗的Poly也可以以同樣的方式進行確定。
CRC Init:該參數為CRC校驗的結果的初始值。
CRC RefIn:該參數確定輸入的數據是否進行字節的反轉,如果是true則需要反轉,若為false則不需要反轉。
CRC RefOut:該參數確定CRC初步校驗結果是否進行字節的反轉,如果是true則需要反轉,若為false則不需要反轉。
CRC XorOut:該參數確定CRC校驗結果輸出時的異或值。
2.3 CRC檢驗的過程的理解:
關于CRC校驗,我的理解是,首先有一個最基本的CRC的算法,它是CRC的主干,它需要的參數是Width、Poly、Init;還有一些外圍的算法,例如輸入輸出是否反轉,輸出結果需要異或的值,它的參數包括:RefIn、RefOut、XorOut。
三、CRC算法Verilog代碼生產工具的使用
3.1 crc-gen工具簡介
crc-gen是一款基于命令行操作的crc校驗代碼生成工具,可以生成VHDL和Verilo HDL語言的CRC算法的基礎代碼。生成基礎代碼之后,我們只需要根據自己所使用的CRC校驗算法的參數要求在進行參數上的修改,就可以寫出符合要求的CRC校驗的VHDL或Verilog HDL的代碼。本人學習的是Verilog HDL語言,本文將以該語言進行講解。
Crc-gen工具可以在網上進行下載,也可以使用下面的鏈接進行下載。
crc-gen下載鏈接:https://pan.baidu.com/s/1BuH7LmCB7x2gd1tJAuPCYA
提取碼:rt2z
3.2 crc-gen 的使用
在進行使用前,請先看一下crc-gen文件夾中的說明文檔。以免下面的操作有不好理解的地方。本例采用CRC-8/MAXIM校驗方式,CRC多項式為:x8+x5+x4+1。
首先打開電腦cmd命令行,并進入crc-gen文件夾,如圖3所示:
圖3 crc-gen初始界面
crc-gen的命令格式如下:
crc-gen language data_width poly_width poly_string
language: verilog or vhdl
data_width : 數據數據位寬,1-1024。
poly_width : CRC多項式寬度,1-1024。
poly_string : CRC多項式描述,即CRC Poly參數,16進制表示。
CRC-8/MAXIM的多項式為x8+x5+x4+1,通過多項式可以得到Poly值為0x31。我們要生成的代碼,編程語言采用Verlog,數據輸入為8位,輸入以下命令:
crc-gen Verilog 8 8 31,如圖4所示:
圖4 crc-gen 命令輸入及代碼生成界面
從圖中可以看出CRC的代碼已經生成,并且公式與我們所要求的公式是一致的。
將代碼賦值到文件中,復制的代碼如下:
module
crc(input
[7:0] data_in
,input crc_en
,output
[7:0] crc_out
,input rst
,input clk
);reg
[7:0] lfsr_q
,lfsr_c
;assign crc_out
= lfsr_q
;always @
(*) beginlfsr_c
[0] = lfsr_q
[0] ^ lfsr_q
[3] ^ lfsr_q
[4] ^ lfsr_q
[6] ^ data_in
[0] ^ data_in
[3] ^ data_in
[4] ^ data_in
[6];lfsr_c
[1] = lfsr_q
[1] ^ lfsr_q
[4] ^ lfsr_q
[5] ^ lfsr_q
[7] ^ data_in
[1] ^ data_in
[4] ^ data_in
[5] ^ data_in
[7];lfsr_c
[2] = lfsr_q
[2] ^ lfsr_q
[5] ^ lfsr_q
[6] ^ data_in
[2] ^ data_in
[5] ^ data_in
[6];lfsr_c
[3] = lfsr_q
[3] ^ lfsr_q
[6] ^ lfsr_q
[7] ^ data_in
[3] ^ data_in
[6] ^ data_in
[7];lfsr_c
[4] = lfsr_q
[0] ^ lfsr_q
[3] ^ lfsr_q
[6] ^ lfsr_q
[7] ^ data_in
[0] ^ data_in
[3] ^ data_in
[6] ^ data_in
[7];lfsr_c
[5] = lfsr_q
[0] ^ lfsr_q
[1] ^ lfsr_q
[3] ^ lfsr_q
[6] ^ lfsr_q
[7] ^ data_in
[0] ^ data_in
[1] ^ data_in
[3] ^ data_in
[6] ^ data_in
[7];lfsr_c
[6] = lfsr_q
[1] ^ lfsr_q
[2] ^ lfsr_q
[4] ^ lfsr_q
[7] ^ data_in
[1] ^ data_in
[2] ^ data_in
[4] ^ data_in
[7];lfsr_c
[7] = lfsr_q
[2] ^ lfsr_q
[3] ^ lfsr_q
[5] ^ data_in
[2] ^ data_in
[3] ^ data_in
[5];end always @
(posedge clk
, posedge rst
) begin
if(rst
) beginlfsr_q
<= {8{1'b1
}};end
else beginlfsr_q
<= crc_en
? lfsr_c
: lfsr_q
;endend
endmodule
四、Verilog代碼移植與修改
4.1參數要求
CRC-8/MAXIM的參數如圖5右側所示,其中Poly為0x31,初始值為0x00,輸入輸出需要數據位翻轉,輸出值要異或0x00(相當于不進行異或)。在生成的代碼中我們要進行初始值的設置,數據輸入輸出的翻轉。
圖5 CRC-8/MAXIM的參數
4.2 代碼修改
從參數身上可以看出,我們需要進行三處的修改(輸出結果異或0x00相當于不異或):
CRC結果初始值,即每次CRC計算的起始值,需設置為0x00。對輸入數據的進行位數的翻轉。對輸出的CRC校驗值進行翻轉。
修改后的代碼如下:
module
crc(input
[7:0] data_in
,input crc_en
,output
[7:0] crc_out
,input rst
,input clk
);reg
[7:0] lfsr_q
,lfsr_c
;wire
[7:0]data
;assign data
= {data_in
[0],data_in
[1],data_in
[2],data_in
[3],data_in
[4],data_in
[5],data_in
[6],data_in
[7]};assign crc_out
= {lfsr_q
[0],lfsr_q
[1],lfsr_q
[2],lfsr_q
[3],lfsr_q
[4],lfsr_q
[5],lfsr_q
[6],lfsr_q
[7]};always @
(*) beginlfsr_c
[0] = lfsr_q
[0] ^ lfsr_q
[3] ^ lfsr_q
[4] ^ lfsr_q
[6] ^ data
[0] ^ data
[3] ^ data
[4] ^ data
[6];lfsr_c
[1] = lfsr_q
[1] ^ lfsr_q
[4] ^ lfsr_q
[5] ^ lfsr_q
[7] ^ data
[1] ^ data
[4] ^ data
[5] ^ data
[7];lfsr_c
[2] = lfsr_q
[2] ^ lfsr_q
[5] ^ lfsr_q
[6] ^ data
[2] ^ data
[5] ^ data
[6];lfsr_c
[3] = lfsr_q
[3] ^ lfsr_q
[6] ^ lfsr_q
[7] ^ data
[3] ^ data
[6] ^ data
[7];lfsr_c
[4] = lfsr_q
[0] ^ lfsr_q
[3] ^ lfsr_q
[6] ^ lfsr_q
[7] ^ data
[0] ^ data
[3] ^ data
[6] ^ data
[7];lfsr_c
[5] = lfsr_q
[0] ^ lfsr_q
[1] ^ lfsr_q
[3] ^ lfsr_q
[6] ^ lfsr_q
[7] ^ data
[0] ^ data
[1] ^ data
[3] ^ data
[6] ^ data
[7];lfsr_c
[6] = lfsr_q
[1] ^ lfsr_q
[2] ^ lfsr_q
[4] ^ lfsr_q
[7] ^ data
[1] ^ data
[2] ^ data
[4] ^ data
[7];lfsr_c
[7] = lfsr_q
[2] ^ lfsr_q
[3] ^ lfsr_q
[5] ^ data
[2] ^ data
[3] ^ data
[5];end always @
(posedge clk
, posedge rst
) begin
if(rst
) beginlfsr_q
<= {8{1'b0
}};end
else beginlfsr_q
<= crc_en
? lfsr_c
: lfsr_q
;endend
endmodule
五、測試及分析
5.1測試代碼
測試輸入數據位0x01、0x02、0x03、0x04,測試代碼如下:
module
CRC(
input CLK
);reg
[1:0]cnt
= 2'd0
;reg CLK_DIV
= 1'd0
;always@
(posedge CLK
)begin
if(cnt
== 2'd3
)beginCLK_DIV
<= ~CLK_DIV
;cnt
<= 2'd0
;end
elsebegincnt
<= cnt
+ 1'd1
;endendreg
[7:0]crc_data_test
[3:0];reg
[7:0]crc_cnt
= 8'd0
;reg
[7:0]crc_data_in
;wire
[7:0]crc_data_out
;reg crc_en
;reg crc_rst
;crc(.data_in(crc_data_in
),.crc_en(crc_en
),.crc_out(crc_data_out
),.rst(crc_rst
),.clk(~CLK_DIV
));always@
(posedge CLK_DIV
)begin
case(crc_cnt
)8'd0
:begincrc_data_test
[0] <= 8'h01
;crc_data_test
[1] <= 8'h02
;crc_data_test
[2] <= 8'h03
;crc_data_test
[3] <= 8'h04
;crc_en
<= 1'd0
;crc_rst
<= 1'd1
;crc_cnt
<= crc_cnt
+ 1'd1
;end
8'd1
:begincrc_en
<= 1'd1
;crc_rst
<= 1'd0
;crc_data_in
<= crc_data_test
[0];crc_cnt
<= crc_cnt
+ 1'd1
;end
8'd2
:begincrc_data_in
<= crc_data_test
[1];crc_cnt
<= crc_cnt
+ 1'd1
;end
8'd3
:begincrc_data_in
<= crc_data_test
[2];crc_cnt
<= crc_cnt
+ 1'd1
;end
8'd4
:begincrc_data_in
<= crc_data_test
[3];crc_cnt
<= 8'd0
;end
default:begincrc_cnt
<= 8'd0
;endendcaseend
endmodule
5.2測試結果
CRC計算機計算結果如圖6所示。
圖6 CRC計算機計算結果
FPGA 測試結果如圖7所示。
圖7 FPGA 測試結果
從圖中可以看到,輸入數據相同的情況下,在數據輸入結束后的,CRC校驗輸出值與CRC計算器計算的結果是一樣。
總結
以上是生活随笔為你收集整理的CRC校验算法的Verilog实现的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。