SV
// UVM パッケージのインクルード
`include "uvm_pkg.sv"
// interface のインクルード
`include "my_apb_if.sv"
// top モジュール
module tb_top ;
// UVM パッケージのインポート
import uvm_pkg::* ;
// UVM マクロのインクルード
`include "uvm_macro.svh"
// clock, reset 信号の宣言
logic clk ;
logic rst_n ;
// interface 信号の宣言
my_apb_if apb_if ( .clk ( clk ), .rst_n ( rst_n ) ) ;
// uvm_test のインクルード
`include "my_test.sv"
// DUT のインスタンス
dut_wrap u_dut_wrap (
.clk ( clk )
, .rst_n ( rst_n )
, .apb_if ( apb_if )
) ;
// clock, reset generation
always clk = #10 ~clk ;
initial begin
rst_n = 0 ;
#100 ;
rst_n = 1 ;
end
// initial for UVM test bench
initial begin
uvm_config_db # ( virtual my_apb_if ) :: set (
null, "*", "apb_vif", apb_vif
) ;
run_test ( ) ;
end
endmodule
// sequence item : トランザクション
// クラス定義。uvm_sequence_item を継承する
class my_apb_item extends uvm_sequence_item ;
rand bit [31:0] addr ;
rand bit is_write ;
rand bit [31:0] wdata ;
bit [31:0] rdata ;
bit pslverr ;
// Factory への登録
`uvm_object_utils_begin ( my_apb_if )
`uvm_field_int ( addr, UVM_ALL_ON )
....
`uvm_ojbect_utils_end
// new
function new ( string name = "my_apb_item" ) ;
super.new ( name ) ;
endfunction
endclass
// my_test_base : すべての test のベースクラス
// env class のインクルード
`include "my_env.sv"
// クラス定義。uvm_test を継承する
class my_test_base extends uvm_test ;
// Factory への登録
`uvm_component_utils ( my_test_base )
// env メンバーの宣言
my_env env ;
// new
function new ( string name = "my_test_base", uvm_component parent = null ) ;
super.new ( name, parent ) ;
endfunction
// build_phase : メンバーのインスタンス
function void build_phase ( uvm_phase phase ) ;
super.biuld_phase ( phase ) ;
env = my_env::type_id::create ( "my_env", this ) ;
endfunction
// run_phase : 何もしないので定義しない
endclass
// my_test : 検証環境のトップ
`include "my_apb_agent.sv"
// クラス定義。uvm_env を継承する
class my_env extends uvm_env ;
// Factory への登録
`uvm_component_utils ( my_env )
// メンバー宣言
my_apb_agent apb_agent ;
// new
function new ( string name = "my_env", uvm_component parent = null ) ;
super.new ( name, parent ) ;
endfunction
// build_phase : メンバーのインスタンス
function void build_phase ( uvm_phase phase ) ;
super.biuld_phase ( phase ) ;
env = my_apb_agent::type_id::create ( "my_apb_agent", this ) ;
endfunction
// run_phase : 何もしないので定義しない
endtask
// my_apb_agent
`include "my_apb_sequencer.sv"
`include "my_apb_driver.sv"
class my_apb_agent extends uvm_agent ;
`uvm_component_utils ( my_apb_agent ) ;
my_apb_sequencer apb_sqr ;
my_apb_driver apb_drv ;
function new ( string name = "my_apb_agent", uvm_component parent = null ) ;
super.new ( name, parent ) ;
endfunctio
function void build_phase ( uvm_phae phae ) ;
...
endfunction
function void connect_phase ( uvm_phase phase ) ;
super.connect_phase ( phase ) ;
apb_drv.seq_item_port.connect ( apb_sqr.seq_item_export ) ;
endfunction
endclass
// my_apb_sequencer
typedef uvm_sequencer # (my_apb_item) my_apb_sequencer ;
// my_apb_driver
class my_apb_driver extends uvm_driver # (my_apb_item) ;
`uvm_component_utils ( my_apb_driver ) ;
virtual my_apb_if apb_vif ;
function new ( string name = "my_apb_driver", uvm_component parent = null ) ;
super.new ( name, parent ) ;
endfunction
function void build_phase ( uvm_phase phase ) ;
// 本当は cast して登録されているかチェックする
uvm_config_db # ( virtual my_apb_if ) :: get (
"*", "*", "my_apb_vif", apb_vif
) ;
endfunction
task run_phase ( uvm_phase ) ;
forever begin
seq_item_port.get_next_item ( req ) ;
// operate DUT
@ ( posedge req.clk ) ;
apb_vif.psel = 1 ;
apb_vif.paddr = req.addr ;
if ( req.is_write == 1 ) begin
apb_vif.pwrite = 1 ;
apb_vif.pwdata = req.wdata ;
end
@ ( posedge req.clk ) ;
apb_vif.penable = 1 ;
@ ( posedge req.clk ) ;
if ( apb_vif.pready == 1 ) begin
if ( apb_vif.pwrite == 0 ) begin
req.rdata = apb_vif.prdata ;
end
req.pslverr = apb_vif.pslverr ;
end
// pready が延びる場合は今回考えない
apb_vif.psel = 0; apb_vif.penable = 0;
seq_item_port.item_done ( ) ;
end // forever
endtask
// 対応する test と sequence は一つのファイルに定義する
class my_test_01_seq extends uvm_sequence # ( my_apb_item ) ;
`uvm_object_utils ( my_test_01_seq ) ;
my_apb_item req ;
function new ( string name = "my_test_01_seq" ) ;
// ...
task body ( ) ;
// item を生成
req = my_apb_item::type_id::create ( "req" );
// item に値をセット
req.addr = 32'h0001_0000 ;
req.is_write = 1 ;
req.wdata = 32'hFFFF_FFFF ;
// シーケンサに渡す
start_item ( req ) ;
// シーケンサからトランザクションが終わるのを待つ
finish_item ( req ) ;
endtask
endclass
class my_test_01 extends # my_test_base ;
`uvm_component_utils ( my_test_01 )
function new string ( name = "my_test_01", uvm_component parent = null ) ;
// ..
endfunction
function void connect_phase ( ) ;
// ここで default sqr を指定する方法もある
endfunctio
task run_phase ( uvm_phase phase ) ;
my_test_01_seq seq ;
seq = new // OK??
phase.raise_objection ( this ) ;
// シーケンサを明示的に指定してシーケンスを発行する方法
seq.start ( env.apb_agent.apb_sqr ) ;
phase.drop_objection ( this ) ;
endtask
endclass