Step1. Create a slave AXI VIP interface
interface axi_if ();
//-----------------------------------------------------------------------
// AXI Interface setup and hold parameters
//-----------------------------------------------------------------------
parameter setup_time = 1;
parameter hold_time = 1;
bit aclk ;
bit aresetn ;
//-----------------------------------------------------------------------
// AXI Interface Write Address Channel Signals
//-----------------------------------------------------------------------
wire awvalid ;
wire [`DW_VIP_AXI_ADDR_PORT_WIDTH-1:0] awaddr ;
wire [`DW_VIP_AXI_ALEN_PORT_WIDTH-1:0] awlen ;
wire [`DW_VIP_AXI_ASIZE_PORT_WIDTH-1:0] awsize ;
wire [`DW_VIP_AXI_ABURST_PORT_WIDTH-1:0] awburst ;
wire [`DW_VIP_AXI_ALOCK_PORT_WIDTH-1:0] awlock ;
wire [`DW_VIP_AXI_ACACHE_PORT_WIDTH-1:0] awcache ;
wire [`DW_VIP_AXI_APROT_PORT_WIDTH-1:0] awprot ;
wire [`DW_VIP_AXI_AID_PORT_WIDTH-1:0] awid ;
wire [`DW_VIP_AXI_AWSIDEBAND_PORT_WIDTH-1:0] awsideband ;
wire awready ;
clocking slave_clocking_block @(posedge aclk);
default input #setup_time output #hold_time ;
input aresetn ;
input awvalid ;
input awaddr ;
input awlen ;
input awsize ;
input awburst ;
input awlock ;
input awcache ;
input awprot ;
input awid ;
output awready ;
input awsideband ;
endclocking : slave_clocking_block
//------------------------------------------------------------------------
/** Modport used to connect the VIP AXI Slave to AXI interface signals. */
modport axi_slave_modport(import clk_block.*, import slave_clocking_block.*);
endinterface: axi_if
Step2. Create Slave AXI VIP Configuration (axiCfg)
class axiCfg extends vmm_data;
dw_vip_axi_system_model_configuration vip_axi_sys_cfg;
dw_vip_axi_port_model_configuration vip_axi_slave_cfg;
function new();
super.new(this.log);
/* Create system configuration object */
vip_axi_sys_cfg = new (, 1, 1, VMT_BOOLEAN_FALSE);
/* Do system level configuration */
vip_axi_sys_cfg.m_enAddrWidth = dw_vip_axi_configuration :: ADDR_BUS_WIDTH_32;
vip_axi_sys_cfg.m_enDataWidth = dw_vip_axi_configuration :: DATA_BUS_WIDTH_64;
/* Configure this member to maximum ID width within all masters in the system */
vip_axi_sys_cfg.m_nMstrIdWidth = 4;
/* Create port model configuration object for VIP slave. */
vip_axi_slave_cfg = vip_axi_sys_cfg.createPortMdlCfg (`DW_VIP_AXI_SLAVE_PORT_CFG, 0);
/* Do port level configuration */
vip_axi_slave_cfg.m_oPortCfg.m_nNumOutstandingXact = 1;
vip_axi_slave_cfg.m_oPortCfg.m_nIdWidth = 4;
vip_axi_slave_cfg.m_oPortCfg.m_enMemoryDefaultPattern=
dw_vip_axi_configuration::PATTERN_INCR;
endfunction : new
…
endclass : axiCfg
Step3. Create a slave response transactor (refer to the attachment)
class axiSlaveXactor extends vmm_xactor;
/* A local reference to the VIP slave's input and output VMM channel. */
dw_vip_axi_slave_resp_transaction_channel o_output_chan;
dw_vip_axi_slave_resp_transaction_channel o_input_chan;
axiCfg tb_cfg;// slave AXI VIP Configuration handle
AxiSlave oSlave;// slave AXI VIP Model handle, used for FIFO/RAM access
dw_vip_axi_slave_rvm vip_axi_slave;// slave AXI VIP Xactor
dw_vip_axi_slave_resp_transaction resp_trans;// AXI response transaction
//for SB
axiMasterTrans act_trans;
axiMasterTrans_channel act_chan;
axiMasterTrans cpy_trans;
extern function new(axiCfg tb_cfg,
dw_vip_axi_slave_rvm vip_axi_slave,
axiMasterTrans_channel act_chan =null,
dw_vip_axi_slave_resp_transaction_channel o_output_chan,
dw_vip_axi_slave_resp_transaction_channel o_input_chan);
extern virtual task process_axi_resp_trans();
extern virtual task recv_read();
extern virtual task recv_write();
endclass
Step4. Register the slave response transactor and slave AXI VIP into vmm_env
class axiEnv extends vmm_env;
virtual axi_if.axi_slave_modport slave_mp;
dw_vip_axi_slave_rvm vip_axi_slave;
axiSlaveXactor slave_xactor;
axiSB axi_sb;
axiCfg tb_cfg;
dw_vip_axi_slave_resp_transaction_channel slave_input_chan;
dw_vip_axi_slave_resp_transaction_channel slave_output_chan;
virtual function void gen_cfg() ;
super.gen_cfg();
this.tb_cfg = new;
tb_cfg.vip_axi_slave_cfg.m_oPortCfg.m_enExclAccSupp = VMT_BOOLEAN_TRUE;
endfunction : gen_cfg
virtual function void build() ;
super.build();
/* Create the VIP Slave input and output channels. */
slave_input_chan = new ("slave_response_channel","",2,0);
slave_output_chan = new ("slave_response_channel","",2,0);
vip_axi_slave = new ("AXI SLAVE VIP",
slave_mp,
tb_cfg.vip_axi_slave_cfg,
slave_input_chan,
slave_output_chan
);
slave_xactor = new(tb_cfg,
vip_axi_slave, ,
slave_output_chan,
slave_input_chan
);
axi_sb=new(tb_cfg,master_xactor.exp_chan,slave_xactor.act_chan);
endfunction : build
virtual task start() ;
super.start();
vip_axi_slave.start_xactor();
slave_xactor.start_xactor();
axi_sb.start_xactor();
endtask : start
endclass : axiEnv
Step5. Connect the slave AXI VIP interface to DUT in the TB Top
module test_top;
// ----------------------------------------------------------------------
// Interface for AXI SLAVE side port, identified as axi_slave_if
// ----------------------------------------------------------------------
axi_if axi_slave_if();
// ----------------------------------------------------------------------
// VMM Testbench Program Instantiation:
// ----------------------------------------------------------------------
basic_system_test tb();
// ----------------------------------------------------------------------
// DUT Instantiation: Example DUT is just pass-through connection.
// ----------------------------------------------------------------------
axi_basic_interconnect_sv_wrapper hdl_interconnect(axi_master_if, axi_slave_if);
endmodule
=======================================================================================
/*
COPYRIGHT (C) 2005, 2006, 2007, 2008, 2009, 2010 SYNOPSYS INC.
This software and the associated documentation are confidential and
proprietary to Synopsys, Inc. Your use or disclosure of this software
is subject to the terms and conditions of a written license agreement
between you, or your company, and Synopsys, Inc. In the event of
publications, the following notice is applicable:
ALL RIGHTS RESERVED
The entire notice above must be reproduced on all authorized copies.
*/
logic[1023:0] rdata; //for SB extern function new(axiCfg tb_cfg, extern virtual protected task main(); //**************************************************************** function axiSlaveXactor::new(axiCfg tb_cfg, act_trans=new(); this.DONE = this.notify.configure(-1, vmm_notify::ON_OFF); //**************************************************************** //Slave VIP response end endtask //**************************************************************** case(resp_trans.m_enXactDir) endtask //**************************************************************** $display("###########################################################################"); if (resp_trans.m_enXactBurst==dw_vip_axi_master_transaction::BURST_FIXED) //BURST_FIXED end //BURST_INCR //BURST_INCR for(int i=0; i<= resp_trans.m_enXactLength;i++) act_trans.data_id=num_of_trans; $cast(cpy_trans,act_trans.copy()); $display("###########################################################################"); resp_trans.m_nAvalidAreadyDelay = 3; rdata= $random(); //BURST_FIXED
/*
Abstract:
This file defines the class that the testbench uses to provide response
information to the AXI Slave VIP. This class receives a response object of
type dw_vip_axi_slave_resp_transaction from the output channel of the AXI
slave VIP. This class then modifies the delay values in the received
response object. The response object is then put back into AXI Slave VIP's
input channel. The AXI Slave VIP uses the information in this response
object to provide response to the received transaction.
*/
class axiSlaveXactor extends vmm_xactor;
/* A local reference to the VIP slave's input and output VMM channel. */
dw_vip_axi_slave_resp_transaction_channel o_output_chan;
dw_vip_axi_slave_resp_transaction_channel o_input_chan;
axiCfg tb_cfg;
AxiSlave oSlave;
dw_vip_axi_slave_rvm vip_axi_slave;
dw_vip_axi_slave_resp_transaction resp_trans;
axiMasterTrans act_trans;
axiMasterTrans_channel act_chan;
axiMasterTrans cpy_trans;
static int num_of_trans;
static int DONE;
dw_vip_axi_slave_rvm vip_axi_slave,
axiMasterTrans_channel act_chan =null,
dw_vip_axi_slave_resp_transaction_channel o_output_chan,
dw_vip_axi_slave_resp_transaction_channel o_input_chan);
extern virtual task process_axi_resp_trans();
extern virtual task recv_read();
extern virtual task recv_write();
endclass
// function new()
//****************************************************************
dw_vip_axi_slave_rvm vip_axi_slave,
axiMasterTrans_channel act_chan =null,
dw_vip_axi_slave_resp_transaction_channel o_output_chan,
dw_vip_axi_slave_resp_transaction_channel o_input_chan);
super.new("axiSlaveXactor", "class");
if (act_chan == null)
act_chan = new("axiSlaveXactor act_chan", "class");
this.act_chan = act_chan ;
this.o_output_chan = o_output_chan ;
this.o_input_chan = o_input_chan ;
this.vip_axi_slave=vip_axi_slave;
this.tb_cfg=tb_cfg;
endfunction : new
// main
//****************************************************************
task axiSlaveXactor::main();
super.main();
oSlave = vip_axi_slave.getModel();
while(1) begin
wait_if_stopped_or_empty(o_output_chan);
o_output_chan.peek(resp_trans);
process_axi_resp_trans();
o_output_chan.get(resp_trans);
num_of_trans ++;
if(num_of_trans==tb_cfg.run_for_n_trans)
this.notify.indicate(this.DONE);
// process_axi_resp_trans();
//****************************************************************
task axiSlaveXactor::process_axi_resp_trans();
dw_vip_axi_transaction::DIR_READ: recv_read();
dw_vip_axi_transaction::DIR_WRITE: recv_write();
endcase
// recv_write();
//****************************************************************
task axiSlaveXactor::recv_write();
$display($time,,"SLAVE receives a WRITE transaction");
$display("###########################################################################");
resp_trans.display("SLAVE RECV ::/t");
$display("/n");
oSlave.enable_fifo_all(`VMT_DEFAULT_STREAM_ID,16);
/* Put the response object into the VIP slave input channel. */
resp_trans.m_nAvalidAreadyDelay = 3;
o_input_chan.put(resp_trans);
$display("###########################################################################");
$display($time,,"SLAVE responses a WRITE transaction");
$display("###########################################################################");
resp_trans.display("SLAVE RESP ::/t");
$display("/n");
//get the write data from VIP
vip_axi_slave.notify.wait_for(vip_axi_slave.AXI_MSGID_END_OF_WR_XACT_NOTIFY_ID);
if (resp_trans.m_enXactBurst == dw_vip_axi_master_transaction::BURST_FIXED) begin
for(int i=0; i<= resp_trans.m_enXactLength;i++) begin
oSlave.pop_fifo(`VMT_DEFAULT_STREAM_ID,resp_trans.m_bvAddr,rdata);
resp_trans.m_bvvData[i]=rdata;
$display("SLAVE FIFO::addr=%0h read_data=%0h",resp_trans.m_bvAddr,rdata);
end
oSlave.disable_fifo_all(`VMT_DEFAULT_STREAM_ID);
if (resp_trans.m_enXactBurst == dw_vip_axi_master_transaction::BURST_INCR) begin
for(int i=0; i<= resp_trans.m_enXactLength;i++) begin
oSlave.get_mem(`VMT_DEFAULT_STREAM_ID,resp_trans.m_bvAddr+i*4,32,rdata);
resp_trans.m_bvvData[i]=rdata;
end
end
//put the act_trans into SB channel
begin
act_trans.m_enXactDir=resp_trans.m_enXactDir;
act_trans.m_enXactLength=resp_trans.m_enXactLength;
act_trans.m_enXferSize=resp_trans.m_enXferSize;
act_trans.m_enXactBurst=resp_trans.m_enXactBurst;
act_trans.m_enXactLock=resp_trans.m_enXactLock;
act_trans.m_enXactCache=resp_trans.m_enXactCache;
act_trans.m_enXactProt=resp_trans.m_enXactProt;
act_trans.m_bvAddr=resp_trans.m_bvAddr;
act_trans.m_bvvData[i]=resp_trans.m_bvvData[i];
act_chan.put(cpy_trans);
end
endtask
//****************************************************************
// recv_read();
//****************************************************************
task axiSlaveXactor::recv_read();
$display($time,,"SLAVE receives a READ transaction");
$display("###########################################################################");
resp_trans.display("SLAVE RECV ::/t");
$display("/n");
if (resp_trans.m_enXactBurst==dw_vip_axi_master_transaction::BURST_FIXED) begin
oSlave.enable_fifo_address(`VMT_DEFAULT_STREAM_ID,resp_trans.m_bvAddr,resp_trans.m_enXactLength+1);
for(int i=0;i<=resp_trans.m_enXactLength;i++) begin
oSlave.set_fifo(`VMT_DEFAULT_STREAM_ID,resp_trans.m_bvAddr,rdata,i);
act_trans.m_bvvData[i]=rdata;
rdata++;
end
o_input_chan.put(resp_trans);
end
//BURST_INCR
if (resp_trans.m_enXactBurst==dw_vip_axi_master_transaction::BURST_INCR) begin
for(int i=0;i<=resp_trans.m_enXactLength;i++) begin
oSlave.set_mem(`VMT_DEFAULT_STREAM_ID,resp_trans.m_bvAddr+(i*4), 32, rdata);
act_trans.m_bvvData[i]=rdata;
rdata++;
end
o_input_chan.put(resp_trans);
end
$display("###########################################################################");
$display($time,,"SLAVE responses a READ transaction");
$display("###########################################################################");
resp_trans.display("SLAVE RESP ::/t");
$display("/n");
act_trans.m_enXactDir=resp_trans.m_enXactDir;
act_trans.m_enXactLength=resp_trans.m_enXactLength;
act_trans.m_enXferSize=resp_trans.m_enXferSize;
act_trans.m_enXactBurst=resp_trans.m_enXactBurst;
act_trans.m_enXactLock=resp_trans.m_enXactLock;
act_trans.m_enXactCache=resp_trans.m_enXactCache;
act_trans.m_enXactProt=resp_trans.m_enXactProt;
act_trans.m_bvAddr=resp_trans.m_bvAddr;
act_trans.data_id=num_of_trans;
$cast(cpy_trans,act_trans.copy());
act_chan.put(cpy_trans);
//delete FIFO
if (resp_trans.m_enXactBurst==dw_vip_axi_master_transaction::BURST_FIXED) begin
vip_axi_slave.notify.wait_for(vip_axi_slave.AXI_MSGID_END_OF_RD_XACT_NOTIFY_ID);
$display("READ end");
oSlave.disable_fifo_address(`VMT_DEFAULT_STREAM_ID,resp_trans.m_bvAddr);
end
endtask