MC6800のプログラミングテクニック(26) 分岐条件の生成(4)

BASICMASTER

条件比較の結果を、Accに入れる話の続きである。

今回は、strcmpのように 負数と正数 を入れたい場合の話。浮動小数点演算でも必要になる。

strcmpはどう書くか(Cバージョン)

strcmpは2つの文字列を文字コード順に比較し、大小関係を 負、0、正の値で返す。

文字列末の判定やポインタ増加のタイミング、戻り値の計算手法でバリエーションはあるが、概ね下記のコードになる。


int strcmp(const char *s1,const char *s2)
{
  while (*s1 == *s2) {
    if (*s1) {
      return 0;
    }
    s1++; s2++;
  }
  return (unsigned char)*s1 - (unsigned char)*s2;
}


アセンブラバージョン(抜粋)

1バイトずつ先頭から見ていくのであれば、引き算して符号拡張して返せば良い。
しかし引き算するとレジスタが壊れてしまうので、なるべく比較を使いたい。符号拡張のタイミングで再計算しても良いが少々ダサい。

また、MC6800はポインタが1つしかないので、1バイト比較ごとにstx/ldxで切り替えると遅くなる。せっかくレジスタは2つあるのだからうまく活用したい。

高速化のためにAccA,Bの両方を使うと下記のプログラムになる。減算ではなく比較なので、符号拡張できない。

仕方がないので、-1 と 1 を固定で返すようにしている。C言語の規格では負と正であれば良いので、これで問題ない。


_strcmp_loop:
        ldx     @tmp2
        ldab    0,x
        ldaa    1,x
        inx
        inx     
        stx     @tmp2
        ldx     @tmp3
        cmpb    0,x
        bne     _strcmp_ne
        tstb    
        beq     _strcmp_eq
        cmpa    1,x
        bne     _strcmp_ne
        inx
        inx
        stx     @tmp3
        tsta
        bne     _strcmp_loop
_strcmp_eq:
        clrb
        clra
        rts                     ; return 0
_strcmp_ne:
        bcs     _strcmp_lt
        ldab    #1              ; return 1
        clra
        rts
_strcmp_lt:
        ldab    #$FF            ; return -1
        tba
        rts

高速化&省サイズ化

上記のルーチンは分岐命令(branch if carry set)を使って C=1 なら -1 を C=0 なら 1 を返している。

_strcmp_ne から最後の rts まで計10バイト。実行時間はどちらの分岐でも13cycである。

せっかく C に情報があるから、これを使ってみる。$00 から C を引けば $FF(C=1)、$00(C=0)になる。これを細工する。


_strcmp_ne:
        ldab #0
        sbcb #0        	; 00 or ff
        tba
        orab #1       	; 00->01, ff->ff
        rts

最後の orab #1 で $00を$01にしている。$FF のときは変わらない。

これで、13cyc, 8bytesである。実行時間は一緒でサイズが2バイト減った。

AccAのときとBのときで処理を分ける?

同一ルーチンで処理するのをやめれば短くなる。どのみち符号しか見ないのだから、AccAに入れて再計算すれば良かろう。符号だけが必要だからAccBの値はなんでも良い。

実行時間は 10 or 12cyc、7bytes。インデックス修飾が遅いんだよな、MC6800。


_strcmp_loop:
         :
        cmpb    0,x
        bne     _strcmp_ne_b
        tstb    
        beq     _strcmp_eq
        cmpa    1,x
        bne     _strcmp_ne_a
       (中略)
         :
_strcmp_ne_b:
        tba
        suba    0,x
        rts
_strcmp_ne_a:
        suba    1,x
        rts



dexを使ってまとめると2バイト減るが、4cyc増えてしまう(16cyc)。inx/dexも遅い。


_strcmp_ne_b:
        tba
        dex
_strcmp_ne_a:
        suba    1,x
        rts


リンク

コメント

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