前回 ADPCM 用 fifo の深さが 0x400 word ありましたが、他の fifo と比べて更新頻度がとても遅いので fifo の深さを 0 M4K で最小の深さの 4 word にしました.
4 word にしたところで dead lock している場所が見つかったので直しました(厳密には知っていたけど問題ではないと思い込んでいたので放置してた). 先日シャーロックホームズの探偵講座を解析したら別の場所での dead lock がかかっていたのでそれを直したら、放置状態となっていた複数のソフトの問題も改善いたしました.
EP2C5 は前回から 1 M4K 減りましたので subchannel 用 fifo も割り当てられそうです. 去年ちょっとやってみようとしたのですが、 BIOS の挙動がよくわからず解析したいのに subchannel fifo をサポートしてる mednafen のデバッガが使いづらくてよくわかりませんでした. これはあとで考えます.
ADPCM memory controller の仕様
かなりの試行錯誤がありましたがようやく完成した気がしますので現在の実装の仕様を書いておきます.
基本的なこと - 理論
UperGrafx はエミュレータと異なり大半をハードウェアで実装しております. ソフトのエミュレータの場合、仮想的に時間を止めて共有RAMを自由に操作できるのですが、時間を止められないハードウェアの場合は優先度を決めたりバッファにため込んで処理をする必要があります.
このためソフトウェアエミュレータのソースコードは私が読んで資料にはなりますが、それを手直ししてコンパイルしてハードウェアにあてるというのは根本的に原理が違いますのでできません. だから開発に手間と時間がかかっております.
基本的なこと - データの流れ
下記の流れです.
処理要求
各方面からの要求は複数あります.
- 6280
- RESET
- voice decoder play request (play)
- length register latch
- read address register latch
- write address register latch
- read data to 6280 (write)
- write data from 6280 (read)
- CD-ROM fifo
- write data by DMA (write)
- MSM5205
- read data by decoder (play, read)
memory controller が動いているときも 6280 の要求はとりこぼさないように内部のレジスタで状態を管理する必要があります. idle 状態になったとき上記の 9 通りの処理要求に優先度をつけて順番に処理します. 優先度は下記となっております.
- RESET
- play 中で decoder 行き fifo が full ではないとき
- fifo への書き込み (READ)
- DMA 転送 が有効で CD-ROM fifo が empty ではないとき
- RAM への書き込み (WRITE)
- READ address の更新
- WRITE address の更新
- 6280 からの読みこみ (READ)
- 6280 からの書き込み (WRITE)
memory 転送途中でも制御レジスタと入出力先の fifo の状態で処理を中断する必要があります.
- RESET
- PLAY register = 0
- PLAY ための READ
- decoder 行き fifo が full になる (4 word になったのでこの時間は短い)
- DMA WRITE
- (6280 からの読み書きは 1 byte ですぐおわるので中断しません)
READ と WRITE は RAM を読み書きする間, PLAY は decoder が有効な間は 1 になりまして、status register に反映が必要です. READ と WRITE は(私の実装では) 同時に 1 になりませんが、 READ と PLAY, WRITE と PLAY は同時に 1 になります.
address register と length register
read address register は play と read で RAM を読み込んだときに byte 単位で increment します. address 0xffff の次は 0x0000 になります. length register は RAM を読み込んだときにbyte 単位で decrement します. address 0x0000 の次は 0x0000 のままです.
write address register と length register は write で RAM を書き込んだときに byte 単位で incrementします. address 0xffff の次は 0x0000 です. length register は 0xffff の場合は更新せずに 0xffff のままです.
ADPCM memory controller からの IRQ2 は細かい部分ははしょりますが下記となります.
- 再生全部完了: length register == 0 && decoder 行き fifo.empty == 0
- 再生半分完了は play & ~(length register bit 15)
特記事項
標準の BIOS を利用せずに CD ソフト側でレジスタを操作することがあります. こういう場合 CD ソフト側の出来がヒドイ*1 での制御手順が BIOS と異なる傾向がありますが無難に処理をやりきる必要があります.
シャーロックホームズの探偵講座では下記の対応が必要です.
- 再生途中に address register や length register を更新しようとするのでできるだけ早めに更新する必要があります.
- 6280 からの読み書きには完了フラグがありますが、書き込み完了フラグは無視しているのでデータはできるだけ書き込む必要があります.
- 実機ではある程度取りこぼしている気がする
- エミュレータでは取りこぼしてないようだ
- UperGrafx では処理を間に合わせたので取りこぼしはないとおもう
*1:遊んで名作とか信頼できるメーカーとか関係ないです