Synthesijerで作ったモジュールをMessagePack-RPCで制御する(IP-Package編)

##はじめに

[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(アーキテクチャ編)](http://qiita.com/ikwzm/items/6cb623b057a687ff4a8e)の続きです。
今回は、[前回](http://qiita.com/ikwzm/items/6cb623b057a687ff4a8e)作った Accumulator と MessagePack-RPC サーバーを IP にパッケージする手順を説明します。

##開発ツール

 - Xilinx社 Vivado 2015.3

##手順1

リポジトリと各submodule をダウンロードします。

````
shell% git clone git://github.com/ikwzm/msgpack-vhdl-examples.git
shell% cd msgpack-vhdl-examples
shell% git submodule init
shell% git submodule update
shell% cd examples/accumulator/fpga/xilinx/ip
````

##手順2

最初の難関は、あちこちに分散された VHDL のソースコードをどのようにかき集めるかです。特に、MessagePack for VHDL のソースコードは結構ファイル数が多く、アナライズする順番に制約があります。

msgpack-vhdl-examples.git には、あらかじめ examples/accumulator/fpga/xilinx/ip に MessagePack for VHDL の必要なソースコードのみをアーカイブした msgpack.vhd と、それ以外のファイルを Vivado のプロジェクトに読み込むためのスクリプトファイル add_sources.tcl が用意してあります。これらのファイルを使う場合は、手順3に飛んでください。

ここでは msgpack.vhd と add_souces.tcl を生成する方法を説明します。
まず、次のような yaml ファイルを用意します。

````YAML:add_souces.yml
- Library:
    Name     :  msgpack
    Archive  :  msgpack.vhd
    PathList :  
        - "../../../../../msgpack-vhdl/src/msgpack/"

- Library:
    Name     :  work
    Print    :  true
    Format   :  "add_vhdl_file sources_1 #{library_name} #{file_name}"
    PathList :  
        - "../../../src/main/vhdl/"
        - "../../../src/main/synthesijer/Accumulator.vhd"
    Top      :  ["Accumulator_Server"]
````

次に ../../../../../PipeWork/tools/vhdl-archiver.rb を使って、msgpack.vhd と add_sources.tcl を作ります。

````
shell% ../../../../../PipeWork/tools/vhdl-archiver.rb --config add_sources.yml > add_sources.tcl
````
このスクリプトにより、../../../../../mstpack-vhdl/src/msgpack から必要なファイルのみを一つのファイル msgpack.vhd にまとめます。
add_sources.tcl は次のような Tcl スクリプトが生成されます。

````Tcl:add_sources.tcl
add_vhdl_file sources_1 WORK ../../../src/main/synthesijer/Accumulator.vhd
add_vhdl_file sources_1 WORK ../../../src/main/vhdl/add_interface.vhd
add_vhdl_file sources_1 WORK ../../../src/main/vhdl/get_interface.vhd
add_vhdl_file sources_1 WORK ../../../src/main/vhdl/set_interface.vhd
add_vhdl_file sources_1 WORK ../../../src/main/vhdl/accumulator_server.vhd
````

これで、IP に必要なソースファイルが揃いました。

##手順3

Vivado の IP-Packager を起動して IP を作ります。
いちいち GUI でボタンをペチペチやるのは非効率なので、Tclスクリプトを用意しました。

````Tcl:create_ip.tcl
#
# create_ip.tcl  Tcl script for create project and generate IP
#
set ip_name                 "accumulator_server"
set ip_vendor_name          "ikwzm"
set ip_library_name         "msgpack"
set ip_root_directory       [file join [file dirname [info script]] $ip_name]
set project_name            "accumulator_server"
set project_directory       [file join [file dirname [info script]] "work"]
set device_parts            "xc7z010clg400-1"
#
# Create project
#
create_project -force $project_name $project_directory
#
# Set project properties
#
set_property "part"               $device_parts    [get_projects $project_name]
set_property "default_lib"        "xil_defaultlib" [get_projects $project_name]
set_property "simulator_language" "Mixed"          [get_projects $project_name]
set_property "target_language"    "VHDL"           [get_projects $project_name]
#
# Create fileset "sources_1"
#
if {[string equal [get_filesets -quiet sources_1] ""]} {
    create_fileset -srcset sources_1
}
#
# Create fileset "constrs_1"
#
if {[string equal [get_filesets -quiet constrs_1] ""]} {
    create_fileset -constrset constrs_1
}
#
# Create fileset "sim_1"
#
if {[string equal [get_filesets -quiet sim_1] ""]} {
    create_fileset -simset sim_1
}
#
# Create run "synth_1" and set property
#
if {[string equal [get_runs -quiet synth_1] ""]} {
    create_run -name synth_1 -part $device_parts -flow "Vivado Synthesis 2014" -strategy "Vivado Synthesis Defaults" -constrset constrs_1
} else {
    set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1]
    set_property strategy "Flow_PerfOptimized_High"   [get_runs synth_1]
}
current_run -synthesis [get_runs synth_1]
#
# Create run "impl_1" and set property
#
if {[string equal [get_runs -quiet impl_1] ""]} {
    create_run -name impl_1 -part $device_parts -flow "Vivado Implementation 2014" -strategy "Vivado Implementation Defaults" -constrset constrs_1 -parent_run synth_1
} else {
    set_property strategy "Vivado Implementation Defaults" [get_runs impl_1]
    set_property strategy "Performance_Explore"            [get_runs impl_1]
}
current_run -implementation [get_runs impl_1]
#
# Add files
#
proc add_vhdl_file {fileset library_name file_name} {
    set file     [file normalize $file_name]
    set fileset  [get_filesets   $fileset  ] 
    set file_obj [import_files -norecurse -fileset $fileset $file]
    set_property "file_type" "VHDL"        $file_obj
    set_property "library"   $library_name $file_obj
}
add_vhdl_file sources_1 MsgPack msgpack.vhd
source "add_sources.tcl"
#
# Create IP-Package project
#
ipx::package_project -root_dir $ip_root_directory -vendor $ip_vendor_name -library $ip_library_name -taxonomy /UserIP -generated_files -import_files -force
#
# Infer Bus Interfaces
#
ipx::infer_bus_interfaces xilinx.com:interface:aximm_rtl:1.0 [ipx::current_core]
ipx::infer_bus_interfaces xilinx.com:interface:axis_rtl:1.0  [ipx::current_core]
#
# Set Supported Families
#
set_property supported_families {zynq Production virtex7 Production qvirtex7 Production kintex7 Production kintex7l Production qkintex7 Production qkintex7l Production artix7 Production artix7l Production aartix7 Production qartix7 Production zynq Production qzynq Production azynq Production} [ipx::current_core]
#
# Set Core Version
#
set_property core_revision 1 [ipx::current_core]
#
# Generate files
#
ipx::create_xgui_files       [ipx::current_core]
ipx::update_checksums        [ipx::current_core]
ipx::save_core               [ipx::current_core]
#
# Close and Done.
#
close_project
````
このスクリプトの肝は

 - add_vhdl_file　プロシージャで VHDLファイルをライブラリを設定しつつimportしている
 - ipx::package_project で IP-Package用のプロジェクトを作成している
 - ipx::infer_bus_interfaces で Interface を推定させている

ことです。特に今回の IP では MessagePack の入出力に AXI4-Stream を使っているので Vivado が自動的に Interface を推定して定義してくれるので大変楽です。

この create_ip.tcl を次のように Vivado で実行します。
````
shell% vivado -mode batch -source create_ip.tcl
````

または Vivado GUI を起動して、Tools > Run Tcl Script... から create_ip.tcl を選択。

これで ./examples/accumulator/fpga/xilinx/ip/accumulator_server が生成されます。

##参照

[MessagePack for VHDL (https://github.com/ikwzm/msgpack-vhdl)](https://github.com/ikwzm/msgpack-vhdl)
[MessagePack for VHDL Examples (https://github.com/ikwzm/msgpack-vhdl-examples)](https://github.com/ikwzm/msgpack-vhdl-examples)
[MessagePack-RPCを使ってFPGAを制御](http://qiita.com/ikwzm/items/2644c6e50a7049c75d49)
[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(アーキテクチャ編)](http://qiita.com/ikwzm/items/6cb623b057a687ff4a8e)
[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(ZYNQ論理合成編)](http://qiita.com/ikwzm/items/0254f1d49602095b5cde)
[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(TTYドライバ編)](http://qiita.com/ikwzm/items/533b905f7d1eb2e6c4d5)
[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(MessagePack-Ruby編)](http://qiita.com/ikwzm/items/f742e2c9b5d9642d8857)
[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(リモートサーバー編)](http://qiita.com/ikwzm/items/cfde888094c7c73f4ba6)