====== MZ-700 ====== ===== 概要 ===== {{:undefined:mz721.jpg?400|}} ===== MZ-800エミュレータでMZ-700のIPLを使う ===== MZ-700のエミュレータは一時期いくつか存在していたが、気づくと Windows版のいくつかのバイナリだけを残してすっかり消えてしまった。 なので、MZ-800エミュレータを代替品として使用するのが一つの方法であるのかと考えられる。 MZ-800はMZ-700モードを持つ上位互換機であるので、理屈としてはMZ-700のソフトウェアを実行可能である。 但し、正しい作法を守れば、という条件がついている。 単純に、MZ-700のIPLを与えれば動くというものではないので、ここではその作法について説明する。 ==== MZ-800をMZ-700のようになるまで初期化する ==== MZ-800はMZ-700互換であるが、異なるハードウェアである。 巷では、MZ-700の海外版であるかのように紹介されているが、MZ-700の海外版は海外版として存在している。 MZ-800はMZ-700とMZ-1500の中間的なハードウェア構成であり、SN76489ANがあったり、ビットマップVRAMを持っていたり、PCGがあったりと、かなり異なるハードウェアであるため、正しくMZ-700モードに移行させてやらなければ、1Z-009Aは動作しない。 ここでは、行うべき初期化について説明し、1Z-009Aにパッチを当てて、MZ-800 エミュレータ上で動作させる方法を説明する。 これにあたっては、以下のものを用意する必要がある。 * MZ-700実機からコピーした IPL.ROM((モニタ上で S00000FFF0000 として、テープにセーブするなどして取り出す。)) * MZ-800エミュレータ((svn checkout https://svn.code.sf.net/p/mz800emu/code/mz800emu-code として取得する。バイナリでも構わないが1.0.8 REV237以降を推奨する。)) * [[https://www.wildtree.jp/~araki/ipl2.rom|MZ-800を初期化するコード(ipl2.rom)]]。 * MZ-700WINなどで使用するFONT.ROM((MZ-700のCGROMはCPUにはつながっておらず、実機から吸い出すことは困難。)) MZ-800エミュレータで1Z-009Aを動作させるためには、IPL.ROMの先頭3バイトを 0xc3,0x00,0xe8 に書き換え、ipl2.rom内の初期化ルーチンを呼び出す形にパッチを当てる必要がある。 パッチを当てたものを iplp.rom とする。 また、フォントについてもMZ-700WINのものをそのままでは使用できず、フォントのビットマップパターンを左右反転させる必要がある。どのような方法でも構わないが、例えば、以下のような ruby のコードを使用すれば変換できる。 変換後のファイルを cgrom.romとする。 #!/usr/bin/env ruby cgrom_rev = [] open('font.rom') do |f| cgrom = f.read.unpack("C*") cgrom.each do |c| i = 128 j = 1 d = 0 while i > 0 do d |= j if c & i != 0 j <<= 1 i >>= 1 end cgrom_rev.push(d) end end open('cgrom.rom','w')do |f| f.write cgrom_rev.pack("C*") end ファイルが揃ったら、MZ-800エミュレータのメニューからROM→Settings for User Defined...を選んで、Enable User Defined ROMにチェックを入れたら、Seperate ROM Binary Filesを選び、それぞれのROMファイルを指定する。 {{::mz800emu_user_defined_rom.png?400|}} {{::mz800emu_rom_setting.png?400|}} Applyを押せば、1Z-009Aが起動する。 {{::mz800emu_1z-009a.png?400|}} ==== MZ-800の初期化処理について ==== MZ-800は電源投入後、またはリセット直後は MZ-800モードで起動するが、その後、MZ-700モードに移行し、CGROMや周辺デバイスの設定を行った後、ディップスイッチの設定を読んで、MZ-800またはMZ-700それぞれのモードに移行する。 MZ-700のROMを使うのであればディップスイッチの如何に関わらずMZ-700モードへと移行し、本来のモニターに制御を戻すようにしてやればいい。 この時、MZ-700とは異なるMZ-800のハードウェアを適切に設定して、適切なポイントへ制御を戻す必要がある。 具体的に問題となる、MZ-700とMZ-800との違いには以下のものがある。 * MZ-800モードとMZ-700モード * CGROMデータのPCGへの転送処理 * 画面モードの設定と画面クリア * 8255/8253およびSN76489ANの初期化 === MZ-800モードとMZ-700モード === MZ-800はポート0xceに0x08を出力することで、MZ-700モードへと移行する。 このポートはディスプレーモードレジスタにつながっていて、画面モードの設定を行うのだが、0x08を渡すと、メモリーマップがMZ-700相当のものになる。 この時、0x0000~0x0fffと0xe000~0xffffにはROM(0xe000~0x00fはmemory mapped I/O)が割り当てられ、0xd000~0xdfffにはVRAMが割り当てられる。 IPL2.ROMではまずこの処理を行う。 === CGROMデータのPCGへの転送処理 === MZ-800はMZ-700とは異なり、CG-ROMにCPUからアクセスができる。 また表示に使われるデータはPCGのデータが参照されるため、CG-ROMの内容をPCGに設定する必要がある。 MZ-700モードにあるときに、ポート0xe0から値を読むと、0x1000~0x1fffにCG-ROMが、0xc000~0xcfffにPCGがそれぞれ割り当てられるので、この状態で、CG-ROMの内容をPCGに転送する。 転送が終わったら、ポート0xe1から値を読みだせば再び0x1000~0x1fff, 0xc000~0xcfffにDRAMが割り当てられた状態に戻る。 in a,(0e0h) ld hl,01000h ld de,0c000h ld bc,01000h ldir in a,(0e1h) これで、MZ-700のCG-ROMデータ((ここでは、エミュレータ用のデータだが。))が表示に使用されるようになった。 === 画面モードの設定と画面クリア === MZ-700のROM内にも画面クリアーのコードがあるが、アトリビュートだけを0x71(文字色白、背景青)にするだけで、文字データ自体をクリアしない。 MZ-700の場合はリセットでおそらくテキストVRAMがクリアされるのだが、MZ-800ではそうではないため、VRAMをクリアするコードを追加してやる必要がある。 これを行わないとリセット直後に謎の模様が画面に表示されることになる。 === 8255/8253およびSN76489ANの初期化 === MZ-700と異なり、MZ-800は8253のポート0の出力がスピーカーに直結せずに、代わりに SN76489ANの Audio INにつながっている。 また、SN76489ANにクロックの供給も行っている。 このクロックの供給の制御は 8255が行っている。 このため、この関係に従って初期化を行わないと、謎のホワイトノイズが出っぱなしになり、8253にコマンドを送っても音を奏でることがなくなってしまう。 MZ-700の8255の初期化は、8253からSN76489ANへのクロック供給を有効化しないため、これに代わる処理を行い、逆にMZ-700側の初期化ルーチンをバイパスしてやる必要がある。 幸い、1Z-009Aの8253/8255の初期化はほぼ初めに行われるため、モニターのエントリーポイントではなく、この処理の直後に、IPL2.ROM側から戻してやることで、システムの状態を正しく保ったまま処理を継続させることができる。 ==== 初期化コード ==== 上記の処理を以下のように実装した。 ;=========================== ; MZ-800 to MZ-700 ;=========================== .z80 org 0e800h mz700 equ 00052h ; do not return to 004ah stack equ 010f0h cgrom equ 01000h pcgram equ 0c000h mset53 equ 00308h entry: di im 1 ; set interrupt mode to 1 ld a,8 ; set MZ-700 mode out (0ceh),a ld a,1 ; set CRTC to MZ-700 mode out (0cdh),a out (0cch),a out (0e4h),a ; set memory map ld sp,stack ; initialize stack pointer ; init 8255 ld a,08ah ld (0e003h),a ; set 8255 to MZ-700/800/1500 mode ld a,1 ld (0e003h),a ; enable clock supply to SN76489AN ld a,5 ld (0e003h),a ; enable timer interrupt ; init 8253 ld de,0 call mset53 ; init PIO ld bc,04fch ld hl,piodat otir ld bc,04fdh otir ; init SIO ld a,1 out (0f7h),a xor a out (0f7h),a ; init PSG (SN76489AN) ld b,4 ld a,09fh psgset: out (0f2h),a add a,020h djnz psgset ; init screen ld hl,0d800h ld de,0d000h ld bc,0400h cls_loop: ld (hl),71h ; set fgc=7/bgc=1 inc hl xor a ld (de),a ; erase vram inc de dec bc ld a,b or c jr nz,cls_loop ; copy CGROM to PCG in a,(0e0h) ld de,pcgram ld hl,cgrom ld bc,1000h ldir in a,(0e1h) jp mz700 org 0e900h piodat db 000h,0cfh,03fh,007h,000h,0cfh,000h,007h end