How to use AXI VIP
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;
Set this member's maximum allowed ID width among all master instances 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.createModelConfig(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
Perform step four. Register the slave response transactor and slave AXI VIP within the virtual memory management environment.
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.
// ----------------------------------------------------------------------
elementary interconnection wrapper type用于被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.
*/
/*
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 instance of the VIP master's VMM channel that handles input and output operations. */
The transactional response on dw_vip_axi_slave_resp_transaction_channel o_outputChan represents the outputs from this transaction.
The transactional response on dw_vip_axi_slave_resp_transaction_channel o_inputChan represents the inputs from this transaction.
arr[1023:0] rd;
cfg_arr tb_config;
slave_type o_SLAVE;
vip_master_slave_ram vip_master_slave_rvm;
response_transaction response_trans;
//for SB
axiMasterTrans action_transfer;
axiMasterTrans_channel action_CHAN;
axiMasterTrans copy_transfer;
static int num_of_trans;
static int DONE;
extern function new(
const axiCfg& tb_cfg,
const VIP AXI_SLAVE& vip_axi_slave,
AXI_MASTERTransChannel act_CHAN = null,
dw_vip_axi_slave_resp_transaction_channel& o_output_CHANNEL,
dw_vip_axi_slave_resp_transaction_channel& o_inputChan
);
extern virtual shared protected function name main();
extern virtual 处理AXI响应转换的任务。
extern virtual 读取接收的数据。
extern virtual 发送接收的数据。
endclass
//****************************************************************
// function new()
//****************************************************************
function axiSlaveXactor::new(axiCfg tb_cfg,
dw_vip_axi_slave_rvm vip_axi_slave,
axtivedChannel activedChannel = null,
dw_vip_axi_slave_resp_transaction_channel responseOutputChannel,
dw_vip_axi_slave_resp_transaction_channel responseInputChannel);
super.new("axiSlaveXactor", "class");
if (act_chan == null)
act_chan = new("axiSlaveXactor act_chan", "class");
this.act_CHAN is assigned to act_CHAN ;
this.o_output_CHAN is configured as o_output_CHAN ;
this.o_inputChan is connected to o_inputChan ;
this.vip_axi_slave is initialized as vip_axi_slave;
this_tb_config is established as tb_config;
act_trans=new();
this.DONE = this.notify.configure(-1, vmm_notify::ON_OFF);
endfunction : new
//****************************************************************
// main
//****************************************************************
task axiSlaveXactor::main();
super.main();
oSlave = vip_axi_slave.getModel();
//Slave VIP response
do {
check whether o_output_CHAN has stopped or is empty;
peek at resp_trans;
process the AXI response;
acquire resp_trans;
increment the transaction count;
when the transaction count reaches tb_cfg.run_for_n_trans
indicate DONE state;
} while(true);
end
endtask
//****************************************************************
// process_axi_resp_trans();
//****************************************************************
task axiSlaveXactor::process_axi_resp_trans();
case(resp_trans.m_action_dir)
dw_vip_axi_transaction::ACCESS_READ: recv_read();
dw_vip_axi_transaction::ACCESS_WRITE: recv_write();
endcase
endtask
//****************************************************************
// recv_write();
//****************************************************************
task axiSlaveXactor::recv_write();
display("###########################################################################");  
display("该任务接收一条WRITE交易");
display("###########################################################################");  
resp_trans.display("SLAVE RECV日志记录::/t");  
display("/n");
当resp_trans.m_enXactBurst字段的值等于dw_vip_axi_master_transaction对象中的固定中断属性时,
将所有前向队列的启用标志设置为启用状态。
/* Transfer the VIP slave to the input channel. */
Assign 3 to m_nAvalidAreadyDelay variable of resp_trans.
o_inputChan->put(resp_trans);
Display a series of hash symbols with a length of 25 characters.
The time indicates that SLAVE responses include a WRITE transaction.
Display another series of hash symbols.
output information indicating successful response processing.
Display a newline character.
//Retrieve write information from VIP
vip_axi_slave.notify.await(vip_axi_slave.AXI_MSGID_END_OF_WR_XACT_NOTIFY_ID);
//BURST_FIXED
当响应事务的状态等于主总线事务AXI master类型中的固定模式时开始:
从i=0开始进行循环直到响应事务的状态达到指定长度:
oSlave执行队列弹出操作以处理来自不同地址的数据流;
将读取的数据加载到响应事务的目标数据缓冲区中;
在日志记录器中显示队列状态信息;
循环结束后关闭相关队列的操作;
end
/Burst Incr控制
当响应事务的执行模式等于主交易AXI扩展配置中的Burst Incr设置时,
开始处理响应事务的数据块读取操作。
对于响应事务中的每个执行块,
oSlave将从内存中读取指定的数据块,
并将其加载到本地存储空间中。
该操作会持续进行直到完成所有数据块的加载。
//BURST_INCR
//将操作传递注入到SB通道中
begin
(act Trans).en_x Act Dir:= (resp Trans).en_x Act Dir;
(act Trans).en_x Act Length:= (resp Trans).en_x Act Length;
(act Trans).en_x Act Burst:= (resp Trans).en_x Act Burst;
(act Trans).en_x Act Lock:= (resp Trans).en_x Act Lock;
(act Trans).en_x Act Cache:= (resp Trans).en_x Act Cache;
(act Trans).en_x Act Prot:= (resp Trans).en_x Act Prot;
bv Addr:= resp_bv Addr;
for (int i = 0; i < = resp_trans.m_enXactLength; ++i) {
transObject actTrans.bvvData[i] = transObject respTrans.bvvData[i];
}
act_trans.data_id=num_of_trans;
$cast(cpy_trans,act_trans.copy());
act_chan.put(cpy_trans);
end
endtask
//****************************************************************
// recv_read();
//****************************************************************
task axiSlaveXactor::recv_read();
display("###########################################################################");  
    display(time,,"accepting a READ transaction", "SLAVE");  
    display("###########################################################################");
Display resp_trans::"SLAVE RECV ::/t";
$display("/n");
resp_trans.m_nAvalidAreadyDelay = 3;
rdata= $random();
//BURST_FIXED
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;
设置actTrans的数据ID为transCount;
apply(cpy_trans, act Chan.transCopy());
insert transChan.transCopy;
//删除FIFO
当resp_trans.m_enXactBurst等于dw_vip_axi_master_transaction::BURST_FIXED时开始
AXI Master Slave通知器等待接收AXI消息标识结束于RD XACT的通知ID
显示"READ end"
oSlave禁用指定队列地址(VMT_DEFAULT_STREAM_ID, resp_trans.m_bvAddr)
endtask
