ファミコン ディスクシステム
RAMアダプタに8KByteのROM(カスタムに内蔵) 32KByteのRAM($6000-$DFFF)、 8KByteのキャラクタRAMのメモリを載せて クィックディスク(QD) ドライブ込みで15、000円はかなり安い またドライブは通信アダプタの底面にあるコネクタ(ロットによっては無くなっている) でも接続可能 RAM、拡張ポート テスト スタートキーとセレクトーキーを押しながらリセットすると実行されます このときにメインRAM$6000-$DFFFのチェック 次にPPU$0000-$1FFFを CPU RAM$C000-$DFFFに転送してチェックを行います エラーがあればOKと表示される所にエラーが出たアドレスが表示されます $0000-$1FFF PPUのアドレス $6000-$DFFF CPUのアドレス 拡張ポートのテストは左からd0-d7の並びになっていて $4026で拡張ポートにデータを書き込み、 $4033で拡張ポートのデータを読み込みます Cf=0にして$FFと左ローテイトで 1つだけビットを0にして他は1にしてポートのチェックを行います ただしd7のBATTRY_SENCEは モータを起動していない為、0(電圧NG)になります ROMの種類 RAMアダプタ内のROMは ファミリーコンピュータ用の旧、新バージョンの2つ ツインファミコンのデモで“Nintendo”と出るのと “Famicom”とでるタイプの2つの計4つがあります ROMのバージョンの判定方法は Iコントローラのスタートキーとセレクトーキーを押しながらリセットすると、 RAM、拡張ポート テスト画面になりますが、 そのテスト画面になる前にIコントローラの右とAを押すと メッセージがでます。 このときDEV 2があれば新バージョン、 数字が出ないのは旧バージョンになります ツインファミコンの方は両方ともDEV 2なので 起動画面が違うだけのようです 若干ROMエントリのアドレスが変っていますので、 そこの部分をコールされると動かない可能性がでます しかし実際に純正ソフトでは使わないようになっているようで 実際問題での不都合はありません 非ライセンスソフトのDISK HACKER Ver1.0では FCBのブロックに$FFがあると 新バージョンではエラーがでます(旧バージョンはそのままコピーが出来ます) バックアップ活用研究のDISK COPYでは RAMアダプタのバージョンに合わせてアドレス変更して対応しています NMI割り込み $E18B ワークエリアの$0100のd7-6(NMIコード)を見て ジャンプするようになっています。 NMIコード $00=RAMアダプタ用 $E18B $40=ゲーム用0 JMP ($DFF6) $80=ゲーム用1 JMP ($DFF8) $C0=ゲーム用2 JMP ($DFFA) IRQ割り込み $E1C7 ディスク アクセスに使用 ワークエリアの$0101のd7-6を見てジャンプします IRQコード $00 =ディスク ロード・スキップの終了 $01~$3F=ディスク ロード・スキップ nnバイト(nn=$01~$3F) *$40 =ディスク1バイト転送 読み込みの場合 A、Xにデータが読み込まれる 書き込みの場合 A にデータをセットする $80 =ディスク ステータスを読む $C0 =JMP ($DFFE) *$40だけPC-下位、PC-上位、PSRを空読みしてRTSを実行($E7A3の割り込みトラップから戻る為) リセット割り込み $EE24 電源を入れるとオートリセットが掛かるので 電源を入れるかリセットを押すとココにジャンプします まずPPUの設定、その他のポートの設定、スタックの設定を行います 次にNMIコードを$C0、IRQコードを$80をセットします リセットコードがあり使用アドレスは $0102-$0103のリセットコードによって動作が変わります 1.$0102が$35以外 RAMアダプタのデモへ行きます。 2.$0102が$35、$0103が$53ならスクロールセット。JMP ($DFFC) 3.$0102が$35、$0103が$ACなら$53にセット、スクロールセットしてJMP ($DFFC) 4.$0102が$35、$0103が$53、$ACでなければ RAMアダプタのデモ 電源を入れると本体RAMの内容が不確定なので$0102と$0103の内容が 特定のデータかチェックして一番最初の起動の判断を行います 次にリセットしたときにRAMアダプタの起動かゲームの再起動が任意に出来ます。 $0102、$0103のデータがリセットコード以外の値(電源をOn)ならデモンストレーションへ $0102が$35、$0103が$ACなら$0103:$53にしてゲームのリセットベクトルへ $0102が$35、$0103が$53ならゲームのリセットベクトルへ スクロールセットは$EAEAのサブルーチンコールを行いますので ゲームではポート$2005のセットは$00FC,$00FDと$EAEAのコールを行い ディスクシステムの基準に倣った方が良いです
拡張I/Oポート $4020:(出力) IRQ タイマ下位 クロックは1.79MHz $4021:(出力) IRQ タイマ上位 $4022:(出力) d:1=IRQタイマカウント開始、0=IRQタイマカウント停止 $4023:(出力) 2C33 タイマーコントロール d7: - d6: - d5: - d4: - d3: - d2: - d1:サウウンドⅠ/Oのアクセス 1=許可、0=禁止 d0:ディスク I/Oのアクセス 1=許可、0=禁止 $4024:(出力) ディスク ライトデータ(/WRITE_DATA) 1バイトのデータをシフトレジスタによって /WRITE_DATAにシリアルデータで転送されます $4023 d0=1 ディスクI/Oアクセス許可 $4025 d2=0 /WRITEGATE データ ライト $4030 d7=1 リード・ライト可能 の条件がそろってないと書き込めません $4025:(出力) ディスク コントロール d7:IRQデータ転送 1=実行する 、0=実行しない d6:CRCレジスタ 1=クリアする 、0=クリアしない d5:不明 (常に1) 1= 、0= d4:CRC-Hコントロール 1=行う 、0=行わない d3:スクロール 1=スクロール-V 、0=スクロール-H d2:/WRITEGATE 1=データ リード 、0=データ ライト d1:/MOTOR 1=モーターの回転停止、0=モーターの回転開始 d0:/RESET 1=リセットを行わない、0=リセットを行う 不明 ほとんど1になっている、CRC転送の実行? 0だとデータ転送が出来ない CRC-Hコントロールを行うと書き込みの場合 CRC-Hが$4024に転送され WaitでCRC-Hをディスクに書き込む? 読み込みの場合 次にロードした$4031のデータとCRC-Hの比較を行い 結果を$4030のd4(同じなら0)に出力する? /RESETは転送タイミングのリセット $4026:(出力) バッテリーコントロール、背面の拡張I/Oライト d7:BATTRY_SENCE 1=オン、0=オフ d6:背面の拡張I/O d5:背面の拡張I/O d4:背面の拡張I/O d3:背面の拡張I/O d2:背面の拡張I/O d1:背面の拡張I/O d0:背面の拡張I/O $4030:(入力)ディスクI/O ステータス d7:ドライブの検知 1=リード・ライト可能、0=リード・ライト不可 d6:ヘッド の検知 1=最後まで移動した 、0=最後まで移動していない d5: d4:CRC-Hチェック 1=エラー有り 、0=エラー無し d3: d2: d1:シフトレジスタ転送 の検知 1=転送中 、0=転送終了 d0:IRQタイマ割り込みの検知 1=発生した 、0=発生していない CRCチェックはCRC-HとCRC上位として読み込んだデータが同じなら0になる? $4031:(入力) ディスク リードデータ(READ_DATA) READ_DATAから転送されたシリアルデータをシフトレジスタによって 1バイトのデータに変換されます $4023 d0=1 ディスクI/Oアクセス許可 $4025 d2=1 /WRITEGATE データ リード $4030 d7=1 リード・ライト可能 の条件がそろってないと読み込めません ???データを書き込んでいる場合(/WRITEGATE=0)はCRC-Lの値 $4032:(入力) ドライブ ステータス d7:不明 0 d6:不明 1 d5:不明 0 d4:不明 0 d3:不明 0 d2:/WRITE_PROTECT 1=カード書き込み禁止 、0=カード書き込み可 d1:/READY 1=内部に移動している 、0=スタート位置 d0:/MEDIA_SET 1=セットされていない 、0=セットされた d6はほとんど1になっている /WRITE_PROTECTはディスクカードのツメが折れていたら1、折れていなければ0 /READY はヘッドが一番外に移動し、内に移動し読み書きのが可能な時に0になる /MEDIA_SET はディスクカードがセットされていなければ1、セットされれば0 $4033:(入力) バッテリーステータス、背面の拡張I/Oリード d7:BATTRY_SENCEの結果 1=電圧 OK、0=電圧 NG d6:背面の拡張I/O d5:背面の拡張I/O d4:背面の拡張I/O d3:背面の拡張I/O d2:背面の拡張I/O d1:背面の拡張I/O d0:背面の拡張I/O $4040~$407F(入出力) 波形メモリ d7:コントロール d6:コントロール d5:メモリd5 d4:メモリd4 d3:メモリd3 d2:メモリd2 d1:メモリd1 d0:メモリd0 $4080 ボリューム、エンベロープ(出力) d7:エンベロープ 1=オン、0=オフ d6:ボリューム増減 1=+1、0=-1 d5:v5 ボリュームまたはエンベロープ d4:v4 d3:v3 d2:v2 d1:v1 d0:v0 $4082 周波数下位 d7:f7 d6:f6 d5:f5 d4:f4 d3:f3 d2:f2 d1:f1 d0:f0 $4081 周波数コントロール+上位 d7:エンベロープ×4 d6:ボリューム、スィープ d5: d4: d3:f11 d2:f10 d1:f9 d0:f8 $4084 MODエンベロープ $4085 MODカウンタ $4086 MOD周波数下位 $4087 MOD周波数コントロール+上位 $4088 MODテーブル $4089 コントロール $408A エンベロープ速度 $4090 ボリュームゲイン $4091 波形Acc $4092 MODゲイン $4093 MODテーブル $4094 MODカウンタゲイン $4095 MODカウンタ $4096 波形メモリテーブル? $4097 MODカウンタ値
ディスク フォーマットFCB部分 まず最初にブロック01、ブロック02が存在します ブロック01にそのディスクのゲーム名、両面ソフトでどの面か、 青色のディスクか黄色のディスクか等の情報が入っています ブロック02はマウントファイル数が書き込まれています ファイル部分 ブロック03がファイル情報、ブロック04がファイルデータになります ブロック03はファイルID、ファイル名、ロードアドレス等が書かれています ブロック04はバイナリデータになります 1つのファイルはブロック03と04の対となります ブロック コードの説明 ------------------------------------------------ GAP : $00 スタートデータ :1バイト $80 ブロックコード :1バイト $01 チェックコード :14バイト *NINTENDO-HVC* メーカーコード :1バイト ゲーム ネーム :4バイト ゲーム バージョン :1バイト ディスク サイド :1バイト 両面 $00=A面、$01=B面)/片面 $00のみ ボリューム(ディスクの順番) :1バイト 2枚以上のソフトで使用 $00から ディスクの種類 :1バイト $00=FMC(ノーマル カード)、$01=FSC(シャッター付きカード) 予備1 :1バイト コールドスタート :1バイト 起動時に読み込む最大ロードナンバ 不明(予備) :5バイト $FF、$FF、$FF、$FF、$FF 製造年月日 :3バイト 国コード :1バイト $49=日本(バーコードと同じか?) 不明 :1バイト $61 地域? 不明 :1バイト $00 場所? 不明 :2バイト $00、$02 不明(各ゲームの情報?) :5バイト 書換えた年月日 :3バイト 店頭販売の場合、製造年月日と同じ 不明 :1バイト 不明 :1バイト $80 書き込んだシステム? ディスクライターのナンバ :2バイト 不明 :1バイト $07 書換えた回数 :1バイト 10進数で書かれている(00=店頭販売のディスク) 実際のディスク サイド :1バイト $00=A面、$01=B面 不明 :1バイト デバグバージョンまたは、プライス:1バイト CRC :2バイト ブロック コード$01は3つに分けると $01-1 *NINTNDO-HVC* $01-2 ディスク アクセス用(メーカーコードからコールドスタートまで) $01-3 メーカー管理用 $01-1はディスクシステムに必要なデータでこれが無いとBIOSからのディスクアクセスが出来ません $01-2はディスクの情報なります ディスクアクセスに必要なデータになります ディスクサイド=$00(A面)、ボリューム=$00でないと起動出来ません ゲーム ネームの最後の1バイトはイベント等を表し $20=通常のディスク $45=E イベント ディスクファックスを使った全国トーナメント $52=R リダクション イン プライス 広告による値引き コールドスタートは起動時に読み込む最大ロードナンバで一括でファイルを読み込みます $0Fの場合、ディスク内のロードナンバ$00~$0Fまで全て読み ロードナンバ$10以上のファイルは読み込みません $01-3は主にメーカー管理用 実際のディスク サイドはディスクライタで両面ソフトの書き換え時にチェックされます もしディスクA面に$01(B面)のデータだとディスクライタはA面の書き換えチェック時にエラーを出します プライスは値段や周辺機器の対応 書き換え回数が00の場合は販売用のディスクの値段となり $01=3400円 $03=3400円(とびだせ大作戦でメガネ同梱版と無しの両方) 01以上の場合は書き換えの値段 $00=500円 $01=600円 帰ってきたマリオブラザースの場合は500円でゲーム内の広告によって-100円なので 書き換え料金は500円扱いになる ------------------------------------------------ GAP : $00 スタートデータ : 1バイト $80 ブロックコード : 1バイト $02 マウントファイル数 : 1バイト 登録されているファイル数 CRC : 2バイト ------------------------------------------------ GAP : $00 スタートデータ : 1バイト $80 ブロックコード : 1バイト $03 ファイルナンバ : 1バイト 一番最初のファイルを$00として以降+1される ロードナンバ : 1バイト 一括ロードするためのグループナンバ ファイル ネーム : 8バイト アドレス : 2バイト 下位、上位の順 ファイルの長さ : 2バイト 下位、上位の順 ファイルの種類 : 1バイト 00=プログラム、01=キャラクタ、02=許諾ファイル CRC : 2バイト ファイルナンバ 最初のファイル(通常はKYODAKUファイル)を$00で次のファイルは$01になり 書き込む場合に使用されます(ファイルを追加するごとに+1) ロードナンバ 読み込むときに使用されるナンバで他のファイルにも同じナンバがある場合があります 同じナンバだと一度にロードする事が可能になります ブロックコード$01-2のコールドスタートではそのロードナンバ以下の値がロードされます 例えばコールドスタートが$0Fなら起動時に$00-$0Fまでの ロードナンバのファイルが一度にロードされ$10以降のファイルはロードされません ファイル ネーム 目安程度なので同じ名前のファイル ネームがあっても構いません ------------------------------------------------ GAP : $00 スタートデータ : 1バイト $80 ブロックコード : 1バイト $04 プログラム : データ本体(ブロックコード$03の長さ分) CRC : 2バイト ------------------------------------------------ ------------------------------------------------ テスト ファイル用 スタートデータ : 1バイト $80 ブロックコード : 1バイト $05 データ : 3バイト $6D、$B6、$DB : | : | 以降この3バイトのデータがディスクの最後まで続く : | CRC : 2バイト ------------------------------------------------ CRCは16ビットでスタートデータからブロックの最後まで計算される まずデータとCRCレジスタを右シフトしてCRCレジスタ最下位が1なら CRCレジスタとXOR $8408を実行する これを8回(8ビット分)繰り返せば1バイトのCRC計算となる これを1ブロック分まで繰りかえす 起動時に必要なもの 1.ブロックコード$01-1 ’*NINTNDO-HVC’ 2.ブロックコード$01-2 ディスクサイド$00、ゲームボリューム$00、コールドスタート$nn 3.ブロックコード$02のマウントファイル数、マウントファイル数分のファイル 4.$00、$00に’KYODAKU-’の許諾ファイル 5.割込み、リセットベクタ($DFFA~$DFFF)のあるプログラムファイル <例>リンクの冒険 A面のファイル内容 ブロックコード$01 ・--------------------・ |+0 +1 +2 +3 +4 +5 +6 +7| | |---------------+----| |01 2A 4E 49 4E 54 45 4E|.*NINTEN| |44 4F 2D 48 56 43 2A 01|DO-HVC*.| |4C 4E 4B 20 00 00 00 00|LNK ....| |00 0F FF FF FF FF FF 62|.......b| |01 14 49 61 00 00 02 00|..Ia....| |25 02 18 00 62 01 14 FF|%...b...| |FF FF FF FF 00 00 00 00|........| ・--------------------・ ’*NINTNDO-HVC’ メーカーコード $01 ゲームネーム ’LNK ’ ゲームバージョン $00 ディスクサイド $00 A面 ボリューム $00 ディスクの種類 FMC 予備1 $00 コールドスタート $0F | ブロックコード$02 マウントファイル数=$07 ブロックコード$03 ・----------------------------------・ |Fnn|Lnn| ファイル名 |アドレス | 長 さ | 種 類 | |--+--+--------+-----+-----+-------| |$00|$00|KYODAKU-|$2800|$00E0|$02(許 諾)| |$01|$03|MAIN-PRG|$6340|$7CC0|$00(PRG)| |$02|$28|CASTLE-L|$C000|$1FF6|$00(PRG)| |$03|$29|ENDING-P|$D660|$0996|$00(PRG)| |$04|$01|CHARA-00|$0000|$2000|$01(CHR)| |$05|$14|CHARA-05|$0E00|$09C0|$01(CHR)| |$06|$06|SAVE-DAT|$6000|$0338|$00(PRG)| ・----------------------------------・ コールドスタート $0Fなので起動時 L$00~$0Fのファイルをロード指定 ディスク サイドA面、ボリューム$00なので起動ディスクとみなしロード開始 $00 $00 KYODAKU- $01 $03 MAIN-PRG $04 $01 CHARA-00 $06 $06 SAVE-DATの4つが一括ロードされる 一括ロード終了後、VRAMの$2800-$28DFに ’KYADAKU-’ファイルがロードされたかチェックを行い 許諾ファイルがVRAMにロードされているのなら、 上スクロールで許諾画面を表示して ’MAIN-PRG’の$DFFC-$DFFDのアドレスにジャンプします 書き込む場合 CRCレジスタのリセット=0 GAP $00を書き込む CRCレジスタのリセット=1 | |スタートデータ$80以降を書き込む | CRCデータ下位の書き込み CRCコントロール=1 CRCデータ上位の書き込み 読み込む場合 GAP $00を読み込む CRCレジスタのリセット=1 | |データを読み込む | CRCデータ下位の読み込む CRCコントロール=1 CRCデータ上位の読み込む ブロックコード$01の書き込み例 JSR $E64D ;Boot Disk Drive LDA $00FA AND #$2B STA $4025 LDA #$00 STA $4024 LDY #$C5 JSR $E153 LDY #$86 JSR $E153 LDA #$01 ;Write $00,$80,$01 JSR $E6B0 | | *NINTENDO-HVC*...のデータをJSR $E7A3で書き込む | JSR $E729 ;Write CRC
エラー ドライブ&ディスクセット関連 01:DISK SET ERR.01 ディスクが正しくセットされていない 02:BATTERY ERR.02 ディスクドライブの電圧が規定値以下になっている 03:WRITE PROTECT ERR.03 ライトプロテクトのツメが折れているのに書き込もうとした 04:GAME MAKER ERR.04 違うメーカのディスクがセットされた 05:GAME NAME ERR.05 違うゲームのディスクがセットされた 06:GAME VERSION ERR.06 違うバージョンのディスクがセットされた 07:A.B.SIDE ERR 07 違うサイドのディスク(表と裏)がセットされた 08:DISK NUMBER ERR.08 違う順番のディスクがセットされた 09:ERR.09 違うディスクの種類がセットされた 10:ERR.10 違う予備1のデータがセットされた 08はROM内ではDISK NO. ERR.08として出力 11-19はディスクライター用? ファイルアクセス関連 20:DISK TROUBLE ERR.20 許諾ファイルが読み込めない 21:DISK TROUBLE ERR.21 ブロックコード$01の*NINTENDO-HVC*が見つからない 22:DISK TROUBLE ERR.22 ブロックコード$01の開始マーク$01が見つからない 23:DISK TROUBLE ERR.23 ブロックコード$02の開始マーク$02が見つからない 24:DISK TROUBLE ERR.24 ブロックコード$03の開始マーク$03が見つからない 25:DISK TROUBLE ERR.25 ブロックコード$04の開始マーク$04が見つからない 26:DISK TROUBLE ERR.26 ディスクに正しく書き込みが出来ない 27:DISK TROUBLE ERR.27 CRCエラーを検出 28:DISK TROUBLE ERR.28 ディスク読み込みでタイミングが合っていない(読み込み途中でヘッドが最後まで行った) 29:DISK TROUBLE ERR.29 ディスク書き込みでタイミングが合っていない(書き込み途中でヘッドが最後まで行った) ユーザーセーブ関連 30:DISK TROUBLE ERR.30 ディスクに書き込みが出来なくなった(容量不足またはドライブ・プロテクトによる強制終了) 31:DISK TROUBLE ERR.31 ディスクのデータ数が合わない、または書き込もうとしたマウントファイル数がマイナスになった 35:DISK TROUBLE ERR.35 テスト ファイル(ブロックコード$05ファイル)の書き込み失敗 その他 40:DISK TROUBLE ERR.40 一括ロードでロード出来なかったファイルがあった(ファイル数が足りない) 41:DISK TROUBLE ERR.41 不明(きね子IIの説明書にERR.41~の表記あり) *DISK TROUBLE ERR.35以降は ROMルーチンではなくソフトのルーチンでエラーの判断を行います ERR40について(リンクの冒険V1.1の場合) リンクの冒険では一括ロードが出来なかった場合 ERR.40を出力するようになっています また他社のソフトでも同様になっている場合があります(きね子IIで確認) <MAIN-PRG> 入力:Y=ロード番号 出力:A=エラーコード(0=エラー無し) A84E8:JSR $8533 ;サウンドオフ ※1 LDA $00FF ;PPU R0 b2=0 AND #$FB STA $00FF STA $2000 TYA ;Y保存(ロード番号) PHA LDA $8489,Y ;一括ロードナンバーセット ※2 STA $8507 LDA $849B,Y STA $8507+1 JSR $E1F8 ;一括ファイル ロード ※3 DW #$846E ;FCB Dataアドレス D8507:DW #$0000 ;一括ロードナンバー TAX ;X=エラーコード(0=エラー無し) STY $0000 ;0000:ロードしたファイル数 PLA ;Y,A=ロード番号 ※4 TAY CPX #$00 ;エラーならA851Bへ BNE A851B ;+++++++++++++++++ ;+ 通常のエラー無しの場合 + ;+++++++++++++++++ LDA $84AD,Y ;Y=ロード番号 CMP $0000 BEQ A851B LDX #$40 ;ERR.40 ;----------------- ;+++++++++++++++++ ;+ サブルーチン終了 + ;+++++++++++++++++ A851B:STX #070A ;エラーコード(0=エラー無し) TXA RTS ※1.エラーメッセージ表示の為のPPU設定 ※2.ロード番号から一括ロードナンバー設定 パラメータ部分D8507を書き換える ロード番号#00の場合は$84BFになる 8489:[BF]C3 C7 D5 D8 DC DF CA ポインタ下位 D5 D8 DC DF D0 D5 D8 DC DF E5 849B:[84]84 84 84 84 84 84 84 ポインタ上位 84 84 84 84 84 84 84 84 84 84 ※3.ROMルーチンコールで一括ファイルロード ロード番号#00の場合、$84BFのデータになるので L$nnの01、03、06の3つのファイルを一括ロードする $01=CHARA-00 $03=MAIN-PRG $06=SAVE-DAT 846E: 01 4C 4E 4B 20 00 01 00 00 00 (ブロック$01データ) 84BF:[01 03 06 FF] 84C3: 01 28 29 FF 84C7: 10 20 FF 84CA: 10 20 15 26 24 FF 84D0: 10 15 20 26 FF 84D5: 11 21 FF 84D8: 11 21 25 FF 84DC: 12 22 FF 84DF: 12 13 22 23 FF 85E4: FF 85E5: 14 28 FF ※4.ロードエラーがあれば各エラーコードを出してEND エラーが無ければ実際にロードしたファイル数と ロードするべきのファイル数を比較 数が合えばERR 0(エラー無し)としてRTS 数が合わなければERR 40としてRTS ロード番号#00の場合 ロードするべきのファイル数は3つとなる 84AD:[03]03 02 02 03 02 04 05 02 03 02 04 04 02 03 02 04 02
DISK ROM エントリ $E000:00 $E001-$E148:キャラクタデータ(文字) $E149:Wait $E153:nnミリ Wait 入力:Y=nnミリ 使用:X、Y Yミリ秒のウェイトをかけます ルーチン内で$0000をロード、コンペアの実行を行っていますが 時間稼ぎの為で内容の変更はありません 主にディスクアクセスのタイミングに使用 $E161:OBJ+BGオフ 使用:A $00FE スプライトとBG画面を表示しません。 $E16B:OBJ+BGオン 使用:A $00FE スプライトとBG画面を表示します。 $E171:OBJオフ 使用:A $00FE スプライトを表示しません。 $E178:OBJオン 使用:A $00FE スプライトを表示します。 $E17E:BGオフ 使用:A $00FE BG画面を表示しません。 $E185:BGオン 使用:A $00FE BG画面を表示します。 $E18B:NMIベクタ ディスク システムのNMIベクタです。 割り込みがかかったら$0100のd7-6をみて、それぞれの処理を行ないます。 0100:11** ****で$DFFAの内容の所へジャンプ 0100:10** ****で$DFF8の内容の所へジャンプ 0100:01** ****で$DFF6の内容の所へジャンプ 0100:00** ****でRAMアダプタ内で処理(許諾画面表示中などで使用) $E1B2:NMIがかかるのを待ちます。 使用:$00FF まず、Aレジスタ、NMIコード($0100の内容)をスタックにセーブしてから NMIコード$00にしてNMIがかかるのを待ちます NMIがかかるとセーブしたNMIコード、Aレジスタを元に戻るようになっています $E1C7:IRQベクタ 入力:$0101=IRQコード 出力:IRQコードによって異なる ディスク システムのIRQです。 割り込みがかかったら$0101のd7-6をみて、それぞれの処理を行ないます。 0101:11** **** $DFFEの内容の所へジャンプ 0101:10** **** $4030(ディスクI/Oステータス)を読んでWaitをかけRTI 0101:01** **** ディスク1バイト転送、スタックからPC-L、PC-H、PSRを取り出してRTS これは1バイト転送($E7A3)をコールしたアドレスに戻る為 ライトの場合入力:A=セーブするデータ 出力:A=CRC下位のデータ X=CRC下位のデータ(Aレジスタと同じ内容) リードの場合出力:A=リードデータ X=リードデータ(Aレジスタと同じ内容) 0101:00** **** $0101の内容が$00なら何もせず、 それ以外はd5-0のデータ分をAにディスクロード(スキップ) $E1F8:ファイル ロード 入力:1st=ブロックコード$01-2 比較データアドレス下位 2nd=ブロックコード$01-2 比較データアドレス上位 3rd=ロードナンバ群 ポインタ下位 4th=ロードナンバ群 ポインタ上位 出力:X、A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $04=GAME MAKER ERR.04 $05=GAME NAME ERR.05 $06=GAME VERSION ERR.06 $07=A.B.SIDE ERR 07 $08=DISK NUMBER ERR.08 $09=ERR.09 $10=ERR.10 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $24=DISK TROUBLE ERR.24 $27=DISK TROUBLE ERR.27 Y=ロード出来たファイル数 使用:A、X、Y $0000 $0001 $0002 $0003 $0004 $0005 $0007 $0008 $000E $00F8 $00F9 $00FA $0101 ブロックコード$01のチェックを行ってから($E445を実行) ブロックコード$02のマウントファイル数を読み込み($E484を実行) ロードナンバデータで$FF(エンドマーク)が出るまでファイルロードを行います ただし、ロードナンバ群の第1バイトが$FFならコールドスタートとしてロードされます このルーチンで一括ロードを行うのですが ファイルをロードできなくてもエラーが出ない恐れがあります その為に幾つロード出来たかYレジスタにロードしたファイル数が入ります ロードするファイル数とロード出来たファイル数とが合わないとERR.40として 各自で処理する必要があります(ROMルーチンでは何もしません) ロードナンバ群 nn,mm,...,$FF(エンドマーク) ロードするロードナンバが記されている(最大19個まで) ロードナンバ群の第1バイト $FF=コールドスタートの値と比較する その場合エンドマークを足して$FF,$FFになる $E237:一番最後にファイル セーブ 入力:1st=ブロックコード$01-2 比較データアドレス下位 2nd=ブロックコード$01-2 比較データアドレス上位 3rd=ブロックコード$03 データアドレス下位 4th=ブロックコード$03 データアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $04=GAME MAKER ERR.04 $05=GAME NAME ERR.05 $06=GAME VERSION ERR.06 $07=A.B.SIDE ERR 07 $08=DISK NUMBER ERR.08 $09=ERR.09 $10=ERR.10 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $26=DISK TROUBLE ERR.26 $27=DISK TROUBLE ERR.27 $0008=コールドスタート出来る最大ロードナンバ 使用:A、X、Y $0004 $0005 $0006 $0007 $0009 $000A $000B $000C $000D $00F8 $00F9 $00FA $0101 Aレジスタに$FFを入れて、下のファイルセーブを行います $E239:ファイル セーブ 入力:A=$00から$FE $0006で指定した場所-1にセーブ(最後のファイル) $FF 最後にセーブ(新しく作成) 1st=ブロックコード$01-2 比較データアドレス下位 2nd=ブロックコード$01-2 比較データアドレス上位 3rd=ブロックコード$03 データアドレス下位 4th=ブロックコード$03 データアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $04=GAME MAKER ERR.04 $05=GAME NAME ERR.05 $06=GAME VERSION ERR.06 $07=A.B.SIDE ERR 07 $08=DISK NUMBER ERR.08 $09=ERR.09 $10=ERR.10 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $26=DISK TROUBLE ERR.26 $27=DISK TROUBLE ERR.27 $0008=コールドスタート出来る最大ロードナンバ 使用:A、X、Y $0004 $0005 $0006 $0007 $0009 $000A $000B $000C $000D $00F8 $00F9 $00FA $0101 ブロックコード$01のチェックを行ってから($E445を実行) 指定した番号のファイルをセーブを行います またブロックコード$02にファイルナンバが書き込まれます ロックコード$03 データアドレスはロードナンバからファイルタイプまで 書かれているアドレスを指します セーブが成功すれば、ベリファイの実行を行います またベリファイの前にマウントファイル数の書き込みを行います ファイルはブロックコード$04も含む LDA #$05 JSR #$E239 DB $01-2データ下位,$01-2データ上位 DB ファイル データ下位,ファイル データ上位 BNE ERROR | $01-2データはメーカーコードからコールドスタートの次の$FFまで ファイルデータはブロックコード$03のロードナンバからファイルタイプまで ファイルデータに記されているアドレスと長さが書き込む範囲になります $E26B:ファイル セーブ (メイン) 入力:$0000=ブロックコード$01-2 比較データアドレス下位 $0001=ブロックコード$01-2 比較データアドレス上位 $0002=ブロックコード$03 データアドレス下位 $0003=ブロックコード$03 データアドレス上位 $000E=$00から$FE $0006で指定した場所-1にセーブ $FF 最後にセーブ 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $04=GAME MAKER ERR.04 $05=GAME NAME ERR.05 $06=GAME VERSION ERR.06 $07=A.B.SIDE ERR 07 $08=DISK NUMBER ERR.08 $09=ERR.09 $10=ERR.10 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $26=DISK TROUBLE ERR.26 $27=DISK TROUBLE ERR.27 $0008=コールドスタート出来る最大ロードナンバ 使用:A、X、Y $0004 $0006 $0007 $0009 $000A $000B $000C $000D $00F8 $00F9 $00FA $0101 ブロックコード$01のチェックを行ってから($E445を実行) $000Eを見て$00なら$0006の場所の最後に移動してファイルをセーブ $FFならブロックコード$02を読み込んでマウントファイル数の最後に移動してセーブ ファイルはブロックコード$04も含む $E2AB:マウントファイル数の書き込み 入力:$0000=ブロックコード$01-2 比較データアドレス下位 $0001=ブロックコード$01-2 比較データアドレス上位 $0006=フマウントァイル数 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $04=GAME MAKER ERR.04 $05=GAME NAME ERR.05 $06=GAME VERSION ERR.06 $07=A.B.SIDE ERR 07 $08=DISK NUMBER ERR.08 $09=ERR.09 $10=ERR.10 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $27=DISK TROUBLE ERR.27 $0008=コールドスタート出来る最大ロードナンバ 使用:A、X、Y $0002 $0004 $0005 $0006 $0007 $0009 $00F8 $00F9 $00FA $0101 ブロックコード$01のチェックを行ってから($E445を実行) ブロックコード$02のマウントファイル数の書き込みを行います $E2B7:ブロックコード$01のチェック、マウントファイル数の書き込み 入力:A=マウントファイル数 $0000=ブロックコード$01-2 比較データアドレス下位 $0001=ブロックコード$01-2 比較データアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $04=GAME MAKER ERR.04 $05=GAME NAME ERR.05 $06=GAME VERSION ERR.06 $07=A.B.SIDE ERR 07 $08=DISK NUMBER ERR.08 $09=ERR.09 $10=ERR.10 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $27=DISK TROUBLE ERR.27 使用:A、X、Y $0002 $0004 $0005 $0006 $0007 $0009 $00F8 $00F9 $00FA $0101 ブロックコード$01のチェックを行ってから ブロックコード$02に指定したマウントファイル数の書き込みを行います。 $E2BB:ブロックコード$01のチェック、マウントファイル数の削除 入力:A=削除するファイル数 $0000=ブロックコード$01-2 比較データアドレス下位 $0001=ブロックコード$01-2 比較データアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $04=GAME MAKER ERR.04 $05=GAME NAME ERR.05 $06=GAME VERSION ERR.06 $07=A.B.SIDE ERR 07 $08=DISK NUMBER ERR.08 $09=ERR.09 $10=ERR.10 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $27=DISK TROUBLE ERR.27 使用:A、X、Y $0002 $0004 $0005 $0006 $0007 $0009 $00F8 $00F9 $00FA $0101 ブロックコード$01のチェックを行ってから ブロックコード$02のマウントファイル数から指定したファイル数の分だけ減らします この時マウントファイル数がマイナスになるとERR.31となります。 $E2F7:マウントファイル数の読み込み 入力:$0000=ブロックコード$01-2 比較データアドレス下位 $0001=ブロックコード$01-2 比較データアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $04=GAME MAKER ERR.04 $05=GAME NAME ERR.05 $06=GAME VERSION ERR.06 $07=A.B.SIDE ERR 07 $08=DISK NUMBER ERR.08 $09=ERR.09 $10=ERR.10 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $27=DISK TROUBLE ERR.27 $0006=ファイル数 $0008=コールドスタート出来る最大ロードナンバ 使用:A、X、Y $0004 $0007 $00F8 $00F9 $00FA ブロックコード$01のチェックを行ってから($E445を実行) ブロックコード$02のマウントファイル数を読み込みます($E484を実行) その為、前もってブロックコード$01の比較データを用意する必要があります。 $E301:マウントファイル数+1を書き込む 入力:A=マウントファイル数 1st=ブロックコード$01-2 比較データアドレス下位 2nd=ブロックコード$01-2 比較データアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $27=DISK TROUBLE ERR.27 $29=DISK TROUBLE ERR.29 $30=DISK TROUBLE ERR.30 使用:A、X、Y $0002 $0004 $0005 $0006 $0007 $00FA $0101 スタック ブロックコード$01-2のチェックを行ってから マウントファイル数より1つ多く書き込みます $E305:マウントファイル数を書き込む 入力:A=マウントファイル数 1st=ブロックコード$01-2 比較データアドレス下位 2nd=ブロックコード$01-2 比較データアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $27=DISK TROUBLE ERR.27 $29=DISK TROUBLE ERR.29 $30=DISK TROUBLE ERR.30 使用:A、X、Y $0002 $0004 $0005 $0006 $0007 $00FA $0101 スタック ブロックコード$01-2のチェックを行ってから マウントファイル数を書き込みます $E307:マウントファイル数+nnを書き込む 入力:A=マウントファイル数 X=nn(加えるファイル数) $0000=ブロックコード$01-2 比較データアドレス下位 $0001=ブロックコード$01-2 比較データアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $27=DISK TROUBLE ERR.27 $29=DISK TROUBLE ERR.29 $30=DISK TROUBLE ERR.30 使用:A、X、Y $0002 $0004 $0005 $0006 $0007 $00FA $0101 スタック ブロックコード$01-2のチェックを行ってから マウントファイル数+nnを書き込みます $E32A:ディスク インフォメーションの収得 入力:1st=ディスク インフォメーション アドレスの下位 2nd=ディスク インフォメーション アドレスの上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $21=DISK TROUBLE ERR.21 $27=DISK TROUBLE ERR.27 $0002-$0003=ディスクの総容量 $000A-$000B=ディスクの総容量 使用:A、X、Y $0000 $0001 $0004 $0005 $0006 $0009 $000A $000B $000C $000D ディスクを最初から読み、指定したアドレスにディスク インフォメーションの取得を行います 新規ファイル作成やユーザディスクに使用か? ディスク インフォメーションの内容 +00 メーカーコード 1バイト +01 ゲーム ネーム 4バイト +05 ゲーム バージョン 1バイト +06 ディスク サイド 1バイト A面=00、B面=01 +07 ディスクの順番 1バイト +08 ディスクの種類 1バイト 00=FMC(黄色の磁気カード)、01=FSC(シャッター付きカード) +09 不明(地域?) 1バイト +0A マウントファイル数 1バイト ブロックコード$02のデータ +0B ロードナンバー00 1バイト ファイルの順番00のロードナンバ (ブロックコード$03のデータ) +0C ファイルネーム00 8バイト ファイルの順番00のファイルネーム(ブロックコード$03のデータ) | | 以降ファイル数分のファイルが続き最後にディスクの総容量 | +nn ディスクの総容量の下位 +mm ディスクの総容量の上位 ディスクの総容量はヘッダ部分 +00~+0A 10バイト ファイル部分 ファイルの順番 1バイト +0B ロードナンバ 1バイト +0C~+12ファイルネーム 8バイト ロードアドレス 2バイト ファイルの長さ 2バイト ファイルタイプ 1バイト GAP? 255バイト($03と$04分?) プログラム部分 ファイルの長さ 以降ファイル部分+プログラム部分がマウントファイル数-1分まで加算されます。 ???ディスクの総容量は$E31Fまで $E3E7:パラメータの取得、現在のドライブの状態を見る(ロード) 入力:A=$FF(パラメータ4バイト)、$00(パラメータ2バイト) 1st,2nd 3rd、4th(パラメータ4バイトの場合) 出力:$0000=1st パラメータ $0001=2nd パラメータ $0002=3rd パラメータ(パラメータ4バイトの場合) $0003=4th パラメータ(パラメータ4バイトの場合) A=エラーコード $00=エラー無し $01=DISK SET ERR 使用:A、X、Y $0004 $0005 $0006 スタック パラメータのの取得を行って$0000からそれぞれ対応するデータをセットして メディア セットを調べます $E3EA:パラメータの取得、現在のドライブの状態を見る(セーブ) 入力:A=$FF パラメータ4バイト セット $00-$FE パラメータ2バイト セット 1st,2nd 3rd、4th(パラメータ4バイトの場合) 出力:$0000=1st パラメータ $0001=2nd パラメータ $0002=入力したAレジスタの内容(パラメータ2バイト セットの場合) 3rd パラメータ (パラメータ4バイト セットの場合) $0003=4th パラメータ (パラメータ4バイト セットの場合) $000E=パラメータnnバイトの値(0か2 エラーの場合) A=エラーコード $00=エラー無し $01=DISK SET ERR $03=WRITE PROTECT ERR 使用:A、X、Y $0004 $0005 $0006 スタック パラメータのの取得を行ってJSR命令の実行した後のアドレスをパラメータとして $0000からそれぞれ対応するデータをセットして Aレジスタにディスクの状態を送ります。 エラーが発生するとRTSする前にスタック操作を行って このルーチンを実行したルーチンを強制終了されます $E3EB:パラメータの取得、現在のドライブの状態を見る メイン 入力:Cf=1 ロード時のドライブ状態を見る 0 サーブ時のドライブ状態を見る A=$FF パラメータ4バイト セット $00-$FE パラメータ2バイト セット 1st、2nd 3rd、4th(パラメータ4バイトの場合) 出力:$0000=1st パラメータ $0001=2nd パラメータ $0002=入力したAレジスタの内容(パラメータ2バイト セットの場合) 3rd パラメータ (パラメータ4バイト セットの場合) $0003=4th パラメータ (パラメータ4バイト セットの場合) $000E=パラメータnnバイトの値(0か2 エラーの場合) A=ロードの場合 $00=エラー無し $01=DISK SET ERR.01 セーブの場合 $00=エラー無し $01=DISK SET ERR.01 $03=WRITE PROTECT ERR.03 使用:A、X、Y $0004 $0005 $0006 スタック パラメータのの取得を行って前にJSR命令の実行した後のアドレスをパラメータとして $0000からそれぞれ対応するデータをセットして Aレジスタにディスクの状態を送ります セーブの状態なら$E3EAをサブルーチンコールをすれば良いのですが ロードの状態はCf=1にしてから$E3EBをコールする事になります。 エラーが発生するとRTSする前にスタック操作を行って このルーチンを実行したルーチンを強制終了されます $E445:ブロックコード$01 リード、チェック 入力:$0000=ブロックコード$01-2 比較データアドレス下位 $0001=ブロックコード$01-2 比較データアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $04=GAME MAKER ERR.04 $05=GAME NAME ERR.05 $06=GAME VERSION ERR.06 $07=A.B.SIDE ERR 07 $08=DISK NUMBER ERR.08 $09=ERR.09 $10=ERR.10 $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $27=DISK TROUBLE ERR.27 $0008=コールドスタート出来る最大ロードナンバ 使用:A、X、Y $0004 $0007 $00F8 $00F9 $00FA ブロックコード$01-1と$01-2のチェックを行います $01-3とCRCはスキップされる 違うメーカ、ゲームネーム、バージョン等の判断が出来ます ブロックコード$01-2のチェックは予備1まで必要です $E484:ブロックコード$02のマウントファイル数 リード 出力:A=エラーコード $00=エラー無し $27=DISK TROUBLE ERR.27 $0006=マウントファイル数 使用:A、X、Y $0004 $0007 $00F9 $00FA $0101 マウントファイル数を読み、CRCチェックを行います。 $E492:ブロックコード$02のマウントファイル数 ライト 入力:A=マウントファイル数 使用:A、X、Y $0004 $0007 $00FA $0101 マウントファイル数を書き込み、CRCデータを書き込みます。 $E4A0:ファイル チェック 入力:$0002=ロードナンバ群 ポインタ下位 $0003=ロードナンバ群 ポインタ上位 $0008=コールドスタートの値 出力:$0009=ロード コントロール $00=ロード $FF=スキップ $000E=ロード出来るファイル カウンタ 使用:A,X、Y $0101 指定したファイルがロードが出来るかチェックを行います ファイルナンバの読み込みから始まりますので ブロックコード$03の$00、$80、$03を読んでからコールします ロードナンバ群とブロックコード$03を読み同じなら $0009に$00、$000Eをインクリメント 違うのなら$0009に$FF ロードナンバ群 nn,mm,...,$FF(エンドマーク) ロードするロードナンバが記されている(最大19個まで) ロードナンバ群の第1バイト $FF=コールドスタートの値と比較する $E4DA:全てのファイルをスキップ 入力:$0006=マウントファイル数 使用:A、X、Y $0002 $0003 $0004 $0007 $0008 $0009 $000A $000B $000C $000D $00F9 $00FA $0101 マウントファイル数の次の所まで移動します 新しくファイルを追加するなどにコールします $E4E0:指定したファイル数をスキップ 入力:A=スキップするファイル数 使用:A、X、Y $0002 $0003 $0004 $0007 $0008 $0009 $000A $000B $000C $000D $00F9 $00FA $0101 指定したファイル数をスキップします $E583:ブロックコード$03のデータ解析 入力:$0002=ブロックコード$03 データポインタ下位 $0003=ブロックコード$03 データポインタ上位 出力:$000A=ロード、セーブアドレス 下位 $000B=ロード、セーブアドレス 上位 $000C=ファイルの長さ 下位 $000D=ファイルの長さ 上位 使用:A、X、Y $00FE 前もって読み書きしたブロックコード$03の内容に沿って ブロックコード$04へ読み書きする為に アドレス、ファイルの長さを取得し ファイルの種類がキャラクタか許諾ファイルなら PPUアドレスをセットします またPPUロードの為1回$2007を空読みを行っています $E64D:ディスク ドライブの起動 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 使用:A、X、Y $0004 $00F8 $00F9 $00FA モータ・オフ 約0.512秒のウェイト モータ・オン+バッテリーチェック ディスクセットのチェックを行いながら /READY=0になるまで待ちます $E685:ディスク ドライブ モーター ストップ 出力:A=$4025の内容 使用:A $00FA ドライブのモーターを止めます $4025に0010 ?110Bを出力し、その内容をAレジスタ出力されます このAレジスタはドライブのモータ スタート($EE17)で使用します つまり$E685と$EE17は対で使用(間にウェイトが入る場合がある)されます $E68F:ブロックコードの読み込み 入力:A=ブロックコード 出力:A=エラーコード $00=エラー無し $21=DISK TROUBLE ERR.21 $22=DISK TROUBLE ERR.22 $23=DISK TROUBLE ERR.23 $24=DISK TROUBLE ERR.24 使用:A、X、Y $0004 $0007 $00F9 $00FA $0101 CRCレジスタをリセットを行い、 1バイト読み込んだデータをブロックコードとして読みます ヘッドが予めブロックコードのある所にいなければなりません $E6B0:ブロックコードの書き込み 入力:A=ブロックコード 使用:A、X、Y $0004 $0007 $00FA $0101 $4025の設定(AND #$2Bをとる) 約0.01秒のウェイト GAP $00を書き込む CRCレジスタのリセット スタートデータ $80を書き込む 指定したブロックコードを書き込みます(1バイト) ヘッドが予めブロックコードのある所にいなければなりません $E6D5-$E6E2:*NINTENDO-HVC* データ '*CVH-ODNETNIN*'(逆になっています) $E6E3:*NINTENDO-HVC*のチェック 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $02=BATTERY ERR.02 $21=DISK TROUBLE ERR.21 使用:A、X、Y $0004 $0007 $00F8 $00F9 $00FA ドライブを起動し ブロックコード$01-1の'*NINTENDO-HVC*'があるかチェックを行います '*NINTENDO-HVC*'が無ければドライブを止め Aレジスタにエラーコード$21を返します $E706:CRC リード 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $27=DISK TROUBLE ERR.27 $28=DISK TROUBLE ERR.28 使用:$00FA CRC-Lデータをリード(データ自体は使用しません) CRC-Hコントロールを1($4025のd4=1) CRC上位バイトをリード リードしたデータがCRC-Hコントロールによってチェックが行われ 結果が$4030のd4に現れ(1=エラー、0=エラー無し) それの合わせてエラーコードが出力され、ドライブクローズされます $E729:CRC ライト 入力:A=CRC-Lデータ 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $29=DISK TROUBLE ERR.29 $30=DISK TROUBLE ERR.30 使用:$00FA *CRC-Lデータをライト CRC-Hコントロールを1($4025のd4=1) 約0.0005秒のウェイト <-ここでCRC-Hが書き込まれている? $4032の/READY=1(d1=1)ならエラー(ERR.31) 0(d1=0)ならエラーなし *CRC-LデータはIRQの1バイトデータ転送ルーチンでAレジスタに出力されています $E761:2バイトロード、ドライブのクローズ 入力:$000A=ロードアドレス下位 $000B=ロードアドレス上位 出力:A=エラーコード $00=エラー無し $01=DISK SET ERR.01 $28=DISK TROUBLE ERR.28 エラーコード$28 (エラーの場合) 使用:$00FA 2バイトロードしてドライブをクローズします CRCチェックは行いません エラーチェックはヘッドの検知を行います CRCデータのロード? $E778:ドライブのクローズ(エラー無し) 入力: 出力:A=エラーコード $00=エラー無し 使用:A、X $00FA X=$00(エラー無し)として ドライブ クローズ($E786)を実行します 当然、出力でAレジスタには$00が入ります $E77F:ディスク コンペア データ Zfチェック 入力:Zf=0 比較データと違う 1 比較データと同じ 出力:A=エラーコード(Zf=0で入力の場合) 使用:$0004 $00FA 前もってデータを比較したりしてZfの変化を見るルーチンになります 入力でZf=1なら何もせずRTS 0ならエラー エラーでは$0004のスタックデータをスタックポインタにして ドライブ クローズ、エラー出力して強制終了します $E786:ドライブ クローズ 入力:X=エラーコード 出力:A=エラーコード(Xレジスタの値) 使用:A、X $00FA $4025 d7:0 6:0 5:1 4:0 3:* 2:1 1:1 0:* XレジスタをAレジスタにコピーして、IRQをオンにします $E794:IRQ 1バイト転送の開始 入力:A=ライト データ(書き込みの場合) 出力:A=CRC下位 (書き込みの場合) X=リード データ(読み込みの場合) A=リード データ(読み込みの場合) 使用:$00FA $0101 IRQコードを$40(0101:40) IRQデータ転送を1($4025のd7=1)にして 下の$E7A3(IRQ 1バイト転送)を実行します ディスクのリード・ライトの始めに使用しますが事前に CRCレジスタをクリアしていないとCRC計算が正しく行われません $E7A3:IRQ 1バイト転送 入力:A=ライト データ(書き込みの場合) 出力:A=CRC下位 (書き込みの場合) X=リード データ(読み込みの場合) A=リード データ(読み込みの場合) IRQをオンにして無限ループでIRQが掛かるまで待ちます 1バイトだけIRQによってディスク転送を行いますが、 ディスクドライブ起動、IRQの設定は行わないので前もって設定する必要があります IRQのディスク1バイト転送ではスタック操作して このルーチンをコールしたアドレスに返るようになっています・ $E7A7:ファイル アドレスのINC、プログラムの長さのDEC 入力:$000A=ファイル アドレス下位 $000B=ファイル アドレス上位 $000C=ファイルの長さ下位 $000D=ファイルの長さ上位 出力:$000A=ファイル アドレス+1下位 $000B=ファイル アドレス+1上位 $000C=ファイルの長さ-1下位 $000D=ファイルの長さ-1上位 使用:A $000Aと$000Bを16ビットカウウンタとしてINCします 下の$E7ADへ続き $000Cと$000Dを16ビットカウウンタとしてDECします ブロックコード$04のデータを読み書き等に使用します 通常、入力はブブロックコード$03のデータ解析($E583)でセットされ このルーチンで入力する事はありません $E7AD:プログラムの長さのDEC 入力:$000C=ファイルの長さ下位 $000D=ファイルの長さ上位 出力:$000C=ファイルの長さ-1下位 $000D=ファイルの長さ-1上位 使用:A $000Cと$000Dを16ビットカウウンタとしてDECします $E7BB:文字列出力 入力:1st=データアドレス下位 2nd=データアドレス上位 使用:A、X、Y $0000 $0001 $0005 $0006 PPUにデータを送ります JSR #$E7BB DB データアドレス下位、データアドレス上位 | 上記の様にJSR命令の後にデータアドレスを指定します データのフォーマットは PPUアドレス上位またはコード PPUアドレス下位 コマンド+表示する長さ データ | コマンド+表示する長さ データ $FF(コード エンドマーク) コード $80-$FFならエンドマークとみなし終了(通常は$FF) $60ならサブデータから戻ります $4Cなら次のデータをアドレス上位、下位の順でサブデータのアクセスを行います サブデータは通常のデータと同じフォーマットになりエンドマークが$60になります コマンド d7 :1=Y方向+1 、0=X方向+1 6 :1=メモリを埋める、0=データレングスとして処理 5-0:長さ $E844:パラメータの取得 入力:コールする前の1st コールする前の2nd 出力:$0000=1st パラメータ $0001=2nd パラメータ 使用:$0005 $0006 ROMのサブルーチンによってはJSR nnmmの後にパラメータを設定するのですが それらのサブルーチンが使用して、パラメータを読みRTSする為のスタックを調節します $0005から$0006の内容が壊れます $E86A:VRAMバッファ出力 入力:$0302=バッファデータ00 VRAMアドレス上位 $0303=バッファデータ00 VRAMアドレス下位 $0304=バッファデータ00 データの長さ $0305=バッファデータ00 VRAMに書き込むデータ | $03nn=エンドマーク($80から$FF) 出力:$0301=$00 $0302=エンドマーク$80から$FF(実際には$FF) 使用:A、X、Y $00FF PPUアクセス時のアドレスの増加をX方向($2000 d2=0)にして VRAMバッファからアドレス、長さを取得してVRAMにバッファデータを書き込みます バッファデータの第1バイトのVRAMアドレスが$80から$FFだとエンドマークになります データフォーマット バッファデータ00 VRAMアドレス上位 バッファデータ00 VRAMアドレス下位 バッファデータ00 出力データの長さ バッファデータ00 出力データ | バッファデータnn VRAMアドレス上位 バッファデータnn VRAMアドレス下位 バッファデータnn 出力データの長さ バッファデータnn 出力データ エンドマーク($80から$FF) $E8B3:VRAMバッファ入力 入力:X=インデックス($02から) Y=転送するバイト数 $0302=データ00 VRAMアドレス 上位 $0303=データ00 VRAMアドレス 下位 $0305=データ01 VRAMアドレス 上位 $0306=データ01 VRAMアドレス 下位 | 出力:$0304=指定したデータ00のVRAMの内容 $0307=指定したデータ01のVRAMの内容 | 使用:A、X、Y $0302にあるVRAMバッファにVRAMの内容を転送します 1バイトごとの転送なので3バイト1組になります 入力するXレジスタの値は$02以上になります VRAMバッファは +00 VRAMアドレス上位 +01 VRAMアドレス下位 +02 VRAMの内容 (3バイトで1組になっています) | +nn $FF(エンドマーク) このルーチンではVRAMバッファのアドレスを読んで その内容をVRAMの内容としてVRAMバッファに書き込みます データの長さは3バイトで1つの長さになります $E8D2:メモリからVRAMバッファへ1行分の転送 入力:A=VRAMアドレス上位 X=VRAMアドレス下位 Y=転送する長さ 1st=データアドレス下位、2nd=データアドレス上位 $0300=VRAMバッファ インデックスの上限 $0301=VRAMバッファ インデックス 出力:A=$01 エラー有り $FF エラー無し $0002=キャラクタ定義用($0002-$0003に$20足される他のルーチン用) $0003=キャラクタ定義用 $0301=入力したVRAMバッファ インデックス+データの長さ(次のインデックス) $0302=VRAMアドレス上位 $0303=VRAMアドレス下位 $0304=データの長さ $0305=データ | $03nn=$FF エンドマーク 使用:A、X、Y $0000 $0001 $0004 $0005 $0006 メモリからVRAMバッファ($0302-$03FF)へ1行分転送(追加)します バッファの上限が$0300に設定され これを超えるとバッファにエンド マーク$FFが書き込まれ このルーチンをコールしたルーチンが強制終了されます 書き込み例 LDA #$20 ;VRAM上位 LDX #$00 ;VRAM下位 LDY #$04 ;転送する長さ JSR $E8D2 ;VRAMバッファに転送 DB データアドレス下位,データアドレス上位 JSR $E1B2 ;VBLANK期間になるまで待つ JSR $E86A ;VRAMバッファからVRAMに転送 JSR $EAEA ;スクロール(画面のクローズ) | DB ’ABCD’ ;データ $E8E1:メモリからVRAMバッファへ数行転送 入力:A=VRAMアドレス上位 X=VRAMアドレス下位 1st=データアドレス下位、2nd=データアドレス上位 $0300=VRAMバッファ インデックスの上限 $0301=VRAMバッファ インデックス 出力:A=$01 エラー有り $FF エラー無し $0002=キャラクタ定義用($0002-$0003に$20足される他のルーチン用) $0003=キャラクタ定義用 $0301=入力したVRAMバッファ インデックス+データの長さ(次のインデックス) $0302=VRAMアドレス上位 $0303=VRAMアドレス下位 $0304=データの長さ $0305=データ | $03nn=$FF エンドマーク 使用:A、X、Y $0000 $0001 $0004 $0005 $0006 メモリからVRAMバッファ($0302-$03FF)へ数行転送(追加)します $E8D2と違うのはデータの第1バイトがPPUデータでなく d7-4:行数で d3-0:データの長さ になります バッファの上限が$0300に設定され これを超えるとバッファにエンド マーク$FFが書き込まれ このルーチンをコールしたルーチンが強制終了されます $E94F:VRAMバッファ アドレスチェック、リード 入力:X=$00 (VRAMバッファ オフセット) Y=VRAMバッファ スキップする個数(3バイトで1) $0000=チェックするVRAMバッファ (VRAMアドレスの上位) $0001=チェックするVRAMバッファ (VRAMアドレスの下位) 出力:<同じアドレスの場合> A=VRAMバッファにあるVRAMの内容 Cf=0 <違うアドレスの場合> チェックしたVRAMバッファ+0=チェックするVRAMアドレス上位($0000) チェックしたVRAMバッファ+1=チェックするVRAMアドレス下位($0001) Cf=1 Y=VRAMバッファ インデックス VRAMバッファ X=インデックス(+0の位置)、Y=スキップする個数(3バイトで1)で X=$0302+X+3*(Y-1)でチェックするアドレスを決めます そのアドレスと$0000、$0001と比較して 同じならAレジスタに+2のデータを読み、Cf=0にしています 違う場合は+0、+1に比較した$0000、$0001のアドレスを書き込み Cf=1にしてエラーとみなします $E97D:座標からネームテーブル0変換 入力:$0002=Y座標(0から224) $0003=X座標(0から255) 出力:$0000=ネームテーブル0 上位 $0001=ネームテーブル0 下位 使用:A ドットの座標からネームテーブル0($2000-$23BF)に変換を行います $E997:ネームテーブルから座標変換 入力:$0000=ネームテーブル 上位 $0001=ネームテーブル 下位 出力:$0002=Y座標(0から232) $0003=X座標(0から248) 使用:A ネームテーブルオフセット($0000-$03BF)からドットの座標に変換を行います 入力のネームテーブル上位は$0000から$03BFで計算を行っているので どのネームテーブル、ネームテーブルオフセットでも同じ出力になります $E9B1:乱数の発生 入力:X=インデックスデータ Y=長さ ゼロページ 出力:ゼロページ+入力したXレジスタからゼロページ+入力したX+Yまで 使用:A、X、Y $0000 指定したゼロページ+Xレジスタのアドレスを起点として長さYまでを 発生レジスタとして乱数の発生を行います 指定したゼロページ+Xレジスタのd1だけマスクして$0000にストア 指定したゼロページ+1+Xレジスタのd1と$0000とEORする 0ならCf=0、1ならCf=1 全発生レジスタを右シフトする $E9C8:仮想OBJエリア セット 使用:A 仮想OBJを$0200に設定します。 $E9D3:ロジック カウンタ 入力:X=カウンタ0のアドレス(ゼロページ内) A=カウンタ1のアドレス(ゼロページ内) Y=カウンタ2のアドレス(ゼロページ内) 出力:X=カウンタ0のアドレス(ゼロページ内0から9) A=カウンタ1のアドレス(ゼロページ内0から255) Y=カウンタ2のアドレス(ゼロページ内0から255) 使用:A、X、Y カウンタを1つ減らします カウンタ0が基本になり、9からカウントダウンして-1になると9に戻ります カウンタ0が9から0の時にカウンタ1のカウントダウン(00で止まる) -1の時にカウンタ2のカウントダウン(00で止まる) $E9EB:リアルタイムでコントローラを読む 出力:$0000:拡張端子のI-コントローラ $0001:拡張端子のII-コントローラ $00F5:I-コントローラ $00F6:II-コントローラ 使用:A、X $00FB 本体コントローラと外部のコントローラを読んで 各ワークエリアにデータをストアします。 $EA0D:コントローラデータの合成 入力:$0000:拡張端子のI-コントローラ $0001:拡張端子のII-コントローラ $00F5:I-コントローラ $00F6:II-コントローラ 出力:$00F5:I-コントローラ $00F6:II-コントローラ 使用:A $E9EBをコールして得たデータをIコン、IIコンの2つにまとめます $EA1A:リアルタイムで本体コントローラを読む 出力:$00F5:I-コントローラ $00F6:II-コントローラ $00F7:I-コントローラを1回押した時の内容 $00F8:II-コントローラを1回押した時の内容 使用:A、X、Y $0000 $0001 リアルタイムでントローラを読み($E9EBをコール) ワークエリアにストアします $00F7と$00F8は 押されたままだと1になり、離すと0になります $EA1F:リアルタイムで本体コントローラと拡張コントローラを読む 出力:$00F5:I-コントローラ $00F6:II-コントローラ $00F7:I-コントローラを1回押した時の内容 $00F8:II-コントローラを1回押した時の内容 使用:A、X、Y $0000 $0001 リアルタイムでコントローラを読み($E9EBをコール) コントローラデータの合成($EA0Dをコール)を行い ワークエリアにストアします $00F7と$00F8は 押されたままだと1になり離すと0になります 使用:A、X、Y $0000 $0001 $EA36:本体コントローラを読む 出力:$00F5:I-コントローラ $00F6:II-コントローラ $00F7:I-コントローラを1回押した時の内容 $00F8:II-コントローラを1回押した時の内容 使用:A、X、Y $0000 $0001 リアルタイムでコントローラを読み($E9EBをコール)、レジスタA、Yに読む リアルタイムでコントローラを読み($E9EBをコール) 1回目と2回目に読んだ内容が同じになるまでループ 同じになったら$00F5から$00F8までのワークに それぞれストアします $EA4C:本体コントローラと拡張コントローラを読む 出力:$00F5:I-コントローラ $00F6:II-コントローラ $00F7:I-コントローラを1回押した時の内容 $00F8:II-コントローラを1回押した時の内容 使用:A、X、Y $0000 $0001 $EA36と同様に本体コントローラと拡張コントローラで コントローラの読み込みを行います $EA84:PPUメモリを埋める 入力:A=PPU アドレス上位 X=埋めるデータ Y=パラメータ(PPUアドレスの指定によって違う) 出力:X=指定した埋めるデータ 使用:A、X、Y $0000 $0001 $0002 指定したPPUアドレスが$2000未満(パターンテーブル)なら XレジスタのデータをYレジスタで指定した長さ*256バイトで埋めます 指定したPPUアドレスが$2000以上なら Xレジスタのデータ$0400バイトをネームテーブルに埋め Yレジスタのデータ$ 40バイトをネームテーブルのアトリビュートに埋めます 主に画面クリアに使用 PPUアドレスは上位のみで下位アドレスは$00になります。 転送量も上位になるので256バイト単位になります。 $EAD2:メモリを埋める 入力:A=埋めるデータ X=スタートアドレス上位 Y=エンド アドレス下位 使用:A、X、Y $0000 $0001 CPUメモリを特定のデータで埋めます 指定できるのはアドレス上位のみなのでページ単位$nn00-$mmFFが指定範囲になります $EAEA:スクロールをセット 入力:$00FC=ポート$2005の内容(X座標) $00FD=ポート$2005の内容(Y座標) $00FF=ポート$2000の内容 使用:A VRAMをアクセスした後スクロールセットをするのに使用します スクロールをセット PPU R#0を$00FFの内容でセット $EAFD:テーブルジャンプ 入力:A=テーブジャンプNo.nn($00-$7Fまで) 1st=テーブルジャンプNo.$00 下位アドレス 2nd=テーブルジャンプNo.$00 上位アドレス 3rd=テーブルジャンプNo.$01 下位アドレス 4th=テーブルジャンプNo.$01 上位アドレス | 使用:A、X、Y $0000 $0001 テーブルジャンプを行います BASICのON A GOTOnnnn,mmmm,...に相当 使用例 JSR $EAFD DW ADDRESS0 ;A=$00のジャンプ DW ADDRESS1 ;A=$01のジャンプ DW ADDRESS2 ;A=$02のジャンプ | $EB13:HVC-007 キーボードのキーマトリクス入力 出力:$0000=キーマトリクスP2 9の反転データ $0001=キーマトリクスP2 8の反転データ $0002=キーマトリクスP2 7の反転データ $0003=キーマトリクスP2 6の反転データ $0004=キーマトリクスP2 5の反転データ $0005=キーマトリクスP2 4の反転データ $0006=キーマトリクスP2 3の反転データ $0007=キーマトリクスP2 2の反転データ $0008=キーマトリクスP2 1の反転データ 使用:A、X、Y $00FB ファミリーBASICのキーボード(HVC-0007)のキーマトリクス入力を行います 出力データは反転されているので押していると1、離している0になります P3 1がd0...P3 8がd7になります$EB66:ポインタ+8バイト、Y=#$00、DEC ($02) 入力:$0000=ポインタ下位 $0001=ポインタ上位 $0002=ブロック(長さ) 出力:Y=$00 $0000=ポインタ下位 $0001=ポインタ上位 $0002=ブロック(長さ)-1 使用:A、Y $0000=ポインタ下位 $0001=ポインタ上位 $0002=ブロック(長さ) $0000から$0001をポインタとして ポインタ+8 Y=#$00 $0002の内容を-1にします パターンテーブル定義用 $EB69:ポインタ+Aバイト、Y=#$00、DEC ($02) 入力:A=ポインタにプラスする値 $0000=ポインタ下位 $0001=ポインタ上位 $0002=ブロック(長さ) 出力:Y=$00 $0000=ポインタ下位 $0001=ポインタ上位 $0002=ブロック(長さ)-1 使用:A、Y $0000=ポインタ下位 $0001=ポインタ上位 $0002=ブロック(長さ) $0000から$0001をポインタとして ポインタ+A Y=#$00 $0002の内容を-1にします パターンテーブル定義用 $EBAF:パターンテーブル定義 入力:Y=PPUアドレス 上位 A=PPUアドレス 下位+コード d7:PPUアドレス A7 d6:PPUアドレス A6 d5:PPUアドレス A5 d4:PPUアドレス A4 d3:コード D1 11=反転 通常 、10=埋める 通常 d2:コード D0 01=通常 埋める、00=通常 通常 d1:コード 1=リード モード、0=ライト モード d0:コード 1=$FFで埋める、0=$00で埋める X=キャラクタ数 1st=パターン データアドレス下位 2nd=パターン データアドレス上位 使用:A、X、Y $0000 $0001 $0002 $0003 $0004 $00FF パターンテーブル(キャラクタ)の定義を行います アクセスするPPUアドレスを指定しますがPPUアドレス下位のd3-0は0になる($xxx0) 次にコード解析でd1-0の設定、d3-2で各キャラクタ定義を行います キャラクタは1キャラ8バイト+8バイトの計16バイト必要で コードによって定義のパターン(必要なパターンデータ数)が変わります コード11(パターン データは1キャラクタ 16バイト必要) プレーン0 パターン データを反転してVRAMに書き込む プレーン1 ライト モード=パターン データをVRAMに書き込む リード モード=VRAMの内容をパターン データに書き込む コード10(パターン データは1キャラクタ 8バイト必要) プレーン0 ライト モード=VRAMに$FFまたは$00で埋める リード モード=VRAMのデータを読み、VRAMに書き込む プレーン1 ライト モード=パターン データをVRAMに書き込む リード モード=VRAMの内容をパターン データに書き込む コード01(パターン データは1キャラクタ 8バイト必要) プレーン0 ライト モード=パターン データをVRAMに書き込む リード モード=VRAMの内容をパターン データに書き込む プレーン1 ライト モード=VRAMに$FFまたは$00で埋める リード モード=VRAMのデータを読み、VRAMに書き込む コード00(パターン データは1キャラクタ 16バイト必要) プレーン0 ライト モード=パターン データをVRAMに書き込む リード モード=VRAMの内容をパターン データに書き込む プレーン1 ライト モード=パターン データをVRAMに書き込む リード モード=VRAMの内容をパターン データに書き込む $ED37-$EE16:許諾画面 データ $EE17:ドライブのモータ スタート 入力:A=$4025の内容 使用:A $00FA /RESET=1にして/MOTOR=0にします 前もってディスク ドライブ モーター ストップ($E685)を実行しておく必要があります $EE24:ディスクシステム スタート(リセット ベクタ) 電源を入れたり、リセットされるとココにとびます。 $F1C3:キャラクタ定義 使用:A、X、Y $0000 $0001 $0002 $0003 $0004 $00FF BG(PPU$1000)に数字、英字のキャラクタ41文字の定義を行います $F431:許諾画面の書き込みチェック 出力:Zf=0 エラーなし 1 エラーあり キャラクタ定義、カラーの設定、BG-Aをクリア BG-Cにロードされた許諾データとROM内にある許諾データの比較を行います $F48C:キャラクタ定義の退避または復帰 入力:Y=$03 キャラクタデータの退避 $07 キャラクタデータの復帰 使用:A、X、Y $0000 $0001 $0002 $0003 $0004 $0007 $0008 $0009 $000A $000B $00FF PPU $2930以降 ディスクを起動したときにはキャラクタ、プログラム、許諾データが一括ロードされている場合があります キャラクタデータがロードされていても必ずしも許諾画面を確実に表示する英数字コードとは限りません そこで、このルーチンでロードしたPPU$1000以降のキャラクタデータを 一旦PPU$2930以降を退避用エリアとして一時退避、復帰を行います データを退避したら英数字のキャラクタ定義を行いPPUにロードした許諾画面のチェック、表示 許諾画面の表示が終了したらデータの復帰を行いロードしたプログラムの実行となります。
$0000:JSR文の後の第1パラメータ データアドレス下位 ポインタ下位 $0001:JSR文の後の第2パラメータ データアドレス上位 ポインタ上位 $0002:JSR文の後の第3パラメータ VRAMアドレス下位 指定したマウントファイル数 $0003:JSR文の後の第4パラメータ VRAMアドレス上位 $0004:スタックポインタ退避 データの長さ $0005:JSRで戻るアドレス下位 ディスクアクセス リトライカウンタ VRAMバッファの長さ $0006:JSRで戻るアドレス上位 マウントファイル数 $0007:ブロックコード $0008:エラーコード 最初に読み込むロードナンバー $0009:ロード コントロール $00=ロード、$FF=スキップ セーブ コントロール $00=セーブ、$FF=ベリファイ $000A:ファイルの先頭アドレス 下位 $000B:ファイルの先頭アドレス 上位 $000C:ファイルの長さ 下位 $000D:ファイルの長さ 上位 $000E:パラメータnnバイトの値 ファイルカウンタ $00F5:コントローラIの内容 1=オン、0=オフ A、B、SELECT、START、上、下、左、右 $00F6:コントローラIIの内容 $00F7:コントローラIを1回押した時の内容 $00F8:コントローラIIを1回押した時の内容 $00F9:ポート$4026の内容 $00FA:ポート$4025の内容 $00FB:ポート$4016の内容 $00FC:ポート$2005の内容(垂直) $00FD:ポート$2005の内容(水平) $00FE:ポート$2001の内容 $00FF:ポート$2000の内容 $0100:NMI コントロール $00=BIOS内 $40=JMP ($DFF6) $80=JMP ($DFF8) $C0=JMP ($DFFA) $0101:IRQ コントロール $00 =ロード・スキップの終了 $01-$3F=ロード・スキップ バイト $40 =ディスク1バイト リード・ライト $80 =ディスク ステータス $C0 =JMP ($DFFE) $0102-$0103:RESET コントロール $0102:35 53=JMP ($DFFC) $0102:35 AC=$0103を$53にしてスクロールセットの後、JMP ($DFFC) それ以外のデータはデモ $0200-$02FF:仮想OBJエリア $0300-$03FF:VRAMバッファ
ディスクドライブのプロテクト 最初のドライブにはプロテクトは掛かっていませんでしたがコピープログラムの発表や発売され 一定時間(約1秒)しか書き込みが出来ないようになりました。 プロテクトの内容はドライブ内の基板でライト信号が送られたらカウントして約1秒たったら シャットダウンする方式でコレをパターンカットとバイバスを通して無効する方法があります。 最終的にはFDC自身に同等のプロテクトを掛けるのですがロジック回路で破られています。 ソフトでのプロテクト 元々QDなのでそれほどきついプロテクトは掛けられません。 特定のソフトのコピーツールに対してのプロテクトとなります。 またPCから読み書きやデュプリケータでは全くプロテクトの意味がありません。 ダミー ファイル ブロックコード$02のマウントファイル数より多くファイルを持つタイプ とびだせ大作戦、夢工場ドキドキパニック、ディープダンジョンII勇士の紋章(店頭販売、書き換え共)が該当します 主に対DISK HACKER V1.1用です DISK HACKER V1.1までではファイル数を見て必要なファイルだけをコピーしていました とびだせ大作戦のA面では実際のファイルはブロックコード$02のファイル数より1つ多く DISK HACKER V1.1でコピーすると最後の1つだけファイルが足りないものになります そのファイルが無ければコピー品と判断しています ダミーファイルとはいえ、とびだせ大作戦はダミーファイルが本当のメインプログラムになっていて ゲームスタートするとMAINPROG(警告プログラム)がロードされ、その後すぐにダミーファイル(本当のメイン)が RAMに上書きされ実行されます ダミーファイルが上書きされないと警告プログラムが動いてコピー品とみなされメッセージを出します 夢工場ドキドキパニック、ディープダンジョンII勇士の紋章では数バイトのデータが書き込まれていて このファイルがロード出来るかでコピー品の判断を行っています。 とびだせ大作戦ではコピー失敗すると作者からメッセージが出ます。夢工場ドキドキパニックのコピー失敗
勇士の紋章のコピー失敗
新鬼ヶ島のコピー失敗
40KB ファイル コピーツールのバッファより大きいファイルを持つタイプ 麻雀家族、スーパーロードランナー、きね子IIが該当 1つのファイルがRAM容量よりも大きくなっています ファイルが40KBのファイルがあり、コピーバッファが少ないとコピー出来ないようになっています 主に対DISK HACKER V1.2用 DISK HACKER V1.3ではV1.2より大きいバッファを持ちコピー出来ます。 ファミコンのディスクはランダムアクセスが出来ないQDなのでトラックやセクタ等は無く テープと同じように最低でも一つのファイルを一気に書き込まないといけません つまり分割して一つのファイルを書き込みする事はかなり困難になります しかし、本体メモリはRAMアダプタ32KB+本体ワーク2KB+VRAM2KB+キャラクタ8K計44KBなので 4KB内でコピープログラム、最低限40KBのバッファを取ってコピー出来るツールもあります スーパーロードランナーではSIDE Aの4番目のファイルLRMAIN01が ロードアドレス$6000で長さ$A000になります 3番目のファイルPROTECT(ローダ)を本体内ワークRAMにローダを転送、実行 LRMAIN01は$6000から読み込まれますが ローダによって始めの$2000バイトを空読みして 残りの$8000バイトが$6000-$DFFFにロードされます ロード終了後、$DFE0-$DFEFのチェック $6000-$DFFFのチェックを行い 正常ロード出来たなら$6000にジャンプします 44KB ファイル 本体内+RAMアダプタの全RAMと同じ容量のファイルを持つタイプ HACKERのソフトで途中から出てきたプロテクトです 1つのファイルの大きさが44KBで本体内の全RAMより同じになります これだとコピープログラムの入る所が無く ソフトのコピーツールではコピー出来なくなります メインプログラムが$4800からロードして BIOSの$F7FFまでロードするようになっていて 実際にはRAM領域の$6000-$DFFFに プログラムがロードされるようになります HACKERのソフトで同タイトルでも プロテクトが掛かっているのと掛かっていない2タイプがあります。 偽データ ブロックコード$03と$04が合わないプロテクトです アイツーのジンゴローが該当 ブロックコード$03にはファイル名やロードされるアドレス、長さが書き込まれています ブロックコード$04が実際のプログラムやデータとなります そのブロックコード$03で書き込まれた長さと ブロックコード$04の長さが合わないようするタイプです コピーツールでブロックコード$03を見てブロックコード$04のファイルをコピーする コピーツールに対して有効です ジンゴローでは最後のファイルがブロックコード$03では1バイトの長さになっていますが 次のブロックコード$04では1バイトでなく7バイト×$2000=$E000バイトのデータが書き込まれており IPLプログラムでデータをメモリとVRAMに振り分けながらロードしています 第1バイトがプログラムデータ(ストア アドレス下位の値で引く) 第2バイトがダミー 第3バイトがダミー 第4バイトがダミー 第4バイトがダミー 第6バイトがキャラクターデータ(ストア アドレス下位の値で足す) 第7バイトがダミー このデータ群をロード(CRC計算もされているのでダミーデータも必要)する様になっています CRCエラー ファイルにワザとCRCエラーの出るファイルが存在するタイプ トンカチエディタが該当 ディスクが起動するまでは通常のフォーマットでその後の読み込みにCRCエラーの出るファイルを ロードしてCRCエラーが出るかチェックします コピーツールによっては正しいCRCが書き込まれるので CRCエラーが出るはずのファイルがエラー無しとなり コピーされたと判断しています オリジナルフォーマット 最後のメーン・ファイルが独自のフォーマットで書き込まれIPLプログラムでロードするプロテクトです 子育てゴッコ、クイックハンターが該当 検査システムでチェックするディスクデータがディスクの最後までデータの読み書きが出来るかチェックされる為 テストファイルが上書きされるので注意が必要なタイプです 途中まで普通のフォーマットでIPLもそのフォーマット内のファイルにあるので IPLをロードして実行、独自のフォーマットで書かれたプログラムを読む 単純なバイナリデータや、加工したデータ、プログラムとダミーデータとVRAMデータと混合等 ソフトによってデータが変わります 子育てゴッコではメインプログラムは$0200-$05FFで 通常のフォーマットの後ろに直接メインプログラムが書かれていて IPLプログラムでこのメインプログラムを$0200からロード ロード終了したら最初の0200:20と最後の05FF:23をチェックして ロードされたか判断をしています このメインプログラムのコピーに失敗すると隠しゲームのバリケードゲームが遊べます。 クイックハンターではIPLプログラムまで行くまでに自己書き換え(一部分が暗号化されている)しながら 数ヶ所にジャンプされています 最終ファイルはブロックコード$00として書き込まれており $1000バイト空読みしてから$B000-$CFFFにロードします $B000以降のロードデータは暗号化されておりEOR $C9(データを一部反転)しながらロードします 当然、このブロックコード$00のファイルもCRCチェックも行われています。 メーカーコード$00 HACKER製コピーツールで HACKER製ソフトをコピー出来ない為のプロテクトです 通常のソフトはメーカーコードは$01からになっており$00は使用していません そこでHACKERのソフトはここに$00を書き込みを行っています メーカーコードが$00だとHACKER製コピーツールではエラー FFを出力して コピーできないようになっています DEV1のRAMディスクとディスクハッカーVer1.0ではエラーが出ずにコピー出来ます DEV2のRAMディスクとディスクハッカーVer1.0ではエラー FFが出てコピー出来ません 他のコピーツールではコピーが出来ますが当然44KBファイルはコピーできません プログラム書き換えチェック これはプロテクトといってもコピープロテクトでは無く プログラムの改造されたかチェックをするタイプ 改造するとチェックサムエラーのメッセージが出たり、 起動画面に飛んだり、ゲームが起動出来ない様になっています ただし完全なチェックを行っているとは限りません コピーライト表記の書き換え(海賊版)対策? コナミやカプコンのソフトに見かけます セクションZのチェックサムエラーメッセージ
ナムコのディスクソフト プロテクトでは無いのですがナムコのディスクソフトは 非ライセンス ソフトと同じような許諾画面を出さないような事をしています 実際には許諾画面を出しているのですが RAMアダプタのプログラムで動いてなくて ゲームソフト(IPLMAIN)が割り込みで RAMアダプタからの許諾画面表示を乗っ取っていながら ゲームソフトから許諾画面を表示しています これにより任天堂が許諾画面表示の乗っ取りプログラムに対する プロテクトを掛けるのが難しくなっています つまりプロテクトを掛けるのを防ぐ為の任天堂に対する逆プロテクト(?)に思えますが 真相は不明です
Home へ戻る