2191の割り込みは、アーキテクチャー共通部と製品依存部に分かれます。共通部はADSP-219xコアを使うすべてのDSPに共通ですのでADSP-2199xといったミックスド・シグナルDSPでも同じ構造をしています。一方製品依存部はプロセッサごとに異なりますからADSP-2191とADSP-2192、ADSP-21990などはすべて異なる構造をもちます。
製品依存部は割り込み源からの割り込み要求に優先順位を与えてコアに渡します。
ADSP-2191の割り込みの流れは下の図のようになっています。図の左側は内蔵割り込みソース群です。割り込みはADSP-2191のSPORTやUARTといった内蔵ペリフェラルが発生します。これらの割り込みは独立したものですが、IPRxレジスタによって個別の入力から割り込み順位に変換され、コアに入力されます。
図中割り込みポートというのは勝手にで呼んでいるだけで、219xコアの割り込み受け付け口と思ってください。ここを通った信号はIMASKレジスタで受付の可否が決定されます。また、ここではスタック割り込み、カーネル割り込みといったコアが生成する割り込みが合流します。
IMASKを通過した割り込み信号はIRPTLにラッチされて初めて割り込みとして受け付けられます。異なる順位の割り込みが同時に来ると、高い順位(数字の小さいほう)が優先されます。割り込み処理中により高い順位の割り込みがきたときの振る舞いはICNTLのINEビットが1の時だけ割り込みがかかります。
これらの動きはICNTLレジスタのGIEが1の時の話です。0の時には割り込みはかかりません。
図1 割り込み機構の概要
IPR0からIPR3までのレジスタはInterrupt Priority Registerの略で、内蔵割り込み源に優先順位をつけるためのものです(HR B-20)。
図2 IPRxレジスタ
IRPxは4ビットごとに4分割されています。それぞれのフィールドは割り込みソースに当てられ、このフィールドにセットした値がペリフェラル割り込み優先順位になります。例えばIRP0のビット8から11までのフィールドはSPORT0のTX割り込みになっています。ここに3を設定するとペリフェラル割り込み順位3となります。
の関係が成り立ちますから、結局SPORT0のTXはコア割り込み順位7の割り込みとなります。この関係は面倒ですので後ほどあらためて表にします。
IPRxの設定は異なる割り込みに同じ優先順位をつけることを許しています。実際にリセット時にはTIMER2, Programmable Flag 0, Programmable Flag 1, Memory DMAが同じ割り込み順位を共有しています。
この場合、割り込みハンドラはどのペリフェラルから割りこみがかかったのか調べなければなりません。調べるにはINTRDxレジスタを調べます(HR B-23)。INTRD0からINTRD11までが用意されており、このxの部分がペリフェラル割り込み順位に対応しています。
INTRDxの各ビットは割り込みソースであるペリフェラルに対応しています。ペリフェラルとINTRDxでのビットの関係を下の表に示します。
内蔵デバイス | INTRDxのビット |
---|---|
Slave DMA / Host Port | 0 |
SPORT0 Receive | 1 |
SPORT0 Transmit | 2 |
SPORT1 Receive | 3 |
SPORT1 Transmit | 4 |
SP0RT2 Receive / SPI0 | 5 |
SPORT2 Transmit / SPI1 | 6 |
UART Receive | 7 |
UART Transmit | 8 |
Timer0 | 9 |
Timer1 | 10 |
Timer2 | 11 |
Programmable Flag A | 12 |
Programmable Flag B | 13 |
Memory DMA | 14 |
例をあげて考えてみましょう。今、INTRD3レジスタのビット3とビット8が同時に1になっているとします。この場合、ペリフェラル割り込み順位3に対して、SPORT1受信およびUART送信割り込みがサービスを待っていることになります。
この情報を下に、割り込みハンドラは自分がどのデバイスの割り込みを処理すべきか知ることが出来ます。
当然ですが、一つの割り込み順位に割り込み源が一つだけ割り当てられている場合にはINTRDxを参照する必要はありません。
なお、Programmable Interruptに関しては0/1と表記するかA/Bと表記するかでマニュアルに混乱が見られます。(HR B-90, C-3)
IPRxによって割り込み順位に変換された割り込み信号は内蔵ペリフェラルから2191コアに与えられます。ここで内蔵ペリフェラルからの割り込み順位は、コア内部の割り込み信号と束ねられて合計16本になります。こうしてコアにそろった割り込み信号ですが、すべてがすぐに処理されるわけではありません。
プログラムによっては一時的に特定の割り込みを扱いたくない場合があります。そのような場合はその割り込みだけ禁止して他の割り込みを受け付けられるようにするのが理想的です。このような用途に用意されたのがIMASKレジスタです(HR 3-30, A-17)。IMASKレジスタは16ビットのレジスタで各ビットがコア割り込み優先順位と対応しています。つまり、ビット3はコア割り込み優先順位3です。
IMASKのあるビットが1のとき、そのビットに対応する割り込み優先順位が、割り込み可能になります。反対に0のときには割り込み不可能になります。
一般に「割り込みをマスクする」と呼ぶと禁止してしまう意味なのでIMASKが1ならば禁止のように考えてしまいます。しかしながら、IMASKで言うところの「マスク」は動詞ではなくて名詞です。つまり「割り込み可能なものを拾い上げるためのビットマスク」という意味です。そのために1のときに割り込み可能になるのです。何にせよ、わかりにくい名前です。
IMASKを通過できれば割り込みがかかりそうに思えますが、実際にはまだ条件があります。IO空間にあるICNTLレジスタのGIEビットはコア全体に対して割り込み可能、割り込み不可能の制御を行います(HR 3-31, A-18)。
言葉を変えると、IMASKがどうであれGIE=0ならば割り込みはかかりません。
IMASKとGIEの関門を通過してきた割り込みは漸くコアから「割り込み有り」と認識されます。コアは割り込みを認識するとIRPTLレジスタにそれを記録します(HR 3-31, A-17)。IRPTLレジスタの各ビットはコアの割り込み優先順位に対応しています。
ここに記録されるのは現在処理中、あるいは処理待ちであると219xコアに認識されている割り込みです。したがって、このレジスタの値を直接変更すれば割り込みを強制的に発生させたり、消したり出来ます。そのためにSETINT (ISR 8-62)およびCLRINT (ISR 8-64)命令が用意されています。
IRPTLをユーザーのアプリケーションが扱うことはめったにありません。
ある割り込みを処理中により優先順位の高い他の割り込みが発生したとします。この場合現在処理中の割り込みをそのままにしてより高い順位の割り込み処理に移ることも考えられます。そのような処理は割り込みに割り込みをかけることから「割り込みの入れ子(Interrupt Nesting)」と呼びます。
ADSP-219xはINCTLレジスタのINEビットによって割り込みの入れ子を許可・禁止できます(HR 3-32, A-17)。
割り込みの処理にあたってはプロセッサは現行アプリケーションに関するレジスタのうち最低限のものを安全なところに退避しなければなりません。そうしなければ割り込みの発生によってアプリケーションが使っていたレジスタが破壊され、プログラムが暴走するでしょう。
ADSP-219xは割り込みが入ると現在のPCとステータス情報を内蔵スタックに退避します(HR 3-34)。それ以外の資源はプログラマが責任を持って退避します。
割り込みが受理され、コンテキストの退避が終了すると219xコアは割り込みベクトルの実行を開始します。割り込みベクトルはメモリー空間の最初の512Wに設置された領域です。割り込みはこの領域の優先順位に応じた場所に32Wずつのプログラムを配置できます(HR C-2)。
32Wで足りないときにはサブルーチンをコールしてください。なお、割り込みからの戻りはRTI命令を使います。
下の表は、IMASK、IRPTLの各ビットに割り当てられた名称及び singal.h でのマクロ名です。なお、ResetおよびEmulation Kernel割り込みは開発装置専用であるため、アプリケーション側でハンドラを用意することはありません。
ビット | 名称 | signal.h | 順位ID | リセット時割り当て |
---|---|---|---|---|
0 | Reset | - | * | * |
1 | Power Down | SIG_PWRDWN | * | * |
2 | Emulation Kernel | SIG_KERNEL | * | * |
3 | Loop/PC Stack | SIG_STACKINT | * | * |
4 | U.D.I. | SIG_INT4 | 0 | Slave DMA / Host Port |
5 | U.D.I. | SIG_INT5 | 1 | SPORT0 Receive |
6 | U.D.I. | SIG_INT6 | 2 | SPORT0 Transmit |
7 | U.D.I. | SIG_INT7 | 3 | SPORT1 Receive |
8 | U.D.I. | SIG_INT8 | 4 | SPORT1 Transmit |
9 | U.D.I. | SIG_INT9 | 5 | SP0RT2 Receive / SPI0 |
10 | U.D.I. | SIG_INT10 | 6 | SPORT2 Transmit / SPI1 |
11 | U.D.I. | SIG_INT11 | 7 | UART Receive |
12 | U.D.I. | SIG_INT12 | 8 | UART Transmit |
13 | U.D.I. | SIG_INT13 | 9 | Timer0 |
14 | U.D.I. | SIG_INT14 | 10 | Timer1 |
15 | U.D.I. | SIG_INT15 | 11 | Timer2, PFA, PFB, Memory DMA |
U.D.I. : User Defined Interrupt
HR(First Ed.)C-2の表ではKernelのほうがStackより低位のビット割り当てになっていますが、これは誤りと思われます。