USB2.0IP设计
最近,在学习USB2.0IP的设计,其中包含了CRC校验码的内容,之前学习千兆以太网曾经用到过CRC32校验(https://www.cnblogs.com/Xwangzi66/p/14185143.html),CRC详细原理可见括号的链接,今天则从怎么用工具快速生成Verilog代码的角度介绍。
一 确定CRC5的多项式
G(X)= X^5 + X^2 + 1,输入数据的位宽为11bit,即CRC5中的输入信号[10:0]data_i.
二 在线网页生成CRC5的Verilog代码
链接如下:https://www.easics.com/crctool/
在线生成CRC5校验代码如下图:第一步是确定多项式,此处是CRC5的多项式。第二步选择CRC的类别,如CRC16,CRC32等。第三步,选择待校验数据的位宽。第四步,选择输出的编程语言,用Verilog实现。第五步,下载打开就🆗。注意填好邮箱,此处为了保护本人隐私则空着。
2.在线工具生成CRC5的Verilog代码
1 module CRC5_D11; 2 3 // polynomial: x^5 + x^2 + 1 4 // data width: 11 5 // convention: the first serial bit is D[10] 6 function [4:0] nextCRC5_D11; 7 8 input [10:0] Data; 9 input [4:0] crc; 10 reg [10:0] d; 11 reg [4:0] c; 12 reg [4:0] newcrc; 13 begin 14 d = Data; 15 c = crc; 16 17 newcrc[0] = d[10] ^ d[9] ^ d[6] ^ d[5] ^ d[3] ^ d[0] ^ c[0] ^ c[3] ^ c[4]; 18 newcrc[1] = d[10] ^ d[7] ^ d[6] ^ d[4] ^ d[1] ^ c[0] ^ c[1] ^ c[4]; 19 newcrc[2] = d[10] ^ d[9] ^ d[8] ^ d[7] ^ d[6] ^ d[3] ^ d[2] ^ d[0] ^ c[0] ^ c[1] ^ c[2] ^ c[3] ^ c[4]; 20 newcrc[3] = d[10] ^ d[9] ^ d[8] ^ d[7] ^ d[4] ^ d[3] ^ d[1] ^ c[1] ^ c[2] ^ c[3] ^ c[4]; 21 newcrc[4] = d[10] ^ d[9] ^ d[8] ^ d[5] ^ d[4] ^ d[2] ^ c[2] ^ c[3] ^ c[4]; 22 nextCRC5_D11 = newcrc; 23 end 24 endfunction 25 endmodule
三 修改成自己USB的IP设计的CRC5校验模块
通过在线工具生成后,自己可以修改模块名,输入输出信号名,寄存器名,以更好地用在自己的FPGA项目中,本人CRC5修改如下:
1 module usbh_crc5 2 ( 3 input [4:0] crc_i, 4 input [10:0] data_i, 5 output [4:0] crc_o 6 ); 7 8 //----------------------------------------------------------------- 9 // Implementation 10 //----------------------------------------------------------------- 11 assign crc_o[0] = data_i[10] ^ data_i[9] ^ data_i[6] ^ data_i[5] ^ data_i[3] ^ data_i[0] ^ 12 crc_i[0] ^ crc_i[3] ^ crc_i[4]; 13 14 assign crc_o[1] = data_i[10] ^ data_i[7] ^ data_i[6] ^ data_i[4] ^ data_i[1] ^ 15 crc_i[0] ^ crc_i[1] ^ crc_i[4]; 16 17 assign crc_o[2] = data_i[10] ^ data_i[9] ^ data_i[8] ^ data_i[7] ^ data_i[6] ^ data_i[3] ^ data_i[2] ^ data_i[0] ^ 18 crc_i[0] ^ crc_i[1] ^ crc_i[2] ^ crc_i[3] ^ crc_i[4]; 19 20 assign crc_o[3] = data_i[10] ^ data_i[9] ^ data_i[8] ^ data_i[7] ^ data_i[4] ^ data_i[3] ^ data_i[1] ^ 21 crc_i[1] ^ crc_i[2] ^ crc_i[3] ^ crc_i[4]; 22 23 assign crc_o[4] = data_i[10] ^ data_i[9] ^ data_i[8] ^ data_i[5] ^ data_i[4] ^ data_i[2] ^ 24 crc_i[2] ^ crc_i[3] ^ crc_i[4]; 25 26 endmodule
通过修改后,代码更简洁高效,更方便调用,直接在USB中调用即可!
后续的CRC16的Verilog实现,同CRC5生成方法一样,先用在线工具生成,再修改一些模块名,输入输出信号即可。
CRC16代码如下:
1 module usbh_crc16 2 ( 3 input [15:0] crc_i, 4 input [7:0] data_i, 5 output [15:0] crc_o 6 ); 7 8 //----------------------------------------------------------------- 9 // Implementation 10 //----------------------------------------------------------------- 11 assign crc_o[15] = data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^ 12 data_i[5] ^ data_i[6] ^ data_i[7] ^ crc_i[7] ^ crc_i[6] ^ 13 crc_i[5] ^ crc_i[4] ^ crc_i[3] ^ crc_i[2] ^ 14 crc_i[1] ^ crc_i[0]; 15 assign crc_o[14] = data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^ data_i[5] ^ 16 data_i[6] ^ crc_i[6] ^ crc_i[5] ^ crc_i[4] ^ 17 crc_i[3] ^ crc_i[2] ^ crc_i[1] ^ crc_i[0]; 18 assign crc_o[13] = data_i[6] ^ data_i[7] ^ crc_i[7] ^ crc_i[6]; 19 assign crc_o[12] = data_i[5] ^ data_i[6] ^ crc_i[6] ^ crc_i[5]; 20 assign crc_o[11] = data_i[4] ^ data_i[5] ^ crc_i[5] ^ crc_i[4]; 21 assign crc_o[10] = data_i[3] ^ data_i[4] ^ crc_i[4] ^ crc_i[3]; 22 assign crc_o[9] = data_i[2] ^ data_i[3] ^ crc_i[3] ^ crc_i[2]; 23 assign crc_o[8] = data_i[1] ^ data_i[2] ^ crc_i[2] ^ crc_i[1]; 24 assign crc_o[7] = data_i[0] ^ data_i[1] ^ crc_i[15] ^ crc_i[1] ^ crc_i[0]; 25 assign crc_o[6] = data_i[0] ^ crc_i[14] ^ crc_i[0]; 26 assign crc_o[5] = crc_i[13]; 27 assign crc_o[4] = crc_i[12]; 28 assign crc_o[3] = crc_i[11]; 29 assign crc_o[2] = crc_i[10]; 30 assign crc_o[1] = crc_i[9]; 31 assign crc_o[0] = data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^ data_i[5] ^ 32 data_i[6] ^ data_i[7] ^ crc_i[8] ^ crc_i[7] ^ crc_i[6] ^ 33 crc_i[5] ^ crc_i[4] ^ crc_i[3] ^ crc_i[2] ^ 34 crc_i[1] ^ crc_i[0]; 35 36 endmodule
总结,一直都是根据多项式,确定硬件电路的形式,然后查表,如V3学院千兆以太网的CRC32校验教程,很繁琐,得理解原理,今天意外知道一种新的方法,通过在线工具生成Verilog实现: