Процессор 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 комментарий