admin管理员组

文章数量:1130349

Verilog

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) beginif(~rst_n) begind<= 0;end else if(vld) begind<=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) beginif(~rst_n) beginnewcrc<= 16'hFFFF;end else if(count==8'd5) beginnewcrc[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) beginif(~rst_n) begincount<= 0;end else if(vld) begincount<=1 ;end else if (count==8'd8) begincount<=0;	 end else if (count!==0) begincount<=count+1;end
end
reg[15:0] crc_reg;
reg crc_vld;
always @(posedge sys_clk or negedge rst_n) beginif(~rst_n) begincrc_reg<= 0;end else if(count==8'd8) begincrc_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 Inputssys_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) beginif(~rst_n) beginvld<= 0;end else if(vld) beginvld<=0 ;end
endendmodule

仿真波形:

从波形中可以看出,发送0x11,得到的crc为4c7f,和使用crc计算器计算的是一致的。
crc计算器链接:.html
crc生成器链接:

Verilog

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) beginif(~rst_n) begind<= 0;end else if(vld) begind<=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) beginif(~rst_n) beginnewcrc<= 16'hFFFF;end else if(count==8'd5) beginnewcrc[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) beginif(~rst_n) begincount<= 0;end else if(vld) begincount<=1 ;end else if (count==8'd8) begincount<=0;	 end else if (count!==0) begincount<=count+1;end
end
reg[15:0] crc_reg;
reg crc_vld;
always @(posedge sys_clk or negedge rst_n) beginif(~rst_n) begincrc_reg<= 0;end else if(count==8'd8) begincrc_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 Inputssys_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) beginif(~rst_n) beginvld<= 0;end else if(vld) beginvld<=0 ;end
endendmodule

仿真波形:

从波形中可以看出,发送0x11,得到的crc为4c7f,和使用crc计算器计算的是一致的。
crc计算器链接:.html
crc生成器链接:

本文标签: Verilog