RTL design (7)-CRC check code generator

Error detection

In the process of data transmission, no matter how perfect the design of the transmission system is, errors will always exist . This error may cause one or more frames transmitted on the link to be destroyed (bit errors occur, 0 becomes 1, or 1 becomes 0), so that the receiver receives the wrong data. In order to improve the accuracy of the data received by the receiver as much as possible, it is necessary to perform error detection on the data before the receiver receives the data , and the receiver actually accepts the data if and only when the detection result is correct.

A [r-bit binary check code] is appended after a [p-bit binary data sequence] to form a binary sequence with a total length of [p+r] . There is a specific relationship between the check code attached to the data sequence and the p-bit binary sequence. If errors occur in some bits in the data sequence due to interference or other reasons, this characteristic relationship will be destroyed. Therefore, the correctness of the received data can be verified by checking the specific relationship .

There are many ways to detect, the common ones are parity check, accumulation and check, and cyclic redundancy check.
(1) Parity check, the detection error probability is about 50%, which is simple but low in transmission efficiency. Parity is mostly used for low-speed data communication, such as RS232.
(2) Accumulation and verification, the detection error probability is about 1/256, simple to implement and widely used.
(3) CRC verification, as long as the number of divisor polynomials selected is large enough, the probability of detection error is almost non-existent.

Cyclic redundancy check

Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here

CRC check code generator

Different generator polynomials have different error detection capabilities. Choose CRC-16 generator polynomial:
G(X) = x 16 + x 15 + x 2 + 1

There are two types of CRC check code generators: serial CRC check code generator and parallel CRC check code generator.

Generally, the value of the CRC check code can be obtained through a linear shift register and an XOR gate . The linear shift register shifts one bit at a time to complete the division function, and the XOR gate completes the subtraction function without carry. If the quotient is 1, the divisor is XORed from the higher-order bits of the dividend, and the shift register is shifted to the right by one bit, ready to perform operations on the lower bits of the dividend; if the quotient is 0, the shift register is shifted to the right by one Bit.

The circuit structure diagram is as follows:
Insert picture description here

The serial CRC check code generator shifts 1 bit per clock, and the parallel CRC check code generator shifts 16 bits per clock cycle (implemented by combinational logic).

CRC can be calculated online at the following website:
http://www.ip33.com/crc.html
Insert picture description here
00AA -> 03FC
AA89 -> 7F3F
2853 -> F1EA

Parallel CRC-16 check code generator

parallelCRC16.v

`timescale 1ns / 1ps

// Company: 
// Engineer: 
// 
// Create Date: 2020/12/14
// Author Name: Sniper
// Module Name: parallelCRC16
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 


module parallelCRC16
#(
    parameter DATA_WIDTH = 16
)
(
    input clk,
    input rst_n,
	input [DATA_WIDTH-1:0] data,
	output reg [15:0] crc_out
);

reg [15:0] crc_temp;
reg temp;

integer i;


//CRC out
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		crc_out <= 0;
	else
		crc_out <= crc_temp;
end


//CRC temp
//G(X) = x16 + x15 + x2 + 1
always@(*)
begin
	if(!rst_n)
    begin
		crc_temp = 0;
		temp = 0;
    end
	else
    begin
        crc_temp = 0;//init
        for(i=DATA_WIDTH-1; i>=0; i=i-1)
        begin
            temp = data[i] ^ crc_temp[15];

            crc_temp[15] = temp ^ crc_temp[14];
            crc_temp[14:3] = crc_temp[13:2];
            crc_temp[2] = temp ^ crc_temp[1];
            crc_temp[1] = crc_temp[0];
            crc_temp[0] = temp;
        end
    end
end


endmodule

tb_parallelCRC16.v

`timescale 1ns / 1ps

// Company:
// Engineer:
//
// Create Date: 2020/12/14
// Author Name: Sniper
// Module Name: tb_parallelCRC16
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//


module tb_parallelCRC16;

//parameter
parameter DATA_WIDTH = 16;


//input
reg clk;
reg rst_n;
reg [DATA_WIDTH-1:0] data;


//output
wire [15:0] crc_out;



initial
begin
    clk = 0;
    rst_n = 0;
    data[DATA_WIDTH-1:0] = 0;

	#100;
    rst_n = 1;

    @(posedge clk);
    data <= 16'h00AA;
    @(posedge clk);
    data <= 16'hAA89;
    @(posedge clk);
    data <= 16'h2853;




end

//clock
always #5 clk = ~clk;



//DUT
parallelCRC16 
#(
    .DATA_WIDTH(DATA_WIDTH)
)
DUT
(
    .clk(clk),
    .rst_n(rst_n),
    .data(data),
    .crc_out(crc_out)
);

initial
begin
    $dumpfile("tb_parallelCRC16.vcd");
    $dumpvars(0,tb_parallelCRC16);
end

initial #1000 $finish;

endmodule

operation result

vcs -R parallelCRC16.v tb_parallelCRC16.v

The CRC result is generated in the next clock cycle of data input.
Insert picture description here

Serial CRC-16 check code generator

serialCRC16.v

`timescale 1ns / 1ps

// Company: 
// Engineer: 
// 
// Create Date: 2020/12/14
// Author Name: Sniper
// Module Name: serialCRC16
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 


module serialCRC16
#(
    parameter DATA_WIDTH = 16
)
(
    input clk,
    input rst_n,
    input clear,
	input data,
	output reg [15:0] crc_out
);

wire temp;
assign temp = data ^ crc_out[15];

//CRC out
//G(X) = x16 + x15 + x2 + 1
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		crc_out <= 0;
	else if(clear)
        crc_out <= 0;
    else
    begin
        crc_out[15] <= temp ^ crc_out[14];
        crc_out[14:3] <= crc_out[13:2];
        crc_out[2] <= temp ^ crc_out[1];
        crc_out[1] <= crc_out[0];
        crc_out[0] <= temp;
    end
end



endmodule

tb_serialCRC16.v

`timescale 1ns / 1ps

// Company:
// Engineer:
//
// Create Date: 2020/12/15
// Author Name: Sniper
// Module Name: tb_serialCRC16
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//


module tb_serialCRC16;

//parameter
parameter DATA_WIDTH = 16;


//input
reg clk;
reg rst_n;
reg clear;
reg data;


//output
wire [15:0] crc_out;


task write_data(input [DATA_WIDTH-1:0] data_all);
begin
    @(posedge clk);
    clear <= 1;

    for(int i=DATA_WIDTH-1;i>=0;i=i-1)
    begin
        @(posedge clk);
        data <= data_all[i];
        clear <= 0;
    end
    repeat(3) @(posedge clk) clear <= 1;
end
endtask


initial
begin
    clk = 0;
    rst_n = 0;
    clear = 0;
    data = 0;

	#100;
    rst_n = 1;

    repeat(3) @(posedge clk);

    write_data(16'h00AA);
    write_data(16'hAA89);
    write_data(16'h2853);



end

//clock
always #5 clk = ~clk;



//DUT
serialCRC16 
#(
    .DATA_WIDTH(DATA_WIDTH)
)
DUT
(
    .clk(clk),
    .rst_n(rst_n),
    .clear(clear),
    .data(data),
    .crc_out(crc_out)
);

initial
begin
    $dumpfile("tb_serialCRC16.vcd");
    $dumpvars(0,tb_serialCRC16);
end

initial #1000 $finish;

endmodule

operation result

vcs -R -sverilog serialCRC16.v tb_serialCRC16.v

The CRC result is generated in the next clock cycle after the last bit of the data is input.
Insert picture description here

Guess you like

Origin blog.csdn.net/meng1506789/article/details/111191638