ファミコン ディスクシステム
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:(出力) 2C33 IRQタイマコントロール
d7: −
d6: −
d5: −
d4: −
d3: −
d2: −
d1:1=IRQタイマカウント開始、0=IRQタイマカウント停止
d0:1=IRQタイマ許可 、0=IRQタイマ禁止
$4023:(出力) 2C33 I/Oコントロール
d7: −
d6: −
d5: −
d4: −
d3: −
d2: −
d1:サウウンドT/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エンベロープ
d7:エンベロープモード 1=オフ、0=オン
d6:減算/加算 1=減算、0=加算
d5:s5 エンベロープモードオフの場合ゲイン、エンベロープスピード
d4:s4 エンベロープモードオンの場合エンベロープスピード
d3:s3
d2:s2
d1:s1
d0:s0
$4085 MODカウンタ
d7:−
d6:b
d5:b
d4:b
d3:b
d2:b
d1:b
d0:b
$4086 MOD周波数下位
d7:f7
d6:f6
d5:f5
d4:f4
d3:f3
d2:f2
d1:f1
d0:f0
$4087 MOD周波数コントロール+上位
d7:MODユニット 1=オン、0=オフ
d6:
d5:−
d4:−
d3:f11
d2:f10
d1:f9
d0:f8
$4088 MODテーブル
d7:−
d6:−
d5:−
d4:−
d3:−
d2:m2
d1:m1
d0:m0
$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 へ戻る