FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Zynq ZedBoardを使ってPSとPLの協調プログラミング入門(2)

f:id:msyksphinz:20160524232435p:plain

前回までで、ZedBoard用のハードウェアの基盤が出来上がったので、今度はPLロジック部に追加するハードウェアを作り、IPとして追加していこう。

msyksphinz.hatenablog.com

  • 使用ツール : Vivado 2016.2
  • 使用OS : Windows 10

VivadoでIPを新規作成する

前回までの状態。ZedBoardのZynqプラットフォームが定義されている。

f:id:msyksphinz:20160827210248p:plain

[Tools]→[Create and Package IP]を選択すると、ウィザードがスタートする。

f:id:msyksphinz:20160827210513p:plain

[Create AXI4 Peripheral]を選択しておく。

f:id:msyksphinz:20160827210514p:plain

IPの情報を入力する。ここでは、AXIのスレーブIPとして、simple_bramという小さなブロックRAMを追加する。

f:id:msyksphinz:20160827210515p:plain

スレーブAXIポートの名前を[S_AXI]に変更しておく。

f:id:msyksphinz:20160827210517p:plain

[Edit IP]を選択して、Finishをクリックする。これでIPの外形の作成は完了だ。

f:id:msyksphinz:20160827210518p:plain

simple_bram_v_1_0_S_AXI.v を編集することにする。

f:id:msyksphinz:20160827210921p:plain

simple_bram_v_1_0_AXI.vの基本構造

どうやら内部を見てみると、AXIのチャネルを4つのサブチャネルに分割したサンプル構造になっているようだ。

データ幅はC_S_AXI_DATA_WIDTHで定義されてり、8ビット毎にバイトイネーブルが定義されている。WSTRBは

     input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,

として定義されていた。これをブロックRAMに格納するために、以下のようなRAMを用意して、書き込みを管理するようにする。バイト単位にアドレスを変えてデータを書き込む。

    reg[ 7: 0] mems0[1023: 0];
...
  always @( posedge S_AXI_ACLK )
    begin
      if ( S_AXI_ARESETN == 1'b0 )
        begin
        end 
      else begin
        if (slv_reg_wren)
          begin
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 0
                mems0[{axi_awaddr[11: ADDR_LSB], {ADDR_LSB{1'b0}}} + byte_index] = S_AXI_WDATA[(byte_index*8) +: 8];
              end
          end
      end
    end    

データの出力は以下のような論理を組み立てる。

  always @(*)
    begin
      reg_data_out <= mems[axi_raddr[11: 0]];
    end

  // Output register or memory read data
  always @( posedge S_AXI_ACLK )
    begin
      if ( S_AXI_ARESETN == 1'b0 )
        begin
          axi_rdata  <= 0;
        end 
      else
        begin    
          // When there is a valid read address (S_AXI_ARVALID) with 
          // acceptance of read address by the slave (axi_arready), 
          // output the read dada 
          if (slv_reg_rden)
            begin
              axi_rdata <= reg_data_out;     // register read data
            end   
        end
    end    

これでIPは完成だ。

IPをZynqのプラットフォームに追加する

作成したsimple_bram_v1.0をZynqプラットフォームに追加してみよう。

Diagramから[Add IP]をクリックし、simple_bram_v1.0をクリックする。

f:id:msyksphinz:20160827211648p:plain

追加されるので、[Run Block Automation]および[Run Connection Automation]をクリックする。

f:id:msyksphinz:20160827211723p:plain

f:id:msyksphinz:20160827211748p:plain

f:id:msyksphinz:20160827211757p:plain

f:id:msyksphinz:20160827211800p:plain

f:id:msyksphinz:20160827211803p:plain

[Rgenerate Layout]をクリックすることで、配線した後のレイアウトを綺麗にすることができる。

f:id:msyksphinz:20160827211842p:plain

ここでアドレスマップを見てみる。アドレス0x43C0_0000から0x43C0_FFFFまでマップされていることが分かる。

f:id:msyksphinz:20160827211921p:plain

参考文献

以下を参考にさせて頂いた。というかほぼパクってしまった。ありがたい。

qiita.com