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

发布于:2025-09-09 ⋅ 阅读:(20) ⋅ 点赞:(0)

项目背景

工业中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 @(*) begin
    lfsr_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 // always

  always @(posedge clk, posedge rst) begin
    if(rst) begin
      lfsr_q <= {16{1'b1}};
    end
    else begin
      lfsr_q <= crc_en ? lfsr_c : lfsr_q;
    end
  end // 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 @(*) begin
    lfsr_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 // always

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      lfsr_q <= {16{1'b1}};
    end
    else begin
      lfsr_q <= crc_en ? lfsr_c : lfsr_q;
    end
  end // 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 / 1ps

module 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;
        #20
        crc_en = 0;
        
        

    end
    

endmodule

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

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 @(*) begin
    lfsr_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 // always

  always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
      lfsr_q <= {16{1'b1}};
    end
    else begin
      lfsr_q <= crc_en ? lfsr_c : lfsr_q;
    end
  end // 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) begin
    if (!rst_n) begin
        data_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
end

endmodule
`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 / 1ps

module 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;
        #20
        crc_en = 1;
        #20
        crc_en = 0;
        
        

    end
    

endmodule

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) begin
    if (!rst_n) begin
        data_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
end

endmodule

`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往后移了一个时钟周期后,数据计算就正确了,所以我想知道这是什么原因?


网站公告

今日签到

点亮在社区的每一天
去签到