Навигация по сайту
Случайная игра

Вступай!!!
Облако тегов
Как расширить ром и переключать банки.


Из чего состоит ром:
из заголовка iNes в 16 байт нужного для эмуляторов, из PRG-rom и CHR-rom(если есть).

В заголовке указано: номер маппера, количество банков prg и chr.

Узнаём эти параметры с помощью эмулятора FCEUX 2.2.2.
После открытия рома: help->message log.

Например ром Chip and Dale.
Нужная нам информация:
PRG ROM: 8 x 16KiB
CHR ROM: 16 x 8KiB
Mapper name: MMC1

Значит имеем 8x16=128 Кб PRG (часть с кодом и данным) и 16x8=128 Кб CHR (часть с графикой - тайлами).
Итого получается 131072+131072+16 = 262160 байт Ром.


Расширить CHR-ROM: (мапперы MMC1, MMC3)
Нам понадобится программа WinHex.
1) Количество chr-банков указано в роме по адресу (offset) 000005.
Его нужно удвоить, то есть меняем 10->20; 20->40, 08->10 (числа указаны в hex)
Максимальный размер CHR для MMC1=128 Кб, для MMC3=256 Кб.
*Ром из примера расширить нельзя, так как уже максимум. Так что надо искать этот же ром переделанный под MMC3.
Большое кол-во таких переделок я видел на сайте raregame.ru ; также можно в good и non-good сетах поискать.

Тогда пока используем другой ром для примера - Ninja Cats.
Параметры такие же, только маппер mmc3:
PRG ROM: 8 x 16KiB
CHR ROM: 16 x 8KiB
Mapper name: MMC3

Меняем используя WinHex: 000005: 10->20
Мы указали вдвое большее количество банков.

2) Теперь доклеим их к рому, увеличив размер файла.
Поскольку увеличивали с 128 до 256 Кб, надо доклеить 128 Кб.
Переходим в WinHex в концу файла (CTRL+END); Нажимаем Edit-paste zero bytes.
Append to the end of file? Нажимаем - yes.
Но значение надо в байтах указывать, 128кб это 131072 байта, указываем нажимаем OK и сохраняем.

После этого перезапускаем ром для проверки:
Должно получиться: CHR ROM: 32 x 8KiB
А размер рома - 384 Кб.


Расширить PRG-ROM: (мапперы MMC1, MMC3, UNROM)
1) Всё почти также как и при расширении CHR, только offset = 000004.
Максимальные размеры PRG для MMC1=256 Кб; для MMC3=512 Кб; для UNROM=256 Кб, но можно и более в зависимости от эмулятора.
Меняем используя WinHex: 000005: 08->10 (Указали вдвое больше количество банков).
2) Теперь надо добавить prg-банков.
Тут вначале разберемся как разбивается PRG-ROM на банки:
Если у нас 128 кб (8 по 16кб), то в общем случае это выглядит так:

--------- rom: 0x10 Cpu: $8000-$BFFF
BANK0
--------- rom: 0x4010 Cpu: $8000-$BFFF
BANK1
--------- rom: 0x8010 Cpu: $8000-$BFFF
BANK2
--------- rom: 0xC010 Cpu: $8000-$BFFF
BANK3
--------- rom: 0x10010 Cpu: $8000-$BFFF
BANK4
--------- rom: 0x14010 Cpu: $8000-$BFFF
BANK5
--------- rom: 0x18010 Cpu: $8000-$BFFF
BANK6
--------- rom: 0x1c010 Cpu: $C000-$FFFF
BANK7
--------- rom: 0x20010 конец PRG рома (Далее пойдет Chr часть рома (если есть))

Банки 0-6 называются подключаемыми, а 7 - постоянным.
(В нём находится большинство кода, и код подключающий банки 0-6 к адресам $8000-$BFFF).

Последний банк находится всегда в конце PRG-ROM'а, поэтому расширение рома производится перед ним:
В WinHex идём к адресу (position-go to offset) 1c010.
Нажимаем Edit-paste zero bytes. Поскольку увеличивали с 128 до 256 Кб, опять же вставляем ещё 128кб (131072 байта).
В примере chip n dale - получим 384 Кб (так как prg мы там не расширяли).
В ninja cats - получим 512 Кб (и prg и chr увеличили в 2раза).

После этого перезапускаем ром для проверки:
PRG ROM: 16 x 16KiB
CHR ROM: 32 x 8KiB


Результат после расширения с 128 до 256 Кб PRG:

--------- rom: 0x10 Cpu: $8000-$BFFF
BANK0
--------- rom: 0x4010 Cpu: $8000-$BFFF
BANK1
--------- rom: 0x8010 Cpu: $8000-$BFFF
BANK2
--------- rom: 0xC010 Cpu: $8000-$BFFF
BANK3
--------- rom: 0x10010 Cpu: $8000-$BFFF
BANK4
--------- rom: 0x14010 Cpu: $8000-$BFFF
BANK5
--------- rom: 0x18010 Cpu: $8000-$BFFF
BANK6
--------- rom: 0x1c010 Cpu: $8000-$BFFF
BANK7 ; новый пустой банк
--------- rom: 0x20010 Cpu: $8000-$BFFF
BANK8 ; новый пустой банк
--------- rom: 0x24010 Cpu: $8000-$BFFF
BANK9 ; новый пустой банк
--------- rom: 0x28010 Cpu: $8000-$BFFF
BANKA ; новый пустой банк
--------- rom: 0x2C010 Cpu: $8000-$BFFF
BANKB ; новый пустой банк
--------- rom: 0x30010 Cpu: $8000-$BFFF
BANKC ; новый пустой банк
--------- rom: 0x34010 Cpu: $8000-$BFFF
BANKD ; новый пустой банк
--------- rom: 0x38010 Cpu: $8000-$BFFF
BANKE ; новый пустой банк
--------- rom: 0x3c010 Cpu: $C000-$FFFF
BANKF ; банк #7 переместился в конец PRG, и теперь он #$0F
--------- rom: 0x40010 конец PRG рома

Далее идёт Chr часть рома (если есть).

Никак вмешательств в код рома не требуется, поскольку оригинальные банки остались на своих местах, а
единственный банк который 'сдвинулся' внутри рома - непереключаемый.



Cooтветственно если надо будет расширять с 256Кб PRG до 512Кб PRG, то адрес вставки будет 0x3c010, а размер - 262144 байта.


Переключение банков:
В большинстве игр уже предусмотрена процедура подключения банков, надо только её найти.

UNROM (только prg)
Чтобы переключить банк на этом маппере надо записать его номер в ром-память. ($8000-$FFFF)
Пример:
LDA #4
STA $8000
Подключили банк #04.

Но эти мапперы требуют, чтобы записываемое число совпало с числом в роме (для избежания т.н. bus conflicts).
Поэтому код выглядит обычно вот так, пример duck tales 2:

; =============== S U B     R O U T     I N E ======================================= 
 
; A=bankID 
 
set_bank:                    ; ... 
          CMP     current_bank 
          BEQ     locret_5400_D39B 
          STA     current_bank 
; End of function set_bank 
 
 
; =============== S U B     R O U T     I N E ======================================= 
 
; A=bank ID 
 
bank_set_nmi:                    ; ... 
          TAY 
          STA     bank_tbls,Y 
 
locret_5400_D39B:               ; ... 
          RTS 
; End of function bank_set_nmi 
 
; --------------------------------------------------------------------------- 
bank_tbls:     .BYTE 0, 1, 2, 3, 4, 5,     6, 7 ; ... 



Указывается номер банка в A. Далее вызывается функция его подключения:
LDA      #4 
 JSR      set_bank 


В ней A копируется в Y, и далее вписывается в таблицу. Таблица содержит номера 0,1,2,3 и т.д.,
таким образом номер записываемого числа (банка) совпадет с числом в роме.
При расширении рома для корректной работы на всех эмуляторах и железе эту таблицу также надо
дописать (При 16 банках - до 0F). Возможно придётся переписать её в другом месте, если место после занято.
Также в этой функции банк дополнительно записывается в current_bank. (текущий номер банка).
Это необходимо для сохранения банка во время обработки кода в nmi. (но некоторые игры содержат заранее
пронумерованные банки по адресам $BFFF или $8000, возможно эти номера придется прописать для добавленных банков).

Исходя из кода выше найти эту процедуру включения банка легко - вбив в winhex в поиске 00010203040506.
(не забываем что может встретиться подобное, но не быть процедурой подключения банка, просто совпадание, так что
проверяем если более 1 раза найдется).

Далее если в новом банке будет именно код, может быть прыжок туда:
LDA     #7 
 JSR      set_bank 
 JSR     $8000     ; начало банка 7, куда будем добавлять новый код. 
  
      ; может быть также необходимо восстановить старый банк,который был до этого. 
 LDA     #4 
 JSR     set_bank 




MMC1 - PRG:
Этот маппер имеет не очень удобную процедуру подключения банка. Но найти её будет не слишком сложно.
Номер банка записывается не разом, а побитно 5 раз. (Запись в адреса рома $E000-$FFFF)

Вот простейший пример:
 LDA     #3     ; номер банка 
          STA     $FFF0     ; записываем 
          LSR     A 
          STA     $FFF0     ; записываем 
          LSR     A 
          STA     $FFF0     ; записываем 
          LSR     A 
          STA     $FFF0     ; записываем 
          LSR     A 
          STA     $FFF0     ; записываем   


А Вот пример процедуры смены банка из игры Chip n Dale 2:

; =============== S U B     R O U T     I N E ======================================= 
 
 
change_prg_bank:               ; ... 
          PHP 
          CMP     current_bank 
          BEQ     loc_5400_C2E3 
          STA     current_bank 
          INC     bank_changing_flag 
          STA     $EFFF 
          LSR     A 
          STA     $EFFF 
          LSR     A 
          STA     $EFFF 
          LSR     A 
          STA     $EFFF 
          LSR     A 
          STA     $EFFF 
          DEC     bank_changing_flag 
 
loc_5400_C2E3:                    ; ... 
          PLP 
          RTS 
; End of function change_prg_bank 



То есть чтобы включить нужный добавленный PRG-банк, указываем его номер, и вызываем готовую функцию
подключения банка:
 LDA      #7     ; номер-банка-7       ; hex - A9 07 
 JSR     $C298     ; change_prg_bank ; hex - 20 98 C2




MMC1 - CHR:
Подключение CHR похоже на PRG, только Адреса рома куда записывать номера - $B000-$BFFF, и $D000-$DFFF.
Так что в случае MMC1 всё сводится к нахождению готовых процедур и изучения их работы.
Пример опять же Chip n Dale2, функция указывает chr-банки. Номера в X и Y.

; =============== S U B     R O U T     I N E ======================================= 
 
 
change_chr_bank:               ; ... 
          INC     bank_changing_flag 
          TXA 
          STA     $BFFF 
          LSR     A 
          STA     $BFFF 
          LSR     A 
          STA     $BFFF 
          LSR     A 
          STA     $BFFF 
          LSR     A 
          STA     $BFFF 
          TYA 
          STA     $DFFF 
          LSR     A 
          STA     $DFFF 
          LSR     A 
          STA     $DFFF 
          LSR     A 
          STA     $DFFF 
          LSR     A 
          STA     $DFFF 
          DEC     bank_changing_flag 
          RTS 
; End of function change_chr_bank 


Но если посмотреть код дальше, то номера X и Y для этой функции считываются из адресов RAM 1f и 20.
То есть в случае с CHR никакого вмешательства скорее всего не потребуется.
Достаточно будет указать только новый номер в том месте, где задавались номера блоков графики, но уже
из новых добавленных банков, а игра всё сделает за вас.



MMC3 - PRG и CHR.
В этом маппере вначале указываем что меняем, а затем его номер.
В $8000 - записываем что менять (регистр), $8001 - номер банка (данные).
Регистры 0-1 - переключают 2 блока графики фона по 4кб каждый.

 LDA #0          ; меняем блок графики фона - верхний кусок в 4 Кб. 
 STA $8000 
 LDA #34     ; номер - 34  (при 256Кб всего 128 номеров по 2кб). 
 STA $8001 
  
 LDA #1          ; меняем блок графики фона - нижний кусок в 4 Кб. 
 STA $8000 
 LDA #36     ; 
 STA $8001 


Регистры 2-5 - переключают 4 блока графики спрайтов по 2кб каждый.

LDA #2          ; меняем блок графики спрайтов - первый кусок в 2кб. 
 STA $8000 
 LDA #44     ; номер 
 STA $8001 
  
 LDA #3          ; меняем блок графики спрайтов - второй кусок в 2кб. 
 STA $8000 
 LDA #49     ; номер 
 STA $8001 
  
 LDA #4          ; меняем блок графики спрайтов - третий кусок в 2кб. 
 STA $8000 
 LDA #15     ; номер 
 STA $8001 
  
 LDA #5          ; меняем блок графики спрайтов - четвёртый кусок в 2кб. 
 STA $8000 
 LDA #33     ; номер 
 STA $8001 
  

Регистры 6-7 - переключают 2 банка PRG.
То есть у MMC3 на самом деле 2 подключаемых банка - один $8000-$9FFF; и второй $A000-$BFFF.
Поэтому номер PRG указывает не для 16Кб блоков а для 8Кб блоков.
(7-ой для MMC1/UNROM, станет парой $0E и $0F для mmc3)


LDA #6          ; меняем prg-bank #1  (cpu: $8000-$9FFF ) 
 STA $8000 
 LDA #$0E     ; номер 
 STA $8001 
  
 LDA #7          ; меняем prg-bank #2 (cpu: $A000-$BFFF ) 
 STA $8000 
 LDA #$0F     ; номер 
 STA $8001 


Также в связи с этим есть такой момент, что один и тот же банк может быть подключен как в $8000-$9FFF, так и
$A000-$BFFF.
Многие игры этим пользуются, что может усложнять хакинг.
Также могут использовать другие режимы и положение банков в роме.(вначале $A000-$BFFF, а потом $8000-$9FFF)
Могут и режим спрайтов/фона поменять (4 сменных куска фона, и 2 спрайтов) - но такое редко.

Другое дело что бывают ромы где фискированным банком является $8000-$BFFF; а $C000-$FFFF - переключаемым.

Из-за этого некоторые игры могут потребовать дополнительные корректировки при расширении (пример TMNT3,TMNT-Tournament Fighters)
(Для начала попробовать не добавлять нулевые байты, а продублировать целиком prg-банк с copy-paste, либо
скопировать какие-то отдельные банки на место новых добавленных)

Использовать процедуры смены CHR-банка, опять же врядли понадобится,
а вот примеры для переключения PRG из игры Ninja Cats:

; =============== S U B R O U T I N E =======================================


set_4k_prg_bank: ; set 2 banks
STX prg1_id
LDY #6
STY last_bank_register
STY $8000
STX $8001
INX
STX prg2_id
INY ; 6->7
STY last_bank_register
STY $8000
STX $8001
RTS
; End of function set_4k_prg_bank


; =============== S U B R O U T I N E =======================================


set_2k_prg_bank: ; ...
STX prg1_id
LDY #6
STY last_bank_register
STY $8000
STX $8001
RTS
; End of function set_2k_prg_bank

; =============== S U B R O U T I N E =======================================


set_2k_prg_bank2: ; ...
LDX #7
STX last_bank_register
STX $8000
STA $8001
STA prg2_id
RTS
; End of function set_2k_prg_bank2



Так что опять же всё сводится к поиску уже готовых процедур смены банков в роме.
В этом варианте , чтобы их найти смотрим в роме записи подобного вида:
STA     $8000  ; hex - $8D 00 $80 
STA     $8001  ; hex - $8D 01 $80 
STX     $8000  ; hex - $8E 00 $80 
STX     $8001  ; hex - $8E 01 $80 
STY     $8000  ; hex - $8C 00 $80 
STY     $8001  ; hex - $8C 01 $80 


Более подробную информацию можно прочитать на http://wiki.nesdev.com/w/index.php/MMC3


Если пригодилось ждите новых статей:
1) как быстро найти звуковой движок в роме / как открыть ром в IDA.
2) как использовать symbolic debug в fceux debugger, автоматически полученный из asm6_sonder.

Если ничего не получилось, отписывайтесь что именно не ясно.

Автор статьи - Ti (c) 2014.



Вернуться
  • Комментарий: 1
  • Просмотров: 4812
hooddy
#1
  • 3 января 2017 16:16
  • Регистрация: --
  • ICQ: {icq}
  • Комментариев: 0
  • Новостей: 0
Круто. Правда, совершенно непонятно, для чего это нужно делать. У меня есть тривиальная задача - некоторые ромы некорректно работают на эмуле pocketnes под gba. Моежете ли в жтом помочь? По понкретному рому исходя из возможностей эмулятора сделать вывод, можно его пропатчить или нет.

Комментарии:

Оставить комментарий