mikotohisashiのページ

LPC1114(Cortex-M0)対OpenRISCのベンチマーク

LPC1114(Cortex-M0)対OpenRISCのベンチマーク比較をやってみました。題材としては、MARYのPROG13_CALC_PIの「#define Simon_Plouffe_1」を有効にした円周率計算プログラムを使用しました。
(1)OpenRISCの動作周波数は50MHzです。バスはWishboneですが、レイテンシが大きいのでキャッシュは必須です。 命令キャッシュ=4KB、データキャッシュ=4KBを搭載しています。命令長は32bitなので、基本的には1サイクルごとに1命令をCPUにフィードするバンド幅になっています。
(2) LPC1114(Cortex-M0)はMARYのMBを使用しています。内蔵発振器を使用しているので動作周波数は48MHzです。内蔵FLASH ROMは2サイクルアクセスしていますが、Thumb2コード(16bit固定長)なので、基本的には1サイクルごとに1命令をCPUにフィードするバンド幅になっています。

※なお、OpenRISCのプログラムにおいて、long long(64bit変数)の計算が正しくないことが判明したので(ライブラリ起因と推定)、moduloを取る方法を以下のように変更してあります。こうすると元のLPC1114のプログラムも多少速くなります。両CPUとも変更後のプログラムを使用して比較しています。
(変更前)#define mul_mod(a,b,m) (( (long long) (a) * (long long) (b) ) % (m))
(変更後)#define mul_mod(a,b,m) ( ((a) % (m)) * ((b) % (m)) )

ベンチマーク結果

CPU 動作周波数 計算時間 備 考
OpenRISC 50MHz 42sec
Cortex-M0 48MHz 114sec
Cortex-M0 50MHz 109sec 換算値
(円周率541桁までの計算時間で比較)

結果的にはOpenRISCの方がLPC1114(Cortex-M0)より2倍以上性能が高いように見えますが、完璧に公平なベンチマークではない可能性もあります。ライブラリの最適化条件などが異なるのであまり鵜呑みにはできません。ただし、OpenRISCは十分に応用できる実力を持っていることはわかります。問題点としては、全ての命令が32bit固定長なのでコードサイズが大きくなる点です。Cortex-M0に比べて2倍以上のコードサイズになってしまいます。
(2011.06.02)

OpenRISCの方が速い理由は、ハードウェア除算器を実装したためと推定しています。Cortex-M0には除算命令がなく、専用のサブルーチンで計算しており時間がかかっています。
(2011.06.18)

OpenRISCの動作の様子


(2011.06.02)

OpenRISC1200でハマったこと

 全くMARYとは関係ない話ですが、お許しください。
 OpenRISCのCPUコアはフリーな点でいいのですが、とにかくさまざまなトラップに引っかかり、なかなかうまくいかないことが多いです。それでも諦めずに執念で使いこなす苦労もそれなりに楽しいものです。
 gnu toolの立ち上げや、JTAGデバッガの立ち上げなど、それはそれで苦労します。しかしこれらはだいたい予想つくものですが、今回は全く「想定外」な問題に出くわしてかなり楽しめたのでご紹介します。

【問題点】割込みを発生させると、たまに暴走するという、とんでもない問題。
【解析経過】
(1) 例外処理の出入り口を記述しているstartupルーチンの問題だろうと予想。しかも自分で書いているからどうせ間違っているはずだろうと推定。しかし、眺めてみても問題なさげだし、そのルーチンを含めたverilogシミュレーションでは問題が再現しない。
(2) mainルーチンとして、LEDをインクリメントする程度のEasyなものを用意して、その上で周期割込みを発生させてみたところ、実機でも全く問題なし。
(3) mainルーチンとして、gnuライブラリをリンクしたちょっと複雑なもの(実際は円周率の計算)を実行させながら周期割込みをぶつけてみた。そうすると実機でしっかり現象が再現。
(4) その(3)の状況で少し長いverilogシミュレーションを実行したら、ようやく再現。「やったー!」
【原因】
(1) なんと、gcc=gnuライブラリの問題であった。
(2) そのライブラリ内の各関数の出入り口では、関数内で使用するレジスタをスタックに退避・復帰している。この退避時の動作として、「なんと」スタックポインタSPを変えずに、(SP-4), (SP-8)、…に対してレジスタをストアしているのである。全部のストアが終わったら、SP本体を変更している。ようするに実質的にスタックを掘る前に退避ストアをしているのだ。この退避ストア命令の列の途中で割込みが起こったらどうなるか。
(3) 割込み例外処理の入り口ではスタックを掘ってから全レジスタを退避している。メインルーチン側でスタックSPを掘っていない状態で割込まれると、メイン側で退避しようとしていた領域に対して、例外入り口での退避が行なわれる。これでスタックが壊れてしまい、暴走に到るのである。
【解決法】
(1) 暫定的に、例外処理の出入り口のスタック堀り距離を延ばす事で問題が解決することを確認した。実際、これがOpenRISCのスタックフレームのポリシーになっているようだ。
(2) 本質的には、gccの吐き出すコードをどうにかすべきだ。

 OpenRISCは、変な問題には命中しましたが、どうにか使いこなせそうなのでもう少し愛用してみます。FPGA用のCPUとして某社のNIOSやMicroBlazeなんぞを使うよりは囚われ感がない点でとても良いのです。
(2011.05.29)(2011.06.02改訂)

MARY拡張基板をOpenRISC1200で制御する

エレキジャックフォーラム2011で衝動買いしたFPGAボード「DE0 nano」に、OpenRISC1200をインプリして、MARY拡張基板を制御してみました。

OpenRISC1200とは

オープンソース・ハードウェアを推進するopencores.orgの旗艦プロジェクトとして開発された、フリーでオープンな32ビットRISC型CPUコアです。gnu tool chainsやlinuxも提供されています。
OpenRISC

動作の様子

ユニバーサル基板にDE0 nanoを載せて、裏でMARY拡張基板と結線しています。このアプリでは、OBに矩形を描画しながら、XBに無線で届く文字列をOBに表示しています。

システムブロック図

FPGAには、OpenRISC1200のCPUコア、JTAGデバッガ、SPI、UART、ROM/RAMをインプリしています。DE0 nanoにはAlteraのUSB Blaster互換インタフェースがありますが、このインタフェースを仮想JTAGポートとしてユーザが使用することができます。すなわち、AlteraのMEGA Functionとして提供されているsld_virtual_jtagを使って、USB経由でOpenRISCのJTAGデバッガを操作できます。ホスト(Ubuntu Linux)上で、advanced_jtag_bridge経由でgdb(デバッガ)とFPGA内のJTAGデバッガを結びつけています。
(2011.05.18)
最終更新:2011年06月18日 22:57