Top > R8C >レジスタバンクをKPITで使う

レジスタバンク

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を経由しているのではないかと考えられます。

RiffInfo.buff[i]のアクセス部分
	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