はじめに
MSX2+ のブートシーケンスの調査をした内容を記します。
ただし、今回は「マッパーおよびPPIの初期化」のみです。
前提条件(対象機種)
MSX2+は機種毎にBIOSの内容が微妙に異なる可能性があります。
今回調査対象とした機種は松下電器(※Panasonicブランド)の FS-A1WSX です。
スロット構成の調査
MSX2+ のスロット構成(プログラムROM/RAMのレイアウトや拡張スロット有無等)は機種毎に異なるので、先ずはそこを調査する必要があります。
スロット構成の調べ方について、MSX Datapack に、
もし手持ちのMSXがどのようにスロットを使用しているかを知りたい人はマニュアルなどで調べて下さい。
と書かれています。
なるほど...
当然ながら、ハードオフで買ったジャンク品にはマニュアルなんて付いていない訳ですが、絶望する必要はありません。
libretro のリポジトリに blueMSX の config.ini が機種毎に置いてあります。
config.ini の内容を読めばスロット構成が何となく分かります。
[CMOS]
Enable CMOS=1
Battery Backed=1
[FDC]
Count=1
[CPU]
Z80 Frequency=3579545Hz
[Board]
type=MSX-T9769B
[Video]
version=V9958
vram size=128kB
[Subslotted Slots]
slot 0=1
slot 1=0
slot 2=0
slot 3=1
[External Slots]
slot A=1 0
slot B=2 0
[Slots]
0 0 0 0 84 "" ""
0 0 0 0 32 "" ""
0 0 0 0 34 "" ""
0 0 0 0 26 "" ""
0 0 0 0 24 "Machines/MSX2+ - Panasonic FS-A1WSX/a1wskfn.rom" ""
0 0 0 4 20 "Machines/MSX2+ - Panasonic FS-A1WSX/a1wsbios.rom" ""
0 2 2 2 78 "Machines/MSX2+ - Panasonic FS-A1WSX/a1wsmus.rom" ""
3 0 0 8 22 "" ""
3 1 0 2 20 "Machines/MSX2+ - Panasonic FS-A1WSX/a1wsext.rom" ""
3 1 2 4 42 "Machines/MSX2+ - Panasonic FS-A1WSX/a1wskdr.rom" ""
3 2 2 4 57 "Machines/MSX2+ - Panasonic FS-A1WSX/a1wsdisk.rom" ""
3 3 0 6 142 "Machines/MSX2+ - Panasonic FS-A1WSX/a1wsfirm.rom" ""
多分 [Slots]
の書式はこんな感じでしょうか。
プライマリ △ セカンダリ △ 配置アドレス÷0x2000 △ サイズ÷0x2000 △ 識別ID? △ "パス" △ "?"
吸い出したBIOSをエミュレータに設定して、TINY野郎さん の TINY SLOT CHECKER というツールでグラフィカルに確認できるので、config.iniを見るよりそちらの方が手っ取り早いかもしれません。
blueMSXにはmacOS版が無いっぽいので、CocoaMSXで動かしてみました。
メインBIOSの全体的な初期化処理の流れ
参考: MSX Datapack
今回は「マッパーおよびPPIの初期化」の調査結果を記します。
マッパーおよびPPIの初期化
(1) コードジャンプ
電源が投入後 Slot0-0
の 0x0000
番地から実行が始まりますが、割り込みを禁止(DI)後 0x0416
へジャンプしています。
di ;[0000] f3
jp $0416 ;[0001] c3 16 04
BIOS の先頭アドレス寄りの領域は、プログラムからの BIOS 機能のエントリポイントや割り込み(0x0038)のためにリザーブされていてコードをあまり多く書けないので、リザーブ領域以降のメインコードにジャンプする形になっています。
(2) メモリマッパ初期化
xor a ;[0416] af
out ($ff),a ;[0417] d3 ff
inc a ;[0419] 3c
out ($fe),a ;[041a] d3 fe
inc a ;[041c] 3c
out ($fd),a ;[041d] d3 fd
inc a ;[041f] 3c
out ($fc),a ;[0420] d3 fc
Port[0xFF] = 0
Port[0xFE] = 1
Port[0xFD] = 2
Port[0xFC] = 3
という形でメモリマッパの初期化をしています。
FS-A1WSX のメモリサイズは標準の 64KB なので、メモリマッパは使っていないだろうからメモリマッパの調査は省略します。
私のようなナウいプログラマだと、メモリマッパよりも「何故 xor a
なんだ?」というどうでも良い部分に疑問を持つものと思われますが、これは 「Z80でレジスタAを0クリアするなら xor a
がもっとも合理的な為」 だと考えられます。
xor a
は A と A を排他的論理和(A = A eor A)する命令です。
同値の排他的論理和の結果は必ず 0 になるので、ld a, $00 ---> A = 0 and $00 -----> A = A and 0
と等価ですが、命令コードに落とすと
ld a, $00 ---> $3e, $00 (7clocks) and a -------> $e6, $00 (7clocks) xor a -------> $af (4clocks)
ということで
xor a
が最も高速 & 容量も節約できるので合理的だといえます。
(3) PPI(i8255)初期化
ld a,$08 ;[0422] 3e 08
out ($bb),a ;[0424] d3 bb
ld a,$82 ;[0426] 3e 82
out ($ab),a ;[0428] d3 ab
xor a ;[042a] af
out ($a8),a ;[042b] d3 a8
ld a,$50 ;[042d] 3e 50
out ($aa),a ;[042f] d3 aa
Port[0xBB] = 0x08
Port[0xAB] = 0x82
Port[0xA8] = 0x00
Port[0xAA] = 0x50
太字部分 について、MSX Datapack に解説が記載されていませんが、以下、それぞれのポート出力にどのような意味があるのか見ていきます。
Port[0xBB] = 0x08
I/Oマップによると、ポート 0xBB は三洋電機製のライトペンと呼ばれるハードウェアに関連するポートのようです。(これはPPIじゃないですね^^;)
ライトペンは MSX2 の頃に仕様化されたデバイスのようですが、MSX2+では廃止されているので深く気にする必要は無さそうです。
Port[0xAB] = 0x82
ポート 0xAB は i8255 のモードセットで 0x82 を OUT する意味については、MSX Datapackで次のように言及されています。
ポート0ABHはPPI(i8255)のモード設定レジスタで、
- ポート0A8Hが出力、
- ポート0A9Hが入力、
- ポート0AAHが出力
に設定されます。
先生、そもそもi8255と言われても何のことやらよく分からないのです...
という訳で先ずは Wikipedia 先生にざっくり教えて貰いましょう。
i8255 は、インテルが開発したプログラマブル・ペリフェラル・インタフェース(Programmable Peripheral Interface)です。
日本語に訳してみると分かりやすいです。
- Programmable: プログラム可能な
- Peripheral: 周辺機器
- Interface: インタフェース
という訳で、もう少し詳しい資料を読んでみましょう。(英語)
要約すると、i8255とは 「3本のポート(A, B, C)で色々な機器と繋げることができるインタフェース」 ということのようです。
そして、i8255 のモードセットは MSB (最上位ビット) が 0 か 1 かで意味が異なるようです。
- MSB = 0 (I/O モード)
- ポートA〜Cの方向(input/output)やモードを設定する
- MSB = 1 (Bit Set/Reset モード)
- ポートCの特定ビット(0〜7)を set(1) にしたり reset(0) にしたりできる
今回、モードセットに 0x82 をセットしているので I/O モードになります。
7 6 5 4 3 2 1 0
0x82 = 1 0 0 0 0 0 1 0 ---> MSB が 1 = I/O mode
I/O mode の場合、次のような意味のようです。
bit7 | bit6〜bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|
1 |
Group A 00: MODE 0 01: MODE 1 1x: MODE 2 |
Group A Port A 1 = input 0 = output |
Group A Port C(U) 1 = input 0 = output |
Group B 0: MODE 0 1: MODE 1 |
Group B Port B 1 = input 0 = output |
Group B Port C(L) 1 = input 0 = output |
つまり、0x82 (0b10000010) を OUT した場合、
- Group A
- MODE 0
- Port A:
output
... ポート 0xA8 が出力 - Port C(upper):
output
... ポート 0xAA 上位が出力
- Group B
- MODE 0
- Port B:
input
... ポート 0xA9Hが入力 - Port C(lower):
output
... ポート 0xAA 下位が出力
というモード設定になるようです。
MODE 0: このモードでは,3つのポート(ポートA,B,C)はすべて単純な入力機能または単純な出力機能として動作することができます。このモードでは、割り込み処理能力はありません。
Port[0xA8] = 0x00
ポート 0xA8 (i8255のポートA) は、MSXではプライマリスロットの設定になります。
bit7~bit6 | bit5~bit4 | bit3~bit2 | bit1~bit0 |
---|---|---|---|
Page3 (0xC000~0xFFFF) | Page2 (0x8000~0xBFFF) | Page1 (0x4000~0x7FFF) | Page0 (0x0000~0x3FFF |
Port[0xAA] = 0x50
FS-A1WSX の場合、ポートB (0xA9) と ポートC (0xAA) に接続されているペリフェラル(周辺機器)はキーボードのようです。
ただし、MSX Datapackのキーボードの解説を読む限り、キーボード入力はBIOSコールで行う事しかできないのが表向きの仕様らしいです。
FS-A1WSX の場合、ポートC (AA) で入力したいキーマトリクス(MSX Datapackのキーボードの解説を参照)の行番号を OUT すれば、ポートB (A9) に入力状態が返ります。
念の為、「FS-A1WSX の場合」と限定するエクステンションを入れてますが、実態的にはほぼ全てのMSX, MSX2, MSX2+が同じ仕様という理解で良いと思われます。
MSX Datapackのブートシーケンスの解説でこの設定が省略されている理由は、ポートA9, AAの設定が表向きには公開されていない仕様だからだと考えられます。
MSXは(機種依存を回避するために)プログラムでのポートI/Oを許していません。
アプリケーションプログラムが入出力を行う時には、必ずBIOSを使って下さい。BIOSを使う目的は、ハードウェアとソフトウェアを分離し、ハードウェアを変更してもソフトウェアをそのまま使えるようにすることです。
例外的にVDPは(ポート番号を特定アドレスから拾った上で)ダイレクトにI/Oして良いらしいです。
ただし、市販ゲームソフトのコードをディスアセンブルすると普通にA9,AAのI/Oでキー入力を行っていますし、この他にはPSG音源へのアクセスなどもダイレクトにI/Oしているものしか見たことがないですが...
備考
本当はブートシーケンスの一連の流れを1本の記事で書こうとしたのですが、メチャクチャ長くなりそうなのでここで力尽きました。ニーズがあればこの先の解析記事も書くかもしれません。(完全に誰得情報なのでニーズは無さそうな気がしますが)
あと、BIOSのコード内容をリバースエンジニアリング・ディスアセンブルしている点について、著作権者(※コピーライトを見る限りMicrosoftという認識)に怒られたら消すかもしれません。
MSXの商標権はMSXライセンシングコーポレーションが有していますがプログラム(BIOS)の著作権はMicrosoftにあるという認識です。(著作権もMSXライセンシングコーポレーションなのかもしれませんが、その辺の詳しいところがよく分かっていません)
次回