UVMでC/C++のテストシーケンスを走らせる場合のアイディアを紹介しておこうと思う。
Dynamic Objectであるclass内ではDPI-CでC/C++ importする事ができない。なので、UVM sequence class内ではC/C++のプログラムを直接importして使う事はできない。ではどうすれば良いのかと言うと、staticな領域であるpackage内でC/C++のfunctionをimportしてそれを呼ぶようにする。その際に直接呼ぶのではなく、そのpackageに別途SVのtaskを用意して、そのtaskからC/C++のfunctionをコールするようにする。そのSVのtaskの引数としてシーケンサーと親シーケンスのハンドルを指定して、それらをそのpackageに渡すようにする。C側から呼ぶSVのレジスタRead/WriteのSVタスクもpackage内に用意し、その中でではAgentのRead/WriteのAPIシーケンスをスタートさせる。その際に、先ほどのpackageに渡ったシーケンサーと親シーケンスのハンドルを引数にして.start()を実行する。
package dpi_seq_pkg;
import "DPI-C" context task C_Program();
export "DPI-C" task sv_write;
export "DPI-C" task sv_read ;
import uvm_pkg::*;
uvm_sequencer_base m_sequencer;
uvm_sequence_base parent_seq;
// Called by a UVM sequence
task start(uvm_sequencer_base sequencer, uvm_sequence_base parent_sequence);
m_sequencer = sequencer;
parent_seq = parent_sequence;
C_Program(); // C/C++ Program Call
endtask
// Called from C side
task sv_write (input int addr, data);
agent_pkg::write_sequence api_wr_seq = agent_write_sequence::type_id::create("api_wr_seq");
api_wr_seq.Val_A = addr;
api_wr_seq.Val_D = data;
api_wr_seq.start( .sequencer(m_sequencer), .parent_seuence(parent_seq) ); // API Sequence Start with Sequencer Handle and Parent Sequencer Handle
endtask : sv_write
// Called from C side
task sv_read (input int addr, output int data);
agent_pkg::read_sequence api_rd_seq = agent_read_sequence::type_id::create("api_rd_seq");
api_rd_seq.Val_A = addr;
api_rd_seq.start( .sequencer(m_sequencer), .parent_sequence(parent_seq) ); // API Sequence Start with Sequencer Handle and Parent Sequencer Handle
data = api_rd_seq.Val_D;
endtask : sv_read
endpackage
task C_sequence::body()
// C Program
dpi_seq_pkg::start( .sequencer(m_sequencer), .parent_sequence(this) );
package内でDPI-Cを使うことは許されていると思うが、とある商用シミュレータでは以前は実行時にオプションを設定しないとできなかった。うまくできない場合は各ベンダーのサポートに聞いてみよう。
上記の例ではdpi_seq_pkgとして別packageを用意したが、もちろんテストsequenceが入っているpackageや他のテストコンポーネントが入っているpackageに同様の記述をしても良い。Agentのpackageをいじれるならこの記述自体をAgentのpackageに入れてC/C++を走らせるAgent API Sequenceとしてしまっても良いかもしれない。
また、Verification Academyでは以下のようなさらにregister modelを使った方法が提案されているが、殆どの場合ここまで複雑にしなくても上記の方法で事足りるのではないだろうか。特にこの為だけにregister modelを作る事も無いだろう。
Verification Academy UVM C Based Stimulus
更に同じくVerification Academy内に以下の様なpapaerも見つけた。この例ではpackageではなく同じくstaticであるinterfaceを介してDPI-CでC/C++をコールしている。そしてinterface内で、Agent API Sequenceを介してではなく、Agentのsequencerを直接参照してsequenceを流しているようである。"the simplest approach"とは言っているがsequencerをいじったりしなくてはならず、とても"the simplest"には思えない。