APB slave侧:
apb_slave_driver.svh:
例化config;注册;virtual vif;增加了 bit[31:0] mem [bit[31:0]]来存放数据;
声明函数new (string name, uvm_component parent); 任务run()、get_and_drive()、drive_transfer(lvc_apb_transfer t)变为drive_response()、reset_listener()、do_idle()、do_write(lvc_apb_transfer t)、do_read(lvc_apb_transfer t);
`ifndef LVC_APB_SLAVE_DRIVER_SVH
`define LVC_APB_SLAVE_DRIVER_SVH
class lvc_apb_slave_driver extends uvm_driver #(lvc_apb_transfer);
//
//
// Public interface (Component users may manipulate these fields/methods)
//
//
lvc_apb_config cfg;
// USER: Add your fields here
bit[31:0] mem [bit[31:0]];
// This macro performs UVM object creation, type control manipulation, and
// factory registration
`uvm_component_utils_begin(lvc_apb_slave_driver)
// USER: Register fields here
`uvm_component_utils_end
// new - constructor
extern function new (string name, uvm_component parent);
// uvm run phase
extern virtual task run();
//
//
// Implementation (private) interface
//
//
// The virtual interface used to drive and view HDL signals.
virtual lvc_apb_if vif;
// This is the method that is responsible for getting sequence transactions
// and driving the transaction into the DUT
extern virtual protected task get_and_drive();
// This method drives response onto the interface
extern virtual protected task drive_response();
// This method that is drive idle respone
extern protected task do_idle();
// This method that is proceed write transaction
extern protected task do_write();
// This method that is proceed read transaction
extern protected task do_read();
// This method reset interface signals
extern virtual protected task reset_listener();
endclass : lvc_apb_slave_driver
`endif // LVC_APB_SLAVE_DRIVER_SVH
apb_slave_driver.sv:
实现头文件中各函数任务;run()→get_and_drive()→get_next_item、drive_transfer(req)中判断trans_kind读写(如下),克隆、id、itemdone→reset_listener(对于vif下)将paddr pwrite psel penable pwdata置0 将总线上prdata pslverr 置0、pready由cfg中SLAVE配置参数确定、将mem清空→drive_response()等待一上升沿,如果psel=1 penable=0(说明总线上有控制信号了)判断读写(如下),否则do idle(对于vif.cb_slv下prdata pslverr置0 pready cfg确定);
写do_write(t):定义32位addr、data变量和两个存放cfg中随机pready次数pslverr状态的变量;当penable=1将vif 中paddr pwdata存入变量,并放入mem对应地址;根据pready次数决定等待周期并根据pslverr状态回应;第一拍给paddr、pwrite=1、psel=1、penable=0,t.data给pwdata;第二拍penable=1传输数据;10ps后等待接口上pready等于1后,1ps判断接口上pslverr如果为1,状态转为ERROR,不为1转为OK;
读do_read(t):定义32位addr、data变量和两个存放cfg中随机pready次数pslverr状态的变量;当penable=1将vif 中paddr 存入变量,判断mem中addr如果有数据提出存入data变量,无数据给默认值;根据pready次数决定等待周期并根据pslverr状态回应,data给vif prdata;
`ifndef LVC_APB_SLAVE_DRIVER_SV
`define LVC_APB_SLAVE_DRIVER_SV
function lvc_apb_slave_driver::new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
task lvc_apb_slave_driver::run();
fork
get_and_drive();
reset_listener();
drive_response();
join_none
endtask : run
task lvc_apb_slave_driver::get_and_drive();
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(), "sequencer got next item", UVM_HIGH)
void'($cast(rsp, req.clone()));
rsp.set_sequence_id(req.get_sequence_id());
seq_item_port.item_done(rsp);
`uvm_info(get_type_name(), "sequencer item_done_triggered", UVM_HIGH)
end
endtask : get_and_drive
task lvc_apb_slave_driver::drive_response();
`uvm_info(get_type_name(), "drive_response", UVM_HIGH)
forever begin
@(vif.cb_slv);
if(vif.cb_slv.psel === 1'b1 && vif.cb_slv.penable === 1'b0) begin
case(vif.cb_slv.pwrite)
1'b1 : this.do_write();
1'b0 : this.do_read();
default : `uvm_error(get_type_name(), "ERROR pwrite signal value")
endcase
end
else begin
this.do_idle();
end
end
endtask : drive_response
task lvc_apb_slave_driver::reset_listener();
`uvm_info(get_type_name(), "reset_listener ...", UVM_HIGH)
fork
forever begin
@(negedge vif.rstn); // ASYNC reset
vif.prdata <= 0;
vif.pslverr <= 0;
vif.pready <= cfg.slave_pready_default_value;
this.mem.delete(); // reset internal memory
end
join_none
endtask: reset_listener
task lvc_apb_slave_driver::do_idle();
`uvm_info(get_type_name(), "do_idle", UVM_HIGH)
vif.cb_slv.prdata <= 0;
vif.cb_slv.pready <= cfg.slave_pready_default_value;
vif.cb_slv.pslverr <= 0;
endtask: do_idle
task lvc_apb_slave_driver::do_write();
bit[31:0] addr;
bit[31:0] data;
int pready_add_cycles = cfg.get_pready_additional_cycles();
bit pslverr_status = cfg.get_pslverr_status();
`uvm_info(get_type_name(), "do_write", UVM_HIGH)
wait(vif.penable === 1'b1);
addr = vif.cb_slv.paddr;
data = vif.cb_slv.pwdata;
mem[addr] = data;
if(pready_add_cycles > 0) begin
#1ps;
vif.pready <= 0;
repeat(pready_add_cycles) @(vif.cb_slv);
end
#1ps;
vif.pready <= 1;
vif.pslverr <= pslverr_status;
fork
begin
@(vif.cb_slv);
vif.cb_slv.pready <= cfg.slave_pready_default_value;
vif.cb_slv.pslverr <= 0;
end
join_none
endtask: do_write
task lvc_apb_slave_driver::do_read();
bit[31:0] addr;
bit[31:0] data;
int pready_add_cycles = cfg.get_pready_additional_cycles();
bit pslverr_status = cfg.get_pslverr_status();
`uvm_info(get_type_name(), "do_read", UVM_HIGH)
wait(vif.penable === 1'b1);
addr = vif.cb_slv.paddr;
if(mem.exists(addr))
data = mem[addr];
else
data = DEFAULT_READ_VALUE;
if(pready_add_cycles > 0) begin
#1ps;
vif.pready <= 0;
repeat(pready_add_cycles) @(vif.cb_slv);
end
#1ps;
vif.pready <= 1;
vif.pslverr <= pslverr_status;
vif.prdata <= data;
fork
begin
@(vif.cb_slv);
vif.cb_slv.pready <= cfg.slave_pready_default_value;
vif.cb_slv.pslverr <= 0;
end
join_none
endtask: do_read
`endif // LVC_APB_SLAVE_DRIVER_SV
apb_slave_monitor.svh:无变化 apb_slave_monitor.sv:---
apb_slave_sequencer.svh、.sv:无变化 apb_slave_agent.svh、.sv:无变化