2020年8月2日日曜日

Z80での PUSH/RET について

Z80エミュレータのテストのために作ったゲームギア・エミュレータのテストの過程で、ゲームのコード解析を結構したのですが、その中で面白かったテクニックとしてPUSH/RETというものがあります。

PUSH: スタックにデータを格納する命令
RET: CALL元へ復帰する命令

RETはCALLから復帰するための命令ですが、戻りアドレスはスタックから取り出すので、「スタックからPOPして得られるアドレス値へジャンプする命令」と解釈することもできます。

つまり、アドレス値をPUSHしてからRETを呼び出せば、「PUSHしたアドレスにジャンプ」することができます。6502には、任意メモリに格納されたアドレスへジャンプする命令が存在しないので、6502であれば割と有用なテクニックだったといえます。

ただ、Z80のプログラムでこのテクニックを利用する意味が分からないです...Z80であれば、任意メモリに格納されたアドレスへジャンプする命令(JP (HL) など)が存在するので。

性能面についても、PUSH/RETを使うメリットはありません。
そもそも、スタックアクセスが遅いので。

例えば、アドレス nn に格納されているアドレスにジャンプしたい場合:

(PUSH/RET)
LD BC, $(nn) ... 20Hz
PUSH BC ... 11Hz
RET ... 10Hz
合計: 41Hz

(JP (HL))
LD HL, $(nn) ... 20Hz
JP (HL) ... 4Hz
合計: 24Hz

上記のように、PUSH/RETだと「17Hz」もの無駄クロックを消費してしまいます。
PUSH(スタックアクセス)がそもそも重い上に、RETも(スタックアクセスするので)重いので、PUSH/RETでは性能的な意味での恩恵が得られることは無い筈です。

なのに何故、あのゲームはZ80だと一見無意味なPUSH/RETを使っていたのか...謎が深まります。(プログラマがFCに慣れてて、Z80をあまり知らない状態で書いたとかそんなオチでしょうけど)

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。

合理的ではないものを作りたい

ここ最近、実機版の東方VGSの開発が忙しくて、東方VGSの曲追加が滞っています。 東方VGS(実機版)のデザインを作りながら検討中。基本レトロUIベースですがシークバーはモダンに倣おうかな…とか pic.twitter.com/YOYprlDsYD — SUZUKI PLAN (...