CRC计算-Verilog实现

一、前言

循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包和计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。(只能检验错误,而不能纠错)。

CRC校验的原理可以参考此篇文章:CRC校验详解(附代码示例)_crc校验代码-CSDN博客

在此不做过多的赘述。

二、数据宽度为8bit的CRC校验

CRC校验的verilog代码可以通过Easics CRC Tool此网站生成,在此网站可以选择常用的生成多项式,比如32位的以太网生成多项式。

也可以自己选择生成多项式,然后根据这篇博客中的表项,选择初始值以及是否要进行数据反转、取反。

下面是根据8位输入,32位输出的CRC代码

复制代码
module CRC32_D8(
  input           i_clk   ,
  input           i_rst   ,
  input [7:0]     i_data  ,
  input           i_en    ,
  output[31:0]    o_crc   

);
    
    reg  [31:0]       crc                 ;
    wire [7:0]        d                   ;
    wire [31:0]       c                   ;
    wire [31:0]       newcrc              ;
    assign  o_crc =   ~{crc[0],crc[1],crc[2],crc[3],crc[4],crc[5],crc[6],crc[7],crc[8],crc[9],
                       crc[10],crc[11],crc[12],crc[13],crc[14],crc[15],crc[16],crc[17],crc[18],crc[19],
                       crc[20],crc[21],crc[22],crc[23],crc[24],crc[25],crc[26],crc[27],crc[28],crc[29],
                       crc[30],crc[31]}                 ;//本次计算的CRC结果输出,数据反转,并进行取反
    assign d = {i_data[0],i_data[1],i_data[2],i_data[3],i_data[4],i_data[5],i_data[6],i_data[7]};   //需不需要反转需要查表
    assign c = crc;//将本次计算的赋值给下一次运算的中间变量

    assign newcrc[0] = d[6] ^ d[0] ^ c[24] ^ c[30];
    assign newcrc[1] = d[7] ^ d[6] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[30] ^ c[31];
    assign newcrc[2] = d[7] ^ d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[26] ^ c[30] ^ c[31];
    assign newcrc[3] = d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[27] ^ c[31];
    assign newcrc[4] = d[6] ^ d[4] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[28] ^ c[30];
    assign newcrc[5] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
    assign newcrc[6] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
    assign newcrc[7] = d[7] ^ d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[29] ^ c[31];
    assign newcrc[8] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
    assign newcrc[9] = d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29];
    assign newcrc[10] = d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[2] ^ c[24] ^ c[26] ^ c[27] ^ c[29];
    assign newcrc[11] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[3] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
    assign newcrc[12] = d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ d[0] ^ c[4] ^ c[24] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30];
    assign newcrc[13] = d[7] ^ d[6] ^ d[5] ^ d[3] ^ d[2] ^ d[1] ^ c[5] ^ c[25] ^ c[26] ^ c[27] ^ c[29] ^ c[30] ^ c[31];
    assign newcrc[14] = d[7] ^ d[6] ^ d[4] ^ d[3] ^ d[2] ^ c[6] ^ c[26] ^ c[27] ^ c[28] ^ c[30] ^ c[31];
    assign newcrc[15] = d[7] ^ d[5] ^ d[4] ^ d[3] ^ c[7] ^ c[27] ^ c[28] ^ c[29] ^ c[31];
    assign newcrc[16] = d[5] ^ d[4] ^ d[0] ^ c[8] ^ c[24] ^ c[28] ^ c[29];
    assign newcrc[17] = d[6] ^ d[5] ^ d[1] ^ c[9] ^ c[25] ^ c[29] ^ c[30];
    assign newcrc[18] = d[7] ^ d[6] ^ d[2] ^ c[10] ^ c[26] ^ c[30] ^ c[31];
    assign newcrc[19] = d[7] ^ d[3] ^ c[11] ^ c[27] ^ c[31];
    assign newcrc[20] = d[4] ^ c[12] ^ c[28];
    assign newcrc[21] = d[5] ^ c[13] ^ c[29];
    assign newcrc[22] = d[0] ^ c[14] ^ c[24];
    assign newcrc[23] = d[6] ^ d[1] ^ d[0] ^ c[15] ^ c[24] ^ c[25] ^ c[30];
    assign newcrc[24] = d[7] ^ d[2] ^ d[1] ^ c[16] ^ c[25] ^ c[26] ^ c[31];
    assign newcrc[25] = d[3] ^ d[2] ^ c[17] ^ c[26] ^ c[27];
    assign newcrc[26] = d[6] ^ d[4] ^ d[3] ^ d[0] ^ c[18] ^ c[24] ^ c[27] ^ c[28] ^ c[30];
    assign newcrc[27] = d[7] ^ d[5] ^ d[4] ^ d[1] ^ c[19] ^ c[25] ^ c[28] ^ c[29] ^ c[31];
    assign newcrc[28] = d[6] ^ d[5] ^ d[2] ^ c[20] ^ c[26] ^ c[29] ^ c[30];
    assign newcrc[29] = d[7] ^ d[6] ^ d[3] ^ c[21] ^ c[27] ^ c[30] ^ c[31];
    assign newcrc[30] = d[7] ^ d[4] ^ c[22] ^ c[28] ^ c[31];
    assign newcrc[31] = d[5] ^ c[23] ^ c[29];

always@(posedge i_clk,posedge i_rst)begin
  if(i_rst)
    crc <= 32'hFFFFFFFF;
  else if(i_en)
    crc <= newcrc;
  else
    crc <= crc;
end
endmodule

三、数据宽度打入8bit的CRC校验

当输入的数据宽度大于1byte时,假设为B1B2B3B4B5B6B7,需要首先计算出B1的CRC1,然后在CRC1的基础上(CRC2的初值变为CRC1)计算B2的CRC2,之后一直持续此过程,直到所有的输入的字节全部计算完成。同时需要将每一个字节CRC计算的结果输出。以64bit位宽的输入为例,计算CRC-32.

复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/04/28 15:49:12
// Design Name: 
// Module Name: CRC32_64bKEEP
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 多位宽的CRC运算,也是按照字节进行的,下一个字节CRC运算值,是在上一个字节的CRC运算值的基础上进行的
//


module CRC32_64bKEEP(
  input           i_clk     ,
  input           i_rst     ,
  input [7:0]     i_data    ,
  input [7:0]     i_data_1  ,
  input [7:0]     i_data_2  ,
  input [7:0]     i_data_3  ,
  input [7:0]     i_data_4  ,
  input [7:0]     i_data_5  ,
  input [7:0]     i_data_6  ,
  input [7:0]     i_data_7  ,  
  input           i_en      ,
  output[31:0]    o_crc     ,   
  output[31:0]    o_crc_1   ,
  output[31:0]    o_crc_2   ,
  output[31:0]    o_crc_3   ,
  output[31:0]    o_crc_4   ,
  output[31:0]    o_crc_5   ,
  output[31:0]    o_crc_6   ,
  output[31:0]    o_crc_7      
);

    reg  [31:0]       crc                 ;
    wire [7:0]        d[0:7]              ;
    wire [31:0]       c[0:7]              ;
    wire [31:0]       newcrc[0:7]         ;
    reg  [31:0]       ro_crc[0:7]         ;

    assign d[0] = {i_data[0],i_data[1],i_data[2],i_data[3],i_data[4],i_data[5],i_data[6],i_data[7]};   //需不需要反转需要查表
    assign d[1] = {i_data_1[0],i_data_1[1],i_data_1[2],i_data_1[3],i_data_1[4],i_data_1[5],i_data_1[6],i_data_1[7]};
    assign d[2] = {i_data_2[0],i_data_2[1],i_data_2[2],i_data_2[3],i_data_2[4],i_data_2[5],i_data_2[6],i_data_2[7]};
    assign d[3] = {i_data_3[0],i_data_3[1],i_data_3[2],i_data_3[3],i_data_3[4],i_data_3[5],i_data_3[6],i_data_3[7]};
    assign d[4] = {i_data_4[0],i_data_4[1],i_data_4[2],i_data_4[3],i_data_4[4],i_data_4[5],i_data_4[6],i_data_4[7]};
    assign d[5] = {i_data_5[0],i_data_5[1],i_data_5[2],i_data_5[3],i_data_5[4],i_data_5[5],i_data_5[6],i_data_5[7]};
    assign d[6] = {i_data_6[0],i_data_6[1],i_data_6[2],i_data_6[3],i_data_6[4],i_data_6[5],i_data_6[6],i_data_6[7]};
    assign d[7] = {i_data_7[0],i_data_7[1],i_data_7[2],i_data_7[3],i_data_7[4],i_data_7[5],i_data_7[6],i_data_7[7]};

    assign o_crc   = ro_crc[0];
    assign o_crc_1 = ro_crc[1];
    assign o_crc_2 = ro_crc[2];
    assign o_crc_3 = ro_crc[3];
    assign o_crc_4 = ro_crc[4];
    assign o_crc_5 = ro_crc[5];
    assign o_crc_6 = ro_crc[6];
    assign o_crc_7 = ro_crc[7];

    assign c[0] = crc;//第一次运算c[0]=32'hFFFFFFFF,第二次运算c[0]=上一次运算的crc结果

    genvar i;
    generate for(i = 0; i < 8;i = i + 1)
    begin
        assign newcrc[i][0]  = d[i][6] ^ d[i][0]  ^ c[i][24] ^ c[i][30];
        assign newcrc[i][1]  = d[i][7] ^ d[i][6]  ^ d[i][1]  ^ d[i][0]  ^ c[i][24] ^ c[i][25] ^ c[i][30] ^ c[i][31];
        assign newcrc[i][2]  = d[i][7] ^ d[i][6]  ^ d[i][2]  ^ d[i][1]  ^ d[i][0]  ^ c[i][24] ^ c[i][25] ^ c[i][26] ^ c[i][30] ^ c[i][31];
        assign newcrc[i][3]  = d[i][7] ^ d[i][3]  ^ d[i][2]  ^ d[i][1]  ^ c[i][25] ^ c[i][26] ^ c[i][27] ^ c[i][31];
        assign newcrc[i][4]  = d[i][6] ^ d[i][4]  ^ d[i][3]  ^ d[i][2]  ^ d[i][0]  ^ c[i][24] ^ c[i][26] ^ c[i][27] ^ c[i][28] ^ c[i][30];
        assign newcrc[i][5]  = d[i][7] ^ d[i][6]  ^ d[i][5]  ^ d[i][4]  ^ d[i][3]  ^ d[i][1]  ^ d[i][0]  ^ c[i][24] ^ c[i][25] ^ c[i][27] ^ c[i][28] ^ c[i][29] ^ c[i][30] ^ c[i][31];
        assign newcrc[i][6]  = d[i][7] ^ d[i][6]  ^ d[i][5]  ^ d[i][4]  ^ d[i][2]  ^ d[i][1]  ^ c[i][25] ^ c[i][26] ^ c[i][28] ^ c[i][29] ^ c[i][30] ^ c[i][31];
        assign newcrc[i][7]  = d[i][7] ^ d[i][5]  ^ d[i][3]  ^ d[i][2]  ^ d[i][0]  ^ c[i][24] ^ c[i][26] ^ c[i][27] ^ c[i][29] ^ c[i][31];
        assign newcrc[i][8]  = d[i][4] ^ d[i][3]  ^ d[i][1]  ^ d[i][0]  ^ c[i][0]  ^ c[i][24] ^ c[i][25] ^ c[i][27] ^ c[i][28];
        assign newcrc[i][9]  = d[i][5] ^ d[i][4]  ^ d[i][2]  ^ d[i][1]  ^ c[i][1]  ^ c[i][25] ^ c[i][26] ^ c[i][28] ^ c[i][29];
        assign newcrc[i][10] = d[i][5] ^ d[i][3]  ^ d[i][2]  ^ d[i][0]  ^ c[i][2]  ^ c[i][24] ^ c[i][26] ^ c[i][27] ^ c[i][29];
        assign newcrc[i][11] = d[i][4] ^ d[i][3]  ^ d[i][1]  ^ d[i][0]  ^ c[i][3]  ^ c[i][24] ^ c[i][25] ^ c[i][27] ^ c[i][28];
        assign newcrc[i][12] = d[i][6] ^ d[i][5]  ^ d[i][4]  ^ d[i][2]  ^ d[i][1]  ^ d[i][0]  ^ c[i][4]  ^ c[i][24] ^ c[i][25] ^ c[i][26] ^ c[i][28] ^ c[i][29] ^ c[i][30];
        assign newcrc[i][13] = d[i][7] ^ d[i][6]  ^ d[i][5]  ^ d[i][3]  ^ d[i][2]  ^ d[i][1]  ^ c[i][5]  ^ c[i][25] ^ c[i][26] ^ c[i][27] ^ c[i][29] ^ c[i][30] ^ c[i][31];
        assign newcrc[i][14] = d[i][7] ^ d[i][6]  ^ d[i][4]  ^ d[i][3]  ^ d[i][2]  ^ c[i][6]  ^ c[i][26] ^ c[i][27] ^ c[i][28] ^ c[i][30] ^ c[i][31];
        assign newcrc[i][15] = d[i][7] ^ d[i][5]  ^ d[i][4]  ^ d[i][3]  ^ c[i][7]  ^ c[i][27] ^ c[i][28] ^ c[i][29] ^ c[i][31];
        assign newcrc[i][16] = d[i][5] ^ d[i][4]  ^ d[i][0]  ^ c[i][8]  ^ c[i][24] ^ c[i][28] ^ c[i][29];
        assign newcrc[i][17] = d[i][6] ^ d[i][5]  ^ d[i][1]  ^ c[i][9]  ^ c[i][25] ^ c[i][29] ^ c[i][30];
        assign newcrc[i][18] = d[i][7] ^ d[i][6]  ^ d[i][2]  ^ c[i][10] ^ c[i][26] ^ c[i][30] ^ c[i][31];
        assign newcrc[i][19] = d[i][7] ^ d[i][3]  ^ c[i][11] ^ c[i][27] ^ c[i][31];
        assign newcrc[i][20] = d[i][4] ^ c[i][12] ^ c[i][28];
        assign newcrc[i][21] = d[i][5] ^ c[i][13] ^ c[i][29];
        assign newcrc[i][22] = d[i][0] ^ c[i][14] ^ c[i][24];
        assign newcrc[i][23] = d[i][6] ^ d[i][1]  ^ d[i][0]  ^ c[i][15] ^ c[i][24] ^ c[i][25] ^ c[i][30];
        assign newcrc[i][24] = d[i][7] ^ d[i][2]  ^ d[i][1]  ^ c[i][16] ^ c[i][25] ^ c[i][26] ^ c[i][31];
        assign newcrc[i][25] = d[i][3] ^ d[i][2]  ^ c[i][17] ^ c[i][26] ^ c[i][27];
        assign newcrc[i][26] = d[i][6] ^ d[i][4]  ^ d[i][3]  ^ d[i][0]  ^ c[i][18] ^ c[i][24] ^ c[i][27] ^ c[i][28] ^ c[i][30];
        assign newcrc[i][27] = d[i][7] ^ d[i][5]  ^ d[i][4]  ^ d[i][1]  ^ c[i][19] ^ c[i][25] ^ c[i][28] ^ c[i][29] ^ c[i][31];
        assign newcrc[i][28] = d[i][6] ^ d[i][5]  ^ d[i][2]  ^ c[i][20] ^ c[i][26] ^ c[i][29] ^ c[i][30];
        assign newcrc[i][29] = d[i][7] ^ d[i][6]  ^ d[i][3]  ^ c[i][21] ^ c[i][27] ^ c[i][30] ^ c[i][31];
        assign newcrc[i][30] = d[i][7] ^ d[i][4]  ^ c[i][22] ^ c[i][28] ^ c[i][31];
        assign newcrc[i][31] = d[i][5] ^ c[i][23] ^ c[i][29]; 

        if(i > 0)begin
            assign c[i] = newcrc[i - 1];
        end
    end
    endgenerate

//8字节的数据输入,每一个字节都会产生一个CRC的运算结果,将每一次计算的数据输入都输出出来
    genvar j;
    generate for(j = 0;j < 8;j = j + 1)
    begin
       always@(posedge i_clk,posedge i_rst)begin
        if(i_rst)
            ro_crc[j] <= 'd0;
        else if(!i_en)
            ro_crc[j] <= 'd0;
        else
            ro_crc[j] <= ~{ newcrc[j][0],newcrc[j][1],newcrc[j][2],newcrc[j][3],newcrc[j][4],newcrc[j][5],newcrc[j][6],newcrc[j][7],newcrc[j][8],newcrc[j][9],
                            newcrc[j][10],newcrc[j][11],newcrc[j][12],newcrc[j][13],newcrc[j][14],newcrc[j][15],newcrc[j][16],newcrc[j][17],newcrc[j][18],newcrc[j][19],
                            newcrc[j][20],newcrc[j][21],newcrc[j][22],newcrc[j][23],newcrc[j][24],newcrc[j][25],newcrc[j][26],newcrc[j][27],newcrc[j][28],newcrc[j][29],
                            newcrc[j][30],newcrc[j][31]};
       end 
    end
    endgenerate


always@(posedge i_clk,posedge i_rst)begin
  if(i_rst || !i_en)
    crc <= 32'hFFFFFFFF;
  else if(i_en)
    crc <= newcrc[7];
  else
    crc <= crc;
end

endmodule
相关推荐
浩子智控15 小时前
电子设备DevOps
fpga开发
cycf1 天前
CRC校验
fpga开发
landyjzlai1 天前
AMBA总线(15)关于AXI-stream(sg模式)
arm开发·fpga开发·amba
白狐_7981 天前
Quartus Prime 新手完全使用指南
fpga开发
Aaron15882 天前
三种主流接收机架构(超外差、零中频、射频直采)对比及发展趋势浅析
c语言·人工智能·算法·fpga开发·架构·硬件架构·信号处理
博览鸿蒙2 天前
一颗数字系统是如何在 FPGA 上“跑起来”的?
fpga开发
雨洛lhw2 天前
FPGA JTAG接口设计全解析
fpga开发·jtag
minglie12 天前
iverilog 配合 Makefile 搭建 Verilog 仿真工程
fpga开发
芒果树技术2 天前
MangoTree案例分享:基于AtomRIO FPGA平台,客户实现自适应主动减振
测试工具·fpga开发·模块测试
雨洛lhw2 天前
按键电路设计的细节
fpga开发