SV
=========================================================
====== Synopsys VIP AXI
=========================================================
Docs
axi_svt_uvm_user_guide.pdf
Top
+- Test (class)
| +- Env (class)
| +- svt_axi_system_env
| +- svt_axi_master_agent
| +- sequencer
| +- monitor
| +- driver
|
+- svt_axi_if (i/f) Interconnect Env (multiple master/slave ports)
=========================================================
top
=========================================================
//----------------------------------
// パッケージの挿入(topの外側)
//----------------------------------
// Include package and interfaces
`include "uvm_pkg.sv" // UVM should be included before VIP
`include "svt_axi.uvm.pkg"
//----------------------------------
// インターフェイス定義の挿入(topの外側)
//----------------------------------
// Include AXI and APB VIP interfaces.
`include "svt_axi_if.svi"
`include "svt_apb_if.svi"
//----------------------------------
// パッケージのimport(topの中)
//----------------------------------
module TB;
// Import UVM package.
import uvm_pkg::*;
// Import SVT UVM package.
import svt_uvm_pkg::*;
// Import AXI and APB VIP packages.
import svt_axi_uvm_pkg::*;
import svt_apb_uvm_pkg::*;
//----------------------------------
// class 定義、インスタンス等の include (topの中)
//----------------------------------
`include "axi_if.sv" // interface instance
`include "my_env.sv" // UVM env class
`include "seq_lib.sv" // Set of sequence class
`include "test_lib.sv" // Set of test scenario
//----------------------------------
// DUT とインターフェイスの接続 (topの中)
//----------------------------------
// 省略 See axi_if.sv
//----------------------------------
// UVM run_test () 呼び出し (topの中)
//----------------------------------
initial begin
// Run UVM test.
run_test();
end
=========================================================
AXI interface
=========================================================
//----------------------------------
// 記述場所
//----------------------------------
top module の中に書く。
別ファイルにして include するのがよい
//----------------------------------
// インスタンス宣言とクロックリセット接続
//----------------------------------
// Instantiate if and connect clock/reset
svt_axi_if axi_if();
assign axi_if.common_aclk = <clk>
assign axi_if.master_if[0].aresetn = <rst>
assign axi_if.slave_if[0].aresetn = <rst>
<< class reference >>
svt_axi_if
+- svt_axi_master_if
+- svt_axi_slave_if
svt_axi_if
common_aclk, aclk // clock
svt_axi_master_if master_if
svt_axi_slave_if slave_if
svt_axi_master_if
clk, axi-ports
logic[31:0] read_addr_xact_num; ... etc. // statictics
//----------------------------------
// DUTとの接続
//----------------------------------
// 以下は DUT のポートが interface 化されている場合
dut dut_inst(axi_if)
//----------------------------------
// config db 登録
//----------------------------------
initial begin
uvm_config_db#(svt_axi_vif)::set(uvm_root::get(),
"uvm_test_top.env.axi_system_env", "vif", axi_if);
end
//----------------------------------
// config 設定
//----------------------------------
See cfg
=========================================================
UVM env
=========================================================
//----------------------------------
// 記述場所
//----------------------------------
top module の中に書く。
別ファイルにして include するのがよい
//----------------------------------
// クラス定義とメンバ
//----------------------------------
class my_env extends uvm_env;
// uvm_env の AXI 版。一段かましているだけ
svt_axi_system_env axi_system_env;
// config (custom) // 下に定義あり
cust_svt_axi_system_configration cfg;
//----------------------------------
// build_phase
//----------------------------------
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// config
if (uvm_config_db#(cust_svt_..configration)::get(this, "", "cfg", cfg)) begin
uvm_config_db#(svt_axi_system_configuration)::set(this,"axi_system_env","cfg",cfg);
end
else begin // no config from test
cfg = cust_svt_axi..config::type_id::create("cfg")
uvm_config_db#(svt_axi_system_configuration)::set(this,"axi_system_env","cfg",cfg);
end
// Instantiate svt_axi_system_env
axi_system_env = svt_axi_system_env::type_id::create("axi_system_env", this);
=========================================================
AXI config
=========================================================
//----------------------------------
// 記述場所
//----------------------------------
top module の中に書く。
別ファイルにして include するのがよい
axi_if と一緒にした。
//----------------------------------
// クラス定義とメンバ
//----------------------------------
class svt_axi_system_cfg extends svt_axi_system_configuration;
//----------------------------------
// new
//----------------------------------
// config の設定はたぶん new でなくてもよいと思う
function new (string name = "...config...");
super.new(name);
// Master/Slave config
this.num_masters = 1;
this.num_slaves = 1;
// Create port config
this.create_sub_cfgs(1,1);
this.master_cfg[0].data_width = 256;
...
this.set_addr_range(0, 64'h0, 64'hffff_...);
<< class reference >>
svt_axi_system_configuration
function void create_sub_cfgs(int num_masters=1, int num_slaves=1, ....)
function bit get_slave_addr_range(input int slave_idx,
outbut bit[SVT_AXI_MAX_ADDR_WIDTH-1:0] lo_addr,
outbut bit[SVT_AXI_MAX_ADDR_WIDTH-1:0] hi_addr )
function void set_addr_range(int slave_idx,
bit[SVT_AXI_MAX_ADDR_WIDTH-1:0] start_addr,
bit[SVT_AXI_MAX_ADDR_WIDTH-1:0] end_addr, .... )
int XXX(ex. arready_watchdog_timeout = .... // Timeout values
rand svt_axi_port_configuration master_cfg[]
rand svt_axi_port_configuration slave_cfg[]
rand int num_masters, num_slaves
svt_axi_port_configuration
rand svt_axi_port_configuration::axi_interface_type_enum axi_interface_type
AXI3, AXI4, AXI4_LITE, AXI4_STREAM, AXI_ACE, ACE_LITE
rand svt_axi_port_configuration::axi_port_kind_enum axi_port_kind
AXI_MASTER, AXI_SLAVE, ...
rand int data_width=SVT_AXI_MAX_DATA_WIDTH
rand bit default_arready=1 // (bready,etc.)
rand int id_width=SVT_AXI_MAX_ID_WIDTH
bit is_active=1 // agent is in active mode
rand num_outstanding_xact=4
real perf_XXX_latency=1
int port_id
svt_axi_system_configuration sys_cfg // handler to above
=========================================================
AXI Master sequence
=========================================================
//----------------------------------
// 記述場所
//----------------------------------
top module の中に書く。
別ファイルにして include するのがよい
//----------------------------------
// クラス定義とメンバ
//----------------------------------
class axi_master_XXX_seq extends svt_axi_master_base_sequences;
`uvm_object_utils(axi_master_XXX_seq)
function new (string name="axi_master_XXX_seq");
super.new(name);
endfunction
//----------------------------------
// body
//----------------------------------
virtual task body();
svt_configuration get_cfg;
super.body();
// obtain a handle to the port configuration
p_sequencer.get_cfg(get_cfg);
if ( !$cast(cfg, get_cfg) ) begin `uvm_fatal(".."); end
//
endtask
<< class reference >>
svt_axi_master_sequence
virtual task body();
function uvm_object create(string name);
svt_axi_port_configuration cfg
svt_axi_master_sequencer p_sequencer
svt_axi_master_sequencer
function void build_phase()
function void get_cfg (ref svt_configuration cfg)
svt_axi_master_transaction vlog_cmd_xact
//----------------------------------
// Master Transaction
//----------------------------------
Write:
svt_axi_master_transaction wt;
`uvm_create(wt);
wt.port_cfg = cfg;
wt.xact_type = svt_axi_transaction::WRITE;
....
wt.data = new[wt.burst_length];
foreach (wt.data[i]) begin
wt.data[i] = ...;
end
`uvm_send(wt);
get_response(rsp);
Read:
svt_axi_master_transaction rt;
`uvm_create(rt);
rt.port_cfg = cfg;
rt.xact_type = svt_axi_transaction::READ;
....
rt.data = new[rt.burst_length];
`uvm_send(rt);
get_response(rsp);
(With random)
`uvm_do_with(req,
{ xact_type == svt_axi_transaction::WRITE; } );
<< class reference >>
svt_axi_transaction
function int is_aborted(int mode=0)
rand bit[SVT_AXI_MAX_ADDR_WIDTH-1:0] addr=0
rand int bready_delay (bvalid_delay, etc..)
rand svt_axi_transation::resp_type_enum bresp, rresp
OKAY, EXOKAY, SLVERR, DECERR
rand bit[] burst_length=1
rand svt_axi_transaction::burst_size_enum burst_size
BURST_SIZE_8BIT, BURST_SIZE_16BIT, ..., BURST_SIZE_1024BIT
rand svt_axi_transaction::burst_type_enum burst_type
FIXED, INCR, WRAP
rand bit[SVT_AXI_MAX_DATA_WIDTH-1:0] data[]
rand bit[SVT_AXI_MAX_ID_WIDTH-1:0] id[]
svt_axi_port_configuration port_cfg
rand svt_axi_transaction::porty_type_num port_type
DATA_SECURE_NORMAL, ..., INSTRUCTION_SECURE_PRIVILEGED, ...
rand int rready_delay[] , rvalid_delay[], wvalud_delay[]
svt_sequence_item::status_enum write_ersp_status
INITIAL, RETRY, ACTIVE, ACCEPT, ABORTED, ...
rand bit[SVT_AXI_WSTRB_WIDTH-1:0] wstrb[]
rand svt_axi_transaction::xact_type_enum xact_type
READ, WRITE, IDLE, ..
svt_axi_transaction
+--> svt_axi_master_transaction
+--> svt_axi_slave_transaction
=========================================================
AXI Slave sequence
=========================================================
//----------------------------------
// クラス定義とメンバ
//----------------------------------
class axi_slave_XXX_seq extends svt_axi_slave_base_sequence;
svt_axi_slave_transaction resp_req;
`uvm_object_utils(axi_slave_XXX_seq);
function new (..) .. endfunction
------------------------------------------------
13 integer status;
...
36 // Randomize the response and delays.
37 status = req_resp.randomize with {
38 bresp == svt_axi_slave_transaction::OKAY;
39
40 foreach (rresp[index]) {
41 rresp[index] == svt_axi_slave_transaction::OKAY;
42 }
43 };
44
45 if (!status) begin
46 `uvm_fatal("body", "Unable to randomize a response");
47 end
------------------------------------------------
//----------------------------------
// body
//----------------------------------
virtual task body();
forever begin
p_sequencer.response_request_port.peek(resp_req);
// Randomize the response and delays.
status = req_resp.randomize with {
bresp == svt_axi_slave_transaction::OKAY;
foreach (rresp[index]) {
rresp[index] == svt_axi_slave_transaction::OKAY;
}
};
// Memory sequence
if (req_resp.xact_type == svt_axi_slave_transaction::WRITE) begin
put_write_transaction_data_to_mem(req_resp);
end
else begin
get_read_data_from_mem_to_transaction(req_resp);
end
$cast(req, req_resp);
`uvm_send(req);
end // forever
endtask
`uvm_rand_send_with(req,
{
foreach (rresp[i]) { rresp[i] {svt_axi_transaction::OKAY};
})
//----------------------------------
// AXI slave mem backdoor
//----------------------------------
svt_axi_slave_agent::write_byte() in amba_vip/src/sverilog/vcs
1. To write a single byte of data ('h0f) at address 'h100 from the test, you can use:
env.axi_system_env.slave[0].write_byte(32'h100, 8'h0f);
2. To read a single byte of data at the address 'h200 from the test, you can use:
bit[7:0] read_data;
env.axi_system_env.slave[0].read_byte(32'h200, read_byte);
$display("data at address 'h200: %h", read_byte);
svt_mem.sv
extern virtual function bit load_mem(string filename,
bit is_pattern = 0,
int data_wdth = -1,
bit [`SVT_MEM_MAX_ADDR_WIDTH-1:0] start_addr = 0,
bit [`SVT_MEM_MAX_ADDR_WIDTH-1:0] end_addr = ((1<<`SVT_MEM_MAX_ADDR_WIDTH)-1));
// $read_memh format
// is_pattern=1 means format is user defined
// data_width=-1 (default) means the width are same in file and memory
extern virtual function bit save_mem(string filename,
int data_wdth = -1,
bit [`SVT_MEM_MAX_ADDR_WIDTH-1:0] start_addr = 0,
bit [`SVT_MEM_MAX_ADDR_WIDTH-1:0] end_addr = ((1<<`SVT_MEM_MAX_ADDR_WIDTH)-1));
extern virtual function bit write(bit [`SVT_MEM_MAX_ADDR_WIDTH-1:0] addr = 0,
bit [`SVT_MEM_MAX_DATA_WIDTH-1:0] data = 0,
bit [`SVT_MEM_MAX_DATA_WIDTH/8-1:0] byteen = ~0,
int set_lock = -1);
extern virtual function logic [`SVT_MEM_MAX_DATA_WIDTH-1:0] read(bit [`SVT_MEM_MAX_ADDR_WIDTH-1:
0] addr, int set_lock = -1);
<< class reference >>
svt_axi_slave_sequence
virtual task body();
task get_read_data_from_mem_to_transaction(svt_axi_transaction xact)
task put_write_transaction_data_to_mem(svt_axi_transaction xact)
svt_mem axi_slave_mem
svt_axi_port_configuration cfg
svt_axi_master_sequencer p_sequencer
svt_axi_slave_sequencer
function void build_phase()
function void get_cfg (ref svt_configuration cfg)
task put (input svt_axi_slave_transaction t)
svt_axi_slave_transaction vlog_cmd_xact
svt_axi_slave_transaction
function string get_cmd_class_name()
=========================================================
Slave Memroy
=========================================================
Implemented using svt_mem.
Frontdoor Access
Updated by the Slave Sequence wherever it observes a transaction.(In active mode)
See the above example.
Backdoor Access
raad()
write()
set_meminit()
load_mem()
save_mem()
clear()
read()/write() the number of bytes accesses should be data_width.
svt_axi_slave_agent::write_byte() / read_byte()
See 6.10
env.axi_system_env.slave[0].write_byte(addr,8'h0f);
env.axi_system_env.slave[0].read_byte(addr,read_byte_data);
Initialization
Address Map
svt_axi_system_configuration::set_address_range()
ex.
set_address_range(0, 32'h0000_0000, 32'h0000_ffff); => See my_axi_cfg
<< class reference >>
svt_mem
function void clear()
function void do_print(uvm_printer print)
function bit get_aligned_addr(ref bit[SVT_MEM_MAX_ADDR_WIDTH-1:0] addr)
function bit load_mem(string filename,
bit is_pattern=0, int data_width=-1,
bit[MAX:0] start_addr, bit[MAX:0] end_addr)
function void new(string name, ... min_addr, max_addr)
function logic[SVT_MEM_MAX_DATA_WIDTH-1:0] read(bit[] addr, int set_lock=-1)
function bit save_mem(string filename,
int data_width=-1,
bit[] start_addr, bit[] end_addr)
task set_meminit(svt_mem::meminit_enum meminit=UNKNONWS,
bit[] meminit_value=0, bit [] meminit_address_offset=0)
UNKNOWNS(X), ZEROES, ONES, ADRESS, VALUE(fixed value), INCR, DECR, USER_PATTERN
function bit write (bit [] addr, bit[] data, bit[] byteen=~0, int set_lock=-1)
int data_width=0
bit[] max_addr=0
svt_mem::meminit_enum meminit
...
=========================================================
UVM test
=========================================================
//----------------------------------
// 記述場所
//----------------------------------
top module の中に書く。
別ファイルにして include するのがよい
シナリオごとにクラスを作る
//----------------------------------
// クラス定義とメンバ
//----------------------------------
class my_test extends uvm_test;
`uvm_component_utils(my_test)
my_env env;
function new (string name, uvm_component parent); ....
//----------------------------------
// build_phase
//----------------------------------
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this); // create env
// bind axi sequences
uvm_config_db#(uvm_object_wrapper)::set(
this, "env.axi_env.master[0].sequencer.main_phase", // master -> main phase
"default_sequencer", axi_master_XXX_seq::type_id::get() );
uvm_config_db#(uvm_object_wrapper)::set(
this, "env.axi_env.slave[0].sequencer.run_phase", // slave -> run phase
"default_sequencer", axi_slave_XXX_seq::type_id::get() );
endfunction
=========================================================
Macro
=========================================================
Override System Constants
$DESIGNWARE_HOME/vip/svt/amba_svt/latest/sverilog/include
svt_axi_common_defines.svi
svt_axi_user_defines.svi
// contain override values
svt_axi_user_defines.svi // anywhere
//----------------------------------
// マクロ設定の変更
//----------------------------------
例:
APB信号のビット幅はマクロで定義する
`define SVT_APB_PWDATA_WIDTH 32
`define SVT_APB_PRDATA_WIDTH 32
物理的な信号の幅はこれで定義し(つまり最大値)、
cfg は実際に使われるビット幅?
=========================================================
その他
=========================================================
//----------------------------------
// Analysis Ports
//----------------------------------
for scoreboard
Callbacks
master
slave
system monitor
- svt_axi_system_monitor_callback
class my_callback extends axi_port_monitor_callback;
virtual function void new_transaction_started
(svt_axi_port_monitor monitor, svt_axi_transaction item);
... item.print();
endfunction
endclass
In uvm_env;
my_callback monitor_cb;
function void start_of_simulation();
monitor_cb = new ("mon");
uvm_callback#(svt_axi_port_monitor,svt_axi_port_monitor_callback)::add(
axi_system_env.master[0].monitor, monitor_cb);
endfunction
<< class reference >>
svt_axi_port_monitor_callback
virtual function void new_transaction_started(svt_axi_port_monitor, svt_axi_transaction);
.....
svt_axi_system_monitor_callback
virtual function void new_master_transaction_received(svt_axi_port_monitor, svt_axi_system_transaction);
.....
//----------------------------------
//----------------------------------
Status
transaction class methods
get_begin_time();
get_end_time();
wait_for_transaction_end();
//----------------------------------
//----------------------------------
Agent
Master Agent
Against Slave DUT
Encapsulates
+ Master Sequencer
+ Master Driver
+ Port Monitor
Stimulus at Master
class svt_axi_master_transaction => svt_axi_transaction
<< class reference >>
svt_axi_master_agent
bunction void build_phase(..)...
svt_axi_master driver
svt_axi_port_monitor monitor
svt_axi_master_sequencer sequencer
svt_axi_master_vif vif
typedef interface svt_axi_master_agent::svt_axi_master_vif
----------------------------------------------------------
Slave Agent
Against Master DUT
Encapsulates
+ Slave Sequencer
+ Slave Driver
+ Port Monitor
When the Port Monitor detects a new transaction,
it provides response request sequence to the Slave Sequencer
through response_request_port.
The sequence item is then provided to the Slave Driver.
<< class reference >>
svt_axi_master_agent
bunction void build_phase(..)...
svt_mem axi_slave_mem
svt_axi_slave driver
svt_axi_slave_sequencer sequencer
svt_axi_slave_if vif
//----------------------------------
//----------------------------------
<< class reference >>
svt_axi_system_monitor
function void build_phase(...)
task run_phase(...)
svt_axi_master_agent master[$}
svt_axi_system_sequencer sequencer
svt_axi_slave_agent slave[$]
svt_axi_system_checker system_checker
svt_axi_system_monitor system_monitor
svt_axi_vif vif
svt_axi_master // implements driver
function void build_phase(...)
task run_phase(...)
svt_axi_slave // implements driver
function void build_phase(...)
task run_phase(...)
svt_axi_system_base_sequence
function uvm_object create(string name="")
svt_axi_system_sequencer p_sequencer
int unsigned sequence_length=10
svt_axi_system_configuration sys_cfg
svt_axi_system_sequencer
function void get_cfg(ref svt_configuration cfg)
svt_axi_master_sequencer master_sequencer[]
svt_axi_slave_sequencer slave_sequencer[]
svt_configuration
svt_monitor
build_phase, run_phase
function void get_cfg (ref svt_configuration cfg)
protected bit is_running
svt_sequence #(REG, RSP)
function void drop_phase_objection()
function void raise_phase_objection()
function string get_phase_name()
static uvm_report_object report;
svt_sequence_item
svt_sequence_item implementation[$] // to lower level
svt_sequence_item_base
svt_sequencer #(REQ=uvm_sequence_item, RSP)
build_phase, run_phase
function void get_cfg(ref svt_configuration cfg)
task get_next_item(output REQ t)
svt_timer
function real get_start_time(), get_stop_time()
function bit is_active()
function void reset()
function void start_timer(real positive_fuse_value, resason,infinit,allow_restart)
function void stop_timer(string reason="")
task track_timeout_foerver()
task wait_for_timeout( output bit timed_out )
uvm_event STARTED, STOPPED, TIMEOUT, EXPIRED
uvm_sequence #(REQ, RSP)
virtual task get_response(output RSP response, input int transaction_id)
function void send_request (uvm_sequence_item req, bit rerandomize=0)
REQ req
RSP rsp
uvm_transaction
function time get_begin_time(), get_end_time()
uvm_event begin_event, end_event
uvm_config_db#(T=int)
static function bit get(uvm_component cntxt,string inst_name,
string field_name, inout T value)
static function bit set(cntxt, inst_name, field_name, value)
static function bit exists(cntxt, inst_name, field_name, bit spell_chk=0)
//----------------------------------
//----------------------------------
//----------------------------------
//----------------------------------
=========================================================
環境設定 (VCSを使用する場合)
=========================================================
//----------------------------------
// setup
//----------------------------------
See SNP_VIP.tx
//----------------------------------
// install
//----------------------------------
# Install AMBA VIPs.
dw_vip_setup -path <path> -add axi_system_env_svt -svlog
dw_vip_setup -path <path> -add apb_system_env_svt -svlog
例
dw_vip_setup -path ./amba_vip -add axi_system_env_svt -svlog
dw_vip_setup -path ./amba_vip -add apb_system_env_svt -svlog
# Install AMBA VIP examples.
# 例をローカルのディレクトリにコピーする。必須ではない
dw_vip_setup -path <path> -example amba_svt/tb_axi_svt_uvm_basic_sys -svtb
dw_vip_setup -path <path> -example amba_svt/tb_apb_svt_uvm_basic_sys -svtb
=========================================================
ツールのオプション (VCSを使用する場合)
=========================================================
//----------------------------------
// build
//----------------------------------
+define+SVT_AXI_INCLUDE_USER_DEFINES // required for AXI VIP
+incdir+${AMBA_VIP_DIR}/include/sverilog
(AMBA_VIP_DIR = ./amba_vip, for example)
//----------------------------------
// run
//----------------------------------