UVM学习之路(4)— 基本的UVM验证平台
一、前言
一般我们将设计输出的文件称为DUT(Design Under Test),即待测设计,验证是来找出DUT中的bug, 这个过程通常是把DUT放入一个验证平台中来实现的。 一个基本的UVM验证平台框图如下所示:
本次使用的源码修改来自张强的《UVM实战》第二章节的源码
二、设计模块
本次我们使用一个最简单的DUT来搭建一个UVM验证环境,其功能非常简单, 通过rxd接收数据, 再通过txd发送出去。该模块信号列表如下所示:
三、UVM验证环境
本次uvm代码的组织结构如下所示:
uvm_test是整个UVM的树根,本次搭建的平台中有3个不同实现的uvm_test
1、 使用default_sequence
case0.sv代码如下
class case0_sequence extends uvm_sequence #(transaction_dut);
transaction_dut m_trans;
function new(string name= "case0_sequence");
super.new(name);
endfunction
virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this);
repeat (10) begin
`uvm_do_with(m_trans, { m_trans.pload.size() == 10;})
end
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
`uvm_object_utils(case0_sequence)
endclass
class case0 extends uvm_test;
my_env env;
function new(string name = "case0", uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("case0", "case0 build_phase", UVM_LOW);
env = my_env::type_id::create("env", this);
/* 1. use default_sequence */
uvm_config_db#(uvm_object_wrapper)::set(this, "env.in_agt.sqr.main_phase",
"default_sequence", case0_sequence::type_id::get());
endfunction
virtual function void report_phase(uvm_phase phase);
uvm_report_server server;
int err_num;
super.report_phase(phase);
server = get_report_server();
err_num = server.get_severity_count(UVM_ERROR);
if (err_num != 0) begin
$display("--------------------------------------------------");
$display("---- TEST CASE FAILED ----");
$display("--------------------------------------------------");
end
else begin
$display("--------------------------------------------------");
$display("---- TEST CASE PASSED ----");
$display("--------------------------------------------------");
end
endfunction
`uvm_component_utils(case0)
endclass
2、 手动创建sequence
case1.sv代码如下
class case1_sequence extends uvm_sequence #(transaction_dut);
transaction_dut m_trans;
function new(string name= "case1_sequence");
super.new(name);
endfunction
virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this);
repeat (10) begin
`uvm_do_with(m_trans, { m_trans.pload.size() == 10;})
end
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
`uvm_object_utils(case1_sequence)
endclass
class case1 extends uvm_test;
my_env env;
function new(string name = "case1", uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("case1", "case1 build_phase", UVM_LOW);
env = my_env::type_id::create("env", this);
endfunction
virtual task main_phase(uvm_phase phase);
/* 2. not use default_sequence */
case1_sequence seq;
seq = case1_sequence::type_id::create("seq");
// set starting_phase for uvm_sequence.body() task
seq.starting_phase = phase;
seq.start(env.in_agt.sqr);
endtask
virtual function void report_phase(uvm_phase phase);
uvm_report_server server;
int err_num;
super.report_phase(phase);
server = get_report_server();
err_num = server.get_severity_count(UVM_ERROR);
if (err_num != 0) begin
$display("--------------------------------------------------");
$display("---- TEST CASE FAILED ----");
$display("--------------------------------------------------");
end
else begin
$display("--------------------------------------------------");
$display("---- TEST CASE PASSED ----");
$display("--------------------------------------------------");
end
endfunction
`uvm_component_utils(case1)
endclass
3、在uvm_test中提起和释放objection
case2.sv
代码如下
class case2_sequence extends uvm_sequence #(transaction_dut);
transaction_dut m_trans;
function new(string name= "case2_sequence");
super.new(name);
endfunction
virtual task body();
repeat (10) begin
`uvm_do_with(m_trans, { m_trans.pload.size() == 10;})
end
#100;
endtask
`uvm_object_utils(case2_sequence)
endclass
class case2 extends uvm_test;
my_env env;
function new(string name = "case2", uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("case2", "case2 build_phase", UVM_LOW);
env = my_env::type_id::create("env", this);
endfunction
virtual task main_phase(uvm_phase phase);
/* 3. not use default_sequence, in addition set objection raise and drop in this */
case2_sequence seq;
phase.raise_objection(this);
seq = case2_sequence::type_id::create("seq");
seq.starting_phase = phase;
seq.start(env.in_agt.sqr);
phase.drop_objection(this);
endtask
virtual function void report_phase(uvm_phase phase);
uvm_report_server server;
int err_num;
super.report_phase(phase);
server = get_report_server();
err_num = server.get_severity_count(UVM_ERROR);
if (err_num != 0) begin
$display("--------------------------------------------------");
$display("---- TEST CASE FAILED ----");
$display("--------------------------------------------------");
end
else begin
$display("--------------------------------------------------");
$display("---- TEST CASE PASSED ----");
$display("--------------------------------------------------");
end
endfunction
`uvm_component_utils(case2)
endclass
四、附录
本篇中的UVM验证平台源码:https://gitee.com/william_william/uvm-s02.git