富士通MB8861の追加命令 (3)ADX

BASICMASTER

富士通MB8861はMC6800上位互換のCPUであり、5種6命令が追加されている。今回はADX命令の解説。

ADXはIXレジスタに8bitの即値あるいはメモリ上の16bitデータを加算する。

命令 code byte cyc 機能概略
ADX
(imm)
EC 2 4 IXL ← (IXL) +(命令の 2 バイト目)
IXH ← (IXH) + C
ADX
(ext)
FC 3 7 IXL ← (IXL) + (M + 1)
IXH ← (IXH) + (M) + C


ADX命令について

MB8861の追加命令で一番嬉しいのがADX命令である。MC6800のIXレジスタの演算は+1/-1しか行えず、大小比較も行えない。

ADXを使うと即値8bit、メモリ上の16bitと加算ができる。命令コードは $EC, $FC。命令サイクルは4,7。

MB8861は(MC6800も) Big-Endian であり、2バイト加算をする場合は手間がかかるので遅い。この辺りの話は以下の記事に書いた。



ADX命令を使って 減算や大小比較をしたい場合は、メモリ上に比較したい値の2の補数を置く。比較として使う場合、キャリーフラグの意味が通常の減算とは逆になるので要注意。
( 2-1 は $0002 + $FFFF = $0001,C=1 になる。2-3 なら $0002 + $FFFD = $FFFF,C=0 になる )

MC6800と6502では 減算時のCフラグの挙動が逆なのも、これに起因する。


フラグ変化は 普通に2バイト加算の結果になる。以下、実機で確認。LDX #nnnn / ADX mmmm / SWI を機械語で入れて実行します。

$FFFE+$0003=$0002の結果。N=0,Z=0,V=0,C=1 なのでCCは$C1。

$0002 + $FFFD = $FFFF。N=1,Z=0,V=0,C=0 なので CCは$C8。

$0002 + $FFFE = $0000。N=0,Z=1,V=0,C=1 なので CCは$C5。



正しく動いています。

ADX命令の応用

MC6800にはIXレジスタが1本しかないので、ブロック転送には手間がかかった。

MB8861も1本なのだが、事前に転送元と転送先のアドレス差を計算できれば、高速に書ける。

2つのポインタの切り替えをadxで行う。


src	rmb	10
dst	rmb	10
src_dst	fdb	src-dst
dst_src	fdb	dst-src
	org	$XXXX
	ldx	#src
	ldaa	#10
loop:	ldab	0,x
	adx	dst_src
	stab	0,x
	adx	src_dst
	inx
	deca
	bne	loop
	swi

MC6800では2本のポインタをstx/ldxで切り替える必要があり、ダイレクトページ経由でも9サイクルかかる。inxも2つ必要だ。

memcpyなどで使う場合は差の計算に手間がかかるが、大きなサイズのコピーなら効果は大きい。
(引き算できるsdxのような命令があれば、なお良かった)

ADXがあるとCコンパイラは嬉しいか?

とても嬉しい。例えば、関数をコンパイルするときには、最初にローカル変数の分だけスタックを減らし、復帰時に回復する必要がある。

MC6800ではSPやIXは直接 加減算できないので、AccABを使う。AccABへの転送も直接は行えないのでダイレクトページを使う。

以下はスタックを減らす処理だが、復帰時に加算する処理も同じ手間がかかる。でかいし遅い。


func:	sts	@tmp
	ldab	@tmp+1
	ldaa	@tmp
	subb	#10
	sbca	#0
	stab	@tmp+1
	staa	@tmp
	lds	@tmp



ADXがあれば簡単である。増やす方は255以下なら即値が使える。減らす方は2の補数をデータとして置いておく。


m10:	fcb	$fff6
func:	tsx
	adx	m10
	txs
	:
	tsx
	adx	#10
	txs



MC6801/6803だと、2バイト加減算はDレジスタだけが対象なので、XGDXで入れ替えて計算する。

1バイト加算もBレジスタを使うのでちょっと面倒。Bを保存する必要がある場合は、減算と同様に xgdx/addd #10/xgdx が良い。


func:	tsx
	xgdx
	subd	#10
	xgdx
	txs
	:
	tsx
	ldab	#10
	abx
	txs



MB8861が普及していれば、Cコンパイラを書くのは(少しは)楽になっていただろうに。


資料

コメント

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