MSX2+ブートシーケンス調査#1（マッパーおよびPPIの初期化）

# はじめに

MSX2+ のブートシーケンスの調査をした内容を記します。

_ただし、今回は「マッパーおよびPPIの初期化」のみです。_

# 前提条件（対象機種）

MSX2+は機種毎にBIOSの内容が微妙に異なる可能性があります。

今回調査対象とした機種は松下電器（※Panasonicブランド）の FS-A1WSX です。

http://usbsecretbase.michikusa.jp/a1wsx/index.html

# スロット構成の調査

MSX2+ のスロット構成（プログラムROM/RAMのレイアウトや拡張スロット有無等）は機種毎に異なるので、先ずはそこを調査する必要があります。

スロット構成の調べ方について、[MSX Datapack](http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=1%BE%CF+%A5%B9%A5%ED%A5%C3%A5%C8) に、

> もし手持ちのMSXがどのようにスロットを使用しているかを知りたい人はマニュアルなどで調べて下さい。

と書かれています。

_なるほど..._

当然ながら、ハードオフで買ったジャンク品にはマニュアルなんて付いていない訳ですが、絶望する必要はありません。

libretro のリポジトリに blueMSX の config.ini が機種毎に置いてあります。

https://github.com/libretro/blueMSX-libretro/tree/master/system/bluemsx/Machines

config.ini の内容を読めばスロット構成が何となく分かります。

```MSX2+ - Panasonic FS-A1WSX/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野郎さん](https://twitter.com/tiny_yarou) の [TINY SLOT CHECKER](https://www.tiny-yarou.com/slotchecker.html) というツールでグラフィカルに確認できるので、config.iniを見るよりそちらの方が手っ取り早いかもしれません。

blueMSXにはmacOS版が無いっぽいので、[CocoaMSX](https://github.com/CocoaMSX/CocoaMSX)で動かしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161417/7db78f39-9ee6-e4c8-8ae4-af6211a0091f.png)

# メインBIOSの全体的な初期化処理の流れ

参考: [MSX Datapack](http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=1%BE%CF+%A5%D6%A1%BC%A5%C8%A5%B7%A1%BC%A5%B1%A5%F3%A5%B9)


```mermaid
graph TB
1_1["マッパーおよびPPIの初期化"] --> 1_2["RAMのサーチ"]
1_2 --> 1_3["システムワークエリアの初期化"]
1_3 --> 1_4["SUB ROMのサーチ"]
1_4 --> 1_5["ROMのサーチ"]
1_5 --> 1_6["スクリーンの設定"]
```

今回は「マッパーおよびPPIの初期化」の調査結果を記します。

# マッパーおよびPPIの初期化

## (1) コードジャンプ

電源が投入後 `Slot0-0` の `0x0000` 番地から実行が始まりますが、割り込みを禁止（DI）後 `0x0416` へジャンプしています。

```z80
di                                      ;[0000] f3
jp      $0416                           ;[0001] c3 16 04
```

BIOS の先頭アドレス寄りの領域は、プログラムからの BIOS 機能のエントリポイントや割り込み（0x0038）のためにリザーブされていてコードをあまり多く書けないので、リザーブ領域以降のメインコードにジャンプする形になっています。

## (2) メモリマッパ初期化

```z80
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
```

1. `Port[0xFF] = 0`
1. `Port[0xFE] = 1`
1. `Port[0xFD] = 2`
1. `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）初期化

```z80
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
```

1. __`Port[0xBB] = 0x08`__
1. `Port[0xAB] = 0x82`
1. `Port[0xA8] = 0x00`
1. __`Port[0xAA] = 0x50`__

__太字部分__ について、[MSX Datapack](http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=1%BE%CF+%A5%D6%A1%BC%A5%C8%A5%B7%A1%BC%A5%B1%A5%F3%A5%B9) に解説が記載されていませんが、以下、それぞれのポート出力にどのような意味があるのか見ていきます。

### `Port[0xBB] = 0x08`

[I/Oマップ](http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=Appendix+A%2E4+I%2FO+%A5%DE%A5%C3%A5%D7)によると、ポート 0xBB は三洋電機製のライトペンと呼ばれるハードウェアに関連するポートのようです。（これはPPIじゃないですね^^;）

ライトペンは MSX2 の頃に仕様化されたデバイスのようですが、MSX2+では廃止されているので深く気にする必要は無さそうです。

### `Port[0xAB] = 0x82`

ポート 0xAB は i8255 のモードセットで 0x82 を OUT する意味については、[MSX Datapack](http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=1%BE%CF+%A5%D6%A1%BC%A5%C8%A5%B7%A1%BC%A5%B1%A5%F3%A5%B9)で次のように言及されています。

> ポート0ABHはPPI(i8255)のモード設定レジスタで、
>
> - ポート0A8Hが出力、
> - ポート0A9Hが入力、
> - ポート0AAHが出力
>
> に設定されます。

_先生、そもそもi8255と言われても何のことやらよく分からないのです..._

という訳で先ずは Wikipedia 先生にざっくり教えて貰いましょう。

https://ja.wikipedia.org/wiki/Intel_8255

i8255 は、インテルが開発したプログラマブル・ペリフェラル・インタフェース（Programmable Peripheral Interface）です。

日本語に訳してみると分かりやすいです。

- Programmable: プログラム可能な
- Peripheral: 周辺機器
- Interface: インタフェース

という訳で、もう少し詳しい資料を読んでみましょう。（英語）

https://www.geeksforgeeks.org/programmable-peripheral-interface-8255/

要約すると、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`<br>00: MODE 0<br>01: MODE 1<br>1x: MODE 2|`Group A`<br>Port A<br>1 = input<br>0 = output|`Group A`<br>Port C(U)<br>1 = input<br>0 = output|`Group B`<br>0: MODE 0<br>1: MODE 1|`Group B`<br>Port B<br>1 = input<br>0 = output|`Group B`<br>Port C(L)<br>1 = input<br>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のキーボードの解説](http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=3%BE%CF+%A5%AD%A1%BC%A5%DC%A1%BC%A5%C9%A1%A6%A5%A4%A5%F3%A5%BF%A1%BC%A5%D5%A5%A7%A5%A4%A5%B9)を読む限り、キーボード入力はBIOSコールで行う事しかできないのが表向きの仕様らしいです。

**FS-A1WSX の場合、ポートC (AA) で入力したいキーマトリクス（[MSX Datapackのキーボードの解説](http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=3%BE%CF+%A5%AD%A1%BC%A5%DC%A1%BC%A5%C9%A1%A6%A5%A4%A5%F3%A5%BF%A1%BC%A5%D5%A5%A7%A5%A4%A5%B9)を参照）の行番号を OUT すれば、ポートB (A9) に入力状態が返ります。**

> 念の為、「FS-A1WSX の場合」と限定するエクステンションを入れてますが、実態的にはほぼ全てのMSX, MSX2, MSX2+が同じ仕様という理解で良いと思われます。

[MSX Datapackのブートシーケンスの解説](http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=1%BE%CF+%A5%D6%A1%BC%A5%C8%A5%B7%A1%BC%A5%B1%A5%F3%A5%B9)でこの設定が省略されている理由は、ポートA9, AAの設定が表向きには公開されていない仕様だからだと考えられます。

MSXは（機種依存を回避するために）プログラムでのポートI/Oを許していません。

http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=7%BE%CF+%A5%D7%A5%ED%A5%B0%A5%E9%A5%E0%B3%AB%C8%AF%A4%CE%BD%F4%C3%ED%B0%D5

> 　アプリケーションプログラムが入出力を行う時には、必ずBIOSを使って下さい。BIOSを使う目的は、ハードウェアとソフトウェアを分離し、ハードウェアを変更してもソフトウェアをそのまま使えるようにすることです。

例外的にVDPは（ポート番号を特定アドレスから拾った上で）ダイレクトにI/Oして良いらしいです。

_ただし、市販ゲームソフトのコードをディスアセンブルすると普通にA9,AAのI/Oでキー入力を行っていますし、この他にはPSG音源へのアクセスなどもダイレクトにI/Oしているものしか見たことがないですが..._

# 備考

本当はブートシーケンスの一連の流れを1本の記事で書こうとしたのですが、メチャクチャ長くなりそうなのでここで力尽きました。ニーズがあればこの先の解析記事も書くかもしれません。（完全に誰得情報なのでニーズは無さそうな気がしますが）

あと、BIOSのコード内容をリバースエンジニアリング・ディスアセンブルしている点について、著作権者（※コピーライトを見る限りMicrosoftという認識）に怒られたら消すかもしれません。

> MSXの商標権はMSXライセンシングコーポレーションが有していますがプログラム（BIOS）の著作権はMicrosoftにあるという認識です。（著作権もMSXライセンシングコーポレーションなのかもしれませんが、その辺の詳しいところがよく分かっていません）

# 次回

https://qiita.com/suzukiplan/items/524ff2e2bf911cd13948