PCGやスプライトのデータと定義処理をROMのPage#0に寄せてみた
先日の記事の続きです。以前の記事の「三角関数プログラミング」のサンプルコードをベースに、スプライトとPCGのデータと作成処理をPage#0に寄せてみることにしました。
まずはサンプルをゲットだぜ
https://github.com/sailorman-msx/games/tree/main/src/sample022
それではプログラムの中をのぞいてみることにしましょう
修正箇所はこちら
修正箇所は以下のコードです。
initialize.asm
;----------------------------------------------------------
; 初期処理(お約束コード)
; 当プログラムでは以下のようなページ構成で
; ROMを作成する
; Page#0 : PCG、スプライト作成処理
; Page#1 : プログラムエリア
; Page#2 : プログラムエリア
; Page#3 : 変数領域/サウンド領域/ワークエリア(F380H以降)
; 変数領域とサウンド領域はC000H-DE3FHまでとする
;-----------------------------------------------------------
; プログラムの開始位置アドレスは0x0000
org $0000
;-------------------------------------------
; PCG, スプライトの定義処理
; Page#0に記述する
;-------------------------------------------
include "pcg_graphic2.asm"
include "sprite_define.asm"
include "data_pcg.asm"
include "data_sprite.asm"
;-------------------------------------------
; Page#0の終端に余りがある場合は
; 0x00で埋める
;-------------------------------------------
defs $4000 - $, $00
(修正点)
ORG を 0000Hにして、pcg_graphic2.asm, sprite_define.asm, data_pcg.asm, data_sprite.asm をPage#0内のアドレスにアセンブルされるようコードを配置しなおしました。sprite_define.asm はもともとの sprite.asm からスプライトのパターン定義の部分のみを切り出したソースになっています。最後の defs ですが、指定したサイズ(バイト数)ぶん、特定の値で埋めつくすディレクティブです。
defs 10, $80
↑たとえば、このように記述するとアセンブル結果として、10バイトぶん$80でそのアドレスから埋め尽くされます。
$は「ここのアドレス」という意味でアセンブラは解釈します。
なので
defs $4000 - $, $00
と書くと $4000 - $ で、現在のアドレスからPage#0の終端(3FFFH)までを0で埋め尽くすようにアセンブルしろ。という意味になります。
changepage.asm
;-------------------------------------------
; 使用ページの初期化処理
;-------------------------------------------
ChangePage0Call:
;----------------------------------------------------------------
; ROMカセットのPage#0(0000H - 3FFFH)を
; Page#1(4000H - 7FFFH)から利用できるようにする
; また、同時に変数PAGE0_FUNCにセットされているアドレスをCALLする
; 処理終了後はPage#0は基本スロットのPage#0に戻し
; 基本スロットのPage#1とPage#2をROMのものに切り替える
;----------------------------------------------------------------
(中略)
ld a, ($FFFF)
cpl
and 00111111B
ld b, a
ld a, d
and 11000000B
or b
ld ($FFFF), a ; 拡張スロット情報を書き換える
;-------------------------------------------
; 変数PAGE0_FUNCにセットされている
; ROMカセットのPage#0の処理を呼び出す
; (Page#1からPage#0の処理を呼ぶ)
;-------------------------------------------
; PAGE0_FUNCのアドレスをCALLするため
; レジスタをいったん退避
push af
push bc
push de
push hl
;-------------------------------------------
; ROMカセットのPage#0のサブルーチンを呼び出す
; PAGE0_FUNC に呼び出し先アドレスをセットしておくこと
;-------------------------------------------
; BCレジスタにPage0FuncRetAddrのアドレスをセットして
; スタックにPUSH後、JPする
; JP先ではRETでBCレジスタのアドレスをPOPしそこにジャンプする
ld bc, Page0FuncRetAddr
push bc
ld hl, (PAGE0_FUNC)
jp (hl)
Page0FuncRetAddr:
nop
;-------------------------
; 基本スロット情報と拡張スロット情報を元の状態に戻す
;-------------------------
pop hl
pop de
pop bc
pop af
ld a, e
out ($A8), a
これは今回新設となったソースコードです。
前回記事のPage#0の利用方法のサンプルをベースとして、ChangePage0Callというサブルーチンを新規に作成しました。このサブルーチンを呼び出す場合は、事前にPAGE0_FUNCという変数にCALL先のアドレスをセットして呼び出すと、Page#0をROMのPage#0に切り替えて、PAGE0_FUNCに格納されているアドレスをCALLします。CALL先からRETしてきたら、Page#0は基本スロットのPage#0(BIOSサブルーチンが入ってるページ)に切り替えて、Page#1とPage#2はROMのページを使えるようにして処理を終了しています。
ChangePage0Callの使用例は次のような感じです。
initialize.asm の抜粋
;-------------------------------------------
; PCGの定義
;-------------------------------------------
; ひらがなフォントを作成する
ld a, 2
ld (WK_VALUE08), a
ld hl, CreateCharacterPattern
ld (PAGE0_FUNC), hl
call ChangePage0Call
ld hl, InitialPCGDatas
ld (PAGE0_FUNC), hl
call ChangePage0Call
xor a
ld (WK_VALUE08), a
ld hl, CreateCharacterPattern
ld (PAGE0_FUNC), hl
call ChangePage0Call
; 英数フォントを作成する
ld a, 1
ld (WK_VALUE08), a
ld hl, CreateCharacterPattern
ld (PAGE0_FUNC), hl
call ChangePage0Call
;-------------------------------------------
; スプライトの定義
;-------------------------------------------
ld hl, CreateSpritePattern
ld (PAGE0_FUNC), hl
call ChangePage0Call
変数PAGE0_FUNCは以下の箇所で定義しています。
variable_define.asm 抜粋
;--------------------------------
; ここから変数
;--------------------------------
DEFVARS $C000
{
; Page#0利用時の変数
PAGE0_FUNC ds.w 1 ; 2バイト Page#0のサブルーチンアドレス
; H.TIMI関連
H_TIMI_BACKUP ds.b 5 ; 5バイト H.TIMIバックアップ用領域
VSYNC_WAIT_CNT ds.b 1 ; 1バイト H.TIMI垂直同期待ちフラグ
WK_GAMESTATUS ds.b 1 ; 1バイト ゲーム進行ステータス
アセンブル結果は巨大になる
当たり前ですが、Page#0($0000 - $3FFF)までのデータ1を必ずROM上に保持する必要がありますのでアセンブル結果のバイナリは大きくなります。
18680バイトありますが、ROMのPage#0のぶんが16KB必ずアセンブルされるのでこのくらいのサイズになります。
PCGとスプライトのデータ、定義処理をPage#0に寄せた効果
さて、どのくらい効果があったのか確認してみましょう。
できあがったアセンブル結果のディスアセンブル(逆アセンブル)結果は、sample022.dis になります。このファイルはテキストファイルなのでそれでROMのPage#0の使用量がどのくらいになったのか確認できますね。
ROMのPage#0の終わりは05CBHのようです。1483バイトですね。1KBちょい。
それでもまだ15KB近く余ってます。15KBぶんのデータをここに詰め込めるなんて、なんだかオラわくわくしてきたぞ!
実際に使う場合は、BGMが消えてもかまわないとか、そういう割り込みを気にしないタイミングであれば、ChangePage0Callを呼び出せば良いかたちになりますね。
次回以降はこのひながたをベースに新作ゲームを書き連ねていきたいとおもいます。
では、また!ノシ