PC-9821 のハードディスク相当を復旧する / その3

(その2はあとでかく) ひとまず Compact FlashMS-DOS が BOOT できるようになりましたので現行のパソコンから dd で dump してみました. 筆者は開発環境として msys2 を常用していますので dd なり /dev/sdx というデバイスは普段から利用できます.

実データ

LBA=0, IPL らしい.


LBA=1, パーティションテーブル.

説明はここにちょっとある. https://hp.vector.co.jp/authors/VA013937/editdisk/tech.html

LBA=2, OS 選択起動画面の文字列.


パーティションテーブルの開始シリンダから MS-DOS 6.2 の領域(つまり FAT) が始まる. これは FORMAT.EXE の固定ディスクの領域確保 (つまりいまでいう fdisk) らしい.

ここまでやって1シリンダが何バイトなのか不明だったのと、利用した古い 64MB の Compact FlashMBR なしのフォーマットと PC-98固定ディスクフォーマットと PC/AT固定ディスクフォーマットがまざりまくって、 FAT の先頭が3つありどれかわからなくなったのでやり直します.

 dd if=/dev/zero of=/dev/sdx bs=1M count=2

FAT filesystem の先頭

先頭 2Mbyte を data 0 で埋めた Compact Flash を接続し再度PC-98から固定ディスクの初期化とシステム転送をしてきました.

LBA=0x88, NEC 5.0 (?) の filesystem header

LBA=0x89, NEC 6.2 (?) の filesystem header

LBA=0x8a, FAT16 の cluster chain table

固定ディスク領域マップによるとこの領域はシリンダ 00001-00915, サイズ 00061 とのことです. 1シリンダが 0x11000 byte なのか 0x11200 byte なのか謎ですが filesystem header をみることにします.

JmpBoot 0xeb 0x45 0x90
OEMName "NEC  5.0"
BytesPerSector 1024
SectorPerCluster 2
ReservedSectorCount 1
NumFats 2
RootEntryCount 3072
TotalSector16 60390
Media 0xf8
FATSz16 59
SectorPerTrack 17
NumHeads 8
HideSector 136
TotSec32 0
DriveNumber 128
Reserved1 0x00
BootSignature 0x29
VolumeID 0x29 0xfe 0x07 0x10
VolumeLabel "NO NAME    "
FilesystemType "FAT16   "
BootSign 0x00 0x00
JmpBoot 0xeb 0x45 0x90
OEMName "NEC  6.2"
BytesPerSector 1024
SectorPerCluster 2
ReservedSectorCount 1
NumFats 2
RootEntryCount 3072
TotalSector16 60390
Media 0xf8
FATSz16 59
SectorPerTrack 17
NumHeads 8
HideSector 136
TotSec32 0
DriveNumber 128
Reserved1 0x00
BootSignature 0x29
VolumeID 0x29 0xc0 0x07 0x16
VolumeLabel "NO NAME    "
FilesystemType "FAT16   "
BootSign 0x00 0x00

NEC 5.0 と NEC 6.2 の内容は大きな違いはないのですがその次に cluster chain がある NEC 6.2 を使うことにします.

PC-9821 のハードディスク相当を復旧する / その1

やることはよくある IDE コネクタに Compact Flash を接続するやつです.

2000年ぐらいにハードオフで本体が 500 円だったから買った PC-9821V16, 周辺機器を買いそろえたら結果としてえらい値段になりました. それからも時々 PC-98 ならではの性能で活躍していましたが、 2010年ごろに HDD が死んだこと忙しくなったことが複合して押し入れの奥にいましたが、復旧用のデータが見つかったのでやることにしました.

目的

  • ハードディスクを Compact Flash に代替する
  • DOS のゲームが動くようにする
  • TCP/IP で現行のパソコンと通信できるようにする

Compact Flash の下調べ

Compact FlashIDE port に挿して代用するのは当時からあった気がしますが、このご時世健康なパラレル IDE のハードディスクは手に入らないし、 Flash Memory はえらいやすいのでこれを利用します.

一応、電子回路設計をする立場なので一般ユーザーが相性という曖昧な言葉で片付けるようなことも技術書や仕様書を読んで下調べしました.

Compact Flash (PC card) を IDE port にさすコネクタはそういう用途前提に設計されているので、物理的な形状の変換だけで済みます. 電源電圧も 5V, 3.3V どちらでも動くようになっているのを確認しました.

Compact Flash のカードそのものはよくいわれているようにこの用途では電源投入時に True IDE mode になる Compact Flash が必要です. True IDE mode は規格上必ず実装されている必要があるが、電源投入時にそれであるかは個別の依存とのことです.

そのつぎに PC-98 側の IDE ハードディスクの容量制限があります. Compact Flash もそれらの制限容量以下のものを用意する必要があります. 目的が DOS のゲームであれば容量は 2GB で十分な気がします.

TCP/IP の下調べ

PC-98DOS という時代、 TCP/IP とかいうマイナープロトコルは話題に上がらなかった気がします. Windows でもダイアルアップでインターネットをしていたのか、 LAN をつないで PC-98 から TCP/IP 通信をするというのは個人では珍しかったのではないでしょうか.

時は流れ今更フロッピーディスクでファイルの受け渡しはかったるいです. そもそも今のパソコンにフロッピードライブなんてついてません.

以前 HDD が死ぬ前は Plamo Linux から TCP/IP を利用しておりました. しかしメインの OS は DOS であり、現行のパソコンとファイル転送するには Linux を立ち上げて ftp なり wget なり scp をして、マウントしておいた DOS パーティーションにアクセスというのをやっていましたが、OS 切り替えが面倒でした.

まだ使ってませんが, TEEN というソフトが MS-DOSTCP/IP 通信が出来るということがわかりましたのでファイル転送にはこれを活用しようと思います. こういうのが無料で手に入るって、中古のV16を500円で買ったときは知りませんでした.
http://www.pc88.gr.jp/teen/wiki/index.php

それらが全て落ち着いたら Plamo Linux は今は配布してないので FreeBSD (98) をいれて openssh でつなぐぐらいはやろうと思います. ただこの分野は(Windowsも含めて)わざわざ PC-98 でやる必要がないので微妙なところです.

下調べからの作業の流れ

  • Compact FlashIDE コネクタに挿す
  • MS-DOS が起動するフロッピーを用意して Compact Flash をフォーマットしてシステム転送
  • Compact Flash が BOOT できることを確認したら現行の PC に持っていって dd でディスクイメージを軽く解析
  • そのディスクイメージにツール,ゲーム,通信のデータを大量に入れ再度 dd で書き込む
  • 実機に持っていってそれらが動くことがわかったら TCP/IP 経由で足りないファイルを補充していく

ということを想定しながら部品を買いそろえました. (つづく)

PCE の入力デバイス用ポートの仕様調査

毎度のごとく公式文書をみたわけではなく、インターネット上に転がっている信憑性の低い情報を元にしていますのでこの情報も信憑性は低いです. 実ソフトの逆アセンブルと分析もいまのところしてません.

pinout

+5V, GND, D3:0, Q1:0

software からの仕様は address 0x1ff000 (0xff:$1000) にある. D3:0 は read data bit 3:0 で Q1:0 は write data bit1:0 となっている.

device: 2 ボタンパッド

74157.SEL = Q0
74157.CLR = Q1
D = ボタン4つ x2
  • 出力端子が 74157 の制御線につながっている単純なもの.
  • Q0 = 0 の場合 D3:0 = 4'b000 となる.
  • SEL を page として, 入力端子を切り替える.

device: 6 ボタンパッド

3 ボタンパッドも設計はほぼ同じなのでそれは省略する. モード切替スイッチも省略する.

74157 #10
CLR = Q1
SEL = Q0
xD = ボタン4つx2

74157 #11
CLR = Q1
SEL = Q0
0D = ボタン4つ
1D = 4'b0000

74157 #0
CLR = Q1
SEL = 74163.QA
0D = 74157#10.Q
1D = 74157#11.Q

74163
CLR = H (H固定なので74161を使っても動作は全く同じ)
CLK = Q1
LOAD = H
PE = H
LE = H
  • 74HC157 が 3つあり, ボタンからポートへの流れは (#1.0 @ #1.1) -> #0 -> PCE となる.
  • 74HC163 は increment counter 固定. 初期値が不定で設定ができないため、 page の確認はボタンが何も押されてないこと前提として page1.1 の D3:0 が 4'b0000 を見つけるぐらいだと思う.
  • page 0 か page 1 の切り替えは Q1 を 0->1 にする.
  • page x.0 か page x.1 の切り替えは Q0 で決める.
  • 2ボタンパッド同様 Q0 = 0 の時は D3:0 は 4'b0000 となる.

device: multitap

回路図が見つからなかったのでソースのコメントに頼る.

  • Q0 == 1 && Q1 0 -> 1 の場合 port = 0
  • Q1 == 0 && Q0 0 -> 1 の場合 port += 1
  • multitap の Q1:0 は接続されたデバイスが利用するときのみそこへ Q1:0 を送る仕組みだと思う,
  • port の値が 5 を越えた場合はどうなるか不明

device: memory base 128

serial clock = Q1
serial write data = Q0
  • シリアルデータ送受信デバイス.
  • 他のデバイス同様 Q1 == 1 の時に Q0 書込み, D3:0 の読み込みを行なう.
  • シリアルデータは LSB->MSB に順番で送る
bit  |write data (1bit)                |read data (4bits)
 0- 9|activation data 10'b10_1010_1000 |0000
10   |R/W select 0:write 1:read        |0100
11-20|set address bit 16:7 (bit6:0 = 0)|0000
21-40|set length bit 19:0              |0000
41-  |data * length                    |000d
last |?                                |0000
  • 最初に10 bit 送った後に bit10 の read data が 4'b0100 でデバイスが接続されていることを見つける.
  • addrss は RAM の address bus と同じ 17bit. bit6:0 = 0 で固定.
  • length は byte 単位ではなく bit 単位で計算するらしいので 17 (address: 0x00000-0x1ffff) + 3 (bit: 0 to 7) となる.
  • multitap との連動の場合は memory base 128 と multitap を挿す組み合わせが何通りかあってそこはいまのところよくわからない.

じゅうべえくえすとの敵が出る数の解析

メガトンコインRTAという動画でキノコングという敵が1匹でるべきである場面でそれが2匹でる, その原因は5つもバージョン違いだろう. という考察が書かれていました. 5つは多すぎでおかしいと思ったのでそれを調べました.

バージョン違いはあるが...

5個の根拠として[b]とか[h]とかついているファイル名があると書かれておりましたが、これは dump の手順を間違えているファイルが過去の混乱の遺物として残っているだけなので無視します.

かなり信憑性のある nescartdb は1つ登録があります. そこそこ信憑性のある MAME の hash/nes.xml には2つ登録があります.

この2つを見比べてみましたが、本当にバージョン違いなのか判断には困りました. 命令が増えたり減ったりしているのでそこの差分の部分をアセンブルするから命令とaddressが差分点からずれるていくものが普通のバージョン違いです. これは lda abs (3byte) 命令を jsr abs (3byte) 命令 にしていて ROM の末尾に命令を増やしています.
この手法は第3者がパッチを当てる場合は自分もよくやるんですが、その jsr 命令の中身が何かの計算の補正だったのでプログラマ当人かはわかりませんがたぶん当時の関係者が手をいれたものと思われます. *1

どちらとも敵の数は基本2匹、たまに1匹

両方のバージョンでキノコングが1匹でるはずであろうというところを確認しましたが、基本2匹、たまに1匹出るのでバージョン違いの可能性は低いと思います. (その2つ以外のバージョンがあるならべつの可能性はありそうだけど、1度生産して終わりの販売規模のこのソフトにはちょっと考えられない)

1匹でる条件を調べてみた

エンカウントで trace log を取りました. CPU address $6050 が敵の数なのはわかりました.

F969: lda ($fc), y <- 敵のテーブルのポインタらしい
F96B: lsr a
F96C: lsr a
F96D: lsr a
F96E: lsr a
F96F: lsr a
F970: sta $6050 <- bit7:6 を敵の数にしている

(中略)

8987: lda $6050
898A: clc
898B: adc $6051
898E: adc $6052
8991: rts
8940: cmp #$02
8942: bcc $8986 ;敵の数が2以上か
8944: jsr $f195
F195: lda $038e ;乱数生成
F198: clc
F199: adc #$17
F19B: sta $038e
F19E: lda $21 ;frame カウンタらしい
F1A0: clc
F1A1: adc #$b1
F1A3: adc $5000 ;φ2カウンタ bit7:0
F1A6: sta $21
F1A8: lda $5800 ;φ2カウンタ bit15:8
F1AB: eor $22
F1AD: adc $21
F1AF: eor $1f
F1B1: adc $038e
F1B4: sta $21
F1B6: rts
8947: lsr a
8948: bcs $8986 ;乱数 bit0 == 0 なら減らさないので分岐
894A: lsr a
894B: bcs $8986 ;乱数 bit1 == 0 なら減らさないので分岐
894D: lsr a
894E: and #$03
8950: cmp #$03
8952: beq $8986 ;乱数 bit3:2 == 3 なら分岐
8954: tay
8955: lda $6050, y ;敵を減らすなら $6050 で乱数 bit3:2 == 0 でいてほしい
8958: beq $8986 ;それが 0 なら減らさないので分岐
895A: sec
895B: sbc #$01
895D: sta $6050, y ;敵の数を1つ減らす
8960: bne $8986
8986: rts

乱数生成のサブルーチンはミサイルポッドの確率を出してた動画(じゅうべえくえすとの鉄パイプ乱数を観察)でもでてきたものと同じです. PC (program counter) $8955 の y の値がちょっと気になるのですが変数 $6050 は敵の数で, 変数 $6051, $6052 は未調査ですが敵に関するパラメータだと思います. (別種類の敵の数かも)

このログからの考察ですと、下記のポイントとなります.

  • 敵がでてくるときに乱数を引く
  • 乱数の bit3:0 == 0 の場合は敵の数を1減らす
  • 敵の数が1匹減る条件は 1/16 (6.2%)
  • この命令は通常敵が出るときでも実行する(ボスはやらない)
  • どちらのバージョンもここに違いはない

おまけ:ランダムエンカウントをなくす方法

FA1B: cmp $d2 
FA1D: bcs $fa22 
FA1F: inc $04c9 <= これを nop にするとランダムエンカウントがきえる 
FA22: jmp $fe05

cmp $d2 をユーザー入力にしてスタートボタンを押したときだけ敵が出るようにアレンジするとすごく遊びやすくなると思います.

*1:第3者がやるならエミュレータで動くように無理矢理書き換えるとか、ゲームを有利に進める目的なのでたぶん白

Super System Card の仕様

address は全て21bit絶対表記です.

0x000000-0x03ffff R-  ROM (A)
0x040000-0x07ffff R-  ROM (A, mirror)
0x080000-0x08ffff --  未定義 (B)
0x090000-0x0bffff R-  RAM (C, mirror, read only)
0x0c0000-0x0cffff --  未定義 (D)
0x0d0000-0x0fffff RW  RAM (C)
0x1ff8c0          RW? RAM control register?? (E)
0x1ff8c1-0x1ff8c7 R?  version register (F)
0x1ff8c8          RW? RAM control register?? (E, mirror)
0x1ff8c9-0x0ff8cf R?  version register (F, mirror)

2018年12月11日(C)を改訂.
2019年1月5日(B)を改訂.
2019年3月10日register offset 7 について追加.

address decode に関する考察

  • ROM と RAM の領域は A18 は address decoder はみていないが、 write strobe 制御でみている.
  • 未定義領域(B)は Arcade Card で 0x8000 byte の領域に mirror での IO port が追加される. Super System Card からの出力はしない.
  • mirror 領域は BIOS では参照しないように作られているので全く同じでなくても動作するらしい.
    • DS 英雄伝説2の起動直後に address 0x99000 へ書き込み、再度読み込んだ結果が異なるとフラグを立てて、ゲームの途中で意図的に止まるように組まれている.

register に関する考察

bios の address は 16bit の PC 表記で絶対アドレスは 0x000000-0x001fff に割り当てられているという設定です.

  • これがないと画面で SUPER の文字が出ない.
    • 逆説的に, IFU-30 などではこの address に data を出すということはない.
  • offset 0 は非公式 BIOS で書き込んでいるので RAM の使用を制御できるらしい?
  • offset 5,6 は TG-16 での同名カードとデータが異なる.
    • データの比較は BIOS 内部で完結するので, データが異なっても BIOS の返す結果には影響はない.
  • offset 1,2,3 は BIOS $e05a で参照する. 目的は version の確認.全ての CD ソフトで確認する.
  • offset 5,6,7 BIOS $e0de で参照する. 目的は同じく version の確認だが、Super CD のみ利用可能. version を知るだけなら $e05a で十分でこの確認をしないソフトが結構多い.
  • offset 7, read, bit7 は super system card の種類. 0 が HuCard の Super System Card と Arcade Card Pro, 1 が Duo シリーズ.
    • PI-CD1 はおそらく 1 になる気がする
    • あすか120%の裏技扱いのシステムカードチェックで判別していたので調べた. Arcade Card のレジスタでは区別できないようだ.

CD Graphics 対応のための調査その3

Subchannel の並びの対応は PC ソフト側 HDL 側共に完了しました. いくつか問題があります.

問題1:回路数限界

HDL のコード上、利用回路数はたいしたことがないはずでしたが、 FIFO を追加したところで EP2C5 に収まらないとエラーが出てしまいました. FIFO の RAM 容量ではなく FIFO を構成する回路の利用量が多いことを忘れていました.
開発機の EP2C8 で利用していますが、本当に採用するなら対策をいれる必要があります.

問題2:command 0xdeと RAM 容量限界

開発機では先述の問題を回避できるので、デバッグを続行しました. 次に判明した CDG player の起動時の処理の順番がおかしいみたいです. おかしい原因が私の実装の互換性不足であれば調査して直せばいいのですが....

  • Audio CD player で Graphics を押す
  • 画面が切り替わるので約3秒以内に再生ボタンを押す
    • 押さないとカーソルが DISC ボタン移動して初期化し直す
  • 再生ボタンが押せた場合、 Audio Disc 再生コマンドが走るがその後に comannd 0xde が走る

最後の command 0xde は TOC を参照し MSFC を返します. RAM 容量をけちるためにここは DISC IMAGE を毎回読みにいってデータを返しておりまして、 Audio play 中に command 0xde を発行すると Audio は停まります...
DISC IMAGE を読まずに最初に RAM に load しておけば良いのですが、RAM 容量は先述ではギリギリの状態でしてあまりここにも余裕をおけない状態です. ここを RAM に展開する場合は単純計算で MSFC*1 の各1バイト * 102 で 408 byte もいります. C は 1bit なのと、 S と F は 7bit で済むのでそこに詰めて 306 byte ならまだいいのかもしれませんが...

問題3:仮に動いたとしても実用に値する物なのか

  • CDG player に入るまでに操作が多い
  • CDG player がなんか変
  • 映像描画規格が明らかに貧弱

難しいものです.

*1:Minute 0-99, Second 0-59, Frame 0-74, Control 0-1

CD Graphics 対応のための調査その2

データの並びは仕様書通りに channel R からW (bit5:0) を利用します.
ここで command と instruction があり、instruction は 6 通り定義されているのに規定外のそれが大量に出てきて解釈に困りました.

これはどういうわけか仕様書に書いてないことで, channel R から W のaddressを並び替えるということがあります. cdgtools v0.3.2 の cdgtools.py に deinterleave の記述がありますのでこれにしたがってやります.

  • 並び替えには 1 度に 3 sectors の読み込みが必要です.
  • channel P と Q は並び替えてはいけません.

interleave は address/data bit のわりと規則性のある並び替えに対して使う言葉と思っていたので、先日の .sub ファイルの並びを仕様書通りに並び直すことを interleave と誤って解釈していました. この2つの並び替えはまた別の物です.

mednafen での動作も大体わかりましたので upergrafx にも実装しようと思います. しかし今のイメージファイルは sunchannel の並び準拠のため、イメージファイルの仕様変更及びそれに追従した ikaebi のコード修正と HDL 側 subchannel Q の解読コードの作り替えと結構面倒くさいことになります.

CD Graphics 対応のための調査その1

CD Graphics (別名 CDG, CD-G, CD+G) を実験として対応してみようかと思います. とりあえず medfenam のソースコードや CD Graphics の仕様書などを見てます.
調べたことを書いていきます.

CD-ROM2 fifo

CDDA 再生中(CD-ROM read 中でも入りそうですが..?) に fifo に subchannel data が入りそれを 6280 の port から読み込む.

address 0x1ff802.w.4
subcchannel FIFO IRQ MASK

address 0x1ff803.r.4
subcchannel FIFO status

address 0x1ff807.r.7:0
subcchannel FIFO data (+auto increment)

IRQ2
status と IRQ MASK が共に1の場合 IRQ2 の線が low になる.
  • FIFO data は 1 sector 読み込むと 98 byte の data が入る.
    • data の並びは 0x00, 0x80, subchannel data. data bit7 が 1 になるのは 2番目の data のみ. subchannel data の並びは規格書通り.
  • FIFO status は subchannel data が入ると 1, address 0x1ff807 を読んで fifo が空になったら 0 を設定.
  • FIFO を意図的に空にする条件は現在不明.

subchannel の仕様

  • 1 sector あたり 98 byte の data を持つ. 先頭 2byte は同期信号.
    • 12 byte ごとに P,Q,R,S,T,U,V,W の 8 つに分ける.
    • P と Q はどの CD でも使われている. CD Graphics は R から W も使う.
  • Compact Disc の仕様では data の並びは 1 byte に P から Wの 1bit ずつを保持する. bit7 が P, bit6 が Q ... bit0 が W となる.
  • 各 1bit は MSB ->LSB

subchannel image の仕様

  • パソコン上で CD image を作ると .sub のファイルができるが同期信号を捨てて順番を並べてかえている.
  • byte offset 0 から 11 を P, byte offset 12 から 23 を Q ... という並びで 1 sector あたり 96 byte となる.
  • 経験上 subchannel の data は PCE の CD に限っては(当時の規格として許容される量の)誤りが多い. そのせいなのかドライブによって補正をかける,補正をかけない,全部 data 0にして出すなど対応はばらける.
    • subchannel data は CD-G などの派生規格やコピープロテクト目的ではない限り、あまり使われず出力しない場合も多かった.
    • subchannel data は通常のCDであればなくても再生成が容易である.
    • 一般ユーザーが疑う PCE の CD image の中身が異なる部分は .img の方のデータの中身であって subchannel は調査しないことが多いし、違っていても大した問題ではない.

CD-ROM2 の ADPCM 用(にもつかえる) RAM の転送その3

別件の修正です.主に CD-ROM コントローラから ADPCM 用 RAM を書いてしまえる DMA と呼ばれているやつです. 等幅に書いてある部分の左端の数値は 6280 からの絶対address 0x1ff80x の略記,その次がそこに書かれる data で並ぶ場合は連続で書かれます.

bios, DMA, write pointer 初期化あり

先日の記載と同じです.

8 xx
9 xx
d 3,2,0
1 81 08 xx xx xx xx 00
b 2
(loading)
b 0

d = 3 の時点で write pointer を更新します, その後の 2, 0 は意味があるのかよくわかりません. b = 1 を書いた時点で転送を開始し、 write pointer がずれることはありません.

b = 2 の代わりに b = 1 をする自前コードがたまにあります. がろすぺがそう.

bios, DMA, write pointer 初期化なし

download2 がやってました. bios を使ってるのであまり文句は言えませんが、write pointer の初期化を忘れていそうです.

d 0
1 81 08 xx xx xx xx 00
b 2
(loading)
b 0

この場合は write pointer はその前に使った値のまま使われます. 以前のソースはここで write pointer を更新していておかしかったようです. 普通の RAM が足りなくてキャラデータを ADPCM 用 RAM にいれておいてボスになったらそれを読み込ませる処理をやっているみたいです.

自前コード,DMA, b を書く順番が違う

先日の記載です.

1 81
8 xx
9 xx
d 3,2,0
b 2
1 xx xx xx xx xx 00
(loading)
b 0

address 0x1ff801 に書く順番がちょっと変ですがここは問題になってないので無視します. b = 2 を書いた後に残りの read(6) のパラメータを書きます. この場合も write pointer はずれません. (ずれてたので直しました)

bios, 6280 write

8 xx
9 xx
d 3,2,0
c xx,xx,...

d = 3 のあと d = 2, d = 0 と続くので, write pointer がずれないようです.

自前コード,6280 write

8 xx
9 xx
d 2
a ??
a xx.xx,...
d 0

d = 2 のままなので write pointer が1個ずれて a = ?? によって補正されるようです.
エミュレータ上の解釈は d の bit2 が 0->1 になるときに bit0 が 1 の場合はwrite pointer はずれない, bit0 が 0 の場合は write pointer はずれる. ということになっています.

5つの例を見ての解釈

  • read(6) の発行の前後にかかわらず address 0x1ff80b の w1 か w0 を 1 にすると CDROM FIFO の buffer が ADPCM 用 RAM に書く
  • address 0x1ff80d w1 を 0->1 にすると write pointer を設定し,状態を write standby にする
    • 先日コードまでこの入力は 0x1ff80d.w1 | 0x1ff80b.w1 | 0x1ff80b.w0 としていましたが解釈を変えました
    • write stand by は address 0x1ff80d w1 を 1->0 にするか, address 0x1ff80a を write すると write ready に変わる
  • address 0x1ff80d.w1 を 1->0 にすると 状態を write ready にする

いまのところ address 0x1ff80d.w0 は意味がないという実装にしていますが、これでうまくいかないソフトがでるならエミュレータと同じにすべきだと思います.
この調査は everdrive 持ってる人がプログラム書いて DUO で動かしてくれるとわかるんでだれかやってほしいです.

続 CD-ROM2 の ADPCM 用(にもつかえる) RAM の転送

コブラIIとロードス島(1作目)の停止理由をみたところ原因は下記でした.

  • READ(6) コマンドの転送先を題名の RAM に設定
  • その初期化の一部を BIOS を使わずに直接制御

ADPCM 用(にもつかえる) RAMというまどろこっしい表現はこの RAM へ ADPCM 用の data をいれればボイスが出るのですが、非SUPERソフト*1で普通に使える RAM 容量不足の対策に使っていてボイスに関係ないことが多々あります.

問題のコードは2作品で流用されていて BIOS と違う初期化手順でも正常動作すればなおりそうです. いまは 1 byte ずれててそこで暴走したり停まってました.

bios

8 0
9 0
d 3,2,0
1 81 08 00 1b f5 1b 00
b 2
(loading)
b 0
(6280 read ADPCM RAM)
8 0
9 0
d 8,0

問題の手順

1 81
8 0
9 0
d 3,2,0
b 2
1 08 00 61 35 0f 00
(loading)
b 0
(6280 read ADPCM RAM, used bios)
8
9
d 8,0

別の手順

address 0x1ff80b に data 0x01 を write するもの. 流用コードとちょっと似ている...

1 81
8 0
9 0
d 3,2,0
1 08 00 0f 1b 05 00
b 1

*1:SUPERソフトでも容量不足になったらやっぱり使う