ピロ彦の何か置き場

4レーへとは何なのか?

4レーへを使用した時の不具合を簡潔にいうと、アイテム名とルーラ登録名の間に2バイトの開始アドレスが挟まっているせいでバグアイテム名としてルーラ登録名を参照すると文字数が0になって文字展開バッファ$0634から255文字展開しようとしてバンク設定が記憶されてるメモリ$06C7まで侵食してしまってバンク切り替えミスが発生して壮大にバグるというものである。

1/60に一回発生するNMI割り込み発生後、バンク切り替えミスでプログラムカウンタが最終的にカートリッジRAMである$6167に到達するので、$6167に任意のコードを仕込むんで実行することが可能になる。


名前配列 1~7文字  8:濁点ビット 9:文字数
$02800E = 10 80            アイテム名開始アドレス $8010
$028010 = 25 23 11 23 28 0D 00 04 06  ひのきのぼう  0b0000100 6文字
$028019 = 14 38 28 0D 00 00 00 10 04  こんぼう    0b0010000 4文字
$028022 = 1E 0D 23 1C 33 11 00 42 06  どうのつるぎ  0b1000010 6文字
$02802B = 18 0C 1F 33 4A 3E 4F 00 07  せいなるナイフ 0b0000000 7文字
$028020 = 24 10 22 23 1C 33 11 21 07  はがねのつるぎ 0b0100001 7文字
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$02845A = CD 7F CF 57 3F 7F 4F 51 07  パープルオーブ 0b1010001 7文字
$028463 = 4F 57 7F 3F 7F 4F 00 42 06  ブルーオーブ  0b1000010 6文字
$02846C = 42 32 7F 5A 3F 7F 4F 41 07  グリーンオーブ 0b1000001 7文字
$028475 = 77 84            ルーラ登録名開始アドレス $8477
$028477 = 3D 32 3D 4D 5A 00 00 00 05 アリアハン     0b0000000 5文字
$028480 = 58 7F 27 00 00 00 00 10 03 レーベ         0b0010000 3文字
$028489 = 59 51 32 3D 00 00 00 00 04  ロマリア    0b0000000 4文字

↓バグアイテム名として文字列展開する場合、文字数と濁点フラグが00になる
$02845A = CD 7F CF 57 3F 7F 4F 51 07  パープルオーブ 0b1010001 7文字
$028463 = 4F 57 7F 3F 7F 4F 00 42 06  ブルーオーブ  0b1000010 6文字
$02846C = 42 32 7F 5A 3F 7F 4F 41 07  グリーンオーブ 0b1000001 7文字
$028475 = 77 84 3D 32 3D 4D 5A 00 00   ̄→アリアハン 0b0000000 0文字
$02847E = 00 05 58 7F 27 00 00 00 00   4レーヘ   0b0000000 0文字
$028487 = 10 03 59 51 32 3D 00 00 00  か2ロマリア  0b0000000 0文字


$0634に展開される文字列
77 84 3D 32 3D 4D 5A 00 00  ̄→アリアハン  
00 05 58 7F 27 00 00 00 00  4レーヘ     
10 03 59 51 32 3D 00 00 00 か2ロマリア  
00 04 40 44 7F 4F 00 00 00  3カサーフ   
28 04 5E 3D 5C 7F 57 00 00 ほ3ノアニール     
00 05 3D 60 44 56 7F 53 00  4アッサラーム 
00 06 3E 45 46 00 00 00 00  5イシス
00 03 D0 57 49 40 00 00 00  2ホルトカ
48 04 4D 4D 56 47 00 00 00 テ3ハハラタ    
40 04 47 7F 51 00 00 00 00 カ3ターマ    
40 03 56 5A 45 7F 57 00 00 カ2ランシール    
00 05 45 CD 5A 42 00 00 00  4シINンク
68 04 5B 45 5A 27 3D 00 00 。3エシンヘア    
28 05 44 51 5A 3F 44 00 00 ほ4サマンオサ    
00 04 46 7F 00 00 00 00 00  3スー
00 02 56 47 49 7F 53 00 00  1ラタトーム    
20 05 49 53 49 7F 56 00 00 に4トムトーラ
     ↑ ̄→アリアハンを使うとバンク設定が53
50 05 54 57 41 49 00 01 01 メルキド
     ↑ 4レーへを使うとバンク設定が57
08 04 51 3E 56 00 00 00 0E マイラ
     ↑か2ロマリア(ID:7Fの空白)を使うとバンクが設定3Eになるが確定フリーズ

↓4レーへを捨てた時のNMI後
$C955:48        PHA                        A:E4 X:A6 Y:0F S:D0 P:nvUBdIzC
$C956:98        TYA                        A:E4 X:A6 Y:0F S:CF P:nvUBdIzC
$C957:48        PHA                        A:0F X:A6 Y:0F S:CF P:nvUBdIzC
$C958:8A        TXA                        A:0F X:A6 Y:0F S:CE P:nvUBdIzC
$C959:48        PHA                        A:A6 X:A6 Y:0F S:CE P:NvUBdIzC
$C95A:A9 10     LDA #$10                   A:A6 X:A6 Y:0F S:CD P:NvUBdIzC
$C95C:25 1B     AND $001B = #$00           A:10 X:A6 Y:0F S:CD P:nvUBdIzC
$C95E:D0 07     BNE $C967                  A:00 X:A6 Y:0F S:CD P:nvUBdIZC
$C960:A9 00     LDA #$00                   A:00 X:A6 Y:0F S:CD P:nvUBdIZC
$C962:85 33     STA $0033 = #$02           A:00 X:A6 Y:0F S:CD P:nvUBdIZC
$C964:20 35 CA  JSR $CA35                  A:00 X:A6 Y:0F S:CD P:nvUBdIZC
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$CAD8:60        RTS                        A:02 X:A6 Y:0F S:CB P:nvUBdIzC
$C967:20 B6 C9  JSR $C9B6                  A:02 X:A6 Y:0F S:CD P:nvUBdIzC
$C9B6:EE DF FF  INC $FFDF = #$80           A:02 X:A6 Y:0F S:CB P:nvUBdIzC
----------------↓$06C7は通常0x0Eが入っている----------------------------
$C9B9:AD C7 06  LDA $06C7 = #$57           A:02 X:A6 Y:0F S:CB P:NvUBdIzC
$C9BC:20 37 C6  JSR $C637                  A:57 X:A6 Y:0F S:CB P:nvUBdIzC
$C637:8D C7 06  STA $06C7 = #$57           A:57 X:A6 Y:0F S:C9 P:nvUBdIzC
$C63A:8D FF 9F  STA $9FFF = #$AF           A:57 X:A6 Y:0F S:C9 P:nvUBdIzC
$C63D:4A        LSR                        A:57 X:A6 Y:0F S:C9 P:nvUBdIzC
$C63E:8D FF 9F  STA $9FFF = #$AF           A:2B X:A6 Y:0F S:C9 P:nvUBdIzC
$C641:4A        LSR                        A:2B X:A6 Y:0F S:C9 P:nvUBdIzC
$C642:8D FF 9F  STA $9FFF = #$AF           A:15 X:A6 Y:0F S:C9 P:nvUBdIzC
$C645:4A        LSR                        A:15 X:A6 Y:0F S:C9 P:nvUBdIzC
$C646:8D FF 9F  STA $9FFF = #$AF           A:0A X:A6 Y:0F S:C9 P:nvUBdIzC
$C649:4A        LSR                        A:0A X:A6 Y:0F S:C9 P:nvUBdIzC
$C64A:8D FF 9F  STA $9FFF = #$AF           A:05 X:A6 Y:0F S:C9 P:nvUBdIzc
--------↑ここでバンクサイズが16KBモードから32KBモードになる-------------
--------$8000-$BFFFがバンク0Aだった場合、$C000-$FFFFはバンク0Bになる------
$C64D:94 5A     STY $5A,X @ $0100 = #$03   A:05 X:A6 Y:0F S:C9 P:nvUBdIzc
--------↓メッセージ群のバンク0Bがプログラムとして実行されている---------
$C64F:82        UNDEFINED                  A:05 X:A6 Y:0F S:C9 P:nvUBdIzc
$C651:2B        UNDEFINED                  A:05 X:A6 Y:0F S:C9 P:nvUBdIzc
$C653:78        SEI                        A:05 X:A6 Y:0F S:C9 P:nvUBdIzc
$C654:B7        UNDEFINED                  A:05 X:A6 Y:0F S:C9 P:nvUBdIzc
$C656:DA        UNDEFINED                  A:40 X:40 Y:0F S:C9 P:nvUBdIzc
$C657:BA        TSX                        A:40 X:40 Y:0F S:C9 P:nvUBdIzc
$C658:66 DC     ROR $00DC = #$44           A:40 X:C9 Y:0F S:C9 P:NvUBdIzc
$C65A:5F        UNDEFINED                  A:40 X:C9 Y:0F S:C9 P:nvUBdIzc
$C65D:C9 75     CMP #$75                   A:6B X:C9 Y:0F S:C9 P:nvUBdIzC
$C65F:E8        INX                        A:6B X:C9 Y:0F S:C9 P:NvUBdIzc
$C660:9F        UNDEFINED                  A:6B X:CA Y:0F S:C9 P:NvUBdIzc
$C663:96 36     STX $0036,Y @ $0045 = #$01 A:6B X:CA Y:0F S:C9 P:NvUBdIzc
$C665:80        UNDEFINED                  A:6B X:CA Y:0F S:C9 P:NvUBdIzc
$C667:6C E8 C1  JMP ($C1E8) = $6167        A:6B X:CA Y:0F S:C9 P:NvUBdIzc
----------------↑$6167にジャンプ----------------------------------------

$9FFFへの書き込みについては下記を参照
https://wiki.nesdev.org/w/index.php/MMC1#Control_.28internal.2C_.248000-.249FFF.29
http://www43.tok2.com/home/cmpslv/Famic/Fcmp1.htm
Control (internal, $8000-$9FFF)
4bit0
-----
CPPMM
|||||
|||++- Mirroring (0: one-screen, lower bank; 1: one-screen, upper bank;
|||               2: vertical; 3: horizontal)
|++--- PRG ROM bank mode (0, 1: switch 32 KB at $8000, ignoring low bit of bank number;
|                         2: fix first bank at $8000 and switch 16 KB bank at $C000;
|                         3: fix last bank at $C000 and switch 16 KB bank at $8000)
+----- CHR ROM bank mode (0: switch 8 KB at a time; 1: switch two separate 4 KB banks)

 

MMC1は通常$8000-$BFFFの16KBは動的に切り替えられ$C000-$FFFFの16KBは最終バンクに固定されているが、PRG ROMバンクモードが32KBに切り替わると$8000-$FFFFまでが一括に読み込まれることになる。

文字展開ルーチン中は文字列を読み込むためのバンク0Aと文字書き込みプログラムのバンク0Eが交互に切り替わっているため、バンク0AのタイミングでNMI割り込みが発生すると最終バンク0Fで固定されてる$C000-$FFFFがバンク0Bになる。

$C5F4:20 BD FF  JSR $FFBD                  A:0A X:10 Y:0D S:E7 P:nvUbdizC
----------------↑バンク0Aに変更
$C5F7:B5 00     LDA $00,X @ $0010 = #$7E   A:00 X:10 Y:0D S:E7 P:nvUbdiZC
$C5F9:85 21     STA $0021 = #$7E           A:7E X:10 Y:0D S:E7 P:nvUbdizC
$C5FB:B5 01     LDA $01,X @ $0011 = #$84   A:7E X:10 Y:0D S:E7 P:nvUbdizC
$C5FD:85 22     STA $0022 = #$84           A:84 X:10 Y:0D S:E7 P:NvUbdizC
$C5FF:B1 21     LDA ($21),Y @ $848B = #$32 A:84 X:10 Y:0D S:E7 P:NvUbdizC
----------------↑バンク0Aからテキストを読み込み
$C601:85 23     STA $0023 = #$51           A:32 X:10 Y:0D S:E7 P:nvUbdizC
$C603:68        PLA                        A:32 X:10 Y:0D S:E7 P:nvUbdizC
$C604:20 BD FF  JSR $FFBD                  A:0E X:10 Y:0D S:E8 P:nvUbdizC
----------------↑バンク0Eに変更
$C607:A6 34     LDX $0034 = #$10           A:00 X:10 Y:0D S:E8 P:nvUbdiZC
$C609:A4 35     LDY $0035 = #$0D           A:00 X:10 Y:0D S:E8 P:nvUbdizC
$C60B:A5 23     LDA $0023 = #$32           A:00 X:10 Y:0D S:E8 P:nvUbdizC
$C60D:60        RTS                        A:32 X:10 Y:0D S:E8 P:nvUbdizC
$B005:99 34 06  STA $0634,Y @ $0641 = #$EA A:32 X:10 Y:0D S:EA P:nvUbdizC
----------------↑$0634+Yに文字展開するプログラム
$B008:C8        INY                        A:32 X:10 Y:0D S:EA P:nvUbdizC
----------------↑Y=Y+1
$B009:C4 7B     CPY $007B = #$00           A:32 X:10 Y:0E S:EA P:nvUbdizC
$B00B:D0 F1     BNE $AFFE                  A:32 X:10 Y:0E S:EA P:nvUbdizC
$AFFE:A9 0A     LDA #$0A                   A:32 X:10 Y:0E S:EA P:nvUbdizC
$B000:A2 10     LDX #$10                   A:0A X:10 Y:0E S:EA P:nvUbdizC
$B002:20 E8 C5  JSR $C5E8                  A:0A X:10 Y:0E S:EA P:nvUbdizC
$C5E8:85 36     STA $0036 = #$0A           A:0A X:10 Y:0E S:E8 P:nvUbdizC
$C5EA:AD D5 06  LDA $06D5 = #$0E           A:0A X:10 Y:0E S:E8 P:nvUbdizC
$C5ED:48        PHA                        A:0E X:10 Y:0E S:E8 P:nvUbdizC
$C5EE:86 34     STX $0034 = #$10           A:0E X:10 Y:0E S:E7 P:nvUbdizC
$C5F0:84 35     STY $0035 = #$0D           A:0E X:10 Y:0E S:E7 P:nvUbdizC
$C5F2:A5 36     LDA $0036 = #$0A           A:0E X:10 Y:0E S:E7 P:nvUbdizC
$C5F4:20 BD FF  JSR $FFBD                  A:0A X:10 Y:0E S:E7 P:nvUbdizC
----------------↑バンク0Aに変更


計算するとバンク0Aの間は74サイクル、バンク0Eは98サイクルで合計172サイクル。
バンク0Aのタイミングは43%ほどの計算になる。
とはいえ1フレーム中の処理量によって変化するのである程度音声タイミングやグラフィック処理で偏る。

DQ3は最終バンク以外にはリセットベクタ等が正しく記述されていないため、PRG ROMバンクモードが32KBだとリセットをしても、電源を入れ直しても、正しく起動しないことがある。