Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

MC6800のプログラミングテクニック(4) 8bit/16bit混在時の加減算(1)

2024/11/18BASICMASTER, 昔のパソコン

MC6800は8bit演算は得意だが、16bit演算はそこそこで、16bitのアドレス計算は苦手なCPUである。プログラムを書くときはなるべくAccA/Bで収まるようなコードにしたい。

大昔にLSI-C80という8080用のCコンパイラがあって、char変数をなるべく8bit演算してくれる素晴らしいコンパイラだった。これは後にMSX-CとしてOEMされた。

当然6800でもなるべく8bitで済むものは8bitにしたい。そうすると16bit変数と混在させたときの演算が面倒くさくなる。

混在するのはこのような場合である。char同士の加算だが、結果はintで処理しないといけない。


	signed char c1, c2;

	c1 = -128;
	c2 = -128;

	if (c1+c2!=-256)
		return	1;

これを現在のFuzix C compilerでコンパイルすると、if文の括弧内は下記のようなコードになる。signed charだと符号拡張が必要なので長いコードになってしまう。
これをなんとかしたい。


        ldb 0,x
        clra
        asrb
        rolb
        sbca #0
        pshb
        psha
        ldb 1,x
        clra
        asrb
        rolb
        sbca #0
        jsr __plus


場合分けしてみる

正+正の場合

0〜127 + 0〜127 なので、結果は0〜254。符号拡張は上位バイトに0を入れる。結果が128以上の場合はOverflowフラグが立つ。

負+負の場合

-128〜-1 + -128〜-1 なので、結果は-256〜-2。符号拡張は上位に$FFを入れる。Carryフラグが必ず立つ。結果が-129以下ならOも立つ。

正・負が混ざる場合

0〜127 + -128〜-1。結果は -128〜126。OもCも立たない。MSBを見て符号拡張する必要がある。

MOTOROLA社 M6800 Microprocessor Applications Manual 1975年 P. 2-2 より引用

考察

直前にclraを入れて、結果が負のときは$FFにする。これは下記のコードで良さそうである。

まず、負数同士の加算の場合、必ずCarryが立つのでこれを利用して符号拡張する(sbca #0)。
負数以外でOverflowが立つ場合は、正の数同士の加算であり、この場合は上位バイトへの桁上がりは生じないので、上位は$00のままで良い。

その他の場合は、結果の正負に応じて符号拡張する。bmi/bplを使って分岐しても良いが、下記のようにasr/rolでbit7をcarryにコピーした方が短くて速い


	clra
	ldab 0,x
	addb 1,x
	bcs L01
	bvs L02
	asrb
	rolb
L01:	sbca #0
L02:
MC6800のプログラミングテクニック(2) AccBを符号拡張してAccABに入れる | ず@沖縄

追記

後で気がついたけど、NとVを見た方が良い。N==V なら 0拡張、N!=V なら $FF 拡張である。簡単すぎる。モトローラ偉い。


	clra
	ldab 0,x
	addb 1,x
	bge L01
	deca
L01: