当前位置:网站首页>FPGA手撕代码——CRC校验码的多种Verilog实现方式 (2021乐鑫科技数字IC提前批代码编程)
FPGA手撕代码——CRC校验码的多种Verilog实现方式 (2021乐鑫科技数字IC提前批代码编程)
2022-08-02 10:13:00 【jk_101】
如有侵权,请告知删除,谢谢!!!
完整工程代码在【FPGA探索者】回复【CRC】获取。
用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)
begin
if( rst)
crc_reg_q <= 8’hff;
elsebegin
if(data_valid )
crc_reg_q<= crc_reg_d;// 输入数据有效就更新值
else
crc_reg_q<= crc_reg_q;// 输入数据无效就等待
end
end(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
end
end1.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 // always
endmodule // 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 : [email protected]
// 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
endfunction
endmodule2. 串行计算,串行输出(函数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
end
end(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表可以自行去查找,这里只是抛砖引玉。
————————————————
版权声明:本文为CSDN博主「DengFengLai123」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/DengFengLai123/article/details/124356120
边栏推荐
- TimerTask(addin timer语音)
- npm ERR! 400 Bad Request - PUT xxx - Cannot publish over previously published version “1.0.0“.
- SVN如何删除文件名包含空格的文件
- 软件测试之发现和解决bug
- LayaBox---TypeScript---声明合并
- MySql千万级分页优化,快速插入千万数据方法
- 你好,我的新名字叫“铜锁/Tongsuo”
- Naive Bayesian Method of Li Hang's "Statistical Learning Methods" Notes
- LayaBox - TypeScript - merge statement
- The 38-year-old daughter is not in love and has no stable job, the old mother is crying
猜你喜欢

适配器模式适配出栈和队列及优先级队列

Turning and anti-climbing attack and defense

Verilog's random number system task----$random

链表的实现

8月份的.NET Conf 活动 专注于 .NET MAUI

第十五章 多线程

The heavyweights are coming!Spoilers for the highlights of the Alibaba Cloud Life Science and Intelligent Computing Summit

ConvNeXt论文及实现

How to choose a truly "easy-to-use, high-performance" remote control software

你好,我的新名字叫“铜锁/Tongsuo”
随机推荐
R语言ggpubr包的ggline函数可视化分组折线图、add参数为mean_se和dotplot可视化不同水平均值的折线图并为折线图添加误差线(se标准误差)和点阵图、自定义palette设置颜色
R语言ggplot2可视化:使用ggpubr包的ggbarplot函数可视化水平柱状图(条形图)、使用orientation参数设置柱状图转置为条形图
Event 对象,你很了解吗?
瑞萨RZ/G2L处理器详细测评
List-based queuing and calling system
LayaBox---TypeScript---Symbols
Event object, do you know it well?
R language ggplot2 visualization: use the ggbarplot function of the ggpubr package to visualize the horizontal column chart (bar chart), use the orientation parameter to set the column chart to be tra
只问耕耘,不问收获,其实收获却在耕耘中
Verilog's random number system task----$random
MSYS2 QtCreator Clangd 代码分析找不到 mm_malloc.h的问题补救
Unknown content monitoring
食品安全 | 鱼肝油不是鱼油,家有宝宝的注意了
LayaBox - TypeScript - merge statement
Linux system uninstall, install, upgrade, migrate clickHouse database
LayaBox---TypeScript---Mixins
21年毕业转行软件测试,从0收入到月薪过万,我真的很幸运...
Hongxing, donate another million
You Only Hypothesize Once: 用旋转等变描述子估计变换做点云配准(已开源)
iNFTnews | Seeing the two sides of the metaverse, what is the true Internet and the Internet of value?