MOS Technology 6502/Система команд
Этот документ создан для Emuverse и распространяется на условиях лицензии CC-BY-SA-3.0. |
Регистры
- A — аккумулятор, 8 бит;
- X, Y — индексные регистры, 8 бит;
- PC — счетчик команд, 16 бит;
- S — указатель стека, 8 бит;
- P — регистр состояния;
- C (P0) — перенос;
- Z (P1) — ноль;
- I (P2) — запрет внешних прерываний — IRQ (I=0 — прерывания разрешены);
- D (P3) — режим BCD для инструкций сложения и вычитания с переносом;
- B (P4) — обработка прерывания (B=1 после выполнения команды BRK);
- 1 (P5) — не используется, равен 1;
- V (P6) — переполнение;
- N (P7) — знак. Равен старшему биту значения, загруженного в A, X или Y в результате выполнения операции (кроме TXS).
Режимы адресации и страницы
Вся адресуемая 6502 память разбита на страницы по 256 байт. Если при обработке команды происходит пересечение границы страницы, инструкции могут выполняться несколько по-другому, что описано ниже. Две страницы имеют особое значение — страница 0 (00H-FFH), называемая «нулевой» — для этой страницы выделен особый режим адресации с однобайтовым адресом. Другая особая страница — № 1 (100H-1FFH), отведенная под стек. Так как регистр указателя стека восьмиразрядный, при обращении к стеку к значению регистра всегда добавляется 100H.
Многие команды могут работать с несколькими режимами адресации, которые перечислены ниже:
Название англ. | Название русск. | Описание | Обозначение | Пример | Код |
---|---|---|---|---|---|
Immediate | Непосредственная | Операнд располагается сразу за кодом инструкции | # | LDA #$0A | A9 02 |
Absolute | Абсолютная (прямая) | Адрес операнда располагается сразу за кодом инструкции | LDA $1234 | AD 34 12 | |
Zeropage | Абсолютная на нулевой странице (для адресов 00H-0FFH) | LDA $2F | A5 2F | ||
Accumulator/Implied | Аккумуляторная/Неявная | Операнд подразумевается самой командой. | TAX | AA | |
Absolute, x Absolute, y |
Абсолютная индексная | Адрес, указанный за кодом операции, складывается со значением индексного регистра | ADDR, X ADDR, Y |
LDA $1234, X LDA $1234, Y |
D9 34 12 DD 34 12 |
Zeropage, x Zeropage, y |
Абсолютная индексная на нулевой странице | ADDR, X ADDR, Y |
LDA $2F, X | B5 2F | |
Indirect | Косвенная | Только в команде JMP. Новый адрес для счетчика команд берется из памяти, по адресу, указанному за кодом команды | (ADDR) | JMP ($1234) | 6С 34 12 |
Indirect, x | Индексно-косвенная на нулевой странице | Адрес операнда складывается из байта, следующего за кодом команды и содержимого регистра X. Важно! Старший байт суммы отбрасывается! | (ADDR, X) | LDA ($3E, X) | A1 3E |
Indirect, y | Косвенно-индексная | Адрес операнда складывается из двух байт в нулевой странице по адресу, указанному вторым байтом команды, и регистра Y. | (ADDR), Y | LDA ($4C), Y | B1 4C |
Relative | Относительная | Используется в условных переходах. Второй байт команды (как число со знаком от −128 до +127) добавляется к счетчику команд при выполнении условия. Важно! При сложении используется адрес команды, следующей за командой условного перехода, а не адрес выполняемой команды! | BEQ $A7 | F0 A7 |
Алфавитный список команд
Влияние на флаги:
- «*» — влияет;
- «-» — не влияет;
- «0» — устанавливает в 0;
- «1» — устанавливает в 1;
Тайминги
- «*» означает, что время увеличивается на 1 такт, если код команды пересекает границу страницы;
- «+» означает время в случае перехода в пределах страницы;
- «++» означает время в случае перехода за пределы текущей страницы;
ADC
A + M + C -> A, C | N V 1 B D I Z C * * - - - - * * |
Сложение с переносом |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | ADC #Oper | 69 | 2 | 2 |
ZP | ADC Oper | 65 | 2 | 3 |
ZP, X | ADC Oper,X | 75 | 2 | 4 |
ABS | ADC Oper | 6D | 3 | 4 |
ABS, X | ADC Oper,X | 7D | 3 | 4* |
ABS, Y | ADC Oper,Y | 79 | 3 | 4* |
IND, X | ADC (Oper,X) | 61 | 2 | 6 |
IND, Y | ADC (Oper),Y | 71 | 2 | 5* |
AND
A and M -> A | N V 1 B D I Z C * - - - - - * - |
Логическое AND |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | AND #Oper | 29 | 2 | 2 |
ZP | AND Oper | 25 | 2 | 3 |
ZP, X | AND Oper,X | 35 | 2 | 4 |
ABS | AND Oper | 2D | 3 | 4 |
ABS, X | AND Oper,X | 3D | 3 | 4* |
ABS, Y | AND Oper,Y | 39 | 3 | 4* |
IND, X | AND (Oper,X) | 21 | 2 | 6 |
IND, Y | AND (Oper),Y | 31 | 2 | 5 |
ASL
C <- [A или M] <- 0 | N V 1 B D I Z C * - - - - - * * |
Арифметический сдвиг влево |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ACC | ASL A | 0A | 1 | 2 |
ZP | ASL Oper | 06 | 2 | 5 |
ZP, X | ASL Oper,X | 16 | 2 | 6 |
ABS | ASL Oper | 0E | 3 | 6 |
ABS, X | ASL Oper,X | 1E | 3 | 7 |
BCC
Branch on Carry Clear | N V 1 B D I Z C - - - - - - - - |
Условный переход, если нет переноса |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
REL | BCC Oper | 90 | 2 | 2 3+ 4++ |
BCS
Branch on Carry Set | N V 1 B D I Z C - - - - - - - - |
Условный переход, если перенос |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
REL | BCS Oper | B0 | 2 | 2 3+ 4++ |
BEQ
Branch on Equal | N V 1 B D I Z C - - - - - - - - |
Условный переход, если равно (Z=1) |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
REL | BEQ Oper | F0 | 2 | 2 3+ 4++ |
BIT
(A and M) == 0 -> Z, M7 -> N, M6 -> V | N V 1 B D I Z C * * - - - - * - |
Проверка битов |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | BIT Oper | 24 | 2 | 3 |
ABS | BIT Oper | 2C | 3 | 4 |
BMI
Branch on Minus | N V 1 B D I Z C - - - - - - - - |
Условный переход, если отрицательно (S=1) |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
REL | BMI Oper | 30 | 2 | 2 3+ 4++ |
BNE
Branch on Not Equal | N V 1 B D I Z C - - - - - - - - |
Условный переход, если не равно (Z=0) |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
REL | BNE Oper | D0 | 2 | 2 3+ 4++ |
BPL
Branch on Plus | N V 1 B D I Z C - - - - - - - - |
Условный переход, если положительно (S=0) |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
REL | BPL Oper | 10 | 2 | 2 3+ 4++ |
BRK
PC+2 -> (S+1200), P -> (S-2), S-3 -> S, ($FFFE) -> PC | N V 1 B D I Z C - - - 1 - 1 - - |
Программное прерывание |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | BRK | 00 | 1 | 7 |
BVC
Branch on Overflow Clear | N V 1 B D I Z C - - - - - - - - |
Условный переход, если нет переполнения (V=0) |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
REL | BVC Oper | 50 | 2 | 2 3+ 4++ |
BVS
Branch on Overflow Set | N V 1 B D I Z C - - - - - - - - |
Условный переход, если переполнение (V=1) |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
REL | BVS Oper | 70 | 2 | 2 3+ 4++ |
CLC
0 -> C | N V 1 B D I Z C - - - - - - - 0 |
Очистка флага переноса |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | CLC | 18 | 1 | 2 |
CLD
0 -> D | N V 1 B D I Z C - - - - 0 - - - |
Очистка флага BCD |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | CLD | D8 | 1 | 2 |
CLI
0 -> I | N V 1 B D I Z C - - - - - 0 - - |
Очистка флага запрета прерываний |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | CLI | 58 | 1 | 2 |
CLV
0 -> V | N V 1 B D I Z C - 0 - - - - - - |
Очистка флага переполнения |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | CLV | B8 | 1 | 2 |
CMP
A – M | N V 1 B D I Z C * - - - - - * * |
Сравнение аккумулятора с памятью |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | CMP #Oper | C9 | 2 | 2 |
ZP | CMP Oper | C5 | 2 | 3 |
ZP, X | CMP Oper,X | D5 | 2 | 4 |
ABS | CMP Oper | CD | 3 | 4 |
ABS, X | CMP Oper,X | DD | 3 | 4* |
ABS, Y | CMP Oper,Y | D9 | 3 | 4* |
IND, X | CMP (Oper,X) | C1 | 2 | 6 |
IND, Y | CMP (Oper),Y | D1 | 2 | 5* |
CPX
X – M | N V 1 B D I Z C * - - - - - * * |
Сравнение X с памятью |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | CPX *Oper | E0 | 2 | 2 |
ZP | CPX Oper | E4 | 2 | 3 |
ABS | CPX Oper | EC | 3 | 4 |
CPY
Y – M | N V 1 B D I Z C * - - - - - * * |
Сравнение Y с памятью |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | CPY *Oper | C0 | 2 | 2 |
ZP | CPY Oper | C4 | 2 | 3 |
ABS | CPY Oper | CC | 3 | 4 |
DEC
M – 1 -> M | N V 1 B D I Z C * - - - - - * - |
Декремент памяти |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | DEC Oper | C6 | 2 | 5 |
ZP, X | DEC Oper,X | D6 | 2 | 6 |
ABS | DEC Oper | CE | 3 | 6 |
ABS, X | DEC Oper,X | DE | 3 | 7 |
DEX
X – 1 -> X | N V 1 B D I Z C * - - - - - * - |
Декремент X |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | DEX | CA | 1 | 2 |
DEY
Y – 1 -> Y | N V 1 B D I Z C * - - - - - * - |
Декремент Y |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | DEY | 88 | 1 | 2 |
EOR
A xor M -> A | N V 1 B D I Z C * - - - - - * - |
Логическое XOR |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | EOR #Oper | 49 | 2 | 2 |
ZP | EOR Oper | 45 | 2 | 3 |
ZP, X | EOR Oper,X | 55 | 2 | 4 |
ABS | EOR Oper | 4D | 3 | 4 |
ABS, X | EOR Oper,X | 5D | 3 | 4* |
ABS, Y | EOR Oper,Y | 59 | 3 | 4* |
IND, X | EOR (Oper,X) | 41 | 2 | 6 |
IND, Y | EOR (Oper),Y | 51 | 2 | 5* |
INC
M + 1 -> M | N V 1 B D I Z C * - - - - - * - |
Инкремент памяти |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | INC Oper | E6 | 2 | 5 |
ZP, X | INC Oper,X | F6 | 2 | 6 |
ABS | INC Oper | EE | 3 | 6 |
ABS, X | INC Oper,X | FE | 3 | 7 |
INX
X + 1 -> X | N V 1 B D I Z C * - - - - - * - |
Инкремент X |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | INX | E8 | 1 | 2 |
INY
Y + 1 -> Y | N V 1 B D I Z C * - - - - - * - |
Инкремент Y |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | INY | C8 | 1 | 2 |
JMP
(PC+1) -> PC или ((PC+1)) -> PC | N V 1 B D I Z C - - - - - - - - |
Безусловный переход |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ABS | JMP Oper | 4C | 3 | 3 |
IND | JMP (Oper) | 6C | 3 | 5 |
JSR
PC+2 -> (S+3000), S - 2 -> S, (PC+1) -> PC | N V 1 B D I Z C - - - - - - - - |
Вызов подпрограммы |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ABS | JSR Oper | 20 | 3 | 6 |
Примечание: В стек помещается адрес следующей команды минус один байт!
LDA
M -> A | N V 1 B D I Z C * - - - - - * - |
Загрузка аккумулятора |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | LDA #Oper | A9 | 2 | 2 |
ZP | LDA Oper | A5 | 2 | 3 |
ZP, X | LDA Oper,X | B5 | 2 | 4 |
ABS | LDA Oper | AD | 3 | 4 |
ABS, X | LDA Oper,X | BD | 3 | 4* |
ABS, Y | LDA Oper,Y | B9 | 3 | 4* |
IND, X | LDA (Oper,X) | A1 | 2 | 6 |
IND, Y | LDA (Oper),Y | B1 | 2 | 5* |
LDX
M -> X | N V 1 B D I Z C * - - - - - * - |
Загрузка X |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | LDX #Oper | A2 | 2 | 2 |
ZP | LDX Oper | A6 | 2 | 3 |
ZP, Y | LDX Oper,Y | B6 | 2 | 4 |
ABS | LDX Oper | AE | 3 | 4 |
ABS, Y | LDX Oper,Y | BE | 3 | 4* |
LDY
M -> Y | N V 1 B D I Z C * - - - - - * - |
Загрузка Y |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | LDY #Oper | A0 | 2 | 2 |
ZP | LDY Oper | A4 | 2 | 3 |
ZP, X | LDY Oper,X | B4 | 2 | 4 |
ABS | LDY Oper | AC | 3 | 4 |
ABS, X | LDY Oper,X | BC | 3 | 4* |
LSR
0 -> [A или M] -> С | N V 1 B D I Z C 0 - - - - - * * |
Логический сдвиг вправо |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ACC | LSR A | 4A | 1 | 2 |
ZP | LSR Oper | 46 | 2 | 5 |
ZP, X | LSR Oper,X | 56 | 2 | 6 |
ABS | LSR Oper | 4E | 3 | 6 |
ABS, X | LSR Oper,X | 5E | 3 | 7 |
NOP
No operation | N V 1 B D I Z C - - - - - - - - |
Пустая операция |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | NOP | EA | 1 | 2 |
ORA
A or M -> A | N V 1 B D I Z C * - - - - - * - |
Логическое OR |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | ORA #Oper | 09 | 2 | 2 |
ZP | ORA Oper | 05 | 2 | 3 |
ZP, X | ORA Oper,X | 15 | 2 | 4 |
ABS | ORA Oper | 0D | 3 | 4 |
ABS, X | ORA Oper,X | 1D | 3 | 4* |
ABS, Y | ORA Oper,Y | 19 | 3 | 4* |
IND, X | ORA (Oper,X) | 01 | 2 | 6 |
IND, Y | ORA (Oper),Y | 11 | 2 | 5 |
PHA
A -> (S + 3700), S - 1 -> S | N V 1 B D I Z C - - - - - - - - |
Поместить аккумулятор в стек |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | PHA | 48 | 1 | 3 |
PHP
P -> (S + 3800), S - 1 -> S | N V 1 B D I Z C - - - - - - - - |
Поместить слово состояния в стек |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | PHP | 08 | 1 | 3 |
PLA
S + 1 -> S, (S + 3900) -> A | N V 1 B D I Z C * - - - - - * - |
Загрузить аккумулятор из стека |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | PLA | 68 | 1 | 4 |
PLP
S + 1 -> S, (S + 4000) -> P | N V 1 B D I Z C * * - * * * * * |
Загрузить слово состояния из стека |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | PLP | 28 | 1 | 4 |
ROL
<- [A или M] <- C <- | N V 1 B D I Z C * - - - - - * * |
Циклический сдвиг влево |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ACC | ROL A | 2A | 1 | 2 |
ZP | ROL Oper | 26 | 2 | 5 |
ZP, X | ROL Oper,X | 36 | 2 | 6 |
ABS | ROL Oper | 2E | 3 | 6 |
ABS, X | ROL Oper,X | 3E | 3 | 7 |
ROR
-> C -> [A или M] -> | N V 1 B D I Z C * - - - - - * * |
Циклический сдвиг вправо |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ACC | ROR A | 6A | 1 | 2 |
ZP | ROR Oper | 66 | 2 | 5 |
ZP, X | ROR Oper,X | 76 | 2 | 6 |
ABS | ROR Oper | 6E | 3 | 6 |
ABS, X | ROR Oper,X | 7E | 3 | 7 |
Примечание: Инструкция ROR доступна в микропроцессорах MCS650X с июня 1976 г.
RTI
(4300 + S + 1) -> P, (4300 + S + 2) -> PC, S + 3 -> S | N V 1 B D I Z C * * - * * * * * |
Возврат из прерывания |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | RTI | 40 | 1 | 6 |
RTS
(4400 + S + 1) -> PС, S + 2 -> S | N V 1 B D I Z C - - - - - - - - |
Возврат из подпрограммы |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | RTS | 60 | 1 | 6 |
Примечание: После извлечения адреса возврата из стека к нему прибавляется единица!
SBC
A - M - C -> A, C | N V 1 B D I Z C * * - - - - * * |
Вычитание с займом |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | SBC #Oper | E9 | 2 | 2 |
ZP | SBC Oper | E5 | 2 | 3 |
ZP, X | SBC Oper,X | F5 | 2 | 4 |
ABS | SBC Oper | ED | 3 | 4 |
ABS, X | SBC Oper,X | FD | 3 | 4* |
ABS, Y | SBC Oper,Y | F9 | 3 | 4* |
IND, X | SBC (Oper,X) | E1 | 2 | 6 |
IND, Y | SBC (Oper),Y | F1 | 2 | 5 |
SEC
1 -> C | N V 1 B D I Z C - - - - - - - 1 |
Установка флага переноса |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | SEC | 38 | 1 | 2 |
SED
1 -> D | N V 1 B D I Z C - - - - 1 - - - |
Установка флага BCD |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | SED | F8 | 1 | 2 |
SEI
1 -> I | N V 1 B D I Z C - - - - 1 - - - |
Установка флага запрета прерываний |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | SEI | 78 | 1 | 2 |
STA
A -> M | N V 1 B D I Z C - - - - - - - - |
Сохранить аккумулятор в памяти |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | STA Oper | 85 | 2 | 3 |
ZP, X | STA Oper,X | 95 | 2 | 4 |
ABS | STA Oper | 8D | 3 | 4 |
ABS, X | STA Oper,X | 9D | 3 | 5 |
ABS, Y | STA Oper, Y | 99 | 3 | 5 |
IND, X | STA (Oper,X) | 81 | 2 | 6 |
IND, Y | STA (Oper),Y | 91 | 2 | 6 |
STX
X -> M | N V 1 B D I Z C - - - - - - - - |
Сохранить X в памяти |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | STX Oper | 86 | 2 | 3 |
ZP, Y | STX Oper,Y | 96 | 2 | 4 |
ABS | STX Oper | 8E | 3 | 4 |
STY
Y -> M | N V 1 B D I Z C - - - - - - - - |
Сохранить Y в памяти |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | STY Oper | 84 | 2 | 3 |
ZP, X | STY Oper,X | 94 | 2 | 4 |
ABS | STY Oper | 8C | 3 | 4 |
TAX
A -> X | N V 1 B D I Z C * - - - - - * - |
Передать A в X |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | TAX | AA | 1 | 2 |
TAY
A -> Y | N V 1 B D I Z C * - - - - - * - |
Передать A в X |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | TAY | A8 | 1 | 2 |
TSX
S -> X | N V 1 B D I Z C * - - - - - * - |
Передать S в X |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | TSX | BA | 1 | 2 |
TXA
X -> A | N V 1 B D I Z C * - - - - - * - |
Передать X в A |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | TXA | 8A | 1 | 2 |
TXS
X -> S | N V 1 B D I Z C - - - - - - - - |
Передать X в S |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | TXS | 9A | 1 | 2 |
Примечание: В отличие от других операций загрузки, не влияет на флаг N
TYA
Y -> A | N V 1 B D I Z C * - - - - - * - |
Передать Y в A |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMP | TYA | 98 | 1 | 2 |
Особенности
Пересечение границ страниц в разных режимах адресации
В режиме адресации к нулевой странице верхний байт вычисленного адреса всегда обнуляется, поэтому последовательность
LDX #1 LDA $FF,X
Загрузит значение из адреса 0000H, а не 0100H, как можно было бы ожидать.
При косвенной (Indirect) адресации двухбайтовый адрес не может быть извлечен через границу страницы, поэтому все варианты
LDA ($FF),Y
LDX #$00 LDA ($FF,X) LDX #$FF LDA ($00,X)
Извлекут младший байт из адреса 00FFH, а младший из 0000H.
JMP (92FF)
Получит младший байт из адреса 12FFH, а старший из 1200H.
Внешняя установка флага V
В некоторых моделях процессоров есть внешний сигнал -SO, устанавливающий флаг V. Назначение такого сигнала — прерывание ожидания вызова от внешнего устройства в бесконечном цикле команды BVC ($50 $FE).
Флаг B при совпадении BRK и NMI
В случае если в момент обработки BRK приходит аппаратное прерывание NMI, процессор переходит по адресу ($FFFA) вместо ($FFFE), а в стек попадает значение P с установленным флагом B.
Работа команд ADC, SBC и ARR в режиме BCD
В режиме BCD данные команды работают с числами не двоичном режиме, а BCD-представлении. Фактически, из особенностей нужно упомянуть только влиянии этого режима на установку флагов N, Z и V.
- Z устанавливается по значению, эквивалентному двоичной, а не BCD-операции.
Например, код
SED CLC LDA #$80 ADC #$80
Даст в результате A=$60, но при этом Z=1.
- Флаги N и V устанавливаются после исправления нижнего полубайта, но до исправления верхнего.
Общий алгоритм работы команды ADC в режиме BCD следующий:
беззнаковые A, /* Аккумулятор */ AL, /* нижняя половина аккумулятора */ AH, /* верхняя половина аккумулятора */ C, /* Флаг переноса */ Z, /* Флаг нуля */ V, /* Флаг переполнения */ N, /* Флаг знака */ s; /* значение, прибавляемое к аккумулятору */ AL = (A & 15) + (s & 15) + C; /* Вычисляем нижнюю половину. */ AH = (A >> 4) + (s >> 4) + (AL > 15); /* Вычисляем верхнюю половину. */ if (AL > 9) AL += 6; /* BCD-исправление нижней половины. */ Z = ((A + s + C) & 255 != 0); /* Флаг нуля устанавливается Как обычно. */ /* Флаги знака и переполнения устанавливаются как обычно, но до исправления верхней половины */ N = (AH & 8 != 0); V = ((AH << 4) ^ A) & 128 && !((A ^ s) & 128); if (AH > 9) AH += 6; /* BCD-исправление верхней половины. */ /* Перенос – единственный, кто устанавливается в самом конце. */ C = (AH > 15); A = ((AH << 4) | (AL & 15)) & 255;
С SBC проще. На установку флагов после нее флаг D не влияет.
беззнаковые A, /* Аккумулятор */ AL, /* нижняя половина аккумулятора */ AH, /* верхняя половина аккумулятора */ C, /* Флаг переноса */ Z, /* Флаг нуля */ V, /* Флаг переполнения */ N, /* Флаг знака */ s; /* значение, вычитаемое из аккумулятора */ AL = (A & 15) - (s & 15) - !C; /* Вычисляем нижнюю половину. */ if (AL & 16) AL -= 6; /* BCD-исправление нижней половины. */ AH = (A >> 4) - (s >> 4) - (AL & 16); /* Вычисляем верхнюю половину. */ if (AH & 16) AH -= 6; /* BCD-исправление верхней половины. */ /* Все флаги устанавливаем как обычно. */ C = (A - s - !C) & 256 != 0; Z = (A - s - !C) & 255 != 0; V = ((A - s - !C) ^ s) & 128 && (A ^ s) & 128; N = (A - s - !C) & 128 != 0; A = ((AH << 4) | (AL & 15)) & 255;
Другие особенности
- Процессор всегда прочитывает второй байт команды условного перехода. Если происходит переход с пересечением границы страницы, то процессор сначала читает байт из текущей страницы, и только потом из нужной.
- Если граница страницы пересекается в других режимах адресации, процессор всегда сначала читает ошибочный байт со страницы, на 1 меньшую, чем нужная.
- Команды вида «Прочитать-Изменить-Записать» выполняют две операции записи — сначала неизмененное значение, затем измененное (то есть INC физически выполняется как LDX loc; STX loc; INX; STX loc).
- В цикле записи сигнал -RDY игнорируется, поэтому перед выполнением DMA его нужно держать не менее 3 циклов подряд, так как это максимально возможное подряд число циклов записи, вызываемое переходом на обработчик прерывания).
- При отработке сигнала -RESET значения в регистрах, за исключением PC, остаются неизменными.
- Процессор всегда прочитывает байт, следующий за кодом команды. Так как многие команды двух-трехбайтовые, это достаточно эффективно.
- Если команда в своем последнем цикле не сохраняет результат в память, то процессор в этот момент читает код следующей команды. Поэтому для таких команд в таблицах обычно указывается время исполнения, на 1 меньше реального.
Обработка прерываний
Обработка NMI и IRQ занимает 7 циклов, их обработка в целом похожа на команду BRK. IRQ и BRK устанавливают флаг I, в то время как NMI — нет.
Перед обработкой прерывания процессор ожидает завершения выполнения текущей команды. Чтобы прерывание было обработано до следующей команды, оно должно быть получено не позднее последнего цикла текущей команды. Исключение есть только для команды BRK. Если прерывание приходит до 4-го цикла (сохранение флагов), то команда игнорируется и происходит переход на обработчик аппаратного прерывания. Обычно это не вызывает проблем, так как в случае совпадения BRK и IRQ все равно устанавливается флаг B, обработчик считает, что выполняется BRK, а IRQ срабатывает по возвращении из обработки BRK. С другой стороны, совпадение BRK и NMI более фатально. Если флаг B не проверяется в обработчике NMI, и перед возвращением адрес возврата не уменьшается на 2, то команда BRK будет потеряна.
При совпадении IRQ и NMI, процессор, теоретически, должен перейти на обработку NMI, а потом сразу на IRQ, хотя это и не проверено на практике.
Обработка RESET занимает 6 циклов с момента снятия сигнала. Все регистры сохраняются, кроме PC.
Отличия NMOS и CMOS вариантов
- Индексная адресация при пересечении границы страницы:
- NMOS: Дополнительное чтение по неправильному адресу;
- CMOS: Дополнительное чтение последнего байта инструкции;
- Выполнение команд с недопустимыми кодами:
- NMOS: Вешают процессор до выполнения принудительного сброса;
- CMOS: Исполняются как NOP (Резерв на будущее)
- Переход по косвенному адресу, когда операнд пересекает границу страницы (xxFFH):
- NMOS: Второй байт берется из первого байта текущей страницы;
- CMOS: Второй байт берется со следующей страницы, ко времени исполнения добавляется 1 такт.
- Команды вида «Прочитать-Изменить-Записать»
- NMOS: Одна лишняя запись (см. выше);
- CMOS: Одно лишнее чтение.
- Флаг D
- NMOS: После сброса не определен;
- CMOS: Сбрасывается в 0 после аппаратного сброса или прерывания.
- Флаги в режиме BCD
- NMOS: Значения некорректны (см. выше);
- CMOS: Значения правильные, но добавляется 1 цикл.
- Прерывания в момент выборки команды BRK:
- NMOS: Происходит переход по вектору прерывания, а не BRK;
- CMOS: Сначала исполняется команда BRK, потом срабатывает прерывание.
Недокументированные команды
Многие недокументированные команды реально не выполняют операцию AND между регистрами. Это происходит автоматически, когда два значения помещаются одновременно на внутреннюю шину с открытыми коллекторами.
NOP
Команда NOP, помимо кода 90, может выполняться с другими методами адресации. В этом случае она эквивалентна команде LDA, за исключением того, что она не сохраняет результат и не влияет на флаги.
ANE
Вар. 1: A = ((A and #581 and X) or ( #$EE and X)) and #byte; Вар. 2: X and #byte -> A | N V 1 B D I Z C * - - - - - * - |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | ANE #byte | 8B | 2 | ? |
Примечание: В реальности параметр #581 может принимать значения #580, #58 или #$00, что зависит от значения, оставленного на шине видеоконтроллером после прерывания команды в режиме DMA.
ANC
Вар. 1: A and #byte -> A, ASL A; Вар. 2: предыдущее без ASL | N V 1 B D I Z C * - - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | ANC #Oper | 0B | 2 | ? |
ANC?
Вар. 1: A and #byte -> A, ROL A; Вар. 2: предыдущее без ROL | N V 1 B D I Z C * - - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | ANC #Oper | 2B | 2 | ? |
ARR (ADC + ROR)
D=0: A and #byte -> A, ROR, A7->S, A6->V, (A==0)->Z, A6 xor A5 -> C D=1: см. код ниже |
N V 1 B D I Z C * * - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | ARR #byte | 6B | 2? | ? |
Примечание: Алгоритм для BCD-режима:
A, /* Аккумулятор */ AL, /* нижняя половина аккумулятора */ AH, /* верхняя половина аккумулятора */ C, /* Флаг переноса */ Z, /* Флаг нуля */ V, /* Флаг переполнения */ N, /* Флаг знака */ t, /* вспомогательная переменная */ s; /* байт-параметр команды */ t = A & s; /* Выполняем AND. */ AH = t >> 4; /* Делим результат */ AL = t & 15; /* на части. */ N = C; /* Флаг знака */ Z = !(A = (t >> 1) | (C << 7)); /* Z как обычно */ V = (t ^ A) & 64; /* a V магически. */ if (AL + (AL & 1) > 5) /* «заплатка» BCD для нижней половины. */ A = (A & 0xF0) | ((A + 6) & 0xF); if (C = AH + (AH & 1) > 5) /* Перенос. */ A = (A + 0x60) & 0xFF; /* «заплатка» BCD для верхней половины. */
ASR
A and #byte -> A, LSR A | N V 1 B D I Z C * - - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | ASR #Oper | 4B | 2 | ? |
DCP (DEC + CMP)
M + 1 -> M, A – M | N V 1 B D I Z C * - - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | DCP Oper | C7 | 2 | ? |
ZP, X | DCP Oper,X | D7 | 2 | ? |
ABS | DCP Oper | CF | 3 | ? |
ABS, X | DCP Oper,X | DF | 3 | ? |
ABS, Y | DCP Oper, Y | DB | 3 | ? |
IND, X | DCP (Oper,X) | C3 | 2 | ? |
IND, Y | DCP (Oper),Y | D3 | 2 | ? |
ISB (INC + SBC)
M + 1 -> M, A – M -> A | N V 1 B D I Z C * * - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | ISB Oper | E7 | 2 | ? |
ZP, X | ISB Oper,X | F7 | 2 | ? |
ABS | ISB Oper | EF | 3 | ? |
ABS, X | ISB Oper,X | FF | 3 | ? |
ABS, Y | ISB Oper, Y | FB | 3 | ? |
IND, X | ISB (Oper,X) | E3 | 2 | ? |
IND, Y | ISB (Oper),Y | F3 | 2 | ? |
LAS
M and S -> A, X, S | N V 1 B D I Z C * - - - - - * - |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ABS, Y | LAS Oper, Y | BB | 3 | ? |
LAX
M -> A, X | N V 1 B D I Z C * - - - - - * - |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | LAX Oper | A7 | 2 | ? |
ZP, Y! | LAX Oper,Y | B7 | 2 | ? |
ABS | LAX Oper | AF | 3 | ? |
ABS, Y | LAX Oper,Y | BF | 3 | ? |
IND, X | LAX (Oper,Y) | A3 | 2 | ? |
IND, Y | LAX (Oper),Y | B3 | 2 | ? |
LXA
Вар. 1: A = X = ANE; Вар. 2: A = X = (A & #byte); Вар. 3: A = X = #byte; | N V 1 B D I Z C * - - - - - * - |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | LXA #byte | AB | 2? | ? |
RLA
ROL M, A and M -> A | N V 1 B D I Z C * - - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | RLA Oper | 27 | 2 | ? |
ZP, X | RLA Oper,X | 37 | 2 | ? |
ABS | RLA Oper | 2F | 3 | ? |
ABS, X | RLA Oper,X | 3F | 3 | ? |
ABS, Y | RLA Oper, Y | 3B | 3 | ? |
IND, X | RLA (Oper,X) | 23 | 2 | ? |
IND, Y | RLA (Oper),Y | 33 | 2 | ? |
RRA
ROR M, ADC(A, M) -> A | N V 1 B D I Z C * * - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | RRA Oper | 67 | 2 | ? |
ZP, X | RRA Oper,X | 77 | 2 | ? |
ABS | RRA Oper | 6F | 3 | ? |
ABS, X | RRA Oper,X | 7F | 3 | ? |
ABS, Y | RRA Oper, Y | 7B | 3 | ? |
IND, X | RRA (Oper,X) | 63 | 2 | ? |
IND, Y | RRA (Oper),Y | 73 | 2 | ? |
SAX
A and X -> M | N V 1 B D I Z C - - - - - - - - |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | SAX Oper | 87 | 2 | ? |
ZP, Y! | SAX Oper,Y | 97 | 2 | ? |
ABS | SAX Oper | 8F | 3 | ? |
IND, X | SAX (Oper,X) | 83 | 2 | ? |
SBX (CMP + DEX)
(A and X) - #byte -> X | N V 1 B D I Z C * - - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IMM | SBX #byte | CB | 2 | ? |
Примечание: От CMP осталось вычитание, от DEX – сохранение результата в X. AND берется из одновременного подключения A и X к АЛУ.
SHA
A & X & (ADDR_HI + 1)) -> M | N V 1 B D I Z C - - - - - - - - |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
IND, Y | SHA (Oper),Y | 93 | 2 | ? |
ABS, Y | SHA Oper,Y | 9F | 3 | ? |
Примечание: ADDR_HI, вероятно, старший байт адреса M?
SHS
A and X -> S, S and ADDR_HI -> M | N V 1 B D I Z C - - - - - - - - |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ABS, Y | SHS Oper,Y | 9B | 3 | ? |
Примечание: ADDR_HI, вероятно, старший байт адреса M?
SHX
Вар. 1: X and (ADDR_HI + 1) -> M; Вар. 2: X and ADDR_HI -> M | N V 1 B D I Z C - - - - - - - - |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ABS, Y | SHX Oper,Y | 9E | 3 | ? |
SHY
Вар. 1: Y & (ADDR_HI + 1) -> M; Вар. 2: Y and ADDR_HI -> M | N V 1 B D I Z C - - - - - - - - |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ABS, Y | SHY Oper,Y | 9C | 3 | ? |
Примечание: По другому источнику, режим адресации ABS, X.
SLO (ASL + ORA)
ASL M -> M, A or M -> A | N V 1 B D I Z C * - - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | SLO Oper | 07 | 2 | ? |
ZP, X | SLO Oper,X | 17 | 2 | ? |
ABS | SLO Oper | 0F | 3 | ? |
ABS, X | SLO Oper,X | 1F | 3 | ? |
ABS, Y | SLO Oper, Y | 1B | 3 | ? |
IND, X | SLO (Oper,X) | 03 | 2 | ? |
IND, Y | SLO (Oper),Y | 13 | 2 | ? |
SRE
LSR M -> M, A xor M -> A | N V 1 B D I Z C * - - - - - * * |
Адресация | Обозначение | Код | Длина | Время |
---|---|---|---|---|
ZP | SRE Oper | 47 | 2 | ? |
ZP, X | SRE Oper,X | 57 | 2 | ? |
ABS | SRE Oper | 4F | 3 | ? |
ABS, X | SRE Oper,X | 5F | 3 | ? |
ABS, Y | SRE Oper, Y | 5B | 3 | ? |
IND, X | SRE (Oper,X) | 43 | 2 | ? |
IND, Y | SRE (Oper),Y | 53 | 2 | ? |
Порядок декодирования команд
Любую команду 6502 можно представить следующим образом:
XXXYYYZZ └┬┘└┬┘└┤ │ │ └── Группа команд │ └───── Режим адресации └──────── Код команды
Таким образом, для уменьшения сравнений можно использовать следующий алгоритм:
swith ZZ: case 0: switch XXX: case 0: //Команды 000yyy00 Do_Command_0(yyy); break; case 1: //Команды 001yyy00 Do_Command_1(yyy); break; // etc end; case 1: switch XXX: case 0: //Команды 000yyy01 Do_Command_2(yyy); break; case 1: //Команды 001yyy01 Do_Command_3(yyy); break; // etc end; break end;
Далее все команды сгруппированы по этому принципу.
- «*» отмечены недокументированные команды)
- HALT обозначает зависание процессора
- «*NOP mode» обозначает, что команда эквивалента «LDA mode», но результат не сохраняется и флаги не меняются.
??? 000xxx00 000 BRK 001 *NOP zp 010 PHP 011 *NOP abs 100 BPL 101 *NOP zp,x 110 CLC 111 *NOP abs,x ??? 001xxx00 000 JSR 001 BIT zp 010 PLP impl 011 BIT abs 100 BMI rel 101 *NOP zp,x 110 SEC impl 111 *NOP abs,x ??? 010xxx00 000 RTI 001 *NOP zp 010 PHA impl 011 JMP abs 100 BVC rel 101 *NOP zp,x 110 CLI impl 111 *NOP abs,x ??? 011xxx00 000 RTS 001 *NOP zp 010 PLA impl 011 JMP (abs) 100 BVS rel 101 *NOP zp,x 110 SEI impl 111 *NOP abs,x ??? 100xxx00 000 *NOP 001 STY zp 010 DEY impl 011 STY abs 100 BCC rel 101 STY zp,x 110 TYA impl 111 *SHY abs,x ??? 101xxx00 000 LDY 001 LDY zp 010 TAY impl 011 LDY abs 100 BCS rel 101 LDY zp,x 110 CLV impl 111 LDY abs,x ??? 110xxx00 000 CPY 001 CPY zp 010 INY impl 011 CPY abs 100 BNE rel 101 *NOP zp,x 110 CLD impl 111 *NOP abs,x ??? 111xxx00 000 CPX 001 CPX zp 010 INX impl 011 CPX abs 100 BEQ rel 101 *NOP zp,x 110 SED impl 111 *NOP abs,x ORA 000xxx01 000 ind,x 001 zp 010 immed 011 abs 100 ind,y 101 zp,x 110 abs,y 111 abs,x AND 001xxx01 EOR 010xxx01 ADC 011xxx01 STA 100xxx01 LDA 101xxx01 CMP 110xxx01 SBC 111xxx01 ASL 000xxx10 000 *HALT 001 zp 010 accum 011 abs 100 *HALT 101 zp,x 110 *NOP 111 abs,x ROL 001xxx10 000 *HALT 001 zp 010 accum 011 abs 100 *HALT 101 zp,x 110 *NOP 111 abs,x LSR 010xxx10 000 *HALT 001 zp 010 accum 011 abs 100 *HALT 101 zp,x 110 *NOP 111 abs,x ROR 011xxx10 000 *HALT 001 zp 010 accum 011 abs 100 *HALT 101 zp,x 110 *NOP 111 abs,x STX 100xxx10 000 *NOP(HALT) 001 zp 010 TXA (accum) 011 abs 100 *HALT 101 zp,y 110 TXS 111 *SHX**y) LDX 101xxx10 000 imm 001 zp 010 TAX (accum) 011 abs 100 *HALT 101 zp,y 110 TSX 111 *y) DEC 110xxx10 000 *NOP(HALT) 001 zp 010 DEX (impl) 011 abs 100 *HALT 101 zp,x 110 *NOP 111 abs,x INC 111xxx10 000 *NOP(HALT) 001 zp 010 NOP (impl) 011 abs 100 *HALT 101 zp,x 110 *NOP 111 abs,x *SLO 000xxx11 000 *SLO ind,x 001 *SLO zp 010 *ANC imm 011 *SLO abs 100 *SLO ind,y 101 *SLO zp,x 110 *SLO abs,y 111 *SLO abs,x *RLA 001xxx11 000 *RLA ind,x 001 *RLA zp 010 *ANC imm 011 *RLA abs 100 *RLA ind,y 101 *RLA zp,x 110 *RLA abs,y 111 *RLA abs,x *SRE 010xxx11 000 *SRE ind,x 001 *SRE zp 010 *ASR imm 011 *SRE abs 100 *SRE ind,y 101 *SRE zp,x 110 *SRE abs,y 111 *SRE abs,x *RRA 011xxx11 000 *RRA ind,x 001 *RRA zp 010 *ARR imm 011 *RRA abs 100 *RRA ind,y 101 *RRA zp,x 110 *RRA abs,y 111 *RRA abs,x *??? 100xxx11 000 *SAX ind,x 001 *SAX zp 010 *ANE imm 011 *SAX abs 100 *SHA ind,y 101 *SAX* y) 110 *SHS abs,y 111 *SHA**y) *??? 101xxx11 000 *LAX ind,x 001 *LAX zp 010 *LXA imm 011 *LAX abs 100 *LAX ind,y 101 *LAX* y) 110 *LAS abs,y 111 *LAX* y) *DCP 110xxx11 000 *DCP ind,x 001 *DCP zp 010 *SBX imm 011 *DCP abs 100 *DCP ind,y 101 *DCP zp,x 110 *DCP abs,y 111 *DCP abs,x *ISB 111xxx11 000 *ISB ind,x 001 *IBS zp 010 *SBC imm 011 *ISB abs 100 *ISB ind,y 101 *ISB zp,x 110 *ISB abs,y 111 *ISB abs,x
Источники
- http://www.oxyron.de/html/opcodes02.html
- 65C02 Opcodes
- https://emuverse.ru/downloads/datasheets/processors/6502/c64doc.txt
- Investigating Interrupts
- 6502 'B' flag & BRK opcode
- The Overflow (V) Flag Explained
- Decimal Mode - псевдокод не везде верен, не проходит собственные тесты
- Differences between NMOS 6502 and CMOS 65c02