|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
虽然已经入夏,但一直阴雨绵绵,闲来无事,无意中发现一个用AI生成完整且可运行的UVM Testbench的方法。以一个FIFO为DUT,下面是AI生成对应的Testbench的一个总结,麻雀虽小,五脏俱全。关键点概述[size=16.002px]DUT 接口
[size=16.002px]定义了 fifo_if 接口,包含 FIFO 的所有信号:时钟、复位、读写使能、数据输入输出、状态标志等 [size=16.002px]接口信号包括:full, empty, almost_full, almost_empty, overflow, underflow
[size=16.002px]事务项 (Transaction) [size=16.002px]fifo_transaction 类继承自 uvm_sequence_item [size=16.002px]包含随机化的数据、写使能和读使能 [size=16.002px]约束确保写和读操作不会同时进行 (wr_en != rd_en)
[size=16.002px]序列 (Sequence) [size=16.002px]fifo_sequence 生成测试序列 [size=16.002px]先填充 FIFO (16 次写操作) [size=16.002px]等待 100ns 让 FIFO 变满 [size=16.002px]然后清空 FIFO (16 次读操作)
[size=16.002px]驱动 (Driver) [size=16.002px]监视器 (Monitor) [size=16.002px]观察 DUT 接口上的活动 [size=16.002px]检测有效的读写操作并发送到分析端口 [size=16.002px]忽略当 FIFO 满时的写操作和空时的读操作
[size=16.002px]记分板 (Scoreboard) [size=16.002px]比较写入和读出的数据 [size=16.002px]统计匹配和不匹配的数量 [size=16.002px]检查写入和读取的事务数量是否一致 [size=16.002px]在报告阶段输出结果
[size=16.002px]代理 (Agent) [size=16.002px]环境 (Environment) [size=16.002px]测试 (Test) [size=16.002px]base_test 提供基本框架 [size=16.002px]basic_test 执行基本 FIFO 测试 [size=16.002px]使用 objection 机制控制测试流程
[size=16.002px]顶层模块 (Top Module) [size=16.002px]实例化 DUT 和接口 [size=16.002px]生成时钟和复位信号 [size=16.002px]设置 UVM 配置数据库 [size=16.002px]运行测试并检查最终结果
测试流程[size=16.002px]初始化阶段:时钟、复位生成 [size=16.002px]UVM 启动:配置虚拟接口并运行测试 [size=16.002px]测试执行: [size=16.002px]先执行 16 次写操作填充 FIFO [size=16.002px]等待 FIFO 变满 [size=16.002px]再执行 16 次读操作清空 FIFO
[size=16.002px]结果检查: [size=16.002px]报告结果:输出匹配/不匹配统计
验证功能[size=16.002px]验证 FIFO 的基本读写功能 [size=16.002px]检查 FIFO 满和空状态行为 [size=16.002px]验证数据一致性 (写入和读出的数据是否匹配) [size=16.002px]检查事务完整性 (写入和读取的数量是否一致)
可扩展性[size=16.002px]可以通过继承 base_test 创建更多测试场景 [size=16.002px]可以添加覆盖率收集 [size=16.002px]可以扩展记分板功能以检查更多边界条件 [size=16.002px]可以添加断言检查 FIFO 的行为
[size=16.002px]
[size=16.002px]下面是生成的testbench的代码:(对天发誓,一个字母没改)
[size=16.002px]
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
// Interface for FIFO DUT
interface fifo_if(input bit clk);
logic rst_n;
logic wr_en;
logic [31:0] data_in;
logic rd_en;
logic [31:0] data_out;
logic full;
logic empty;
logic almost_full;
logic almost_empty;
logic overflow;
logic underflow;
endinterface
// FIFO Transaction Item
class fifo_transaction extends uvm_sequence_item;
rand bit [31:0] data;
rand bit wr_en;
rand bit rd_en;
`uvm_object_utils_begin(fifo_transaction)
`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_transaction");
super.new(name);
endfunction
constraint valid_ops {
wr_en != rd_en;
}
endclass
// FIFO Sequence
class fifo_sequence extends uvm_sequence #(fifo_transaction);
`uvm_object_utils(fifo_sequence)
rand int num_transactions = 20;
fifo_transaction transactions[$];
function new(string name = "fifo_sequence");
super.new(name);
endfunction
task body();
// First fill the FIFO
for (int i = 0; i < 16; i++) begin
fifo_transaction tx;
`uvm_create(tx)
tx.wr_en = 1;
tx.rd_en = 0;
assert(tx.randomize());
transactions.push_back(tx);
`uvm_send(tx)
end
// Wait for FIFO to be full
#100;
// Then empty the FIFO
for (int i = 0; i < 16; i++) begin
fifo_transaction tx;
`uvm_create(tx)
tx.wr_en = 0;
tx.rd_en = 1;
tx.data = 0; // Data doesn't matter for reads
transactions.push_back(tx);
`uvm_send(tx)
end
endtask
endclass
// FIFO Driver
class fifo_driver extends uvm_driver #(fifo_transaction);
`uvm_component_utils(fifo_driver)
virtual fifo_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", vif)) begin
`uvm_fatal("NOVIF", "Virtual interface not set for driver")
end
endfunction
task run_phase(uvm_phase phase);
forever begin
fifo_transaction tx;
seq_item_port.get_next_item(tx);
@(posedge vif.clk);
vif.wr_en <= tx.wr_en;
vif.rd_en <= tx.rd_en;
vif.data_in <= tx.data;
seq_item_port.item_done();
end
endtask
endclass
// FIFO Monitor
class fifo_monitor extends uvm_monitor;
`uvm_component_utils(fifo_monitor)
virtual fifo_if vif;
uvm_analysis_port #(fifo_transaction) ap;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new("ap", this);
if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", vif)) begin
`uvm_fatal("NOVIF", "Virtual interface not set for monitor")
end
endfunction
task run_phase(uvm_phase phase);
forever begin
fifo_transaction tx = fifo_transaction::type_id::create("tx");
@(posedge vif.clk);
if (vif.wr_en && !vif.full) begin
tx.wr_en = 1;
tx.rd_en = 0;
tx.data = vif.data_in;
ap.write(tx);
end
if (vif.rd_en && !vif.empty) begin
tx = fifo_transaction::type_id::create("tx");
tx.wr_en = 0;
tx.rd_en = 1;
tx.data = vif.data_out;
ap.write(tx);
end
end
endtask
endclass
// FIFO Scoreboard
class fifo_scoreboard extends uvm_scoreboard;
`uvm_component_utils(fifo_scoreboard)
uvm_analysis_imp #(fifo_transaction, fifo_scoreboard) item_export;
fifo_transaction write_q[$];
fifo_transaction read_q[$];
int write_count = 0;
int read_count = 0;
int match_count = 0;
int mismatch_count = 0;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
item_export = new("item_export", this);
endfunction
function void write(fifo_transaction tx);
if (tx.wr_en) begin
write_q.push_back(tx);
write_count++;
end
else if (tx.rd_en) begin
read_q.push_back(tx);
read_count++;
end
endfunction
function void report_phase(uvm_phase phase);
super.report_phase(phase);
// Compare write and read transactions
while (write_q.size() > 0 && read_q.size() > 0) begin
fifo_transaction write_tx = write_q.pop_front();
fifo_transaction read_tx = read_q.pop_front();
if (write_tx.data !== read_tx.data) begin
`uvm_error("SCOREBOARD", $sformatf("Data mismatch! Expected: 0x%0h, Actual: 0x%0h",
write_tx.data, read_tx.data))
mismatch_count++;
end
else begin
match_count++;
end
end
// Check for transaction count mismatch
if (write_count != read_count) begin
`uvm_error("SCOREBOARD", $sformatf("Transaction count mismatch! Writes: %0d, Reads: %0d",
write_count, read_count))
end
`uvm_info("SCOREBOARD", $sformatf("Scoreboard Results: Matches=%0d, Mismatches=%0d, Writes=%0d, Reads=%0d",
match_count, mismatch_count, write_count, read_count), UVM_LOW)
endfunction
endclass
// FIFO Agent
class fifo_agent extends uvm_agent;
`uvm_component_utils(fifo_agent)
fifo_driver driver;
fifo_monitor monitor;
uvm_sequencer #(fifo_transaction) sequencer;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
monitor = fifo_monitor::type_id::create("monitor", this);
if (get_is_active() == UVM_ACTIVE) begin
driver = fifo_driver::type_id::create("driver", this);
sequencer = uvm_sequencer#(fifo_transaction)::type_id::create("sequencer", this);
end
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (get_is_active() == UVM_ACTIVE) begin
driver.seq_item_port.connect(sequencer.seq_item_export);
end
if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", driver.vif)) begin
`uvm_fatal("NOVIF", "Virtual interface not set for driver")
end
if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", monitor.vif)) begin
`uvm_fatal("NOVIF", "Virtual interface not set for monitor")
end
endfunction
endclass
// FIFO Environment
class fifo_env extends uvm_env;
`uvm_component_utils(fifo_env)
fifo_agent agent;
fifo_scoreboard scoreboard;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = fifo_agent::type_id::create("agent", this);
scoreboard = fifo_scoreboard::type_id::create("scoreboard", this);
uvm_config_db#(uvm_active_passive_enum)::set(this, "agent", "is_active", UVM_ACTIVE);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
agent.monitor.ap.connect(scoreboard.item_export);
endfunction
endclass
// Base Test
class base_test extends uvm_test;
`uvm_component_utils(base_test)
fifo_env env;
fifo_sequence seq;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = fifo_env::type_id::create("env", this);
seq = fifo_sequence::type_id::create("seq");
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
seq.start(env.agent.sequencer);
phase.drop_objection(this);
endtask
endclass
// Basic Test
class basic_test extends base_test;
`uvm_component_utils(basic_test)
function new(string name = "basic_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info(get_type_name(), "Starting basic FIFO test", UVM_LOW)
seq.start(env.agent.sequencer);
// Wait for all transactions to complete
#200;
phase.drop_objection(this);
endtask
endclass
// Top Module
module top;
import uvm_pkg::*;
bit clk;
bit rst_n;
// Instantiate DUT interface
fifo_if fif_if(clk);
// Instantiate DUT
FIFO #(
.DATA_WIDTH(32),
.FIFO_DEPTH(16),
.ALMOST_FULL_THRESH(12),
.ALMOST_EMPTY_THRESH(4)
) dut (
.clk(clk),
.rst_n(fif_if.rst_n),
.wr_en(fif_if.wr_en),
.data_in(fif_if.data_in),
.rd_en(fif_if.rd_en),
.data_out(fif_if.data_out),
.full(fif_if.full),
.empty(fif_if.empty),
.almost_full(fif_if.almost_full),
.almost_empty(fif_if.almost_empty),
.overflow(fif_if.overflow),
.underflow(fif_if.underflow)
);
// Clock generation
initial begin
clk = 0;
forever #5 clk = ~clk;
end
// Reset generation
initial begin
fif_if.rst_n = 0;
#20 fif_if.rst_n = 1;
end
// UVM test setup
initial begin
uvm_config_db#(virtual fifo_if)::set(null, "uvm_test_top.env*", "vif", fif_if);
run_test("basic_test");
end
// Final check
final begin
if (uvm_report_server::get_server().get_severity_count(UVM_FATAL) > 0) begin
$display("Simulation finished with UVM_FATAL errors");
$finish(2);
end
else if (uvm_report_server::get_server().get_severity_count(UVM_ERROR) > 0) begin
$display("Simulation finished with UVM_ERROR errors");
$finish(1);
end
else begin
$display("Test passed successfully");
$finish(0);
end
end
endmodule
完整代码
完整版DUT,Testbench和Testcase 代码打包文件:
FIFO_release.zip
(8.1 KB, 下载次数: 3 )
实现方式
1. AIDEV Project Workspace
2. 输入dut fifo的功能需求,选择生成和编译选项,填入额外的test需求,提交,坐等代码生成,发入你邮箱。
|
|