Содержание
Режим адресации (адресация памяти) - способ обращения процессора к своей памяти.
Любая инструкция процессора состоит как минимум из опкода инструкции. В зависимости от выбранного режима адресации, после опкода может быть дополнительно записан операнд (аргумент) этой инструкции размером 1 или 2 байта. В итоге получается инструкция размером от 1-го до 3-х байтов.
Разные инструкции могут использовать один и тот же режим адресации. У одних инструкций может быть больше выбора режимов адресации, чем у других.
Выбери режим адресации из списка, чтобы посмотреть его описание и примеры использования.
Immediate | Zero Page | Absolute | Indexed | Indirect | Relative | Прочие |
Непосредственная адресация. Используется для работы с константами, то есть с неизменяемыми значениями, записанными в самой программе. Например, можно задать начальное количество жизней и прочитать его одним из регистров.
Операнд инструкции размером 1 байт, в нем указывается константа, с которым будет работать эта инструкция.
Чтобы инструкция
Адресация нулевой страницы. Нулевой страницей являются адреса RAM в диапазоне $0000-$00FF. Старший байт адресов этого диапазона = #$00, поэтому страница называется "нулевая".
8-битная адресация Zero Page служит для экономии ресурсов процессора, поскольку затрачивает меньше тактов на выполнение инструкции по сравнению с режимом адресации Absolute.
По этой причине данные, которые будут использованы кодом игры чаще, чем другие, обычно находятся именно в нулевой странице для снижения нагрузки на процессор при регулярной работе с этими данными. За счет сэкономленных тактов можно успеть выполнить больше кода за кадр.
Операнд инструкции размером 1 байт, которым указывается младший байт адреса. А старший байт адреса всегда будет = #$00.
Чтобы инструкция
Абсолютная адресация. Полноценная 16-битная адресация, позволяет инструкциям работать с любым адресом памяти процессора (NES Memory) в диапазоне $0000-$FFFF.
Операнд инструкции размером 2 байта, ими указывается 16-битный адрес. Из-за особенностей архитектуры процессора, в операнде старший и младший байты адреса
Чтобы инструкция
Поскольку адресация Absolute затрагивает весь возможный диапазон $0000-$FFFF, ей можно указывать и адреса из нулевой страницы. Однако так делать нежелательно, ведь выполнение таких инструкций затрачивает больше тактов, чем с адресацией Zero Page, и сама инструкция по размеру на 1 байт больше, а результат будет точно такой же.
Необходимость прибегнуть к режиму адресации Absolute для указания адресов нулевой страницы есть только в том случае, когда у выбранной инструкции не существует варианта с адресацией Zero Page Indexed, а есть только Absolute Indexed. Например, у инструкции LDA,Y.
Индексная адресация. При вычислении адреса учитывается значение индексного регистра X или Y. К адресу, указанному в операнде инструкции, добавляется текущее значение индексного регистра во время выполнения инструкции. После сложения операнда и индексного регистра получается итоговый адрес, с которым будет работать инструкция.
Инструкция, работающая с индексным регистром, не может использовать этот же регистр с режимом адресации Indexed. То есть не существует инструкций вроде LDX,X или LDY,Y.
Поскольку значение индексного регистра может быть в диапазоне от #$00 до #$FF, при помощи одной-единственной инструкции можно обратиться к целому диапазону размером 256 адресов, изменяя значение индексного регистра перед выполнением этой инструкции.
Этот подход очень часто применяется при создании циклов и подпрограмм. А также адресация Indexed - одна из наиболее важных причин, почему однотипные адреса у различных игровых объектов, например их координаты, очень часто находятся в RAM по соседству. Ведь достаточно загрузить порядковый номер объекта в нужный индексный регистр, и можно работать с адресом именно этого объекта через ту же самую инструкуцию.
Адресация Indexed может быть использована как с режимом адресации Zero Page, так и Absolute. У некоторых инструкций есть ограничение по выбору этих разновидностей адресации Indexed, в основном ограничения по использованию регистра Y.
Также адресация Indexed может использоваться с адресацией Indirect, которая описана отдельно.
Используется вместе с адресацией Zero Page (диапазон $0000-$00FF). Поскольку указывается адрес нулевой страницы, операнд инструкции должен быть размером 1 байт.
Чтобы инструкция
Нельзя выйти за пределы нулевой страницы, используя адресацию Zero Page Indexed. Например, выполняя инструкцию STA $FF,X с текущим значением X = #$01, байт из регистра A будет записан в адрес $0000, а не $0100.
Используется вместе с адресацией Absolute (диапазон $0000-$FFFF). Операнд будет размером 2 байта, старший и младший байты адреса записываются в обратном порядке.
В примере показан цикл, с помощью которого происходит поочередное копирование байтов из адресов $E000-$E005 в адреса $0120-$0125.
Чтобы инструкция
Нельзя выйти за пределы диапазона $0000-$FFFF, используя адресацию Absolute Indexed. Например, выполняя инструкцию LDA $FFFF,Y с текущим значением Y = #$01, байт в регистр A будет загружен из адреса $0000, а не $10000.
У некоторых инструкций при использовании адресации Absolute Indexed будет затрачен +1 дополнительный такт. Это происходит в случае перехода на новую страницу адресов, то есть когда при сложении операнда и значения индексного регистра увеличивается старший байт адреса, указанного в операнде инструкции.
Косвенная (непрямая) адресация. Итоговый адрес вычисляется исходя из байтов, находящихся в двух соседних адресах. В первом адресе находится младший байт итогового адреса, а во втором - старший байт.
Эти 2 соседних адреса могут находиться в любом месте диапазона $0000-$FFFF, но в подавляющем большинстве случаев это будут адреса RAM $0000-$07FF, так как в RAM можно без труда менять байты на нужные, чтобы контролировать косвенный адрес.
Единственная инструкция, использующая чистый режим адресации Indirect -
Операнд инструкции размером 2 байта, ими указывается 16-битный адрес первого соседнего адреса. Старший и младший байты этого адреса записываются в обратном порядке.
Адрес $0120 содержит младший байт итогового адреса, а соседний адрес $0121 - старший байт. Чтобы инструкция
Если подготовить таблицу с младшими и старшими байтами, и записывать их в 2 соседних адреса RAM, выбранных в операнде инструкции Indirect
В процессоре 6502 существует баг, из-за которого нельзя выйти за пределы страницы памяти, если в операнде инструкции указать младший байт адреса #$FF.
Однако эмулятор FCEUX не эмулирует данную особенность, в нем соседним адресом будет считаться адрес $0300.
Косвенно-индексная адресация. В отличие от обычной индексной адресации, итоговый адрес контролируется при помощи регистра Y. Этот режим адресации используется для более гибкого обращения к памяти, чем обычная индексная адресация, а также при работе с таблицами, которые по размеру больше, чем 256 байтов.
Для инструкции, использующей косвенно-индексную адресацию, требуется 2 соседних адреса в нулевой странице. Операнд инструкции размером 1 байт, которым указывается младший байт первого адреса нулевой страницы.
Если в операнде инструкции указать младший байт адреса #$FF, то соседним адресом будет считаться $0000, а не $0100.
Как и в случае с обычной индексной адресацией, по соседним адресам записываются младший и старший байты итогового адреса.
Получив итоговый адрес $F080, можно добавлять к нему значение регистра Y, который нужно подготовить перед выполнением инструкции
Это позволит работать с диапазоном памяти размером 256 адресов. Но в отличие от обычной индексной адресации, ты можешь изменять начальный адрес этого диапазона когда это небходимо.
У некоторых инструкций при использовании адресации Post-Indexed Indirect будет затрачен +1 дополнительный такт. Это происходит в случае перехода на новую страницу адресов, то есть когда к адресу, вычисляемому по младшему и старшему байтам в соседних адресах, прибавляется значения индексного регистра, после чего увеличивается старший байт итогового адреса.
Индексно-косвенная адресация. Встречается в коде довольно редко, так как использование этого режима адресации слишком затратно и неэффективно.
Отличается от косвенно-индексной тем, что здесь используется индексный регистр X. Этот регистр влияет не на итоговый адрес, а на тот адрес, откуда будут считываться младший и старший байты для итогового адреса.
В примере подготавливаются младшие и старшие байты сразу в двух парах соседних адресов нулевой страницы.
По итогу всех этих действий удалось получить лишь 2 адреса - $ABCD и $0525. Слишком дорогое удовольствие с учетом того, что ради этого было выделено целых 4 адреса в нулевой странице. Чтобы повлиять на итоговые адреса, надо изменять байты в соседних адресах нулевой страницы.
Указав в операнде инструкции с индексно-косвенным режимом адресации младший байт адреса #$FF, либо попытавшись увеличить старший байт адреса при сложении значения регистра X, соседние адреса все равно будут находиться в пределах нулевой страницы.
Относительный режим адресации. Используется только в инструкциях условного перехода, которые проверяют состояние флагов и совершают относительный переход при выполнении условия инструкции.
Режим называется "относительный", потому что он не имеет конкретного адреса перехода. В операнде, который размером 1 байт, указывается дистанция того, сколько байтов нужно "перепрыгнуть" относительно адреса нижестоящей инструкции.
В операнде инструкции условного перехода ставится положительный байт #$00-#$7F. Начальным адресом перехода является адрес, в котором находится следующая по списку инструкция. Например, если инструкция
К начальному адресу перехода добавляется операнд инструкции. Если операнд #$01, адрес будет $8105, если #$02, то адрес $8106, и так далее. Если нужно при выполнении условия перейти на инструкцию
Операндом ставится отрицательный байт #$80-#$FF. Если байт #$00 это начальный адрес перехода, то #$FF - смещение адреса перехода на 1 байт назад, #$FE - смещение на 2 байта назад, и так далее.
Очень часто обратный переход используется при создании циклов, чтобы повторно выполнить его тело, пока не будет выполнено условие выхода из цикла.
Если операндом записать байт #$FE, то при выполнении своего условия инструкция перейдет сама на себя, повторно выполнит свое условие и снова перейдет на себя. Это приведет к созданию бесконечного цикла.
Если условие инструкции условного перехода не выполняется, будет затрачено 2 такта. Если же условие выполняется, затрачивается 3 такта.
А если условие выполняется, и при вычислении адреса перехода старший байт этого адреса будет увеличен/уменьшен на #$01 относительно начального адреса, затрачивается 4 такта.
С опытом короткие дистанции можно будет вычислить на глаз, а иногда даже заранее будешь ставить нужный байт, когда уже знаешь какой именно код тебе нужно прописать. Но лучше все же не пытаться вычислять операнды до тех пор, пока код не будет написан полностью. Временно оставляй операнд #$00.
Чтобы правильно подобрать дистанцию условного перехода, нужно в Hex Editor'е изменить байт операнда инструкции на тот, который ты считаешь приблизительно правильным. Затем кликни на Debugger, который обновит адрес перехода с учетом операнда. При необходимости скорректируй байт в ту или иную сторону и повторно сверься с Debugger'ом.
Для большей наглядности создай временный комментарий для адреса, на который нужно перейти. Если операнд записан правильно, этот комментарий должен отобразиться еще и в адресе перехода у инструкции Bxx.
В Hex Editor'е выделяешь байты, которые требуется перепрыгнуть. Возьмем код из первого примера, где в операнде инструкции
Чтобы вычислить операнд для перехода на адрес $8108, нужно начать выделение с байта опкода инструкции, находящейся сразу после
В названии окна будет отображено количество выделенных байтов HEX-числом (#$04), этот байт нужно записать в опкоде
Рекомендуется использовать окно Inline Assembler, в котором можно указать конкретный адрес условного перехода. Операнд будет вычислен автоматически. Этот же способ походит и для указания адреса перехода вперед.
Альтернативно можно придумать свою формулу, например "операнд = #$100 + желаемый адрес перехода - базовый адрес перехода". #$100 + $8105 - $810B = #$FA. С этим поможет калькулятор.
Эти режимы адресации просто для ознакомления. Им не требуется указание операнда, инструкция состоит лишь из опкода. Подробнее про работу этих инструкций прочитаешь в соответствующем разделе.
Инструкции
"Подразумеваемый" (неявный) режим адресации. Инструкция уже содержит информацию о том, с каким регистром нужно работать. Таких инструкций довольно много, к примеру