68000 アセンブラテクニックその2

move.[bw] #0,dn

clr.[bw] dn

clr.l では moveq に置換するの対して move.[bw] では clr.[bw] を使う. moveq に変えてしまうと使用容量と実行速度が同じ上に bit 31:16 が 0 になってしまうのでよいことはない.

話がそれるが clr 命令はレジスタのみに使う. clr 命令をメモリに使うのはよくない. マイクロコードの都合なのか不要な memory read が発生して遅い. 68010 以降はこの問題がない. bclr 命令はメモリを読んでフラグを更新してからメモリに書くので memory read の必要性はあるんだが、clr 命令はそれがない.

lea (an,dn.[wl]),an

src と dest の an が同じ場合に限る.

adda.[wl] dn,an

data pointer table 共通事項

jump table 共通事項の jmp/jsr がない. 基本方針は jump table と同じで dc.l を dc.w か dc.b の配列に変える.

このため index が pointer の数を超えている動作の場合は同等にならない. jump table では高確率でおかしくなるので元々のプログラム開発時に気づいて直していると思うが, data table は気づかずに動いてしまっていることが十分に考えられる.

pointer の中身が1種類

jump table の場合
	jmp pointer
data table の場合
	lea poiter,an

意外なことにこれが結構あった.

pointer が等間隔

pointer0
	dc.w	0,1,2,3,4,5
pointer1:
	dc.w	6,7,8,9,10,11

基本は data pointer table だけに適用する. jump table の場合は定数設定だけで分岐している場合だったので適切なコードを作った方がいい.

;間隔12の場合は index * 4 + index * 8 -> (index << 2) + (index << 3)
;として乗算をシフトと加算に変える. 
	lsl.w	#2,dn
 if near
	lea	(pc,pointer0,dn.w),an
 else
	lea	pointer0,an
	adda.w	dn,an
 endif
	lsl.w	#1,dn
	adda.w	dn,an

2の累乗ではない値の乗算回避のテーブルと思いきや間隔が 2 や 8 もあった.
加算回数が多すぎる場合は自動生成をやめて元通りテーブルを使うのも悪くはない. その場合は dc.l (→ lea; movea.l) から dc.w (→ lea; adda.w) に変えるほうが容量を削減できる.

pointer の中身が -0x80 から 0x7f で収まる場合

ほかの条件は jump table とやることは大体同じなので省略.

 if near
	move.b	(pc,table,dn.w),dn
	ext.w	dn
	lea	(pc,table,dn.w),an
 else
	lea	table,an
	move.b	(an,dn.w),dn
	ext.w	dn
	adda.w	dn,an
 endif
	...
	...
table:
	dc.b	pointer0 - table
	dc.b	pointer1 - table
	align	2

その他

pointer table の index を 8 bit でうち bit7 を別の意味を持たせている場合.

元のコード
	lea	table,an
	tst.w	dn
	bmi	xxx
	andi.w	#$007f,d7
	lsl.w	#2,d7
	movea.l	(an,d7.w),an
	...
	...
	...
xxx:
	andi.w	#$007f,d7
	lsl.w	#2,d7
	movea.l	(an,d7.w),an
	...
	...
	...
修正後
	lea	table,an
	andi.w	#$00ff,d7 ;bit15:8 を 0 にする
	lsl.b	#1,d7 ;.w から .b に変えて bit7 の有無をフラグにする
	movea.w	(an,d7.w),an ;movea はフラグが変わらない
	bcs	xxx
	...
	...
	...
xxx:
	...
	...
	...

src の bit0 を dest の bit7 へ代入

static uint8_t hoge(uint8_t src, uint8_t dest)
{
	dest &= 0x7f;
	if(src & 1){
		dest |= 0x80;
	}
	return dest;
}
;d0 = src, d1 = dest
	lsl.b	#1,d1 ;d1 <<= 1
	lsr.b	#1,d0 ;x=d0[0]
	roxr.b	#1,d1 ;d1[7:0]= {x,d1[7:1]}