把monitor和driver封装成agent
monitor
- driver和monitor处理的是同一种协议。由于二者相似,UVM中将二者封装在一起,成为一个agent。
- 不同的agent就代表了不同的协议
my_agent代码
`ifndef MY_AGENT__SV
`define MY_AGENT__SV
class my_agent extends uvm_agent ;
//所有的agent都要派生自uvm_agent类
my_driver drv;
my_monitor mon;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void connect_phase(uvm_phase phase);
`uvm_component_utils(my_agent)
//使用uvm_component_utils宏来实现factory注册
endclass
function void my_agent::build_phase(uvm_phase phase);
super.build_phase(phase);
if (is_active == UVM_ACTIVE) begin
//is_active是uvm_agent的一个成员变量
//build_phase中根据is_active这个变量的值来决定是否创建driver的实例
drv = my_driver::type_id::create("drv", this);
end
mon = my_monitor::type_id::create("mon", this);
endfunction
function void my_agent::connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
`endif
agent的UVM_PASSIVE和UVM_ACTIVE
- is_active是uvm_agent的一个成员变量,agent的build_phase中根据is_active这个变量的值来决定是否创建driver的实例
- is_active的值默认为UVM_ACTIVE
- active下,创建driver,用作input端;passive下,不创建driver,只有monitor,用作output端
env中例化agent
把driver和monitor封装成agent后,在env中需要实例化agent
`ifndef MY_ENV__SV
`define MY_ENV__SV
class my_env extends uvm_env;
my_agent i_agt;
my_agent o_agt;
//声明两个agent,一个input,一个output
function new(string name = "my_env", uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
//agent的build_phase中创建两个agent的实例,并且指定is_active的值
i_agt = my_agent::type_id::create("i_agt", this);
o_agt = my_agent::type_id::create("o_agt", this);
i_agt.is_active = UVM_ACTIVE;
o_agt.is_active = UVM_PASSIVE;
endfunction
`uvm_component_utils(my_env)
endclass
`endif
在top_tb中修改config_db set的路径
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "my_if.sv"
`include "my_transaction.sv"
`include "my_driver.sv"
`include "my_monitor.sv"
`include "my_agent.sv"
`include "my_env.sv"
module top_tb;
reg clk;
reg rst_n;
reg[7:0] rxd;
reg rx_dv;
wire[7:0] txd;
wire tx_en;
my_if input_if(clk, rst_n);
my_if output_if(clk, rst_n);
dut my_dut(.clk(clk),
.rst_n(rst_n),
.rxd(input_if.data),
.rx_dv(input_if.valid),
.txd(output_if.data),
.tx_en(output_if.valid));
initial begin
clk = 0;
forever begin
#100 clk = ~clk;
end
end
initial begin
rst_n = 1'b0;
#1000;
rst_n = 1'b1;
end
initial begin
run_test("my_env");
//run_test只创建my_env实例,my_env中的agent在build_phase中创建
end
initial begin
//config_db的set函数中修改driver和monitor的路径
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.i_agt.drv", "vif", input_if);
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.i_agt.mon", "vif", input_if);
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.o_agt.mon", "vif", output_if);
end
endmodule
UVM树形图
- 只有uvm_component才能作为树的结点
- build_phase的从树根到树叶的执行顺序
- UVM要求UVM树最晚在build_phase时段完成