6502

Процессор 6502 был разработан компанией MOS в 197-бородатом году. За основу была положена архитектура процессора Motorolla 6800:

6502_die_shot.jpg 6800.jpg
(видно что в обоих случаях верхнюю часть занимает декодер и рандомная логика, а всю нижнюю часть процессора занимает контекст)

Описание внутренней архитектуры процессора 6502

Процессор делится на 2 части: верхняя и нижняя.

В верхней части находится управляющая часть, которая выдает ряд контрольных линий ("команд") для управления нижней частью.
В нижней части находится контекст процессора: внутренние шины и регистры, с одним исключением - регистр флагов (P) находится в верхней части в "размазанном" виде.

Работа процессора тактируется тактовым импульсом PHI0, при этом используются оба полутакта. Во время первого полутакта (PHI1) процессор находится в режиме "говорю". В это время процессор выдает наружу данные.
Во время второго полутакта (PHI2) процессор находится в режиме "слушаю", во время этого полутакта внешние устройства могут помещать данные на шину данных, чтобы процессор их "обработал".

Регистры

  • PD: текущее значения кода операции для предекодирования
  • IR: регистр инструкций (хранит код текущей операции)
  • X, Y: индексные регистры
  • S: указатель стека
  • AI, BI: входные значения для АЛУ
  • ADD: промежуточный результат операции на АЛУ
  • AC: аккумулятор
  • PCH/PCL: program counter, состоящий из 2-х половинок
  • PCHS/PCLS: вспомогательные регистры program counter (S означает "set" (?))
  • ABH/ABL: регистры для вывода на внешнюю шину адреса
  • DL: data latch, хранит последнее прочитанное значение внешней шины данных
  • DOR: data output register, содержит значение которое будет записано в шину данных
  • P: регистр флагов, на самом деле состоит из множества разбросанных по схеме защелок

Непосредственно программисту доступны следующие регистры: A (аккумулятор), X, Y, S, P, PC.

Внешние шины

Внешних шин всего две: 16-разрядная адресная (ADDR) и 8-разрядная шина данных (DATA). Адресная шина односторонняя - писать в неё может только процессор. Шина данных двунаправленная.

Внутренние шины

  • ADH/ADL: шина адреса
  • SB: special bus, шина для обмена регистрами
  • DB: внутренняя шина данных

Во время второго полутакта (PHI2) все внутренние шины подзаряжаются и имеют значение 0xff. Сделано это по причине того, что "разрядить" транзистор в нужный момент получается быстрее, чем "зарядить" (смена значения 1⇒0 происходит быстрее, чем смена 0⇒1).

Соединения регистров с шинами

6502_context.jpg

Последовательно соединяя шины и регистры процессор выполняет разнообразные инструкции. Многообразие соединений обеспечивает разнообразие команд процессора, а разделение команд на такты позволяет выполнять сложные действия. Дополнительно производится управление АЛУ (сложение, логическое-И и пр.)

Режимы адресации 6502

Адресация - это способ доставить операнд в нужное место памяти (или загрузить его оттуда). Разработчики 6502 были очень щедрыми и добавили в контекст ажно два индексных регистра X и Y.

"Индексный" - это означает что к адресу памяти определенным образом добавляется смещение, чтобы получить новый адрес. Обычно это нужно для доступу к массивам. В этом случае начало массива будет являться фиксированным адресом, а значение в индексном регистре - индексом массива (смещением).

Список режимов адресации :

  • Immediate (непосредственный операнд). В этом случае операнд хранится в самой инструкции (обычно вторым байтом, после кода операции). Пример LDA #$1C : A = 0x1C
  • Absolute (абсолютная адресация). В инструкции указывается полный 16-разрядный адрес, откуда следует получить операнд. Например LDA $1234 : A = [$1234]
  • Zero page absolute (абсолютная адресация на нулевой странице) : Разработчики сделали оптимизированную версию абсолютной адресации, добавив возможность адресоваться только к нулевой странице (страницы 6502 имеют размер 256 байт). Пример LDA $56 : в этом случае процессор автоматом делает старшие 8 разрядов адреса равными 0x00, а младшие 8 разрядов берутся из инструкции. Итоговый адрес получается 0x0056. A = [0x0056]. Сделано это для экономии размера инструкции (экономится 1 байт).
  • Indexed (индексная) : в этом режиме адресации к постоянному значению адреса добавляется смещение из регистра X или Y. Например LDA $1234, X : A = [$1234 + X]
  • Zero page Indexed (индексная адресация на нулевой странице) : аналогично индексной, но использовать можно только регистр X. Пример LDA $33, X : A = [$0033 + X]

Ну а дальше начинается особенная магия:

  • Pre-indexed indirect (косвенная с пре-индексацией) : Значение операнда, который является адресом в нулевой странице складывается со значением регистра X и получается косвенный адрес. Затем по адресу, на который ссылается косвенный адрес, получается значение операнда. Пример LDA ($34, X) : A = [[$0034 + X]]. Важно : при сложении адреса и значения в регистре X происходит "заворачивание" вокруг 256 байт. То есть перенос в старшую половину адреса не происходит. ( 0xFF + 0x02 будет равно 0x0001, а не 0x0101). Косвенная означает "взять адрес по адресу".
  • Post-indexed indirect (косвенная с пост-индексацией) : Отличается от предыдущей тем, что вначале выбирается косвенный адрес из нулевой страницы, а затем к нему добавляется значение индексного регистра Y. Пример LDA ($2A), Y : A = [[$002A] + Y].

Набор инструкций

6502 обладает всеми необходимыми инструкциями, а также включает в себя такие достаточно удобные инструкции как ротация бит (ROL/ROR) и тестирование разряда (BIT). Не все процессоры того времени содержали такие операции.

Поведение инструкций, а также адресные режимы полностью задаются кодом операции, для упрощения декодирования, однако ширина шины (8 разрядов) не позволяет выполнять все инструкции за 1 такт. Также декодер несколько не оптимизирован, поэтому минимальное время выполнения инструкций - 2 такта, при этом первый такт всегда занимает выборка кода операции (1й байт инструкции).

Краткое содержание инструкций :

ИнструкцияДействие
ADC Add Memory to Accumulator with Carry
AND "AND" Memory with Accumulator
ASL Shift Left One Bit (Memory or Accumulator)
BCC Branch on Carry Clear
BCS Branch on Carry Set
BEQ Branch on Result Zero
BIT Test Bits in Memory with Accumulator
BMI Branch on Result Minus
BNE Branch on Result not Zero
BPL Branch on Result Plus
BRK Force Break
BVC Branch on Overflow Clear
BVS Branch on Overflow Set
CLC Clear Carry Flag
CLD Clear Decimal Mode
CLI Clear interrupt Disable Bit
CLV Clear Overflow Flag
CMP Compare Memory and Accumulator
CPX Compare Memory and Index X
CPY Compare Memory and Index Y
DEC Decrement Memory by One
DEX Decrement Index X by One
DEY Decrement Index Y by One
EOR "Exclusive-Or" Memory with Accumulator
INC Increment Memory by One
INX Increment Index X by One
INY Increment Index Y by One
JMP Jump to New Location
JSR Jump to New Location Saving Return Address
LDA Load Accumulator with Memory
LDX Load Index X with Memory
LDY Load Index Y with Memory
LSR Shift Right One Bit (Memory or Accumulator)
NOP No Operation
ORA "OR" Memory with Accumulator
PHA Push Accumulator on Stack
PHP Push Processor Status on Stack
PLA Pull Accumulator from Stack
PLP Pull Processor Status from Stack
ROL Rotate One Bit Left (Memory or Accumulator)
ROR Rotate One Bit Right (Memory or Accumulator)
RTI Return from Interrupt
RTS Return from Subroutine
SBC Subtract Memory from Accumulator with Borrow
SEC Set Carry Flag
SED Set Decimal Mode
SEI Set Interrupt Disable Status
STA Store Accumulator in Memory
STX Store Index X in Memory
STY Store Index Y in Memory
TAX Transfer Accumulator to Index X
TAY Transfer Accumulator to Index Y
TSX Transfer Stack Pointer to Index X
TXA Transfer Index X to Accumulator
TXS Transfer Index X to Stack Pointer
TYA Transfer Index Y to Accumulator

Разработчики подбирали кодировку таким образом, чтобы её было удобней обрабатывать декодером и рандомной логикой. Более подробное описание каждой инструкции вы можете узнать перейдя по ссылке соотв. кода операции.

Прерывания

Всего у 6502 существует четыре типа прерываний:

  • IRQ: обычное аппаратное прерывание. Можно запретить флагом I (interrupt disable), если флаг I=1, это значит что прерывание "отключено" и не проходит в процессор.
  • NMI: немаскируемое прерывание. Имеет более высокий приоритет над IRQ, срабатывает по перепаду уровня, конкретно - по спаду (falling edge).
  • RES: аппаратный сброс. После включения 6502 нужно устанавливать контакт /RES в 0 в течении нескольких тактов, чтобы процессор "пришёл в себя".
  • BRK: программное прерывание. Инициируется инструкцией BRK.
  • Показать исходный текст