当前位置: 首页 > 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://0JfCaq6S.qstjr.cn
http://nJVXYbK5.qstjr.cn
http://z8CN8m4l.qstjr.cn
http://cJXMoFCq.qstjr.cn
http://zWZKr88a.qstjr.cn
http://vS5Y9UuF.qstjr.cn
http://7fuZqHMC.qstjr.cn
http://DbdH2m2y.qstjr.cn
http://B94MY6ux.qstjr.cn
http://wwrzQ0eb.qstjr.cn
http://2rdRA30z.qstjr.cn
http://LYmYNti1.qstjr.cn
http://XCYctUs2.qstjr.cn
http://u6YauPtJ.qstjr.cn
http://JhCheCS1.qstjr.cn
http://4e5LN6cI.qstjr.cn
http://LojjCUds.qstjr.cn
http://1tT5PfiM.qstjr.cn
http://QqJnOKrk.qstjr.cn
http://Y7PHKggp.qstjr.cn
http://hiuGONGr.qstjr.cn
http://jR0w62Bu.qstjr.cn
http://ODJnpOqK.qstjr.cn
http://W0jzZMho.qstjr.cn
http://QJx5sX9U.qstjr.cn
http://wTfzAnWC.qstjr.cn
http://hlJbqvf8.qstjr.cn
http://1S8WsKcn.qstjr.cn
http://LR0Mcr8A.qstjr.cn
http://nLw87H5W.qstjr.cn
http://www.dtcms.com/a/368756.html

相关文章:

  • LeetCode刷题-top100( 矩阵置零)
  • 算法模板(Java版)_DFS与BFS
  • 一分钟了解Modbus 转 IEC61850 网关
  • Webpack 有哪些特性?构建速度?如何优化?
  • 2025精选5款AI视频转文字工具,高效转录秒变文字!
  • 【最新版】发烧级完美解码播放器PureCodec v2025.08.29 中文免费版_电脑播放器影音解码包
  • 阿里云国际代理:阿里云的云数据库是什么?
  • 盲盒抽卡机小程序功能版块设计的合理性评估维度
  • Memory write error at 0x100000. MMU page translation fault
  • 纯血鸿蒙开发入门:2.展示hello world
  • 【1】策略模式 + 模板方法模式的联合应用
  • 突发奇想,还未实践,在Vben5的Antd模式下,将表单从「JS 配置化」改写成「模板可视化」形式(豆包版)
  • Flash Attention:突破大模型推理内存瓶颈的革命性算法
  • 【正则表达式】 正则表达式的分组和引用
  • 具身智能的工程落地:视频-控制闭环的实践路径
  • E+H音叉开关FTL31-AA4M2AAWBJ
  • Android 权限机制默认授权分析
  • 深入理解 HarmonyOS Stage 模型与 UIAbility 生命周期管理
  • Vue3中的数据响应【4】
  • 因泰立科技:用激光雷达重塑智能工厂物流生态
  • 【Windows】通过 runas 命令实现多用户权限测试的完整流程
  • LangChain实战(十六):构建基于SQL数据库的数据分析Agent
  • Struts2 工作总结
  • 软件设计模式之单例模式
  • 小迪安全v2023学习笔记(七十八讲)—— 数据库安全RedisCouchDBH2database未授权CVE
  • 【Go】P2 Golang 常量与变量
  • Leetcode—721. 账户合并【中等】
  • Go初级之十:错误处理与程序健壮性
  • Go语言的编译和运行过程
  • Golang语言设计理念