SSブログ
English Version

ZSIDの制限とZ80のRレジスタ [Z80]

 自作のZ80ボードであるZ80GALを使ってCP/M-80でZSIDを使用中に下記の操作ログに示すようにアセンブル機能でRレジスタの設定ができないことに気が付きました。
 更にメモリ設定機能で "LD R,A" のマシンコードである ED 4F を設定し、逆アセンブルしてみるとRではなくIレジスタへのLD命令として表示されました。"LD A,R"についても同様でした。どうやらZSIDはRレジスタには対応していないようです。

 因みにZSIDMはZSIDに1行ダンプ表示や小文字シンボル対応し、更にMSX-DOS対応のためにZSIDで使用するRSTをRST38からRST28へ変更したものです(Z80GALもRST38はボード側で使用しているので変更が必要)
 詳細は「MSX-DOSに自作スクリーンエディタ移植」を参照してください。

CP/M-80でのZSID操作ログ
  a>zsidm
  ZSIDM Ver 1.4
  #a
  0100  LD I,A
  0102  LD R,A
  ?
  0102  NOP
  0103  NOP
  0104  .
  #l100,103
    0100  LD   I,A
    0102  NOP
    0103  NOP
    0104
  #s100
  0100 ED
  0101 47
  0102 00 ED
  0103 00 4F
  0104 3D .
  #l100,103
    0100  LD   I,A
    0102  LD   I,A
    0104
  #


 何故、ZSIDでRレジスタを弄ろうとしていたかというとRレジスタのインクリメント条件に関して確かめてみたいことがあったからです。
 始めにおさらいとして Z80 のフェッチサイクルを下図に示します。

Z80 Instruction Opecode Fetch

※Zilog's Z80 Family Product Specifications Handbook から引用


 Rレジスタは7bitカウンタでM1サイクル(オペコード フェッチ)毎にインクリメントされますが、プレフィックス付きの命令の場合、1命令で2回インクリメントされます。

 つまりRレジスタの増分は
  1. "XOR A"(AF)等のプレフィックスのない通常の命令では+1
  2. "BIT 0,(HL)"(CB 46)や"LD (IX+0),A"(DD 77 00)等のプレフィックス付きの命令では+2
  3. "BIT 0,(IX+0)"(DD CB 00 46)を実行した場合のRレジスタの増分は?

 上記の疑問を確認するために下記のプログラムを作ってみました。
 この確認試験に使っているZ80GALはシリアル通信のためにタイマー割込みを使っているので割込み処理の影響を無くすためにRレジスタ参照ループ内は割込み禁止にし、またシリアル通信の送信バッファを空にするためにプログラム先頭でwait処理を行っています。

Rレジスタカウントアップ確認プログラム
                        ;+++++++++++++++++++++++++++++++++++++++
                        ; test refresh register
                        ;  Ver 0.01 2021/10/16 by skyriver
                        ;+++++++++++++++++++++++++++++++++++++++

  1000                  BUFADR1 EQU     1000H
  2000                  BUFADR2 EQU     2000H

                                .Z80

  0000'                         ASEG
                                ORG     0100H

  0100                  START:
  0100    01 0000               LD      BC,0
  0103                  WAIT:   ; to be empty serial buf
  0103    10 FE                 DJNZ    WAIT

  0105    0D                    DEC     C
  0106    20 FB                 JR      NZ,WAIT

  0108    AF                    XOR     A
  0109    21 1000               LD      HL,BUFADR1
  010C    CD 0118               CALL    REFTEST
  010F    3E 80                 LD      A,80H
  0111    21 2000               LD      HL,BUFADR2
  0114    CD 0118               CALL    REFTEST
  0117    C9                    RET

  0118                  REFTEST:
  0118    F3                    DI
  0119    06 00                 LD      B,0
  011B    ED 4F                 LD      R,A
  011D    ED 5F         LOOP:   LD      A,R
  011F    77                    LD      (HL),A
  0120    DD CB 00 46           BIT     0,(IX+0)
  0124    23                    INC     HL
  0125    10 F6                 DJNZ    LOOP

  0127    FB                    EI
  0128    C9                    RET


                        END


 ZSIDで実行した結果は下記のようになりました。
 逆アセンブル部分の011Bと011Dのアドレスで'I'と表示されているのは前述のようにZSIDが'R'に対応していないためです。

確認プログラムの実行結果
b>a:zsidm rregtest.com
ZSIDM Ver 1.4
NEXT  PC  END
0180 0100 C1FF
#l100,128
  0100  LD   BC,0000
  0103  DJNZ FE
  0105  DEC  C
  0106  JR   NZ,FB
  0108  XOR  A
  0109  LD   HL,1000
  010C  CALL 0118
  010F  LD   A,80
  0111  LD   HL,2000
  0114  CALL 0118
  0117  RET
  0118  DI
  0119  LD   B,00
  011B  LD   I,A
  011D  LD   A,I
  011F  LD   (HL),A
  0120  BIT  0,(IX+00H)
  0124  INC  HL
  0125  DJNZ F6
  0127  EI
  0128  RET
  0129
#g100,117

*0117
#d1000
1000: 02 09 10 17 1E 25 2C 33 3A 41 48 4F 56 5D 64 6B .....%,3:AHOV]dk
1010: 72 79 00 07 0E 15 1C 23 2A 31 38 3F 46 4D 54 5B ry.....#*18?FMT[
1020: 62 69 70 77 7E 05 0C 13 1A 21 28 2F 36 3D 44 4B bipw~....!(/6=DK
1030: 52 59 60 67 6E 75 7C 03 0A 11 18 1F 26 2D 34 3B RY`gnu|.....&-4;
1040: 42 49 50 57 5E 65 6C 73 7A 01 08 0F 16 1D 24 2B BIPW^elsz.....$+
1050: 32 39 40 47 4E 55 5C 63 6A 71 78 7F 06 0D 14 1B 29@GNU\cjqx.....
1060: 22 29 30 37 3E 45 4C 53 5A 61 68 6F 76 7D 04 0B ")07>ELSZahov}..
1070: 12 19 20 27 2E 35 3C 43 4A 51 58 5F 66 6D 74 7B .. '.5<CJQX_fmt{
1080: 02 09 10 17 1E 25 2C 33 3A 41 48 4F 56 5D 64 6B .....%,3:AHOV]dk
1090: 72 79 00 07 0E 15 1C 23 2A 31 38 3F 46 4D 54 5B ry.....#*18?FMT[
10A0: 62 69 70 77 7E 05 0C 13 1A 21 28 2F 36 3D 44 4B bipw~....!(/6=DK
#d2000
2000: 82 89 90 97 9E A5 AC B3 BA C1 C8 CF D6 DD E4 EB ................
2010: F2 F9 80 87 8E 95 9C A3 AA B1 B8 BF C6 CD D4 DB ................
2020: E2 E9 F0 F7 FE 85 8C 93 9A A1 A8 AF B6 BD C4 CB ................
2030: D2 D9 E0 E7 EE F5 FC 83 8A 91 98 9F A6 AD B4 BB ................
2040: C2 C9 D0 D7 DE E5 EC F3 FA 81 88 8F 96 9D A4 AB ................
2050: B2 B9 C0 C7 CE D5 DC E3 EA F1 F8 FF 86 8D 94 9B ................
2060: A2 A9 B0 B7 BE C5 CC D3 DA E1 E8 EF F6 FD 84 8B ................
2070: 92 99 A0 A7 AE B5 BC C3 CA D1 D8 DF E6 ED F4 FB ................
2080: 82 89 90 97 9E A5 AC B3 BA C1 C8 CF D6 DD E4 EB ................
2090: F2 F9 80 87 8E 95 9C A3 AA B1 B8 BF C6 CD D4 DB ................
20A0: E2 E9 F0 F7 FE 85 8C 93 9A A1 A8 AF B6 BD C4 CB ................
#


 メモリダンプの結果からRレジスタはループ内で +7 づつ増加しています。
 "LD A,R"はプレフィックスが付いていてRレジスタが +2 になるので "BIT 0,(IX+0)" でRレジスタは +2 の値になるということになります。

  LOOP:   LD      A,R     ; +2
          LD      (HL),A       ; +1
          BIT     0,(IX+0)     ; +2
          INC     HL           ; +1
          DJNZ    LOOP         ; +1

 その他、上記の結果から次のことが判ります。
  • RレジスタのMSBは設定値が保持される
  • ダンプの最初の値が02なので"LD R,A"実行後のRレジスタはA+1の値になる(プレフィックスでの+1は上書きされる)
  • 同様に"LD A,R"ではこの命令でRレジスタが+1された値がAレジスタに設定される(命令実行後は+2となる)

★追記 2021/10/17 {
 "LD R,A"実行後はRレジスタはAの値のままで"LD A,R"でRレジスタが+2された後の値がAにロードされているという考え方も成り立つがマシン語のフェッチと実行タイミングを考慮するとこれは考え辛い。上記のようにマシン語実行後リフレッシュ時にRレジスタがインクリメントされると推測する。
}
 実際にM1/やRFSH/等の制御信号をロジアナで確認しようかとも思いましたが「レトロマイコンZ80ボードの構想(その10)CP/M80 BIOS検討2」のコメントに書いたサイトに命令実行時の制御信号状態のデータがあったことを思い出し、アクセスしてみたらURLが変更になっていました。新URLを確認できたのでリンクを貼っておきます。

 これらのデータを見るとM1サイクル数=リフレッシュ回数であり、リフレッシュする毎にRレジスタがインクリメントされるということが良く判ります。

★追記 2022/05/02
 Twitterで得た情報ですが Z80 の動作の詳細が記述されている a detailed look at Z80 instruction timings with the help of a Z80 netlist simulatio のリンクを貼っておきます。


★追記 2021/10/17
 twitterで The Undocumented Z80 Documented の 6.1 R register and memory refresh にプリフィックスが2つの場合のRレジスタの増分について今回の調査結果と同様のことがかかれているとのコメントを頂きました。
 同資料には
 It is unclear whether the Z80 increases the R register before or after putting IR on the bus.
と書かれていますが、RESET_and_NOP.txt (リセット後最初の命令を実行開始するまでの動きを調査)を参照すると、リセットでRが0の状態の直後のNOPでのリフレッシュ時のアドレスが0なのでRレジスタのインクリメントタイミングはRをバス上に出力した後だということが判ります。
※上記のIRはIレジスタとRレジスタのペアのことでリフレッシュ中はIレジスタがアドレスバスの上位に出力されます。


★追記 2021/10/19
 Web上で動作するMSXのエミュレータであるMSXPenでMSX-DOS環境を使って同様の確認を行ってみました。結果は下のキャプチャーのとおりで実機のZ-80と同様でした。
 Rレジスタはゲーム等で簡易乱数として使われることもあるためかエミュレータなのに良く対応できているものですね。

MSXPenでのRレジスタ確認プログラム実行結果


nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。