3. 注入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字段,错误注入机制有效。