UVM - 8 (override - 1)
在uvm 中可以利用factory机制的重载作用改变某些component的特性, 而不用去修改testbench。比如说:写了2个driver的class,但是uvm环境中只需要用到一个,如果这两个driver都是用factory注册,那么就可以用override的方式替换当前uvm环境中的driver。
Note:一、两个组件都注册,注册component时候使用uvm_component_utils,
创建component对象的时候使用::type_id::creat(), 而不是使用new()
案例
架构
Components:
- Agents
- my_agent
1. my_agent_v2 (child)
- Drivers
base_driver
1. eth_driver (child)
2. spi_driver (child)
- Sequencer - my_seqeuncer
- Sequences
- base_sequence
1. seq1 (child)
2. seq2 (child)
3. seq3 (child)
- Data
- eth_packet
- eth_v2_packet (child)
Sequencer within m_agnt2 operate on seq3, while the other two operate on seq1 by default
Coding
1.packet
- 定义一个data packet的base class,然后派生出一个子类
- packet继承自uvm_sequence_item,继承自uvm_sequence_item的类是事务类,可以使用packet或者transaction进行命名
//------------------ eth_packet-----------------------------------
class eth_packet extends uvm_sequence_item;
`uvm_object_utils (eth_packet) // 在工程中注册
...
function new (string name = "eth_packet");
super.new (name);
`uvm_info (get_type_name(), "Packet created", UVM_MEDIUM)
endfunction
endclass
//------------------ eth_v2_packet-----------------------------------
class eth_v2_packet extends eth_packet;
`uvm_object_utils (eth_v2_packet) // 在工厂中注册
...
function new (string name = "eth_v2_packet");
super.new (name);
endfunction
endclass
2. driver
- 创建一个driver的base class ,然后派生出两个子类:eth_driver和spi_driver
//------------------ base_driver-----------------------------------
// driver需要传入事务类型
class base_driver #(type T=eth_packet) extends uvm_driver;
`uvm_component_utils (base_driver #(T))
T pkt;
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
// 创建packet对象
pkt = T::type_id::create ("pkt0");
endfunction
virtual task run_phase (uvm_phase phase);
super.run_phase (phase);
`uvm_info (get_type_name(), $sformatf("Driver running ...with packet of type : %s", pkt.get_type_name()), UVM_MEDIUM)
endtask
endclass
//----------------- eth_driver-----------------------------------
class eth_driver #(type T=eth_packet) extends base_driver #(T);
`uvm_component_utils (eth_driver #(T))
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction
endclass
//----------------- spi_driver-----------------------------------
class spi_driver #(type T=eth_packet) extends base_driver #(T);
`uvm_component_utils (spi_driver #(T))
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction
endclass
3.sequence
- 定义几个seqence
//----------------- base_sequence-----------------------------------
class base_sequence extends uvm_sequence;
`uvm_object_utils (base_sequence)
endclass
//----------------- seq1 -------------------------------------------
class seq1 extends base_eth_sequence;
`uvm_object_utils (seq1)
...
endclass
//----------------- seq2 -------------------------------------------
class seq2 extends base_eth_sequence;
`uvm_object_utils (seq2)
...
endclass
//----------------- seq3 -------------------------------------------
class seq3 extends base_eth_sequence;
`uvm_object_utils (seq3)
...
endclass
4.agent
//----------------- my_agent -------------------------------------------
class my_agent extends uvm_agent;
`uvm_component_utils (my_agent)
base_driver m_drv0;
my_sequencer m_seqr0;
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction
virtual function void **build_phase** (uvm_phase phase);
super.build_phase (phase);
m_drv0 = base_driver::type_id::create ("m_drv0", this); // 创建driver对象
m_seqr0 = my_sequencer::type_id::create ("m_seqr0", this); // 创建sequencer对象
endfunction
virtual function void **connect_phase** (uvm_phase phase);
super.connect_phase (phase);
m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);//sequencer的seq_itme_export接口和driver.seq_item.port接口连接
endfunction
endclass
//----------------- my_agent_v2 -------------------------------------------
class my_agent_v2 extends uvm_agent;
`uvm_component_utils (my_agent_v2)
eth_driver m_drv0;
my_sequencer m_seqr0;
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
m_drv0 = eth_driver::type_id::create ("m_drv0", this);
m_seqr0 = my_sequencer::type_id::create ("m_seqr0", this);
endfunction
virtual function void connect_phase (uvm_phase phase);
super.connect_phase (phase);
m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);
endfunction
endclass
5.env
- my_agent中包含base_driver,my_agent_v2中包含eth_driver,
- 在环境当中创建多个agent,每个agent中包含的组件不同
class my_env extends uvm_env ;
`uvm_component_utils (my_env)
my_agent m_agnt0;
my_agent m_agnt1;
my_agent_v2 m_agnt2;
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction : new
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
m_agnt0 = my_agent::type_id::create ("m_agnt0", this);
m_agnt1 = my_agent::type_id::create ("m_agnt1", this);
m_agnt2 = my_agent_v2::type_id::create ("m_agnt2", this);
endfunction : build_phase
endclass : my_env
6. test
class feature_test extends base_test;
`uvm_component_utils (feature_test)
function new (string name, uvm_component parent = null);
super.new (name, parent);
endfunction
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
`ifdef PKT_OVERRIDE
// Substitute all eth_packets with eth_v2_packet
// 查找override表,也相当于在override表中更新信息
// 用eth_v2_packet替代eth_packet类
**set_type_override_by_type (eth_packet::get_type(), eth_v2_packet::get_type());**
`endif
// These are the three different styles to override something
`ifdef DRV_STYLE1
// Substitute all instances of base_driver with driver2
set_type_override_by_type (base_driver::get_type(), spi_driver::get_type());
`elsif DRV_STYLE2
// Substitute only eth_driver in agnt2 with spi_driver - by calling the component to be replaced method
eth_driver::type_id::set_inst_override (spi_driver::get_type(), "m_top_env.m_agnt2.m_drv0", this);
`elsif DRV_STYLE3
// Substitute base_driver only in agnt0 - by calling the factory method
factory.set_inst_override_by_type (base_driver::get_type(), eth_driver::get_type(), {get_full_name(), ".m_top_env.m_agnt0.*"});
`endif
// Trying to override a sequence
`ifdef SEQ_TYPE
// Substitute seq1 with seq2
set_type_override_by_type (seq1::get_type(), seq3::get_type());
`elsif SEQ_INST
// Substitute seq1 with seq2 only for agnt1
set_inst_override_by_type ("m_top_env.m_agnt1.m_seqr0.*", seq1::get_type(), seq2::get_type());
`else
`endif
factory.print();
endfunction
// Enter test code for feature here
endclass