本文设计思想采用明德扬至简设计法。由于本人项目需要进行光纤数据传输,为了保证通信质量要对数据进行校验。在校验算法中,最简单最成熟的非CRC校验莫属了。

  得出一个数的CRC校验码还是比较简单的:

  1. 选定一个CRC生成多项式G(x);
  2. 将发送数据左移K位,右侧补零(其中K为生成多项式最高次幂);
  3. 用移位补零后的数据对G(x)进行模2除法(其实就是异或运算);
  4. 用得到的余数即为该数据的CRC校验码;

  发送端将移位补零后数据的低K位0替换成CRC校验码组成新的数据发送出去,接收端对带有校验码的数据对同样的G(x)做模2除法。由于发送端将余数加入在数据尾部,相当于已做了“去余”处理,故若数据传输正确时,接收端的模2除运算余数应为0。其中校验位数和生成多项式不是随便选定的,一般采用常用的标准形式。其中CRCK是指有K为校验位,不同位数对应不同的纠检错能力。之前本人在网上找到一篇关于CRC校验原理的文章,比较详细且浅显易懂:http://mp.weixin.qq.com/s/RNHLZGPD9Ysbxb1FNDn6EA

  当刚看完这些资料,对CRC有了大概认识之后,我和很多初学的朋友们一样充满疑惑。CRC如何用硬件实现呢?如何对包含多个数据的数据帧进行校验呢?FCS又是如何在帧尾的下一个时钟周期就得到结果的呢?

  最原始的实现方式是采用LFSR(线性反馈移位寄存器)来完成校验功能,以下是结构示意图:

  寄存器个数等于G(x)最高次幂,图中gx表示链路通断,与多项式系数相对应:系数为1时连接,0则断开。数据在每个时钟周期从右侧输入1bit,且寄存器内数据右移一位。如此移位,反馈异或的过程即为待发送数据移位后对生成多项式做模2除的过程,故当全部数据位输入完毕,寄存器内部的值即为CRC校验码。我们以较简单的CRC8为例,其G(x) = x^8 + x^2 + x^1 + 1,根据上述分析得到:

              reg2(i) = reg1(i-1)^reg7(i-1)^d(i)

              reg1(i) = reg0(i-1)^reg7(i-1)^d(i)

              reg0(i) = reg7(i-1)^d(i)

              regk(i) = regk-1(i-1)       (k!=0,1,2)

  其中,i表示当前时刻,i-1表示上一时刻。数据位宽定为4bit,经过四个节拍,寄存器内部数据变化过程见表:

  根据上述传递方程推导得出四个节拍后reg7~reg0保存的数值,试想一下:既然每个触发器内保存数值表达式已知,那么如果直接将第四行表达式赋值寄存器,下一个时钟节拍即可得到最终校验结果,而无需等待四个时钟节拍。这就是CRC校验的并行实现方式了!传统的CRC校验算法已经非常成熟,在使用过程中不需要完全自己推导公式,了解基本原理即可。至于代码,有做好的线上生成工具  http://www.easics.com/webtools/crctool  我们选定CRC8,并将数据位宽定义为4bit,验证上述推导过程是否正确。

  生成源代码:

  1. ////////////////////////////////////////////////////////////////////////////////
  2. // Purpose : synthesizable CRC function
  3. // * polynomial: x^8 + x^2 + x^1 + 1
  4. // * data width: 4
  5. ////////////////////////////////////////////////////////////////////////////////
  6. module CRC8_D4;
  7.  
  8. // polynomial: x^8 + x^2 + x^1 + 1
  9. // data width: 4
  10. // convention: the first serial bit is D[3]
  11. function [:] nextCRC8_D4;
  12.  
  13. input [:] Data;
  14. input [:] crc;
  15. reg [:] d;
  16. reg [:] c;
  17. reg [:] newcrc;
  18. begin
  19. d = Data;
  20. c = crc;
  21.  
  22. newcrc[] = d[] ^ c[];
  23. newcrc[] = d[] ^ d[] ^ c[] ^ c[];
  24. newcrc[] = d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[];
  25. newcrc[] = d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[];
  26. newcrc[] = d[] ^ d[] ^ c[] ^ c[] ^ c[];
  27. newcrc[] = d[] ^ c[] ^ c[];
  28. newcrc[] = c[];
  29. newcrc[] = c[];
  30. nextCRC8_D4 = newcrc;
  31. end
  32. endfunction
  33. endmodule

  代码中公式逻辑部分与表格中第四节拍中寄存器保存的数据一致,证明推导正确。

  一个数据的校验大家应该已经掌握了,那如何对整个数据帧进行校验呢?可以看出代码中有data和crc两个数据接口,说明上一个数据的校验结果要作为下一个数据校验过程中移位寄存器的初值,如此循环往复在数据帧的下一拍就能输出整个数据帧的校验值了。关于CRC校验原理和逻辑实现方式已经告一段落。因数据帧校验对校验算法的纠检错能力要求较高,故采用CRC32。这里仅实现检错丢弃功能,即对接收端校验正确的数据帧保留,错误帧丢弃。同样由线上生成工具得到CRC32源代码(数据位宽32bit):

  1. ////////////////////////////////////////////////////////////////////////////////
  2.  
  3. // Purpose : synthesizable CRC function
  4. // * polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
  5. // * data width: 32
  6.  
  7. ////////////////////////////////////////////////////////////////////////////////
  8. module CRC32_D32;
  9.  
  10. // polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
  11. // data width: 32
  12. // convention: the first serial bit is D[31]
  13. function [:] nextCRC32_D32;
  14.  
  15. input [:] Data;
  16. input [:] crc;
  17. reg [:] d;
  18. reg [:] c;
  19. reg [:] newcrc;
  20. begin
  21. d = Data;
  22. c = crc;
  23.  
  24. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  25. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  26. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  27. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  28. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  29. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  30. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  31. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  32. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  33. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  34. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  35. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  36. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  37. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  38. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  39. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  40. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  41. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  42. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  43. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  44. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  45. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  46. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  47. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  48. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  49. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  50. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  51. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  52. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  53. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  54. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  55. newcrc[] = d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  56. nextCRC32_D32 = newcrc;
  57. end
  58. endfunction
  59. endmodule

  这推导一遍可要了命了!还好是现成的。代码以函数形式给出,我们对此稍作修改并补充好接口逻辑。

  1. `timescale 1ns / 1ps
  2.  
  3. module CRC32_D32(
  4. input clk,
  5. input rst_n,
  6. input clr,//同步清零
  7. input din_vld,
  8. input [:] din,
  9.  
  10. output reg dout_vld,
  11. output reg [:] dout//crc校验结果
  12. );
  13.  
  14. // polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
  15. // data width: 32
  16. // convention: the first serial bit is D[31]
  17. // function [31:0] nextCRC32_D32;
  18.  
  19. wire [:] d;
  20. wire [:] c;
  21.  
  22. assign d = din;
  23. assign c = dout;
  24.  
  25. always@(posedge clk or negedge rst_n)begin
  26. if(!rst_n)
  27. dout <= 'hffff_ffff;
  28. else if(clr)
  29. dout <= 'hffff_ffff;
  30. else if(din_vld)begin
  31. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  32. dout[] <=d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  33. dout[] <=d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  34. dout[] <=d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  35. dout[] <=d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  36. dout[] <=d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  37. dout[] <=d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  38. dout[] <=d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  39. dout[] <=d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  40. dout[] <=d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  41. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  42. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  43. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  44. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  45. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  46. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  47. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  48. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  49. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  50. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  51. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  52. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  53. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  54. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  55. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  56. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  57. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  58. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  59. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  60. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  61. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  62. dout[] <= d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ d[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[] ^ c[];
  63. end
  64. end
  65.  
  66. //dout_vld
  67. always@(posedge clk or negedge rst_n)begin
  68. if(!rst_n)
  69. dout_vld <= ;
  70. else
  71. dout_vld <= din_vld;
  72. end
  73.  
  74. endmodule

  寄存器的每一位仅与其对应的表达式有关,故可以通过时序逻辑和阻塞赋值实现并行计算。现添加测试激励仿真验证:

  1. `timescale 1ns / 1ps
  2. //////////////////////////////////////////////////////////////////////////////////
  3. // Company:
  4. // Engineer:
  5. //
  6. // Create Date: 2017/10/17 17:39:59
  7. // Design Name:
  8. // Module Name: CRC32_tb
  9. // Project Name:
  10. // Target Devices:
  11. // Tool Versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //////////////////////////////////////////////////////////////////////////////////
  21.  
  22. module CRC32_tb;
  23.  
  24. reg clk,rst_n;
  25. reg [:] din;
  26. reg din_vld;
  27. reg clr;
  28.  
  29. wire [:] dout;
  30. wire dout_vld;
  31. wire [:] result_final;
  32.  
  33. CRC32_D32 CRC32_D32(
  34. .clk(clk),
  35. .rst_n(rst_n),
  36. .clr(clr),//同步清零
  37. .din_vld(din_vld),
  38. .din(din),
  39.  
  40. .dout_vld(dout_vld),
  41. .dout(dout)//crc校验结果
  42. );
  43.  
  44. parameter CYC = ,
  45. RST_TIME = ;
  46.  
  47. initial begin
  48. clk = ;
  49. forever#(CYC /2.0) clk = ~clk;
  50. end
  51.  
  52. initial begin
  53. rst_n = ;
  54. #;
  55. rst_n = ;
  56. #(CYC*RST_TIME) rst_n = ;
  57. end
  58.  
  59. initial begin
  60. //Initialize Inputs
  61. #;
  62. din = ;
  63. clr = ;
  64. din_vld = ;
  65. #(CYC*RST_TIME)
  66. #(CYC*)
  67. din_vld = ;
  68. din = 'h12345678;
  69. #(CYC*)
  70. din = 'hdf8a8a2b;
  71. #(CYC*)
  72. din_vld = ;
  73. #(CYC*)
  74. $stop;
  75. end
  76.  
  77. assign result_final = ~dout;
  78.  
  79. endmodule

  波形如下:

  将第一个数的校验结果作为第二个待校验数时,最终校验结果为全1.我们再多加几个数看看

  同样,得到前四个数校验结果后,将其添加到数据帧尾作为第五个待校验数值时,最终结果亦为全1.由此可知,当将前N-1个数取反前校验结果作为第N个数一起计算时,下一拍校验值取反一定为全1,这正好是数据传输正确情况下接收端的状态。

  有CRC代码生成工具,自然有校验结果计算工具:On-line CRC calculation and free library  https://www.lammertbies.nl/comm/info/crc-calculation.html 注意本文中CRC代码计算结果与计算工具不符,这是因为校验算法中会涉及到一些以字节为单位的bit颠倒,字节颠倒和取反等操作,根据不同的应用场合会有所变动。

数据帧CRC32校验算法实现的更多相关文章

  1. CRC-32 校验算法

      crc32的头文件 ===========================分割线=========================== //crc32.h #ifndef _CRC32_H #de ...

  2. 常用校验算法CRC、MD5、SHA_转

    1.算法概述 数据摘要算法是密码学算法中非常重要的一个分支,它通过对所有数据提取指纹信息以实现数据签名.数据完整性校验等功能,由于其不可逆性,有时候会被用做敏感信息的加密.数据摘要算法也被称为哈希(H ...

  3. C#校验算法列举

    以下是工作中常用的几种校验算法,后期将不断更新 和校验 /// <summary> /// CS和校验 /// </summary> /// <param name=&q ...

  4. CRC校验算法详解

    CRC(Cyclic Redundancy Check)循环冗余校验是常用的数据校验方法,讲CRC算法的文章很多,之所以还要写这篇,是想换一个方法介绍CRC算法,希望能让大家更容易理解CRC算法. 先 ...

  5. 银行卡luhm校验算法

    /** * 15位银行卡luhm校验算法 * 1.从卡号最后一位数字开始,逆向将奇数位(1.3.5等等)相加. * 2.从卡号最后一位数字开始,逆向将偶数位数字,先乘以2(如果乘积为两位数,则将其减去 ...

  6. CRC32校验的用法

    CRC32校验数据的完整性 这里的数据包括字符串.文件,还有哪些? 文件校验相当于下载大型软件,有md5加密结果.这里的用途是什么?

  7. 使用 boost 进行 CRC32 校验

    使用 boost 进行 CRC32 校验 - firebird321的专栏 - 博客频道 - CSDN.NET 使用 boost 进行 CRC32 校验 分类: 文件操作 2008-06-06 18: ...

  8. C# 异或校验算法

    C# 的异或校验算法 直接上代码 public partial class FormCRC : Form { public FormCRC() { InitializeComponent(); } p ...

  9. CRC校验算法学习

    原文:http://www.repairfaq.org/filipg/LINK/F_crc_v31.html 本文根据上述链接原文翻译而来,如有错误,忘广大网友互相帮忙纠正,谢谢! 1.前言: 1.0 ...

随机推荐

  1. python日记_01 python实现6个人围成一圈,扔到第三个人出局,循环扔的问题。

    #!/usr/bin/python shoplist=['mango','apple','carrot','banana','oracle','python'] length = len(shopli ...

  2. Struts2第五篇【类型转换器、全局、局部类型转换器】

    前言 上篇博文已经讲解了,Struts2为我们实现了数据自动封装-由上篇的例子我们可以看出,表单提交过去的数据全都是String类型的,但是经过Struts自动封装,就改成是JavaBean对应成员变 ...

  3. Spring-hibernate-BaseDao

    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w ...

  4. htt p第一章概述

    http的概述 1 web客户端与服务器是如何通信 2 web资源来自的何方 3 web事务是怎样的工作的 4 http通信所使用的报文结构 5 底层tcp的传输的结构 6不同的http协议体 什么是 ...

  5. python实现算24的算法

    1.介绍 给定4个整数,数字范围在1-13之间,任意使用 + - * / ( ) ,构造出一个表达式,使得最终结果为24,这就是常见的算24的游戏.本文介绍用Python语言实现的两种方式.2.实现思 ...

  6. GCD之全局、主线程

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 -(NSString *)fetchData {     [NSThread sleepFo ...

  7. 已被.NET基金会认可的弹性和瞬态故障处理库Polly介绍

    前言 本节我们来介绍一款强大的库Polly,Polly是一种.NET弹性和瞬态故障处理库,允许我们以非常顺畅和线程安全的方式来执诸如行重试,断路,超时,故障恢复等策略. Polly针对对.NET 4. ...

  8. Quartz学习——Spring和Quartz集成详解(三)

    Spring是一个很优秀的框架,它无缝的集成了Quartz,简单方便的让企业级应用更好的使用Quartz进行任务的调度.下面就对Spring集成Quartz进行简单的介绍和示例讲解!和上一节 Quar ...

  9. Vi快捷操作 vim配置【shell文件格式从windows转换为linux】

    vim配置 http://www.cnblogs.com/ma6174/archive/2011/12/10/2283393.html gg 首行 dd 删除当前行 :.,$d  删除全部内容 :se ...

  10. S2_SQL_第五章

    UNIQUE|FULLTEXT|SPATIAL:分别表示唯一索引,全文索引和空间索引,为可选参数index_name;指定索引名称table_name;指定创建索引表名colymn_name;指定需要 ...