現状のRISC-VベースMCUと将来

さて、IAR DevConでは実際にそのRISC-V(今回はIAR DevCon Evaluation boardではなく、SiFiveのHiFive 1を利用)を使ってのハンズオンも開催されたので、その内容を元にちょっとMCUとしての現状のRISC-Vをご紹介したいと思う。

そもそもRISC-V向けのソフトウェア開発環境としては、GitHubで色々公開されているほか、Andes Technologyが今年1月末にAndeSightというRISC-V向けIDEを無償公開するなど選択肢はいくつかあり、IAR EWRISC-Vは「初の商用開発環境」という扱いになるが、商用というだけにきちんとサポートが整った環境が提供される。以下、RISC-V一般の話とEWRISC-Vの話が混在するが、ちょっとまとめてご紹介したい。

まずは割り込み回り。現状RISC-Vそのものは割り込みに関して割と寛容というか、どうにでもなる仕様で、実際はPLICがその管理を行う形になるが、これが標準化されているという訳ではない(Photo11)。

  • RISC-V

    Photo11:これはあくまでSiFiveのEF310(それもEF310-002)の例、と但し書きがある様に、実際はSoCによって実装が異なる

割り込みIDも、GPIOやPWMのピン1つひとつに割り当てられているとか、優先度7レベルとか、MCUとしてはかなりリッチな構成になっているが、当然これはSoCというかPLICごとに機能が異なる訳で、EF310を使う限りにおいてはこれが役に立つが、他のSoCだとこの辺りが全然違う、という事が起こりえる(というか、おそらく違う)。

  • RISC-V

    Photo12:もちろん、こんなに一杯IDがあっても大変なので、Photo11に出てきたCLINTである程度絞る形になるのだと思われる

また見慣れないものとしてHPM(High Performance Monitor)という64bitカウンタが定義されており、これでCycle Timeを計測できる機能がある(Photo13)。

  • RISC-V

    Photo13:MPUではこの手のカウンタは珍しくないが、MCUで実装されているのはちょっと珍しい。ただし、31個はアーキテクチャで定義された上限で、実際にはもっと少ない(EF300の場合、実際には40bitのカウンタが3つとか説明があった気がする)

また実行制御用にCSR(Control Status Register)が汎用レジスタとは別に用意されているのは一般的であり、したがってこれを煩雑にアクセスする必要がある。それもあって、EWRISC-Vはこれらを直接ハンドリングできる組み込み関数を多数用意している(Photo14)。

  • RISC-V

    Photo14:NOP関数が用意されているあたりは、さすがに良く分かっているという気がする

先ほど紹介したCustom Instruction Extentionに対しては、EWRISC-Vからはインラインアセンブラを利用するという形でサポートを行うという話であった(Photo15,16)。

  • RISC-V

    Photo15:.instディレクティブに関してはC/C++コンパイラの最適化の対象外となるため、ここで記述したものがそのままRISC-V(経由でCustom Instruction Circuit)に渡されることになる

  • RISC-V

    Photo16:さまざまなRISC-Vの命令フォーマットにすべて対応できるとする

またレジスタはRISC-Vの場合32本(縮小命令のRV32Eは16本)利用可能なので、関数呼び出しなどもStackを積むよりもなるべくレジスタ渡しとした方が効率が良いが、このためのルールがPhoto16/17である。

  • RISC-V

    Photo17:ちなみにEWRISC-Vではレジスタ名の表記がRISC-Vのものと異なる。ここで言うa0~a7レジスタは、x10~x17レジスタに相当する。a0/a1(x0/x1)は引数・戻り値レジスタ、a2~a7(x2~x7)は引数レジスタと定義されている

またRV32Iの場合レジスタ長は32bitとなるが、64bitデータを扱う場合は少なくない(先のHPMも64bit長が必要)。この場合は64bit Alignに注意する必要がある(Photo18)。

  • RISC-V

    Photo18:このあたりは、RISV-Vが64bitを結構多用する事とも関係してくる。64bit値は64bit Alignになっている、というのはRISC-Vの仕様である(まぁ当然といえば当然だが)

Stackもちょっと特徴的で、必ず16Bytes Alighで配置される。なので、従来の様に引数の数だけStackを戻す、なんてやり方はRISC-Vではそのままでは動作しないことになる(Photo19)。

  • RISC-V

    Photo19:結果としてStackを利用するとメモリの圧迫が大きくなりがちである。まぁ、だからこそ汎用レジスタが多数利用できるし、これを利用してレジスタ渡しを使おうという話ではあるが

ちなみにもう少しHiFive 1寄りの話で言えば、例えばリセットが掛かった場合プログラムは0x2001_0000番地からプログラムを実行する(0x0000_0000ではない)とか、リセット直後のEF310は最高速の320MHzではなく、HFROSCの72MHzクロックを利用して駆動されている(つまり動作周波数は72MHz)なので、ブート後にPLLの設定を行って320MHzまで「自分で」動作周波数を引き上げてやる必要がある(しかもこの設定がまた面倒)など、色々と独自というか、EF310独自の話がかなりある。ここには書かないが、他にも色々注意すべき点は多く、それもあってセッションの中ではEF310の使い方を理解するためには

  • SiFive EF310-F002 Manual v19p04
  • SiFive EF310-F002 Preliminary Datasheet v1p0
  • SiFive HiFive1 Rev B Getting Starded Guide Version 1.1
  • The RISC-V Instruction Set Manual Volume I
  • The RISC-V Instruction Set Manual Volume II

のマニュアルを読む必要がある、と説明されている。

最後の2つはRISC-Vのアーキテクチャマニュアルであるため、必須にしても、最初の3つはEF310とHiFive 1の「癖」(あるいは独自仕様)を理解するために必要、という話である。

正直に言えば、現状RISC-VベースのMCUでシステムを開発する(それも仕事で)と言うのであれば、まずはIARのRISC-Vのセミナーを受講するのが一番手っ取り早い様に思われる。今回は簡単な90分(座学45分+ハンズオン45分)のセッションであったが、内容は盛り沢山でとても書ききれなかった。まだRISC-Vのノウハウが十分に普及していない現状、IARのノウハウは、特に仕事としてRISC-Vを利用する際には欠かせないと思う。

ところでこうした部分、例えばIRQのハンドリングの仕方とかアドレスの開始位置、I/Oポートのアドレスなどは、EF310と今後登場するであろうRISC-VベースのMCUでまったく異なるということになる。この状況、どこかで似た話が…ということで思い出したのが、Cortex-MというかCMSIS登場前のArm(当時の表記だとARM)ベースMCUである。

ARM7とかARM9を搭載したMCUは世の中にかなり沢山出回ったが、共通点はARMベースというだけで、割り込みやI/Oポート、メモリ空間などは全部異なっており、あるARMベースMCU用のミドルウェアを別のMCUに移植しようとすると、こうした部分に関わるところを全部書き直す必要がしばしば発生した。このあたりの混乱が整理されたのはArmがCMSIS(Cortex-M Software Interface Standard)を提供し、これを利用することで機種間の相違が吸収されるようになってからである。

現状のRISC-Vは、まさにこのCMSIS登場前夜に相当する。今のところこれに相当するI/FをRISC-V向けに提供する、という話は(非公式には何かしら動いているかもしれないが)公式には存在しない。そのため、現状RISC-VベースのMCUを使うのは、情報の少なさ(というかArmが多すぎるというべきでこれと比べるのはフェアではないのかもしれないが)と相まって、なかなか大変であろうと想像される。

このあたりの話はMCUだけでなく、Linuxを使うMPUでも似た話は当然出てくると思われる(Linus Torvalds氏がArm向けのKernel Patchが多すぎると激怒した話はまだ記憶に新しい)。RISC-VがArmのポジションを本気で狙うためには、まずここを何とかする必要がありそうに筆者には思えるのだが、そのArmにしても状況が収束するまで数年要した事を考えると、RISC-Vも1年やそこらでこれが収まるとは考えにくい。ここが何とかなるまでRISC-VはArmの敵にはなり得ない、というのが筆者の見解であるが、さてこの状況をどの程度の時間で解決できるのか楽しみでもある。