apb_if放入所有apb需要的信号,以及cb
`ifndef APB_IF_SV
`define APB_IF_SV
interface apb_if;
logic pclk;
logic prst;
logic penable;
logic psel;
logic pwrite;
logic[31 : 0] prdata;
logic[31 : 0] pwdata;
logic[31 : 0] paddr;
logic[2:0] prot;
logic[3:0] pstrb;
logic pready;
logic pslverr;
clocking slv_cb@(posedge pclk);
default input #1ps output #1ps;
input penable,psel,pwrite,pwdata,paddr,prot,pstrb;
output prdata,pready,pslverr;
endclocking:slv_cb
clocking mon_cb@(posedge pclk);
default input #1ps output #1ps;
input penable,psel,pwrite,pwdata,paddr,prot,pstrb;
input prdata,pready,pslverr;
endclocking:mon_cb
endinterface
`endif // APB_IF_SV
slv_tran的Read or Write,AHB-ram是在types文件里定义,这个在package里定义了
`ifndef APB_TRAN_SV
`define APB_TRAN_SV
class apb_tran extends uvm_sequence_item;
rand logic[31 : 0] pdata;
rand logic[31 : 0] paddr;
rand logic[2:0] prot;
rand logic[3:0] pstrb;
rand bit pslverr;
rand int unsigned nready_num;//cycle number
rand pkind_type_enum pkind_type;
//Read or Write 之前是在types文件里定义 这个在package里定义了
`uvm_object_utils_begin(apb_tran)
`uvm_field_int(paddr,UVM_DEFAULT)
`uvm_field_int(pdata,UVM_DEFAULT)
`uvm_field_int(prot,UVM_DEFAULT)
`uvm_field_int(pstrb,UVM_DEFAULT)
`uvm_field_int(pslverr,UVM_DEFAULT)
`uvm_field_int(nready_num,UVM_DEFAULT)
`uvm_field_enum(pkind_type_enum,pkind_type,UVM_DEFAULT)
`uvm_object_utils_end
function new (string name = "apb_tran");
super.new(name);
endfunction
endclass
`endif//APB_TRAN_SV
apb_drv: 使用一个mem(32,32)存放数据,传递vif(之前在agent传递并连接drv、mon);get and run要确保penable=0 psel=1时开始;在drive_one_t中根据tran中的nready_num测试没有准备好的状态;写操作放入mem;读操作从mem提出;
`ifndef APB_SLV_DRV_SV
`define APB_SLV_DRV_SV
class apb_slv_drv extends uvm_driver#(apb_tran);
`uvm_component_utils(apb_slv_drv)
virtual apb_if vif;
apb_mem#(32,32) mem;//存放写data数据
apb_tran t;
function new(string name = "apb_slv_drv", uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
t=apb_tran::type_id::create("pkt",this);
mem=apb_mem#(32,32)::type_id::create("apb_mem",this);
if(!uvm_config_db#(virtual apb_if)::get(this,"","vif",vif))begin
`uvm_fatal("NO VIF","vif is not found");//传递vif 之前是在agent传递并连接drv、mon
end
endfunction
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
vif.slv_cb.pready <= 1'b1;//初始化ready、slverr
vif.slv_cb.pslverr <= 1'b0;
fork
get_and_drive();
join_none
endtask
virtual task get_and_drive();
forever begin
@(vif.slv_cb)
if(!vif.slv_cb.penable & vif.slv_cb.psel)begin//sel阶段
seq_item_port.get_next_item(t);
`uvm_info(get_type_name(),"sequencer got next item",UVM_HIGH)
drive_one_t(t);
seq_item_port.item_done(t);
`uvm_info(get_type_name(), "sequencer item_done_triggered", UVM_HIGH)
end
end
endtask:get_and_drive
virtual task drive_one_t(apb_tran t);
int nready_cnt;
nready_cnt = t.nready_num;//测试nready
while(nready_cnt != 0)begin
vif.slv_cb.pready <= 1'b0;
nready_cnt--;
@(vif.slv_cb);
end
vif.slv_cb.pready <= 1'b1;
vif.slv_cb.pslverr<= t.pslverr;
if(vif.slv_cb.pwrite)
do_write(t);
else
do_read(t);
endtask
virtual task do_write(apb_tran t);//写操作放入mem
if(!t.pslverr)begin
mem.put_data(vif.slv_cb.paddr,vif.slv_cb.pwdata);
end
endtask
virtual task do_read(apb_tran t);//读操作从mem提出
if(!t.pslverr)begin
vif.slv_cb.prdata <= mem.get_data(vif.slv_cb.paddr);
end
else begin
vif.slv_cb.prdata <= t.pdata;
end
endtask
endclass
`endif//APB_SLV_DRV_SV
mem:写入put进去 读出时判断是否存在写入过的地址
class apb_mem#(DW=32,AW=32) extends uvm_object;
`uvm_object_param_utils(apb_mem)
logic [DW-1:0] mem[int];
function new(string name = "apb_mem");
super.new(name);
endfunction
task put_data(int addr,logic[DW-1:0] data);
this.mem[addr] = data;
`uvm_info(get_full_name(), $sformatf("APB-Memory Write.Address:%0h. Data:%0h.",addr,data),UVM_MEDIUM)
endtask
function logic[DW-1:0] get_data(int addr);
if(this.mem.exists(addr))begin//判断mem中是否有这个地址写入过
get_data = this.mem[addr];
`uvm_info(get_full_name(), $sformatf("APB-Memory pre-defined Read.Address:%0h. Data:%0h.",addr,get_data),UVM_MEDIUM)
end
else begin
get_data = $urandom_range(32'hffff_ffff);
`uvm_info(get_full_name(), $sformatf("APB-Memory un-defined Read.Address:%0h. Data:%0h.",addr,get_data),UVM_MEDIUM)
end
endfunction
endclass
mon:
`ifndef APB_SLV_MON
`define APB_SLV_MON
class apb_slv_mon extends uvm_monitor;
`uvm_component_utils(apb_slv_mon)
uvm_analysis_port #(apb_tran) item_port;
virtual apb_if vif;
function new(string name = "apb_slv_mon", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
item_port = new("item_observed_port", this);
if(!uvm_config_db#(virtual apb_if)::get(this,"","vif",vif))begin
`uvm_fatal("No vif","vif is not found")
end
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
apb_tran t;
while(1)begin
@(vif.mon_cb);
if(vif.mon_cb.penable & vif.mon_cb.pready &vif.mon_cb.psel & vif.mon_cb.presetn)begin
t = apb_tran::type_id::create("t",this);
t.paddr = vif.mon_cb.paddr;
t.prot = vif.mon_cb.prot;
t.pslverr = vif.mon_cb.pslverr;
t.pkind_type = vif.mon_cb.pwrite ? WRITE:READ;
t.pdata = vif.mon_cb.pwrite ? vif.mon_cb.pwdata : vif.mon_cb.prdata;
item_port.write(t);
end
end
endtask
endclass
`endif // APB_SLV_MON
apb_agt: 如果is_active为1例化sqr、drv,否则只例化mon
方便芯片集成以后只接收别的模块来的信号,不需要自己发送激励
`ifndef APB_SLV_AGT_SV
`define APB_SLV_AGT_SV
class apb_slv_agt extends uvm_agent;
apb_slv_drv drv;
apb_slv_mon mon;
apb_slv_sqr sqr;
virtual apb_if vif;
`uvm_component_utils(apb_slv_agt)
function new(string name = "apb_slv_agt", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual apb_if)::get(this,"","vif",vif))begin
`uvm_fatal("GETVIF","cannot get vif handle from config DB")
end
mon = apb_slv_mon::type_id::create("mon",this);
uvm_config_db#(virtual apb_if)::set(this,"mon_i","vif",vif);
void'(uvm_config_db#(uvm_active_passive_enum)::get(this,"","is_active",is_active));
if(is_active == UVM_ACTIVE)begin
sqr_i = apb_slv_sqr::type_id::create("sqr_i",this);
drv_i = apb_slv_drv::type_id::create("drv_i",this);
uvm_config_db#(virtual apb_if)::set(this,"drv_i","vif",vif);
end
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if(is_active == UVM_ACTIVE)begin
drv_i.seq_item_port.connect(sqr_i.seq_item_export);
end
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
endtask
endclass
`endif // APB_SLV_AGT_SV