FPGA開発日記

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

RISC-V Foundationのメンバーのインタビュー記事から考える、半導体で生き残る道

RISC-VのFoundation Memberの一人、"Krste Asanovic"のインタビュー記事が掲載されている。

普段このような細かいニュース記事をブログにすることはないのだけれども、この記事を読めばRISC-Vが何を狙っているのか良く分かるので、興味のある人は読んでほしい。

circuitcellar.com

ここで彼が答えていることはRISC-Vの概要、そして狙っているターゲット、RISC-Vの将来について。 これらについては、ほぼ私の考えている事と一致しているというのは正直安心した。

つまり、

  • ISAをオープンソースにすることによって誰が利益を享受するのか?

    • ARMのような高価なコアを購入することのできない中小ベンダ。
  • 既にARM、x86が占拠しているマイクロプロセッサ業界において、何処をターゲットにするのか?

    • IoT、自動車分野など、まだ上記のプロセッサが占拠できていない場所
    • (私の意見だが)、IoTはまだしも、自動車は難しいと思うんだな。。。制御マイコンは工場などの品質を含めた協力が必要、上位はより高性能なアクセラレータが必要。。。

プロセスが進むにつれてGoogleNVIDIAなど、一部の巨大企業のみがチップを作れるようになっている。 一方で古いプロセスにて、無料でIPを使うことができ、プロセッサを含めデザインを構築することができるというのは、現在の産業界の摩擦(技術はあってもチップを作るお金がない)などの問題を解決することができるとしている。 つまり直接RISC-Vの利益を享受できるのは、協賛に入っているGoogleMicrosoftNVIDIA、も含めだが、より重要なのはあまりお金を持っていない中小企業だ。

また、これまでの少品種大量生産から、大量のバリエーションを少量ずつ生産するというモデルに代わる際、現在のIPビジネスは成り立たなくなり、自由に利用できカスタマイズできるOpenISAに利点が集まるとしている。

これを読んでわかることは、もう日本の古い半導体企業を含め、プロセッサなんて差異の出ない分野に取り組んではいけないということだ。

プロセッサは汎用品で十分。むしろ最も時間をかけずに実装できるものを選ぶべき。そして、その傍に何を搭載するか、アクセラレータだったり、ペリフェラルだったり、ソフトウェアだったり、そちらに焦点を当てないと乗り遅れるぞ、と言っているんじゃないのかい?

とまあ偏った考え方をしてみたが、RISC-Vが狙っているのはこのような世界ではないかと思えてきた。

RISC-Vがプロセッサの世界で標準として確立されるならば、そのメリットに大いに享受して、ほかの人はそれ以外のことを考えるべき、じゃないだろうか?

VivadoでIPを生成する方法の調査(VivadoのIPインテグレーションの仕組み調査3. tclを用いた自動化の調査)

f:id:msyksphinz:20170723164014p:plain

Vivadoで生成したIPを接続してVivadoプロジェクトをビルドし、SDカードに書き込むことでブートできるようになった。

f:id:msyksphinz:20170726005913p:plain

物理デバイスにアクセスしてBlockRAMとして制御できているか確認する。 書き込んだ値が読めている。またアドレス毎に別々に値が読み書きできていることから、BlockRAMとしてきちんと動作できていることが分かる。

f:id:msyksphinz:20170726010447p:plain

  • devmem2 について

armadillo.atmark-techno.com

さて、ここまでは良いとして、いちいちGUIを立ち上げるのは面倒なので、どうにかしてtcl化したい。

いろいろ参考にしているが、主にQiitaの記事を参考にしている。

qiita.com

qiita.com

Vivadoプロジェクトのビルド後に、ハードウェアをエクスポートするのもスクリプト化しておく。まさしく上記の記事がドンピシャだ。

以下のようなプロジェクトを作成した。

github.com

  • create_hdf.tcl
set project_directory   [file dirname [info script]]
set hw_name             "system_top_hw_platform_0"
set project_name adv7511_zed

open_project [file join $project_directory $project_name]

set project_directory [file dirname [info script]]
set sdk_workspace  [file join $project_directory $project_name.sdk]

if { [file exists [file join $sdk_workspace $hw_name]] == 0 } {
    file mkdir [file join $sdk_workspace $hw_name]
}
set design_top_name [get_property "top" [current_fileset]]
file copy -force [file join $project_directory $project_name.runs "impl_1" $design_top_name.sysdef] [file join $sdk_workspace $hw_name $design_top_name.hdf]

close_project

次に、SDKを走らせてfsbl.elfを作成する。こちらもスクリプト化してある。

  • ceate_fsbl.tcl
#!/usr/bin/tclsh

set app_name            "fsbl"
set app_type            {Zynq FSBL}
set bsp_name            "fsbl_bsp"
set hw_name             "system_top_hw_platform_0"
set hwspec_file         "system_top.hdf"
set proc_name           "ps7_cortexa9_0"
set project_directory   [file dirname [info script]]
set sdk_workspace       [file join $project_directory "adv7511_zed.sdk"]

if {[info commands sdk::setws] ne ""} {
    sdk setws         $sdk_workspace
} else {
    sdk set_workspace $sdk_workspace
}

if {[info commands sdk::createhw] ne ""} {
    sdk createhw          -name $hw_name -hwspec [file join $sdk_workspace $hwspec_file]
} else {
    sdk create_hw_project -name $hw_name -hwspec [file join $sdk_workspace $hwspec_file]
}

hsi::open_hw_design  [file join $sdk_workspace $hw_name $hwspec_file]
hsi::create_sw_design $bsp_name -proc $proc_name -os standalone
hsi::add_library xilffs
hsi::generate_bsp -sw $bsp_name -dir [file join $sdk_workspace $bsp_name] -compile
hsi::close_sw_design  $bsp_name

if {[info commands sdk::createapp] ne ""} {
    sdk createapp          -name $app_name -hwproject $hw_name -proc $proc_name -os standalone -lang C -app $app_type -bsp $bsp_name
} else {
    sdk create_app_project -name $app_name -hwproject $hw_name -proc $proc_name -os standalone -lang C -app $app_type -bsp $bsp_name
}

if {[info commands sdk::projects] ne ""} {
    sdk projects -build
} else {
    sdk build_project $app_name
}

exit

boot.binの作成も上記のQiitaの要領だ。とても役に立つ!

bootgen:
        bootgen -image ./boot.bif -o i boot.bin

boot.bifは以下のように記述した。

image : {
        [bootloader]./adv7511_zed.sdk/fsbl/Debug/fsbl.elf
        ./adv7511_zed.sdk/system_top_hw_platform_0/system_top.bit
        ../../../../u-boot-xlnx/u-boot.elf
}

VivadoでIPを生成する方法の調査(VivadoのIPインテグレーションの仕組み調査2. )

ZedBoardのIPデザインに対して、BlockRAMのモジュールを挿入する。

BlockRAMの設計

AXI4のインタフェースを持ったBlockRAMデザインを設計する。AXI4のインタフェースは他のデザインから取ってくる。

github.com

blockram_test_v1_0
 - blockram_test_v1_0_S00_AXI

blockram_test_v1_0はAXI4のインタフェースを持たせた。

module blockram_test_v1_0 #
  (
   // Users to add parameters here

   // User parameters ends
   // Do not modify the parameters beyond this line


   // Parameters of Axi Slave Bus Interface S00_AXI
   parameter integer C_s_axi_ID_WIDTH = 1,
   parameter integer C_s_axi_DATA_WIDTH = 32,
   parameter integer C_s_axi_ADDR_WIDTH = 6,
   parameter integer C_s_axi_AWUSER_WIDTH = 0,
   parameter integer C_s_axi_ARUSER_WIDTH = 0,
   parameter integer C_s_axi_WUSER_WIDTH = 0,
   parameter integer C_s_axi_RUSER_WIDTH = 0,
   parameter integer C_s_axi_BUSER_WIDTH = 0
   )
   (
    // Users to add ports here

    // User ports ends
    // Do not modify the ports beyond this line

    // Ports of Axi Slave Bus Interface S00_AXI
    input wire                                s_axi_aclk,
    input wire                                s_axi_aresetn,
    input wire [C_s_axi_ID_WIDTH-1 : 0]       s_axi_awid,
    input wire [C_s_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,
...

これ、まだ良く分かっていないのだが、インタフェースの名前をs_axi_xxxとしているとBlockデザインをインテグレートするときにC_s_axi_ID_WIDTHと同様のフォーマットに合わせないとインテグレートに失敗する?

まず、IPをビルドするためのスクリプトを用意する。

# ip 

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

adi_ip_create blockram_test_v1_0
adi_ip_files blockram_test_v1_0 [list \
  "hdl/blockram_test_v1_0_S00_AXI.v" \
  "hdl/blockram_test_v1_0.v" \
                             ]

# adi_ip_properties blockram_test_v1_0

# adi_ip_properties_lite blockram_test_v1_0

ipx::package_project -root_dir . \
    -vendor analog.com \
    -library user \
    -taxonomy /Analog_Devices

set_property vendor_display_name {Analog Devices} [ipx::current_core]
set_property company_url {www.analog.com} [ipx::current_core]

set_property supported_families {\
                                     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 \
                                     virtexu       Production \
                                     kintexuplus   Production \
                                     zynquplus     Production \
                                     kintexu       Production \
                                     virtex7       Beta \
                                     qvirtex7      Beta \
                                     kintex7       Beta \
                                     kintex7l      Beta \
                                     qkintex7      Beta \
                                     qkintex7l     Beta \
                                     artix7        Beta \
                                     artix7l       Beta \
                                     aartix7       Beta \
                                     qartix7       Beta \
                                     zynq          Beta \
                                     qzynq         Beta \
                                     azynq         Beta \
                                     virtexu       Beta \
                                     virtexuplus   Beta \
                                     kintexuplus   Beta \
                                     zynquplus     Beta \
                                     kintexu       Beta}\
    [ipx::current_core]

ipx::remove_all_bus_interface [ipx::current_core]
set memory_maps [ipx::get_memory_maps * -of_objects [ipx::current_core]]
foreach map $memory_maps {
    ipx::remove_memory_map [lindex $map 2] [ipx::current_core ]
}

# end of adi_ip_properties_lite

ipx::infer_bus_interface {\
                              s_axi_awid \
                              s_axi_awaddr \
                              s_axi_awlen \
                              s_axi_awsize \
                              s_axi_awburst \
                              s_axi_awlock \
                              s_axi_awcache \
                              s_axi_awprot \
                              s_axi_awqos \
                              s_axi_awregion \
                              s_axi_awuser \
                              s_axi_awvalid \
                              s_axi_awready \
                              s_axi_wdata \
                              s_axi_wstrb \
                              s_axi_wlast \
                              s_axi_wuser \
                              s_axi_wvalid \
                              s_axi_wready \
                              s_axi_bid \
                              s_axi_bresp \
                              s_axi_buser \
                              s_axi_bvalid \
                              s_axi_bready \
                              s_axi_arid \
                              s_axi_araddr \
                              s_axi_arlen \
                              s_axi_arsize \
                              s_axi_arburst \
                              s_axi_arlock \
                              s_axi_arcache \
                              s_axi_arprot \
                              s_axi_arqos \
                              s_axi_arregion \
                              s_axi_aruser \
                              s_axi_arvalid \
                              s_axi_arready \
                              s_axi_rid \
                              s_axi_rdata \
                              s_axi_rresp \
                              s_axi_rlast \
                              s_axi_ruser \
                              s_axi_rvalid \
                              s_axi_rready} \
    xilinx.com:interface:aximm_rtl:1.0 [ipx::current_core]

ipx::infer_bus_interface s_axi_aclk xilinx.com:signal:clock_rtl:1.0 [ipx::current_core]
ipx::infer_bus_interface s_axi_aresetn xilinx.com:signal:reset_rtl:1.0 [ipx::current_core]
ipx::add_memory_map {s_axi} [ipx::current_core]
set_property slave_memory_map_ref {s_axi} [ipx::get_bus_interfaces s_axi -of_objects [ipx::current_core]]

# ipx::add_address_block {axi_lite} [ipx::get_memory_maps s_axi -of_objects [ipx::current_core]]
# set_property range {65536} [ipx::get_address_blocks axi_lite \
    #                                 -of_objects [ipx::get_memory_maps s_axi -of_objects [ipx::current_core]]]

ipx::add_address_block {axi} [ipx::get_memory_maps s_axi -of_objects [ipx::current_core]]
set_property range {65536} [ipx::get_address_blocks axi \
                                -of_objects [ipx::get_memory_maps s_axi -of_objects [ipx::current_core]]]
ipx::add_bus_parameter ASSOCIATED_BUSIF [ipx::get_bus_interfaces s_axi_aclk \
                                             -of_objects [ipx::current_core]]
set_property value s_axi [ipx::get_bus_parameters ASSOCIATED_BUSIF \
                              -of_objects [ipx::get_bus_interfaces s_axi_aclk \
                                               -of_objects [ipx::current_core]]]

# end of adi_ip_properties

adi_ip_constraints blockram_test_v1_0 [list \
  "blockram_test_constr.xdc" \
  "$ad_hdl_dir/library/common/ad_axi_ip_constr.xdc" ]

ipx::save_core [ipx::current_core]

IPのインテグレート

作成したIPをインテグレートするためのスクリプトを用意する。

# Add IPs
update_compile_order -fileset sources_1
open_bd_design {./adv7511_zed.srcs/sources_1/bd/system/system.bd}
update_ip_catalog -rebuild
startgroup
create_bd_cell -type ip -vlnv analog.com:user:blockram_test_v1_0:1.0 blockram_test_0
endgroup
apply_bd_automation -rule xilinx.com:bd_rule:axi4 \
    -config {Master "/sys_ps7/M_AXI_GP0" intc_ip "Auto" Clk_xbar "Auto" Clk_master "Auto" Clk_slave "Auto" }  \
    [get_bd_intf_pins blockram_test_0/S_AXI]
regenerate_bd_layout
reset_run synth_1
reset_run system_xbar_0_synth_1
launch_runs impl_1 -to_step write_bitstream -jobs 2
wait_on_run impl_1
save_bd_design

おそらく重要なのは

  • create_bd_cell : サブブロックをインスタンスする。
  • apply_bd_automation : ルーティングを実行する

である。これで自分の好きなIPをインテグレートする訳だ。

github.com

rm -rf *.cache *.data *.xpr *.log *.jou xgui *.runs *.srcs *.sdk *.hw *.sim .Xil *.ip_user_files
vivado -mode batch -source system_project.tcl >> adv7511_zed_vivado.log 2>&1

f:id:msyksphinz:20170723195744p:plain

VivadoでIPを生成する方法の調査(VivadoのIPインテグレーションの仕組み調査)

XilinxのIP生成およびそのインテグレーションの方法って、ネット上にもほとんど情報が出ていなくて、みんなどうやってやってるんだと不思議に思いながら調査しているのだけれども。

Block Designを使わない場合はみんなソースファイルを突っ込んで合成しているだけなのかもしれないが、そうでない場合はBlock Designに結合して、AXIバスか何かで接続できるIPを作らないと接続できない。 このためのフローがネット上に情報公開されて無さ過ぎる。

とりあえず下記の資料を読みながら進めていたのだけれども、

https://www.xilinx.com/support/documentation/sw_manuals_j/xilinx2012_2/ug895-vivado-system-level-design-entry.pdf

  • Vivado Design Suite Xilinx Core Instance files (XCI)

    • VivadoでIPを生成するとこのファイルが生成され、プロジェクトにIntegrateすることでIPを追加できるようになる。
  • CORE Generator コア (XCO)

    • Vivadoが提供している標準コアのファイル。CORE Generator で使用するとこのファイルが生成される。
  • サードパーティ IP

    • NGCファイルおよびEDIFファイルを経由して、VivadoプロジェクトにIPを挿入することが可能。

資料を読んでいると、xciかIP専用のファイルでないとVivadoにインテグレートできないのかな?と思っていたのだけれども、xprもインテグレート出来るような気がしている。 ADIのライブラリ生成用のスクリプトを読んでいると、いろいろラッパーで包んであるけれども、結局生成しているのはxprファイルだよね?

だいたいXilinx IP Integratorの資料も無さ過ぎる。ipx::save_coreの資料とか何処に置いてあるんだ? 仕方がないので、以下の資料などを参考にしながらIPを生成していた。

qiita.com

さらに、生成したIPをVivadoのデザインに組み込むためには、以下のようなスクリプトを組み込んで合成を実行した。

# Add IPs
update_compile_order -fileset sources_1
open_bd_design {./adv7511_zed.srcs/sources_1/bd/system/system.bd}
update_ip_catalog -rebuild
startgroup
create_bd_cell -type ip -vlnv analog.com:user:blockram_test_v1_0:1.0 blockram_test_0
endgroup
apply_bd_automation -rule xilinx.com:bd_rule:axi4 \
    -config {Master "/sys_ps7/M_AXI_GP0" intc_ip "Auto" Clk_xbar "Auto" Clk_master "Auto" Clk_slave "Auto" }  \
    [get_bd_intf_pins blockram_test_0/S_AXI]
regenerate_bd_layout
reset_run synth_1
reset_run system_xbar_0_synth_1
launch_runs impl_1 -to_step write_bitstream -jobs 2
wait_on_run impl_1
save_bd_design

合成結果を確認してみると、一応blockram_test_v1_0デザインはインスタンスされているが、ポートが繋がっていない。こりゃ、AXI-Liteと勘違いされているかもしれない。

f:id:msyksphinz:20170723164014p:plain

f:id:msyksphinz:20170723164233p:plain

ええええ。

(大昔の)ThinkPad にRISC-V実験環境を構築したが、HiFive1の調子がおかしい(続き)

HiFive1の試行を引き続き行っているが、たぶんこれ誰も大規模なプログラム流したことないのかな、というのが分かってきた(気がする)。

一枚目のボードを壊してしまったぽいのだが、2枚目のボードもちょっと大きめに配列を取ってコンパイル後、流したら不正終了。そして次回以降バイナリの焼き込みを受け付けなくなってしまった。やばい!

書き込もうとしていたのは以下のバイナリ。注意!これ書き込むとHiFive1フリーズして動かなくなります!

github.com

だいぶプログラムを削りまくって、以下くらいにしてみた。L1キャッシュに入らない程度のプログラムだと、スタックを使いつぶした挙句、変なところに書き込むっぽい?

#define INPUTNO  (28*28)    // No of input cell
#define OUTPUTNO (10)
#define HIDDENNO (50)    // No of hidden cell
#define ALPHA    (10)   // Coefficient of learning
#define SEED     (65535)  // Seed of random
// #define MAXINPUTNO (60000)  // Max number of learning data
#define MAXINPUTNO (100)  // Max number of learning data
#define BATCH_SIZE (100)
#define LEARNING_RATE (0.1)
#define WEIGHT_INIT (0.01)

int main ()
{
  fix16_t wh0[INPUTNO * HIDDENNO];
  fix16_t wb0[HIDDENNO];

  fix16_t wh1[HIDDENNO * OUTPUTNO];
  fix16_t wb1[OUTPUTNO];
...

試行錯誤するうちに、どうやらリセットボタンを何度も押していると復旧するタイミングがある様子。 そのタイミングで別のシンプルなプログラム(helloとかled_fadeとか)を書き込むと復旧する。

これ、マイコンボードとしてはだいぶ危ういな。。。気を付けて使わないと。。。

f:id:msyksphinz:20170721230657j:plain

(大昔の)ThinkPad にRISC-V実験環境を構築したが、HiFive1の調子がおかしい

前の記事の続き。無事にThinkPad に HiFive1の環境を構築したのだが、やはりSPI経由でプログラムを書き込もうとすると書き込めない。

いろいろSiFiveのフォーラムを見ながら試行錯誤しているのだが、どうもまだ解決策が見つからない。これは最悪もう一枚HiFive1ボードを買うことになるかもしれないなあ。。。

HiFive1には、コマンドライン環境から制御する方法 (freedom-e-sdkを利用する)と、ArduinoIDEを利用する方法があるのだが、どちらもうまく書き込むことができない。

一応ツールチェインのリコンパイルからやり直しているが、どうも上手く行く気配が見られないなあ。。。もう思い切って買い替えないとダメかな。

f:id:msyksphinz:20170720012518p:plain

追記。本日幸運にもHiFive1をもう一枚貸して頂く機会をもらい、早速家に帰って書き込みを実行してみると無事に書き込めました。

どうやら本当にFlashの変なところに書いてしまったっぽい。これはHiFive1のバグかなあ。バグと言っても二度と再現させたくないけど。

f:id:msyksphinz:20170721230657j:plain

(大昔の)ThinkPad にRISC-V実験環境を構築する

HiFive1のボードを実験するのに、これまではWindows上のVirtualBoxUbuntuをインストールし、その上でデバイスと接続していたのだが、時々調子が悪くなる。

解析するのも面倒なので、大昔のノートPC(ThinkPad X301)を取り出してUbuntuをインストールし、HiFive1用の開発環境を構築している。

Windows10のUbuntu Packageも選択肢としては考えれるが、いきなり不思議環境にインストールして戸惑うよりもまずは確実なところでやっていきたい。

というわけでインストール中。古いPCだから遅いね!

とりあえずHiFive1接続して格好良くしているけど、まだ接続してないし何もできていない。

あと、机の上が汚い。

f:id:msyksphinz:20170720013349j:plain

f:id:msyksphinz:20170720012518p:plain