=A=L=X=
> Scorpion ZX 256 - прям в точку на эту тему.
У нас копировали все, кто пытался хоть что-то ваять сам. У меня на Балтике было. Причём озу было 512к
Вообще несколько обидно от того какой разброд пошёл после архитектуры ZX Spectrum 128, которая управляется портом $77FD
Официальный ZX Spectrum +3 умудрился дойти до такого, что через его порт $1FFD управление дополнительными банками ПЗУ требовало обязательно записи в него для переключения между банками ПЗУ Basic 128 и Basic 48 - этим чудакам даже пришлось переписать процедуру переключения банков по адресу $5B00, ибо иначе никак. То есть ломалась совместимость как будто намеренно, вместо расширения порт 1FFD вёл себя как обязалово.
У тех же пентагонов и скорпионов тоже радикально отличаются подходы к менеджменту дополнительных банков памяти свыше 128Кб.
В общем когда пытаешься выйти за рамки ZX Spectrum 128, то уже приходится выбирать конкретную архитектуру под что пишешь без совместимостей с остальным зоопарком.
Почитав поподробнее про первую популярную портативную консоль от Nintendo - Game Boy я с удивлением обнаружил, что процессором в нём служил не клон Zilog Z80 (полностью совместимый с Intel 8080) и даже не "совместимый с 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, **
Код Было Стало ------------------------------------ 08 ex af, af' ld (a16), sp 10 djnz * stop 0 D9 exx reti
Код Было Стало ------------------------------------ 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)
Любопытны так же две последние инструкции из таблицы выше - дело в том, что они уже были в 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-)
Вот такой мутантик получился из Z80 и i8080 в руках Nintendo.
Полностью таблицу его оп-кодов любопытствующим можно посмотреть здесь: http://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html
А чтобы было с чем сравнивать - вот таблицы оп-кодов Z80: http://clrhome.org/table/
=A=L=X=
> Это был процессор Sharp LR35902, который являлся дикой смесью из Intel 8080 и
> Z80 с собственными блекджеками.
> Во первых - он был почти совместим по системе команд с Intel 8080. Однако
> некоторые вещи даже из i8080 пошли под нож.
Интересно, это они из любви к прекрасному или просто пытались удешевить чип ?
0iStalker
> Интересно, это они из любви к прекрасному или просто пытались удешевить чип ?
Game Boy должен был как можно дольше работать от батареи, поэтому наверное тут больше попытка сделать всё сердито для энергоэффективности.
В процессе пописывания данных статей немного познакомился с энтузиастом, который пишет на TS Config.
TS Config - это конфигурация для компьютера-конструктора ZX Evolution, разработанная TS-Labs.
В базисе совместима с Pentagon 512, но еще куча фарша добавлено.
Так вот, он совсем недавно портировал Соника Супер-Ёжика с 8-битной Sega Master System на этот самый TS Config, подробнее о приключениях в процессе можно почитать тут: http://hype.retroscene.org/blog/822.html
P.S.
А вот здесь сам бинарь и ссылка на эмулятор: http://hype.retroscene.org/blog/games/821.html#cut
Немного обновил и переупорядочил выше текст про Sharp LR35902 и задумался - вот выкинули из него (по сравнению с i8080 и Z80) флаги S (знака) и P (чётности/знакового переполнения) - а насколько эти флаги были востребованы?
Оказалось, что в общем то действительно не особо.
Во первых - все условные переходы в Z80 работали исключительно по содержимому одного только флага. Если с Z/NZ и C/NC всё довольно логично, нужно и уместно, то для сравнения чисел со знаком этого уже сильно не хватает. Ну во первых знак, то есть самый верхний бит, можно протестировать двухбайтовой командой BIT 7, A, где установится флаг Z, а можно и однобайтовой RLCA с разрушением правда аккумулятора, но 7-ой бит ляжет во флаг C. Так или иначе для проверки чисел со знаком на больше-меньше нужно тестировать сразу и бит знака и бит знакового переполнения.
Например, в 8086 условный переход JGE (Greater or equal) осуществляется когда SF = OF, а условный переход JL (Less) когда SF <> OF, где SF и OF это флаги знака и знакового переполнения.
В Z80 таких "комбинированных" команд сравнивающих флаги просто не было - флаги тестировались по одному и надо было выстраивать цепочки переходов, чтобы отсекать нужные условия. В общем сравнения чисел со знаком становились геморроем - и это действительно в одном кросс-компиляторе Си под Z80 упоминается в заметках про оптимизацию.
Кроме учета знакового переполнения в арифметических команда флаг P в Z80 в логических командах выступал как флаг чётности (parity) - хранил чётное или нечетное в результате было число единичных бит.
Вот это применение флага еще более интересно.
В 8086 этот флаг даже не пытались совмещать, а сделали прямо отдельным флагом PF, который до сих пор, даже в AMD64 хранит чётное или нечётное число единичных бит содержится в самом нижнем байте результата. Заметьте, что учитывается только нижний байт, даже если регистр 64-битный.
На деле этот флаг уже давным давно потерял какую либо актуальность. Тестирование байта на чётность количества единичных бит было крайне распространённой техникой детектирования ошибок в телекоммуникационных линиях когда то. Да и сейчас встречается. Но когда то ради удешевления периферии дошли до того, что этот контроль чётности снимали с самих коммуникационных портов и возлагали на центральный процессор. Операция несложно реализовывалась на транзисторах, но имитация её другими командами процессора вовлекала длинные циклы и создатели процессоров сознательно шли на включение такого флага в систему команд ради гипотетического быстрого контроля некой коммуникационной линии. Z80 поступил еще довольно разумно совместив этого флаг и флаг знакового переполнения в одном, но в 8086 сия древность занимает свой личный бит в регистре флагов с самого начала и видимо навсегда.
Забавно, что некий программист всяких сетевых штук Wolfgang Kern пишет, что пользовался переходом по флагу PF на i386 всего два раза за всю жизнь - как раз в драйвере COM-порта и в каком то очень старом 8-битном вычислении. При этом он утверждает, что кодобаза по которой он вёл поиск занимает ажно 14 Гб. пруф
=A=L=X=
P вообще самый бесполезный флаг был. Через него детектился режим IFF2. Но я честно говоря не сталкивался с необходимостью это как-то делать. Это скорее востребовано в коде обслуживания Magic button.
Dexus
В Z80 флаг P был вообще многофункциональным. При арифметических командах он выступал в роли знакового переполнения (oVerflow), при логических - в роли собственно чётности (Parity), но так же еще строковые команды типа CPI и LDI заполняют его чтобы сигнализировать об обнулении счётчика BC, что может быть полезно тоже. Про детекцию режима IFF2 даже не знаю.
Поэтому в принципе в Z80 он мог быть полезен и кроме функционала проверки чётности единичных бит. Однако пока я писал текст выше я сам забыл об истории вопроса. А ведь 8080 являлся идеологическим потомком 8008, а 8008 проектировался для того чтобы стать микропроцессором в терминале Datapoint 2200, а терминалы по природе своей обязаны решать задачу пересылки данных по линии связи с сервером. Поэтому parity-бит и был внедрён прямо в архитектуру процессора, а далее понятно, что Intel протащило его через 8080, 8086 и вплоть до современных процессоров. Если взять лагерь конкурентов - семейство Motorola/MOS, то там никакого parity отродясь не было.
А если взять ARM, то там флагов вообще ровно четыре - Z (ноль), C (перенос), V (overflow) и S (sign) - компактная четвёрка, решающая сейчас все адекватные задачи на проверки переполнений и сравнений как знаковых так и беззнаковых.
Как то так получилось, что я никогда не видел алгоритм целочисленного деления (на асме, разумеется, ибо на ЯВУ он и не нужен).
Вот умножение - и сам делал и другие реализации видел, а деление всегда оставалось за кадром. И в связи с тезисами, что оно в железе заметно тормознее умножения я так же думал, что алгоритм должен быть зубодробительным. Это убеждение подпитывалось даже гуглом, в котором если искать вещи типа "быстрое деление на Z80", то начинает вываливаться какая то неточная аппроксимация, отсылки к томику Кнута с какими то оценочными аналитиками, проблемы непростого масштабирования на произвольное число разрядов и т.п.
Вчера же случайно наткнулся на набор математических функций для Z80 и смотрю - вот оно, целочисленное деление байт. Ассемблер может выглядеть довольно cryptic, особенно когда результат прямо в аргументе прокруткой формируют, но смотрю и точно понимаю, что алгоритм должен легко масштабироваться и он совсем небольшой - не больше умножения. Начинаю всматриваться дальше и понимаю, что это банальное деление столбиком, причем как и умножение оно в двоичной системе сильно упрощается по природе своей. Хахаха, а вся сложность по сравнению с умножением заключается в невозможности распараллелить на независимые шаги со слиянием результата. Как грица myth busted.
Dexus
> P вообще самый бесполезный флаг был.
Стoп! Так-с…
Зря я этот флаг, значит, у себя в x80 поддерживаю?
Хотя без него «SKIP/LOOP/WAIT»-режимы не реализуешь…
(Не выделять же под них отдельный регистр!)
P.S.: Никогда не задумывался «о рудиментарности» флага паритета…
Да и в политике «паритет» частенько звучит…
=A=L=X=
> Как грица myth busted.
Поразрядные алгоритмы (их, кстати, дохрена: деление, корень, логарифм, тригонометрия) — это вариант исключительно для ущербных микроконтоллеров.
Они имеют смысл исключительно при отсутствии хардварного умножения. С умножением полиномиальные аппроксимации и итерационные методы заруливают все.
}:+()___ [Smile]
У тебя есть некий полиномиальный алгоритм бинарного умножения, с количесивом итераций меньше количества бит операндов?? Что-то ты сформулировал свой тезис как-то невнятно, насчёт ущербности.
Alikberov
> Зря я этот флаг, значит, у себя в x80 поддерживаю?
Если стояла цель совместимости с 8086 то не зря конечно.
}:+()___ [Smile]
> Они имеют смысл исключительно при отсутствии хардварного умножения.
Лет 10 уже назад читал и тестировал (оказалось правдой), что на FPU x86 эпохи всяких пентиумов 2 или 3 деление работало почти так же быстро как умножение, потому что работает оно там через reciprocal+mul (то есть быстрая полиноминальная 1/x + умножение на результат y). Но при этом целочисленное умножение этому трюку не поддавалось и работало медленнее всех арифметических операций, включая вещественные.
P.S.
Хотя это не исключает, что целочисленное деление всё равно как то наскипидарено, но забавно как раз в том, что его целочисленность путалась под ногами даже тогда.