Почему у ZX Spectrum нелинейная раскладка видеопамяти

Тема в разделе "WASM.ARTICLES", создана пользователем aa_dav, 17 ноя 2021.

Метки:
  1. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    439
    Если у вас был ZX Spectrum, то даже без навыков программирования графики в ассемблере вы постоянно должны были замечать странную вещь при загрузке игр с магнитофона — линейная заливка видеопамяти данными визуально выглядела нелинейно:
    [​IMG]
    (типичнаая загрузка экранной заставки на ZX Spectrum)
    Графическое разрешение спектрума — 256x192 пикселей. Визуально экран как бы поделен на три части — так называемые "трети экрана" каждая из которых состоит из восьми строк символов, 32 символа 8x8 пикселей в строке. Строка пикселей описывается 32 байтами монохромного изображения (8 пикселей на байт) идущих в памяти линейно, но вот строки чередуются весьма замысловатым образом. Данные о цвете (таблица атрибутов) хранятся сразу после данных пикселей, являются квадратным массивом 32x24 байт и применяются к блокам 8x8 пикселей по сути описывая какой цвет будет у всех нулевых и какой цвет будет у всех единичных пикселей данного блока (символа), что было продуманным компромиссом между потреблением памяти и графико/цветовыми возможностями компьютера, порождая однако сильную головную боль у всех кто хотел выйти за рамки вывода текста и выводить графические данные в цвете. Но это отдельная песня.

    Здесь же мы исследуем вопрос о том почему строки изображения идут в видеопамяти таким странным образом. Вопрос этот мучал меня с детства, но ответ на него я нашёл только вчера (имеется ввиду момент написания статьи!).
    Если бы видепамять в спектруме была бы линейной, то 16–битный адрес каждого её байта (описывающего горизонтальную полоску из 8 пикселей) имел бы следующую битовую маску:
    Код (Text):
    1. 010yyyyy yyyxxxxx
    Здесь биты X (от 0 до 32) — это номер полоски в строке, а биты Y (от 0 до 191) — номер строки. Но в спектруме три нижних бита верхнего байта адреса поменяны местами с верхними тремя битами нижнего байта адреса:
    Код (Text):
    1. 010ttwww yyyxxxxx
    При этом получается, что биты X по прежнему описывают номер байта в строке, но у других бит возникает новый специфический смысл.
    Биты T (от 0 до 2) определяют треть экрана, биты Y (от 0 до 7) — вертикальную позицию знакоместа в этой трети, а биты W (от 0 до 7) вертикальную полоску пикселей внутри знакоместа. В силу такой раскладки заливка видеопамяти и выглядит как на гифке выше.
    Так зачем же так сделано?

    Я слышал много вариантов объяснения этому — использование уже готовых микросхем с такой системой, упрощение регенерации памяти, ускорение вывода текста... но все они оказались неверными.

    Как ни странно, но для объяснения такого положения вещей придётся вспомнить ключевые особенности динамического ОЗУ или DRAM. ОЗУ реализованное на транзисторах по схеме триггера называется статическим — Static RAM (SRAM) и по природе своей сохраняет информацию до тех пор пока к нему подводится ток. Но оно дорогое и применяется в современных компьютерах в основном в роли кэша процессора. Основное же ОЗУ реализовано как динамическое Dynamic RAM (DRAM) — в нём биты хранятся в виде зарядов микроскопических конденсаторов и эти конденсаторы постоянно "утекают" и теряют заряд, поэтому периодически их надо обновлять в процессе называемом регенерацией. Периодически надо считывать или записывать ячейку памяти — при этом её содержимое в конденсаторе обновляется и начинает "утекать" снова. Обновлять память надо довольно быстро, но обновляются не отдельные биты или байты, а большие блоки называемые "строками" в которых отдельные байты представлены как "столбцы". У чипа памяти сперва запрашивается строка — при этом он извлекает её во внутренний буфер–защёлку всю за раз, а потом опрашивается столбец — и вот здесь уже нужный бит (или больше, в зависимости от микросхемы) выдаётся наружу. И в этот же момент происходит обновление всей строки из защёлки — происходит регенерация этой строки. Адресные линии памяти спектрума разведены таким образом, что нижние (именно нижние) 7 бит адреса являются номером строки в чипах памяти, а верхние 9 бит выступают в роли столбца (правда после разброски по нескольким чипам).

    И вот здесь возникает интересный момент — чипы применявшиеся в то время имеют функцию ускорения доступа к памяти — так называемый page mode. Когда адрес строки уже выставлен и строка считана в защёлку, то повторные обращения к столбцам можно делать без выставления строки — экономится время как на выставление адреса строки, так и на считывание самой строки в защёлку.

    Когда видеочип спектрума выводит очередную полоску пикселей ему нужно считать два байта — саму полоску из пиксельных данных и её цвета из таблицы атрибутов.

    И вот тут то и выстреливает "магия" нелинейной видеопамяти — оказывается, при такой адресации как принята в спектруме нижний байт адреса полоски пикселей всегда совпадает с нижним байтом адреса его атрибутов. То есть эти байты всегда находятся в одной и той же строке чипов памяти.

    Более того, если адрес полоски пикселей имеет битовое представление 010ttwww yyyxxxxx, то адрес его атрибутов равен 010110tt yyyxxxxx — то есть просто откидывается компонента www и некоторые биты преставляются местами с полным сохранением нижнего байта адреса. Это позволяет видеоконтроллеру при отрисовке видеопамяти воспользоваться ускоренным режимом считывания с сохранением адреса строки и считывать пиксели и их атрибуты за 170 нс вместо 320 нс которые нужно было бы тратить на считывание двух байт из разных страниц. И это было важно для инженеров, потому что процессор и видеочип конкурировали за одну и ту же память, приоритет отдавался видеочипу и процессор вынужден был ждать если хотел работать с ней в тот же момент когда видеочип производит отрисовку.
    И вот уже в рамках этого аппаратного хака/ускорения была выбран такой вариант раскладки в котором было удобно заливать одно знакоместо данными (тот самый момент, что увеличивая верхний байт адреса мы переходим к следующей строке пикселей внутри знакоместа).

    Стоит заметить, что в модели ZX Spectrum 128 и многочисленных клонах применялись уже более скоростные чипы памяти и этот трюк в принципе был не нужен, но ради совместимости раскладку видеопамяти менять уже не стали конечно.
     
    Последнее редактирование: 17 ноя 2021
    Indy_ и Thetrik нравится это.
  2. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    aa_dav,

    Там была апи P, bit = f(X, Y) но небыло обратной. У меня сохранился на бумаге кодес:

    Код (Text):
    1. ; inv #8874
    2. POS:
    3.     ld a,h
    4.     and 7
    5.     ld b,a
    6.     ld a,h
    7.     rla
    8.     rla
    9.     rla
    10.     and 192
    11.     or b
    12.     ld b,a
    13.     ld a,l
    14.     rra
    15.     rra
    16.     and 56
    17.     or b
    18.     cpl
    19.     add a,176
    20.     ld b,a    ; Y
    21.     ld a,l
    22.     rla
    23.     rla
    24.     rla
    25.     and 248
    26.     ld c,a
    27.     ld a,d
    28. L:
    29.     rlca
    30.     ret c    ; X
    31.     inc c
    32.     jr L
    - с непривычки на шелл или крипту похоже :)
     
    aa_dav нравится это.
  3. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    439
    Т.е. это перевод из адреса обратно в координаты?

    Я сам в детстве до реальных практик на асме/машкодах на спектруме не дошёл, только общие азы усвоил.
    Но вот последние годы в рамках ретроностальгических настроений закрываю гештальты.
    У меня есть папка тестов где и ассемблер (SjAsmPlus) и эмулятор (Unreal) и разные исходники что сам набираю в FAR-е и тут же пробую: https://disk.yandex.ru/d/XJzNIt4g3YcMsP

    С год-два назад на западе замутили уберклон и по сути даже официальное продолжение - ZX Spectrum Next.
    Там процессор реализован на FPGA и даже добавили новые инструкции, включая вычисление адреса и маски пикселя. :) PutPixel пишется так теперь:
    Код (Text):
    1.  
    2. ; В D:E координаты X:Y
    3. PutPixel:
    4.     pixelad  ; в HL - адрес байта с пикселем D:E
    5.     setae ; в a - маска пикселя для этого байта
    6.     or a, (hl) ; спрягаем его с содержимым видеопамяти
    7.     ld (hl), a ; и сохраняем результат обратно
    8.  
    Вуаля! :lol:
    И pixelad и setae - это новые инструкции Z80-совместимого процессора ZX Spectrum Next. :)
     
  4. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    aa_dav,

    Было много времени потрачено на заливку фигур, нашлось апп, которое это делало нереально быстро. Хотел его реверснуть, но всё откладывал так не пропал интерес спустя столько лет, может когда и дойдут руки :)
     
  5. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    439
    Раз уж заикнулся выше, сюда же помещу крохотную статейку по новым инструкциям ZX Spectrum Next, ибо Спектрум в целом немного неформат сайта и плодить про него темы не особо имеет тут смысл.

    ZX Spectrum Next не просто духовный наследник ZX Spectrum или клон - это вполне официальный бренд честно взятый у правообладателей на условиях пожертвований доли с его продаж на благотворительность.
    [​IMG]
    Поэтому это даже можно сказать что единственный официальный продолжатель рода за многие многие годы.
    Технически это весьма нафаршированная платформа на FPGA и в том числе на FPGA реализован процессор совместимый с Z80, но кроме всего прочего сильно расширяющий его систему команд.

    Вообще когда дело заходит про систему команд Zilog Z80 я люблю смотреть вот в эту табличку: https://clrhome.org/table/ - довольно хорошо всё расписано и подчёркнуто с высоты табличного вида, поэтому если кто-то вдруг сейчас захочет вспомнить а какие именно инструкции в принципе были у Z80 в базисе своём - можно освежить память по ссылке.

    Что же касается ZX Spectrum Next - полностью весь набор его инструкций можно посмотреть тут: wiki.specnext.dev/Extended_Z80_instruction_set
    Новые инструкции там отмечены литерой E в колонке «Status».
    Все они реализованы на неиспользованных слотах расширенных команд Z80 с префиксом $ED.
    Было любопытно взглянуть что это за инструкции и я бы даже сказал, что в них частично отразилась профессиональная боль программистов под ZX Spectrum. :)

    • PUSH imm16 — затолкать в стек непосредственное данное зашитое в инструкцию. Раньше можно было только регистровую пару.
    • LDWS — интересный вариант блочной инструкции, перебрасывает байт из адреса (HL) в (DE) при этом инкрементирует регистры L и… D. Т.е. только нижний байт HL и верхний байт DE. Написано что это полезно для заполнения графикой Layer 2.
    • LDIX, LDIRX, LDDX, LDDRX — аналоги старых блочных инструкций без префикса X. Все они перебрасывают байт из (HL) в (DE) и декрементируют BC. Старые инструкции без префикса X при этом — если третья буква I — то инкрементируют HL и DE, а если D — декрементируют их. Если есть префикс R, то инструкция автоматически повторяется пока BC не станет равен 0.
      Новые варианты с X главным отличием имеют то, что если перебрасываемый байт равен аккумулятору A, то запись в (DE) не производится. Ну, очевидно, это у нас прозрачность при проброске битмапов можно так реализовать. Еще важное отличие, что новые команды не меняют флаги и декрементирующие с третьей литерой D увеличивают DE, а не уменьшают.
    • LDPIRX — еще одна новая блочная инструкция больше всего по поведению похожая на LDIRX, но не изменяет значения HL, а адрес откуда байт читается берет не просто HL, а подменяет ему нижние 3 бита нижними тремя битами DE. Т.е. HL указывает на выровненный по 8 байтам 8-байтный блок-паттерн, а DE идёт по памяти линейно и переливает этот паттерн циклически в неё. Как и написано — полезно для заливок трафаретом.
    • ADD HL/DE/BC, A — интереснейшая вещь — сложение 16-битных регистровых пар с 8-битным аккумулятором (беззнаково). Очень на самом деле полезно, т.к. в Z80 приёмником 16-битных сложений мог быть только HL и IX/IY в расширенных командах, а увеличить регистровую пару больше чем на один инкремент хочется нередко без длинных пробросок.
    • ADD HL/DE/BC, imm16 — опять таки сложение 16-битных регистровых пар с 16-битной константой из инструкции — по вышеописанным же причинам очень полезная штука.
    • MIRROR A — переставляет биты аккумулятора полностью задом-наперёд (0-7 в 7-0).
    • TEST imm8 — «тестирует» аккумулятор с непосредственным данным — выполняет AND imm16 изменяя флаги, но не меняя аккумулятор.
    • BSLA/BSRA/BSRL/BSRF/BRLC DE,B — сдвиги и прокрутки 16-битной регистровой пары DE на B бит. Тоже очень полезные инструкции, т.к. все сдвиги и прокрутки в Z80 сдвигали и прокручивали только на 1 бит за инструкцию, здесь же можно сразу на любое осмысленное и программируемое в рантайме число бит. Забавно что прокрутка (rotate) выражена только командой «прокрутка влево»: BRLC, а чтобы вращать вправо надо выполнить её же с B=16-параметр. Еще необычным тут показался сдвиг вправо BSRF — он в отличие от сдвига со знаком всегда вдвигает в верхние разряды 1 (т.е. принудительно делает число отрицательным даже если оно было положительным). Не припомню такого где-то еще.
    • SETAE — очищает аккумулятор A и выставляет в нём единичный бит с номером 7-E (на деле 7-(E&7), т.к. в E учитываются только нижние 3 бита). Написано, что это полезно как маска для пиксельных режимов ULA когда в E находится координата X.
    • SWAPNIB — обменивает местами нижнюю и верхнюю квадры бит в аккумуляторе.
    • JP (C) — выполняет чтение из порта ввода с номером в регистре C и обновляет нижние 14 бит счётчика инструкций PC следующим образом: PC[13:0] = (IN (C) << 6). Вот тут я растерялся зачем оно может быть полезно и пояснение «can be used to execute code block read from a disk stream» ничем не помогло.
    • OUTINB — действует как OUTI, но НЕ декрементирует B, т.е. out(BC,(HL)); HL++
    • NEXTREG nn1, nn2 — часть новых портов ввода-вывода ZX Spectrum Next действует опосредованно через порт $243B. Сперва в него пишется номер суб-порта с которым мы работаем, а потом записывается данное которое мы в него пишем. Эта инструкция делает запись в этот порт непосредственных данных минуя эту сложную развязку. А по смыслу (но не размеру и скорости) это эквивалентно out($243B,nn1); out($253B,nn2).
    • NEXTREG nn, A — то же самое что выше в варианте out($243B,nn); out($253B,a).
    • PIXELDN — берёт адрес в HL как адрес в видеопамяти и обновляет его так чтобы он указывал на одну строку пикселей ниже. Тоже полезная штука, т.к. нелинейность видеопамяти спектрума эту задачу делает не совсем тривиальной (см. тут или более академично тут).
    • PIXELAD — помещает в HL адрес байта в видеопамяти ULA в котором содержится точка с координатами (E,D). Ох! Это штука конечно берёт приз моих зрительских симпатий. xD
     
  6. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    561
    Ещё можно VGA(1987 г) рассмотреть. Вот почему не добавили условное копирования блока, VRAM-->VRAM? Облегчило использования спрайтов, а так же окошек, винду можно было выпустить намного раньше.
     
  7. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    439
    То, что IBM как большая деловая колбаса корпорация не интересовалась игровыми применениями своих компьютеров, имхо, неудивительно. Собственно сама история о том как бесплатный стандарт IBM PC покорил сердца миллионов своей открытостью это романтическое искажение фактов. На самом же деле большая громоздкая корпорация "Больших Машин для Бизнеса" просто прошляпила направление персональных компьютеров которое изначально считала баловством (откуда и концепция "все детали взять с полки, а не напрягать производственные линии самой IBM"), а когда судорожно попыталась загнать джинна обратно в бутылку (PS/2), то ей этого уже просто не дали сделать фирмы прикормившиеся на плодородной ниве.
    А вот если взять тот же Commodore 64 который правил половину бала в Северных Америках, то у него как раз видеоадаптер умел самые настоящие аппаратные спрайты как какая-нибудь консоль игровая и ограниченная поддержка скроллинга была (хотя такая, что скроллинг всё-равно превращался в задачку, но в любом случае намного более реальную, чем всю экранную область переписывать каждый кадр).

    Из серии видеоадаптеров IBM мне понравился тот фактик, что CGA который запомнился у нас игрокам по глазоразрывным видеорежимам с четырьмя ядовитыми цветами которые были совершенно непригодны к играм на самом деле мог показывать 16-цветную картинку очень мягких и красочных тонов. Причём на аппаратном уровне это были те же самые во всём видеорежимы кроме одного - включался сигнал color burst и вход видеосигнала надо было брать с телевизионного выхода на телевизор NTSC (этот вывод в поздних ревизиях видеокарты пустили под нож и её истинные возможности стало просто невозможно оценить в полной мере). Дело в том, что со включенным битом генерации сигнала color burst на выходе видеосигнала NTSC из четырёх бит составляющих четыре соседних пикселя в монохромном режиме или два соседних пикселя в 4-х цветном режиме в трактах цветного телевизора генерировались мягкие цветовые комбинации.
    Разница налицо:
    [​IMG]
    [​IMG]
     
  8. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    561
    Ну это прозевали толстозадые заплывшие жиром мозги из руководства, и не только IBM. Сколько игропром, эээ, какую игропром(игры, игровые устройства(приставки, видеокарты)) имеет капитализацию? С 1975-2021? Точно больше триллиона американских фантиков. Сколько точно, я не знаю. О как! В середине 80-х ИБЭМЭ пыталось создать игровой ПК, но нихрена не получилось, вот что бывает, если за дело берётся умный, но при этом, просто придурок, а всего-то надо было добавить в В/К некоторые аппаратные функции. А я думаю..., а чего-то вот в играх не сделано вот так? А оно то вон что, наличие умного мозга, ещё ничего не значит...
    ЗЫ
    Это камень в огород, и сэру Клайву Синклеру, тот ещё боклан...
     
  9. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    439
    Ооо, я только пару лет назад наткнулся на обстоятельный разбор по Синклеру "без купюр": http://zxnext.narod.ru/hist7275_1.htm
    Это очень интересно на самом деле насколько "китайской" была стратегия всей его жизни.
    Три презабавнейших фактика оттуда я скомпилировал в виде небольшой статьи тоже:

    Три примера бизнес-гениальности (сэра) Клайва Синклера

    Некоторое время назад мне попалось видео про калькулятор от Sinclair Research и я лениво поискал в этих наших интернетах о том с чего фирма начинала и довольно быстро меня поразило то насколько "китайской" была бизнес–стратегия Клайва Синклера которой он придерживался всю жизнь. Да, я читал и много раньше о том, что он любил дешево и сердито и собственно архитектура ZX Spectrum — наглядный тому пример. Но проникнувшись ниже изложенными разрозненными фактиками я восхитился тому насколько же "прожжённый" был этот жук. :)
    Вот здесь: http://zxnext.narod.ru/hist7275_1.htm, (помимо много чего прочего — отличный цикл статей про историю компании!) можно узнать такую пикантную деталь, что наладив контакты с американской Texas Instruments Синклер начал покупать у неё бракованные чипы интегральных усилителей SN76013. Бракованными они были потому что не выдерживали целевые токи, перегревались и перегорали. Фирма Синклера брала этот брак по дешевке, ставила на него массивный радиатор, исключая перегрев, и продавала в составе усилителя!
    [​IMG]
    (...брюки превращаются из брака в третий сорт)

    Но вернёмся к калькуляторам — первый калькулятор Синклеа — Sinclair Executive произвёл своего рода фурор — для своего времени (1972 год) он был крайне малых размеров — всего лишь размером с ладонь или чековую книжку:
    [​IMG]
    И за этим стоит интересный момент. Главная и доминирующая над всей прочей схемотехникой микросхема в нём — Texas Instruments TMS1802 "калькулятор в чипе" (7 тысяч транзисторов).
    Этот чип в норме потреблял 350 милливатт и жрал батарейки как не в себя. Калькуляторы на его базе на рынке уже были и не один, но либо с огромным отсеком для батарей либо с блоком питания от сети.

    Однако инженер Sinclair Дэвид Парк обнаружил, что требования к питанию можно было снизить до 20 милливатт. Дело тут в том, что в той полупроводниковой технологии по которой был чип сделан пиковая мощность схемой потребляется во время поступления синхроимпульса и тем самым запуска перехода транзисторной логики в новое состояние. После "шага вычисления" токи "устаканиваются", выходят на постоянный уровень и он оказывается уже весьма небольшим. Так вот энергию в новом калькуляторе начали поставлять импульсами длительностью 1,7 микросекунд. Тактовый генератор работал с частотой 200 килогерц во время вычислений и 15 килогерц между операциями, что означало, что отключения энергии длились 3,3 микросекунды во время вычислений и до 65 микросекунд между ними. Устройство полагалось на ёмкость чипов чтобы сохранять информацию когда энергия не поступала и 1,7 микросекунды оказалось достаточно для чипа чтобы выполнить один переход состояния электронной схемы. Любое вычисление могло быть сделано за 1000 таких переходов. Это позволило увеличить срок жизни батареи до 20 часов непрерывного использования при использовании трёх крохотных батареек от слухового аппарата, что было эквивалентно четырём месяцам обычного использования (вообще в приборе было четыре таблеточных батарейки, т.к. необходимо было запитывать еще табло и т.п.).

    Как говорится, не родись электронным чипом при капитализме — и тебя загонят как раненую лошадь и заставят работать без питания. :lol:
    Это позволило миниатюризировать калькулятор сделав его для своего времени невероятно маленьким — легко помещающимся в карман и на рынке он произвёл фурор продаваясь по цене £79,95 без НДС при себестоимости в £10.

    А вот чтобы лучше понять следующий пример я обрисую ситуацию с самими чипами для калькуляторов. Как правило это были 4–битные чипы с десятичной арифметикой — один десятичный разряд соответствовал группе из четырёх бит и базовая арифметическая операция — сложение двух разрядов с учётом переноса из предыдущего был апогеем вычислительных способностей таких чипов. Чтобы реализовать сложение нужно было последовательно применить суммирование цифр разряд за разрядом. Чтобы реализовать умножение — в точности как мы умножаем столбиком повторять сложения со сдвигом над неким аккумулятором и так далее. Классические такие чипы как те же от Texas Instruments при этом имели память программы которая прошивалась на заводе при выпуске микросхемы под нужды заказчика — таким образом заказчик мог программно управлять числом разрядов в своём калькуляторе и возможно даже навешивать на него какие то дополнительные функции, например кнопку M+ или кнопки сразу подставляющие на табло избранные математические константы. Однако память программы была не бесконечна и добавить много новых функций было невозможно. Для более мощных вычислений, например тригонометрических, нужны были чипы помощнее, а вот с [+][–][*][/] справлялись самые базовые.
    И вот Клайв Синклер приезжает в США чтобы заказать в Texas Instruments чип для планируемого научного калькулятора — под научностью тут понимается наличие не только арифметических операций, но и тригонометрических и логарифмических функций. Однако по неизменному своему кредо он хочет сделать его крайне дешевым и интересуется — не влезет ли такой функционал в арифметический чип TMC0805?

    Инженеры Texas Instruments посмеиваясь ответили, что конечно же нет: в этом чипе было только три регистра, память инструкций в 320 шагов и отсутствовал механизм вызова подпрограмм. Его характеристик с запасом хватало для арифметических операций и парочки "фич", но научный калькулятор? Невозможно!

    Но там где у других было "невозможно" Синклер видел только возможность заработать. Работа закипела и за несколько дней в отеле со своим специалистом Найджелом Сиэлом они создали прошивку научного калькулятора на базе арифметического чипа и сдали её в заказ в Texas Instruments.
    [​IMG]
    По ссылке приведённой в начале этой статьи ключевые решения позволившие сделать невозможное обрисованы в общих чертах. Однако я нашёл подробнейший разбор подкапотных полётов на английском языке вот тут: http://files.righto.com/calculator/sinclair_scientific_simulator.html (там же в онлайн–эмуляторе можно попробовать как работает этот калькулятор на ощупь) и вкратце тут его перескажу.
    Нулевым, но не менее "изящным" чем остальные пунктом можно назвать отсутствие у калькулятора кнопок с математическими константами — места под них не было совсем, но зато некоторые из них были заботливо вынесены на лицевую панель калькулятора в качестве памятки, что прекрасно видно на фото.

    Во первых — конечно же ключевой особенностью было переиспользование кода, но без механизма подпрограмм куски кода просто ориентируясь на глобальные флаги (а других там и не было) переходили условными переходами туда или сюда — так эмулировались подпрограммы.

    Во вторых не было никаких проверок на ошибки — если алгоритмы не справлялись, они просто выплёвывали мусор никак не сигнализируя об ошибке.
    Например арктангенс маленькой величины, например 0.0005, считался 1 минуту 48 секунд и выплёвывал неверное значение 0. На самом деле из–за особенностей алгоритма число в регистре испытывало переполнение и проворачивалось через 999.99955 и через 9999 итераций проваливалось в ветку выполнения арктангенса.

    В третьих для большего упрощения алгоритмов пользователь обязан был вводить числа в нормализованной форме, т.е. невозможно было ввести число 450, надо было вводить число 4,5E02 (где E02 это форма записи "десять в степени два", что можно воспринимать как добавление двух нулей справа). Десятичная запятая в этом калькуляторе всегда прикреплена к своему месту сразу после первого разряда и пользователь вынужден был с этим мириться. Таким образом перед операциями числа сразу были нормализованы как и после операций и программа не тратила драгоценные операции на их приведение в "человекочитаемый вид".

    В четвёртых — калькулятор использовал нечто вроде обратной польской нотации, только по сути своей это была просто простейшая модель вычислителя.

    В обычном калькуляторе мы складываем числа нажимая кнопки [1] [+] [2] [=], но это требует от программы калькулятора запоминания на каком этапе ввода выражения мы находимся и Синклеру не подходило.

    В Sinclair Scientific же не было вообще кнопки [=]! Кнопки операций сразу совершали действие над теневым регистром и числом введённым на табло после чего помещали результат в теневой регистр и до нажатия следующей кнопки показывали его на дисплее. Так после сброса в теневой регистра записывался 0 и чтобы, например, разделить 8 на 4 мы должны были набрать:
    1) [8]
    2) [+] — при этом 8 сложится с 0 в теневом регистре и попадёт в него
    3) [4]
    4) и вот теперь нажать [/] — тут и произойдёт искомое деление.
    Т.е. промежуточное нажатие на [+] использовалось как разделитель чисел используя просто тот факт, что сумма числа с нулём — это само это число. На программируемых советских калькуляторах я видел что под действие разделения чисел была предназначена отдельная клавиша, а тут жмотство опять во главе угла! :lol:

    Ну и в пятых — калькулятор тупо не гнался за точностью. Ну т.е. вообще. Как метко написано в русской статье — соревновался в точности он скорее с логарифмическими линейками. Точность вычислений в 3–4 разряда после запятой на чём то сложнее арифметики была нормой, но в некоторых предельных случаях очень больших или маленьких чисел калькулятор и вовсе мог выдавать неверные результаты! Инженеров из Texas Instruments или Hewlett Packard инфаркт бы хватил от идеи, что калькулятор может неточно вычислять числа в своей разрядной сетке, поэтому их сознание и было зашорено "невозможно!", но для Синклера и это был не предел!
    Например для крайнего упрощения тригонометрии алгоритм поиска синуса сводился к последовательному применению поворота точки!

    Пусть S — это синус угла, а C — это его косинус. Тогда пользуясь формулой поворота комплексного числа (комплексное умножение есть поворот) можно выйти на тригонометрию вот так:
    C = C — S / 1000
    S = S + C / 1000
    Это формула поворачивающая С и S (как координаты точки на единичной окружности и по совместительству — тригонометрические функции) на 0.001 радиана. Повторяя её N раз в цикле, где N=радианы*1000 (напомню, что в калькуляторной десятичной арифметике умножение или деление на 1000 это просто сдвиг на 3 разряда) мы вычисляем нужные синусы и косинусы.
    Вуаля!
    И подобными же трюками Синклер и его инженер запихали еще и тангенсы и логарифмы до кучи в какую то жалкую (оставшуюся после реализации арифметики) сотню инструкций калькулятора который вообще не предназначался для чего либо сложнее арифметики!
    В результате, конечно, калькулятор реально мог задуматься на десяток секунд считая какие то предельные случаи, иногда глючил по точности даже хуже трёх знаков после запятой и вообще. Но, это был научный калькулятор за жалкие £49,95 (без НДС) (~$120)! Что в то время было конечно фантастическим предложением, учитывая что прямой конкурент из Hewlett Packard — HP35 стоил $375!

    Поэтому нужно ли удивляться, что ZX Spectrum оказался тем ПК который завоевал сердца и умы миллионов оказавшись в экстремальной позиции на шкале "цена/качество"?