FC2カウンター FPGAの部屋 無償ツールで実践する「ハード・ソフト協調検証」をやってみる5(ライブラリ化)
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

無償ツールで実践する「ハード・ソフト協調検証」をやってみる5(ライブラリ化)

17.ライブラリ化する
無償ツールで実践する「ハード・ソフト協調検証」(6) ―― 協調シミュレーションを実行するの2ページ目の”17.ライブラリ化する”のavalon_cpu.svのコードをコピーして、avalon_cpu.svとしてセーブした。これにtb_prog.svファイルを追加した。avalon_cpu.svファイルに一部を示す。(リスト11のコードを引用させていただきます。)

module avalon_cpu (
    input  wire        clk,
    input  wire        reset,
    output wire [31:0] avm_address,
    output wire [2:0]  avm_burstcount,
    input  wire [31:0] avm_readdata,
    output wire [31:0] avm_writedata,
    input  wire        avm_waitrequest,
    output wire        avm_write,
    output wire        avm_read,
    output wire [3:0]  avm_byteenable,
    input  wire        avm_readdatavalid        
);
    altera_avalon_mm_master_bfm #(
    )
    .............. // AV_ADDRESS_W 等の定義
    cpu (
        .clk                    (clk),
        .reset                  (reset),
        .address                (avm_address),
        .avm_burstcount         (avm_burstcount),
        .avm_readdata           (avm_readdata),
        .avm_writedata          (avm_writedata),
        .avm_waitrequest        (avm_waitrequest),
        .avm_write              (avm_write),
        .avm_read               (avm_read),
        .avm_byteenable         (avm_byteenable), 
        .avm_readdatavalid      (avm_readdatavalid),
        .avm_begintransfer      (),
        .avm_beginbursttransfer () 
    );
    
    `define BFM cpu


    // =========================================================================
    // DPI-C
    // =========================================================================

    `ifndef TEST_BFM
    import "DPI-C" context task dpi_main();
    `endif // TEST_BFM

    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;

    // =========================================================================
    // Main
    // =========================================================================

    initial begin

    `BFM.init();

    `ifdef TEST_BFM
    test_bfm;
    `else
    dpi_main();
    `endif // TEST_BFM

    #100;
    $finish(2);
    end
    
    ............ // tb_prog.svの残り
    
endmodule : avalon_cpu 


System ContentsタブのComponent LibraryからProjectの下のNew component... をダブルクリックすると、Component Editorダイアログが立ち上がった(ハード・ソフト協調検証」(6)の図18)。
Nextボタンをクリックして、HDL Filesタブに移動して、Addボタンをクリックして、avalon_cpu.svを追加する。(ハード・ソフト協調検証」(6)の図19)
そうすると、エラーがたくさん出る。これはSOPC Builder がSystemVerilogに対応していないからだと思う。
hard_soft_19_100303.png

これだと、avalon_cpuはSOPC Builderのコンポーネントとして認識されないようだ?ハード・ソフト協調検証」(6)の図21にも図22にも何も表示されない。
どうもおかしいので、Verification Engineerの戯言さんのブログで聞いてみたら、`ifdef DPI_Cが必要とのことだった。それを加えた全ソースをリスト11から引用させていただきます。(Verification Engineerの戯言さん、ありがとうございました。問題があったらお知らせください)

module avalon_cpu (
    input  wire        clk,
    input  wire        reset,
    output wire [31:0] avm_address,
    output wire [2:0]  avm_burstcount,
    input  wire [31:0] avm_readdata,
    output wire [31:0] avm_writedata,
    input  wire        avm_waitrequest,
    output wire        avm_write,
    output wire        avm_read,
    output wire [3:0]  avm_byteenable,
    input  wire        avm_readdatavalid        
);
    altera_avalon_mm_master_bfm #(
        .AV_ADDRESS_W             (32),
        .AV_SYMBOL_W              (8),
        .AV_NUMSYMBOLS            (4),
        .AV_BURSTCOUNT_W          (3),
        .USE_READ                 (1),
        .USE_WRITE                (1),
        .USE_ADDRESS              (1),
        .USE_BYTE_ENABLE          (1),
        .USE_BURSTCOUNT           (1),
        .USE_READ_DATA            (1),
        .USE_READ_DATA_VALID      (1),
        .USE_WRITE_DATA           (1),
        .USE_BEGIN_TRANSFER       (0),
        .USE_BEGIN_BURST_TRANSFER (0),
        .USE_WAIT_REQUEST         (1),
        .AV_BURST_LINEWRAP        (1),
        .AV_BURST_BNDR_ONLY       (1),
        .AV_MAX_PENDING_READS     (1),
        .AV_FIX_READ_LATENCY      (1)
    )
    cpu (
        .clk                    (clk),
        .reset                  (reset),
        .address                (avm_address),
        .avm_burstcount         (avm_burstcount),
        .avm_readdata           (avm_readdata),
        .avm_writedata          (avm_writedata),
        .avm_waitrequest        (avm_waitrequest),
        .avm_write              (avm_write),
        .avm_read               (avm_read),
        .avm_byteenable         (avm_byteenable), 
        .avm_readdatavalid      (avm_readdatavalid),
        .avm_begintransfer      (),
        .avm_beginbursttransfer () 
    );
    
    `define BFM cpu

    `ifdef DPI_C
        // =========================================================================
        // DPI-C
        // =========================================================================

        `ifndef TEST_BFM
        import "DPI-C" context task dpi_main();
        `endif // TEST_BFM

        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;

        // =========================================================================
        // Main
        // =========================================================================

        initial begin

        `BFM.init();

        `ifdef TEST_BFM
        test_bfm;
        `else
        dpi_main();
        `endif // TEST_BFM

        #100;
        $finish(2);
        end

        // =========================================================================
        // Task
        // =========================================================================

        import avalon_mm_pkg::*;

        task automatic 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  

        task automatic 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

        task automatic 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

        task automatic bfm_read16(  int unsigned addr, output shortint unsigned data );
        int byte_enable;
        int unsigned word;

        if( addr & 'h1 ) begin // address check
            data = 'hffff;
            return;
        end

        case ( addr & 'h2 )
          0 : byte_enable = 'h3;
          2 : byte_enable = 'hc;
        endcase
          
        bfm_run( REQ_READ, addr, byte_enable, word );

        case( addr & 'h2 )
          0 : data = (word & 'h0000_ffff) >>  0;
          2 : data = (word & 'hffff_0000) >> 16;
        endcase

        $display("bfm_read16  : addr = 0x%h, data = 0x%x", addr, data );
          
        endtask : bfm_read16

        task automatic bfm_write16( int unsigned addr, input shortint unsigned data );
        int byte_enable;
        int unsigned word;

        if( addr & 'h1 ) begin // address check
            return;
        end

        case ( addr & 'h2 )
          0 : begin byte_enable = 'h3; word = (data <<  0) & 'h0000_ffff; end
          2 : begin byte_enable = 'hc; word = (data << 16) & 'hffff_0000; end
        endcase

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

        endtask : bfm_write16

        task automatic bfm_read8(  int unsigned addr, output byte unsigned data );
        int byte_enable;
        int unsigned word;

        case ( addr & 'h3 )
          0 : byte_enable = 'h1;
          1 : byte_enable = 'h2;
          2 : byte_enable = 'h4;
          3 : byte_enable = 'h8;
        endcase

        bfm_run( REQ_READ, addr, byte_enable, word );

        case ( addr & 'h3 )
          0 : data = (word & 'h0000_00ff) >>  0;
          1 : data = (word & 'h0000_ff00) >>  8;
          2 : data = (word & 'h00ff_0000) >> 16;
          3 : data = (word & 'hff00_0000) >> 24;
        endcase

        $display("bfm_read8   : addr = 0x%h, data = 0x%x", addr, data );
          
        endtask : bfm_read8

        task automatic bfm_write8( int unsigned addr, input byte unsigned data );
        int byte_enable;
        int unsigned word;

        case ( addr & 'h3 )
          0 : begin byte_enable = 'h1; word = (data <<  0) & 'h0000_00ff; end
          1 : begin byte_enable = 'h2; word = (data <<  8) & 'h0000_ff00; end
          2 : begin byte_enable = 'h4; word = (data << 16) & 'h00ff_0000; end
          3 : begin byte_enable = 'h8; word = (data << 24) & 'hff00_0000; end
        endcase

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

        endtask : bfm_write8

        task automatic bfm_nop( int no );

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

        endtask : bfm_nop

        task test_bfm;
        int unsigned addr;

        addr = 'h0000_0000;

        for ( int n=0 ; n<4 ; n+=4 ) begin : int_loop    
          int unsigned a, b;

          a  = 'h1234_5678;
          bfm_write32( addr, a );
          bfm_read32 ( addr, b );
          $display("addr = 0x%h, exp = 0x%h, data = 0x%h", addr, b, a );  
        end

        addr = 'h0000_1000;
        for ( int n=0 ; n<4 ; n+=2 ) begin : short_loop
          shortint unsigned a, b;
          
          a  = 'h4567 + n*2; 
          bfm_write16( addr + n, a );
          bfm_read16 ( addr + n, b );
          $display("addr = 0x%h, exp = 0x%h, data = 0x%h", addr, b, a );  
          a += a;
        end

          addr = 'h0000_2000;
        for ( int n=0 ; n<4 ; n++ ) begin : byte_loop
          byte unsigned a, b;
          
          a  = 'h12 + n*4;
          bfm_write8( addr + n, a );
          bfm_read8 ( addr + n, b );
          $display("addr = 0x%h, exp = 0x%h, data = 0x%h", addr, b, a );
          a += a;
        end

        endtask : test_bfm 
    `else // DPI_C
    
    `endif // DPI_C

endmodule : avalon_cpu 


これだと、HDL Filesタブに移動して、Addボタンをクリックして、avalon_cpu.svを追加してもエラーは発生しない。(ハード・ソフト協調検証」(6)の図19
以下順番に続けると、Analyzing avalon_cpu.sv Completedダイアログが表示される(ハード・ソフト協調検証」(6)の図20)。
closeボタンをクリックすると、HDL Filesにavalon_cpu.sv が入っている。
hard_soft_16_100301.png

Nextボタンをクリックすると、Signalsタブが表示される(ハード・ソフト協調検証」(6)の図21)。
次々にボタンをクリックして行くと、ハード・ソフト協調検証」(6)の図22から図24までが表示された。
Libraryにavalon_cpuが表示された。
hard_soft_17_100301.png

Avalon MM Master BFMを削除して、生成したavalon_cpuを入れて、onchip_memory2_0と接続した。
hard_soft_20_100303.png

その後、Generateボタンでシステムを生成し、成功した。

次に、シミュレーションを行うが、その前に、setup_sim.doの書き換えを行う。setup_sim.doはSOPC BuilderのGenerateで作り直されている。よって、下の部分を変更して、setup_dpi_lib.do としてセーブした。下にalias _vsimの部分とvlogの部分を抜き出す。

alias _vsim {vsim -t ps +nowarnTFMPC -sv_root prog -sv_lib dpi_main -L lpm_ver -L sgate_ver -L altera_mf_ver -L altgxb_ver -L stratixiigx_hssi_ver -L stratixgx_ver -L stratixgx_gxb_ver -L stratixiigx -L altera_ver -L stratixiii_ver -L stratixii_ver -L cycloneii_ver -L cycloneiii_ver -L stratixiv_hssi_ver -L arriaii_ver -L arriaii_pcie_hip_ver -L arriaii_hssi_ver -L stratixiv_pcie_hip_ver -L cycloneiv_pcie_hip_ver -L cycloneiv_hssi_ver -L hardcopyiv_pcie_hip_ver -L hardcopyiv_hssi_ver test_bench} } else {
alias _vsim {vsim -t ps +nowarnTFMPC -sv_root prog -sv_lib dpi_main test_bench } }


-sv_root prog -sv_lib dpi_mainを付け加えた。

vlog -sv +incdir+.. ../avalon_bfm.v;


-svを付け加えた。
これで、ModelSim AE 6.5bを起動し、avalon_bfm_sim.mpfをオープンして(オープンしてあった)、Transcriptペインで、

do setup_sim_lib.do


を実行した。次に(sを実行してコンパイルが抜けていました。追加します。)

_vsim


を実行すると、シミュレーションがスタートした。
次に、

do wave.do

を行っても、信号はwaveウインドウに表示されなかったので、Simウインドウのtest_bench -> DUT -> the_avalon_cpu_0 -> avalon_cpu_0 を選択して、Objectウインドウに表示された信号をwaveにドラックアンドドロップした。

run -all

をしてRUNするが、finishしない。
hard_soft_21_100304.png

そういえば、Simウインドウのtest_bench -> DUT -> the_avalon_cpu_0 -> avalon_cpu_0 を選択してもSystemVerilogの信号名が表示されないのはおかしい?
そうかそういえば、コンパイルするときに DPI_C を define していないから当たり前か?
コンパイル時にdefine をしてくれるオプションを探すことにした。ModelSimのリファレンスマニュアルを見ると、コンパイルはvlogで行うことがわかった。そして、+define+macro_nameでコンパイル時にdefine 出来ることがわかった。
早速、setup_sim_lib.do のvlog の行を下のように変更した。

vlog -sv +define+DPI_C +incdir+.. ../avalon_bfm.v;


その後、ModelSim AE 6.5bのTranscriptペインで、

do setup_sim_lib.do


を実行して、次に

s


を実行したら、vsimも走って、シミュレーションの準備が終了した。Simウインドウのtest_bench -> DUT -> the_avalon_cpu_0 -> avalon_cpu_0 を選択すると、Objectウインドウに信号名が表示されたので、それをwaveウインドウにドラックアンドドロップした。waveウインドウの信号名のRadix をHexadicmal に変更した。その上で、

run -all


を実行したら、finishのダイアログが表示されて、うまく行った。Noボタンをクリックすると、前回と同様に波形が表示された
hard_soft_22_100305.png

やっとうまく行った。うれしい。。。これで、SOPC Builderで新しいコンポーネントとして作ったバストランザクションモデルをCから起動してシミュレーションを行うことができた。
Verification Engineerの戯言さん、ありがとうございました。無事に成功しました。

(2010/03/05:追記)
コメントでvlogさんに教えていただきました。ありがとうございました。
ModelSimのProjectに入れれば、右クリックのプロパティで開いたProject Complier SettingsダイアログのVerilog & System VerilogタブのOther Verilog OptionsのMacro...ボタンをクリックして開いたDefine MacroダイアログのMacro NameにDPI_Cを入れればコンパイル時にMacroが定義されるそうです。
hard_soft_23_100305.png
  1. 2010年03月05日 04:52 |
  2. SystemVerilog
  3. | トラックバック:0
  4. | コメント:4

コメント

define設定

こんんちは。いつも参考にさせて頂いております。

すでにご存知でしたらすみません。

defineの設定方法でもうひとつ。
Projectウィンドウからdefineを指定したいソースファイルを選択し、
右クリックでプロパティを表示させます。
Verilog&SystemVerilogのタブの下の方にあるMacroボタンを押すと
MacroNameおよびvalueの値が設定できます。

  1. 2010/03/05(金) 13:13:43 |
  2. URL |
  3. vlog #-
  4. [ 編集 ]

vlogさん、こんにちは。
教えていただいて、ありがとうございました。ブログに追記させていただきました。
  1. 2010/03/05(金) 18:47:15 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

うまくいってよかったですね!

私の記事の情報不足にて、ご迷惑おかけしました。

  1. 2010/03/05(金) 21:48:22 |
  2. URL |
  3. Verification Engineerの戯言 #YTIpxIas
  4. [ 編集 ]

こんにちは。
ありがとうございました。お陰さまでやってみることができました。
終わりまでやってみたいと思います。
  1. 2010/03/06(土) 04:27:34 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/1393-87cc10b8
この記事にトラックバックする(FC2ブログユーザー)