Навигация по сайту
- Игры / Образы
- Игры на русском языке
- Коды / Советы / Секреты
- Наши переводы
- Наши проекты
- Игры на русском языке (OnLine)
- Эмуляторы
- Обзоры игр
- Информация
- Статьи
- Интервью
- Мануалы / Инструкции
Случайная игра
Вступай!!!
Облако тегов
Показать все теги
Команды загрузки и записи, изучение дебаггера
В танчиках сделай рестарт, теперь ты находишься в меню выбора режима игры. Поставь эмулятор на паузу, найди в NES адрес 0051 (счетчик жизней). Нажми на него правой кнопкой - Add Write Breakpoint. Для основной оперативки бывают 2 вида бряка - на чтение и на запись. Они вылавливают команды загрузки и записи соответственно по нужным тебе адресам. Сейчас нам интересен момент записи количества жизней в этот адрес, поэтому выбирай Write.
У тебя откроется окно дебаггера. Пока что сверни это окно, теперь переключись на эмулятор, сними паузу и нажми кнопку Start. Если ты все сделал правильно, то на экране все еще будет меню с выбором режима, вылезет окно дебаггера, а эмулятор поставится на паузу.
Взглянем на окно дебаггера. Здесь очень много всего, так что будем потиху разбирать самое важное для тебя. Промотай стрелочкой текст чуть повыше, чтобы выглядело примерно как у меня на скрине. Окно можешь растянуть как тебе удобнее.
Разберем левую часть окна. Адреса команд (всегда указаны по тем же адресам, что и в NES), байты команд и перевод этих байтов в текстовый вариант. У каждой команды процессора есть свой номер (байт). Дебаггер распознает эти байты и отображает их здесь.
Стрелочка сейчас находится там, где собирается выполниться код. Адрес рядом со стрелочкой аналогичен адресу рядом с кнопкой Seek PC. Промотай экран на несколько страниц вверх или вниз, нажми эту кнопку, и дебаггер вернет тебя на позицию стрелочки.
При помощи бряка мы выловили момент попытки записать количество жизней в адрес 0051, но этого еще не произошло. Команда LDA расшифровывается как загрузить байт в A (Load to A). A - это один из трех важнейших регистров, он используется для хранения байтов и для различных операций с этим байтом. В дебаггере ты увидишь регистр A его рядом с байтом 03, как и другие 2 регистра - X и Y. Справа от каждого регистра находится байт, который уже был ранее в них загружен. Эти байты можно менять вручную, что иногда полезно для тестирования кода. Байт 03 оказался в регистре A при помощи команды LDA #$03. Команда STA - записать байт из A в определенный адрес (Set A to). STA $0051 = записать байт из A в адрес 0051 (адрес с жизнями первого игрока). Нажав кнопку Step Into, код сделает 1 шаг вперед и выполнит команду. Далее идет следующая команда - STA $0052 - записать этот же байт в 0052 (адрес с жизнями второго игрока). Снова нажми Step Into, код сделает еще 1 шаг вперед и выполнит эту команду.
Сейчас твоя задача - увеличить начальное количество жизней. Ты уже нашел нужную команду (LDA #$03), теперь надо найти и поменять байт 03 на какой-то другой. Есть несколько способов найти этот байт, покажу самый простой.
Слева от LDA адрес C2CD. Кликни в дебаггере 1 раз на этом адресе, он выделится, скопируй его. Переходишь в хекс, жмешь Ctrl+G, откроется окошко, вставь этот адрес и нажми ОК.
A9 - байт команды LDA, 03 - байт с жизнями. Кликаешь на байте правой кнопкой - Go Here In ROM File. Тебя перекинет на реальный адрес этого байта в ROM (этот адрес всегда будет отличаться от адреса в NES). Меняешь байт 03 например на 05, затем в хексе File - Save Rom As, сохраняешь ром под другим именем. Если использовать Save Rom вместо Save Rom As, измененые байты сразу же запишутся в ром, с которым ты работаешь, а также эти байты снова станут черными, и ты уже не сможешь отменить изменения. Открой еще одно окно эмулятора, открой этот ром и проверь, изменилось ли количество жизней.
Поздравляю с твоим первым хаком!
Подробное изучение команд
Сначала я расскажу про регистр статуса процессора. Это еще один очень важный регистр. Байт, находящийся в нем, разбивается на биты, и каждый бит отражает состояние процессора и свойства результатов предыдущих операций. В статусе процессора биты называются флагами. Флаг - индикатор того, что было/не было произведено определенное действие. Он как лампочка на панели управления, которая загорается или тухнет в зависимости от чего-то, к чему она привязана. Если бит = 0, то привязанный к нему флаг будет деактивирован (очищен), если бит = 1, флаг будет активен (выставлен). Я предпочитаю слова активен и очищен. Сам байт тебе не понадобится разбивать на биты, эмулятор уже сделал это за тебя и отобразил на отдельной панели в дебаггере. Кстати, ты можешь кликать по этим галочкам, меняя вручную состояние флагов, иногда полезно для тестирования кода.
Во время загрузки байта командами загрузки обновляется статус процессора, а конкретно флаги N (бит7) и Z (бит1). Флаг N указывает на то, положительный или отрицательный это байт. Процессор считает положительными байтами 00-7F, а отрицательными - 80-FF. Если байт положительный, флаг N очищается, если отрицательный - активируется. Флаг Z указывает на то, что байт = или ≠00. Если байт = 00, флаг Z активируется, если ≠00 - очищается. Оба флага никак не влияют на команды загрузки и записи, но они окажут влияние на другие команды. Для сокращения я буду писать N-, N+, Z-, Z+.
Execute 8100
Я буду переписывать команды из дебаггера сюда и объяснять их. Читай и пошагово прокручивай код. Некоторые читатели могут читать учебник вдали от компа, так что скриншоты команд прилагаются. Скрин может слегка отличаться от того, что ты видишь у себя в дебаггере прямо сейчас.
LDA #$00
STA $00FF
Ничего примечательного, похожий код ты уже видел. Грузим 00 в A, при этом Z+ (байт = 00), N- (это положительный байт). Пишем 00 в 00FF.
LDA #$95
STA $00FF
STA $00FF
Z- (байт ≠00), N+ (отрицательный байт). 95 2 раза подряд пишется в 00FF. При таком коде вторая команда просто перезапишет 95 по этому адресу, по сути она не делает ничего полезного, но сами команды STA отличаются друг от друга. В первой используются 2 байта - 85 FF, а во второй уже 3 байта - 8D FF 00. 85 и 8D - разновидности команды STA. Смысл этих команд один и тот же, но команда 85 может работать только с диапазоном адресов 0000-00FF, а 8D - 0000-FFFF, то есть по максимуму. 85 используется для экономии места, и разработчики игр активно этим пользуются, что слегка усложняет ромхакинг, если тебе нужно поменять адрес на более крупный, и не только. Адрес для команд с двумя байтами вроде 85 вычисляется так: по умолчанию адрес 0000, к нему прибавляется FF = 00FF. В процессоре адрес для любых команд с тремя байтами вроде 8D вычисляется по-другому: FF и 00 переворачиваются местами = 00FF. В дебаггере сразу отображается итоговый адрес, а после него - байт, который в нем уже записан. Я предпочитаю использовать команду 8D, и прочие команды процессора, которые охватывают весь диапазон. На скрине со списком команд отображены в основном команды, охватывающие максимальный диапазон, они подписаны как АДРЕС. Там есть и другие команды с нулевым адресом вроде 85, они подписаны как адрес, там их немного, но они там только из-за того, что не существует другой разновидности.
LDX #$01
LDY #$20
Байт можно загружать не только в A, но также в X и Y, для каждого регистра своя команда. Байты появятся в дебаггере рядом с этими регистрами. Z-, N-, им не важно какой из трех регистров ты используешь.
STX $0123
STY $0124
Записываем байты из этих регистров по разным адресам.
LDA $012E,X
STA $012C,Y
Для вычисления адреса в командах загрузки и записи тебе может пригодиться любой из двух регистров X и Y, которые я называю регистрами координат, потому что они могут использоваться для уточнения конечных адресов. Сейчас X = 01, Y = 20. Адрес вычисляется так: 012E + X = 012F, 012C + Y = 014C. Дебаггер отображает итоговый адрес, однако в течении всего кода X и Y могут несколько раз меняться, пока код не дойдет до нужного тебе места, и соответственно будут пересчитываться адреса, это нужно учитывать при просмотре кода. Правильным итоговым адресом можно считать тот адрес, который дебаггер отображает в момент выполнения команды. Причем в разное время могут быть разные байты в X и Y, но для того эти команды и существуют, чтобы одной такой командой охватить несколько адресов. При грамотном использвании этих команд можно значительно сократить размер кода.
LDY #$2F
Обновим Y.
STX $00FF,Y
LDY $0134,X
X и Y могут использовать друг друга для вычисления конечного адреса для загрузки и записи. Для команд загрузки STX,Y и STY,X существуют лишь варианты с нулевым адресом, а для максимального адреса нельзя использовать противоположный регистр. Это может показаться немного неудобным, но на то они и вспомогательные регистры, у них ограниченные возможности. Записи по адресам лучше проводить через A.
LDX #$17
LDY #$9D
Обновим байты в регистрах.
LDA ($4E,X)
LDA ($8A),Y
Это 2 сложные команды загрузки. Есть 2 аналогичные команды записи, но я их в своем хаке не прописывал, ведь они могли повлиять на работу игры. Этими командами я сам почти не пользуюсь, но ты можешь встретить их во время просмотра кода игры, и тебе нужно понимать как в них вычисляется адрес. Сейчас я не могу знать что творится в твоей оперативке, поэтому просто покажу механику.
Разберем команду LDA ($4E,X). Итоговый адрес вычисляется так:
1. по умолчанию адрес 0000.
2. 0000 + 4E + X = адрес1.
3. читается байт1 из адреса1.
4. читается байт2 из адреса2 (адрес1 + 01).
5. байт1 и байт2 меняются местами = итоговый адрес, отсюда загружается байт в A.
Теперь разберем команду LDA ($8A),Y. Вот как вычисляется итоговый адрес:
1. по умолчанию адрес 0000
2. 0000 + 8A = адрес1.
3. читается байт1 из адреса1.
4. читается байт2 из адреса2 (адрес1 + 01).
5. оба байта меняются местами = адрес3.
6. адрес3 + Y = итоговый адрес, отсюда загружается байт в A.
A1 использовал X для вычисления адреса на начальном этапе, а B1 использовал Y в самом конце. Чтобы было проще запомнить, обрати внимание на отображение команд в дебаггере: X находится в скобке (помогает вычислению адресов, откуда будут считываться байты), а Y вынесен за скобки (помогает вычислить итоговый адрес). Как в реальной математике - то, что находится в скобках, вычисляется первее. Ты прикинь, вероятно вот он, тот самый случай, про который тебе в школе твердили учителя - применение знаний на практике. Не зря же ты домашку делал.
RTS -----
Эта команда завершает отрезок кода, про нее я расскажу в командах со стеком. Палочки после команды просто для удобства восприятия.
А пока на этом все. В этой статье были показаны не все разновидности, но это не страшно, в дебаггере все равно показывается что это за команда, а разновидность легко понять по количеству байтов и по методу вычисления конечного адреса. И еще раз напомню про обновление состояния флагов во время загрузки байтов.
Команды сравнения
Команды сравнения бывают CMP, CPX и CPY для каждого регистра соответственно. Само сравнение происходит с помощью вычитания из регистра некого байта, а результат этого вычитания будет отображаться во флагах N, Z и C, то есть команды сравнения нужны как раз для того, чтобы повлиять на эти флаги. Напомню для чего нужен каждый флаг:
• N - активен если байт или результат отрицательный (80-FF), очищен если положительный (00-80)
• Z - активен если байт или результат = 00, очищен если ≠00
• C - его мы еще не изучали. Он активен если байт больше или = байту, с которым тот сравнивался, очищен если меньше. На этот флаг можно повлиять не только сравнением, но об этом в других статьях.
А для того, чтобы использовать состояние этих флагов в своем коде, существуют 6 команд, по 2 на каждый флаг.
Execute 8200
LDA #$99
LDX #$12
LDY #$01
STA $0130
STX $0131
STY $0132
Подготовка кода. Это значит что я специально прописал эти команды для дальнейшей демонстрации работы кода.
LDA $0131
В A загрузили 12. N-, Z-. C не обновляется при загрузке.
CMP #$12
Сравниваем A с байтом 12. Результат = 00, N-, Z+. C+, потому что A оказался больше или = 12. В A все еще 12, потому что команды сравнения не меняют байты в регистрах, они только оказывают влияние на флаги.
BEQ 8219
STA $0134
BEQ - проверка на = 00, то есть команда проверяет на Z+. Если активен, условие команды выполняется, код перепрыгнет STA и окажется на адресе 8219, который в дебаггере прописан после BEQ. Разберемся откуда взялся 8219. BEQ состоит из двух байтов - сама команда F0 + байт 03 (расстояние прыжка). BEQ прописан по адресу 8214. Адрес прыжка высчитывается так: 8214 + 02 + 03 = 8219. Недалекие прыжки легко посчитать на глаз. Команда STA = 8D + 34 + 01 = 3 байта, и если ты хочешь перепрыгнуть только STA, то прописываешь 03. При промотке кода STA перепрыгивается. Код уже становится интересней, это больше не загрузка + запись, а запись при каком-то условии.
BNE $8220
LDA #$00
STA $0134
Z все еще +. BNE проверяет на ≠00, то есть на Z-. Условие не выполнено, код запишет 00 в 0134. Если бы условие было выполнено, код прыгнул бы на 8220 (8219 + 02 + 05).
LDX $0132
CPX #$05
BMI $822A
STY $0135
X = 01. 01 - 05 = FC. В процессоре нету таких чисел как минус 4, поэтому если байт меньше вычитаемого, мысленно прибавляй к нему 100. Получится 101 - 05 = FC. N+, Z-. C-, потому что X оказался меньше 05. BMI проверяет на отрицательный байт. N+, условие выполнено, прыжок.
LDX #$03
Подготовка кода.
LDY $012D,X
CPX #$03
CPY #$03
BPL $8238
LDA $0132
Загрузили 99 в Y. Но дальше идет CPX, которому не интересен Y, ведь он проверяет X. Нужно быть внимательным при прописывании кода и не путать команды. CPX проверит X, 03 - 03 = 00, N-, Z+, C+. CPY проверит Y, 99 - 03 = 96, N+, Z-, C+. BPL проверяет на положительный байт. N+, условие не выполнено, A = 01.
CMP #$02
BCS $8200
BCC $823F
RTS -----
LDA $0150,Y
RTS -----
01 - 02 = FF. N+, Z-, C-. BCS проверяет на C+. Условие не выполняется - код идет дальше. Кстати, прыжок уже в обратную сторону, на 8200. После BCS прописан C4. Дело в том, что при помощи всех этих 6 команд можно прыгать не только вперед (положительными байтами), но и назад (отрицательными байтами). Если ты поменяешь байт после команды и кликнешь на дебаггер, он обновит адрес для прыжка, поэтому ты можешь корректировать адрес для прыжка сколько угодно, пока не попадешь на нужный. К счастью, условие BCS не выполняется, иначе мы бы прыгнули в самое начало и все началось бы по новой. Таким образом можно даже зациклить код, если он составлен неправильно. BCC проверяет на C-, условие выполнено, прыжок на LDA. Еще один вариант зацикливания - если прописать FE после BCC, и при выполнении условия она будет бесконечно прыгать сама на себя.
Итак, ты узнал про команды сравнения и чтения флагов для составления условий в своих кодах. Для флага C обязательна предварительная команды сравнения, потому что команды загрузки на него не влияют, а других способов влияния ты пока не знаешь.
Команды увеличения и уменьшения на 01
Первые 2 команды - INC (увеличить байт в адресе на 01) и DEC (уменьшить байт в адресе на 01). Команды не умеют работать напрямую с A, только с адресами. Результат этих команд повлияет на флаги N и Z как обычно.
Execute 8300
LDX #$01
LDY #$07
LDA #$00
STA $0137
Подготовка кода. В итоге N-, Z+.
INC $0137
0137 = 01. N-, Z-.
DEC $0137
0137 = 00. N-, Z+
DEC $0136,X
0137 = FF. N+, Z-. После этих команд A остается без изменений
Теперь команды, работающие напрямую с X и Y. Результат отобразится в этих регистрах.
DEX
INY
Уменьшаем X на 01 и увеличиваем Y на 01.
LDA #$77
STA $0137,Y
DEY
INX
CPX #$05
BNE $8316
RTS
Код, который будет записывать 77по различным адресам. Это пример того, как X может работать в качестве счетчика. Сначала мы грузим 77в A, и пишем его в 013F, поскольку Y = 08. Далее мы уменьшаем Y на 01, и увеличиваем X на 01. Если X еще ≠05, мы прыгаем на команду записи A в адрес, который уже изменился благодаря DEY. В итоге у нас будут использованы 5 различных адресов пока X увеличивается от 00 до 04, потому что при 05 код завершится. В данном примере BNE можно заменить на BCC. Сам прыжок можно было делать на 8314, а не на 8316, но A на протяжении этого отрезка кода останется без изменений, поэтому нет смысла повторно загружать его перед STA.
Арифметические команды
Первые 2 команды - сложение и вычитание. ADC - прибавить к A некий байт, SBC - вычесть из A некий байт. Результат повлияет на N и Z как обычно. У обеих команд есть свои особенности с флагом C, будем подробно разбирать.
Execute 8400
CLC
SEC
Предварительно разберем 2 команды, которые вручную меняют состояние C. CLC = C-, SEC = C+.
LDX #$00
LDY #$00
Подготовка кода.
CLC
LDA #$01
ADC #$02
Очищаем C, делаем сложение 01 + 02 = 03, результат отобразится в A.
SEC
ADC $8450,X
Активируем C, делаем сложение 03 + 23 = 27, что вроде как неправильно, ведь должно быть 26. Дело в том, что ADC проверяет на C, и если C+, команда прибавляет лишние 01, в итоге 03 + 23 + 01 = 27. Также C-, дальше объясню почему.
INX
ADC $8450,X
Увеличили X на 01. 27 + E2 = 109, отобразится как 09. Результат перевалил за FF, следовательно C+. В предыдущем примере мы не привысили FF, поэтому там был C-.
SBC #$03
C+. 09 - 03 = 06. Команда SBC по взаимодействию с C зеракльна ADC. При C+ она сделала обычное вычитание. Результат не перевалил за 00, следовательно C+.
CLC
SBC $8458
C-. 06 - 25 - 01 = E0. Результат перевалил за 00, C-.
INX
INY
Подготовка кода.
LDA #$44
CLC
ADC $8450,X
CLC может быть прописана до или после LDA, это не важно, потому что LDA не влияет на C, важно чтобы перед ADC. Вообще, CLC можно ставить где угодно до ADC, если ты убедился что ничто другое не повлияет на C после CLC. Результат = 20, C+.
LDA #$44
SBC $8458,Y
Результат также = 20, C+. Обе команды взаимозаменяемые, ты в принципе можешь использовать любую из них для одинаковых целей, как тебе удобней.
Вторые 2 команды - умножение и деление. ASL - умножить байт на 2, LSR - разделить байт на 2. Результат повлияет на N и Z как обычно. Также команды влияют на C, каждая по-своему.
LDA #$21
ASL
C+. Результат = 21 * 2 = 42. Мы работаем с A, поэтому в нем отображается результат. N-, Z-. C-, потому что результат не перевалил за FF.
ASL
42 * 2 = 84. N+, Z-, C-.
ASL
STA $012C
84 * 2 = 108 = 08. N-, Z-. C+, потому что результат перевалил за FF. Пишем A в 012C.
LSR $012C x 5
1. 08 / 2 = 04. N-, Z-. C-, потому что мы делим четное число. Сейчас мы работаем с адресом, а не с регистром, поэтому A без изменений.
2. 04 / 2 = 02. N-, Z,. C-.
3. 02 / 2 = 01. N-, Z,. C-.
4. 01 / 2 = 00. N-, Z+. При делении нечетного байта разультат всегда округляется в меньшую сторону. И раз это нечетный байт, то C+.
5. 00 / 2 = 00. N-, Z+, C-.
Эти особенности команд с флагом C сделаны для расширения возможностей вычисления, однако новичку они скорее будут мешать на начальном этапе. Я сам не могу вспомнить чтобы где-то их использовал. Главное запомнить, что для привычного сложения нужен предварительный C-, а для вычитания C+.
Команды со стеком, прыжки и прочие команды
Наконец-то разберемся что такое стек. Это адреса 0100-01FF, которые используется для хранения байтов и для их извлечения из стека обратно, по принципу последним зашел - первым вышел. Содержимое стека можно посмотреть в дебаггере.
Адрес указывает на адрес, в который будет помещен следующий байт для хранения, после чего адрес уменьшится, а при извлечении байта адрес увеличится. Этот адрес можно менять вручную при помощи команды TXS (которую мы изучать не будем). Со стеком нужно работать очень аккуратно, чтобы не испортить оригинальное течение кода игры, хотя здесь нет особых сложностей. Не используй стек в качестве свободных адресов, если ты не уверен что эти адреса не будут использоваться игрой в будущем.
Также стек применяется для хранения адресов прыжков с возвратом. Но сначала разберем хранение байтов.
Execute 8400
LDA #$24
LDX #$85
LDY #$11
Подготовка кода.
PHA
Помещаем A в стек. Байт 24 отобразится в стеке в дебаггере. В A байт без изменений.
TXA
PHA
TXA - предварительно копируем байт из X в A, потому что в стек нельзя напрямую помещать X и Y. Теперь в обоих регистрах одинаковый байт. При копировании байта между регистрами обновляются N и Z. Теперь помещаем A в стек. В дебаггере отображено сначала 85, затем 24, потому что 85 мы засунули последним, и сейчас он первый в списке на извлечение.
TYA
PHA
Аналогично сохраняем в стеке Y через A.
LDA #$01
LDX #$02
LDY #$03
Обновим байты в регистрах для демонстрации.
PLA
TAY
PLA
TAX
PLA
Сначала вытаскиваем из стека байт 11 и перемещаем его в Y. Затем вытаскиваем 85 и перемещаем в X. И последним вытаскиваем 24, который раньше был в A. В итоге мы сохранили по очереди байты из 3х регистров в стеке, и вытащили их из него в обратном порядке. Байты в регистрах поменялись на те, которые были извлечены из стека. Если вытащить больше/меньше байтов в конце своего кода, игра может в последствии зависнуть, поэтому тебе нужно убедиться что ты в стеке ничего не забыл, а также что ты не стащил из него ничего лишнего.
PHP
PLP
PHP - отдельная команда для регистра статуса процессора. Как ты помнишь, байт в этом регистре разбивается на биты и каждый бит отвечает за свой флаг, но байт остается байтом. PHP сохраняет этот байт в стеке, а PLP извлекает его оттуда. Изредка могут быть такие ситуации, когда тебе нужно полностью сохранить состояние флагов, для этого и нужны эти 2 команды. Кстати, стек не запоминает откуда был байт, который в нем хранится, поэтому в теории можно например поместить любой байт при помощи PHA, а вытащить его уже PLP, и флаги станут соответственными.
JSR $8530
JSR - прыжок с сохранением адреса прыжка, или прыжок с возвратом. 2 байта после команды меняются местами и получается адрес прыжка. При выполнении команды тебя перекинет на адрес 8530, а в стеке появятся 2 байта - 1A и 85. Дело в том, что JSR прописана по адресу 8518. Старший байт 85 записывается в стек первым, а к младшему 18 прибавляется 02 и он записывается последним.
STA $0127
RTS
В данный момент ты находишься в подпрограмме благодаря JSR, то есть JSR создает подпрограмму (это просто для технической инфы). RTS - возврат из этой подпрограммы. Команда считывает 2 последних байта из стека и составляет из них адрес 85 + (1A + 01) = 851B. Таким образом, находясь в подпрограмме, по байтам из стека ты можешь вычислить откуда был прыжок. Но для этого есть еще один способ. Найди в дебаггере кнопку Step Out. При нажатии на нее тебя вернет к месту после JSR, а конкретнее по адресу из последних двух байтов стека. Если чуть более подробно, то при нажатии этой кнопки код будет выполняться до того момента, пока не дойдет до команды RTS, и выполнит эту команду (байты в стеке к этому времени уже могут отличаться от тех, которые ты видишь в стеке до нажатия кнопки).
JSR $8535
Еще один прыжок, но давай не будем прыгать, а разберем еще одну кнопку - Step Over. Эта кнопка перепрыгивает команды JSR, но не просто перепрыгивает, а выполняет весь код из подпрограммы и возвращает тебя на следующую команду после JSR. Обе кнопки не всегда работают как надо, но это не баг, не буду в это углубляться.
JMP $853A
Это обычный прыжок, но без возврата, то есть в стеке не появится новых байтов, хотя команды RTS работают как надо, поэтому RTS не стоит ставить где попало.
STY $0129
JMP ($0127)
Этот прыжок (6C) отличается от предыдущего (4C). После команды прописаны 27 01. Меняем байты местами и получаем 0127. 0127 = 24, 0128 = 85. Меняем байты местами, получаем 8524 - это адрес прыжка.
NOP x 5
NOP - отсутствие команды. При чтении этой команды эмулятор ничего не делает. Он просто шагнет на эту команду, посмотрит на нее, и пойдет дальше. Команда может быть полезна в основном для затирания кода. Допустим, ты написал много кода, и понял что что-то в нем лишнее. Ты можешь переписать свой код так, чтобы исключить из него этот лишний кусок, что займет у тебя некоторое время, а можешь просто на месте лишнего кода прописать много этих самых NOP. В общем, делай так, как тебе удобнее. Твое решение может зависеть от размера лишнего кода, от времени, которое тебе потребуется на перезапись, от того, что возможно ты потом захочешь вернуть все как было изначально, а также от других факторов. Ах да, еще классическое применение NOP - начальный читерский ромхакинг, затирание всяких DEC, чтобы жизни не отнимались. Кстати, не всегда можно просто затереть эту команду, нужно смотреть на то, какой код идет дальше, иногда лучше DEC заменить на LDA #$байт.
Ну и команда UNDEFINED. Есть несколько байтов, которые дебаггер отобразит вот так, это значит что команда не определена, то есть такой команды не существует. При написании кода убедись, что твой код не шагает по таким вот UNDEFINED, потому что результат может быть непредсказуемым. BOOM!!! Если в дебаггере под бряками поставить галочку Break on Bad Opcodes, то дебаггер будет вызываться при шаге кода по таким неопознанным командам. Это может быть если ты неправильно указал координаты для прыжков и команд сравнения, или если ты использовал например JMP, а код завершаешь JSR, и все покатилось к чертям. В общем, отлично подходит для поиска багов, рекомендую постоянно включать эту галочку.
Учебник по ромхакингу NES
Автор учебника BZK
Автор учебника BZK