Каллисто на Си: дорожная карта

Идея перевести Каллисто на Си была высказана пару лет назад. Я изначально был и остаюсь её противником. Сама постановка вопроса, на мой взгляд, вызвана не столько практическими нуждами, сколько непониманием Форта и культуры, возникшей вокруг него. Но после глубокого изучения вопроса я понял, что Каллисто на переносимом Си возможна и способна, на данном этапе, помочь сообществу. Для игр и работы с Каллисто сразу перестанет быть нужна дорогая МК-161, которая не у всех есть.

Заниматься переводом на Си я не намерен, это бы лишь отняло время от разработки Каллисто-2. Сишный диалект лежит в стороне от магистрального пути, на котором важнее достичь самокомпиляции Каллисто — на любую платформу. Но помогать могу. Задача всего лишь кажется непосильной. В этой статье расскажу, с какого конца к ней подступиться.

«Данный алгоритм пригоден только для калькулятора! С точки зрения алгоритмических языков он абсолютно неверен. По самой своей сути алгоритм должен иметь два обязательных элемента: начало и конец. Начало у «Лунолёта-2» видно: это ввод… А конца-то у него нет! То есть если по такому алгоритму написать программу для ЭВМ, то машина… НИКОГДА НЕ КОНЧИТ ИГРАТЬ.» В. Талалаев, Киев. ТМ №9, 1986, стр. 35

С самого начала определимся, что речь идёт о Каллисто Классик (4173 строк, html), релиз которой состоялся 7 ноября 2017 года, после года независимого тестирования. Каллисто снабжена профессионально написанным Руководством (pdf, 9Мб), оформление которого содержит дизайн алфавитной клавиатуры для калькулятора (стр. 3). Всё это богатство выложено в Интернет под свободной лицензией и основано на многолетнем советском наследии (1980: Б3-34, 1982: МК-54/56, 1984: МК-61, 1985: МК-52), учитывает его творческое развитие Новосибирском (2007: МК-152, 2009: МК-161, 2011: МК-152М, 2013: МК-1152) наравне с советским опытом разработки трансляторов Форта (1986: Ленинград, ФОРТ-ЕС и 1988: Москва, FORTH ИТЭФ).

Переход от входного языка МК к Каллисто можно сравнить с переходом от RPN к RPL в американских калькуляторах фирмы HP (1987: HP-28C,… 2006: HP 50g). Это бережный вывод отечественных ПМК на проверенный путь из уже до блеска выскобленного тупика keystroke programming — программирования, основанного на автоматическом повторении запомненной последовательности нажатий клавиш. При переходе (перелёте?) на Каллисто сохраняется обратная совместимость с библиотекой советских программ и программ для ЭКВМ (пример) — настолько, насколько это вообще возможно при таких коренных изменениях. Новые же программы разрабатывать значительно проще и дешевле на Каллисто.

Версия на Си может реализовать десятичную арифметику самостоятельно или использовать 64-битную «двойную точность» (англ.) из библиотеки Intel® Decimal Floating-Point Math Library (англ.), уже успешно применённой в «швейцарце» DM42. Благодаря современной технологии «плотной упаковки десятичных» DPD (англ.) американская библиотека в тех же 8 байтах даст 16 разрядов мантиссы и чуть больше 2 разрядов порядка, что достаточно для полноценной замены 14-разрядного BCD-АЛУ «Электроники МК-161».

В статье рассматриваются сразу несколько вариантов. При переводе Каллисто на Си предстоит принять ряд решений, исходя из ограничений целевой платформы по объёмам памяти и быстродействию. Также не забывайте, что по ходу дела придётся реализовывать на Си клавиатуру, шрифты, блочную внешнюю память для хранения исходников и файлы сохранения каллистянских сеансов. Как полная совместимость, так и конкуренция с МК-161 также потребуют энергонезависимой памяти, часов и таймера, библиотек для рисования линий и пищания спикером, для поддержки последовательного порта и остального, что в ЭКВМ «из коробки» и на что Каллисто опирается.

Код Каллисто защищён авторским правом и лицензирован под GNU GPL. Хотя ваш труд может быть оплачен в App Store и других магазинах, его результат должен оставаться свободной программой, с открытыми исходниками — чтобы другие программисты также могли им воспользоваться, внося свой вклад в дорогую всем нам отечественную архитектуру.

1. Единое адресное пространство

В Каллисто 1.0 разрозненные адресные пространства «Электроники МК-161» (память программ и регистры данных) объединены в единое адресное пространство со сквозной нумерацией. Адреса шагов программы оставлены без изменений, а к номерам регистров прибавляется 10000.

Это решение, вызванное желанием совместимости с Фортом, где память линейна и однородна, оказалось неудачным для МК-161 и пересматривается в Каллисто-2. Зато оно облегчает перенос Каллисто на Си. В сишной версии единое адресное пространство проще всего сделать единым массивом типа unsigned char (байт, целые от 0 до 255) размером в 18168 байт (10000 память программ + 1000 десятичных регистров + 4Кб двоичных регистров + 3Кб текста).

При каждом обращении к памяти Каллисто совершает проверку и преобразование адреса. Это необходимо, так как для чтения из памяти программ и для доступа к регистрам на МК-161 используются разные команды. Такие накладные расходы и делают данный приём не самым удачным на медленных машинах. Можно либо буквально переводить эти проверки на Си, либо немного подумать и избавиться от них.

Не получится избежать проверки обращения к десятичным регистрам R0-R999 с едиными адресами от 10000 до 10999 — в них находится, в том числе, стек данных. Эту тысячу регистров придётся разместить в отдельном 8000-байтном массиве, по 8 байт на регистр. Можно сэкономить 1000 байт, соответствующую этим адресам, продолжив отделять память программ от памяти данных и сохранив все проверки — тогда память программ (адреса от 0 до 9999) имеет смысл разместить в ПЗУ, а байтовые регистры в ОЗУ (адреса от 11000 до 18167).

Какие регистры функций МК-161 реализовать (адреса 19000-19999) и насколько их сделать совместимыми с ЭКВМ, зависит от щедрости разработчика.

После успешного перевода сишный диалект Каллисто можно улучшить, в несколько раз расширив память, доступную получившемуся ПМК — адреса 18168-18999, а также 20000-65535 на МК-161 не используются. Эти области памяти можно использовать для целевой компиляции (англ.). Со временем Си можно будет отбросить, как строительные леса, и этот путь может оказаться короче, чем выбранный мною через SP-Forth.

2. Примитивы и адресный интерпретатор

Средствами Каллисто 1.0 невозможно написать примитив. Эти ошмётки гарвардской архитектуры (на МК-161 память программ, откуда выполняется код примитива, доступна только для чтения), как ни странно, оказались главным, что изменило моё мнение насчёт возможности Каллисто на Си.

Примитивы могут быть реализованы функциями на языке Си. Это приведёт к изменению адресного интерпретатора, который из-за объединения адресных пространств в едином массиве станет больше напоминать адресный интерпретатор Каллисто-2. В нём пропадут разные точки входа для памяти программ и данных (NEXTP и NEXTD), в обработчике CALL исчезнут хитрые косвенные вызовы через регистр C (RPUSHRIP и RPUSHRID). С этой точки зрения адресный интерпретатор упростится. С другой стороны, ему придётся вместо передачи управления на обработчики вызывать функции, которые обязаны в этот же адресный интерпретатор возвращаться. Именно это направление развития выбрано для Каллисто-2, где косвенный шитый код будет сосуществовать с подпрограммным.

Сомневаюсь, что в архитектуре ARM два байта смогут полноценно адресовать функцию. При необходимости должен быть предусмотрен отдельный массив свёрток, преобразующий содержимое поля кода в адрес функции-обработчика. Есть и более производительные альтернативы — многостраничный оператор выбора (switch, арифметический goto) или даже переход (goto) относительно адреса первого примитива на 16-битное смещение, записанное в поле кода (приводит к уязвимости из «песочницы»). Эти две альтернативы дадут экономию на дорогих вызовах сишных функций.

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

Скорее всего адресный интерпретатор на Си окажется быстрее, чем его аналог на языке МК. При желании его можно ускорить, закодировав на ассемблере как сам интерпретатор, так и вызываемые им примитивы. Ну и постепенно двигая исходник к тому, как обычно пишутся Форты.

3. Возможная архитектура

Как бы я перевёл Каллисто на Си? Сперва массиву единой памяти надо подобрать имя и инициализировать магическим числом, например:

unsigned char Mem[18168] = "Magic123";

Эта «песочница» будет содержать часть транслятора, доступную для чтения средствами самого языка — словарь и шитый код (Callisto.mkp). В идеале сразу после компиляции Callisto.c в двоичном образе можно обнаружить участок памяти в 18168 байт, начинающийся с "Magic123". Легко разработать инструмент, который засовывает Callisto.mkp в эту часть двоичного образа, завершая сборку транслятора. Как альтернатива, можно преобразовывать Callisto.mkp в текст на Си, инициализирующий массив, и включать этот автоматически генерируемый исходник #include’ом.

Callisto.mkp из дистрибутива Каллисто 1.0 не подойдёт, хотя для подготовки сишной версии можно использовать новосибирские инструменты и «похудевший» исходный текст Callisto.mkl, из которого должны быть выкинуты все «потроха» на языке МК — исполнять код МК всё равно некому. Зато в полях кода теперь должны быть специальные значения, по которым адресный интерпретатор Callisto.c будет находить и исполнять нужный обработчик примитива. Драйвер клавиатуры с таблицами придётся перевести с языка МК на Си, как и вывод литер CHPUT. Всё остальное, включая высокоуровневый шитый код, можно будет повторно использовать из проекта для МК-161.

Похожая схема используется в 161eForth, где таблица констант в исходнике на SP-Forth позволяет выполнять примитивы, определённые в исходнике на языке МК. Здесь, правда, обратная ситуация. Исходник на «расширенном языке МК» в отсутствии «Электроники МК-161» вынужден ссылаться на функции, определённые в Callisto.c.

4. Почему Каллисто

Использованный в МК-85/90 Бейсик хорош тем, что широко известен и дружелюбен к начинающим. В нём неплохая математика, уровня Фортрана. Увы, он слишком многословен, так как не был рассчитан на карманные устройства. К Бейсику идеальна полноразмерная клавиатура и дисплей на 24 строки — который отображает подпрограмму целиком. Но это ещё не вся беда.

Программы на Бейсике пишутся одними и теми же операторами. Даже написав несколько сот строчек кода программист продолжает формулировать решение в тех же унылых терминах IF, INPUT, PRINT, FOR, GOSUB, SQRT, LINE, CIRCLE, RUN и т.п. Как и отечественная «Электроника МК-161», этот иностранный входной язык закрыт, словарный запас ограничен, правила жёстко зафиксированы производителем. Программист не может упростить себе работу, несмотря на затраченный труд.

Каллисто поощряет творчество и общение. Она унаследовала от Форта возможность совершенствования языка по мере написания приложения. Обнаружив типовые задачи, выполняемые в полевых условиях, можно их автоматизировать и придумать решениям удобные, полноправные имена-команды. Ваши новые команды могут быть короткими, простыми для быстрого ввода «на весу» с клавиатуры ПМК. Могут быть длинными, указывающими на выполняемую задачу. Удачные нововведения заимствуются в другие проекты. Простые строительные блоки объединяются в более мощные конструкции, обогащая словарный запас ПМК и простоту решения новых задач.

Каждый настраивает Каллисто под себя и свою задачу, вплоть до написания проблемно-ориентированного языка (DSL). Например, можно заимствовать из того же словарного запаса Бейсика, если именно он вам удобен и понравился — в каллистянских примерах я реализовал и использовал музыкальный макроязык на основе полюбившегося PLAY. Запала в сердце графическая библиотека Турбо Паскаля? И её можно реализовать. Все новые слова занимают то же место в языке, что и старые. Используются наравне с IF FOR + SIN TYPE CREATE, это завораживает.

Конечно, не каждый владелец ПМК способен самостоятельно разработать невиданные ранее структуры управления, да и вообще захочет заниматься системным программированием. Но мы живём в век Интернета. Если владельцу приглянулся оператор CASE, сопрограммы или любое другое расширение языка (для Форта чего только не придумано), его можно скопировать в свою версию Каллисто и начать использовать на своём ПМК. Даже без расширений язык хорош, прямо «из коробки» вобрав в себя лучшее из Форта и наших любимых советских ПМК. Всем будет интересно наблюдать эволюцию Каллисто. Ещё интересней участие в ней.

Надеюсь, что сишная версия, если будет написана, послужит популярности Каллисто и за пределами новосибирской платформы. Возможно, такой подход поможет создать каллистянские математические библиотеки (СКМ), а также создаст конкуренцию и приблизит реализацию Каллисто на машинном языке W77LE516P/W77LE516F — процессора МК-161.

EDIT. Работа Вики восстановлена, ссылки работают. Вот ещё одна: «Начальная загрузка Каллисто». Важную информацию советую копировать к себе, на всякий пожарный.