FPGA并行实现CRC(循环冗余码)校验

关于 CRC 校验原理及 C 语言实现,尚为网曾写过相应的文章——循环冗余检验 (CRC) 算法原理及 C 语言实现,为了加快 CRC 的计算速度,也写过CRC 算法查表法推导及 C 语言实现。这里再写一篇 FPGA 并行实现 CRC 校验。

其实,对于 C 语言实现 CRC 校验,只需要弄懂 CRC 的原理和处理逻辑就可以了,而 FPGA 实现 CRC 则是通过其内部的数字器件,如触发器来并行处理 CRC 校验的。例如,LFSR(Linear Feedback Shift Register,线性反馈移位寄存器)计算 CRC,可以用多项式 G(x)表示,G(x) = X16+X12+X5+1 模型可如下图所示。

FPGA并行实现CRC(循环冗余码)校验
图 1 LFSR 计算 CRC 模型

根据上图可以看出 FPGA 实现 CRC 校验,其实就是靠 FPGA 内部的触发器和门器件实现的,具体原理就不再详述,这里重点看一下 Verilog HDL 的实现。

FPGA 并行实现 CRC 的流程

(1)FPGA 并行计算 crc 用 verilog 语言描述是复杂繁琐的,所以可以使用在线工具生成 verilog 或者 VHDL 模板(在线工具见文末),模板生成的代码稍加修改即可使用。

(2)本次校验模型为 G(x) = X16+X12+X5+1。在线工具中操作相关选项生成模板。

FPGA并行实现CRC(循环冗余码)校验
图 2 在线工具生成 verilog HDL/VHDL 代码

模板.v 文件如下:

////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1999-2008 Easics NV.
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Purpose : synthesizable CRC function
//   * polynomial: x^16 + x^12 + x^5 + 1
//   * data width: 16
//
// Info : tools@easics.be
//        http://www.easics.com
////////////////////////////////////////////////////////////////////////////////
module CRC16_D16;

  // polynomial: x^16 + x^12 + x^5 + 1
  // data width: 16
  // convention: the first serial bit is D[15]
  function [15:0] nextCRC16_D16;

    input [15:0] Data;
    input [15:0] crc;
    reg [15:0] d;
    reg [15:0] c;
    reg [15:0] newcrc;
  begin
    d = Data;
    c = crc;

    newcrc[0] = d[12] ^ d[11] ^ d[8] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[8] ^ c[11] ^ c[12];
    newcrc[1] = d[13] ^ d[12] ^ d[9] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[9] ^ c[12] ^ c[13];
    newcrc[2] = d[14] ^ d[13] ^ d[10] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[10] ^ c[13] ^ c[14];
    newcrc[3] = d[15] ^ d[14] ^ d[11] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[11] ^ c[14] ^ c[15];
    newcrc[4] = d[15] ^ d[12] ^ d[8] ^ d[4] ^ c[4] ^ c[8] ^ c[12] ^ c[15];
    newcrc[5] = d[13] ^ d[12] ^ d[11] ^ d[9] ^ d[8] ^ d[5] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[5] ^ c[8] ^ c[9] ^ c[11] ^ c[12] ^ c[13];
    newcrc[6] = d[14] ^ d[13] ^ d[12] ^ d[10] ^ d[9] ^ d[6] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[6] ^ c[9] ^ c[10] ^ c[12] ^ c[13] ^ c[14];
    newcrc[7] = d[15] ^ d[14] ^ d[13] ^ d[11] ^ d[10] ^ d[7] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[7] ^ c[10] ^ c[11] ^ c[13] ^ c[14] ^ c[15];
    newcrc[8] = d[15] ^ d[14] ^ d[12] ^ d[11] ^ d[8] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[8] ^ c[11] ^ c[12] ^ c[14] ^ c[15];
    newcrc[9] = d[15] ^ d[13] ^ d[12] ^ d[9] ^ d[8] ^ d[4] ^ c[4] ^ c[8] ^ c[9] ^ c[12] ^ c[13] ^ c[15];
    newcrc[10] = d[14] ^ d[13] ^ d[10] ^ d[9] ^ d[5] ^ c[5] ^ c[9] ^ c[10] ^ c[13] ^ c[14];
    newcrc[11] = d[15] ^ d[14] ^ d[11] ^ d[10] ^ d[6] ^ c[6] ^ c[10] ^ c[11] ^ c[14] ^ c[15];
    newcrc[12] = d[15] ^ d[8] ^ d[7] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[7] ^ c[8] ^ c[15];
    newcrc[13] = d[9] ^ d[8] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[8] ^ c[9];
    newcrc[14] = d[10] ^ d[9] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[9] ^ c[10];
    newcrc[15] = d[11] ^ d[10] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[10] ^ c[11];
    nextCRC16_D16 = newcrc;
  end
  endfunction
endmodule

(3)修改模板最终如下:

`timescale 1ns/1ps
module crc16_test (
    input     wire              i_clk                 , //时钟;
    input     wire              i_rst_n               , //同步复位;
    input     wire              i_din_valid           , //输入数据有效;
    input     wire    [15:0]    i_din                 , //输入数据;
    output    wire              o_dout_valid          , //输出 CRC 值有效;
    output    wire    [15:0]    o_dout                  //输出 CRC;
);
reg [15:0] r_dout;
wire [15:0] d;
wire [15:0] c;
assign d = i_din;
assign c = r_dout;
always @(posedge i_clk) begin
    if (~i_rst_n)
        r_dout <= 16'hffff; //初始值为 ffff;
    else if (i_din_valid)
    begin //计算逻辑;
        r_dout[0]  = d[12] ^ d[11] ^ d[8] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[8] ^ c[11] ^ c[12];
        r_dout[1]  = d[13] ^ d[12] ^ d[9] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[9] ^ c[12] ^ c[13];
        r_dout[2]  = d[14] ^ d[13] ^ d[10] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[10] ^ c[13] ^ c[14];
        r_dout[3]  = d[15] ^ d[14] ^ d[11] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[11] ^ c[14] ^ c[15];
        r_dout[4]  = d[15] ^ d[12] ^ d[8] ^ d[4] ^ c[4] ^ c[8] ^ c[12] ^ c[15];
        r_dout[5]  = d[13] ^ d[12] ^ d[11] ^ d[9] ^ d[8] ^ d[5] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[5] ^ c[8] ^ c[9] ^ c[11] ^ c[12] ^ c[13];
        r_dout[6]  = d[14] ^ d[13] ^ d[12] ^ d[10] ^ d[9] ^ d[6] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[6] ^ c[9] ^ c[10] ^ c[12] ^ c[13] ^ c[14];
        r_dout[7]  = d[15] ^ d[14] ^ d[13] ^ d[11] ^ d[10] ^ d[7] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[7] ^ c[10] ^ c[11] ^ c[13] ^ c[14] ^ c[15];
        r_dout[8]  = d[15] ^ d[14] ^ d[12] ^ d[11] ^ d[8] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[8] ^ c[11] ^ c[12] ^ c[14] ^ c[15];
        r_dout[9]  = d[15] ^ d[13] ^ d[12] ^ d[9] ^ d[8] ^ d[4] ^ c[4] ^ c[8] ^ c[9] ^ c[12] ^ c[13] ^ c[15];
        r_dout[10] = d[14] ^ d[13] ^ d[10] ^ d[9] ^ d[5] ^ c[5] ^ c[9] ^ c[10] ^ c[13] ^ c[14];
        r_dout[11] = d[15] ^ d[14] ^ d[11] ^ d[10] ^ d[6] ^ c[6] ^ c[10] ^ c[11] ^ c[14] ^ c[15];
        r_dout[12] = d[15] ^ d[8] ^ d[7] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[7] ^ c[8] ^ c[15];
        r_dout[13] = d[9] ^ d[8] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[8] ^ c[9];
        r_dout[14] = d[10] ^ d[9] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[9] ^ c[10];
        r_dout[15] = d[11] ^ d[10] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[10] ^ c[11];
    end
end
reg r_dout_valid = 0;
always @(posedge i_clk) //输入数据在一个时钟内完成 CRC 计算,下一个时钟输出;
begin
    r_dout_valid <= i_din_valid;
end

assign o_dout_valid = r_dout_valid;
assign o_dout = r_dout ;

endmodule // end the crc16_test model;

FPGA 并行实现 CRC 仿真分析

仿真结果和在线工具计算结果进行比较,在线工具地址:http://www.ip33.com/crc.html

(1)编写 tb 文件,对代码进行测试,测试结果如下图所示:

FPGA并行实现CRC(循环冗余码)校验
图 3 FPGA 并行实现 CRC 仿真分析

(2)在线校验。输入需要校验的数据,选择参数模型,输入初始值(此次 crc 结果的前一个 crc 值,代码中初始化为 ffff)。可以对比发现计算无误。

FPGA并行实现CRC(循环冗余码)校验
图 4 CRC 在线计算校验

第一次计算 0011(初始值为 ffff),结果为 1f1f。

第二次计算 0013(初始值为 1f1f),结果为 d2c1。

FPGA 并行实现 CRC 占用资源及时序分析

本次综合参考芯片为:xc7k325tffg676-2

(1)资源使用量如下图所示。

FPGA并行实现CRC(循环冗余码)校验
图 5 FPGA 并行实现 CRC 资源占用情况

(2)模块时钟约束为 100M,裕量如下图所示,满足时序要求。

FPGA并行实现CRC(循环冗余码)校验
图 6 FPGA 并行实现 CRC 时序裕量

Verilog HDL/VHDL 并行实现 CRC 在线生成工具

  1. bues.ch/cms/hacking/crcgen.html
  2. http://outputlogic.com/?page_id=321

CRC 校验的原理、算法、电路结构和 verilog 代码实现

扫码关注尚为网微信公众号

尚为网微信公众号
每天学习电路设计嵌入式系统的专业知识,关注一波,没准就用上了。

原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/986.html

(2)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2021年3月10日 15:30
下一篇 2021年7月1日 17:50

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注