Z80アセンブラでは、1つの命令の置き換えだけで実行速度が明確に変化することが多いです。特に多用するのはインクリメントやデクリメントといった、アドレスを±1する命令だと思います。また、アドレス演算では ADD HL,DE のような16bitの加減算命令を用いる事も多いかと思います。
命令の中で最も高速なのは、8bitインクリメント/デクリメント命令ですが、アドレスは16bitであるため、桁上がりを考慮すると16bit計算しなければいけない…と思い込んではいませんか?ここで考えたいのがアライメントです。アドレスがいくつかの前提であると指定するだけで、16bit演算を大幅に減らすことが可能となります。
アドレスの指定は org を使います。この命令はアセンブル開始アドレスだけで使っていては、大変勿体ないですよ?
命令の中で最も高速なのは、8bitインクリメント/デクリメント命令ですが、アドレスは16bitであるため、桁上がりを考慮すると16bit計算しなければいけない…と思い込んではいませんか?ここで考えたいのがアライメントです。アドレスがいくつかの前提であると指定するだけで、16bit演算を大幅に減らすことが可能となります。
アドレスの指定は org を使います。この命令はアセンブル開始アドレスだけで使っていては、大変勿体ないですよ?
このように記述すれば、その先に記述したデータやワークのアドレスは、必ず偶数から始まる前提でコーディングできます。つまり…
org ($ + 1) / 2 * 2
このような計算は
inc hl
inc hl
inc hl inc hl
このように書き換えることが出来ます。桁上がりは 0xFF の次に発生します。0xFF は奇数ですから、偶数のアドレスからは桁上がりがあり得ないので、8bit演算で良いというわけです。これの考え方を更に推し進めます。今度はデータやワーク全体が256の範囲内に必ず収まっているとすれば、どうなるでしょうか。アドレス指定は以下のようになります。
inc l
inc hl
inc l inc hl
これで 256境界範囲に入っていることが保証されます。この状態であれば、データサイズが256未満であれば…
org ($ + 255) / 256 * 256
と、全て8bit演算で済ませることが出来るのです。また、この状態では、データまたはワークは必ず 0xNN00 とキリの良いアドレスから開始されているのも保証されますので、データテーブル参照などは、さらに高速化することが出来るようになります。例えば座標計算ですが…
inc l
inc l
inc l inc l
アライメントが 00 から始まっている前提なので、座標テーブルの下位8bitはY座標の2倍のままで、テーブルにアクセスできるというワケなのです。応用としては、例えばサウンドドライバのワークエリアを各チャンネル毎に 128バイトとして 0x00 と 0x80 から始める前提とすれば、inc l / dec l だけでワーク参照できたりします。
org ($ + 255) / 256 * 256
;-----------------------------------------------------------------------
; 座標テーブル
;
VRAMOffset:
dw 0 * 120, 1 * 120, 2 * 120, 3 * 120,
dw 4 * 120, 5 * 120, 6 * 120, 7 * 120,
dw 8 * 120, 9 * 120, 10 * 120, 11 * 120,
dw 12 * 120, 13 * 120, 14 * 120, 15 * 120,
dw 16 * 120, 17 * 120, 18 * 120, 19 * 120,
dw 20 * 120, 21 * 120, 22 * 120, 23 * 120,
dw 24 * 120,
;-----------------------------------------------------------------------
; XY座標から描画アドレスを取得する
; HL = XY座標
; out: HL = VTEXT Address
;
GRPGetVTextAdrs:
ld e, h
ld h, VRAMOffset / 256
sla l
ld a, (hl)
inc l
ld h, (hl)
ld l, a
ld d, 0xF3
add hl, de
ret
この方法は、拙作の Newシティヒーローにも多用しています。ご参考になれば幸いです。
コメント
コメント一覧 (2)
org (($+255)/256)*256
ではないかと愚考いたします。
内藤時浩
がしました