画面表示

画面表示周りのハードウェア構成

 MZ-700の画面表示能力は、40桁×25行のテキスト画面のみです。VRAMの D000h〜D3E7h にディスプレイコードを、D800h〜DBE7h にアトリビュートを書くと、指定の文字が指定の文字色・背景色で表示されます。アトリビュートVRAMのビット配置は以下の通り。
アトリビュートVRAM
Bit76543210
信号ATB文字色
背景色
カラー番号
0:黒4:緑
1:青5:水色
2:赤6:黄色
3:マゼンタ 7:白
キャラクタセット0 (ATB=0)
キャラクタセット1 (ATB=1)

 ディスプレイコードってなに? と思われるかもしれません。普通テキストVRAMを持つパソコンではASCIIコードをテキストVRAMに書き込めば対応する文字が画面に表示されるように作られているものですが、MZ-700ではそうなっていません。テキストVRAMに書き込む値はASCIIコードとまったく関係のないコードになっており、これをディスプレイコードと呼んでいます。上の表がMZ-700の表示できる全文字です。

 例えば、D000h に 01h を、D800h に 62h を書き込むと、画面の左上に 'A' が黄色の文字・赤色の背景で表示されます。
 D800h に書き込む値を D2h にする(ATBを1にする)と、'a' が黄色の文字・赤色の背景で表示されます。
 モニタのMコマンドでいろいろな値を書き込んで試してみてください。

 座標 (x, y) に対応するVRAMアドレスは、VRAM先頭アドレス + y*40 + x で計算できます。

 これだけ!


VRAMのウェイト

 VRAMの機能はこれですべてです。が、実際にVRAMに大量のアクセスをすると、マシン語でも意外と遅くなります。これは、VRAMアクセスにウェイトがかかるせいです。高速にアクセスするには、VRAMのウェイトに関する仕様を理解する必要があります。

 MZ-700では、CPUがVRAMにアクセスできるのはCRTコントローラがVRAMにアクセスしていないときだけです。CRTコントローラがVRAMをアクセスしている最中にCPUからVRAMにアクセスしようとすると、CPUがアクセスできるようになるまでウェイトがかかり、待たされます。具体的には、水平表示期間はCPUからVRAMにアクセスできず、水平ブランキング期間のみVRAMにアクセスできます。このウェイトは水平表示タイミングのみに依存しており、垂直ブランキング期間であっても発生します。

 CPUから見ると、165クロックのアクセス不能期間と、63クロックのノーウェイトアクセス可能期間が交互に来るように見えます。

 例えば、LD A,(0D000h) を水平表示期間中に実行すると、VRAMに対するメモリリードサイクルが行われた時点でウェイトがかかり、水平ブランキング期間まで待たされます。そして、63クロックのノーウェイトアクセス可能期間の最初の3クロックがメモリリードサイクルにあてられ、命令終了時点での残りのノーウェイトアクセス可能期間は60クロックとなります。

 高速に画面を更新するには、このMZ-700のハードウェアの仕様に合わせた処理を行う必要があります。MZ-700のCPUクロックはCRTコントローラのクロックと同一の水晶発振器から来ているため、CPUの実行クロック数を数えることで、完全に画面表示と同期するプログラムを書くことが可能です。

高速に画面を更新する

 メインメモリからVRAMへの転送を行うことを考えてみます。LDIRでテキスト・アトリビュート全画面分2000バイトを転送しようとすると、ノーウェイトアクセス可能期間に実行されるLDIRは3命令分で、残りはすべてウェイトで消費されます。228クロック(1ラスタ)あたりの転送バイト数は 3 となります。2000バイト転送するので、転送を終えるまでに 2000/3=667ラスタ分かかり、画面全体を更新するのに2.54フレームかかることになります。
 LDIを必要数だけ並べると、1ラスタあたり4バイト転送できることになります(16×4>63ですが、命令実行サイクル中のメモリライトサイクルがアクセス可能期間に入っていればいいのでOKです)。
 POP HL/LD (nn),HL を並べる方法はノーウェイトの環境では最も高速な転送方法ですが、MZ-700のVRAMに対しては6バイト/ラスタの転送レートにとどまります。
 アクセス不能期間に転送データをPOPで読み込み、アクセス可能期間に集中してPUSHで書き込むことで、転送レートを最大11バイト/ラスタまで上げることが可能です。この転送レートなら60fpsで画面を更新することが可能です。
各転送方法で画面全体(2000バイト)を更新するときの速度
転送方法転送可能バイト数/ラスタ最大画面更新速度(fps)
LDIR323.58
LDI431.44
POP/LD (nn),HL647.16
POP/PUSH1186.46

MZ-1500: PCG-RAMのウェイト

 MZ-1500のPCG-RAM (PCGパターンを格納するメモリ) をアクセスするときにも同様のウェイトが発生します。ただしアクセス可能期間が58クロックと少し短くなっています。

 CPUから見ると、170クロックのアクセス不能期間と、58クロックのノーウェイトアクセス可能期間が交互に来るように見えます。
最大転送レートは10バイト/ラスタです。


メインメモリ→VRAMの高速転送 サンプルプログラム


 ;------------------------------------------------------------------------------
 ; メインメモリ上の仮想VRAMを実VRAMに転送する
 ;      仮想VRAMは実VRAMと全く同じ構造とする
 ;      IX, IY以外のすべてのレジスタが破壊される
 ;------------------------------------------------------------------------------
 VRAMTRANS:
        DI
        LD      (L3+1), SP                      ; SP保存

        LD      HL, source_address_text         ; テキスト仮想VRAM 転送元先頭アドレス
        LD      (L1+1), HL
        LD      HL, source_address_attr         ; アトリビュート仮想VRAM 転送元先頭アドレス
        LD      (L2+1), HL
        EXX                                     ; (裏)
        LD      HL, 0D000h + 800h - 1           ; 実VRAM 転送先アドレス
        EXX                                     ; (表)
        LD      A, 91                           ; ループカウンタ 1000÷11≒91
        LD      (0D000h), A                     ; VRAMにダミーのアクセスを行い、同期を取る
                                ;表示期間:ブランク期間 消費クロック
 L0:                            ;   ( 17)        (ループから戻った時点の消費クロック)
        EX      AF, AF'         ;  4( 21)
 L1:    LD      SP, 0000h       ; 10( 31)        テキスト 転送元アドレス
        EXX                     ;  4( 35)        (裏)
        LD      BC, -800h + 11  ; 10( 45)        VRAM転送先 -800h + 11
        ADD     HL, BC          ; 11( 56)        テキストVRAMへ移りつつ転送アドレスを進める
        EXX                     ;  4( 60)        (表)
        POP     AF              ; 10( 70)        データ読み取り[0,1] ※ここからフラグを変化させないこと
        POP     BC              ; 10( 80)        データ読み取り[2,3]
        POP     DE              ; 10( 90)        データ読み取り[4,5]
        POP     HL              ; 10(100)        データ読み取り[6,7]
        EXX                     ;  4(104)        (裏)
        POP     BC              ; 10(114)        データ読み取り[8,9]
        POP     DE              ; 10(124)        データ読み取り[10]
        DEC     SP              ;  6(130)        1バイト進みすぎた分を戻す
        LD      (L1+1), SP      ; 20(150)        転送元アドレスを更新
        LD      SP, HL          ;  6(156)        転送先アドレス
        LD      (HL), E         ;  4(162): 3( 3) データ書き込み[10]
        PUSH    BC              ;         11(14) データ書き込み[8,9]
        EXX                     ;          4(18) (表)
        PUSH    HL              ;         11(29) データ書き込み[6,7]
        PUSH    DE              ;         11(40) データ書き込み[4,5]
        PUSH    BC              ;         11(51) データ書き込み[2,3]
        PUSH    AF              ;         11(62) データ書き込み[0,1] ※ここまで

 L2:    LD      SP, 0000h       ;  9(  9): 1(63) アトリビュート 転送元アドレス
        POP     AF              ; 10( 19)        データ読み取り[0,1] ※ここからフラグを変化させないこと
        POP     BC              ; 10( 29)        データ読み取り[2,3]
        POP     DE              ; 10( 39)        データ読み取り[4,5]
        POP     HL              ; 10( 49)        データ読み取り[6,7]
        EXX                     ;  4( 53)        (裏)
        POP     BC              ; 10( 63)        データ読み取り[8,9]
        POP     DE              ; 10( 73)        データ読み取り[10]
        DEC     SP              ;  6( 79)        1バイト進みすぎた分を戻す
        LD      (L2+1), SP      ; 20( 99)        転送元アドレスを更新
        SET     3, H            ;  8(107)        VRAM転送先 +800h アトリビュートVRAMへ
        LD      SP, HL          ;  6(113)        転送先アドレス
        LD      (HL), E         ;  4(117): 3( 3) データ書き込み[10]
        PUSH    BC              ;         11(14) データ書き込み[8,9]
        EXX                     ;          4(18) (表)
        PUSH    HL              ;         11(29) データ書き込み[6,7]
        PUSH    DE              ;         11(40) データ書き込み[4,5]
        PUSH    BC              ;         11(51) データ書き込み[2,3]
        PUSH    AF              ;         11(62) データ書き込み[0,1] ※ここまで

        EX      AF, AF'         ;  3(  3): 1(63)
        DEC     A               ;  4(  7)
        JP      NZ, L0          ; 10( 17)

 L3:    LD      SP, 0000h                       ; SP復帰
        RET

VRAMアドレス 上位バイトの繰り上がり箇所

 VRAMの範囲はD000h-D3FFhですので、範囲内でアドレスの上位バイトが変化するのは3ヶ所です。これを頭に入れておくと、16ビット演算を8ビット演算で済ますことができたりするかもしれません。
Y\X0


39
0
:
5

6
(16,6)
7
:
11

12
(32,12)
13
:
18

19
(8,19)
20
:
24


戻る