見出し画像

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を呼び出せば良いかたちになりますね。

次回以降はこのひながたをベースに新作ゲームを書き連ねていきたいとおもいます。

では、また!ノシ


セーラー服が似合うおじさんです。猫好き、酒好き、ガジェット好き、楽しいことならなんでも好き。そんな「好き」をつらつらと書き留めていきます。