FPGA实现CRC校验

发布于:2025-09-10 ⋅ 阅读:(13) ⋅ 点赞:(0)

        本文介绍了一种基于x⁸+x²+x+1多项式(0x07)的并行CRC-8校验实现方法。通过Verilog HDL设计了一个查找表(LUT)方式的CRC计算模块crc8_parallel_lut,包含数据输入、计算使能和控制信号。模块采用逐字节异或运算实现CRC计算,并包含帧结束检测功能。测试部分提供了包含多组数据的仿真激励,验证了模块的正确性,包括单字节(0x00)和字符串"Hello"的测试用例。仿真结果与在线CRC计算工具的结果对比,验证了设计的准确性。该实现适用于FPGA平台,具有并行处理能力和较高的计算效率经过并行方式实现CRC校准值,代码如下:

////x⁸ + x² + x + 1 (0x07)。

module crc8_parallel_lut (
    input wire clk,
    input wire reset,
    input wire [7:0] data_in,
    input wire data_valid,
    input wire calc_enable,
    output reg [7:0] crc_out,
    output reg crc_ready
);

    reg [7:0] crc_reg;
    reg prev_data_valid;
    wire frame_end;
    assign frame_end = prev_data_valid && !data_valid;
    
    // 查找表函数
    function [7:0] crc8_byte;
        input [7:0] crc;
        input [7:0] data;
        begin
            crc8_byte[0] = crc[7] ^ crc[6] ^ crc[0] ^ data[7] ^ data[6] ^ data[0];
            crc8_byte[1] = crc[6] ^ crc[1] ^ crc[0] ^ data[6] ^ data[1] ^ data[0];
            crc8_byte[2] = crc[6] ^ crc[2] ^ crc[1] ^ crc[0] ^ data[6] ^ data[2] ^ data[1] ^ data[0];
            crc8_byte[3] = crc[7] ^ crc[3] ^ crc[2] ^ crc[1] ^ data[7] ^ data[3] ^ data[2] ^ data[1];
            crc8_byte[4] = crc[4] ^ crc[3] ^ crc[2] ^ data[4] ^ data[3] ^ data[2];
            crc8_byte[5] = crc[5] ^ crc[4] ^ crc[3] ^ data[5] ^ data[4] ^ data[3];
            crc8_byte[6] = crc[6] ^ crc[5] ^ crc[4] ^ data[6] ^ data[5] ^ data[4];
            crc8_byte[7] = crc[7] ^ crc[6] ^ crc[5] ^ data[7] ^ data[6] ^ data[5];
        end
    endfunction
	

	
	
	
    
    always @(posedge clk or posedge reset) begin
        if (reset) begin
            crc_reg <= 8'h00;
            prev_data_valid <= 1'b0;
            crc_ready <= 1'b0;
            crc_out <= 8'h00;
        end else begin
            prev_data_valid <= data_valid;
            crc_ready <= 1'b0;
            
            if (calc_enable) begin
                if (data_valid) begin
                    // 使用查找表计算CRC
                    crc_reg <= crc8_byte(crc_reg, data_in);
                end
                
                // 检测帧结束
                if (frame_end) begin
                    crc_out <= crc_reg;
                    crc_ready <= 1'b1;
                end
            end else begin
                crc_reg <= 8'h00;
            end
        end
    end

endmodule

        仿真激励代码如下:

`timescale 1ns / 1ps


module tb_crc8_parallel;

    reg clk;
    reg reset;
    reg [7:0] data_in;
    reg data_valid;
    reg calc_enable;
    wire [7:0] crc_out;
    wire crc_ready;
    
    // 实例化CRC计算器
    crc8_parallel_lut dut (
        .clk(clk),
        .reset(reset),
        .data_in(data_in),
        .data_valid(data_valid),
        .calc_enable(calc_enable),
        .crc_out(crc_out),
        .crc_ready(crc_ready)
    );
    
    // 时钟生成
    always #5 clk = ~clk;
    
    // 测试任务:发送多个字节
    task send_bytes;
        input [7:0] data [];
        integer i;
        begin
            for (i = 0; i < data.size(); i = i + 1) begin
                data_in = data[i];
                #10;
            end
        end
    endtask
    
    initial begin
        // 初始化信号
        clk = 0;
        reset = 1;
        data_in = 8'h00;
        data_valid = 0;
        calc_enable = 0;
        
        // 复位
        #20 reset = 0;
        calc_enable = 1;
        
        // 测试用例1:发送数据0x01, 0x02, 0x03
        $display("开始测试用例1...");
        data_valid = 1;
        begin
            reg [7:0] test_data [3] = '{8'h01, 8'h02, 8'h03};
            send_bytes(test_data);
        end
        data_valid = 0;
        
        #20;
        $display("CRC结果: 0x%h", crc_out);
        
        // 等待一段时间后开始下一个测试
        #100;
        
        // 测试用例2:发送单个字节0x00
        $display("开始测试用例2...");
        data_valid = 1;
        data_in = 8'h00;
        #10;
        data_valid = 0;
        
        #20;
        $display("CRC结果: 0x%h", crc_out);
        
        // 测试用例3:发送字符串"Hello"
        $display("开始测试用例3...");
        data_valid = 1;
        begin
            reg [7:0] hello_data [5] = '{"H", "e", "l", "l", "o"};
            send_bytes(hello_data);
        end
        data_valid = 0;
        
        #20;
        $display("CRC结果: 0x%h", crc_out);
        
        // 结束仿真
        #100;
        $finish;
    end

endmodule

        例如输入16进制01 02 03,经过FPGA仿真结果如下:

        使用在线校准结果如下:

 

        在线计算结果和代码计算的值,检验无误。


网站公告

今日签到

点亮在社区的每一天
去签到