FPGA開発日記

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

RISC-V SiFive Freedomプラットフォームのビルド手順

前回、SiFiveのFreedomプラットフォームについてまとめたが、今回は実際にそのプロジェクトを触ってみる。

Freedomプラットフォームはgithubに公開されており、デバイスさえあれば誰でもビルドすることができるようになっている。

github.com

ビルド対象のFPGAは2種類用意されており、Freedom EverywhereではDigilentのArty FPGA、Freedom UnleashedではXilinxのVC707 FPGA Boardをターゲットとしている。

f:id:msyksphinz:20170328235514p:plain

とりあえずWebPackを持っている私としては、DigilentのArty FPGAボードのほうが入手しやすい(持ってないけど)。 どのようなプロジェクトが出来上がるのか、確認しておこう。

Vivado WebPackでFreedom E310 Arty FPGA Dev Kitをビルドするためには

Vivado WebPackはデフォルトではArty FPGAボードの情報を持っていない。したがって、VivadoをインストールしてすぐにArty向けにビルドをしてもエラーをはいて終了してしまう。

そこで、DigilentのホームページからArty FPGAボードのボード情報ファイルを取得してきた。

Vivado Version 2015.1 and Later Board File Installation [Reference.Digilentinc]

f:id:msyksphinz:20170328235822p:plain

“Download"からボード情報をダウンロードして、展開した。これをXilinxのVivadoインストールフォルダの/data/boards/board_filesに展開する。

f:id:msyksphinz:20170328235936p:plain

上手く行けば、VivadoのCreate Projectから、Artyボードを選択できるようになっているはずだ。

f:id:msyksphinz:20170329000522p:plain

これを確認して、SiFiveプラットフォームをビルドしてみる。

$ make -f Makefile.e300artydevkit verilog
$ make -f Makefile.e300artydevkit mcs

無事にビルドが完了し、FPGA用のMCSファイルが生成されると、以下のようなメッセージとともにVivadoが終了する。

...
#   create_fileset -simset sim_1
# }
# set obj [current_fileset -simset]
# add_files -norecurse -fileset $obj [glob -directory $srcdir {*.v}]
# set_property TOP {tb} $obj
# if {[get_filesets -quiet constrs_1] eq ""} {
#   create_fileset -constrset constrs_1
# }
# set obj [current_fileset -constrset]
# add_files -norecurse -fileset $obj [glob -directory $constrsdir {*.xdc}]
source script/cfgmem.tcl
# lassign $argv mcsfile bitfile datafile
# set iface spix4
# set size 16
# set bitaddr 0x0
# write_cfgmem -format mcs -interface $iface -size $size \
#   -loadbit "up ${bitaddr} ${bitfile}" \
#   -loaddata [expr {$datafile ne "" ? "up 0x400000 ${datafile}" : ""}] \
#   -file $mcsfile -force
Command: write_cfgmem -format mcs -interface spix4 -size 16 -loadbit {up 0x0 obj/system.bit} -loaddata {} -file obj/system.mcs -force
Creating config memory files...
Creating bitstream load up from address 0x00000000
Loading bitfile obj/system.bit
Writing file obj/system.mcs
Writing log file obj/system.prm
===================================
Configuration Memory information
===================================
File Format        MCS
Interface          SPIX4
Size               16M
Start Address      0x00000000
End Address        0x00FFFFFF

Addr1         Addr2         Date                    File(s)
0x00000000    0x0021728B    Mar 28 23:45:11 2017    obj/system.bit
0 Infos, 0 Warnings, 0 Critical Warnings and 0 Errors encountered.
write_cfgmem completed successfully
INFO: [Common 17-206] Exiting Vivado at Tue Mar 28 23:45:45 2017...
make[1]: Leaving directory '/home/msyksphinz/work/freedom/fpga/e300artydevkit'
cp /home/msyksphinz/work/freedom/fpga/e300artydevkit/obj/system.mcs /home/msyksphinz/work/freedom/builds/e300artydevkit/sifive.freedom.everywhere.e300artydevkit.E300ArtyDevKitConfig.mcs

dcp(Design Check Point)が生成されていたので、ちょっと見てみた。

f:id:msyksphinz:20170329001650p:plain

Coreplexが、CPUの部分だ。

関連記事

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

RISC-Vプラットフォーム SiFive Freedomについて

RISC-VのASICチップおよび評価ボードとして、SiFiveのHiFive1ボードがすでに世界中で販売されているが、このHiFive1の持つFreedomプラットフォームについてまとめておこう。

そもそもHiFive1のRISC-Vプラットフォームはどのようになっているのだろう。

SiFive Freedomプラットフォームについて

そもそもHiFive1とは何なのか

dev.sifive.com

HiFive1は、SiFive FE310-G000という製品名として定義されている。

The FE310-G000 is the first Freedom E300 SoC, and forms the basis of the HiFive1 developmentboard for the Freedom E300 family.

f:id:msyksphinz:20170328004906p:plain

FE310-G000のブロックダイアグラム

ブロックダイアグラムの左側が、E31 CoreplexというCPUコアの部分になる。 HiFive1のE31 Coreplexは、以下のような構成となっている。

  • コア構成 : RV32IMAC (浮動小数点無し)
  • 分岐予測 : 40エントリのBranch-Target Buffer(BTB), 128エントリの分岐ヒストリ, 2エントリのReturn Stack Pointer(RAS)
  • 整数乗算 : 1サイクルあたり8ビットの乗算、つまり32ビットの計算を4クロックで実行
  • 整数除算 : 1ビットあたり1サイクル。計算サイクルは可変
  • 命令キャッシュ : 16kB, 2ウェイセットアソシアティブ
  • データキャッシュ : 16kB SRAM
  • システムマスクROM : 8kB ブートコード、コンフィグレーション文字列、デバッグROMルーチン挿入用

Freedom プラットフォームについて

Freedom プラットフォームには、現在2種類が存在する。 Freedom Unleashedという大規模SoC向けプラットフォームと、Freedom Everywhereというマイコン向けプラットフォームだ。 それぞれのプラットフォームの特徴を比較してみる。

Freedom Unleashed Freedom Everywhere
コア種類 U5 Coreplex at 1.6GHz+ E3 Coreplex
アーキテクチャ RV64GC RV32IMC/RV32EMC
マルチコア マルチコア、キャッシュコヒーレンシ -
Peripherals PCIe 3.0, USB3.0, GbE, DDR3/4 On chip Flash, OTP, SRAM
プロセス TSMC 28nm TSMC 180nm
OS Linux FreeRTOS
デバッグツール サポート サポート
FPGA VC707 FPGA Board(Xilinx) Arty FPGA Board(Xilinx)
ASIC - HiFive1

Freedom Unleashed

UNIXベースのSoCプラットフォームを構築するためのプラットフォーム。マシンラーニング、ストレージ、ネットワークなどの用途向けとなっている。

サポートFPGAボード

現在では、VC707 FPGAをサポートしている。開発環境は、githubから入手可能だ。

https://dev.sifive.com/static/core/images/dev-boards/xilinx-virtex-7-fpga-vc707-evaluation-kit.7cc42519defd.jpg

ブロックダイアグラム

f:id:msyksphinz:20170328010836p:plain

Freedom U500プラットフォームは、1~8コアまでのマルチコアをサポートしている。またキャッシュコヒーレンシをとるためのL2ユニットと、DDR3/4、PCI-Express Gen3.0, Ethernet, USB-3.0などを接続可能だ。

Freedom Everywhere

マイクロコントローラタイプのプラットフォーム。組み込みマイクロプロセッサ、IoT、ウェアラブルなどのマーケット向け。

サポートFPGAボード

現在では、Arty FPGAボードをサポートしている。開発環境は、githubから入手可能だ。 また、ASICチップとして、HiFive1が入手できる。

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

https://dev.sifive.com/static/core/images/dev-boards/hifive1.c27e1a6465d5.png

ブロックダイアグラム

ブロックダイアグラムはHiFive1のものと同一だ。

f:id:msyksphinz:20170328004906p:plain

関連記事

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

RISC-V用LinuxのビルドとSpikeによるシミュレーション(vmlinuxとroot.binの解析)

f:id:msyksphinz:20170325154038p:plain

前回、SpikeシミュレータでRISC-V版Linuxをビルドしようとしたのだが、なぜかエラーが発生して起動しなかった。 どこに原因があるのかさっぱりわからないため、まずはルートファイルシステムとvmlinuxを切り替えて起動実験をしてみる。

lowRISCには、すでにプレビルドされたLinuxのイメージとルートファイルシステムが存在する。

$ cd ./fpga-zynq/zedboard/fpga-images-zedboard/riscv
$ ls -1
root.bin
vmlinux

これらを使って、Spikeでシミュレーションをしてみる。

その前に、bblのリビルドをしておこう。

cd ~/work/riscv-tools/
CC= CXX= build_project riscv-pk --prefix=$RISCV --host=riscv64-unknown-elf --with-payload=/home/msyksphinz/work/fpga-zynq/zedboard/fpga-images-zedboard/riscv/vmlinux

シミュレーションしてみる。

$ spike +disk=root.bin bbl vmlinux
$ spike +disk=root.bin bbl /home/msyksphinz/work/linux-4.6.2/vmlinux
              vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
                  vvvvvvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrr       vvvvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrr      vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr    vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr    vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr    vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrr      vvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrr       vvvvvvvvvvvvvvvvvvvvvv
rr                vvvvvvvvvvvvvvvvvvvvvv
rr            vvvvvvvvvvvvvvvvvvvvvvvv      rr
rrrr      vvvvvvvvvvvvvvvvvvvvvvvvvv      rrrr
rrrrrr      vvvvvvvvvvvvvvvvvvvvvv      rrrrrr
rrrrrrrr      vvvvvvvvvvvvvvvvvv      rrrrrrrr
rrrrrrrrrr      vvvvvvvvvvvvvv      rrrrrrrrrr
rrrrrrrrrrrr      vvvvvvvvvv      rrrrrrrrrrrr
rrrrrrrrrrrrrr      vvvvvv      rrrrrrrrrrrrrr
rrrrrrrrrrrrrrrr      vv      rrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrr          rrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrr      rrrrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrrrr  rrrrrrrrrrrrrrrrrrrrrr

       INSTRUCTION SETS WANT TO BE FREE

うーん、途中で止まってしまった。何が悪いのかまだよく分からない。

RISC-V用LinuxのビルドとSpikeによるシミュレーション(Spikeによるシミュレーション→失敗)

f:id:msyksphinz:20170325154038p:plain

msyksphinz.hatenablog.com

前回、Linuxビルド用のRISC-V GCCの構築が終わったので、次にLinux本体のビルドとシミュレータによる実行をしてみたい。

github.com

RISC-V用Linuxの構築

まずはRISC-V用Linuxの作業リポジトリと、Linux本体を取得してくる。

curl -L https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.6.2.tar.xz | tar -xJ
cd linux-4.6.2
git init
git remote add -t master origin https://github.com/riscv/riscv-linux.git
git fetch
git checkout -f -t origin/master
git remote set-branches --add origin linux-4.6.y-riscv
git fetch

make ARCH=riscv defconfig
make -j4 ARCH=riscv vmlinux

これでLinuxの本体であるvmlinuxが生成される。生成される場所を今回は /home/msyksphinz/work/linux-4.6.2/vmlinuxとしている。

BusyBoxのビルド

github.com

BusyBox - Wikipedia

BusyBoxというのは、Linuxの一連のコマンド群をまとめたものだ。 私もあまり詳細は知らないのだが、MS-DOSのcmd.exeみたいなものだろうか。

特定用途のLinuxディストリビューションや組み込みシステムに適しており、「組み込みLinuxの十徳ナイフ」とも呼ばれている。

cd ~/work/riscv-tools/
curl -L http://busybox.net/downloads/busybox-1.21.1.tar.bz2 | tar -xj
cd busybox-1.21.1
make allnoconfig

make -j

これにより、busyboxが生成される。

ls -l
...
drwxr-xr-x  5 msyksphinz msyksphinz  4096  325 14:33 shell
drwxr-xr-x  3 msyksphinz msyksphinz  4096  325 14:33 util-linux
drwxr-xr-x  2 msyksphinz msyksphinz  4096  325 14:33 sysklogd
drwxr-xr-x  2 msyksphinz msyksphinz 16384  325 14:33 libbb
-rw-rw-r--  1 msyksphinz msyksphinz 15998  325 14:33 busybox_unstripped.out
-rw-rw-r--  1 msyksphinz msyksphinz 37906  325 14:33 busybox_unstripped.map
-rwxrwxr-x  1 msyksphinz msyksphinz 13840  325 14:33 busybox_unstripped
-rwxrwxr-x  1 msyksphinz msyksphinz 10344  325 14:33 busybox

Linux用ルートファイルシステムの構築

Linuxのルートファイルシステムを構築するために、イメージファイルの作成を行う。

cd ~/work/riscv-tools/root_bin/
dd if=/dev/zero of=root.bin bs=1M count=64
mkfs.ext2 -F root.bin
mkdir mnt
sudo mount -o loop root.bin mnt

cd mnt
sudo mkdir -p bin etc dev lib proc sbin sys tmp usr usr/bin usr/lib usr/sbin

sudo cp ~/work/riscv-tools/busybox-1.21.1/busybox bin
curl -L https://www.ocf.berkeley.edu/~qmn/linux/linux-inittab > etc/inittab

linux-inittabgithubの説明の場所には存在していなかったので、別の場所から取ってきた。

busyboxをリンクする。

cd sbin
ln -s ../bin/busybox init

cd ../../
sudo umount mnt

bblの再構築

Spikeで完成したLinuxをシミュレーションする前に、bblの再構築を行わなければならない。vmlinuxの場所を指定してriscv-pkを再構築する。

cd ~/work/riscv-tools/
export RISCV=/home/msyksphinz/riscv
. build.common
CC= CXX= build_project riscv-pk --prefix=$RISCV --host=riscv64-unknown-elf --with-payload=/home/msyksphinz/work/linux-4.6.2/vmlinux

Spikeでのシミュレーション

これでSpikeを走らせてみたのだが、どうも起動途中に失敗してしまった。

spike +disk=root_bin/root.bin bbl ../linux-4.6.2/vmlinux

f:id:msyksphinz:20170325161631p:plain

...
[    0.040000] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[    0.040000] CPU: 0 PID: 1 Comm: swapper Not tainted 4.6.2-00044-gdf91b31 #1
[    0.040000] Call Trace:
[    0.040000] [<ffffffff80012fc8>] walk_stackframe+0x0/0xc8
[    0.040000] [<ffffffff80056e90>] panic+0xec/0x20c
[    0.040000] [<ffffffff800011d8>] mount_block_root+0x248/0x328
[    0.040000] [<ffffffff8000292c>] ksysfs_init+0x10/0x40
[    0.040000] [<ffffffff80001488>] prepare_namespace+0x148/0x198
[    0.040000] [<ffffffff80000da0>] kernel_init_freeable+0x1c8/0x200
[    0.040000] [<ffffffff8021b160>] rest_init+0x80/0x84
[    0.040000] [<ffffffff8021b174>] kernel_init+0x10/0x11c
[    0.040000] [<ffffffff8021b160>] rest_init+0x80/0x84
[    0.040000] [<ffffffff80011c0c>] ret_from_syscall+0x10/0x14
[    0.040000] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
: msyksphinz@msyksphinz-pc:~/work/riscv-tools$ ^C

解析の必要あり。

RISC-V Linuxビルド用GCCの構築

f:id:msyksphinz:20170325154038p:plain

RISC-V用のLinuxは、以下のリポジトリで公開されている。

github.com

f:id:msyksphinz:20170325153123p:plain

Compile and install RISC-V cross-compiler · lowRISC

RISC-V用のLinuxには、riscv64-unknown-linux-gnu-gcc が必要だ。このビルドには、riscv-gnu-toolchainフォルダでのリビルドが必要になる。

# set up the RISCV environment variables
export RISCV=/home/msyksphinz/riscv

cd ~/work/riscv-tools/riscv-gnu-toolchain
# ignore if build already exist
mkdir build
cd build
../configure --prefix=$RISCV
make -j linux

一度buildディレクトリが生成され、通常用のriscv64-unknown-elf-gccが生成されている場合は一度ファイルをすべて削除しておくこと。

cd build
rm -rf *

これで、$RISCVディレクトリにriscv64-unknown-linux-gnu-gccが生成される。これでRISC-V Linuxの構築が行える。

Zephyr-OSがRISC-Vをサポート(QEMUでの試行)

少し前に、RISC-VのMLにてZephyr-OSがRISC-Vをサポートしたというアナウンスがあった。

Zephyr-OSは、Linux Foundationが発表した、モバイル用途向けの小規模のオペレーティングシステムだ。

Home | Zephyr Project

Zephyr (operating system) - Wikipedia

f:id:msyksphinz:20170324003639p:plain

Wikipediaによると、Zephyr-OSは以下のような特徴があるということだ。

RISC-V QEMUでZephyr-OS を動作させる

ZephyrのRISC-V移植版は以下で入手できる。

github.com

手順としてはReadmeに書いてある通りで動作させることができる。ただし、事前にriscv32のツールチェインと、riscv-qemuをビルドしておくこと。

  • Compiling zephyr-riscv for the qemu_riscv32 board

github.com

以下を実行することで、とりあえずQEMU中でZephyrを動作させることはできた。

cd zephyr-riscv/samples/philosophers
make BOARD=qemu_riscv32 run

f:id:msyksphinz:20170324004627p:plain

なんか動き始めた。哲学者の食事問題を動作させているのかな?

詳細については、今後勉強していこう。

HiFive1のパフォーマンスカウンタについて

前回Coremarkの測定を行ったし、その前は各命令のレイテンシを測定した。 このとき、実際にプログラムのサイクル数を測定しているわけだが、これはどのようにして実現しているのだろう。

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

まず各命令のレイテンシ、スループット測定には、以下のようなサイクル取得ルーチンを使用している。

#define rdmcycle(x)  {                                 \
    uint32_t lo, hi, hi2;                              \
    __asm__ __volatile__ ("1:\n\t"                     \
                          "csrr %0, mcycleh\n\t"       \
                          "csrr %1, mcycle\n\t"        \
                          "csrr %2, mcycleh\n\t"       \
                          "bne  %0, %2, 1b\n\t"                 \
                          : "=r" (hi), "=r" (lo), "=r" (hi2)) ; \
    *(x) = lo | ((uint64_t) hi << 32);                          \
  }

これはつまり、

  1. 現在のmcyclehの値を取得し、hiに代入する。
  2. 現在のmcycleの値を取得し、loに代入する。
  3. 現在のmcyclehの値を取得し、hi2に代入する。
  4. hiとhi2を比較し、不一致ならば1.から繰り返す。

これはmcyclehがオーバフローした場合を考慮したルーチンとなっている。

例えば、

1.を実行した時点で{mcycleh,mcycle}=0x0000_0010_ffff_ffff 2.を実行した時点で{mcycleh,mcycle}=0x0000_0011_0000_0000

となった場合、最後の計算で{mcycleh,mcycle}=0x0000_0011_ffff_ffff となってしまい、大幅にサイクル数が狂ってしまう。 これを防ぐために、mcyclehを2回ロードし、変化していないことを確認してからサイクル数を計算するという訳だ。

32bit版RISC-V (HiFive1) プロセッサでのサイクルカウント方法

計算方法としては難しいけれども、32bit版のRISC-Vでは上記ではそのまま計測できない。そこで、サイクルカウンタのHiレジスタとLoレジスタを別々に出力することにした。

#define rdmcycle(hi_cycle, lo_cycle)  {                            \
    uint32_t lo, hi, hi2;                              \
    __asm__ __volatile__ ("1:\n\t"                     \
                          "csrr %0, mcycleh\n\t"       \
                          "csrr %1, mcycle\n\t"        \
                          "csrr %2, mcycleh\n\t"       \
                          "bne  %0, %2, 1b\n\t"                 \
                          : "=r" (hi), "=r" (lo), "=r" (hi2)) ; \
   hi_cycle = hi; lo_cycle = lo;                               \
  }

以下のようにして出力する。差分の計算とかは難しいけど。とりあえずprintf()くらいは表示できるようになった。

  uint32_t start_cycle[2], stop_cycle[2];
  rdmcycle(start_cycle[1], start_cycle[0]);
...

  printf ("Correct = %d\n", correct);
  printf ("Time = %08x%08x - %08x%08x\n", stop_cycle[1], stop_cycle[0], start_cycle[1], start_cycle[0]);