目录
一、UVM类库地图
UVM验证环境可分为两部分uvm_component和uvm_object类型。
uvm_component类型主要包括uvm_driver、uvm_monitor、uvm_sequencer、uvm_agent等构成验证环境基本的组成单元,uvm_componet拥有两大特性是uvm_object没有的:
- 在new()时指定parent参数,用于形成UVM验证环境的树形结构。
- 具有phase机制的自动执行特点。
uvm_object类型直接继承于uvm_void,能力最差,但其可扩展性也是最强的。基本除了uvm_component派生的类都继承于uvm_object,类似于uvm_transaction、uvm_sequence_item、config类型。
二、工厂机制
工厂机制最主要的作用就是重载(override),等于是对SV new函数的扩充。在实例化时,UVM会通过factory机制查找是否有相关的重载记录,若有记录,就会有新的类型替代旧的类型。
重载采用的机制是parent win,重载将原来所属的类型替换为另一个类型而无需修改原始代码,保证了原有代码的封装性。
重载有四大条件:
1.必须用工厂机制注册
`uvm_component_utils()
`uvm_object_utils()
2.被重载的类在实例化时,要使用factory机制进行例化。
exmaple_inst = exmaple::type_id::create("exmaple_inst");
3.重载的类要与被继承的类有派生关系,最终重载的类必须派生自最初被重载的类。
4.component和object之间互相不能重载。
重载方式:
set_type_override_by_type(uvm_object_wrapper original_type,uvm_object_wrapper override_type,bit replace = 1);//replace参数表示是否能再次重载(连续重载)。
set_inst_override_by_type(string relative_inst_path,uvm_object_wrapper original_type,uvm_object_wrapper override_type); //路径下进行替代
set_type_override(string original_type,string override_type,bit replace = 1);//字符串代替
set_inst_override(string relative_inst_path,string original_type,string override_type);
uvm_coreservict_t类
该类内置了UVM世界核心的组件和方法
- 唯一的uvm_factory,该组件用来注册、覆盖和例化。
- 全局的report_server,该组件用于消息统筹和报告。
- 全局的tr_database,该组件用于记录transaction记录。
- get_root()方法用例来返回当前UVM环境的结构顶层对象。
三、常见的component类型
1.uvm_driver
uvm_driver:所有driver都要派生于uvm_driver,driver的功能主要就是向sequencer索要sequence_item(transaction),并按照协议将sequence_item(transaction)的内容驱动到dut端口上。
uvm_driver声明:
class uvm_driver extends #(type REQ = uvm_sequence_item,type RSP =REQ) extends uvm_component;
uvm_driver常见成员变量和端口:
uvm_seq_item_pull_port #(REQ,RSP) seq_item_port;
uvm_analysis_port #(RSP) rsp_port;
REQ req;
RSP rsp;
driver类与sequencer类的通信就是通过pull的方式实现的:
driver.seq_item_port.connect(sequencer.seq_item_export);
driver.rsp_port.connect(sequencer.rsp_export);
示例:
class lvc_ahb_driver #(type REQ = lvc_ahb_transaction, type RSP = REQ) extends uvm_driver #(REQ, RSP); //继承
`uvm_component_utils(lvc_ahb_driver) //注册
//例化
function new(string name = "lvc_ahb_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
fork
get_and_drive();
join_none
endtask
virtual task get_and_drive();
forever begin
seq_item_port.get_next_item(req); //获取transaction
`uvm_info(get_type_name(), "sequencer got next item", UVM_HIGH)
drive_transfer(req); //驱动到dut
void'($cast(rsp, req.clone())); //复制req 类型转换
rsp.set_sequence_id(req.get_sequence_id());
rsp.set_transaction_id(req.get_transaction_id()); //标记ID
seq_item_port.item_done(rsp); //获取rsp,item_done
`uvm_info(get_type_name(), "sequencer item_done_triggered", UVM_HIGH)
end
endtask : get_and_drive
2.uvm_monitor
uvm_monitor:所有monitor都要派生于uvm_monitor,uvm_monitor几乎没有做任何扩充。
主要实现功能如下:
1.观测DUT的interface,收集总线信息。
2.观测内部信号或总线协议时做一些时序检查。
3.将监测到的数据发送至scoreboard和coverage collected,供其比较。
4.永远保持passive模式,不驱动DUT。
示例:
class lvc_ahb_monitor extends uvm_monitor;
uvm_analysis_port #(lvc_ahb_transaction) item_observed_port; //一般都会在monitor声明一个ap端口,用于广播收集到的transaction
`uvm_component_utils(lvc_ahb_monitor)
function new(string name = "lvc_ahb_monitor", uvm_component parent = null);
super.new(name, parent);
item_observed_port = new("item_observed_port", this); //ap端口例化
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
fork
monitor_transactions();
join_none
endtask
task monitor_transactions();
lvc_ahb_transaction t;
forever begin
collect_transfer(t); //收集transaction
item_observed_port.write(t); //广播
end
endtask
3.uvm_sequencer
uvm_sequencer:当driver要获取sequence时,就把生成的sequence_item发送给driver,组织和管理sequence,拥有不同的仲裁机制,起着路由器的作用。
class lvc_ahb_sequencer #(type REQ = lvc_ahb_transaction, type RSP = REQ) extends uvm_sequencer #(REQ, RSP); //参数化的类
4.uvm_agent
uvm_agent:最小的验证单位,通常包含一个driver、monitor、sequencer。
包含成员变量is_active
uvm_active_passive_enum is_active = UVM_ACTIVE;
当只需要监测激励时,把is_active置成passive模式,有选择性的例化driver和sequencer。
示例:
function void build_phase(uvm_phase phase);
super.build_phase(phase);
monitor = lvc_ahb_master_monitor::type_id::create("monitor", this);
if(cfg.is_active) begin //是否例化
driver = lvc_ahb_master_driver::type_id::create("driver", this);
sequencer = lvc_ahb_master_sequencer::type_id::create("sequencer", this);
end
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if(cfg.is_active) begin //是否连接
driver.seq_item_port.connect(sequencer.seq_item_export);
end
endfunction
5.uvm_scoreboard
uvm_agent:用于数据比对和报道,没有添加额外的成员变量和方法。
6.uvm_env
uvm_agent:结构化的容器,放置不同component,便于上层复用。
7.uvm_test
uvm_test:所有的测试用例都要派生自uvm_test或其派生类。验证环境建立的唯一入口,只有通过它才能正常运转UVM的phase机制,若不继承uvm_test ,通过run_test无法启动验证环境。
test的目标包括:
1.提供不同的配置,包括环境结构配置,测试模式配置等,然后创建验证环境。
2.例化测试序列,并挂载到sequencer,使其命令driver发送激励。
事实上uvm环境的顶层应该是uvm_top,uvm_top是uvm_root的唯一实例,所有不指定parent参数的都将继承于uvm_top,uvm_top是所有test的组件的顶层。
uvm_top是一个全局变量,可以用如下的方式得到它的指针。
uvm_root top;
top = uvm_root::get();
四、域的自动化
UVM内置了一些打印比较信息的方法,通过宏注册,实现如下方法:
copy、clone、print、compare 、pack 、upack等。
copy和clone都是深拷贝,clone=copy+new。
示例:
typedef enum {WHITE,BLUE,YELLOW} color_t;
class box extends uvm_object;
int volume = 120;
color_t color = WHITE;
string name = "box";
`uvm_object_utils_begin(box) //一般通过这种格式来包裹域的自动化
`uvm_fild_int(volume,UVM_ALL_ON)
`uvm_fild_enum(color_t,color,UVM_ALL_ON)
`uvm_fild_string(name,UVM_ALL_ON)
`uvm_object_utils_end
endclass