state save (sound未対応)
概要
M72 のソフトでは V30 の NMI を使ってないのでゲームのステートセーブを実装できそうだと試してみました。
Z80, Z80向け RAM, サウンドデバイス(特に自分が作っていないYM2151)は対応が難しそうなので実装していません。
仕様
- main CPU 領域のみの対応
- save
- 動作に関係のある RAM と CPU レジスタを全て SD カードのファイルへ書き出す
- load
- save で書き込んだファイルを読み込み、 RAM と CPU レジスタへ読み込ませる
実装
ホストCPUの 68000 側ではシステム制御待ちになっています。
- システム制御要求が入ると 68000 は V30 へ NMI を発行。
- V30 は NMI を受付け、作成した NMI ルーチンを実行。
- NMI ルーチンの途中で V30 を停止 (HLDRQ を 有効にする)
- 68000 は HLDAK を見張り、有効になり次第、コンソールを再開する
- s コマンド (save) 実行時に M72 の main 関連 (V30 RAM と VRAM) の内容を SD カードのファイルへ保存する。
- l コマンド (load) 実行時はファイルからRAMへ内容を復帰する。
- V30 再開命令を受け付けると 68000 は HLDRQ を無効にする
- 途中で止まっている NMI ルーチンを再開し、元のプログラムを実行する
NMI ルーチン
大きく分けて3つの流れがあります。
- CPUレジスタとVRAMを RAM へダンプ
- V30 の CPU レジスタ (AX,BX など)を stack へ push
- 68000 から直接参照できない sprite attribute RAM と color RAM を普通の RAM へコピー
- HLDRQ 制御 OUTPUT PORT へ write (この PORT は本物の M72 にはありません)
- CPUレジスタとVRAMを復帰
実際の命令は下記のようになっています。この命令を実行させるために ROM image の NMI vector address は変更します。
org xxxx ;push CPU registers push ax push bx push cx push dx push si push di push bp push ds ;copy stack pointer mov ax,nmiseg mov bx,ramseg mov ds,ax mov [ssoffset],ss mov [spoffset],sp ;copy sprite RAM mov es,ax mov ds,bx xor si,si mov di,dataoffset mov cx,0400h>>1 rep movsw ;copy color RAM mov si,8000h mov cx,0c00h>>1 rep movsw mov si,0c000h mov cx,0c00h>>1 rep movsw ;sleep v30, wakeup TG68 out 24h,al nop nop nop ;wakeup v30 nop nop nop nop ;restore stack pointer mov ds,ax mov ss,[ssoffset] mov sp,[spoffset] ;restore sprite RAM mov es,bx mov si,dataoffset xor di,di mov cx,0400h>>1 rep movsw ;restore color RAM mov di,8000h mov cx,0c00h>>1 rep movsw mov di,0c000h mov cx,0c00h>>1 rep movsw ;pop CPU registers pop es pop ds pop bp pop di pop si pop dx pop cx pop bx pop ax ; sti iret
NMI ルーチンは単純にしましたので、68000がRAMを書き換えなくても毎回内容を復帰することになります。
scroll register と scanline interrupt register は本来 write only なので read できるようにして RAM へ dump することも考えましたが、M72 の特性上、1フレーム当たり2度書き換えるものが大半ですから、ソフトで毎フレーム書き換えると判断しました。よってこの2つの register は state save の対象外です。
実際の動作について
手間取るかと思いきや1発でちゃんと動きました。今回の開発で1発で成功はかなり珍しかったです。
NMI の発生タイミングと復帰タイミングは vblank 割り込みがかかる直前にかけてあります。実際に動かしたところをみるとそこまで厳密にやらなくてもちゃんと動いているみたいです。
やはりサウンドが未対応なので、死んでしまって曲が停まったところで load をすると曲が停まったままゲームが再開してしまいます。かかっていた曲番号を記憶して、再生し直す実装をいれたほうがいいかもしれません。
あとは.... 実CPUとはいえこの手のPCで動くエミュレータぽい機能を入れると、それとの違いがわからなくなります。NMI の実用実験を兼ねて入れましたが、本来はない方がいいかもしれません。(デバッグには便利です)
- 最終更新:2014-12-30 00:13:12