Навигация по сайту
- Игры / Образы
- Игры на русском языке
- Коды / Советы / Секреты
- Наши переводы
- Наши проекты
- Игры на русском языке (OnLine)
- Эмуляторы
- Обзоры игр
- Информация
- Статьи
- Интервью
- Мануалы / Инструкции
Случайная игра
Вступай!!!
Облако тегов
Показать все теги
Как расширить ром и переключать банки.
Из чего состоит ром:
из заголовка 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
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.