1.1 波形理解
- 先看T4-T7拍,可以发现:T4拍写入的地址为0x28,T5拍Ready信号为低,slave一侧没有做好接收数据的准备,因此data等了一拍以后才写出去,从之前的波形中可以看出来,data正常都是等了一拍以后才会写出去,因此在t4拍开始等了两拍,在第三拍的时候才将数据成功发送。
1.1 搭建VIP_lib框架
1.1.1 ahb_agent框架搭建
:::danger 【思考】
为了验证AHB_RAM的设计代码,其接口类型是AHB的,为了通过这个AHB给DUT给定测试激励,首先需要agent来在环境中帮助给出激励,而这个agent需要VIP来提供,因此我们需要使用到AHB这个协议,此部分来实现VIP。 :::其中ahb_driver_common.sv用来防止一些公共的驱动; ahb_types用来放置一些公共的类型; 之所以有一些类名前没有master,是因为之后slave和master可能有相同的部分,因此都需要继承同一个公共的类。
:::info (1)在ahb_pkg中导入VIP文件; :::
`ifndef AHB_PKG_SV
`define AHB_PKG_SV
package ahb_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
`include "ahb_defines.svh"
`include "ahb_types.sv"
`include "ahb_transaction.sv"
`include "ahb_sequencer.sv"
`include "ahb_driver.sv"
`include "ahb_monitor.sv"
`include "ahb_master_transaction.sv"
`include "ahb_master_sequencer.sv"
`include "ahb_master_driver.sv"
`include "ahb_master_monitor.sv"
`include "ahb_master_agent.sv"
endpackage
`endif // AHB_PKG_SV
:::info
(2)ahb_driver & ahb_master_driver
:::
:::danger
【注】
对于driver和sequencer参数类而言,由于在master和slave中可能传递的是不同的transaction,因此这里应当在父类中给定参数的传递:
:::
`ifndef AHB_DRIVER_SV
`define AHB_DRIVER_SV
class ahb_driver #(type REQ = ahb_transaction, type RSP = REQ) extends uvm_driver #(REQ, RSP);
`uvm_component_utils(ahb_driver)
function new (string name = "ahb_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
function build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
function connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.raise_objection(phase);
phase.drop_objection(phase);
endtask
endclass
`endif // AHB_DRIVER_SV
1.1.2 参数类问题
ahb_driver作为父类而言,不仅不能做参数,还应当保留参数。使得继承于它的子类可以将这些属性保留下来
- uvm_sequencer首先应该是一个参数类,所以紧跟它有一个#;
- 同时,为了将REQ和RSQ在这一层子类的类型传导到父类,所以在后面加了第二个#。
第一个#是声明参数,第二个#是参数的传导/给定。
需要将参数传导至上一层的原因是,父类中传递的事物是uvm_sequence_item类型的,而driver中传递的事物是ahb_transaction类型的。
:::info (3)编辑参数类ahb_sequencer & ahb_master_sequencer :::
`ifndef AHB_SEQUENCER_SV
`define AHB_SEQUENCER_SV
class ahb_sequencer #(type REQ = ahb_transaction, type RSP = REQ) extends uvm_sequencer #(REQ, RSP);
`uvm_component_utils(ahb_sequencer)
function new (string name = "ahb_sequencer", uvm_component parent = null);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
endtask
endclass
`endif // AHB_SEQUENCER_SV
`ifndef AHB_MASTER_SEQUENCER_SV
`define AHB_MASTER_SEQUENCER_SV
class ahb_master_sequencer extends ahb_sequencer;
`uvm_component_utils(ahb_master_sequencer)
function new (string name = "ahb_master_sequencer", uvm_component parent = null);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
endtask
endclass
`endif // AHB_MASTER_SEQUENCER_SV
:::info (4)编辑ahb_monitor & ahb_master_monitor :::
`ifndef AHB_MONITOR_SV
`define AHB_MONITOR_SV
class ahb_monitor extends uvm_monitor;
`uvm_component_utils(ahb_monitor)
function new (string name = "ahb_monitor", uvm_component parent = null);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
endtask
endclass
`endif // AHB_MONITOR_SV
`ifndef AHB_MASTER_MONITOR_SV
`define AHB_MASTER_MONITOR_SV
class ahb_master_monitor extends ahb_monitor;
`uvm_component_utils(ahb_master_monitor)
function new (string name = "ahb_master_monitor", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
endtask
endclass
`endif // AHB_MASTER_MONITOR_SV
:::info (5)编辑configuration及agent_configuration :::
`ifndef AHB_CONFIGURATION_SV
`define AHB_CONFIGURATION_SV
class ahb_configuration extends uvm_object;
`uvm_object_utils_begin(ahb_configuration)
`uvm_object_utils_end
function new (string name = "ahb_configuration");
super.new(name);
endfunction
endclass
`endif // AHB_CONFIGURATION_SV
config文件不仅要对ahb进行配置,还需要对ahb_vip中的agent进行配置。
:::info (6)Makefile文件 ::: :::danger 【思考】
- 搭好了框架以后如何让AHB开始工作?AHB在ENV中应该给出什么样的激励给DUT?
- 给AHB_RAM供给什么数据内容?
:::
1.1.3 VIP_lib补充
注:实际上对于VIP_lib的补充是发生在env连接关系之后的,根据移植过来的env环境来对vip_lib中的各个组件进行修改。 :::info 根据env中的连接关系:
- 虽然在env中是ahb_mst_monitor上的port连接到了predictor上,实际上mst_monitor和slave_monitor都会监测数据,所以将这个port放在ahb_monitor上,使得继承于它的子类都能够使用该port。
:::
``verilog
ifndef AHB_MONITOR_SV `define AHB_MONITOR_SV
class ahb_monitor extends uvm_monitor;
uvm_analysis_port #(ahb_transaction) item_observed_port;
`uvm_component_utils(ahb_monitor)
function new (string name = “ahb_monitor”, uvm_component parent = null); super.new(name,parent); item_observed_port = new(“item_observed_port”, this); endfunction
function void build_phase(uvm_phase phase); super.build_phase(phase); endfunction
function void connect_phase(uvm_phase phase); super.connect_phase(phase); endfunction
task run_phase(uvm_phase phase); super.run_phase(phase); endtask
endclass
`endif // AHB_MONITOR_SV
:::info
(2)在env的connect_phase中,有许多port连接到了组件上,因此需要在agent中对组件进行例化:
- 在agent中声明config和vif,并在build_phase中从上层拿到cfg和vif;
- 在agent中声明组件并在build_phase中例化;
- 在connect_phase中完成driver和sequencer之间端口的连接,将vif与子一级的组件之间进行连接
:::
:::info
【补充】<br />根据标准的VIP_lib,在ahb_agent_configuration中需要声明is_active变量,作用是对driver和monitor进行开关控制。
:::
```verilog
`ifndef AHB_MASTER_AGENT_SV
`define AHB_MASTER_AGENT_SV
class ahb_master_agent extends uvm_agent;
ahb_agent_configuration cfg;
ahb_master_driver driver;
ahb_master_monitor monitor;
ahb_master_sequencer sequencer;
virtual ahb_if vif;
`uvm_component_utils(ahb_master_agent)
function new (string name = "ahb_master_agent", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db #(ahb_agent_configuration)::get(this, "", "cfg", cfg) begin
`uvm_fatal("GETCFG", "cannot get ahb_agent_configuration")
end
if(!uvm_config_db #(ahb_if)::get(this, "", "vif", vif) begin
`uvm_fatal("GETVIF", "cannot get vif")
end
monitor = ahb_master_monitor::type_id::create("monitor", this);
if(cfg.is_active) begin
driver = ahb_master_driver::type_id::create("driver", this);
sequencer = 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);
driver.vif = vif;
monitor.vif = vif;
sequencer.vif = vif;
end
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
endtask
endclass
`endif // AHB_MASTER_AGENT_SV
`ifndef AHB_MASTER_DRIVER_SV
`define AHB_MASTER_DRIVER_SV
class ahb_master_driver extends ahb_driver;
ahb_agent_configuration cfg;
virtual ahb_if vif;
`uvm_component_utils(ahb_master_driver)
function new (string name = "ahb_master_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
endtask
endclass
`endif // AHB_MASTER_DRIVER_SV
`ifndef AHB_MASTER_MONITOR_SV
`define AHB_MASTER_MONITOR_SV
class ahb_master_monitor extends ahb_monitor;
ahb_agent_configuration cfg;
virtual ahb_if vif;
`uvm_component_utils(ahb_master_monitor)
function new (string name = "ahb_master_monitor", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
endtask
endclass
`endif // AHB_MASTER_MONITOR_SV
1.2 ahb_ram顶层环境搭建及仿真
1.2.1 env一侧代码
:::danger 之前已经完成了agent框架的搭建,接下来需要搭建ahb_ram的上层环境,在env中例化agent并运行仿真,在仿真中观察验证结构是什么样的。 ::: :::info (1)ahb_ram_virt_sequencer.sv文件编辑 :::
`ifndef AHB_RAM_VIRTUAL_SEQUENCER_SV
`define AHB_RAM_VIRTUAL_SEQUENCER_SV
class ahb_ram_virtual_sequencer extends uvm_sequencer;
ahb_master_sequencer ahb_mst_sqr;
ahb_ram_config cfg;
`uvm_component_utils(ahb_ram_virtual_sequencer)
function new(string name = "ahb_ram_virtual_sequencer", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
//Get configuration from env layer
uvm_config_db#(ahb_ram_config)::get(this, "", "cfg", cfg);
endfunction
endclass
`endif //AHB_RAM_VIRTUAL_SEQUENCER
:::info (2)env中已经例化了ahb_config文件,所以此处对ahb_config文件进行编辑:
- 声明并例化ahb_vip中的config;
- 在config中声明vif的句柄。
:::
``verilog
ifndef AHB_RAM_CONFIG_SV `define AHB_RAM_CONFIG_SV
class ahb_ram_config extends uvm_object;
int seq_check_count; int seq_check_error;
int scb_check_count; int scb_check_error;
bit scb_enable = 1; bit cov_enable = 1;
ahb_configuration ahb_cfg; virtual ahb_ram_if vif;
`uvm_object_utils(ahb_ram_config)
// USER to specify the config items
function new (string name = “ahb_ram_config”); super.new(name); ahb_cfg = ahb_configuration::type_id::create(“ahb_cfg”); endfunction : new
endclass `endif // AHB_RAM_CONFIG_SV
> config中配置了用于控制scoreboard和coverage的开关。
:::info
(3)在config中配置了用于控制scoreboard和coverage的开关,因此需要对subscriber编辑:
:::
```verilog
`ifndef AHB_RAM_SUBSCRIBER_SV
`define AHB_RAM_SUBSCRIBER_SV
`uvm_analysis_imp_decl(_apb)
class ahb_ram_subscriber extends uvm_component;
// analysis import
uvm_analysis_imp #(ahb_transaction, ahb_ram_subscriber) ahb_trans_observed_imp;
// Declare events
ahb_ram_config cfg;
virtual ahb_ram_if vif;
`uvm_component_utils(ahb_ram_subscriber)
function new(string name = "ahb_ram_subscriber", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
apb_trans_observed_imp = new("apb_trans_observed_imp", this);
// Get configuration from test layer
if(!uvm_config_db#(ahb_ram_config)::get(this, "", "cfg", cfg)) begin
`uvm_fatal("GETCFG", "cannot get conifg object from config db")
end
vif = cfg.vif;
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
do_events_trigger();
do_listen_events();
endtask
virtual function void write(ahb_transaction tr);
endfunction
virtual task do_events_trigger();
endtask
virtual task do_listen_events();
endtask
endclass
`endif // AHB_RAM_SUBSCRIBER_SV
:::info (4)suscriber中监听了来自monitor的数据,scoreboard对采集到的数据进行比较: :::
`ifndef AHB_RAM_SCOREBOARD_SV
`define AHB_RAM_SCOREBOARD_SV
class ahb_ram_scoreboard extends ahb_ram_subscriber;
// Events of scoreboard
`uvm_component_utils(ahb_ram_scoreboard)
function new (string name = "ahb_ram_scoreboard", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
do_countdown_check();
endtask
task do_listen_events();
endtask
virtual task do_data_check();
endtask
endclass
`endif // AHB_RAM_SCOREBOARD_SV
:::info (5)编辑ahb_ram的coverage文件 :::
`ifndef AHB_RAM_COV_SV
`define AHB_RAM_COV_SV
class ahb_ram_cov extends ahb_ram_subscriber;
`uvm_component_utils(ahb_ram_cov)
// Covergroup definition below
function new (string name = "ahb_ram_cov", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task do_listen_events();
endtask
endclass
`endif // AHB_RAM_COV_SV
:::info
(6)寄存器模型编辑:
在生成寄存器模型的时候也需要将map声明到寄存器模型中
:::
`ifndef AHB_RAM_REG_SV
`define AHB_RAM_REG_SV
class ahb_ram_rgm extends uvm_object;
`uvm_object_utils(ahb_ram_rgm)
uvm_reg_map map;
function new (string name = "ahb_ram_rgm");
super.new(name);
endfunction
virtual function build();
map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
endfunction
endclass
`endif // AHB_RAM_REG_SV
:::info
(7)有了寄存器模型,那么也相应需要adapter来进行寄存器模型和总线之间的访问:
adapter中暂时没有声明具体的方法来完成rgm_operation和bus_item之间的转换。
:::
`ifndef AHB_RAM_ADAPTER_SV
`define AHB_RAM_ADAPTER_SV
class ahb_ram_adapter extends uvm_reg_adapter;
`uvm_object_utils(ahb_ram_adapter)
function new(string name = "ahb_ram_adapter");
super.new(name);
endfunction
function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
endfunction
function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
endfunction
endclass
`endif //AHB_RAM_ADAPTER_SV
:::danger (7)在完成了上述组件的内容之后,最后一步就是将他们集成到env中: :::
`ifndef AHB_RAM_ENV_SV
`define AHB_RAM_ENV_SV
class ahb_ram_env extends uvm_env;
ahb_master_agent ahb_mst;
ahb_ram_config cfg;
ahb_ram_virtual_sequencer virt_sqr;
ahb_ram_rgm rgm;
ahb_ram_adapter adapter;
uvm_reg_predictor #(ahb_transfer) predictor;
ahb_ram_cov cov;
ahb_ram_scoreboard scb;
`uvm_component_utils(ahb_ram_env)
function new (string name = "ahb_ram_env", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Get configuration from test layer
if(!uvm_config_db#(ahb_ram_config)::get(this,"","cfg", cfg)) begin
`uvm_fatal("GETCFG","cannot get config object from config DB")
end
uvm_config_db#(ahb_ram_config)::set(this, "virt_sqr", "cfg", cfg);
uvm_config_db#(ahb_ram_config)::set(this, "cov", "cfg", cfg);
uvm_config_db#(ahb_ram_config)::set(this, "scb", "cfg", cfg);
uvm_config_db#(ahb_agent_configuration)::set(this, "ahb_mst", "cfg", cfg.ahb_cfg);
ahb_mst = ahb_master_agent::type_id::create("ahb_mst", this);
virt_sqr = ahb_ram_virtual_sequencer::type_id::create("virt_sqr", this);
if(!uvm_config_db#(ahb_ram_rgm)::get(this,"","rgm", rgm)) begin
rgm = ahb_ram_rgm::type_id::create("rgm", this);
rgm.build();
end
uvm_config_db#(ahb_ram_rgm)::set(this, "*", "rgm", rgm);
adapter = ahb_ram_adapter::type_id::create("adapter");
predictor = uvm_reg_predictor#(ahb_transfer)::type_id::create("predictor", this);
scb = ahb_ram_scoreboard::type_id::create("scb", this);
cov = ahb_ram_cov::type_id::create("cov", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
virt_sqr.ahb_mst_sqr = ahb_mst.sequencer;
rgm.map.set_sequencer(ahb_mst.sequencer, adapter);
ahb_mst.monitor.item_observed_port.connect(predictor.bus_in);
predictor.map = rgm.map;
predictor.adapter = adapter;
ahb_mst.monitor.item_observed_port.connect(cov.ahb_trans_observed_imp);
ahb_mst.monitor.item_observed_port.connect(scb.ahb_trans_observed_imp);
endfunction
function void report_phase(uvm_phase phase);
string reports = "\n";
super.report_phase(phase);
reports = {reports, $sformatf("================================================= \n")};
reports = {reports, $sformatf("CURRENT TEST SUMMARY \n")};
reports = {reports, $sformatf("SEQUENCE CHECK COUNT : %0d \n", cfg.seq_check_count)};
reports = {reports, $sformatf("SEQUENCE CHECK ERROR : %0d \n", cfg.seq_check_error)};
reports = {reports, $sformatf("SCOREBOARD CHECK COUNT : %0d \n", cfg.scb_check_count)};
reports = {reports, $sformatf("SCOREBOARD CHECK COUNT : %0d \n", cfg.scb_check_error)};
reports = {reports, $sformatf("=================================================")};
`uvm_info("TEST_SUMMARY",reports, UVM_LOW);
endfunction
endclass
`endif // AHB_RAM_ENV_SV
在env搭建这一步中,特别是在connect_phase这一步中,需要观察每一个组件中哪些部分进行了连接:
- rgm中map连接到了sequencer和adapter中,故需要在adapter中添加map;
- monitor的port连接到了predictor的bus_in上,故需要在monitor中声明port;
1.2.2 test一侧代码
:::info 新建ahb_ram_seq_lib.svh并将base_virt_seq和发烟_seq集成在内; :::
`ifndef AHB_RAM_SEQ_LIB_SVH
`define AHB_RAM_SEQ_LIB_SVH
`include "ahb_ram_base_virtual_seq.sv"
`include "ahb_ram_smoke_virt_seq.sv"
`endif
`ifndef AHB_RAM_BASE_VIRT_SEQ_SV
`define AHB_RAM_BASE_VIRT_SEQ_SV
class ahb_ram_base_virt_seq extends uvm_sequence;
ahb_ram_config cfg;
virtual ahb_ram_if vif;
ahb_ram_rgm rgm;
bit [31:0] rd_val, wr_val;
uvm_status_e status;
`uvm_object_utils(ahb_ram_base_virt_seq)
`uvm_declare_p_sequencer(ahb_ram_virtual_sequencer)
function new(string name = "ahb_ram_base_virt_seq");
super.new(name);
endfunction
virtual task body();
`uvm_info("body","Entered...",UVM_LOW)
//Get cfg from p_sequencer
cfg = p_sequencer.cfg;
vif = cfg.vif;
rgm = cfg.rgm;
`uvm_info("body","Exiting...",UVM_LOW)
endtask
virtual function void compare_data(logic[31:0] val1, logic[31:0] val2);
cfg.seq_check_count++;
if(val1 === val2)
`uvm_info("CMPSUC", $sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)
else begin
cfg.seq_check_error++;
`uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))
end
endfunction
task wait_reset_asserted();
@(posedge vif.rst_n);
endtask
task wait_reset_released();
@(negedge vif.rst_n);
endtask
endclass
`endif //AHB_RAM_BASE_VIRT_SEQ
`ifndef AHB_RAM_SMOKE_VIRT_SEQ_SV
`define AHB_RAM_SMOKE_VIRT_SEQ_SV
class ahb_ram_smoke_virt_seq extends apb_watchdog_base_virt_seq;
`uvm_object_utils(ahb_ram_smoke_virt_seq)
function new(string name = "ahb_ram_smoke_virt_seq");
super.new(name);
endfunction
virtual task body();
super.body();
`uvm_info("body","Entered...",UVM_LOW)
`uvm_info("body","EXited...", UVM_LOW)
endtask
endclass
`endif //AHB_RAM_SMOKE_VIRT_SEQ_SV
:::info 在test一层中补充对应的test文件:
- apb_ram_base_test.sv
- apb_ram_smoke_test.sv
:::
``verilog
ifndef AHB_RAM_BASE_TEST_SV `define AHB_RAM_BASE_TEST_SV
virtual class ahb_ram_base_test extends uvm_test;
ahb_ram_config cfg;
ahb_ram_env env;
ahb_ram_rgm rgm;
function new(string name = "ahb_ram_base_test", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
rgm = ahb_ram_rgm::type_id::create("rgm");
rgm.build();
uvm_config_db#(ahb_ram_rgm)::set(this, "env", "rgm", rgm);
cfg = ahb_ram_config::type_id::create("cfg");
cfg.rgm = rgm;
if(!uvm_config_db#(virtual ahb_ram_if)::get(this,"","vif", cfg.vif)) begin
`uvm_fatal("GETCFG","cannot get virtual interface from config DB")
end
uvm_config_db#(ahb_ram_config)::set(this, "env", "cfg", cfg);
env = ahb_ram_env::type_id::create("env", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.phase_done.set_drain_time(this, 1us);
phase.raise_objection(this);
phase.drop_objection(this);
endtask
endclass
`endif //AHB_RAM_BASE_TEST
```verilog
`ifndef AHB_RAM_SMOKE_TEST_SV
`define AHB_RAM_SMOKE_TEST_SV
class ahb_ram_smoke_test extends apb_watchdog_base_test;
`uvm_component_utils(ahb_ram_smoke_test)
function new(string name = "ahb_ram_smoke_test", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase(uvm_phase phase);
ahb_ram_smoke_virt_seq seq = ahb_ram_smoke_virt_seq::type_id::create("this");
super.run_phase(phase);
phase.raise_objection(this);
seq.start(env.virt_sqr);
phase.drop_objection(this);
endtask
endclass
`endif //AHB_RAM_SMOKE_TEST_SV
`ifndef AHB_RAM_TESTS_SVH
`define AHB_RAM_TESTS_SVH
`include "ahb_ram_base_test.sv"
`include "ahb_ram_smoke_test.sv"
`endif // AHB_RAM_TESTS_SVH
【调试及结果】
调试报错没有拿到vif
:::info
在tb中例化interface并使用config_db机制向下传递。
:::
搭建好以后的结构如上图所示