アトリビュートVRAM Bit 7 6 5 4 3 2 1 0 信号 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 で計算できます。
これだけ!
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の実行クロック数を数えることで、完全に画面表示と同期するプログラムを書くことが可能です。
各転送方法で画面全体(2000バイト)を更新するときの速度 転送方法 転送可能バイト数/ラスタ 最大画面更新速度(fps) LDIR 3 23.58 LDI 4 31.44 POP/LD (nn),HL 6 47.16 POP/PUSH 11 86.46
CPUから見ると、170クロックのアクセス不能期間と、58クロックのノーウェイトアクセス可能期間が交互に来るように見えます。
最大転送レートは10バイト/ラスタです。
;------------------------------------------------------------------------------ ; メインメモリ上の仮想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 |
Y\X 0 39 0
:
56 (16,6) 7
:
1112 (32,12) 13
:
1819 (8,19) 20
:
24