3. 注入CRC校验错误

注入CRC校验错误 学习卡片

任务目标

在UVM验证环境中,构造一个携带错误CRC字段的数据包并注入到接收通路,验证接收端DUT能够检测到CRC错误并产生相应的错误指示信号。本案例聚焦于CRC校验错误注入的最小可复现闭环。

环境依赖

需要UVM-1.2或更高版本,以及支持SystemVerilog的仿真器(如VCS、QuestaSim)。DUT为一个简化的CRC校验接收模块,输入为数据包(含CRC字段),输出为错误标志。

关键完整代码

// 简化DUT:CRC-8校验接收器
module crc_receiver (
    input  logic        clk,
    input  logic        rst_n,
    input  logic [31:0] packet_in,  // {data[23:0], crc[7:0]}
    input  logic        valid_in,
    output logic        crc_error,
    output logic        ready_out
);
    logic [7:0] calc_crc;
    logic [7:0] recv_crc;
    
    // CRC-8多项式 0x07
    function automatic logic [7:0] crc8(input logic [23:0] data);
        logic [7:0] crc = 8'h00;
        for (int i = 0; i < 24; i++) begin
            crc ^= data[23-i];
            for (int j = 0; j < 8; j++) begin
                if (crc[7]) crc = {crc[6:0], 1'b0} ^ 8'h07;
                else        crc = {crc[6:0], 1'b0};
            end
        end
        return crc;
    endfunction
    
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            crc_error <= 1'b0;
            ready_out <= 1'b0;
        end else if (valid_in) begin
            recv_crc  <= packet_in[7:0];
            calc_crc  <= crc8(packet_in[31:8]);
            crc_error <= (calc_crc != recv_crc);
            ready_out <= 1'b1;
        end else begin
            ready_out <= 1'b0;
        end
    end
endmodule

// UVM测试平台:CRC错误注入
import uvm_pkg::*;
`include "uvm_macros.svh"

class crc_error_test extends uvm_test;
    `uvm_component_utils(crc_error_test)
    
    virtual interface crc_if vif;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    task run_phase(uvm_phase phase);
        logic [31:0] good_pkt, bad_pkt;
        logic [7:0]  good_crc;
        
        phase.raise_objection(this);
        
        // 等待复位释放
        @(posedge vif.rst_n);
        
        // 构造正确数据包:data=24'hA5A5A5
        good_crc = compute_crc8(24'hA5A5A5);
        good_pkt = {24'hA5A5A5, good_crc};
        
        // 发送正确包,验证无错误
        vif.send_packet(good_pkt);
        @(posedge vif.clk);
        assert (vif.crc_error === 0) else
            `uvm_error("CRC_TEST", "正确包被误报为CRC错误");
        
        // 构造错误包:翻转CRC最低位
        bad_pkt = good_pkt ^ 32'h00000001;
        
        // 发送错误包,验证检测到错误
        vif.send_packet(bad_pkt);
        @(posedge vif.clk);
        assert (vif.crc_error === 1) else
            `uvm_error("CRC_TEST", "错误包未被检测到CRC错误");
        
        `uvm_info("CRC_TEST", "CRC错误注入与检测验证通过", UVM_LOW)
        phase.drop_objection(this);
    endtask
    
    // 与DUT相同的CRC-8计算(用于测试激励生成)
    function automatic logic [7:0] compute_crc8(input logic [23:0] data);
        logic [7:0] crc = 8'h00;
        for (int i = 0; i < 24; i++) begin
            crc ^= data[23-i];
            for (int j = 0; j < 8; j++) begin
                if (crc[7]) crc = {crc[6:0], 1'b0} ^ 8'h07;
                else        crc = {crc[6:0], 1'b0};
            end
        end
        return crc;
    endfunction
endclass

// 接口定义
interface crc_if(input logic clk, input logic rst_n);
    logic [31:0] packet;
    logic        valid;
    logic        crc_error;
    logic        ready;
    
    task send_packet(input logic [31:0] pkt);
        @(posedge clk);
        packet <= pkt;
        valid  <= 1'b1;
        @(posedge clk);
        valid  <= 1'b0;
    endtask
endinterface

运行与验证

运行方式:将上述代码保存为crc_error_test.sv,在仿真器中编译并运行。需要将DUT的packet_in、valid_in、crc_error、ready_out连接到crc_if接口对应信号。

验证通过条件:仿真结束时UVM报告无UVM_ERROR,且打印“CRC错误注入与检测验证通过”信息。具体判定逻辑:

  • 发送正确CRC包后,crc_error信号必须为0;
  • 发送翻转CRC最低位后的错误包,crc_error信号必须为1。

若两个断言均通过,则证明接收端能正确区分正确与错误的CRC字段,错误注入机制有效。