![見出し画像](https://assets.st-note.com/production/uploads/images/126878134/rectangle_large_type_2_050fbf8392272733a422b8874ba196c4.png?width=1200)
MSX-DOSでのプログラミング第2回
ソースコード解析
今回は前回Gitにアップしたソースコードの説明です。
前回アップしましたがちょこちょこと修正したので最新版をゲットしてください。
https://github.com/sailorman-msx/games/tree/main/src/sample019
DOSMAC01.asm
メインとなるプログラムはDOSMAC01.asmです。
基本的にはArkosTracker2のお勉強用の記事のそれと変わりありませんが、ポイントだけ説明します。
0100Hからアドレスが開始している
MSX-DOSプログラムの場合は、ORG(プログラムの開始アドレス)が0100Hになっています。
いままでのROMの場合はORG 4000Hになってました。これはページ#0(0000H-3FFFH)がBIOSやMSX-BASICのインタプリタ領域に割り当てられているためそうする必要がありましたが、MSX-DOSの場合はすべてのページがRAMになっているためページ#0からプログラム領域として活用できます。
ただし、0000H-00FFHまではMSX-DOSが使用されるシステムスクラッチエリアと呼ばれる場所のため、そこは使わないようになっています。
システムスクラッチエリアにはスロット切り替え用のBIOSコール用のコードなどがちりばめられています。またROM用のプログラミングコードとの互換性を保つためそれぞれのサブルーチン呼び出しのアドレスはROMのそれと同じになっています。例えばJP CALLFのアドレスは0030Hですが、これはBIOS-ROMとも同じアドレスです。MSX-DOSよくできてます。
![](https://assets.st-note.com/img/1704595313447-kpCTpYxVDH.png?width=1200)
![](https://assets.st-note.com/img/1704595693833-my9Y1utCpd.png?width=1200)
(DOSMAC01.asm抜粋)
; ========================================
; ワークエリアの上限:
; DISK-BASICでの上限はDE3FHが推奨値
; MSX-DOSでの上限はD405H
; MSX-DOSでのプログラミング時には
; ワークエリアが極端に狭くなるので
; 注意する必要がある
; ========================================
; MSX-DOSプログラムの開始位置アドレスは0x0100
org $0100
Start:
; Main procedure.
; メイン処理
MAIN:
BIOS呼び出しは常にインタースロットコール
前記事でも説明してあるとおり、MSX-DOSプログラムが動作している状態ではすべてのページがMSX-DOSのRAMになっているため、MSX-DOSプログラムからBIOSを呼び出す場合はインタースロットコールで呼び出す必要があります。今回のサンプルでは次のようになってます。
(DOSMAC01.asm抜粋)
;-------------------------------------------
; 画面構成の初期化
;-------------------------------------------
; Initialize screen
; 画面の初期化
ld a, $0F
ld (FORCLR), a
ld a, $01
ld (BAKCLR), a
ld (BDRCLR), a
;SCREEN1,2
ld a,(RG0SAV+1)
or 2
ld (RG0SAV+1),a
ld a, 1 ; SCREEN MODE = 1
ld ix, CHGMOD
call BiosInterSlotCall
(中略)
BiosInterSlotCall:
; インタースロットコールにて
; 呼び出す
; IXレジスタに呼び出し先をセットしてある必要あり
ld iy,(EXPTBL-1) ; MAINROMのスロット
ld de, CALSLT ; 指定したスロットの指定アドレスを呼びだす
; JP (DE)
push de
ret
ちょっとトリッキーなコードですが、BiosInterSlotCallでは、IXレジスタに呼び出したいBIOSサブルーチンのアドレスをセットして、必要であればBIOS呼び出し時に必要なレジスタの値もセットして、CALSLTにジャンプしています。
![](https://assets.st-note.com/img/1704601974260-vn8eLlAulC.png?width=1200)
; JP(DE)
push de
ret
と書いてありますが、PUSHでCALSLTのアドレスをスタックにPUSHしてRETすることでCALSLTのアドレスにジャンプしています。
*呼び出し元にRETしているわけではありません。
トリッキーです。
スタックの応用です。
詳細については過去記事のスタックポインタの記事を参照してください。ちなみに、JP (HL)という命令はあるけれど、存在しない JP (DE)みたいなことをしてみたい。というただそれだけの理由のコードです(汗)
いずれにしても、MSX-DOSプログラムからBIOSを呼び出すときはインタースロットコールが必須である。ということになります。これ重要。
H.TIMIはどーなるの?
H.TIMIですが、割込がかかったタイミングが呼び出し先となるアドレスが表に出てるタイミングかもしれないしそうじゃないかもしれない。という不定な状態であるため、念には念を入れてインタースロットコールで自作のH.TIMI処理(H.TIMIチェイン先とも呼びます)を呼び出しています。
(DOSMAC01.asm抜粋)
;================================
; Initialized H.TIMI Interrupt routine
; H.TIMI割り込み時に呼ばれる処理を初期化する
;================================
INIT_H_TIMI_HANDLER:
push af
push bc
push de
push hl
; Backup H.TIMI original procedure
; もともと存在していたH.TIMI処理を退避する
ld hl, H_TIMI
ld de, H_TIMI_BACKUP
ld bc, 5
ldir
; Override the H.TIMI procedure
; H.TIMI処理処理を書き換える
; ==============================================
; H.TIMIが呼ばれたときに呼び出し先の
; アドレス(ページ)が表に出ているとは限らない。
; そのためインタースロットコールを使って
; 自身が作成したH.TIMIチェーン先のサブルーチンを
; 呼び出す。
; ==============================================
ld a, $F7 ; H_TIMI + 0 <- RST30H
ld (H_TIMI + 0) , a
ld a, (RAMAD3) ; H_TIMI + 1 <- Page#3のスロット
ld (H_TIMI + 1), a
ld hl, H_TIMI_HANDLER
ld (H_TIMI + 2), hl ; H_TIMI + 2 <- 呼び出し先アドレス下位8bit
; H_TIMI + 3 <- 呼び出し先アドレス上位8bit
ld a, $C9 ; H_TIMI + 4 <- RET
ld (H_TIMI + 4) , a
pop hl
pop de
pop bc
pop af
ret
RST 30Hというのがありますが、前述したCALLFサブルーチンの使い方をここで実現させてるだけです。4バイトでインタースロットコール形式で自前のH.TIMIチェイン先を呼び出して、最後の1バイトでRETしてます。
BiosInterSlotCallサブルーチンでは、CALSLTというサブルーチンを呼び出すことでインタースロットコールを実現させていますが、CALLFを使うと5バイトでインタースロットコールが実現できるよ。というやつです。
MSXよくできてますね。。。
さらに、、、
インタースロットコールを使ったあとは必ずEIする
インタースロットコールを使うと機種によっては、割込禁止の状態で戻ってくる場合があるらしく、必ずEIすることを忘れてはいけないようです。
ソースコード中では以下がその場所になっています。
呼び出されたH_TIMI_HANDLERの処理の最後で必ずEIしてます。
(DOSMAC01.asm抜粋)
;=================================
; This program's own H.TIMI hook process.
; At the end of this process, it jumps to the
; original H.TIMI process.
; この処理は独自のH.TIMI処理となる
; この処理の終了後に本来のH.TIMI処理を呼び出す
;=================================
H_TIMI_HANDLER:
(中略)
; ==============================================
; インタースロット呼び出し後で割込がDISABLEになる
; 場合があるため必ずEIして終了する
; ==============================================
ei ; Enable Interrupt.
ArkosTracker2はどうなるの??
便利なサウンドドライバ、ArkosTracker2ですが今までの記事ではROM用のセッティングでビルドしていました。今回はMSX-DOSなので少し修正が必要です。とは、いっても最初の設定ファイルをちょっといじるだけでOKです。ご安心を。
(CompileAT2Files.asm抜粋)
;Compiles the player, the music and sfxs, using RASM.
;No ORG needed.
;This is the music, and its config file.
include "TRAINING_BGM.asm"
include "TRAINING_BGM_playerconfig.asm"
include "TRAINING_SFX.asm"
include "TRAINING_SFX_playerconfig.asm"
;What hardware? Uncomment the right one.
PLY_AKG_HARDWARE_MSX = 1
;Comment/delete this line if not using sound effects.
PLY_AKG_MANAGE_SOUND_EFFECTS = 1
;============================================
; The following configuration parameters are
; required only for the ROM version.
;============================================
; === FOR ROM
; === PLY_AKG_Rom = 1
; === PLY_AKG_ROM_Buffer = #d900
;This is the player.
include "PlayerAkg.asm"
PLY_AKG_Rom
PLY_AKG_ROM_Buffer
の指定をコメントアウトして。rasmして、Disarkして、、
でOK!!!
ArkosTracker2の詳細については過去記事を参照ください。
サンプルを動かしたい
サンプルはasmになっていますが、アセンブルした結果のバイナリファイルをDOSMAC01.COMとしてコピーして、Diskイメージに書き込んでからWebMSXで動かしています。ですが、MSX-DOS.SYSとCOMMAND.COMが権利上の問題で自由配布ではなさそうなのでDSKイメージをGitにはコミットしていません。
読者の皆様のお手元にMSX0があれば良いのですけれど。。。
とりあえず動作させた動画だけ。。こちらになります。
まとめ
とまあ、こんな感じでMSX-DOSではプログラミングするようですね。
おおきく、ざーーーっくりまとめると
・MSX-DOSで動くときは64KBが全部RAMになってる。
・そのためBIOSのROMが見えない。
・なのでBIOSのROMを使う場合はインタースロットコールを使う必要がある。
・インタースロットコールをやると割込がDisableになることがあるので必ずEI命令でEnableにしておく。
・ワークエリア(F380H以降)はROM版のプログラム作成同様にふつーに使える。
・ページ#0の(0100Hから3FFFH)もプログラム領域として使える。ありがとう・・ありがとう・・
フロッピーディスクからのロード処理やセーブ処理については筆者もまだよくわかっていませんので、わかるようになったらまた記事にします。
それができるようになれば720KiBの広大な領域を使ったプログラミングも可能になるはず・・ディスクシステムのゼルダのようなものができるかも・・ゴクリ
では、また!ノシ
いいなと思ったら応援しよう!
![MSXのZ80で何か作る](https://assets.st-note.com/production/uploads/images/165443512/profile_71e620b4702dc58b8c67c13f72890394.jpeg?width=600&crop=1:1,smart)