ADSP-2191には裏レジスタが存在し、ENA命令とDIS命令を利用することで簡単にレジスタセットを切り替えることができます。これを利用すると割り込みハンドラの先頭でのコンテキスト切り替えを非常に高速に行えます。
残念ながら割り込みを使おうで説明したinterrupt()はこの方法に対応していません。高速割り込みは入れ子にできないなどの制限があるためだと思われます。interrupt()関数による割り込みハンドルは非常に手軽なのですが、100サイクル程度のオーバーヘッドがかかってしまいます。
うまいことに、これには逃げ道があります。コンパイラに二つのプラグマを与えることで、関数を高速割り込みハンドラとして定義することができます。以下にその例を示します。使うのはinterruptとalterregistersの二つのプラグマで、下のプログラムのようにハンドラとして利用したいコードの前にプラグマを起きます。
volatile int a=3;
#pragma interrupt
#pragma altregisters
void handler(void)
{
a++;
}
プラグマ付きでコンパイルした結果を下に示します。コンパイラのバージョンは6.1.3です。必要のないスタックフレームを作っているあたりに無駄があるものの、実際の割り込みハンドラはもっと複雑になることを考えればそれほど問題ではありません。全体としてまずまずのコードです。
// PROCEDURE: _handler
.global _handler;
_handler:
.type _handler, STT_FUNC;
ENA M_MODE, DIS BIT_REV, DIS AR_SAT, DIS AV_LATCH;
MODIFY(I4 += -32);
DM(I4 += M5) = AR;
AR = I4 ;
ENA SD;
I4 = AR ;
M6 = 1;
ENA SR;
DM(I4 += M5)=I5, I5=I4;
// line 39
AY1 = DM(_a);
AR = AY1 + 1 ;
DM(_a) = AR;
// line 40
AR = DM(I5 += M6);
DIS SR, DIS SD;
RTI (DB);
AR = DM(I4 + 1);
MODIFY(I4 += 33);
この大きさであれば余裕で割り込みベクトルに格納することができます。しかし実用的なハンドラはもっと大きくなることを考えれば、ハンドラはprogramセクションに置くべきでしょう。ハンドラは最後にRTIで処理を終了するため、割り込みベクトルからハンドラへの分岐はコールではなくジャンプを使います。下にそのプログラムを示します。ベクトルとして使うので固有のセクション名をつけておきます。
.section/code myint15; // 標準割り込みベクトルの代わりに使うベクトルコード .global _handler; jump _handler; // ハンドラにジャンプするだけよん♪
最後に標準LDFの割り込みベクトルマッピング部をいじります。この部分はVDSP++になってからベクトルごとにセクションを分けてくれているのでカスタマイズが容易になりました。方針としては、乗っ取りを行うベクトル位置に、先の自分で定義したセクションをマッピングするだけです。ただ、追い出されたセクション全体を消さずに、物理メモリーへのマッピング部だけ消します。こうしないと、標準ライブラリの当該セクションの持って行き場がなくなるため、リンカーがエラーを吐きます。
この修正をすると、例でいえばIVint15が追い出されます。このセクションのコード自身はどこにも配置されませんが、シンボルだけは配置されたことになっているため、デバッガで探るとないはずのシンボルが幽霊のように残っています。深い理由はわからないのですが、外部デバッガとの協調作業用とのことです。気にしなくていいでしょう。
IVint15_dxe {
INPUT_SECTIONS( $OBJECTS(IVint15) $LIBRARIES(IVint15) ) }
// > mem_INT_INT15 コメントアウトしたので、このセクションは闇に消える
IVint15_dxe { // 替わりのジャンプコード
INPUT_SECTIONS( $OBJECTS(myint15) $LIBRARIES(myint15) ) }
> mem_INT_INT15