Verilog --crc16 modbus

Verilog --crc16 modbus

1 、CRC 校验原理
CRC 的基本原理就是在一个 n 位二进制数据序列之后附加一个 r 位二进制检验码序列,从而构成一个总长为 p = n + r 位的二进制序列。这里附加在数据序列之后的 CRC 码与数据序列的内容之间存在某种特定的关系。
如果在数据传输过程中,由于噪声或传输特性不理想而使数据序列中的某一位或某些位发生错误,这种特定关系就会被破坏。可见在数据的接收端通过检查这种特定关系,可以很容易地实现对数据传输正确性的检验。

下面是verilog代码:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: cui
// 
// Create Date: 2020/05/24 17:04:30
// Design Name: 
// Module Name: CRC16_modbus 
// Width:8
// Poly:0x8005
// Init:0xFFFF;
// Refin:True;
// Refout:True;
// Xorout:0x0000;
// 
//////////////////////////////////////////////////////////////////////////////////


module CRC16_modbus(
    input sys_clk,
    input rst_n,
    input[7:0] data_l,
    input vld,
    output crc_vld,
    output crc_reg

    );
reg[7:0] d;
always @(posedge sys_clk or negedge rst_n) begin
	if(~rst_n) begin
		 d<= 0;
	end else if(vld) begin
		 d<=data_n ;
	end
end
reg[15:0] crc;
reg[15:0] newcrc;
reg[15:0] nextCRC16_D8;
wire[15:0] c;
assign c=newcrc;
always @(posedge sys_clk or negedge rst_n) begin
	if(~rst_n) begin
		 newcrc<= 16'hFFFF;
	end else if(count==8'd5) begin
	newcrc[0] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[2] ^ d[1] ^ d[0] ^ c[8] ^ c[9] ^ c[10] ^ c[11] ^ c[12] ^ c[13] ^ c[14] ^ c[15];
    newcrc[1] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[2] ^ d[1] ^ c[9] ^ c[10] ^ c[11] ^ c[12] ^ c[13] ^ c[14] ^ c[15];
    newcrc[2] = d[1] ^ d[0] ^ c[8] ^ c[9];
    newcrc[3] = d[2] ^ d[1] ^ c[9] ^ c[10];
    newcrc[4] = d[3] ^ d[2] ^ c[10] ^ c[11];
    newcrc[5] = d[4] ^ d[3] ^ c[11] ^ c[12];
    newcrc[6] = d[5] ^ d[4] ^ c[12] ^ c[13];
    newcrc[7] = d[6] ^ d[5] ^ c[13] ^ c[14];
    newcrc[8] = d[7] ^ d[6] ^ c[0] ^ c[14] ^ c[15];
    newcrc[9] = d[7] ^ c[1] ^ c[15];
    newcrc[10] = c[2];
    newcrc[11] = c[3];
    newcrc[12] = c[4];
    newcrc[13] = c[5];
    newcrc[14] = c[6];
    newcrc[15] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[2] ^ d[1] ^ d[0] ^ c[7] ^ c[8] ^ c[9] ^ c[10] ^ c[11] ^ c[12] ^ c[13] ^ c[14] ^ c[15];
    nextCRC16_D8 = newcrc;
	end
end
reg[7:0] count;
always @(posedge sys_clk or negedge rst_n) begin
	if(~rst_n) begin
		 count<= 0;
	end else if(vld) begin
		 count<=1 ;
    end else if (count==8'd8) begin
    	 count<=0;	 
	end else if (count!==0) begin
		 count<=count+1;
	end
end
reg[15:0] crc_reg;
reg crc_vld;
always @(posedge sys_clk or negedge rst_n) begin
	if(~rst_n) begin
		 crc_reg<= 0;
	end else if(count==8'd8) begin
		 crc_reg<=crc_n^xor_a ;
		 crc_vld<=1;
	end else begin 
		 crc_vld<=0;
	end
end
parameter xor_a=16'd0;
wire[7:0] data_n;
assign data_n[7]=data_l[0];
assign data_n[6]=data_l[1];
assign data_n[5]=data_l[2];
assign data_n[4]=data_l[3];
assign data_n[3]=data_l[4];
assign data_n[2]=data_l[5];
assign data_n[1]=data_l[6];
assign data_n[0]=data_l[7];

wire[15:0] crc_n;
assign crc_n[15]=nextCRC16_D8[0];
assign crc_n[14]=nextCRC16_D8[1];
assign crc_n[13]=nextCRC16_D8[2];
assign crc_n[12]=nextCRC16_D8[3];
assign crc_n[11]=nextCRC16_D8[4];
assign crc_n[10]=nextCRC16_D8[5];
assign crc_n[9]=nextCRC16_D8[6];
assign crc_n[8]=nextCRC16_D8[7];
assign crc_n[7]=nextCRC16_D8[8];
assign crc_n[6]=nextCRC16_D8[9];
assign crc_n[5]=nextCRC16_D8[10];
assign crc_n[4]=nextCRC16_D8[11];
assign crc_n[3]=nextCRC16_D8[12];
assign crc_n[2]=nextCRC16_D8[13];
assign crc_n[1]=nextCRC16_D8[14];
assign crc_n[0]=nextCRC16_D8[15];

endmodule

testbench:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Module Name: vtf_crc16_test
//////////////////////////////////////////////////////////////////////////////////

module vtf_crc16_test;
// Inputs
reg sys_clk;
reg rst_n ;
// Outputs
wire crc_vld;
wire[15:0] crc_reg;
reg[7:0] data;
reg vld;
// Instantiate the Unit Under Test (UUT)
CRC16_modbus uut (
    .sys_clk(sys_clk),   
    .rst_n(rst_n),
    .vld(vld),
    .data_l(data),
    .crc_vld(crc_vld),
    .crc_reg(crc_reg)
    
 );

initial 
begin
// Initialize Inputs
    sys_clk = 0;
    rst_n = 0 ;
    vld=0;
    #1000 ;
    rst_n = 1;
    #10 begin 
    	data=8'h11;
    end 
    #10 @(posedge sys_clk)begin 
    	vld=1;
    end
    #500 begin 
    	data=8'hFF;
    end
    #10 @(posedge sys_clk)begin 
    	vld=1;
    end
    #2000 begin 
    	$finish; 
    end
end
//Create clock
always #10 sys_clk = ~ sys_clk; 
always @(posedge sys_clk or negedge rst_n) begin
	if(~rst_n) begin
		 vld<= 0;
	end else if(vld) begin
		 vld<=0 ;
	end
end






endmodule


仿真波形:
Verilog --crc16 modbus_第1张图片
从波形中可以看出,发送0x11,得到的crc为4c7f,和使用crc计算器计算的是一致的。
crc计算器链接:http://www.ip33.com/crc.html
crc生成器链接:https://www.easics.com/webtools/crctool

你可能感兴趣的:(Verilog --crc16 modbus)