MC6800のプログラミングテクニック(27) ループ処理(1)

BASICMASTER

strcmpを見たついでに、ループ処理の話をしよう。まずは単純に文字列の末端を探すループを書いてみる。


  while (*s) {
    s++;
  }

素直にMC6800のアセンブラに落とすとこうなるが、こう書いてはいけない。


loop:
  tst 0,x
  beq break
  inx
  bra loop
break:


ループ末端は分岐命令にする

先のコードはループ1回あたり 7+4+4+4 = 19cyc 必要である。

分岐を最後に移動すると、バイト数は同じだがループ内は 4+7+4 = 15cyc に減る。


  bra start
loop:
  inx
start:
  tst 0,x
  bne loop
break:


先にdexする

コードをよくみると、最初の bra start は inx をスキップしているだけである。

dexしてinxすれば元に戻るので、そのように書き直す。実行時間は同じだが1バイト減る。

inx/dexが遅いんだよな、MC6800。Big Endian なので素直に(トランジスタを節約して)実装すると遅くなるのは仕方ない。


  dex
loop:
  inx
  tst 0,x
  bne loop
break:

文字列の長さが0バイトの場合だけは、元バージョンは7+4=11cycで終了し、こちらは4+4+7+4=19cycかかるので遅い(最初のdex/inxの8cyc分だけ遅い)。

ループ1回あたり4cyc縮むので、2文字以上あれば高速になる。

なるべくtstは使わない

MC6800レジスタを壊さずにメモリ内容をテスト・操作する命令があって便利である。便利だが遅いのである。

上記プログラムの tst を ldaa に変えると、ループ内は 4+5+4 = 13cyc になり、2cyc減る。

AccA,Bが使えるなら、tstの代わりにldaを使うべきである。


  dex
loop:
  inx
start:
  ldaa 0,x
  bne loop
break:


なんでtstが遅いのか?

Motorolaのマニュアルの 命令ごとの CYCLE-BY-CYCLE 表を見るとわかる。

tst命令はaslなどのメモリ操作命令と同一タイミングになっている。たぶんトランジスタ節約のためだろう。

そのためにアドレスバスに再度アドレスを出し、書き込むサイクルが発生していて、これが2サイクル余分にかかる原因となっている。

(もちろん、tst命令では メモリを書き換えないように VMA=0 で保護しているが、実行時間は無駄になる)

Motorola MC6800 8-BIT MICROPROCESSING UNIT (MPU) p.34 TABLE-16 – INDEXED MODE CYCLE BY CYCLEを加工し作成


日立HD6803では不要なメモリサイクルが減ったので、気兼ねなくtstを使えるようになったが、モトローラ版はMC68HC11に至っても遅いままなのが困りものである。

コメント

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