1 组件家族
SV环境中的验证组件按照功能需要,被称之为激励器(stimulator)、监测器(monitor)和检查器(checker)。
这三个核心组件与验证环境的三个关键特性对应, 即激励、 监测和检查。 在过往那么多验证方法学中, 都有与其对应的组件(component)。
UVM组件家族是从UVM基类继承的一个核心分支即uvm_component类。
发送激励部分:uvm_driver,uvm_sequencer,uvm_sequencer_base,uvm_random_stimulus
监测激励部分:uvm_monitor
检查激励部分:uvm_scorebord,uvm_in_order_comparator,uvm_algorithm_comparator
环境的层次结构:uvm_agent,uvm_env,uvm_test
寄存器包:uvm_reg_predictor
从uvm_component类继承的类均可以构成验证环境, 这是因为它们都从uvm_component类继承了phase机制, 也都会经历各个phase阶段。
在UVM入门的模块中, 主要介绍构成环境的常见组件类:
• uvm_driver
• uvm_monitor
• uvm_sequencer
• uvm_agent
• uvm_scoreboard
• uvm_env
• uvm_test
其中,uvm_driver和uvm_sequencer会单独整理。
2 uvm_monitor
从名字来看, 这个类是为了监测接口数据, 而任何需要用户自定义数据监测行为的monitor都应当继承于该类。
• 虽然uvm_monitor与它的父类相比, 并没有增添新的成员和方法,但将新定义的monitor类继承于uvm_monitor类会有助于实现父类uvm_monitor的方法和特性。
通常所执行的功能包括:
1. 观测DUT的interface, 并收集总线信息;
2. 永远保持PASSIVE模式, 即永远不会驱动DUT;
3. 在总线协议或者内部信号协议观察时, 可以做一些功能和时序的检查;
4. 对于更加复杂的检查要求, 它们可以将数据发送至其它验证组件, 例如scoreboard、 reference model或者coverage collector。
class serial_monitor extends uvm_monitor;
virtual serial_if.monitor mi;//virtual interface + modportl
`uvm_component_utils(serial_monitor)
function new(string name, uvro_component parent);
super.new(name, parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction: build_phase
task run_phase (uvm_phase);
...
endtask: run_phase
endclass: serial_monitor
task serial_monitor::run_phase (uvm_phase);
serial_transaction tr;
tr = new;
forever begin
wait(mi.rts);
@ (negedge mi. line);
#(bit_period/2);
for(int i=O; i<= 7; i++) begin
#(bit_period);
tr.parity_error ^= mi.line;
tr.data[i] = mi.line; //监测数据
end
#(bit_period) assert(mi.line == l'bl) else //检查协议
`uvm_warning("MON", "Framing error")
...
end
endtask: run_phase
3 uvm_agent
uvm_agent 本身不具备什么神技, 但它是一个标准的验证环境 “单位 ”。这样的标准单位通常包含一个 driver 、 一个 monitor 和一个 sequencer。这三个小伙伴经常聚在一起, 组成一 个小团伙 agent。 同时为了复用, 有时 uvm_agent 中只需包含一个 monitor, 而不需 driver 和 sequencer, 这就需要通过一个变量来进行有条件的例化。
uvm_active_passive_enum is_active = UVM_ACTIVE;
is_active 是 agent 的一个成员,默认值是UVM_ACTIVE, 这表示处在 active 模式的 agent 需要例化 driver、 monitor 和 sequencer; 而如果 is_active 的值是UVM_PASSIVE 则表示 agent 是 passive 模式, 只可以例化 monitor。 active 模式的 agent 既有激励功能也有监测功能, passive 模式的 agent 只具有监测功能。 active 模式对应着 DUT 的接口暴露给 agent 且需要激励的场景, 而 passive 模式对应着 DUT 的接口已经与其他设计连接而只需要监测的场景。 通过 is_active 变量, agent 需要在 build_phase()和 coonect_pbase()等函数中通过选择语句来对driver和 sequencer 进行有条件的例化和连接。 下面这段例码即作为如何对 agent 内三个组件进行有条件例化参考。
class my_agent extends uvm_agent;
my_sequencer m_sqr;
my_driver m_drv;
my_monitor m_mon; //agent中常见的组件
dut_if vif;
uvm_active_passive_enum is_active = UVM_ACTIVE;//is_active决定agent内部结构
extern function void build_phase(uvm_phase phase);
extern function void connect_phase(uvm_phase phase); //函数内容在外部设置
`uvm_component_utils ( my_agent)
endclass: my_agent
function void template_master_agent::build();
super.build();
monitor=template_master_monitor::type_id::create("monitor",this);
if(is_active== UVM ACTIVE) begin
sequencer=template_master_sequencer::type_id::create ("sequencer", this);
driver=template_master_driver::type_id::create("driver" ,this);
end
endfunction: build
function void template_master_agent::connect();
if(is_active== UVM_ACTIVE) begin
driver.seq_item_port.connect(sequencer.seq_item_export);
end
endfunction: connect
Agent的存在是为了验证环境的复用。
按照总线的传输方向划分, 可以分为master和slave。
Master agent是用来向DUT发起transaction。
Slave agent是用来响应DUT的events。
对于UVM初学者,按照“套路”,只需要考虑在agent中创建所列出的常见组件。