MC6800のプログラミングテクニック(4) 8bit/16bit混在時の加減算(1)
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:
追記
後で気がついたけど、NとVを見た方が良い。N==V なら 0拡張、N!=V なら $FF 拡張である。簡単すぎる。モトローラ偉い。
clra
ldab 0,x
addb 1,x
bge L01
deca
L01:
ディスカッション
コメント一覧
まだ、コメントがありません