モニターは DUT のレスポンスの変化を検知して他のコンポーネントに知らせる(broadcast)役 割を果たします。DUT のレスポンスはシグナル・レベルである為、モニターにはシグナル・レ ベルの情報をトランザクション・レベルに変換する機能が必要になります。その機能を持つコン ポーネントは、一般的に、コレクター(collector)と呼ばれます。コレクターは virtual interface
(下図では、vifとして参照)を使用してDUTの信号変化を取得します。
class simple_sequencer extends uvm_sequencer #(simple_item);
`uvm_component_utils(simple_sequencer)
function new(string name,uvm_component parent);
super.new(name,parent);
endfunction endclass
class simple_driver extends uvm_driver #(simple_item);
...
task run_phase(uvm_phase phase);
...
forever begin
seq_item_port.get_next_item(item);
send_to_dut(item);
seq_item_port.item_done();
end endtask ...
endclass
図 3-2 モニターとコレクターの接続
モニター内にコレクターの機能を組み込む事が出来ますが、ここではコレクターを別のコンポー ネントとして定義します。
コレクターをuvm_componentから定義する事が出来ます。簡単な例を以下に示します。
コレクターは virtual interface を使用して DUTの信号変化を探ります。従って、コレクター内の プロパーティ vif に interface へのポインターを設定しなければなりません。この例 では、
connect_phase()で virtual interface の設定を行っています。文字列をベースとしたインスタンス名
称を使用して vifに interfaceのポインターを取得します。インスタンス名と実際の interfaceイン スタンスの対応はトップ・レベルのモジュールが行います。
3.4.2 モニターの定義
class simple_collector extends uvm_component;
virtual dut_if vif;
uvm_analysis_port #(simple_item) item_collected_port;
`uvm_component_utils(simple_collector)
function new(string name,uvm_component parent);
super.new(name,parent);
item_collected_port = new("item_colled_port",this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if( !uvm_config_db#(virtual dut_if)::get(this, get_full_name(),"vif",vif) )
`uvm_error("NOVIF",
{"virtual interface must be set for: ", get_full_name(),".vif"})
endfunction
task run_phase(uvm_phase phase);
simple_item item;
item = simple_item::type_id::create("simple_item");
forever begin
@(posedge vif.clk);
// ...
item_collected_port.write(item);
end endtask endclass
monitor collector
uvm_analysis_im p
uvm_analysis_port uvm_analysis_port vif
行い、トランザクションが準備されている事を他のコンポーネントに知らせます(broadcast)。
コレクターのお陰でモニターはトランザクション処理に専念する事が出来ます。
モニターを uvm_monitor、又は、そのサブクラスを使用して定義します。uvm_monitor には特別 なプロパーティが定義されていませんので、使用するプロパーティをユーザが定義しなければな りません。
以下に、簡単な例を紹介します。broadcastする為のanalysis portとしてitem_collected_portを定義 しています。また、コレクターからトランザクションを受け取る為の analysis export として coll_mon_exportを定義しています。
コレクターがトランザクションの準備を終了すると simple_monitor::write()を呼びます。このモニ
ターの write()ファンクションがトランザクションを受け取ると、チェック、及び、カバレッジ計
算を行います。そして、コレクターから取得したトランザクションを他のコンポーネントに
broadcastします。スコアボード等のコンポーネントは、このトランザクションを受け取ります。
class simple_monitor extends uvm_monitor;
bit checks_enable = 1;
bit coverage_enable = 1;
uvm_analysis_port #(simple_item) item_collected_port;
uvm_analysis_imp #(simple_item) coll_mon_export;
simple_item collected_item;
`uvm_component_utils(simple_monitor) covergroup cg;
// ...
endgroup
function new(string name,uvm_component parent);
super.new(name,parent);
cg = new();
item_collected_port = new("item_colleted_port",this);
coll_mon_export = new("coll_mon_export",this);
endfunction
function void write(simple_item item);
collected_item = item;
if( checks_enable ) perform_checks();
if( coverage_enable ) perform_coverage();
item_collected_port.write(collected_item);
endfunction
function void perform_checks();
// ...
endfunction
function void perform_coverage();
// ...
endfunction endclass