現在地

Z80のRレジスタについて


カテゴリー:

Universal MonitorのZ80版にR(egister)コマンド実装していてRレジスタの挙動について誤解していたことがわかりました。そこで今回はZ80のRレジスタについて書いてみることにします。

今さら役に立つ機会なんて無いでしょうけどね。

これまでのRレジスタについての理解はざっとこんなところでした。

  1. リフレッシュアドレスは7ビットなので7ビットのレジスタ(最上位ビットは常に0)
  2. 1命令実行のたびにインクリメントされる
  3. LD A,R, LD R,A命令で値の出し入れができる

はっきり言ってあまり使い道はありません。ゲームなどの簡易乱数発生器として使うか、プロテクトのチェッカルーチンで解析妨害のために使うくらいしか思いつきません。あとは同じ値を代入し続けてソフト的にリフレッシュ動作を不全にするくらいでしょうか。

普通なら無かったことにしても構わないレジスタなのですが...

せっかくR(egister)コマンド作るなら対応してみたくなったのでやってみました。

まずブレーク(Z80ではRST 38Hを使用)命令で退避する必要がありますが、これはAレジスタを経由しなくてはならないので先にPUSH AFが必要です。RST 38Hやこれらの処理の間にもインクリメントされてしまうので補正が必要です。

次にレジスタに値を戻すときにもLD R,Aの後にPOP AF, RETなどが必要で、ここでも補正が必要になります。

さて補正量はいくつにすればよいのでしょう。まずは補正量をともに0にしておいていろいろ試してみます。

最初はブレーク時です。

START:  XOR     A
        LD      R,A
        RST     38H

Rに0を入れた直後にブレークさせます。この場合R=00となるのが自然と考えられますから、試して表示された値が補正量になります。

これは実際に試すと05Hになりました。実測だけでは納得がいかないので以下のソース(関連部分のみ)を数えてみます。

      40/      38 :                     	ORG	0038H
      41/      38 : C3 2D 08            	JP	RST38H

    1309/     82D :                     RST38H:
    1310/     82D : =>TRUE              	IF USE_REGCMD
    1311/     82D :                     
    1312/     82D : F5                  	PUSH	AF
    1313/     82E : ED 5F               	LD	A,R
    1314/     830 : 32 37 FF            	LD	(REGR),A
  1. RST 38Hで+1
  2. 0038HのJPで+1
  3. 082DHのPUSH AFで+1
  4. 082EHのLD A,Rで+2
    Rレジスタは厳密にはM1サイクルのたびにインクリメントされるので、LD A,R命令のようにプレフィックス付きの命令ではプレフィックスの分余計にインクリメントされます。
    これ知識としては知っていましたが、実際に試して確認したのは今回が初めてです。

合計+5となります。

次は実行開始(ブレークからの復帰)時です。

START:  LD      A,R
        RST     38H

R=00に設定しておいて実行します。LD A,R命令のデコード時にRは+2されるのでR=00の状態で実行すればA=02とならなくてはなりません。

この場合の補正値は02Hでした。同様に見てみます。

     388/     30D : 3A 37 FF            	LD	A,(REGR)
     389/     310 : ED 4F               	LD	R,A
     390/     312 : F1                  	POP	AF
     391/     313 : C9                  	RET			; POP PC

Rレジスタへの代入後のインクリメントは次のようになります。

  1. 0310HのLD R,Aは+2された後に代入されるので+0
  2. 0312HのPOP AFで+1
  3. 0313HのRETで+1

合計は+2で実測と一致することがわかります。

以上の補正を加えていろいろ確認していたときに不思議なことが起きました。Rレジスタの最上位ビットが立つことがあるのです。

仕様書(Z80 Family Product Specifications Handbook)を確認したところ、Rレジスタの説明として8ビット・「Provides user-transparent dynamic memory refresh. Lower seven bits are automatically incremented and all eight are placed on the address bus during each instruction fetch cycle refresh time.」とあります。

最上位ビットはLD R,Aで書き込んだものがそのまま保持されるようです。

「補正」処理を単純に引き算で行なったために最上位ビットを変化させてしまったようです。仕方ないので最上位ビットは元の値を保存するように変更です。

ここまでできたら以下を確認をしておきます。

START:  XOR     A
        LD      R,A
        LD      A,R
        RST     38H

これをそのまま実行した場合と、LD A,Rの1バイト目の0EDHを0FFHに書き換えてブレークさせた後0EDHに書き戻して継続実行させたときで結果が同一になることを確認しておきます。ブレークが対象プログラムに影響を与えていないことを確かめるためです。

先ほどの仕様書の説明の後半も気になりますね。8ビット分がバスに出力されるということは割り込みか何かで定期的に最上位ビットを反転すれば8ビットリフレッシュできるということか。個人的に未確認ですが、言及している文書見つけました(下記リンク参照)。

というわけで次のようなムダ知識を得てしまったのでした。

  1. Z80のRレジスタの最上位ビットは書いた値が保存される
  2. Z80のRレジスタの最上位ビットはリフレッシュ時にA7に出力される

最後にZ80互換プロセッサの場合について書いておきます。

HD64180, Z180の場合
現物を動かせる環境が無いのでデータシートをもとに書いています。実機動作未確認です。

「the least significant seven bits of the R counter (R) serve to count the number of instructions executed by the HD64180. R is incremented for each CPU op-code fetch cycles (each LIR cycles).」とあるのでソフトウェアからはZ80と同等のようです(LIRはLoad Instruction RegisterのことでZ80のM1と同じ)。

ハードウェアの視点だと違ってきます。Z80ではM1サイクル毎にリフレッシュ(Rレジスタのインクリメントも)し仕様にもRレジスタの値をバスに出力すると書かれているのですが、HD64180はLIRでインクリメントするものの実際のリフレッシュ動作はLIRとは独立に実行されます。

どうやら簡易乱数などの互換性維持のためにソフトウェアから見えるRレジスタはZ80と同じ動作をさせ、実際のリフレッシュアドレスのカウンタは別に持っていると思われます。

Z280の場合
「The Refresh register is used by the Z80 CPU to indicate the current refresh address, but does not perform this function in the Z280 CPU; instead, it is another 8-bit register available for the programmer.」
Rレジスタは単なる(使いにくい)汎用の8ビットレジスタになりました。勝手にインクリメントされたりしないのでAレジスタの一時退避などに使用できるようになりましたが、逆に積極的に利用していたソフトウェアは困ることになります。まぁ前述のように使い道は限られているので問題になることはあまり無いと思いますが...

ただUniversal Monitorは困りますので、CPU判別でZ280と判定された場合には「補正」処理をスキップするようにしています。他のZ80互換プロセッサの対応時には要注意ポイントの一つです。

参考文献・関連図書: 
"Z80 Family Product Specifications Handbook", February 1984, Zilog.
HD64180R/Zデータシート, Hitachi.
"Z280 Preliminary Technical Manual", Zilog.

コメント

言及も何も、公式Databook にそうしろと書いてあります。1992_Zilog_Microprocessors_and_Peripherals (bitsaver にあり) p.1186 Z80-CPU Q&A 参照。他の互換 CPU がどうなっているかの一端は私のとこでまとめてあります。

情報ありがとうございます。
この資料 IFF2 が正常に読めないことがある件で読んだ記憶はありましたが、リフレッシュについては気付いていませんでした。

NS の NSC800 では、R が 8bit でカウントアップするようになっていますね。
あと、I/O空間の 0xBB に割り込み制御レジスタ(ICR)が存在しますが、write only
なので判別には使えないかもしれません。

まさに簡易乱数発生器として使いましたが、値の変化が周期的なので、若干イマイチでしたね。
値の変化が周期なのは、Rレジスタの仕様としてごもっともなのですが。

まぁ本来の用途ではないので仕方ないですね。
それで十分な用途なら使えばいいし、もっと良い乱数が必要ならM系列なんかを書くなりするしかないです。

コメントを追加

Plain text

  • HTMLタグは利用できません。
  • ウェブページアドレスとメールアドレスは、自動的にハイパーリンクに変換されます。
  • 行と段落は自動的に折り返されます。
※ コメントは原則公開です。個別のご相談などは「ご意見・ご要望」からお願いします。