Почитав поподробнее про первую популярную портативную консоль от 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): Код (Text): 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 некоторые поменяли своё назначение: Код (Text): Код Было Стало ------------------------------------ 08 ex af, af' ld (a16), sp 10 djnz * stop 0 D9 exx reti RETI — это RET + EI, то есть возврат из процедуры с одновременным разрешением маскируемых прерываний. STOP вероятно стопорит как то иначе нежели HALT. Но кроме вышеперечисленных кодов осталось еще немало других с зарезанными флагами, их в результате начали использовать по другому (то есть это переиначенные коды команд еще из i8080): Код (Text): Код Было Стало ------------------------------------ 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 можно еще записать иначе, чтобы понять лучше их сущность: Код (Text): 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: Код (Text): Код Было Стало ------------------------------------ 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/