Nios® II 高速化手法シリーズ
このシリーズでは Nios® II の高速化に役に立つ情報について紹介します。
目的
多くの場合、割り込み処理には即時実行と高速処理が求められます。Nios® II ではデフォルトで例外レジスター方式(ソフトウェアによるプライオリティー・エンコーダ:Internal Interrupt Controller)が実装されますが、割り込み発生からサービス・ルーチンの呼び出しまでのレイテンシーが長いため、即時実行の観点からはあまり好ましい方式とは言えません。
しかし、Nios® II にはプライオリティー・エンコーダを外部(External Interrupt Controller) にハードウェアとして実装出来る Vectored Interrupt Controller(VIC) コアがあり、それを使う事で短いレイテンシーでサービス・ルーチンを呼び出す事が出来るようになります。
また、Internal Interrupt Controller では、サービス・ルーチンのアドレスをテーブルから検索する必要があるため、割り込み ID の値が大きいものはレイテンシーが長くなりますが、VIC では均一のレイテンシーとなるのも特徴です。
本検証では、Internal Interrupt Controller と VIC の動作を比較し、即時実行と高速処理をどのように実現して行くかを解説して行きます。
キャッシュの影響
割り込み処理の多くは、main() 処理ループ実行中、任意の外部信号によって動作を始めます。したがって、割り込みサービス・ルーチンやその変数がキャッシュにヒットする事は少なく、キャッシュの恩恵を受けられない場合が多いと考えられます。(もちろん、main() 処理が非常に小規模で、キャッシュを大量に実装している場合は別です)
本検証では、キャッシュの影響についても考察しています。
Internal Interrupt Controller
例外レジスタ方式を採用している Internal Interrupt Controller の検証は下記の構成で行っています。
[ Block Diagram ]
Nios® II Gen2 /f コアを実装し、プログラム・メモリーは On-Chip RAM 128KB 、キャッシュは、Instruction / Data 共に 4KB としています。割り込みモジュールは PIO Input を 8 個(in_0 ~ in_7)実装し、PIO Output(out)からの折り返し信号を入力する事で、Nios® II のソフトウェアで割り込みを掛けられるようにしています。
ソフトウェアは下記のとおりです。PIO Input の割り込みハンドラーと main() のみで構成され、8 個の割り込みを登録した後、key の状態を取得し、立上りを検出した際に PIO Output の 1 bit を順番に High にして行く事で、PIO Input の IRQ を発行させます。
なお、PIO Output 出力の前に alt_icache_flush_all() , alt_dcache_flush_all() を呼んでいますが、ここで一旦キャッシュを無効にすることで、サービス・ルーチンがキャッシュに残存しないようにしています。
本検証では、上記 alt_icache_flush_all() , alt_dcache_flush_all() をコメントアウトする事で、キャッシュに残存した場合の計測も行っていますので、参考にしてください。
割り込みハンドラーでは、呼び出し直後に LED を On しています。.objdump で確認すると IOWR_ALTERA_AVALON_PIO_DATA は 4 命令で動作しますので、1 命令 1 clock = 4 clock、レジスタ書込みから IO 出力まで 1 clock と仮定すると、サービス・ルーチンの呼び出しは LED 点灯の 5 clock 前と考えられます。
BSP Editor およびアプリケーション・プロパティーの設定は、オプティマイズ・レベルを -O3 としています。
[ BSP Editor -> Main ]
[ Application Properties ]
Internal Interrupt Controller での計測結果
下記が計測時のシグナルタップ(SignalTap II)の波形です。中心にある波形は、LED が High になった位置の波形を拡大したものです。IRQ 0 では 199 clk だったものが、IRQ 7 では 231 clock になっています。
[ SignalTap II ]
上記結果はキャッシュ・フラッシュ有り(サービス・ルーチンがキャッシュに残存していない)の時間ですが、キャッシュ・フラッシュを行わなかった場合(サービス・ルーチンがキャッシュに残存している)の時間は下記の通りで、IRQ 0 で 61 clock、IRQ 7 で95 clock と大幅にレイテンシーが短縮されています。
[ SignalTap II & No flash ]
External Interrupt Controller ( VIC ) での計測結果
VIC を使用した検証は下記の構成で行っています。
[ Block Diagram ]
Internal Interrupt Controller の検証デザインと基本構成は同じですが、IRQ を VIC に接続しています。
ソースコードも同じですが、BSP Editor の設定に違いがあります。Drivers タブに altera_vic_driver の項目が追加されていますので、その enable_preemption (ネスト割り込み許可/不許可)を切り替えて計測を行ってみます。( RRS や RIL については単独の割り込みにおいてはレイテンシーに影響しないためデフォルトのままにしています)
[ BSP Editor -> Drivers ]
[ シグナルタップ (SignalTap II) Enable Preemption ]
[ シグナルタップ (SignalTap II) Disable Preemption ]
ネスト割り込みを許可する場合の設定では、IRQ 番号に関わらず 68 clock 一定で、ネスト割り込みを許可しない場合の設定では、こちらも IRQ 番号に関わらず 59 clock でした。
キャッシュ・フラッシュを行わなかった場合(サービス・ルーチンがキャッシュに残存している)の時間は下記の通りで、35 clock と 26 clock と言う結果となりました。
[ シグナルタップ (SignalTap II) Enable Preemption & No flash ]
[ シグナルタップ (SignalTap II) Disable Preemption & No flash ]
これまでの事から VIC による低レイテンシー化の効果は大きいものの、さらに高速化するためには、キャッシュような高速で動作するメモリーを割り込み関連のメモリーに割り当てる事が有効だと考えられます。
External Interrupt Controller と Tightly Coupled Memory の併用での計測結果
Tightly Coupled Memory (TCM) は、Nios® II のプロセッサ・コアと直接接続されますので、高速なメモリーアクセスが可能になります。これを割り込みベクタやサービス・ルーチンに割り当てる事で、より高速な割り込み処理を目指します。
[ Block Diagram ]
BSP Editor において TCM のセクションを割り当てます。
BSP Editor を開いて、Linker Script タブの Section Mappings の Add... をクリックし、".handler" と言うセクションを TCM Instruction に割り当てます。
[ BSP Editor -> Linker Script ]
ベクターテーブルを TCM Instruction に割り当てるため、Drivers タブの linker_section を ".handler" に変更します。
[ BSP Editor -> Drivers ]
割り込みで使用されるスタック・メモリーを TCM に割り当てるため、Main タブのenable_exception_stack および enable_interrupt_stack を TCM Data に割り当てます。
[ BSP Editor -> Main ]
ソースコードを変更します。
__attribute__((section()) でサービス・ルーチンを ".handler" セクションに割り当てます。
[ シグナルタップ (SignalTap II) Enable Preemption ]
[ シグナルタップ (SignalTap II) Disable Preemption ]
ネスト割り込みを許可する場合の設定では 49 clock、ネスト割り込みを許可しない場合の設定では 40 clock でした。TCM を使用しなかった場合の時間が 68 clock と 59 clock でしたから、共に 19 clock の短縮が可能になりました。Internal Interrupt Controller ではレイテンシーが 200 clock 程度ありましたので 19 clockの短縮は 10 % 程度となり、あまり効果は実感できませんが、VIC では大幅な短縮となりますので TCM への実装は効果があると言えます。
補足になりますが、キャッシュ・フラッシュを行わなかった場合の時間を下記に掲載しますので、参考にしてください。
[ シグナルタップ (SignalTap II) Enable Preemption & No flash ]
[ シグナルタップ(SignalTap II) Disable Preemption & No flash ]
今回の検証では実行メモリーに OnChip-RAM を使用していますので TCM の使用による高速化はさほど大きくありませんが、実行メモリーを外部メモリーなどにしている場合は今回よりも低速になる可能性がありますので、TCM 化の効果は大きいと考えられます。
おすすめページ
弊社では Nios® II に関する各種情報とまとめた「Nios® II まとめページ」をご用意しております。本記事以外にも有用な情報が満載ですのでこちらも併せてご確認ください。