----------------env、virtual sequencer、scoreboard、顶层config、covergroup、subscriber
subscriber:负责从monitor测监听数据,收到master transaction。scoreboard继承于subscriber
virtual sequencer:
`ifndef RKV_AHBRAM_VIRTUAL_SEQUENCER_SV
`define RKV_AHBRAM_VIRTUAL_SEQUENCER_SV
class rkv_ahbram_virtual_sequencer extends uvm_sequencer;
// add sub-instances' sqr handles below for routing把各个Sequencer添加在下面
rkv_ahbram_config cfg; //顶层的配置文件
lvc_ahb_master_sequencer ahb_mst_sqr;
`uvm_component_utils(rkv_ahbram_virtual_sequencer)
function new (string name = "rkv_ahbram_virtual_sequencer", 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#(rkv_ahbram_config)::get(this,"","cfg", cfg)) begin
`uvm_fatal("GETCFG","cannot get config object from config DB")
end
endfunction
endclass
`endif
顶层config:在env中set
`ifndef RKV_AHBRAM_CONFIG_SV
`define RKV_AHBRAM_CONFIG_SV
class rkv_ahbram_config extends uvm_object;
int seq_check_count;
int seq_check_error;
int scb_check_count;
int scb_check_error;
bit enable_cov = 1;
bit enable_scb = 1;
lvc_ahb_agent_configuration ahb_cfg;//导入底层agent的config
virtual rkv_ahbram_if vif;//接口
rkv_ahbram_rgm rgm;//寄存器模型 有什么用?
`uvm_object_utils(rkv_ahbram_config)
// USER to specify the config items
function new (string name = "rkv_ahbram_config");
super.new(name);
ahb_cfg = lvc_ahb_agent_configuration::type_id::create("ahb_cfg");
endfunction : new
endclass
`endif // RKV_AHBRAM_CONFIG_SV
subscriber:
`ifndef RKV_AHBRAM_SUBSCRIBER_SV
`define RKV_AHBRAM_SUBSCRIBER_SV
class rkv_ahbram_subscriber extends uvm_component;
// analysis import
uvm_analysis_imp #(lvc_ahb_transaction, rkv_ahbram_subscriber) ahb_trans_observed_imp;
// events delcared
protected uvm_event_pool _ep;//event pool用途?
rkv_ahbram_config cfg;
virtual rkv_ahbram_if vif;
`uvm_component_utils(rkv_ahbram_subscriber)
function new (string name = "rkv_ahbram_subscriber", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ahb_trans_observed_imp = new("ahb_trans_observed_imp", this);//例化import
// Get configuration from test layer
if(!uvm_config_db#(rkv_ahbram_config)::get(this,"","cfg", cfg)) begin
`uvm_fatal("GETCFG","cannot get config object from config DB")
end
vif = cfg.vif;//目的是?
// Local event pool and events creation
_ep = new("_ep");
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
do_events_trigger();
do_listen_events();
endtask
virtual function void write(lvc_ahb_transaction tr);
endfunction
virtual task do_events_trigger();
endtask
virtual task do_listen_events();
endtask
endclass
`endif
scoreboard:
`ifndef RKV_AHBRAM_SCOREBOARD_SV
`define RKV_AHBRAM_SCOREBOARD_SV
class rkv_ahbram_scoreboard extends rkv_ahbram_subscriber;
// events of scoreboard
// typedef enum {CHECK_LOADCOUNTER} check_type_e;
`uvm_component_utils(rkv_ahbram_scoreboard)
function new (string name = "rkv_ahbram_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_data_check();
endtask
task do_listen_events();
endtask
virtual task do_data_check();
endtask
endclass
`endif
env:
`ifndef RKV_AHBRAM_ENV_SV
`define RKV_AHBRAM_ENV_SV
class rkv_ahbram_env extends uvm_env;
lvc_ahb_master_agent ahb_mst;
rkv_ahbram_config cfg;
rkv_ahbram_virtual_sequencer virt_sqr;
rkv_ahbram_rgm rgm;
rkv_ahbram_reg_adapter adapter;
uvm_reg_predictor #(lvc_ahb_transaction) predictor;
rkv_ahbram_cov cov;
rkv_ahbram_scoreboard scb;
`uvm_component_utils(rkv_ahbram_env)
function new (string name = "rkv_ahbram_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#(rkv_ahbram_config)::get(this,"","cfg", cfg)) begin
`uvm_fatal("GETCFG","cannot get config object from config DB")
end
uvm_config_db#(rkv_ahbram_config)::set(this, "virt_sqr", "cfg", cfg);
uvm_config_db#(rkv_ahbram_config)::set(this, "cov", "cfg", cfg);
uvm_config_db#(rkv_ahbram_config)::set(this, "scb", "cfg", cfg);
uvm_config_db#(lvc_ahb_agent_configuration)::set(this, "ahb_mst", "cfg", cfg.ahb_cfg);//config的set都在env
ahb_mst = lvc_ahb_master_agent::type_id::create("ahb_mst", this);
virt_sqr = rkv_ahbram_virtual_sequencer::type_id::create("virt_sqr", this);
if(!uvm_config_db#(rkv_ahbram_rgm)::get(this,"","rgm", rgm)) begin
rgm = rkv_ahbram_rgm::type_id::create("rgm", this);
rgm.build();
end
uvm_config_db#(rkv_ahbram_rgm)::set(this,"*","rgm", rgm);//set rgm?
adapter = rkv_ahbram_reg_adapter::type_id::create("adapter", this);
predictor = uvm_reg_predictor#(lvc_ahb_transaction)::type_id::create("predictor", this);
cov = rkv_ahbram_cov::type_id::create("cov", this);
scb = rkv_ahbram_scoreboard::type_id::create("scb", 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 end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
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 ERROR : %0d \n", cfg.scb_check_error)};
reports = {reports, $sformatf("=============================================== \n")};
`uvm_info("TEST_SUMMARY", reports, UVM_LOW)
endfunction
endclass
`endif // RKV_AHBRAM_ENV_SV
rgm: object类型没有build phase 只能用build
`ifndef RKV_AHBRAM_REG_SV
`define RKV_AHBRAM_REG_SV
class rkv_ahbram_rgm extends uvm_reg_block;
`uvm_object_utils(rkv_ahbram_rgm)
uvm_reg_map map;
function new(string name = "rkv_watchdog_rgm");
super.new(name, UVM_NO_COVERAGE);
endfunction
virtual function build();
map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
// TODO
endfunction
endclass
`endif
monitor中加了个port:uvm_analysis_port #(lvc_ahb_transaction) item_observed_port;以及new
完善agent(cfg)例化并创建driver、monitor、sequencer。 以及vif
lvc_ahb_agent_configuration cfg;
lvc_ahb_master_driver driver;
lvc_ahb_master_monitor monitor;
lvc_ahb_master_sequencer sequencer;
virtual lvc_ahb_if vif;
…………
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(lvc_ahb_agent_configuration)::get(this,"","cfg", cfg)) begin
`uvm_fatal("GETCFG","cannot get config object from config DB")
end
if(!uvm_config_db#(virtual lvc_ahb_if)::get(this,"","vif", vif)) begin
`uvm_fatal("GETVIF","cannot get vif handle from config DB")
end
monitor = lvc_ahb_master_monitor::type_id::create("monitor", this);
if(cfg.is_active) begin
driver = lvc_ahb_master_driver::type_id::create("driver", this);
sequencer = lvc_ahb_master_sequencer::type_id::create("sequencer", this);
end
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
monitor.vif = vif;
if(cfg.is_active) begin
driver.seq_item_port.connect(sequencer.seq_item_export);
driver.vif = vif;
sequencer.vif = vif;
end
endfunction
在agent_configuration,加入is_active,如果为1则在agent创建以及连接driver、sequencer否则只有monitor。
在master_driver\monitor\sequencer里加入cfg 和vif
-----------------顶层创建rkv_ahbram_base_virtual_sequence、rkv_ahbram_smoke_virt_seq、rkv_ahbram_seq_lib
rkv_ahbram_seq_lib包含两个sequence
`ifndef RKV_AHBRAM_SEQ_LIB_SVH
`define RKV_AHBRAM_SEQ_LIB_SVH
`include "rkv_ahbram_base_virtual_sequence.sv"
`include "rkv_ahbram_smoke_virt_seq.sv"
`endif
rkv_ahbram_base_virtual_sequence:
`ifndef RKV_AHBRAM_BASE_VIRTUAL_SEQUENCE_SV
`define RKV_AHBRAM_BASE_VIRTUAL_SEQUENCE_SV
class rkv_ahbram_base_virtual_sequence extends uvm_sequence;
rkv_ahbram_config cfg;
virtual rkv_ahbram_if vif;
rkv_ahbram_rgm rgm;
bit[31:0] wr_val, rd_val;
uvm_status_e status;//?
`uvm_object_utils(rkv_ahbram_base_virtual_sequence)
`uvm_declare_p_sequencer(rkv_ahbram_virtual_sequencer)
function new (string name = "rkv_ahbram_base_virtual_sequence");
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;
// TODO in sub-class
`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("CMPERR", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))
end
endfunction
task wait_reset_signal_assertted();
@(posedge vif.rstn);
endtask
task wait_reset_signal_released();
@(negedge vif.rstn);
endtask
endclass
`endif
-------------------顶层base test 和smoke test
`ifndef RKV_AHBRAM_BASE_TEST_SV
`define RKV_AHBRAM_BASE_TEST_SV
virtual class rkv_ahbram_base_test extends uvm_test;
rkv_ahbram_config cfg;
rkv_ahbram_env env;
rkv_ahbram_rgm rgm;
function new (string name = "rkv_ahbram_base_test", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
rgm = rkv_ahbram_rgm::type_id::create("rgm");//rgm的创建在test中
rgm.build();
uvm_config_db#(rkv_ahbram_rgm)::set(this, "env", "rgm", rgm);
cfg = rkv_ahbram_config::type_id::create("cfg");//config的创建
cfg.rgm = rgm;
if(!uvm_config_db#(virtual rkv_ahbram_if)::get(this,"","vif", cfg.vif))
`uvm_fatal("GETCFG","cannot get virtual interface from config DB")
uvm_config_db#(rkv_ahbram_config)::set(this, "env", "cfg", cfg);
env = rkv_ahbram_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
`ifndef RKV_AHBRAM_SMOKE_TEST_SV
`define RKV_AHBRAM_SMOKE_TEST_SV
class rkv_ahbram_smoke_test extends rkv_ahbram_base_test;
`uvm_component_utils(rkv_ahbram_smoke_test)
function new (string name = "rkv_ahbram_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);
rkv_ahbram_smoke_virt_seq seq = rkv_ahbram_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
两个test文件存到tests文件里
最后文件都放package里
make elab
make run GUI=1 &
在顶层testbench:例化和set interface
module rkv_ahbram_tb;
import uvm_pkg::*;
`include "uvm_macros.svh"
import rkv_ahbram_pkg::*;
ahb_blockram_32 dut();
lvc_ahb_if ahb_if();
rkv_ahbram_if ahbram_if();
initial begin
uvm_config_db#(virtual lvc_ahb_if)::set(uvm_root::get(), "uvm_test_top.env.ahb_mst", "vif", ahb_if);
uvm_config_db#(virtual rkv_ahbram_if)::set(uvm_root::get(), "uvm_test_top", "vif", ahbram_if);
uvm_config_db#(virtual rkv_ahbram_if)::set(uvm_root::get(), "uvm_test_top.env", "vif", ahbram_if);
uvm_config_db#(virtual rkv_ahbram_if)::set(uvm_root::get(), "uvm_test_top.env.virt_sqr", "vif", ahbram_if);
run_test();
end
endmodule