UVM入门系列(三)----通过uvm_gen脚本快速搭建一般验证平台(中)
前言
本篇博文继续之前博文的内容对验证平台进行补全,之前博文内容链接:
UVM入门系列(一)----通过uvm_gen脚本快速搭建一般验证平台(上)
monitor
1 i_monitor
i_monitor承担的功能是监测DUT的输入信号,并传输给reference model进行处理。由上篇博文给出的脚本生成的代码的基本框图可以知道,脚本生成的代码已经将i_monitor和i_agent之间进行了端口连接,所以本博文i_monitor传输包给reference model的数据通路设计如图
i_agent的analysis_port到analysis_fifo(在env中定义)到reference model的uvm_blocking_get_port之间的连接在env中进行。
数据包在i_monitor中通过write函数写入fifo,在reference model中通过get函数从fifo中取出。数据包的收发过程均是主动的过程,利于控制。
文章之后的o_monitor和scoreboard之间、reference model和scoreboard之间的连接以此方式进行连接。
下面开始进行代码的补充:
由于已经做了i_monitor到i_agent之间的连接,所以i_monitor代码部分只要增加输入端口的采样和write该函数即可。
i_monitor的采样频率由uvm_event控制,每次seq发送item之后,会触发event,i_monitor等待到event之后开始进行信号采样。
add_seq.sv:
class add_seq extends i_base_seq;
`uvm_object_utils(add_seq)
uvm_event seq_begin_ev;
uvm_event o_seq_begin_ev;
extern function new(string name="add_seq");
extern task body();
endclass
function add_seq::new(string name="add_seq");
super.new(name);
endfunction
task add_seq::body();
seq_begin_ev=uvm_event_pool::get_global("seq_begin_ev");
o_seq_begin_ev=uvm_event_pool::get_global("o_seq_begin_ev");
`uvm_info(get_type_name(),"Default sequence starting",UVM_HIGH)
o_seq_begin_ev.trigger();
repeat(100) begin
seq_begin_ev.trigger();
`uvm_do(req);
end
`uvm_info(get_type_name(),"Default sequence end",UVM_HIGH)
endtask
seq_begin_ev 用于控制i_monitor的采样
o_seq_begin_ev 用于控制o_monitor的采样
i_monitor.sv:
class i_monitor extends uvm_monitor;
`uvm_component_utils(i_monitor)
virtual interface i_agent_if vif;
virtual interface cr_if cvif;
uvm_analysis_port #(i_seq_item) analysis_port;
i_seq_item m_trans;
uvm_event seq_begin_ev;
extern function new(string name, uvm_component parent);
extern virtual function void build_phase (uvm_phase phase);
extern virtual function void connect_phase(uvm_phase phase);
extern task main_phase(uvm_phase phase);
extern task do_mon();
endclass : i_monitor
function i_monitor::new(string name, uvm_component parent);
super.new(name, parent);
analysis_port = new("analysis_port", this);
endfunction : new
function void i_monitor::build_phase(uvm_phase phase);
seq_begin_ev=uvm_event_pool::get_global("seq_begin_ev");
endfunction : build_phase
function void i_monitor::connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (!uvm_config_db #(virtual i_agent_if)::get(this, "", "vif", vif))
`uvm_error("NOVIF", {"virtual interface must be set for: ",get_full_name(),".vif"})
if (!uvm_config_db #(virtual cr_if)::get(this, "", "cvif", cvif))
`uvm_error("NOVIF", {"virtual interface must be set for: ",get_full_name(),".cvif"})
endfunction : connect_phase
task i_monitor::main_phase(uvm_phase phase);
`uvm_info(get_type_name(), "main phase", UVM_HIGH)
fork
forever begin
seq_begin_ev.wait_trigger();
seq_begin_ev.reset();
@(posedge cvif.sysclock);
m_trans = i_seq_item::type_id::create("m_trans");
do_mon();
analysis_port.write(m_trans);
`uvm_info("I_MON",m_trans.sprint,UVM_LOW)
end
join_none
endtask : main_phase
task i_monitor::do_mon();
m_trans.a=vif.a;
m_trans.b=vif.b;
m_trans.cin=vif.cin;
endtask : do_mon
2 o_monitor
o_monitor与i_monitor类似,用于DUT输出端口信号的采样。
首先补全o_seq_item.sv
class o_seq_item extends uvm_sequence_item;
rand bit cout;
rand bit [8:0] sum;
`uvm_object_utils_begin(o_seq_item)
`uvm_field_int(cout,UVM_DEFAULT)
`uvm_field_int(sum,UVM_DEFAULT)
`uvm_object_utils_end
extern function new(string name = "o_seq_item");
endclass : o_seq_item
function o_seq_item::new(string name = "o_seq_item");
super.new(name);
endfunction : new
o_monitor会采样o_seq_item,并发送给scoreboard。
class o_monitor extends uvm_monitor;
`uvm_component_utils(o_monitor)
virtual interface o_agent_if vif;
virtual interface cr_if cvif;
uvm_analysis_port #(o_seq_item) analysis_port;
uvm_event o_seq_begin_ev;
o_seq_item m_trans;
extern function new(string name, uvm_component parent);
extern virtual function void build_phase (uvm_phase phase);
extern virtual function void connect_phase(uvm_phase phase);
extern task main_phase(uvm_phase phase);
extern task do_mon();
endclass : o_monitor
function o_monitor::new(string name, uvm_component parent);
super.new(name, parent);
analysis_port = new("analysis_port", this);
endfunction : new
function void o_monitor::build_phase(uvm_phase phase);
o_seq_begin_ev=uvm_event_pool::get_global("o_seq_begin_ev");
endfunction : build_phase
function void o_monitor::connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (!uvm_config_db #(virtual o_agent_if)::get(this, "", "vif", vif))
`uvm_error("NOVIF", {"virtual interface must be set for: ",get_full_name(),".vif"})
if (!uvm_config_db #(virtual cr_if)::get(this, "", "cvif", cvif))
`uvm_error("NOVIF", {"virtual interface must be set for: ",get_full_name(),".cvif"})
endfunction : connect_phase
task o_monitor::main_phase(uvm_phase phase);
`uvm_info(get_type_name(), "main phase", UVM_HIGH)
fork
begin
o_seq_begin_ev.wait_trigger();
@(posedge cvif.sysclock);
@(posedge cvif.sysclock);
forever begin
m_trans = o_seq_item::type_id::create("m_trans");
do_mon();
analysis_port.write(m_trans);
`uvm_info("O_MON",m_trans.sprint,UVM_LOW)
end
end
join_none
endtask : main_phase
task o_monitor::do_mon();
m_trans.sum=vif.sum;
m_trans.cout=vif.cout;
@(posedge cvif.sysclock);
endtask : do_mon
3 在env中进行port的连接:
声明fifo
uvm_tlm_analysis_fifo#(i_seq_item) i_ref_fifo;
uvm_tlm_analysis_fifo#(o_seq_item) o_scb_fifo;
i_ref_fifo=new("i_ref_fifo",this);
o_scb_fifo=new("o_scb_fifo",this);
连接port:
m_o_agent.analysis_port.connect(o_scb_fifo.analysis_export);
m_scb.get_o_port.connect(o_scb_fifo.blocking_get_export);
m_refm.analysis_port.connect(ref_scb_fifo.analysis_export);
m_scb.get_ref_port.connect(ref_scb_fifo.blocking_get_export);
总结
本篇博文完成了dut输入输出信号的采样工作,并将采样的接口信号打包发送给reference model和scoreboard进行处理,后续博文会继续进行reference model 和scoreboard部分代码的完善。