FPGA開発日記

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

RISC-VのFreeBSD実装をZedBoardで動作させたい(トラブルあり未解決)

http://riscv.wpengine.com/wp-content/uploads/2015/01/riscv-logo.png https://www.freebsd.org/logo/logo-full-thumb.png

(画像はriscv.org, freebsd.orgより拝借)

FreeBSDは現在RISC-Vに移植されており、RISC-Vで動作させることが出来るらしい。

いろいろチュートリアルはあるのだが、まだちゃんと動作させたことが無い。

riscv - FreeBSD Wiki

BBLというものをビルドしなければならないのだが、これが上手く行っていないのか... FreeBSDの仕組みをちゃんと理解していないのだが、上記サイトの--with_payloadに何を指定すれば良いのか分からずに、詰んでいる。

../configure --prefix=$PREFIX --host=riscv64-unknown-freebsd11.0 --with-payload=path_to_freebsd_kernel

path_to_freebsd_kernelのところに、/home/vagrant/riscv-world/もしくは、/home/vagrant/freebsd-riscv/riscv.imgを指定してbblをビルドしてみたのだが、上手く行かない。

ちなみに、FreeBSD環境で構築したBBLは、RISC-V用ビルドで作成したSDカードに同様にコピーすれば使用できる。

Create sdcard using 'Quick instructions' on https://github.com/ucb-bar/fpga-zynq, then copy bbl to sdcard (to the first msdos partition). Once you have booted linux from sdcard on Zedboard, then you can run FreeBSD/RISC-V:

そしてZedBoardに挿入して立ち上げようとしたのだが、まだ上手く行っていない。

./fesvr-zynq /mnt/boot/bbl
root@zynq:~# ./fesvr-zynq /mnt/boot/bbl
../bbl/kernel_elf.c:53: failed to load payload

f:id:msyksphinz:20161124012152p:plain

これは改善中。。。

RISC-Vの実装をZedBoardで手っ取り早く試すためのチュートリアル

自分でも良く分からなくなるのでまとめておく。RISC-Vを手っ取り早くFPGAボードで動作させたいときのために、githubからいろんなビルド済みの何かをダウンロードして動作させる方法をまとめておく。

用意するもの

FPGAボード (ZedBoard, Zybo, zc706)

私はZedBoardしか持っていないのでそれで試す。

www.avnet.co.jp

SDカード

4GBもあれば十分。

ZedBoard向けの環境を作る手順

1. RISC-Vビルド用のLinux(ゲストOS)をVirtualBox上で構築する

Vagrant上でUbuntu Linuxを構築しても良いのだけど、SDカードを認識させるのに随分苦労しているので、普通にVirtualBox上でUbuntu 16.10の環境を構築する。

ただし、僕はGUI環境が大嫌いなので、sshでmsys2からログインできるようにしておく。

Ubuntu 16.10 (Yakkety Yak)

SDカードが認識できることを確認しておくこと。

f:id:msyksphinz:20161124003045p:plain

また、ポーテフォワーディングにより、sshでmsys2からログインできるようにしておくと作業が楽だ。

f:id:msyksphinz:20161124003159p:plain

fpga-zynqというリポジトリが、githubで公開されているのでそれをcloneする。

git clone https://github.com/ucb-bar/fpga-zynq.git
git submodule status
cd zedboard/fpga-images-zedboard
git submodule update .

2. ビルド済みバイナリをダウンロードする

一からビルドするのは面倒なので、ビルドしたものをダウンロードしてくる。

cd fpga-zynq/zedboard
make fetch-images
make fetch-riscv-linux

3. SDカードを準備しておく

lsblkで、SDカードが認識されていることを確認しておく。下記では、/dev/sdbに認識されていることが分かる。

lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda      8:0    0   50G  0 disk
├─sda1   8:1    0   46G  0 part /
├─sda2   8:2    0    1K  0 part
└─sda5   8:5    0    4G  0 part [SWAP]
sdb      8:16   1  3.7G  0 disk
sr0     11:0    1 1024M  0 rom

SDカードのフォーマットとマウントをして、書き込みの準備を整えよう。fdiskを使ってSDカードのパーディションを割り当てる。特に何か設定をする必要は無い。

$ sudo fdisk /dev/sdb

Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


コマンド (m でヘルプ): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p):

Using default response p.
パーティション番号 (1-4, default 1):
First sector (2048-7626751, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-7626751, default 7626751):

Created a new partition 1 of type 'Linux' and of size 3.7 GiB.

コマンド (m でヘルプ): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

lsblkをすると、sdb1が追加されていることが確認できる。

lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda      8:0    0   50G  0 disk
├─sda1   8:1    0   46G  0 part /
├─sda2   8:2    0    1K  0 part
└─sda5   8:5    0    4G  0 part [SWAP]
sdb      8:16   1  3.7G  0 disk
└─sdb1   8:17   1  3.7G  0 part
sr0     11:0    1 1024M  0 rom

SDカードをMSDOSでフォーマットし、必要なファイルを転送する。これはmakeで一発で出来る。

$ sudo mkfs.msdos -n LABEL1 /dev/sdb1
$ sudo mount /dev/sdb1 /media/masayuki/SDCARD
$ sudo make load-sd SD=/media/masayuki/SDCARD
/home/masayuki/fpga-zynq/common/load_card.sh /media/masayuki/SDCARD
+ cp fpga-images-zedboard/boot.bin /media/masayuki/SDCARD
+ cp fpga-images-zedboard/devicetree.dtb /media/masayuki/SDCARD
+ cp fpga-images-zedboard/uImage /media/masayuki/SDCARD
+ cp fpga-images-zedboard/uramdisk.image.gz /media/masayuki/SDCARD
+ '[' -a fpga-images-zedboard/riscv/vmlinux ']'
+ mkdir -p /media/masayuki/SDCARD/riscv
+ cp fpga-images-zedboard/riscv/vmlinux /media/masayuki/SDCARD/riscv/
+ cp fpga-images-zedboard/riscv/root.bin /media/masayuki/SDCARD/riscv/
$ sudo umount /media/masayuki/SDCARD

4. ZedBoardでLinuxを起動する

SDカードを取り出し、ZedBoardに挿入して、SDカードからブートするモードに切り替えて起動する。

TeraTermから起動する様子を観察する。ビットレートは115200に設定しておく。

f:id:msyksphinz:20161124005032p:plain

放っておくとLinuxが起動する。ユーザ名root, パスワードrootでログインできる。

5. fesvr-pkのテスト

まずは、fesvr-pkという、RISC-Vを制御するためのフロントエンドのテストだ。

root@zynq:~# ./fesvr-zynq pk hello
hello!

hello!と表示されたOKだ。

5. ZedBoardでRISC-V Linuxを起動する。

まずは、SDカードのファイルシステムをマウントする。

root@zynq:~# mkdir /sdcard
root@zynq:~# mount /dev/mmcblk0p1 /sdcard

フロントエンドから、RISC-V Linuxを起動する。

root@zynq:~# ./fesvr-zynq +disk=/sdcard/riscv/root.bin bbl /sdcard/riscv/vmlinux

起動した!

f:id:msyksphinz:20161124005526p:plain

unameをして、確認する。

[    0.120000] Freeing unused kernel memory: 568K (ffffffff80000000 - ffffffff8008e000)
[    0.120000] This architecture does not have kernel memory protection.
/ #
/ # uname -a
Linux ucbvax 4.6.2-g8205b66 #3 Tue Sep 20 17:52:08 PDT 2016 riscv GNU/Linux
/ #

riscv GNU/Linuxと表示されている。OKだ。

ただし、やはりPL環境で100MHz?程度で動作しているので、動作はかなりもっさりだ。

自作プロセッサの性能解析とその対策(3. Loadデータのレイテンシを1つ削減)

自作RISC-Vプロセッサの性能向上対策その3。

ロード命令のレイテンシは、プロセッサの性能に重大な影響を与えることは既知の通りだ。

プロセッサのLoad-Useの性能を向上させるために、ロード命令のレイテンシを1つ短縮しよう。 もともとこれはロード処理の直後にFFが入っており、さらにWriteBackステージでFFが入っており無駄だったので、これを削除して短縮するという訳だ。

f:id:msyksphinz:20161123155412p:plain:w400

ここで、LSUのFFは、直後にWBUでFFで再度受けるので不要。削除してレイテンシを1つ削減させる。

f:id:msyksphinz:20161123155503p:plain:w400

上記のように、FFを削除してシミュレーションを実行する。

この2つの性能を比較した。

Cycle Rate
Load Latency +1 52915 100%
Load Latency +0 49889 94.2%

IPCの経過グラフは以下のようになった。

f:id:msyksphinz:20161123155916p:plain:w999

青のグラフが改善前のIPC経過、赤のグラフが改善後のIPC経過。若干グラフの平均値が大きくなっている。

参考情報 : Superscalar Microprocessor Designによる解説

マイクロプロセッサの性能比較といえば、Mike Johnsonによる"Superscalar Microprocessor Design"が有名だ。

Superscalar Microprocessors Design (Prentice Hall Series in Innovative Technology)

Superscalar Microprocessors Design (Prentice Hall Series in Innovative Technology)

こちらの解説では、ストアフォワーディングによる解説しか載っていなかったが、これらの性能向上対策でも、大きくて4%程度の性能向上であった。

自作プロセッサの性能解析とその対策(2. 分岐命令用エントリ数の増強)

自作RISC-Vプロセッサの性能解析をしているのだが、パイプライントレースを解析していてまず気になったのは、分岐予測の結果が悪いことだ。

分岐予測では、即値による分岐、PC相対分岐をターゲットにしており、単純な分岐ではあるがそれなりにヒットするはずだった。 調査してみると、分岐予測バッファのエントリ数が極端に少ないため、分岐予測バッファが書き換えられ、分岐予測が行なわれていないことが分かった。

具体的には、現在は16x4エントリ分の分岐予測しか持っていない。さらに、4エントリを1ペアにして、4エントリ中は同一PCでしか予測できない構造になっているので、最悪の場合16エントリ分の予測しか持っていない。これは少ない!

まずは実装コストを度外視して、エントリ数を増やすことにより効果があるかどうかを確認する。

まずは16エントリの分岐予測バッファを、思い切って128エントリまで増やす。現在は実装の形式があまり合成に優しくない形式になっているので直す必要があるが、とりあえずシミュレーションで動けば良いので良しとする。

この結果、ある程度IPCの向上が見られた。つまり、分岐予測バッファのエントリ数はこれまで足りていなかったということだ。

前回までのグラフと重ねてみる。まだデバッグが完了していないので、途中でシミュレーションが落ちてしまっているが、灰色の「BRU Entry-4 & Pred-Buffer 128が比較的数値が高く、また全体のシミュレーション時間も若干前倒しになっているのが分かると思う。

ただし、これだけではまったく十分ではない。全体的に解析していて気になるのはやはりLoad-Useの遅さだ。この部分でストールが大量に発生してしまい、その結果全体のサイクル数が増大している。 1次キャッシュで、パイプラインをある程度埋めることは出来ているが、やはり問題になるのはロード命令から次の命令へのレイテンシだ。この辺りはどのようにして改善していこうかなあ。。。

f:id:msyksphinz:20161122023015p:plain

2016/11/23 追記: いくつかバグを修正して最後までCoremarkを流れるようにした。Google Spreadsheetによりグラフをプロットしてみた。

  • 分岐命令用命令RSエントリ=1, 分岐予測エントリ=16
  • 分岐命令用命令RSエントリ=2, 分岐予測エントリ=16
  • 分岐命令用命令RSエントリ=4, 分岐予測エントリ=128

分岐予測を追加したことにより、黄色のラインが若干上に上がっている。

f:id:msyksphinz:20161123022551p:plain:w1200

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

自作プロセッサの性能解析とその対策(1.ReservationStationエントリ数と性能の関係)

自作プロセッサにおいて、性能面でどうしても納得出来ないところがあり、調査していた。

(Cm13,53)[PC=000017a8] R15<=00008184 : LW        r15,0x004,r11       (46)    909
(Cm14,--)[PC=000017ac]               : SH        r13,0x002,r15               910
(Cm18,31)[PC=000017bc] R14<=00000003 : ANDI      r14,r16,0x007       (34)    914
                                                                                
                                                                                
                                                                                
                                                                                
(Cm19,42)[PC=000017c0] R17<=000080f0 : LW        r17,0x000,r11       (62)    915
(Cm23,37)[PC=000017d0] R15<=00000302 : AND       r15,r15,r28         (61)    919
(Cm24,--)[PC=000017d4]               : BEQ       r17,r 0,0x00                920
                                                                                
(Cm25,--)[PC=000017d8]               : BLTU      r13,r 6,0x7e                921
                                                                                
                                                                                
                                                                                
(Cm26,49)[PC=000017a8] R15<=00008180 : LW        r15,0x004,r11       (37)    922
(Cm27,--)[PC=000017ac]               : SH        r13,0x002,r15               923
(Cm31,52)[PC=000017bc] R14<=00000004 : ANDI      r14,r16,0x007       (35)    927
                                                                                
                                                                                
                                                                                
                                                                                
(Cm32, 3)[PC=000017c0] R17<=000080e8 : LW        r17,0x000,r11       (42)    928
(Cm36, 9)[PC=000017d0] R15<=00000403 : AND       r15,r15,r28         (13)    932
(Cm37,--)[PC=000017d4]               : BEQ       r17,r 0,0x00                933
                                                                                
(Cm38,--)[PC=000017d8]               : BLTU      r13,r 6,0x7e                934
                                                                                
                                                                                
                                                                                
(Cm39,48)[PC=000017a8] R15<=0000817c : LW        r15,0x004,r11       ( 9)    935
(Cm40,--)[PC=000017ac]               : SH        r13,0x002,r15               936
(Cm44,11)[PC=000017bc] R14<=00000005 : ANDI      r14,r16,0x007       (60)    940
                                                                                
                                                                                
                                                                                
                                                                                
(Cm45,16)[PC=000017c0] R17<=000080e0 : LW        r17,0x000,r11       ( 3)    941
(Cm49,56)[PC=000017d0] R15<=00000504 : AND       r15,r15,r28         (45)    945
(Cm50,--)[PC=000017d4]               : BEQ       r17,r 0,0x00                946
                                                                                
(Cm51,--)[PC=000017d8]               : BLTU      r13,r 6,0x7e                947
                                                                                
                                                                                
                                                                                
(Cm52,51)[PC=000017a8] R15<=00008178 : LW        r15,0x004,r11       (56)    948
(Cm53,--)[PC=000017ac]               : SH        r13,0x002,r15               949
(Cm57,58)[PC=000017bc] R14<=00000006 : ANDI      r14,r16,0x007       ( 8)    953
                                                                                
                                                                                
                                                                                
                                                                                
(Cm58, 7)[PC=000017c0] R17<=000080d8 : LW        r17,0x000,r11       (16)    954
(Cm62,31)[PC=000017d0] R15<=00000605 : AND       r15,r15,r28         (53)    958
(Cm63,--)[PC=000017d4]               : BEQ       r17,r 0,0x00                959
                                                                                
(Cm 0,--)[PC=000017d8]               : BLTU      r13,r 6,0x7e                960
                                                                                
                                                                                
                                                                                
(Cm 1, 6)[PC=000017a8] R15<=00008174 : LW        r15,0x004,r11       (31)    961
(Cm 2,--)[PC=000017ac]               : SH        r13,0x002,r15               962
(Cm 6,44)[PC=000017bc] R14<=00000007 : ANDI      r14,r16,0x007       (62)    966
                                                                                
                                                                                
                                                                                
                                                                                
(Cm 7,59)[PC=000017c0] R17<=000080d0 : LW        r17,0x000,r11       ( 7)    967
(Cm11,52)[PC=000017d0] R15<=00000706 : AND       r15,r15,r28         (49)    971
(Cm12,--)[PC=000017d4]               : BEQ       r17,r 0,0x00                972
                                                                                
(Cm13,--)[PC=000017d8]               : BLTU      r13,r 6,0x7e                973
                                                                                

これはある命令シーケンスを一部切り出してきたものだが、LWの前にかなりの空きが出来ている。だが、これらの問題はデータキャッシュの導入によりだいぶ改善されたはずだ。 何が悪いんだろう?

調査してみると、分岐命令のReservationStationの数が足りないため、メモリアクセス命令を十分に発行出来ていないことが分かった。

極端な例だが、たとえば分岐ユニットのReservationStationのエントリ数が少ない状況を考える。

f:id:msyksphinz:20161121020831p:plain

上記の例では、ALUは4エントリx2が2つ分、16命令を保持することが出来るが、LSUは4エントリしか命令を保持できず、また分岐ユニット(BRU)は1命令しか命令を保持できないとする。

すると、例えば数命令内に複数の分岐命令が存在すると、BRUは常に埋まっており、別のエントリに命令が発行出来ない状況が生じる。

f:id:msyksphinz:20161121021204p:plain

たとえば、Inst-03が分岐命令のRSエントリに入ってオペランドを待ち合わせている場合、他のALU命令やLSU命令はそれぞれの命令のエントリに投入されるが、 次のInst-06が分岐命令の場合、その命令は分岐命令用のエントリが空くまで待つことになる。

この場合、同じRNUのスロットに入っているInst-04,Inst-05,Inst-07は無事にRSエントリに投入することは出来るかもしれないが、現在の実装の構造上Inst-06が掃けないと次の命令群、Inst-08,Inst-09,Inst-10,Inst-11を発行することが出来ない。

これを解決するためには、まず単純に数の少ないエントリ数の場所で、エントリ数を増やすということが挙げられる。まずは、この改良を実施しよう。

単純に分岐命令のエントリ数を1から2に挙げた場合、IPCは以下のようになった(デバッグ未なので、いろいろと間違っているかもしれないが...)。

f:id:msyksphinz:20161121021602p:plain:w1200

若干改善しているが、そこまで有意ではない。エントリ数が足りていないか、別のところにも問題がありそうだ。調査継続しよう。

自作プロセッサの性能解析

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

FPGA開発日記 記事整理インデックスを更新しました

FPGA開発日記の記事整理インデックスを更新して、ここ数ヶ月の記事を追加しました。

FPGA開発日記 記事整理インデックス

主に、

あたりが追加されています。

L1データキャッシュの実装設計(LSUとの接続部の設計)

L1データキャッシュについて、ロード命令とストア命令を1つのキューで制御した場合、コミットの制御とフラッシュの制御が面倒になる、というのを前回までで考えた。

msyksphinz.hatenablog.com

そのときの解決策の一つとして、ロード命令も一旦コミットを待ち、実際にライトバックを起こすのはコミット後にすれば、ストア命令と状態を統一することが出き、問題を解決できるのではないかということだ。

これを実装してみて、どのような影響があるのかを確認する。

ロード時のコミットを2回発生させる方法の検討

ロード命令、というか通常のレジスタ書き込み命令は、スーパスカラプロセッサの場合、

  1. レジスタへの書き込みを発生させる (ライトバック)
  2. コミットが発生する → レジスタへの書き込みが確定

となる。ところが、レジスタへの書き込み、つまりメモリからのロードデータがコミットよりも先にレジスタに書かれると、後続のストア命令とのキューのリソース管理に問題が発生する。

LSUの命令管理キューには、4つのインデックスが存在する。

  • リクエスト受付インデックス : キューのうちどこまでリクエストで使用しているか。Cyclic FIFOのヘッドのようなものだ。
  • コミット受付インデックス : キューのうちどこまでの命令がコミット確定したか。ロード命令の場合はメモリアクセスが完了後に進み、ストア命令の場合はメモリアクセスの前に進む。
  • メモリアクセスリクエスト・インデックス : キューのうちどこまでがメモリアクセスのリクエストを発生させたか。ロードの場合はリクエストを出したがリプライ応答待ち、ストアの場合はリクエストが受け付けられた時点で進める。
  • メモリアクセスリプライ・インデックス : キューのうちどこまでがメモリアクセスのリプライを発生させたか。ロードの場合はメモリアクセスのリプライが発生した場合、ストアの場合は進まないのでリクエストが受け付けられた時点で進める。

では、フラッシュが発生した場合に、それぞれどのようなタイミングでインデックスを更新すれば良いだろう?

  • リクエスト受付インデックス : コミット前のインデックスは全て破棄する。つまり、コミット受付インデックスの場所まで戻す。
  • コミット受付インデックス : フラッシュに影響を受けない。
  • メモリアクセスリクエスト・インデックス : ロード命令実行中は、コミット未確定のため、コミット受付インデックスまで戻さなければならない。一方でストア命令の実行中は、ストア命令を実行しているということは既にコミット確定のため、インデックスを変えてはならない。
  • メモリアクセスリプライ・インデックス : メモリアクセスリクエストインデックスと同じ。

つまり、メモリアクセスリクエスト・インデックスだけはロード命令、ストア命令によって動作を変えなければならないということだ。

以上をまとめると以下のようになる。

通常時の動作 フラッシュ時の動作
リクエスト受付インデックス 他のすべてのインデックスよりも先行する コミット受付インデックスまで戻す
コミット受付インデックス(ロード命令) メモリアクセス系インデックスの方が先行する 変化しない
メモリアクセスリクエスト・インデックス(ロード命令) コミット受付インデックスよりも先行する コミット受付インデックスまで戻す
メモリアクセスリプライ・インデックス(ロード命令) コミット受付インデックスよりも先行する コミット受付インデックスまで戻す
コミット受付インデックス(ストア命令) メモリアクセス系インデックスよりも先行する 変化しない
メモリアクセスリクエスト・インデックス(ストア命令) コミット受付インデックスの方が先行する 変更しない
メモリアクセスリプライ・インデックス(ストア命令) コミット受付インデックスの方が先行する 変更しない

なんとか、実装できるんじゃないか?抜けが無いといいが...