Статус флаги ассемблера 6502 nes/famicom/dendy
Для более глубокого понимания как происходит ветвление в программах написанных на ассемблере 6502 необходимо углубиться в флаги и понять какие команды влияют на тот или иной флаг. Это поможет избежать множество ошибок связанных с не очевидностью ветвления вашей программы.
Состояние статус флагов это один из шести архитектурных регистров процессора 6502:
Регистр аккумулятора A
Регистры X и Y
Статус регистр (статус флаги)
Указатель стека
Программный счетчик
С регистрами A, X, Y мы уже знакомы, мы их часто используем для операций с данными и записи в различные порты процессоров. Указатель стека — хранит в себе указатель на последнее/первое значение стека. Программный счетчик — всегда указывает на следующую команду которую нужно будет выбрать и выполнить, он 16 битный и после выполнения обновляется указатель на следующую команду. Более подробно рассмотрим в следующих статьях работу с этими регистрами.
Давайте рассмотрим более подробно флаги они в регистре расположены следующим образом NV**DIZC где:
N — Negative — этот флаг будет содержать 7-й бит результата если команда имеет результат
V — Overflow — флаг переполнения устанавливается если при сложение (ADC) или вычитание (SBC) результат знакового числа получился больше/меньше диапазона -127 — +127
D — Decimal — флаг указывающий на работу с десятичными цифрами в денди не используется
I — Interrupt disable — флаг указывающий на то что отключены все прерывания кроме NMI
Z — Zero — флаг указывающий что результат команды равен 0, часто используется в программе и ветвление с помощью BEQ (переход если равно 0) и BNE (переход если не равен 0)
C — Carry — флаг переноса устанавливается если результат больше 255 или меньше 0 с беззнаковыми числами, так же устанавливается если при сравнение CMP результат больше либо равно. Тоже часто используется BCC (если очищен) и BCS (если установлен)
* — не используемые биты
Собственно нас интересуют больше флаги C, Z так как они часто используются при разработке игр на денди, по этому более подробнее поговорим о них, остальные же флаги для сокращения объема статьи, пока рассматривать подробно не будем.
Флаг Z — zerro
Влияют следующие команды на этот флаг: LDA, LDX, LDY, AND, INX, INY, INC, DEX, DEY, DEC, CMP, EOR, ORA и многие другие, важно просто понимание что если результат выполнения 0 то флаг Z установлен к примеру
LDA #$00 ; установлен
LDA #$01 ; не установлен
LDX #$00 ; установлен так же и LDY
DEX ; как только X станет 0 будет установлен, так же с DEC, DEY
AND #%0000 ; если результат 0 то будет установлен, так же EOR, ORA
LDA #$07
CMP #$07 ; если при сравнение с памятью значение равно то флаг будет установлен
Таким образом при установке данного флага будет выполняться переход с помощью BEQ если установлен и BNE если не установлен либо результат не равен 0.
Флаг C — carry
Команды которые влияют на данный флаг:
ADC — если после сложения больше 255
SBC — если меньше 0
CMP — если сравниваемое значение больше либо равно значению в аккумуляторе, альтернативное использование данного флага
ASL, LSR, ROL, ROR — содержит бит который был сдвинут.
На самом деле, перед ADC и SBC, я часто сбрасываю флаг переноса командой CLC для того что бы указатель переноса был 0 в таком случае ADC установит флаг переноса при достижения результат больше 255.
При программирование игры меня больше интересует использование этого флага для условий «больше либо равно» и соответственно «меньше», это такая альтернатива использования данного флага
LDA #$01
CMP #$02 ; флаг C установлен
BCS greatOrEq ; больше либо равно
BCC less ; значение в cmp меньше аккумулятора
В качестве заключения
Когда я начал изучать ассемблер 6502, я сделал большую ошибку не вникнув в работу флагов, по этому было довольно сложно понять почему после AND часто используют BEQ или же BNE переход.
Немного о планах
В ближайшем будущем я планирую написать статью о массивах байтов и как правильно их использовать и для чего надо в zeropage грузить и старший и младший байт указателя. Не так давно я разобрался как сделать коллизии фона, основанных на bitmap с загрузкой для каждого перерисованного экрана своей карты коллизий.