MC6800のプログラミングテクニック(17) AccBを符号拡張・Excess128,127
昨今のC言語で普通にcharと書くとsigned charである。イマドキのCPUでは符号拡張のコストはほぼ0なので問題ないのだが、MC6800では大騒ぎである。
chibicc-6800で使っているのは下記のコード。ASR/ROLでbit7をcarryにコピーする。サイズは5bytes、実行時間は8cycle。
clra ; 2 1
asrb ; 2 1
rolb ; 2 1
sbca #0 ; 2 2
Excess 128
6502.orgのforumで知ったのだが、Excess 128というテクニックがある。
1バイトのsigned charの範囲は -128〜127 だが、これを 0〜255 に変換して作業し、最後に128を引く。浮動小数点演算の指数部の下駄履きと同じ考えだ。
この考えで、符号拡張してみよう。
eorb #$80 は (キャリーを無視すれば)addb #$80 と一緒。その後、128を引けば符号拡張できる eorb にしているのは後々の布石である。
8cyc,7bytes なので シフトした方が良さそうだが、続きがある。
clra eorb #$80 subb #128 sbca #0
定数加算が続く場合
符号拡張のあとに定数加算が続く場合がある。例えば、配列の添字としてsigned charを使ったときだ。
int sub(char x) { static unsigned char a[] = "0123456789abcdef"; // staticなのでアドレスは定数になる return a[x]; }
現状のchibicc-6800だと、下記のコードになる。符号拡張して、配列のベースアドレスと足している。ベースアドレスは定数である。
ldab 0,x clra asrb rolb sbca #0 addb #<__L_45 adca #>__L_45 stab @tmp1+1 staa @tmp1 ldx @tmp1 clra ldab 0,x
先の、Excess 128形式の符号拡張は最後に128を引いていたが、これは-128($FF80)を足しても良い。下記のコードになる。
addb/adcaの連続はpeep hole optimizerでまとめられるので、addb #<__L_45+$80 / adca #>__L_45+$FF になる。
実質的に、符号拡張が4cyc,3bytesでできることになる。素晴らしい!
ldab 0,x clra erob #$80 addb #$80 adca #$FF addb #<__L_45 adca #>__L_45 stab @tmp1+1 staa @tmp1 ldx @tmp1 clra ldab 0,x
減算の場合
signed charの加算はまだしも、減算だともっと大騒ぎだ。
int sub(char x) { static unsigned char a[] = "0123456789abcdef"; return a[15-x]; }
現在の chibicc-6800 は下記のコードを出す。符号拡張して、2の補数を取って加算している。14cyc, 9bytes使う。
ldab 0,x clra asrb rolb sbca #0 nega negb sbca #0 addb #<15+__L_45 adca #>15+__L_45 stab @tmp1+1 staa @tmp1 ldx @tmp1 clra ldab 0,x
unsigned charなら、アドレス計算はこれだけで済む。大差だ。
ldab #<16 clra subb 0,x sbca #0 addb #<__L_45 adca #>__L_45
減算のExcess 127
負数の場合は、ちょっとコードが変わる。eor #$80 ではなく、eor #$7f を行う。
すると、-128〜127 (減算なので+128〜-127)が、255〜0 になる。本来の値よりも127多い。これを加算して最後に127を引けば良い($ff81を足す)
先のコードで符号拡張+2の補数の部分がこうなる。8cyc,7bytes。素晴らしい。
ldab 0,x eorb #$7f clra addb #<$ff81 adca #>$ff81
配列アドレス計算まで入れると、こうなる。いやー、短い。コンパイラを修正して、このコードが出るようにしたい。
ldab 0,x eorb #$7f clra addb #<$ff81+15+__L_45 adca #>$ff81+15+__L_45 stab @tmp1+1 staa @tmp1 ldx @tmp1 clra ldab 0,x
ディスカッション
コメント一覧
まだ、コメントがありません