2. 模拟FIFO溢出错误
任务说明
构造一个最小可综合的同步FIFO(深度8,宽度8位),通过连续写入超过容量的数据来触发溢出条件。验证重点:溢出标志(overflow)是否在FIFO满后再次写入时正确拉高,以及错误处理逻辑(此处为拒绝写入)是否生效。
环境依赖
本案例使用 SystemVerilog + UVM 1.2,仿真工具为 QuestaSim 或 VCS。无需额外IP,FIFO设计代码与UVM验证环境均在本案例内完整提供。
FIFO设计(DUT)
// fifo_depth8.sv
module fifo_depth8 #(
parameter DATA_WIDTH = 8,
parameter DEPTH = 8
)(
input logic clk,
input logic rst_n,
input logic wr_en,
input logic rd_en,
input logic [DATA_WIDTH-1:0] din,
output logic [DATA_WIDTH-1:0] dout,
output logic full,
output logic empty,
output logic overflow,
output logic underflow
);
logic [$clog2(DEPTH)-1:0] w_ptr, r_ptr;
logic [$clog2(DEPTH)-1:0] count;
logic [DATA_WIDTH-1:0] mem [DEPTH];
assign full = (count == DEPTH);
assign empty = (count == 0);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
w_ptr <= 0;
r_ptr <= 0;
count <= 0;
overflow <= 0;
underflow <= 0;
end else begin
overflow <= 0;
underflow <= 0;
if (wr_en && !full) begin
mem[w_ptr] <= din;
w_ptr <= w_ptr + 1;
count <= count + 1;
end else if (wr_en && full) begin
overflow <= 1; // 溢出标志:满时仍写入
end
if (rd_en && !empty) begin
dout <= mem[r_ptr];
r_ptr <= r_ptr + 1;
count <= count - 1;
end else if (rd_en && empty) begin
underflow <= 1;
end
end
end
endmodule
UVM验证环境
以下代码包含:事务类、序列(连续写10次,超过深度8)、驱动器、监视器、参考模型(计数值比对)、计分板以及测试类。环境通过uvm_sequence驱动写端口,不执行读操作,从而保证FIFO必然填满并触发溢出。
// fifo_overflow_test.sv
`include "uvm_macros.svh"
import uvm_pkg::*;
// 事务
class fifo_txn extends uvm_sequence_item;
rand logic [7:0] data;
rand bit wr_en;
rand bit rd_en;
`uvm_object_utils_begin(fifo_txn)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_int(wr_en, UVM_ALL_ON)
`uvm_field_int(rd_en, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "fifo_txn");
super.new(name);
endfunction
endclass
// 序列:连续写10次(深度8,必溢出)
class write_overflow_seq extends uvm_sequence #(fifo_txn);
`uvm_object_utils(write_overflow_seq)
function new(string name = "write_overflow_seq");
super.new(name);
endfunction
task body();
fifo_txn txn;
repeat (10) begin
txn = fifo_txn::type_id::create("txn");
start_item(txn);
txn.wr_en = 1;
txn.rd_en = 0;
txn.data = $urandom;
finish_item(txn);
end
endtask
endclass
// 驱动器
class fifo_driver extends uvm_driver #(fifo_txn);
virtual fifo_if vif;
`uvm_component_utils(fifo_driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
@(posedge vif.clk);
vif.wr_en <= req.wr_en;
vif.rd_en <= req.rd_en;
vif.din <= req.data;
seq_item_port.item_done();
end
endtask
endclass
// 监视器
class fifo_monitor extends uvm_monitor;
virtual fifo_if vif;
uvm_analysis_port #(fifo_txn) mon_ap;
`uvm_component_utils(fifo_monitor)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
mon_ap = new("mon_ap", this);
endfunction
task run_phase(uvm_phase phase);
fifo_txn txn;
forever begin
@(posedge vif.clk);
txn = fifo_txn::type_id::create("txn");
txn.wr_en = vif.wr_en;
txn.rd_en = vif.rd_en;
txn.data = vif.din;
mon_ap.write(txn);
end
endtask
endclass
// 参考模型:跟踪写入次数
class fifo_scoreboard extends uvm_scoreboard;
`uvm_component_utils(fifo_scoreboard)
uvm_analysis_imp #(fifo_txn, fifo_scoreboard) sb_imp;
int write_count;
int overflow_detected;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
sb_imp = new("sb_imp", this);
write_count = 0;
overflow_detected = 0;
endfunction
function void write(fifo_txn txn);
if (txn.wr_en) begin
write_count++;
if (write_count > 8) begin
overflow_detected = 1;
`uvm_info("SCB", $sformatf("溢出条件触发: 第%0d次写入(容量8)", write_count), UVM_LOW)
end
end
endfunction
function void check_phase(uvm_phase phase);
if (overflow_detected == 1)
`uvm_info("SCB", "TEST PASSED: 溢出标志已触发", UVM_LOW)
else
`uvm_error("SCB", "TEST FAILED: 未检测到溢出")
endfunction
endclass
// 环境
class fifo_env extends uvm_env;
fifo_driver drv;
fifo_monitor mon;
fifo_scoreboard scb;
`uvm_component_utils(fifo_env)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
drv = fifo_driver::type_id::create("drv", this);
mon = fifo_monitor::type_id::create("mon", this);
scb = fifo_scoreboard::type_id::create("scb", this);
endfunction
function void connect_phase(uvm_phase phase);
drv.seq_item_port.connect(seqr.seq_item_export);
mon.mon_ap.connect(scb.sb_imp);
endfunction
endclass
// 测试
class fifo_overflow_test extends uvm_test;
fifo_env env;
`uvm_component_utils(fifo_overflow_test)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
env = fifo_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
write_overflow_seq seq;
phase.raise_objection(this);
seq = write_overflow_seq::type_id::create("seq");
seq.start(env.drv.seqr);
#100ns;
phase.drop_objection(this);
endtask
endclass
接口与连接
// fifo_if.sv
interface fifo_if(input logic clk);
logic rst_n;
logic wr_en, rd_en;
logic [7:0] din, dout;
logic full, empty, overflow, underflow;
endinterface
运行方式
# 编译(QuestaSim示例)
vlib work
vlog fifo_depth8.sv fifo_if.sv fifo_overflow_test.sv
vsim -c -do "run -all; quit" fifo_overflow_test
# 预期输出(确定性结果)
# UVM_INFO : 溢出条件触发: 第9次写入(容量8)
# UVM_INFO : TEST PASSED: 溢出标志已触发
验证判定标准
- 仿真结束时出现
TEST PASSED信息,且无UVM_ERROR。 - DUT的
overflow信号在FIFO满(第9次写)后拉高一个时钟周期。 - 计分板检测到写入次数超过8,确认溢出路径被真实执行。