Навигация по сайту
Follow Us
Funding Request

If you like what we are doing, please consider supporting us.

Support Via Patreon

Visit Our Patreon Profile

Visit our Patreon profile and become a patron.

Any amounts raised will directly support the development of our current and upcoming projects.

Thank you very much!

Принимаем пожертвования

Яндекс: 410012588249319
WMR: R371578751646 (рублики)
WMZ: Z803750001922 (доллары)

Случайная игра

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


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

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

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