(1) 在connection中进行signal的连接,以及config_db.
`include "uvm_pkg.sv"
`include "svt_axi_if.svi"
`include "svt_axi.uvm.pkg"
import uvm_pkg::*;
import svt_uvm_pkg::*;
import svt_axi_uvm_pkg::*;
module top;
svt_axi_if axi_if;
initial begin
信号连接.
force axi_if.xxx = dut.xxx;
uvm_config_db#(virtual svt_axi_if)::set(uvm_root::get(), "uvm_test_top.env.axi_system_env", "vif", axi_if);
end
endmodule
(2) 在env中搭建axi的相关环境
axi_system_env中master和slave的monitor中有item_start_port和item_observed_port,item_start_port中只有地址相关信息,item_observed_port比较常用,包含地址和数据和strb等信息, 连接后把数据打印一下就好.
`include "cust_svt_axi_system_configuration.sv"
class base_env extends uvm_env;
svt_axi_system_env axi_system_env;
cust_svt_axi_system_configuration axi_sys_cfg;
axi_slv_subscriber slv_scbr;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
axi_system_env = svt_axi_system_env::type_id::create("axi_system_env", this);
axi_sys_cfg = cust_svt_axi_system_configuration::type_id::("axi_sys_cfg");
uvm_config_db#(svt_axi_system_configuration)::set(this, "axi_sytem_env", "cfg", axi_sys_cfg);
slv_scbr = axi_slv_subscriber::type_id::create("slv_scbr", this);
endfunction
virtual function void connet_phase(uvm_phase phase);
vseqr.axi0_mst_seqr = axi_system_env.master[0].sequencer;
vseqr.axi0_slv_seqr = axi_system_env.slave[0].sequencer;
xxx
axi_system_env.master[0].monitor.item_started_port.connect(slv_scbr.analysis_export);
axi_system_env.master[0].monitor.item_observed_port.connect(slv_scbr.axi_slv_export);
endfunction
endclass
(3) cust_svt_axi_system_configuration相关部分配置
class cust_svt_axi_system_configuration extends svt_axi_system_configuration;
`uvm_object_utils(cust_svt_axi_system_configuration)
function new(string name = "cust_svt_axi_system_configuration");
super.new(name);
this.num_masters = 3;
this.num_slaves = 3;
this.create_sub_cfgs(3,3);
this.wready_watchdog_timeout = 0;
this.rdata_watchdog_timeout = 0;
this.rready_watchdog_timeout = 0;
this.bready_watchdog_timeout = 0;
this.master_cfg[0].is_active = 1;
this.master_cfg[0].enable_xml_gen =1;
this.master_cfg[0].addr_width =32;
this.master_cfg[0].data_width = 64;
this.master_cfg[0].id_width = 5;
if($test$plusargs("exclusive")) begin
this.master_cfg[0].exclusive_access_enable = 1;
end else begin
this.master_cfg[0].exclusive_access_enable = 0;
end
if($test$plusargs("bready_delay")) begin
this.master_cfg[0].default_bready = 0;
end
this.master_cfg[0].axi_interface_type = svt_axi_port_configuragion:AXI4;
this.master_cfg[0].awuser_enable = 1;
this.master_cfg[0].wuser_enable = 0;
this.master_cfg[0].buser_enalbe = 0;
this.master_cfg[0].aruser_enable = 1;
this.master_cfg[0].ruser_enable = 0;
this.master_cfg[0].awqos_enable = 0;
this.master_cfg[0].awregion_enable = 0;
this.master_cfg[0].arqos_enable = 0;
this.master_cfg[0].arregion_enable = 0;
this.master_cfg[0].num_outstanding_xact = -1;
if($test$plusargs("ostd_on")) begin
this.master_cfg[0].num_read_outstanding_xact = 128;
this.master_cfg[0].num_write_outstanding_xact = 128;
end else begin
this.master_cfg[0].num_read_outstanding_xact = 1;
this.master_cfg[0].num_write_outstanding_xact = 1;
end
this.master_cfg[0].toggle_coverage_enable = 1'b0;
this.master_cfg[0].state_coverage_enable = 1'b0;
this.master_cfg[0].transaction_coverage_enable = 1'b0;
this.slave_cfg[0].is_active = 1;
this.slave_cfg[0].enable_xml_gen =1;
this.slave_cfg[0].addr_width = 32;
this.slave_cfg[0].data_width = 64;
this.slave_cfg[0].id_width = 5;
if($test$plusargs("exclusive")) begin
this.slave_cfg[0].exclusive_access_enable = 1;
end else begin
this.slave_cfg[0].exclusive_access_enable = 0;
end
if($test$plusargs("bready_delay")) begin
this.slave_cfg[0].default_bready = 0;
end
this.slave_cfg[0].axi_interface_type = svt_axi_port_configuragion:AXI4;
this.slave_cfg[0].awuser_enable = 1;
this.slave_cfg[0].wuser_enable = 0;
this.slave_cfg[0].buser_enalbe = 0;
this.slave_cfg[0].aruser_enable = 1;
this.slave_cfg[0].ruser_enable = 0;
this.slave_cfg[0].awqos_enable = 0;
this.slave_cfg[0].awregion_enable = 0;
this.slave_cfg[0].arqos_enable = 0;
this.slave_cfg[0].arregion_enable = 0;
this.slave_cfg[0].num_outstanding_xact = -1;
if($test$plusargs("ostd_on")) begin
this.slave_cfg[0].num_read_outstanding_xact = 128;
this.slave_cfg[0].num_write_outstanding_xact = 128;
end else begin
this.slave_cfg[0].num_read_outstanding_xact = 2;
this.slave_cfg[0].num_write_outstanding_xact = 2;
end
this.slave_cfg[0].toggle_coverage_enable = 1'b0;
this.slave_cfg[0].state_coverage_enable = 1'b0;
this.slave_cfg[0].transaction_coverage_enable = 1'b0;
xxx
endfunction
endclass
(4) 在filelist.f中添加define
+define+SYNOPSYS_SV
+define+UVM_DISABLE_AUTO_ITEM_RECORDING
+define+UVM_PACKER_MAX_BYTES=1500000
(5) 在scbr中打印axi的transaction
class axi_slv_subscriber extends uvm_subscriber#(svt_axi_transaction);
`uvm_analysis_imp_decl(_axi_slv)
uvm_analysis_imp_axi_slv#(svt_axi_transaction, axi_slv_subscriber) axi_slv_export;
function new(string name="axi_slv_subscriber", uvm_componet parent=null);
super.new(name, parent);
axi_slv_export = new("axi_slv_export", this);
endfunction
extern virtual function void write_axi_slv(svt_axi_transaction t);
endclas
function void axi_slv_subscriber ::write_axi_slv(svt_axi_transaction t);
svt_axi_transaction item;
if(!$cast(item, t.clone()))
`uvm_fatal("subscriber", "unable to case");
item_q.push_back(item);
`uvm_info(get_type_name(), $sformatf("subscriber, axi_item", item.sprint()), UVM_LOW)
endfunction
(6) master seq和slave seq的基本用法.
class write_sequence extends svt_axi_master_base_sequence;
svt_axi_master_transaction req;
`uvm_object_utils(write_sequence)
function new(string name="write_sequence");
super.new(name);
endfunction
virtual task body();
svt_configuration get_cfg;
super.body();
p_sequencer.get_cfg(get_cfg);
if(!$cast(cfg, get_cfg))begin
`uvm_fatal("body", "unable to case")
end
`uvm_create(req);
req.port_cfg = cfg;
assert(req.randomize with {
req.xact_type == svt_axi_transaction::WRITE;//READ
req.enable_interleave == 1'b0;
req.addr[31:0] == xx_addr;
foreach(xx_data[idx])
req.data[idx] == xx_data[idx];
req.burst_type == svt_axi_transaction::INCR;
req.burst_size == svt_axi_transaction::BURST_SIZE_32BIT;
req.burst_length== xx_len;
req.atomic_type == svt_axi_transaction::NORMAL;
req.data_before_addr == 0;
reference_event_for_first_wvalid_delay == svt_axi_transaction::WRITE_ADDR_HANDSHAKE;
foreach(wstrb[j]) {(wstrb[j]== 32'hffff)};
})
`uvm_send(req)
get_response(rsp);
endtask
endclass
class axi_slave_sequence exntends svt_axi_slave_base_sequence;
svt_axi_slave_transaction req_resp;
`uvm_object_utils(axi_slave_sequence)
function new(string name="axi_slave_sequence");
super.new(name);
endfunction
virtual task body();
interger status;
sink_responses();
forever begin
p_sequencer.response_request_port.peek(req_resp);
resp_cnt++;
status = req_resp.randomize with {
bresp == svt_axi_transaction::OKAY;
foreach (rresp[index]) {
rresp[index] inside {svt_axi_transaction::OKAY};
enable_interleave == 0;
}
}
if(!status)
`uvm_fatal("body", "unable to randomize a resps")
`uvm_send(req)
end
endtask
endclass