R8Cの汎用レジスタ(R0〜FB)は左の図のように2セットあり、 レジスタバンクを構成しています。レジスタバンクは、 フラグレジスタのレジスタバンク指定フラグBによって、 2サイクルで切り替えることができます。 割り込みルーチン等、レジスタバンクを使用することで、 push/popによるレジスタ待避を省略することができ、 僅かながらプログラムが高速になります。
v0903以降のKPIT Cコンパイラでは、 関数の属性にレジスタバンク切り替えによるレジスタ待避 __attribute__((bank_switch))を指定することができます。 以下は、割り込みルーチンでレジスタバンクを使用する方法です。
レジスタバンク使用前のソースコードとリスト出力を以下に示します。 ソースは音声波形をDAから出力するプログラムの割り込みルーチン部分です。 リスト出力を見てみると、割り込みルーチンの開始と終了で、 r0,r1,a0レジスタの待避と復帰を行っていることがわかります。
//データ出力します void _timer_re(void) __attribute__ ((interrupt)); void _timer_re(void) { BYTE n, i; // バッファデータをDAに出力 n = RiffInfo.count; if ( n ) { RiffInfo.count = --n; i = RiffInfo.idx_r; da1.byte = RiffInfo.buff[i++]; if( i>=sizeof(RiffInfo.buff) ) i = 0; RiffInfo.idx_r = i; } }
__timer_re: pushm r0,r1,a0 ; end of prologue mov.b _RiffInfo+70,r0l cmp.b #0,r0l jeq .L1 add.b #-1,r0l mov.b r0l,_RiffInfo+70 mov.b _RiffInfo+69,r0l mov.b r0l,r1l mov.b #0,r1h mov.w r1,a0 add.w #_RiffInfo,a0 mov.b 71[a0],r1l mov.b r1l,218 add.b #1,r0l cmp.b #-3,r0l jleu .L3 mov.b #0,r0l .L3: mov.b r0l,_RiffInfo+69 .L1: ; start of epilogue popm r0,r1,a0 reit
関数の属性に__attribute__((bank_switch)) を追加した場合のソースコードとリスト出力を示します。 レジスタバンク使用後のリスト出力では、 割り込みルーチン開始時にfset Bでバンクが切り替わっています。 なお、割り込みルーチンから戻る際にBフラグは自動的に元に戻ります。
//__attribute__ ((bank_switch)) を追加 void _timer_re(void) __attribute__ ((bank_switch)) __attribute__ ((interrupt)); void _timer_re(void) { : : }
__timer_re: fset B ; end of prologue mov.b _RiffInfo+70,r0l cmp.b #0,r0l jeq .L1 add.b #-1,r0l mov.b r0l,_RiffInfo+70 mov.b _RiffInfo+69,r0l mov.b r0l,r1l mov.b #0,r1h mov.w r1,a0 add.w #_RiffInfo,a0 mov.b 71[a0],r1l mov.b r1l,218 add.b #1,r0l cmp.b #-3,r0l jleu .L3 mov.b #0,r0l .L3: mov.b r0l,_RiffInfo+69 .L1: ; start of epilogue reit
以下に示したのは、今回使用したソースコードのRiffInfo.buff[i] アクセス部分と対応するリスト出力部分です。 インデックスのインクリメントとDAレジスタへの代入部分は省いています。 この部分ではbuffのアドレスを直接r1lにロードしないで、 一旦r0lを経由させています。
これは推測ですが、命令長の短縮が目的ではないかと思われます。 R8Cの命令フォーマットにはG,Q,S,Zの4つの形式があります。 1つの命令に対して命令フォーマットは複数用意されており、 命令長はGが最長で、Zが最短となります。 当然、命令長が短いほど命令のロードにかかる時間が短縮されます。 しかしながら、Q形式やS形式ではアドレッシングモードが制限されています。
以下の例では、S形式のmov.bが利用できるアドレッシングモードは、 r1lをdestに指定できないため、 r0lを経由しているのではないかと考えられます。
i = RiffInfo.idx_r; da1.byte = RiffInfo.buff[i++];
mov.b _RiffInfo+69,r0l mov.b r0l,r1l mov.b #0,r1h mov.w r1,a0 add.w #_RiffInfo,a0