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