Процессор Sharp LR35902





Почитав поподробнее про первую популярную портативную консоль от Nintendo — Game Boy я с удивлением обнаружил, что процессором в нём служил не клон Zilog Z80 и даже не «совместимый с Z80» чип, как иногда можно прочитать в разных местах (и как я сам иногда писал), а довольно таки своеобразный зверёк — Sharp LR35902. В английской вики можно найти утверждения, что он является смесью Intel 8080 и Z80, но это тоже правда лишь отчасти. Судя по всему Sharp LR35902 был продуктом вдумчивой переработки микросхемы Z80 с участием инженеров как Nintendo так и Sharp, чтобы получить 8–битный процессор идеальный в их представлении для портативной консоли. Явно преследовались цели простоты и энергоэффективности — вещи критически важные для машины, работающей от батареек. Основная часть произведенных над Sharp LR35902 работ являлась отрезанием сложного и ненужного, но так же взамен были предложены некоторые простые, но эффективные вещи.

Итак, по системе команд LR35902 старается как можно больше унаследовать от Intel 8080 и Z80, но в процессе упрощения были ликвидированы флаг P (parity/чётность или overflow/переполнение), флаг S (sign/знак) и, поэтому, половина команд условного выполнения (условия P, M, PO и PE). В результате в системе команд остались только условия Z, NZ, C, NC, то есть условные вещи (а в i8080 это JP, CALL и RET) стали возможны только по флагу нуля и переноса. Кроме того под нож из i8080 пошли порты ввода–вывода.
В результате в LR35902 освободилось много кодов инструкций из которых следующие так и остались незанятыми (все мнемоники здесь и далее берутся как в Z80):

D3  out (*), a
DB  in a, (*)
E3  ex (sp), hl
EB  ex de, hl
E4  call po, **
EC  call pe, **
F4  call p, **
FC  call m, **

То есть эти инструкции из i8080 в Sharp LR35902 отсутствуют.
От Z80 осталось еще меньше — команды относительного перехода JR, да перфикс битовых операций CB (о нём ниже). Ни регистры IX, IY, ни дополнительные команды наподобие LDIR и расширенной 16-битной арифметики в LR35902 не попали.
Так что по сравнению с Z80 и не используются еще коды DD, ED и FD.
Более того, некоторые из команд Z80 введённых в нём по сравнению с i8080 некоторые поменяли своё назначение:

Код     Было            Стало
------------------------------------
08      ex af, af'      ld (a16), sp
10      djnz *          stop 0
D9      exx             reti

RETI — это RET + EI, то есть возврат из процедуры с одновременным разрешением маскируемых прерываний.
STOP вероятно стопорит как то иначе нежели HALT.
Но кроме вышеперечисленных кодов осталось еще немало других с зарезанными флагами, их в результате начали использовать по другому (то есть это переиначенные коды команд еще из i8080):

Код     Было            Стало
------------------------------------
E0      ret po          ldh (a8), a
F0      ret p           ldh a, (a8)
E2      jp po, **       ld (c), a
F2      jp p, **        ld a, (c)
E8      ret pe          add sp, r8
F8      ret m           ld hl, sp+r8
EA      jp pe, **       ld (a16), a
FA      jp m, **        ld a, (a16)

И вот эти новые команды и интересны. Еще в Famicom/Денди (а скорее всего и ранее) Nintendo маппило порты ввода-вывода в память, поэтому и избавилось от специализированных команд ввода-вывода. Но вместо них были добавлены новые — работающие с основной памятью особым образом. Команды LDH можно еще записать иначе, чтобы понять лучше их сущность:

LDH (A8), A = LD ($FF00+A8), A
LD  (C), A  = LD ($FF00+C), A

То есть эти команды записывают (или считывают) аккумулятор в верхние 256 байт памяти 64Кб-ого адресного пространства ЦП по непосредственному смещению или косвенно по регистру C. Забавно, но это очень похоже на zero-page из семейства процессоров MOS 6502, клоны которых и стояли в Famicom, но только со спецификой 8080 — теперь это можно назвать FF-page, так как в нулевая страница у 8080 занята под точки входа в прерывания.
И действительно у Game Boy верхние 256 байт памяти поделены на две почти равных зоны по 128 байт между портами ввода-вывода и служебным ОЗУ, которое может быть использовано таким образом для хранения быстрых переменных.
Следующие две инструкции — ADD SP, R8 и LD HL, SP+R8 позволяют прибавить к SP байт со знаком или загрузить в HL сумму SP с байтом со знаком — это явно инструкции для поддержки локальных переменных на стеке. Без индексных регистров IX и IY от Z80 адресовать стек в стиле ЯВУ стало трудно, но эти две команды помогают это сделать — выправлять кадр стека с помощью первой и помещать в HL адрес переменной рядом с вершиной стека, а косвенные загрузки по HL в 8080 уже есть.

Любопытны так же две последние инструкции из таблицы выше — дело в том, что они уже были в i8080, но с другими кодами. Оказался переделан еще один кусок кодов i8080:

Код     Было            Стало
------------------------------------
22      ld (**), hl     ld (hl+), a
2A      ld hl, (**)     ld a, (hl+)
32      ld (**), a      ld (hl-), a
3A      ld a, (**)      ld a, (hl-)

То есть инструкции 32 и 3A переехали жить в EA и FA, а вместо них и загрузки HL из адреса стали жить загрузки/сохранения аккумулятора по адресу HL с постинкрементами и постдекрементами. Видимо это упрощало декодер.
От Z80 выжил полностью доп-код CB — большое множество битовых операций над всеми 8-битными регистрами процессора.
Однако он не только выжил, но и слегка обогатился — в оригинале коды в диапазоне CB30-CB37 были недокументированными, в Sharp LR35902 же в этих кодах разместили инструкцию SWAP r, которая обменивает у указанного 8-битного регистра верхнюю и нижнюю квадру бит.

Вот такой мутантик получился из Z80 и i8080 в руках Nintendo.
Полностью таблицу его оп-кодов любопытствующим можно посмотреть здесь: www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html
А чтобы было с чем сравнивать — вот таблицы оп-кодов Z80: clrhome.org/table/

1 комментарий

avatar
Спасибо, было интересно почитать. Этот бы кругозор разработчикам Next…
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.