基于FPGA实现CRC校验码算法(以MODBUS中校验码要求为例)verilog代码+仿真验证
项目背景
工业中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往后移了一个时钟周期后,数据计算就正确了,所以我想知道这是什么原因?