RISC-V ボード(HiFive 1)を動かしてみる

投稿者: | 2019/12/09

My first evaluation of SiFive HiFive 1 (Arduino form factor RISC-V board).

今日は、随分と以前に購入した HiFive 1 を引っ張り出してきました。これは、SiFive という会社から 2016年の終わり頃にリリースされた、RISC-V ボードなのです。基板の形は Arduino Uno などと同一であり、いくつかの Arduino シールドが流用できるようです。このボード、私は去年の 5月頃に入手していたのですが、ずっと放置していました。(ちなみに、私の持っているのは Rev. A01 というものです。現在は Rev. B というものが入手可能なはずです。)

本当は FPGA で RISC-V を動かしてみたいのですが、やはり手元に「ちゃんと」動作する RISC-V がないと不安なので、遅ればせながら動かしてみることにしました。土日には Patterson 先生と Waterman さんの The RISC-V Reader も読み、命令セットもおおよそ理解しました。これでアセンブリデバッグもオーケーななずです。

ツールのインストール

ツールのインストール方法については、こちらに「HiFive1 Getting Started Guide」というドキュメントがあります。現在の版は 1.0.2 版なのですが、実はこれはちょっと内容が古く、freedom-e-sdk の最新版(v201908-branch)と整合が取れていません。もっとまずいことに、この v201908-branch のドキュメント README.md にも若干の不整合があり、この説明通りにやってもハマる方があるのではないかと思います。(はい、私のことです。)

もう一つ。Getting Started Guide では、出荷時にブートローダーとサンプルプログラムが Flash SPI ROM に書き込まれていると記述されているのですが、私の購入したユニットでは書き込まれていませんでした。ウェブで議論を見ると同じようなことを書いている方があり、フラッシュ書き込みを忘れたまま出荷したボードがかなりあるのではないかと推察されます。この点にも注意しながら、評価していきたいと思います。(なお、私は今回ホスト OS として Ubuntu 16.04.6 を使用しました。)

まず最初に、GitHub からfreedom-e-sdk(v201908-branch)を clone します。

$ git clone -b v201908-branch --recursive https://github.com/sifive/freedom-e-sdk.git

皆様がこれを見ているときには、既にもっと新しいバージョンが出ているかも知れません。その場合には、以下の内容は既に古くなっているかも知れませんので、御了承ください。

続いて、README.md を読み、いくつかのツールをインストールしました。

  • GNU Make(これは通常インストールされていると思いますが、なければ sudo apt install make)
  • Git
  • RISC-V GNU Toolchain
  • RISC-V QEMU
  • RISC-V OpenOCD

環境変数 RISCV_OPENOCD_PATH と RISCV_PATH と PATH も設定しましょう。Ubuntu であれば、~/.profile 末尾に

PATH=$HOME/riscv-qemu-4.1.0-2019.08.0-x86_64-linux-ubuntu14/bin:$PATH
export RISCV_OPENOCD_PATH=$HOME/riscv-openocd-0.10.0-2019.08.2-x86_64-linux-ubuntu14
export RISCV_PATH=$HOME/riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14

のような感じで良いと思いますが、バージョンが異なるかも知れませんので、チェックしてください。

なお、README.md の中で git pull origin master として最新版にアップデートする方法が説明されていますが、これは間違いだと思います。ここではブランチ v201908-branch を使うことになっているので、

$ git pull

だけで良いはずです。(そうしないと、master ブランチから pull してしまう。)

インストールはこれで完了です。Getting Started Guide では make tools が必要とありますが、これは、ブランチ v201908-branch では不要です。(エラーになります。)

ちなみに、後でブランチ v1_0 を使うことになりますが、そちらは make tools が必要です。これはなんと、GCC や GDB のビルドを含んでいるので、非常に時間がかかります。RISC-V の GCC や GDB がバイナリで入手可能になったのは嬉しいことです。

Linux USB の設定

ここで、USB の設定をしておきます。こちらについては、Getting Started Guide が参考になります。Chapter 5 の Boot and Run を見て設定しましょう。(一度ログアウト/ログインをし直し、id コマンドでユーザーモードの設定が有効になっていることを確認しておきます。)

サンプルプログラムのビルドと書き込み

README.md を見るといろいろ難しそうなことが書いてありますし、Getting Started Guide は内容が古いです。以下の通りにすれば大丈夫だと思います。

$ cd freedom-e-sdk
$ make software PROGRAM=sifive-welcome TARGET=sifive-hifive1

Getting Started Guide では demo_gpio というプログラムをビルドすることになっていますが、ブランチ v201908-branch にはありません。

次にフラッシュに書き込みます。

$ make upload PROGRAM=sifive-welcome TARGET=sifive-hifive1

途中で Loading section .init, size 0x194 lma 0x20400000 のような表示が出ると思います。A debugging session is active という表示の後、Remote communication error. という表示がありますが、たぶん大丈夫です。私もエラーの内容はまだ調べていません。

HiFive 1 上の RGB カラー LED がいろいろな色で点滅していれば、書き込み成功です。

ブートローダーが入っていなかったら

ここで本来は、HiFive の UART から起動メッセージが出るはずなのですが、リセット直後にメッセージを出すだけなので、メッセージを確認するためにリセットボタンを押す必要があります。そこで、端末ソフト(Windows であれば Tera Term でも良いのですが、私は GNU screen を使いました)を起動し、ボード上のリセットボタン(赤いほう)を押します。

…。

プログラムが動きません!!(動いた方は、このセクションは飛ばして結構です。本来は、LED の点滅前に、UART に次のような表示が出るはずなのです。)

                  SIFIVE, INC.

           5555555555555555555555555
          5555                   5555
         5555                     5555
        5555                       5555
       5555       5555555555555555555555
      5555       555555555555555555555555
     5555                             5555
    5555                               5555
   5555                                 5555
  5555555555555555555555555555          55555
   55555           555555555           55555
     55555           55555           55555
       55555           5           55555
         55555                   55555
           55555               55555
             55555           55555
               55555       55555
                 55555   55555
                   555555555
                     55555
                       5


               Welcome to SiFive!

さあ、どうしましょう。上記の make upload ではフラッシュエリア(0x2040_0000〜)に書き込んでいるはずなのに、どうしてリセットボタンを押してもプログラムが再開しないのでしょうか。

実は、HiFive 1 に搭載しているプロセッサ FE310-G000 は、リセットされるとフラッシュメモリ(0x2000_0000〜)の先頭にジャンプするのです。本来は HiFive 1 の出荷時に、ここにブートローダーが書かれていなくてはいけないのですね。それが、私の購入したボードでは書き込まれていない、という訳でした。そのため、make upload(内部で、OpenOCD + GDB を使って JTAG 経由でフラッシュ書き込みしてます)時には正しく 0x2040_0000 から実行できるのに、リセットボタンでは実行できない、ということなのです。

現在のブランチ v201908-branch では、既にこのブートローダーのソースコード(プロジェクト)は削除されており、そのままではブートローダーをビルドできません。ビルドをするには、ブランチ v1_0 をチェックアウトする必要があります。その方法は、以下に議論があります。

この手順で git clone, make tools をすると、非常に時間がかかります。(あ、その前にブランチ v1_0 の README.md を読んで、必要なツールをインストールするのを忘れないようにしましょう。)

私の場合は、途中で(確か)newlib のビルド中にエラーでコケてしまい途方に暮れましたが、幸い、後で説明する double_tap_dontboot のビルドには差し支えなかったので、エラーは無視しました。

なお、上記「議論」では公式パッチなるものが提供されていますが、本質的な修正についてはこちらに議論があります。

つまり、ブートローダーのソースコード(プロジェクト)はブランチ v1_0 の software/double_tap_dontboot であり、Makefile の設定(monitor flash protect ...)を書き換えることでフラッシュのプロテクトエリアを変更し、さらにリンカ指示ファイル中の ORIGIN を書き換え、プログラムのロードアドレスを 0x2040_0000 ではなく 0x2000_0000 にすることで書き込めますよ、ということです。

蛇足ですが、この辺のやり方はブランチ v201908-branch では変更されており、v1_0 と同じ方法は使えません。また、double_tap_dontboot を ブランチ v201908-branch にコピーしてきても、SDK の API が変わってしまっているので、簡単にはビルドできません。

上記手順に従うことで、私の HiFive 1 も無事にリセットボタンでブートするようになりました。

GDB を動かしてみよう

さて。折角 GDB と OpenOCD をインストールしましたので、デバッグも試してみましょう。いまここで試しておくことで、次回(?)MCU Eclipse などでビジュアルデバッグする際にも、裏で何が動いているかということが理解できるので、自信を持って作業できるはずです。

GDB でデバッグをするには、

$ make debug PROGRAM=sifive-welcome TARGET=sifive-hifive1

のようにします。すると、GDB が立ち上がります。

(gdb) l 146

とし、LED を点滅させている部分を探しましょう。

143	    // Red -> Green -> Blue, repeat
144	    while (1) {
145	
146	        // Turn on RED
147	        wait_for_timer(led0_red);

こんなコードが見つかると思いますので、147行目にブレークポイントを設定します。

(gdb) b 147

そして、continue してみましょう。

(gdb) c

LED の色が変わってから停止しますね。

Continuing.
Note: automatically using hardware breakpoints for read-only addresses.
halted at 0x20400546 due to hardware trigger

Breakpoint 1, main () at sifive-welcome.c:147
147	        wait_for_timer(led0_red);

c コマンド(continue)を繰り返すと、毎回 147 行目で停止することを確認できます。C 言語コードで 1行だけステップ実行したい場合は n コマンドです。

(gdb) n
halted at 0x2040054a due to step
halted at 0x2040054a due to step
halted at 0x2040033c due to step
halted at 0x2040033c due to step
Info : Retrying memory read starting from 0x20400540 with more delays
Info : Retrying memory read starting from 0x20400540 with more delays
Info : Retrying memory read starting from 0x20400540 with more delays
halted at 0x2040054c due to hardware trigger
150	        wait_for_timer(led0_green);

うまくデバッグできていそうですね。

なお、ブレークポイントを張る位置によっては、割込の都合などでうまくいかない場合もあるようです。今後、もう少し調査してみたいと思います。

最後にレジスタを覗いてみましょう。

(gdb) info reg
ra             0x2040054c	0x2040054c <main+402>
sp             0x80000c60	0x80000c60
gp             0x80000f90	0x80000f90
tp             0x1e6cd34f	0x1e6cd34f
t0             0x20400dc6	541068742
t1             0xf	15
t2             0xffffffff	-1
(略)

良い感じですね。

SDK の API ドキュメント

最後に、ドキュメントの在処(場所)についてです。

今回のような組込系のプログラミングでは、SiFive 社の SDK の一つである Freedom Metal というライブラリを使います。マニュアルは、ディレクトリ freedom-e-sdk/freedom-metal/doc/html の中に生成されます。ブラウザで index.html を開くと、ドキュメントを閲覧できます。

私もちょっと覗いてみたのですが、metal_gpio_get_device() とか metal_cpu_get() とか、ちょっと私の苦手なタイプの(抽象化レベルの高すぎる)API 仕様です。もっと簡単な API のほうが好きなんですけどね。

もっとも、実は HiFive 1 で使用しているプロセッサ FE310-G000 は、非常にコンパクトな仕様であり、そのドキュメント SiFive FE310-G000 Manual v3p1(データシートでないほう)を見ると、なんとたったの 110ページしかありません。もし、Freedom Metal の SDK API が気に入らなければ、ドキュメントを読んで直接レジスタを叩くコードを書くこともできるのではないか、と思います。

ちなみに、「110ページというのは短いのか!?」と思われる方があるかと思いますが、たとえば ARM 組込系プロセッサメーカーの雄「STMicroelectronics」の STM32F7 シリーズのマニュアル(RM0410 Rev. 4 )などは 1954ページの長さがあります!!  もちろん備えている機能の量は全然異なりますので単純な比較はできませんが、プログラマへの負担は大分異なってくると思います。SiFive 社には、今後も簡潔な仕様のペリフェラル機能、ドキュメントの提供をお願いしたいところです。

今日はここまで。次回は、統合開発ツール Freedom Studio や MCU Eclipse での開発、デバッグなどを評価してみたいと思います。

お問い合わせはお気軽にどうぞ!

御返答は 24時間以内(営業時間中)とさせて頂いております。もし返答が届かない場合、何らかの事情でメールが不達となっている可能性がございます。大変お手数ですが、別のメールアドレス等で督促頂けますと幸いです。なお、Facebook ページ(https://www.facebook.com/flogics/)でも御連絡頂けます。