FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

VivadoでIPを生成する方法の調査(tclを使った生成方法)

f:id:msyksphinz:20170715133001p:plain

Zynqを使ったカスタムデザインのIPが作りたくて、IPの生成方法をいろいろ調査しているのだが、どうもGUIを操作するものばかりでつまらない。

GUIの操作方法なんて一瞬で忘れてしまうので、tclとmakefileで一気に作れるような環境を用意しておきたい。

いろいろ調査していて、結局ZedBoardのIP生成ディレクトリのスクリプトにたどり着いた。

github.com

こちらのリポジトリは"project"と"library"のディレクトリに分かれており、libraryはVivadoのIPを生成するようなスクリプトが用意されている。

例えば、axi_clkgenというIPを作るためには、リポジトリ内でaxi_clkgenのリポジトリに移動してmakeを叩くだけである。

$ cd library/axi_clkgen
$ make
rm -rf *.cache *.data *.xpr *.log component.xml *.jou xgui *.ip_user_files *.srcs *.hw *.sim .Xil
vivado -mode batch -source axi_clkgen_ip.tcl  >> axi_clkgen_ip.log 2>&1

axi_clkgen_ip.tclを見てみると、以下のような構造になっている。各種サポート関数群 (adi_xxx)は、 adi_ip.tclに格納されているので、これは必要ならば参照する。

source ../scripts/adi_env.tcl
source $ad_hdl_dir/library/scripts/adi_ip.tcl

adi_ip_create axi_clkgen
adi_ip_files axi_clkgen [list \
  "$ad_hdl_dir/library/common/ad_rst.v" \
  "$ad_hdl_dir/library/xilinx/common/ad_mmcm_drp.v" \
  "$ad_hdl_dir/library/common/up_axi.v" \
  "$ad_hdl_dir/library/common/up_clkgen.v" \
  "axi_clkgen_constr.xdc" \
  "axi_clkgen.v" ]

adi_ip_properties axi_clkgen

ipx::remove_bus_interface {clk} [ipx::current_core]
ipx::associate_bus_interfaces -busif s_axi -clock s_axi_aclk [ipx::current_core]

set_property driver_value 0 [ipx::get_ports *clk2* -of_objects [ipx::current_core]]

adi_ip_constraints axi_clkgen [list \
  "axi_clkgen_constr.xdc" ]

ipx::save_core [ipx::current_core]

どうやら必要なのは、

  1. adi_ip_createでIPを生成する。
  2. adi_ip_filesコンパイル対象のファイル群を指定する。
  3. adi_ip_propertiesコンパイル対象プロジェクトのプロパティを設定する。
  4. 各種バスや製薬の設定。
  5. adi_ip_constraintsで制約条件の設定。
  6. `ipx::save_core でIPの保存。

上記の構成を真似て、オリジナルのIPを作ってみる。ベースはまずはGUI生成したものからとってる来るが、インタフェースを合わせて合成できるようにする。

github.com

注意する点としては adi_ip_propertiesで設定するインタフェースの信号名と合わせておいた方がよい。

  • adi_ip.tcl
proc adi_ip_properties {ip_name} {

  adi_ip_properties_lite $ip_name

  ipx::infer_bus_interface {\
    s_axi_awvalid \
    s_axi_awaddr \
    s_axi_awprot \
    s_axi_awready \
    s_axi_wvalid \
...
  • blockram_test_v1_0.v
    // Ports of Axi Slave Bus Interface S00_AXI
    input wire                                  s_axi_aclk,
    input wire                                  s_axi_aresetn,
    input wire [C_S00_AXI_ID_WIDTH-1 : 0]        s_axi_awid,
    input wire [C_S00_AXI_ADDR_WIDTH-1 : 0]  s_axi_awaddr,
    input wire [7 : 0]                            s_axi_awlen,
    input wire [2 : 0]                            s_axi_awsize,
    input wire [1 : 0]                            s_axi_awburst,
    input wire                                  s_axi_awlock,
    input wire [3 : 0]                            s_axi_awcache,
    input wire [2 : 0]                            s_axi_awprot,
    input wire [3 : 0]                            s_axi_awqos,
    input wire [3 : 0]                            s_axi_awregion,
    input wire [C_S00_AXI_AWUSER_WIDTH-1 : 0]    s_axi_awuser,

最初、Verilog記述の方がs00_axi_...という記述で全くコンパイルが通らなかったので不思議に思っていたのだが、s_axi_...という記述に変更したら上手く行くようになった。

次に、これをVivadoに取り込んで、IPとして利用できるようにする。