目次

MZ-700

概要

MZ-800エミュレータでMZ-700のIPLを使う

MZ-700のエミュレータは一時期いくつか存在していたが、気づくと Windows版のいくつかのバイナリだけを残してすっかり消えてしまった。

なので、MZ-800エミュレータを代替品として使用するのが一つの方法であるのかと考えられる。 MZ-800はMZ-700モードを持つ上位互換機であるので、理屈としてはMZ-700のソフトウェアを実行可能である。 但し、正しい作法を守れば、という条件がついている。 単純に、MZ-700のIPLを与えれば動くというものではないので、ここではその作法について説明する。

なお、mz-800emuは2.0.x-previewから mz700emu-ntsc, mz700emu-pal, mz1500emu もビルドできるようになっており、それぞれの機種向けのROMも内包している。1)

ただし、実機から吸い出したROMを使用する場合は、たとえmz700emu-ntscであっても、以下で説明しているパッチを適用する必要がある。

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-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ファイルを指定する。

Applyを押せば、1Z-009Aが起動する。

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モード

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データ5)が表示に使用されるようになった。

画面モードの設定と画面クリア

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
1)
ただしライセンス的に白かどうかは不明。MZ-1500に関しては、書籍でIPLが完全公開されているので問題はないかもしれないが。
2)
モニタ上で S00000FFF0000 として、テープにセーブするなどして取り出す。
3)
svn checkout https://svn.code.sf.net/p/mz800emu/code/mz800emu-code として取得する。バイナリでも構わないが1.0.8 REV237以降を推奨する。
4)
MZ-700のCGROMはCPUにはつながっておらず、実機から吸い出すことは困難。
5)
ここでは、エミュレータ用のデータだが。