0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

用Verilog实现CRC-8的串行计算

FPGA自习室 来源:FPGA自习室 作者:FPGA自习室 2021-03-12 17:47 次阅读

(2021乐鑫科技数字IC提前批代码编程

Verilog实现CRC-8的串行计算,G(D)=D8+D2+D+1,计算流程如下图所示:

一、分析

CRC循环冗余校验码(Cyclic Redundancy Check),检错码。

(1)该题目所述为CRC-8,即输出8位CRC校验值,给定一段长为N-bit的有效输入序列,输出(N+8)-bit的数据,其中前N-bit数据为输入的原始数据,添加的8-bit数据为CRC校验数据;

(2)该CRC-8的生成多项式为G(D)=D8+D2+D+1,对CRC进行简化表示时可以忽略最高位的D8,结合图示中三个异或运算的位置更容易理解生成多项式,8位CRC有8个寄存器C0~C7,根据多项式,C0、C1和C2的输入是由异或运算而来;

二、Verilog编程

1. 并行计算,串行输出

对于输入位宽为1的输入,这种方法的计算非常简单,直接根据生成多项式运算。

(注意!如果输入位宽不为1,则需要根据多项式进行化简,可以使用http://outputlogic.com/?page_id=321生成运算逻辑和代码)

1.1 自己一步一步写

完整工程代码在【FPGA探索者】公众号回复【CRC】获取。

(1)先定义8个寄存器reg [7:0]

reg [7:0] crc_reg_q;// 寄存器 Q 输出端reg [7:0] crc_reg_d;// 寄存器 D 输入端

(对crc_reg_d,使用always赋值就定义成reg,使用assign就定义成wire)

(2)异或计算

寄存器0的输入crc_reg_d[0],来自寄存器7的输出crc_reg_q[7]和数据输入data_in异或运算,即:

crc_reg_d [0] = crc_reg_q[7] ^ data_in;

同理可得:

always @ (*)begin crc_reg_d[0] = crc_reg_q[7] ^ data_in;crc_reg_d[1] = crc_reg_q[7] ^ data_in ^ crc_reg_q[0];crc_reg_d[2] = crc_reg_q[7] ^ data_in ^ crc_reg_q[1];crc_reg_d[3] = crc_reg_q[2];crc_reg_d[4] = crc_reg_q[3];crc_reg_d[5] = crc_reg_q[4];crc_reg_d[6] = crc_reg_q[5];crc_reg_d[7] = crc_reg_q[6];end

上述使用组合逻辑实现异或运算和数据的传递,另外,对于每个寄存器的输入到输出(D端到Q端),使用时序逻辑,并且按照题目要求,设置初始值为全1,将数据有效标志作为控制逻辑:

always @ (posedge clk)beginif(rst) crc_reg_q <= 8’hff; elsebegin if(data_valid ) crc_reg_q<= crc_reg_d;// 输入数据有效就更新值else crc_reg_q<= crc_reg_q;// 输入数据无效就等待 endend

(3)串行输出

上述已经实现了并行的 CRC,计算出的 CRC 结果就是直接的 8 位 CRC,按照题目要求,需要串行输出 CRC 结果。

思路:写一个计数器,当需要输出 CRC 时,串行计数输出,实现并串转换。这里,由于题目给了一个信号 crc_start,我把这个信号作为 CRC 的标志,当 data_valid 有效时表示输入的是数据,当 data_valid 无效且crc_start 有效表示数据输入完毕,该输出 CRC 了。

reg [2:0] count;always @ (posedge clk)begin if(rst)begin crc_out <= 0; count<= 0; end elsebegin if(data_valid) begin crc_out <= data_in; crc_valid <= 1'b0; end elseif(crc_start)begin count <= count + 1'b1; crc_out <= crc_reg_q [7-count]; crc_valid <= 1'b1; end elsebegin crc_valid <= 1'b0; end endend

完整工程代码在【FPGA探索者】公众号回复【CRC】获取。

1.2 CRC Generator自动生成

在Step1中,根据要求,1处表示输入数据位宽为1,2处CRC输出8位,3处选择自定义CRC的多项式,4处点击运用设定,然后进入Step2。

根据生成多项式,勾选1、X1、X2即可(对应1+D1+D2,最高位的D8不用管)。

//-----------------------------------------------------------------------------// Copyright (C) 2009 OutputLogic.com // This source file may be used and distributedwithout restriction // provided that this copyright statement is notremoved from the file // and that any derivative work contains theoriginal copyright notice // and the associated disclaimer. // // THIS SOURCE FILE IS PROVIDED "ASIS" AND WITHOUT ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, WITHOUTLIMITATION, THE IMPLIED // WARRANTIES OF MERCHANTIBILITY AND FITNESS FORA PARTICULAR PURPOSE. //-----------------------------------------------------------------------------// CRC module for data[0:0] , crc[7:0]=1+x^1+x^2+x^8;//-----------------------------------------------------------------------------module crc( input [0: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 @(*) begin lfsr_c[0] = lfsr_q[7] ^ data_in[0]; lfsr_c[1] = lfsr_q[0] ^ lfsr_q[7]^ data_in[0]; lfsr_c[2] = lfsr_q[1] ^ lfsr_q[7]^ data_in[0]; lfsr_c[3] = lfsr_q[2]; lfsr_c[4] = lfsr_q[3]; lfsr_c[5] = lfsr_q[4]; lfsr_c[6] = lfsr_q[5]; lfsr_c[7] = lfsr_q[6]; end // always always @(posedge clk, posedge rst) begin if(rst) begin lfsr_q <= {8{1'b1}}; end else begin lfsr_q <= crc_en ? lfsr_c: lfsr_q; end end // alwaysendmodule // crc

将上述代码按照题目要求改变输入输出的名称,并进行串并转换(并->串)即可。

1.3 easics自动生成

https://www.easics.com/crctool

(1)1处选择CRC的生成多项式,这里与1.2的不同在于,要把最高位的D8选上,easics能识别的CRC协议更多;

(2)2处自动识别出这个CRC多项式其实是CRC8 ATM HEC协议使用的 CRC;

(3)3处设置输入数据位宽为1;

(4)选择生成Verilog代码;

(5)下载代码。

仔细阅读代码注释,注意!

convention: the first serial bit is D[0]

数据的最低位先输出,此代码将会把低位作为异或移出位,而上面已经提到的两种方法均是将最高位作为移出位去异或,所以,代码中需要稍作修改,将d[0]改成d[7],d[1]改成d[6],…,以此类推,c[0]- c[7]不要变。

有兴趣的可以去看看【大小端问题】,在不同处理器、不同协议中非常常见。

///////////////////////////////////////////////////////////////////////////////// Copyright (C) 1999-2008 Easics NV.// This source file may be used and distributedwithout restriction// provided that this copyright statement is notremoved from the file// and that any derivative work contains theoriginal copyright notice// and the associated disclaimer.//// THIS SOURCE FILE IS PROVIDED "AS IS"AND WITHOUT ANY EXPRESS// OR IMPLIED WARRANTIES, INCLUDING, WITHOUTLIMITATION, THE IMPLIED// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR APARTICULAR PURPOSE.//// Purpose : synthesizable CRC function// *polynomial: x^8 + x^2 + x^1 + 1// * datawidth: 1//// Info : tools@easics.be// http://www.easics.com///////////////////////////////////////////////////////////////////////////////module CRC8_D1; //polynomial: x^8 + x^2 + x^1 + 1 // datawidth: 1 //convention: the first serial bit is D[0] function[7:0] nextCRC8_D1; inputData; input[7:0] crc; reg [0:0]d; reg [7:0]c; reg [7:0]newcrc; begin d[0] =Data; c = crc; newcrc[0]= d[0] ^ c[7]; newcrc[1]= d[0] ^ c[0] ^ c[7]; newcrc[2]= d[0] ^ c[1] ^ c[7]; newcrc[3]= c[2]; newcrc[4]= c[3]; newcrc[5]= c[4]; newcrc[6]= c[5]; newcrc[7]= c[6]; nextCRC8_D1 = newcrc; end endfunctionendmodule

2. 串行计算,串行输出(函数function用法)

CRC计算的重要思想是不断的消除最高位。

(1)新建函数function

Verilog函数名为next_crc,输入信号为 data_in 和 current_crc,输出信号为8位的新 crc。

函数功能为:根据输入信号data_in,跳转CRC的状态;

函数的设计逻辑为:

(a)将CRC寄存器的数据左移1位,低位补零,得到

{current_crc[6:0],1'b0} (其中{ }为位拼接符);

(b)新输入的数据data_in和移出的CRC最高位做异或得到

current_crc[7]^data_in;

(c)使用位拼接符对异或结果进行位扩展,CRC-8进行8位的扩展,得到

{8{current_crc[7]^data_in}};

(d)扩展后的数据和生成多项式进行与运算,得到

{8{current_crc[7]^data_in}}&(8'h07);

(e)将(a)的数据和(d)的数据进行异或运算,得到CRC结果;

next_crc = {current_crc[6:0],1'b0} ^({8{current_crc[7]^data_in}} & (8'h07));

上述,(a)是对CRC低位的处理,(b)-(d)是对CRC最高位的处理。

8’h07从何而来?

因为生成多项式G(D) = D8+D2+D1+D0,前面提到了最高位的D8不用管,那么使用8位去表示为0000_0111,即低3位为1,其余为0,即8’h07。

function [7:0] next_crc; inputdata_in; input[7:0] current_crc; begin next_crc = {current_crc[6:0],1'b0} ^ ({8{current_crc[7]^data_in}} &(8'h07)); end endfunction

(2)调用function函数

初始化时给寄存器赋值全为1,当数据有效时,进行CRC计算。

reg [7:0] crc_reg;always @ (posedge clk)begin if(rst)begin crc_reg <= 8'hff; end elsebegin if(data_valid) begin crc_reg <= next_crc(data_in, crc_reg); end endend

(3)串行输出(串并转换)

按照上面的老方法,串并转换(并->串)。

完整工程代码在【FPGA探索者】公众号回复【CRC】获取。

输入32个1,先输出输入的32个1,紧跟着输出32个1的CRC校验值8’b00001111。

三、原理图设计

使用Quartus原理图设计,调用DFF触发器和XOR异或门搭建题目所示的CRC逻辑。

这里没有做data_valid的控制,输入数据是连续的32个1,输入完成后的CRC值是8’h0f,串行输出8位二进制数据 8’b00001111。

四、扩展

1. 并行计算并行输出

(1)对于单bit输入的序列,只要将并行计算串行输出的串并转换去掉,直接输出8-bit的CRC校验值即可;

(2)对于多bit同时输入的序列,通过介绍的两个在线平台去生成运算逻辑(笔试肯定不会丧心病狂到考多bit并行);

2. 查表法

实际工程中,为了减少运算量,还经常使用一种查表法,将CRC的校验表直接存储在ROM中,进行索引查找,常见的CRC表可以自行去查找,这里只是抛砖引玉。

责任编辑:lq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1603

    文章

    21331

    浏览量

    593304
  • crc
    crc
    +关注

    关注

    0

    文章

    191

    浏览量

    29200
  • Verilog
    +关注

    关注

    28

    文章

    1327

    浏览量

    109313

原文标题:FPGA手撕代码——CRC校验码的多种Verilog实现方式

文章出处:【微信号:FPGA_Study,微信公众号:FPGA自习室】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    STM32L05x的CRC模块做modbus CRC16计算,结果不正确是为什么?

    根据参考文档,CRC模块可以配置CRC多项式,应该可以做(Modbus)CRC16计算,自己试了一下,发现结果不正确,总是一个固定值,不知道为什么?另外多项式应该是0x8005还是0x
    发表于 04-29 06:50

    verilog中for循环是串行执行还是并行执行

    中的for循环也是并行执行的。 Verilog中的for循环可以用来实现重复的操作,例如在一个时钟周期中对多个电路进行操作。在循环内部,多个语句可以同时执行,而不受循环次数的限制。这种并行执行的机制使得Verilog在硬件设计中
    的头像 发表于 02-22 16:06 707次阅读

    fpga报告crc故障是什么意思

    方法,通过对发送的数据进行计算并附加到数据末尾,接收方能够使用相同的校验算法来检测传输中的错误。CRC可以检测多种不同类型的错
    的头像 发表于 01-04 11:06 460次阅读

    CRC校验原理及其软件实现

    电子发烧友网站提供《CRC校验原理及其软件实现.pdf》资料免费下载
    发表于 11-16 10:11 0次下载
    <b class='flag-5'>CRC</b>校验原理及其软件<b class='flag-5'>实现</b>

    CRC校验码的多种Verilog实现方式

    CRC-8的生成多项式为G(D)=D8+D2+D+1,对CRC进行简化表示时可以忽略最高位的D8,结合图示中三个异或运算的位置更容易理解生成多项式,8位CRC有8个寄存器C0~C7,根据多项式,C0、C1和C2的输入是由异或运
    的头像 发表于 11-12 09:53 1965次阅读
    <b class='flag-5'>CRC</b>校验码的多种<b class='flag-5'>Verilog</b><b class='flag-5'>实现</b>方式

    N32G45x硬件CRC计算Modbus的CRC16

    以前都是使用软件CRC,浪费计算时间,有硬件CRC不用,真是可惜。本次使用硬件CRC对ModBus的CRC进行
    的头像 发表于 10-16 15:01 575次阅读
    N32G45x硬件<b class='flag-5'>CRC</b><b class='flag-5'>计算</b>Modbus的<b class='flag-5'>CRC</b>16

    STM32F3 CRC计算单元

    8,16,32位输入 数据大小 •CRC计算最多在4个AHB时钟周期(HCLK)内完成 •通用8位寄存器(可用于临时存储)
    发表于 09-12 08:20

    STM32F0 CRC计算单元介绍

    可用于避免AHB总线在计算过程中停滞 时间,从而为其他并发操作释放AHB1总线  它还有一个通用的8位寄存器(可用于临时存储)  新模式  可编程CRC初始值,在CRC
    发表于 09-12 08:07

    如何使用软件算法计算CRC-16/8的结果

    应用程序:使用查询表或应用软件算法计算 CRC-32/16/8 结果 BSP 版本: NUC230/240 Series BSP CMSIS v3.01.002 硬件: NuTiny - EVB
    发表于 08-31 09:50

    GD32VF103片内CRC单元的应用方法

    进行计算 提供一个与计算无关的独立8位寄存器CRC_FDATA,可以供其他任何外设随时使用 实验部分 本期实验主要让大家了解CRC
    发表于 08-16 07:13

    verilog每日一练】位拼接符的应用:如何实现串行数据的接收与输出

    若1bit串行信号data_in按高位先发的顺序传输一个8bit的数据,data_en为使能信号,请用位拼接符实现串行数据的接收并输出接收的8
    发表于 08-07 16:05

    CRC校验码的多种Verilog实现方式

    CRC循环冗余校验码(Cyclic Redundancy Check),检错码。
    的头像 发表于 06-21 15:03 3008次阅读
    <b class='flag-5'>CRC</b>校验码的多种<b class='flag-5'>Verilog</b><b class='flag-5'>实现</b>方式

    GD32开发实战指南(基础篇) 第18章 CRC校验

    循环冗余校验(CRC)计算单元是根据固定的生成多项式得到任一32位全字的CRC计算结果。
    的头像 发表于 05-19 20:32 3341次阅读
    GD32开发实战指南(基础篇) 第18章 <b class='flag-5'>CRC</b>校验

    CRC校验的问题

    ------------------------------------------------------------*/ #define BUFFER_SIZE_55/* CRC7_DATA8_TEST5[] is 5-byte long*/ #define
    发表于 05-11 12:46

    Modbus RTU CRC校验值怎么计算呢?

    Modbus RTU CRC校验详细步骤?CRC值怎么计算
    发表于 05-05 16:05