読者です 読者をやめる 読者になる 読者になる

FPGA開発日記

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

「Zedroid - Android (5.0 and later) on Zedboard」をやってみる(9. uramdisk.image.gzの展開)

前回は、u-bootが立ち上がったもののinitを起動させることができず、どうしたらよいのか分からないところで終わった。

そこまで日記に書いたところ、uramdisk.image.gzを事前に展開しておく必要があるということを @ksmakoto さんに教わった。 確かにその通りで、u-bootはinitがどこにあるのか(実際にはuramdisk.image.gzに格納されている)がどこにあるのかも知らないし、それをメモリに展開したところで場所を教えないとどうしようもない。 どうしたらよいのだろうと調査した結果、Xilinxの以下のページを発見し、試行してみた。

Xilinx Wiki - U-boot

なるほど、以下のようにしてイメージをメモリに展開するのか。さらに展開した場所をカーネルに教えてやり、起動する。

u-boot> fatload mmc 0 0x3000000 uImage
u-boot> fatload mmc 0 0x2A00000 devicetree.dtb
u-boot> fatload mmc 0 0x2000000 uramdisk.image.gz
u-boot> bootm 0x3000000 0x2000000 0x2A00000

同じように実行すると、起動し始めた。よしよし。

brd: module loaded
loop: module loaded
libphy: XEMACPS mii bus: probed
[Firmware Warn]: /amba@0/eth@e000b000/phy@0: Whitelisted compatible string. Please remove
xemacps e000b000.eth: pdev->id -1, baseaddr 0xe000b000, irq 33
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
usbcore: registered new interface driver usb-storage
usbcore: registered new interface driver usbserial
usbcore: registered new interface driver usbserial_generic
usbserial: USB Serial support registered for generic
usbcore: registered new interface driver ftdi_sio
usbserial: USB Serial support registered for FTDI USB Serial Device
mousedev: PS/2 mouse device common for all mice
i2c /dev entries driver
xiic-i2c 41600000.i2c: input clock not found.
xiic-i2c: probe of 41600000.i2c failed with error -2
Xilinx Zynq CpuIdle Driver started
sdhci: Secure Digital Host Controller Interface driver
sdhci: Copyright(c) Pierre Ossman
sdhci-pltfm: SDHCI platform and OF driver helper
mmc0: SDHCI controller on e0100000.sdhci [e0100000.sdhci] using ADMA
ledtrig-cpu: registered to indicate activity on CPUs
hidraw: raw HID events driver (C) Jiri Kosina
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
adv7511-hdmi-snd fpga-axi@0:adv7511_hdmi_snd: ASoC: CODEC DAI adv7511 not registered
mmc0: new high speed SDHC card at address 1234
zed-adau1761-snd fpga-axi@0:zed_sound: ASoC: CODEC DAI adau-hifi not registered
mmcblk0: mmc0:1234 SA08G 7.25 GiB
 mmcblk0: p1 p2 p3 p4
NET: Registered protocol family 17
zynq_pm_ioremap: no compatible node found for 'xlnx,zynq-ddrc-a05'
zynq_pm_late_init: Unable to map DDRC IO memory.
Registering SWP/SWPB emulation handler
of_graph_get_next_endpoint(): no port node found in /fpga-axi@0/axi_hdmi@70e00000
adv7511-hdmi-snd fpga-axi@0:adv7511_hdmi_snd: ASoC: CODEC DAI adv7511 not registered
zed-adau1761-snd fpga-axi@0:zed_sound: ASoC: CODEC DAI adau-hifi not registered
hctosys: unable to open rtc device (rtc0)
xemacps e000b000.eth: Set clk to 25000000 Hz
xemacps e000b000.eth: link up (100/FULL)
Sending DHCP requests ., OK
IP-Config: Got DHCP answer from 192.168.0.1, my address is 192.168.0.7
IP-Config: Complete:
     device=eth0, hwaddr=00:0a:35:00:01:22, ipaddr=192.168.0.7, mask=255.255.255.0, gw=192.168.0.1
     host=192.168.0.7, domain=airport, nis-domain=(none)
     bootserver=0.0.0.0, rootserver=0.0.0.0, rootpath=     nameserver0=192.168.0.1
ALSA device list:
  No soundcards found.
Freeing unused kernel memory: 248K (c0698000 - c06d6000)
This architecture does not have kernel memory protection.
init: cannot find '/system/bin/debuggerd64', disabling 'debuggerd64'ev/block/mmcblk0p3,target=/data,type=ext4)=0
init: cannot find '/system/bin/install-recovery.sh', disabling 'flash_recovery'
Unable to find swap-space signature
shell@zedboard:/

しかししばらく待っていると、以下のエラーメッセージを吐いてリブートしてしまった。えー、何だこりゃ。

$ init: critical process 'healthd' exited 4 times in 4 minutes; rebooting into recovery mode
reboot: Restarting system with command 'recovery'

調査していると、以下のブログを発見した。

henryomd.blogspot.jp

うーん、nfsが関係しているのか?以下を追加してみよう。

setenv bootargs 'earlyprintk maxcpus=1 console=ttyPS0,115200 ip=dhcp root=/dev/nfs nfsroot=192.168.1.2:/export/root/zedroid,nfsvers=3 rw init=/init'

saveenv

今度は、以下のエラーを出して同様にリブートがかかってしまった。

init: critical process 'servicemanager' exited 4 times in 4 minutes; rebooting into recovery mode
eboot: Restarting system with command 'recovery'

うーん、まだ調整が必要だなあ。

f:id:msyksphinz:20170513025151p:plain

関連記事

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

「Zedroid - Android (5.0 and later) on Zedboard」をやってみる(8. Kernel Panic)

前回からいろいろブートファイルを作り直して、どうにかu-bootが立ち上がるようになった。

そして zedroid_device_xilinx_zedboard-kernel を少し変更する必要があったが、U-bootでの動作は始まったようだ。

  • zynq-zed-adv7511.dtsi
diff --git a/arch/arm/boot/dts/zynq-zed-adv7511.dtsi b/arch/arm/boot/dts/zynq-zed-adv7511.dtsi
index 1209b8c..4afed32 100644
--- a/arch/arm/boot/dts/zynq-zed-adv7511.dtsi
+++ b/arch/arm/boot/dts/zynq-zed-adv7511.dtsi
@@ -106,6 +106,10 @@
                        audio-codec = <&adau1761>;
                        cpu-dai = <&axi_i2s_0>;
                };
+               efuse@f800d000 {
+            compatible = "xlnx,zynq-efuse";
+                   reg = <0xf800d000 0x20>;
+               };
        };

        leds {

しかしAndroid(というかLinux)が起動するまでに以下のようなエラーメッセージを吐いてカーネルパニックになっている。

通常通りにブートしても、Linuxを起動するときの最初のプロセスにあたるinitが存在せず、カーネルパニックになってしまっていると思われる。

initは、/dev/sdb1 (SDカードのパーティション0)に格納したuramdisk.image.gzに入っているはずだ。これはLinux起動時に展開されるはずなので、 以下のようにしてU-bootのコマンドラインで指定すればよいと思う。

setenv bootargs console=ttyPS0,115200 root=/dev/ram rw earlyprintk init=/init
boot   # 起動

しかし今度は以下のエラーメッセージで止まってしまう。良く分からないなあ。。。

No filesystem could mount root, tried:  ext3 ext2 ext4 vfat msdos
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0)
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.6.0 #1

うーん、これは何だろう?

f:id:msyksphinz:20170512000615p:plain

SiFiveの64bit RISC-VコアE51をArty FPGAで動作させる

SiFiveはフリーのRISC-Vコアデザインとして、32bitのE31、64bitのE51を提供している。

www.sifive.com

f:id:msyksphinz:20170510223409p:plain

これらのソースコードはリクエストしないとダウンロードすることは出来ないが、mcsファイルが配布されているためこれを使って手っ取り早くFPGAで動作させてみることができる。

mcsファイルのダウンロードは無料なので、さっそくダウンロードして実行させてみよう。

FPGA Bitstreamを入手する

E31およびE51のFPGAビットストリームは、以下で入手可能だ。ターゲットハードウェアとして、XilinxのArty FPGA Boardのものが用意されている。

https://dev.sifive.com/static/core/images/dev-boards/arty-artix-7.cf703ff39240.jpg

SiFiveのウェブサイトからダウンロード可能だ。

dev.sifive.com

f:id:msyksphinz:20170511010949p:plain

ダウンロードしたら、SiFive_E51_Coreplex_FPGA_Evaluation_v1p0_r0.tar.gzを展開する。SiFive_E51_Coreplex_FPGA_Evaluation_v1p0_r0.mcsがあるので、これを書き込む訳だ。

ダウンロードおよび動作確認にはUbuntuを利用するので、Vivado経由で書き込むときはドライバのインストールを忘れないこと。以下を参考にした。

github.com

 cd /opt/Xilinx/Vivado/2015.1/data/xicom/cable_drivers/lin64/install_script/install_drivers  
 sudo ./install_digilent.sh  
 cd /opt/Xilinx/Vivado/2015.1/data/xicom/cable_drivers/lin64/install_script/install_drivers  
 sudo ./install_drivers

また、コンフィグ格納用のSPIメモリの指定は、自分の過去の記事を参考にした。

msyksphinz.hatenablog.com

これでシリアルポートを開いて、115200bpsに指定して受信していると、メッセージが表示される。

f:id:msyksphinz:20170510233518p:plain

一応ここまで。デバッグケーブルを持っていないのでここから先は進めないが、RISC-Vボードを活用するためにデバッグケーブルを購入するか否か。。。 5000円程度だから思い切って買ってしまえばよいのだけれど。

参考。E51(64bit版RISC-V)のベンチマークプログラムのコンパイル

E51用のサンプルプログラムやベンチマークプログラムは、以前紹介したfreedom-e-sdkリポジトリから入手可能だ。

github.com

詳細は省略するが、まずはツールのビルド(別リポジトリにツールがビルドされるので本当は嫌なのだが、オリジナルのriscv64-unknown-elf-gccを使うとリンクでエラーが出たのでとりあえず回避…)

sudo aptitude install libtcl8.5 # openocdのビルドに必要
make tools BOARD=coreplexip-e51-arty -j4

Coremarkのコンパイルは以下で可能だ。

make software PROGRAM=coremark BOARD=coreplexip-e51-arty

SiFiveの新RISC-VコアIP(E51, E31 Coreplex IP)

RISC-V 6th Workshop にて、SiFiveが新RISC-VコアIPであるE51を発表した。これまで発表されていたE31 Coreplex-IPは32ビット版だが、E51は64bitだ。

www.eetimes.com

SiFiveはそれ以外にも、E51の有償サポートを発表している。足回りのIPにより値段が若干変わるが、有償サポートは1年のライセンスで$600となっている。

dev.sifive.com

E31とE51はほとんど構成が変わらず、コアの内容だけが32bitから64bitとなっている。どちらもLinuxをサポートしていないが、Exxシリーズではなく、UxxシリーズではすでにLinuxをサポートしている。

f:id:msyksphinz:20170510223409p:plain

また、E31もE51も、リクエストすればRTLをダウンロードできるようになっている。

dev.sifive.com

今回発表されたE51、また既存のE31の特徴をまとめると、

  • RISC-V ISA準拠
    • E31 : RV32IMACサポート
    • E51 : RV64IMACサポート
  • マイクロアーキテクチャ
    • 整数乗算、除算ハードウェアをサポート
    • アトミック演算をサポート
    • Complexモードをサポート
    • マシンモード、ユーザモードを持つ
    • インオーダ 5-6ステージパイプライン
  • メモリ
    • 16kB, 2-way 命令キャッシュ
    • 最大64kBのデータキャッシュ
  • 割り込み
    • ローカル割り込み
    • プラットフォームレベル割り込み
    • Coreplexローカル割り込み
  • 8領域のメモリプロテクション
  • 性能
    • E31 : 1.61 DMIPS/MHz, 2.73 Coremark/MHz
    • E51 : 1.80 DMIPS/Mhz, 2.76 Coremark/MHz

コンパイルオプションを変えてCoremarkベンチマークを改善する

自作RISC-Vプロセッサは16バイト単位で命令をフェッチしてくる。つまり分岐などで新しい場所に命令フェッチを発生した時も、16バイトアラインで命令をフェッチする。

このとき、分岐先や関数の先頭が16バイトに乗っていると効率的だ。16バイトアラインの乗っていないとその分命令フェッチラインを損していることになる。

このとき、分岐先の命令のバイトアラインを調整するために、RISC-VのGCCには以下のコンパイルオプションが乗っている。

-falign-functions=16 -falign-jumps=16 -falign-labels=16 -falign-loops=16

これらにより、ジャンプ先の命令が16バイトアラインに制限される。

例えば、分岐先を調整するために以下のようにわざとnopが挿入される。

80001050:       0088de93                srli    t4,a7,0x8
80001054:       01de6f33                or      t5,t3,t4
80001058:       01e59023                sh      t5,0(a1)
8000105c:       00259583                lh      a1,2(a1)
80001060:       40b50533                sub     a0,a0,a1
80001064:       00008067                ret
80001068:       00000013                nop   // この2つのnopにより、次の関数の場所が調整される。
8000106c:       00000013                nop   // この2つのnopにより、次の関数の場所が調整される。

80001070 <core_list_mergesort.constprop.2>:
80001070:       00100f93                li      t6,1
80001074:       000f8393                mv      t2,t6
80001078:       26050c63                beqz    a0,800012f0 <core_list_mergesort.constprop.2+0x280>
8000107c:       00000013                nop
80001080:       00000f13                li      t5,0
80001084:       00000693                li      a3,0
80001088:       00000293                li      t0,0
8000108c:       00000013                nop
80001090:       00052783                lw      a5,0(a0)

この調整を行って、昨日と同様にCoremarkの性能を測定した。

Inst Bufferサイズ サイクル数 比率 サイクル数 比率
通常Coremark アライン調整Coremark
2 406395 1.00 360167 0.89
4 371580 0.91 340276 0.84
8 403437 0.99 366379 0.90
16 476439 1.17 429816 1.06

やはり、命令バッファが4の場合に最大の効果が得られた。命令の位置を調整しただけで、かなりの効果だ。

f:id:msyksphinz:20170509232542p:plain

命令バッファのサイズによる性能変化の調査

自作RISC-VプロセッサでCoremarkベンチマークを計測しているが、命令フェッチをどれだけ投機的に実行するかによって性能がずいぶん変わってきた。

投機フェッチは、命令バッファが空いている限り実行しているが、あまりフェッチを出しすぎると、パイプラインフラッシュによるフェッチ破棄を行った場合のペナルティが大きくなる。

命令キャッシュミスが発生しており外部に命令フェッチを出している場合、その命令フェッチを破棄することはできないので、フェッチが戻ってくるまで待機することになる。このペナルティが、以外と影響してくる。

f:id:msyksphinz:20170509221651p:plain

そこで、命令バッファのサイズを変えて、どの大きさにするのが一番性能が出るのかを調査した。

Inst Bufferサイズ サイクル数 比率
2 406395 1.00
4 371580 0.91
8 403437 0.99
16 476439 1.17

やはりバッファのサイズを大きくすればよいわけではないらしい。かと言って、小さすぎると今度は投機フェッチが出せなさ過ぎている。

今回の実装は、命令バッファのサイズを4にしておくのがよさそうだ。今回の実装では1リクエストで128ビットをフェッチしてくるので、最大で128x4=512bit=16命令文を保持できる計算となる。

自作RISC-VプロセッサにRASを実装する

自作RISC-VプロセッサにRAS(Return Address Stack)を実装して性能を調査した。

RASの実装をここしばらくやっていたのだが、意外と難しいということが分かった。

Return命令の判定をどこで行うか

RAS以外の分岐予測、アドレスを使って分岐予測を行う方式の分岐予測は、フェッチアドレスを見て予測し、次のフェッチアドレスを決める。 この方式の場合はIFU(命令フェッチユニット)から出力されるアドレスを見ればよいのだが、RASの場合はReturn命令を検出しなければならないので、 フェッチ後のデータを見て予測しなければならない。したがって、予測がアドレスを基にする予測よりも少し遅れることになった。

f:id:msyksphinz:20170509003802p:plain

よって、アドレスを使う分岐予測BHTなどと比較して少しペナルティが発生することになった。これについては、まあそんなものだということで割り切らなければならない。

Return予測の失敗条件

RAS予測の失敗条件というのはいろいろあって、思いついたのは、

  • Return Registerが書き換えられていて、予測したは良いが実際のアドレスが異なっていた。
  • ジャンプの深さが深すぎて、昔のジャンプ記録が破棄されてしまった(今回の実装では最大深さ4のJump And Link命令しかサポートしていない)。

などがありうる。したがって、RASは無条件分岐命令だけれども、本当に正しいアドレスに分岐予測できたのか判定する必要がある。

比較命令などで実施する分岐命令は、現在のプログラムカウンタの場所からの相対位置でジャンプ先が決まるので、分岐する場合のアドレスは必ず決まっている。 しかしレジスタ相対ジャンプの場合は、「分岐するorしない」以外にも「その分岐アドレスは本当に正しいか」を判定しなければならないという問題がある。

これらをチェックし、もし分岐予測したジャンプアドレスが、実際の戻りアドレスと異なっている場合にもパイプラインフラッシュを発生される機構を導入した。

性能測定

RASの実装有り無しで、性能を比較した。使用したのはCoremarkだ。

サイクル数 比率
RAS無し 393771 1.00
RAS有り 371580 0.94

約5%の性能向上となった。と言っても5%かあ。。。もっと向上するかと思ってたのになあ。。

もう一つ、IPC推移を取ってみた。X軸が命令数、Y軸は1000命令単位でのIPCをプロットしている。

f:id:msyksphinz:20170509010525p:plain

全体的に少しだけ向上しているが、そこまで目立ったものじゃないなあ。実装がまずいのかもしれない。