無償ツールで実践する「ハード・ソフト協調検証」(4) ―― SystemVerilog側のDPI-Cの記述を作成する

Verification Enginnerの戯言

tag: 半導体

技術解説 2009年12月28日

 

 tb_prog.svのtb_progモジュールでは,AvalonのMaster BFMのパッケージ(avalon_mm_pkg)をインポートしています(tb_prog.svの6行目).そのあと,一つのimport(15行目)と七つのexport(18~24行目)を宣言しています.

 importのdpi_mainタスクは,以下のように何の引き数も持ちません.

  import "DPI-C" context task dpi_main();


 taskの前にcontextがあるのは,C言語側の関数(dpi_main)内でSystemVerilog側のタスク(exportしているタスク)を呼び出すためです.

 一方,exportの七つのタスクは,C言語側から呼び出されるものです.

  export "DPI-C" task bfm_write32;
  export "DPI-C" task bfm_read32;
  export "DPI-C" task bfm_write16;
  export "DPI-C" task bfm_read16;
  export "DPI-C" task bfm_write8;
  export "DPI-C" task bfm_read8;
  export "DPI-C" task bfm_nop;


 bfm_write32,bfm_write16,bfm_write8の三つのタスクはライト・サイクルを実行します.32,16,8はアクセスするデータのサイズ(32ビット,16ビット,8ビット)です.bfm_read32,bfm_read16,bfm_read8の三つのタスクはリード・サイクルを実行します.ライト・サイクルと同じように,32,16,8はアクセスするデータのサイズです.bfm_nopタスクは,指定したサイクル(クロック)の間,ウェイトします.

 C言語側のdpi_main関数の中では,先に説明した七つのexportタスクを使ってSystemVerilog側にアクセスします.

 それでは各タスクについて説明します.

 

●dpi_main

 dpi_mainタスクは,以下のようにinitial文内(tb_prog.svの30~42行目)で実行します.

  initial begin

    `BFM.init();

    ・・・
    dpi_main();
    ・・・

    #100;
    $finish(2);
  end


 dpi_mainタスクを実行する前に,AvalonのMaster BFMの初期化関数(init)を実行します.AvalonのMaster BFMのインスタンス名は「`BFMマクロ」を使っています.`BFMマクロは,

   `define BFM  test_bench.DUT.the_mm_master_bfm_0.mm_master_bfm_0


のように定義します.なお,インスタンス名のパスはSOPC Builderが自動生成したものです.

 dpi_mainタスクを実行したあと,#100(100ns)だけウェイトし,シミュレーションを終了($finish)します.dpi_mainタスクが実行されると,C言語側のdpi_main関数が呼ばれます.

 

●bfm_write32,bfm_write16,bfm_write8

 bfm_write32,bfm_write16,bfm_write8の三つのタスクはアクセスするデータのサイズが違うだけなので,ここではbfm_write32タスク(tb_prog.svの93~105行目)についてのみ説明します.

  task bfm_write32( int unsigned addr, input int unsigned data );
      int byte_enable;
 
     if( addr & 'h3 ) begin // address check
          return;
    end

    byte_enable = 'hf;

    bfm_run( REQ_WRITE, addr, byte_enable, data );
    $display("bfm_write32 : addr = 0x%h, data = 0x%x", addr, data );

  endtask : bfm_write32


 bfm_write32タスクでは,最初のアドレスのチェックを行います.32ビット(4バイト)アクセスなので,アドレスの下位2ビットは0でなければなりません.次にバイト・イネーブル(byte_enable)をすべて1('hf)にして,bfm_runタスクを呼び出しています.

 bfm_runタスク(tb_prog.svの50~76行目)は,以下のようにAvalonのMaster BFMに対してサイクルを実行します.

  task bfm_run( Request_t request, int addr, int byte_enable, inout int data );
    `BFM.set_command_request(request);
    `BFM.set_command_address(addr);
    `BFM.set_command_byte_enable(byte_enable,0);
    `BFM.set_command_idle(0,0);
    `BFM.set_command_init_latency(0);
    `BFM.set_command_burst_count(1);
    `BFM.set_command_burst_size(1);

    if( request == REQ_WRITE )
      `BFM.set_command_data(data, 0);

    `BFM.push_command();

    while(1) begin
      @(posedge `BFM.clk);
      if(`BFM.get_response_queue_size() > 0)
        break;
    end

    `BFM.pop_response();

    if( request == REQ_READ )
      data = `BFM.get_response_data(0);

  endtask : bfm_run 


 bfm_runタスク内では,AvalonのMaster BFMが提供しているAPIを使ってバス・サイクルを発生させます.`BFM.set_command_xxxで始まる行でコマンドを設定します.

 ライト・サイクルのときは,データを設定します(`BFM.set_command_data).`BFM.push_command()でコマンドを登録します.この時点で,AvalonのMaster BFMは登録されたコマンドを取り出し,バスにサイクルを発生します.bfm_runタスクでは,AvalonのMaster BFMからのレスポンスが戻ってくるまで待ちます.

  ( `BFM.get_response_queu_size() > 0 )


 レスポンスが戻ってきたら,`BFM.pop_response()でレスポンス情報を取り出します.リード・サイクルのときは,レスポンスからデータ(data)を取り出します.

 

●bfm_read32,bfm_read16,bfm_read8

 fm_read32,bfm_read16,bfm_read8の三つのタスクはアクセスするデータのサイズが違うだけなので, ライト・サイクルのところと同じようにbfm_read32タスク(tb_prog.svの78~91行目)のみ説明します.
 bfm_read32タスクでは,最初のアドレスのチェックを行います.

  task bfm_read32(  int unsigned addr, output int unsigned data );
    int byte_enable;

    if( addr & 'h3 ) begin // address check
      data = 'hffff_ffff;
      return;
    end

    byte_enable = 'hf;

    bfm_run( REQ_READ, addr, byte_enable, data );
    $display("bfm_read32  : addr = 0x%h, data = 0x%x", addr, data );

  endtask : bfm_read32


 32ビット(4バイト)アクセスなので,アドレスの下位2ビットは0でなければなりません.次にバイト・イネーブル(byte_enable)をすべて1('hf)にして,bfm_runタスクを呼び出しています.リードしたデータがdataに書き込まれます.

 

●bfm_nop

 bfm_nopタスク(tb_prog.svの190~195行目)では,引き数で指定されたクロック数だけウェイトします.

  task bfm_nop( int no );

    for( int n=0 ; n<no ; n++ )
      @(posedge `BFM.clk);

  endtask : bfm_nop

 


(第5回へ続く)

Verification Enginnerの戯言
http://blogs.yahoo.co.jp/verification_engineer

 

«  1  2
組み込みキャッチアップ

お知らせ 一覧を見る

電子書籍の最新刊! FPGAマガジン No.12『ARMコアFPGA×Linux初体験』好評発売中

FPGAマガジン No.11『性能UP! アルゴリズム×手仕上げHDL』好評発売中! PDF版もあります

PICK UP用語

EV(電気自動車)

関連記事

EnOcean

関連記事

Android

関連記事

ニュース 一覧を見る
Tech Villageブログ

渡辺のぼるのロボコン・プロモータ日記

2年ぶりのブログ更新w

2016年10月 9日

Hamana Project

Hamana-8最終打ち上げ報告(その2)

2012年6月26日