MC6800のプログラミングテクニック(11) シフト操作の高速化

BASICMASTER

複数回の左右シフト操作を効率化したい。例えば、AccABを左に8bitシフトする場合は、TBAが使える。

LSLB/ROLA が4cycle必要なので、普通に書くと32cyc,16bytes必要。
(8回繰り返して 8bit左シフト)


	lslb
	rora
	lslb
	rora
	:
	lslb
	rora
	lslb
	rora

下記の方法なら 4cyc, 2bytesである

厳密にはフラグの立ち方が異なるが、コンパイラで使うならこれで十分。


	tba
	clrb


右シフト 8回の場合

unsigned 16bitは簡単である。


	tab
	clra

signed の場合は最上位ビットが0か1かを見る必要がある。普通に書くと以下のプログラムになる。
TBAしたあと、上位バイトは0クリアしておき、下位バイトが負なら$FFにする(符号拡張する)。

分岐あり(正の数)で10cyc, 無し(負の数)は12cyc, 6bytes.

TABの時にNフラグが変化しているのに、それを捨てているのが勿体無いが、CLRAでもLDAA #0でもNが消えるので仕方がない。


	tab
	clra
	tstb
	bpl pos
	coma
pos:

符号拡張するいつもの方法。10cyc,6bytes。少しだけ速い。


	tab
	clra
	asrb
	rolb
	suba #0

追記(2025/01/03): TABの時に変化したNフラグを使う方法を思いついた。8 or 10cycle, 5bytes。短くて速い。

tab すると AccA == AccB なので、sba すれば 0 になる。負数のときに deca しておけば、AccAが$FFになる。


	tab
	bpl	plus
	deca
plus:	sba

7bit右シフトにも使える。tabでは Carry が壊れないのがミソ。

こちらは10cyc, 6bytes。


	aslb
	rola
	tab
	sbca #0
	sba



左シフトのバリエーション

1,2,3,4,5 回までは単純に aslb/rola を繰り返せば良い。実行時間はシフト数*4, バイト数はシフト数*2。

8回以上は、TBAしてシフトする。以下は9回左シフトの場合。


	tba
	clrb
	asla

14-15回シフトはLSBをMSBに持ってくれば良い。以下は15回の場合 8cyc, 5bytes。14回だとlsrb/roraが増えて12cyc,7bytes。13回はTBA+左シフトが勝る。


	lsrb
	rora
	anda #$80
	clrb

追記: anda ではなくて、clraで良いです。1バイト減った(8cyc, 4bytes)。13回の場合はTBA版がまだ良い。


	clra
	lsrb
	rora
	clrb

7回シフトはTBAと組み合わせる。10cyc, 6bytes。

TBAではCarryは保存されるので、1bitはC経由で移動できるのがミソ。


	lsra
	tba
	rora
	rorb
	andb #$80




6回の場合。psha/tba/pulbで、AccABを入れ替える。この状態で2bit分右rotateすることで、元のAccAの下位2bitをMSB 2bitに移動する。22cyc, 10bytes


	psha
	tba
	pulb
	lsrb
	rora
	rorb
	rora
	rorb
	andb #$c0
回数 単純法 TBA+ LSRB/RORA TBA++
1 4, 2
2 8, 4
3 12, 6
4 16, 8
5 20, 10
6 24, 12 22, 10
7 28, 14 10, 6
8 4, 2
9 6, 3
10 8, 4
11 10, 5
12 12, 6 20, 10
13 14, 7 16, 8
14 16, 8 12, 6
15 18, 9 8, 4

5,6回は20cycle以上かかって遅い。うまい方法はないだろうか?

コメント

タイトルとURLをコピーしました