当前位置: 首页 > news >正文

基于FPGA实现CRC校验码算法(以MODBUS中校验码要求为例)verilog代码+仿真验证

基于FPGA实现CRC校验码算法(以MODBUS中校验码要求为例)verilog代码+仿真验证

  • 项目背景
  • 一、确定校验码相关参数
    • 1.数据输入
    • 2.参数模型
    • 3.初始值异或值
    • 4.输入数据反转(重点)
    • 5.输出数据反转(重点)
    • 6.计算案例
      • 输入不反转,输出不反转
      • 输入反转,输出不反转
      • 输入反转,输出反转
  • 二、代码设计
    • 1.代码在线生成网站(好用)
  • 三、仿真验证
    • 1.输入不反转,输出不反转仿真
    • 2.输入反转,输出不反转
    • 3.输入反转,输出反转
  • 总结

项目背景

工业中MODBUS协议是一个非常普及的一种通信协议,其中MODBUS RTU协议中数据帧格式包括校验码。下面就围绕该格式校验码进行实验,实验工具选择FPGA开发平台,语言verilog。

一、确定校验码相关参数

在进行设计之前你需要知道你应该算出来什么数据,比如输入确定,你的正确输出应该是什么?
两种方法:一种是手算,一种是电脑算^ ^。我选择毫不犹豫的电脑算,手算的话还得去复习数电那些知识,不过后面需要用c语言在嵌入式中实现的话,好像确实需要知道原理,进而就需要知道一步一步算的步骤,不过目前FPGA实现我觉得不需要知道那么深,会应用就行啦。
这边首先利用CRC(循环冗余校验)在线计算 这个网站进行参数的正确设置,然后进行固定输入计算,得到正确的计算结果,进而为你后面仿真结果提供标杆。
在这里插入图片描述

1.数据输入

数据输入注意的点就是根据你的校验码多项式确定,有输入是8位的,有16位的。MODBUS校验码中规定输入是16位的,同时最好是使用16进制格式输入,如果好奇为什么是16进制就去看一下原理,其实本质上有串行和并行的计算模式,就是1位1位算的。

2.参数模型

参数模型其实就是你选择对应的多项式。这边我们从图中可以看到有很多种类型,这边我们选择MODBUS的多项式。其多项式X16+X15+X2+1。这个也就确定了我们多项式的16进制表达是16’h8005.
在这里插入图片描述

3.初始值异或值

参数模型选定之后,初始值和异或值也就确定了。一般都是从0000或者FFFF中选一个。

4.输入数据反转(重点)

REFIN:输入数据是否反转
字节为最小单位,低位变高位,高位变低位,
例如:0001 1001 0010 1010得到的值是1001 1000 0101 0100。
例如:16’h12_34,他反转的话是12自己做从低位到高位的反转,34自己做低位到高位的反转。12 34的位置是相对不变的。

5.输出数据反转(重点)

REFOUT:输出数据是否反转
这个跟输入数据反转又不一样,这个是整体的高位到低位的反转。
例如:0001 1001 0010 1010得到的值是0101 0100 1001 1000。

6.计算案例

输入数据反转和输出数据反转咱们先不勾选,一步一步来计算看结果都是什么,也是为了后续代码验证作参考。

输入不反转,输出不反转

这时候我们选择自定义进行计算,多项式什么和前面MODBUS保持一致,只不过把反转都取消勾选。
输入:1234 输出:6CB6
在这里插入图片描述

输入反转,输出不反转

输入:1234 输出:30E3
16’h12_34的反转是16‘h48_2C
所以不反转,输入482C的结果跟上面是一样的。
在这里插入图片描述

输入反转,输出反转

输入:1234 输出:C70C

在这里插入图片描述

二、代码设计

1.代码在线生成网站(好用)

代码在线生成网站verilog或者VHDL都可
上面通过在线计算网站初步知道了计算过程以及计算结果,下面可以进行代码设计,但是代码甚至都不需要自己进行编写。
进入上面的网站,进行选择即可在线生成,同时生成的代码是并行计算的,不存在时间延迟,即进即出。
在这里插入图片描述
黄色框中选择输入输出的位宽。然后点击apply,进入下一步

在这里插入图片描述
MODBUS的多项式是X16+X15+X2+1,就要按照这个进行设置即可。有一个注意的点:最高位X16是默认为1的,所以在图中并没有看到X16的选项,因此只选择了X15 X2 1 三个。
然后选好之后点击生成verilog代码即可。

//-----------------------------------------------------------------------------
// Copyright (C) 2009 OutputLogic.com
// 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.
//-----------------------------------------------------------------------------
// CRC module for data[15:0] ,   crc[15:0]=1+x^2+x^15+x^16;
//-----------------------------------------------------------------------------
module crc(input [15:0] data_in,input crc_en,output [15:0] crc_out,input rst,input clk);reg [15:0] lfsr_q,lfsr_c;assign crc_out = lfsr_q;always @(*) beginlfsr_c[0] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[15] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[11] ^ data_in[12] ^ data_in[13] ^ data_in[15];lfsr_c[1] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[11] ^ data_in[12] ^ data_in[13] ^ data_in[14];lfsr_c[2] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[14] ^ data_in[0] ^ data_in[1] ^ data_in[14];lfsr_c[3] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[15] ^ data_in[1] ^ data_in[2] ^ data_in[15];lfsr_c[4] = lfsr_q[2] ^ lfsr_q[3] ^ data_in[2] ^ data_in[3];lfsr_c[5] = lfsr_q[3] ^ lfsr_q[4] ^ data_in[3] ^ data_in[4];lfsr_c[6] = lfsr_q[4] ^ lfsr_q[5] ^ data_in[4] ^ data_in[5];lfsr_c[7] = lfsr_q[5] ^ lfsr_q[6] ^ data_in[5] ^ data_in[6];lfsr_c[8] = lfsr_q[6] ^ lfsr_q[7] ^ data_in[6] ^ data_in[7];lfsr_c[9] = lfsr_q[7] ^ lfsr_q[8] ^ data_in[7] ^ data_in[8];lfsr_c[10] = lfsr_q[8] ^ lfsr_q[9] ^ data_in[8] ^ data_in[9];lfsr_c[11] = lfsr_q[9] ^ lfsr_q[10] ^ data_in[9] ^ data_in[10];lfsr_c[12] = lfsr_q[10] ^ lfsr_q[11] ^ data_in[10] ^ data_in[11];lfsr_c[13] = lfsr_q[11] ^ lfsr_q[12] ^ data_in[11] ^ data_in[12];lfsr_c[14] = lfsr_q[12] ^ lfsr_q[13] ^ data_in[12] ^ data_in[13];lfsr_c[15] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[11] ^ data_in[12] ^ data_in[14] ^ data_in[15];end // alwaysalways @(posedge clk, posedge rst) beginif(rst) beginlfsr_q <= {16{1'b1}};endelse beginlfsr_q <= crc_en ? lfsr_c : lfsr_q;endend // always
endmodule // crc

注意这个代码中是不包含输入数据反转、输出数据反转以及异或值的,其中初始值就是lfsr_q <= {16{1’b1}}; 这样设置的。
所以说,后续需要基于这个代码模版进行修改。

三、仿真验证

1.输入不反转,输出不反转仿真

代码:异步复位

//-----------------------------------------------------------------------------
// Copyright (C) 2009 OutputLogic.com
// 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.
//-----------------------------------------------------------------------------
// CRC module for data[15:0] ,   crc[15:0]=1+x^2+x^15+x^16;
//-----------------------------------------------------------------------------
module CRC_MODBUS(input [15:0] data_in,input crc_en,output [15:0] crc_out,input rst_n,input clk);reg [15:0] lfsr_q,lfsr_c;assign crc_out = lfsr_q;always @(*) beginlfsr_c[0] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[15] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[11] ^ data_in[12] ^ data_in[13] ^ data_in[15];lfsr_c[1] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[11] ^ data_in[12] ^ data_in[13] ^ data_in[14];lfsr_c[2] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[14] ^ data_in[0] ^ data_in[1] ^ data_in[14];lfsr_c[3] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[15] ^ data_in[1] ^ data_in[2] ^ data_in[15];lfsr_c[4] = lfsr_q[2] ^ lfsr_q[3] ^ data_in[2] ^ data_in[3];lfsr_c[5] = lfsr_q[3] ^ lfsr_q[4] ^ data_in[3] ^ data_in[4];lfsr_c[6] = lfsr_q[4] ^ lfsr_q[5] ^ data_in[4] ^ data_in[5];lfsr_c[7] = lfsr_q[5] ^ lfsr_q[6] ^ data_in[5] ^ data_in[6];lfsr_c[8] = lfsr_q[6] ^ lfsr_q[7] ^ data_in[6] ^ data_in[7];lfsr_c[9] = lfsr_q[7] ^ lfsr_q[8] ^ data_in[7] ^ data_in[8];lfsr_c[10] = lfsr_q[8] ^ lfsr_q[9] ^ data_in[8] ^ data_in[9];lfsr_c[11] = lfsr_q[9] ^ lfsr_q[10] ^ data_in[9] ^ data_in[10];lfsr_c[12] = lfsr_q[10] ^ lfsr_q[11] ^ data_in[10] ^ data_in[11];lfsr_c[13] = lfsr_q[11] ^ lfsr_q[12] ^ data_in[11] ^ data_in[12];lfsr_c[14] = lfsr_q[12] ^ lfsr_q[13] ^ data_in[12] ^ data_in[13];lfsr_c[15] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[11] ^ data_in[12] ^ data_in[14] ^ data_in[15];end // alwaysalways @(posedge clk or negedge rst_n) beginif(!rst_n) beginlfsr_q <= {16{1'b1}};endelse beginlfsr_q <= crc_en ? lfsr_c : lfsr_q;endend // always
endmodule // crc

测试文件:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/09/04 16:39:07
// Design Name: 
// Module Name: tb_CRC_MODBUS
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////`timescale 1ns / 1psmodule tb_CRC_MODBUS();reg clk;reg rst_n;reg crc_en;reg [15:0] data_in;wire [15:0] crc_out;// 实例化被测试模块CRC_MODBUS uut (.data_in(data_in),.crc_en(crc_en),.crc_out(crc_out),.rst_n(rst_n),.clk(clk));// 生成50MHz时钟always #10 clk = ~clk; // 每个10ns翻转一次,周期20ns -> 50MHz// 测试用例initial begin// 初始化信号clk = 0;rst_n = 0;crc_en = 0;data_in = 16'h0000;// 释放复位#20 rst_n = 1;#10// 测试用例1: 简单数据测试data_in = 16'h12_34;crc_en = 1;#20crc_en = 0;endendmodule

结果:与第二章计算案例结果一致
在这里插入图片描述

2.输入反转,输出不反转

代码:增加关于输入反转的部分功能代码。
这其中发现了很奇怪的问题,因为我本人确实之前也没学习过时序约束相关太多的概念,对这个问题不知道原因?如果有小伙伴看到麻烦帮我回答一下。
首先1234按照字节为单位反转得到482C 这是对的,那么482C就作为输入进行计算,但是计算结果却是800d。
同时还发现无论输入改成什么输出都是800d。
具体的代码在下方,其实就是crc_en与数据反转在同一时刻。我将crc_en往后移了一个时钟周期后,数据计算就正确了,所以我想知道这是什么原因?

在这里插入图片描述
在这里插入图片描述
这两个代码不同的地方就在测试文件,就是我crc_en给的时间点不一样。

//-----------------------------------------------------------------------------
// Copyright (C) 2009 OutputLogic.com
// 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.
//-----------------------------------------------------------------------------
// CRC module for data[15:0] ,   crc[15:0]=1+x^2+x^15+x^16;
//-----------------------------------------------------------------------------
module CRC_MODBUS(input [15:0] data_in,input crc_en,output [15:0] crc_out,input rst_n,input clk);reg [15:0] lfsr_q,lfsr_c;assign crc_out = lfsr_q;always @(*) beginlfsr_c[0] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[15] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[11] ^ data_in[12] ^ data_in[13] ^ data_in[15];lfsr_c[1] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[11] ^ data_in[12] ^ data_in[13] ^ data_in[14];lfsr_c[2] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[14] ^ data_in[0] ^ data_in[1] ^ data_in[14];lfsr_c[3] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[15] ^ data_in[1] ^ data_in[2] ^ data_in[15];lfsr_c[4] = lfsr_q[2] ^ lfsr_q[3] ^ data_in[2] ^ data_in[3];lfsr_c[5] = lfsr_q[3] ^ lfsr_q[4] ^ data_in[3] ^ data_in[4];lfsr_c[6] = lfsr_q[4] ^ lfsr_q[5] ^ data_in[4] ^ data_in[5];lfsr_c[7] = lfsr_q[5] ^ lfsr_q[6] ^ data_in[5] ^ data_in[6];lfsr_c[8] = lfsr_q[6] ^ lfsr_q[7] ^ data_in[6] ^ data_in[7];lfsr_c[9] = lfsr_q[7] ^ lfsr_q[8] ^ data_in[7] ^ data_in[8];lfsr_c[10] = lfsr_q[8] ^ lfsr_q[9] ^ data_in[8] ^ data_in[9];lfsr_c[11] = lfsr_q[9] ^ lfsr_q[10] ^ data_in[9] ^ data_in[10];lfsr_c[12] = lfsr_q[10] ^ lfsr_q[11] ^ data_in[10] ^ data_in[11];lfsr_c[13] = lfsr_q[11] ^ lfsr_q[12] ^ data_in[11] ^ data_in[12];lfsr_c[14] = lfsr_q[12] ^ lfsr_q[13] ^ data_in[12] ^ data_in[13];lfsr_c[15] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[11] ^ data_in[12] ^ data_in[14] ^ data_in[15];end // alwaysalways @(posedge clk or negedge rst_n) beginif(!rst_n) beginlfsr_q <= {16{1'b1}};endelse beginlfsr_q <= crc_en ? lfsr_c : lfsr_q;endend // always
endmodule // crc
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/09/05 16:09:25
// Design Name: 
// Module Name: DATA_IN_REV
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////module DATA_IN_REV(input [15:0] data_in,output reg [15:0] data_in_rev,input rst_n,input clk
);// 按字节内部反转数据
always @(posedge clk or negedge rst_n) beginif (!rst_n) begindata_in_rev <= 16'h0000;end else begin// 反转低位字节 (data_in[7:0])data_in_rev[0] <= data_in[7];data_in_rev[1] <= data_in[6];data_in_rev[2] <= data_in[5];data_in_rev[3] <= data_in[4];data_in_rev[4] <= data_in[3];data_in_rev[5] <= data_in[2];data_in_rev[6] <= data_in[1];data_in_rev[7] <= data_in[0];// 反转高位字节 (data_in[15:8])data_in_rev[8] <= data_in[15];data_in_rev[9] <= data_in[14];data_in_rev[10] <= data_in[13];data_in_rev[11] <= data_in[12];data_in_rev[12] <= data_in[11];data_in_rev[13] <= data_in[10];data_in_rev[14] <= data_in[9];data_in_rev[15] <= data_in[8];end
endendmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/09/05 16:28:29
// Design Name: 
// Module Name: CRC
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////module CRC(input [15:0] data_in,input crc_en,output [15:0] crc_out,input rst_n,input clk);
wire [15:0] data_in_rev;
// 实例化数据反转模块
DATA_IN_REV data_rev_inst (.data_in(data_in),.data_in_rev(data_in_rev),.rst_n(rst_n),.clk(clk)
);// 实例化CRC模块,使用反转后的数据
CRC_MODBUS crc_inst (.data_in(data_in_rev), // 使用反转后的数据.crc_en(crc_en),.crc_out(crc_out),.rst_n(rst_n),.clk(clk)
);
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/09/04 16:39:07
// Design Name: 
// Module Name: tb_CRC_MODBUS
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////`timescale 1ns / 1psmodule tb_CRC();reg clk;reg rst_n;reg crc_en;reg [15:0] data_in;wire [15:0] crc_out;// 实例化被测试模块CRC uut (.data_in(data_in),.crc_en(crc_en),.crc_out(crc_out),.rst_n(rst_n),.clk(clk));// 生成50MHz时钟always #10 clk = ~clk; // 每个10ns翻转一次,周期20ns -> 50MHz// 测试用例initial begin// 初始化信号clk = 0;rst_n = 0;crc_en = 0;data_in = 16'h0000;// 释放复位#20 rst_n = 1;#10// 测试用例1: 简单数据测试data_in = 16'h12_34;#20crc_en = 1;#20crc_en = 0;endendmodule

3.输入反转,输出反转

增加了输出反转的功能代码。结果正确。
在这里插入图片描述

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/09/05 16:09:25
// Design Name: 
// Module Name: DATA_IN_REV
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////module DATA_OUT_REV(input [15:0] data_in,output reg [15:0] data_in_rev,input rst_n,input clk
);// 按字节内部反转数据
always @(posedge clk or negedge rst_n) beginif (!rst_n) begindata_in_rev <= 16'h0000;end else begin// 反转低位字节 (data_in[7:0]) data_in_rev[0] <=      data_in[15];data_in_rev[1] <=      data_in[14];data_in_rev[2] <=      data_in[13];data_in_rev[3] <=      data_in[12];data_in_rev[4] <=      data_in[11];data_in_rev[5] <=      data_in[10];data_in_rev[6] <=      data_in[9]; data_in_rev[7] <=      data_in[8]; // 反转高位字节 (data_in[15:8])data_in_rev[8]  <=     data_in[7];data_in_rev[9]  <=     data_in[6];data_in_rev[10] <=     data_in[5];data_in_rev[11] <=     data_in[4];data_in_rev[12] <=     data_in[3];data_in_rev[13] <=     data_in[2];data_in_rev[14] <=     data_in[1];data_in_rev[15] <=     data_in[0];end
endendmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/09/05 16:28:29
// Design Name: 
// Module Name: CRC
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////module CRC(input [15:0] data_in,input crc_en,output [15:0] crc_out,input rst_n,input clk);
wire [15:0] data_in_rev;
wire [15:0] crc_out_rev;DATA_OUT_REV data_out_rev_inst (.data_in(crc_out_rev),.data_in_rev(crc_out),.rst_n(rst_n),.clk(clk)
);
// 实例化数据反转模块
DATA_IN_REV data_rev_inst (.data_in(data_in),.data_in_rev(data_in_rev),.rst_n(rst_n),.clk(clk)
);// 实例化CRC模块,使用反转后的数据
CRC_MODBUS crc_inst (.data_in(data_in_rev), // 使用反转后的数据.crc_en(crc_en),.crc_out(crc_out_rev),.rst_n(rst_n),.clk(clk)
);
endmodule

总结

其实CRC计算本身也不是要求即入即出,但是对于这个问题:还是很想知道原因!!

代码:增加关于输入反转的部分功能代码。
这其中发现了很奇怪的问题,因为我本人确实之前也没学习过时序约束相关太多的概念,对这个问题不知道原因?如果有小伙伴看到麻烦帮我回答一下。
首先1234按照字节为单位反转得到482C 这是对的,那么482C就作为输入进行计算,但是计算结果却是800d。
同时还发现无论输入改成什么输出都是800d。
具体的代码在下方,其实就是crc_en与数据反转在同一时刻。我将crc_en往后移了一个时钟周期后,数据计算就正确了,所以我想知道这是什么原因?

http://www.xdnf.cn/news/1470907.html

相关文章:

  • Python命令行选项(flags)解析
  • 漫画布局面板设计系统
  • 事务管理的选择:为何 @Transactional 并非万能,TransactionTemplate 更值得信赖
  • 从Java全栈到前端框架:一位程序员的实战之路
  • NestJS 整合 Redis 特性详解
  • 2025年统计与数据分析领域专业认证发展指南
  • [TryHackMe]Wordpress: CVE-2021-29447(wp漏洞利用-SSRF+WpGetShell)
  • harmony 中集成 tuanjie/unity
  • Leetcode每日一练--20
  • ESP-IDF串口中断接收
  • 概率论第二讲——一维随机变量及其分布
  • 广告投放全链路解析
  • B.50.10.01-消息队列与电商应用
  • PyInstaller完整指南:将Python程序打包成可执行文件
  • Nacos中yaml文件新增配置项不规范导致项目启动失败
  • 在 CentOS 上完整安装 Docker 指南
  • SQLServer死锁监测方案:如何使用XE.Core解析xel文件里包含死锁扩展事件的死锁xml
  • LightDock.server liunx 双跑比较
  • 消息队列-ubutu22.04环境下安装
  • 激光雷达与IMU时间硬件同步与软件同步区分
  • 深度学习之第八课迁移学习(残差网络ResNet)
  • ChartGPT深度体验:AI图表生成工具如何高效实现数据可视化与图表美化?
  • RequestContextFilter介绍
  • 53.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--新增功能--集成短信发送功能
  • 《C++变量命名与占位:深入探究》
  • SDRAM详细分析—06 存储单元架构和放大器
  • RPC内核细节(转载)
  • 软件设计模式之单例模式
  • 实战:Android 自定义菊花加载框(带超时自动消失)
  • 微型导轨如何实现智能化控制?