Каллисто-2: разработка быстродействующего Форта для МК-161

Каллисто-2 будет написана на SP-Forth! Подробнее см. соответствующую тему В Контакте.

Кусочек исходного кода — чтобы было понятно, как это сейчас выглядит:

0xD0 COP КИП0  0xD1 COP КИП1    0xD2 COP КИП2    0xD3 COP КИП3   0xD4 COP КИП4  0xD5 COP КИП5  0xD6 COP КИП6  0xD7 COP КИП7
0xD8 COP КИП8  0xD9 COP КИП9    0xDA COP КИПА    0xDB COP КИПВ   0xDC COP КИПС  0xDD COP КИПД  0xDE COP КИПЕ  0xDF 2OP РКИП
0xE0 COP Кx=00 0xE1 COP Кx=01   0xE2 COP Кx=02   0xE3 COP Кx=03  0xE4 COP Кx=04 0xE5 COP Кx=05 0xE6 COP Кx=06 0xE7 COP Кx=07
0xE8 COP Кx=08 0xE9 COP Кx=09   0xEA COP Кx=0А   0xEB COP Кx=0В  0xEC COP Кx=0С 0xED COP Кx=0Д 0xEE COP Кx=0Е 0xEF 2OP РКx=0

0xF2 COP РРВ/О
0xF4 3OP РРП
0xF6 3OP РРИП

\ -------------------------
\ Исходный код Каллисто-2

\ Инициализация
Cx
9 5 0 0 РРП 9042    \ Адрес таблицы свёрток
1 0 9 9 П6          \ RI := Начало шитого кода - 1
1 6 П9              \ Занесём в R9 адрес NEXT

A: NEXT
КИП6 ВП 2 КИП6 + П7 \ W := REGW[RI++], считываем CFA в R7
КИП7 РРП 9210       \ Находим по CFA адрес обработчика
П8 КБП8             \ Передаём на него управление

ORG 100             \ Обработчик 000
2 РРП 9010          \ Инициализация графического экрана
1 2 8               \ Код буквы "А"
РРП 9020            \ Вывод символа на графический экран
КГРФ                \ Обновляем индикатор
КБП9                \ NEXT

ORG 200             \ Обработчик 001
РРИП 9029           \ Чтение кода нажатой клавиши
КNOT                \ Проверка на 255
Fx≠0 00             \ Дождёмся чего-нибудь, отличного от 255
КБП9                \ NEXT

Полностью исходный код + результат качать отсюда: http://the-hacker.ru/2016/Callisto2-d4.zip

Черновик 4 выводит на экран букву, ждёт нажатия клавиши и выходит по С/П. Работает NEXT (адресный интерпретатор), но пока нет ни меток, ни имён слов. Использование SP Forth позволяет не только избежать ручной компиляции кода МК-161, но также автоматизировать множество вещей, которые в Каллисто Классик, написанной на MK.EXE, приходилось делать вручную.

Каллисто-2, черновик 5: http://the-hacker.ru/2016/Callisto2-d5.zip

Теперь шитый код генерируется SP-Forth, в полном соответствии с требованиями нового адресного интерпретатора. «Ассемблер» ЯМК вынесен в отдельный список слов. Определения примитивов выглядят весьма красиво:

code w1               \ === Обработчик 000 ===
  2 РРП 9010          \ Инициализация графического экрана
  1 2 9               \ Код буквы "Б"
  РРП 9020            \ Вывод символа на графический экран
  КГРФ                \ Обновляем индикатор
  КБП9                \ NEXT
end-code

Каллисто-2, черновик 6: http://the-hacker.ru/2016/Callisto-d6.zip

Заработали определения высокого уровня, то есть стек возвратов и CALL/EXIT. Производительность не мерил, но должно работать ощутимо быстрей Каллисто Классик.

Также добавлены циклы begin/until и begin/again для примитивов — слов на языке МК-161. Этот типично фортовский приём позволяет обходиться без меток в БП и условных переходах назад.

Каллисто-2, черновик 7: http://the-hacker.ru/2016/Callisto2-d7.zip

Начал писать терминал. Теперь после запуска Каллисто-2 выводит на индикатор нажимаемые клавиши. Раскладка примерно соответствует цифровой клавиатуре Каллисто Классик и пока не переключается в русский и латинский режимы.

На этот раз я не спешу и делаю всё, как надо. Ввод реализован с помощью прерываний. Вводимые литеры ставятся в очередь длиной 8 литер. Реализован автоповтор, впервые на «Электронике МК-161».

В метаязыке произошёл переход от 2 РРП 9010 к каллистянскому 2 9010 РРП — есть и другие изменения, которые позволят написать такую крупную программу, как транслятор Каллисто-2.

Каллисто-2, черновик 8: http://the-hacker.ru/2017/Callisto2-d8.zip

Внешне изменений нет — Каллисто-2 отображает нажатые клавиши, как и раньше. Внутри существенные изменения. Например, появился стек данных. Вершина стека теперь всегда хранится в регистре C.

Во многих реализациях Форта подобный трюк повышает быстродействие. В нашем случае выгода не очевидна. Я довольно долго размышлял над этим решением. Что-то станет работать чуть быстрей, что-то чуть медленней. Будет возможность сравнить.

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

code dup ИПС КП3 КБП9 end-code
code 1+ 1 ИПС + ПС КБП9 end-code
code 2+ 2 ИПС + ПС КБП9 end-code
code 10ˣ ИПС F10ˣ ПС КБП9 end-code
code eˣ ИПС Feˣ ПС КБП9 end-code
code lg ИПС Flg ПС КБП9 end-code
code ln ИПС Fln ПС КБП9 end-code
code x² ИПС Fx² ПС КБП9 end-code
code √ ИПС F√ ПС КБП9 end-code

Команды ИП П БП ПП и несколько других стали «умными». Зная, к какому регистру или шагу происходит обращение, они сами выбирают нужный код операции — либо двухшаговой/внутристраничной, либо трёхшаговой/межстраничной команды.

Например РРИП 9000 теперь записывается в ассемблере, как 9000 ИП — ровно также, как в Каллисто. Переходы также стали использовать обратную польскую нотацию. Сперва пишем, куда. Потом пишем БП или Fx=0

При компиляции Каллисто-2 SP Forth выдаёт предупреждения о переопределении ряда слов. Это нормально. В конце-концов, мы и заняты определением слов Каллисто на Форте. Арифметические и другие операции получают новое определение.

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

Каллисто-2, черновик 9:
http://the-hacker.ru/2017/Callisto2-d9.zip

Как я уже писал в Контакте, верхние два элемента стека данных Каллисто теперь совпадают с регистрами стека X и Y. Поэтому многие примитивы упрощаются до предела, например:

code 1+ 1 + next; 
code 2+ 2 + next; 
code + + jdrop2 БП; 
code - - jdrop2 БП; 
code × × jdrop2 БП; 
code ÷ ÷ jdrop2 БП; 
code / ÷ К[x] jdrop2 БП;
code min Кmax ↔ jdrop2 БП; 
code max Кmax jdrop2 БП; 
code 10ˣ F10ˣ next; 
code eˣ Feˣ next; 
code lg Flg next; 
code ln Fln next; 
code x² Fx² next; 
code √ F√ next; 
code 1/x F1/x next; 

Также Каллисто-2 теперь состоит из трёх файлов (mkp, mkb и mkd) — все три надо передать в МК-161 или эмулятор, чтобы проверить работоспособность. В файле десятичных данных пока передаются лишь два десятичных регистра (R9 и R16), но это только начало. Больше размер исполняемого кода увеличиваться не будет, ибо уже некуда. Но с тремя файлами придётся смириться. Лучше их сохранять на внутренний диск под одним именем. Тогда они образуют «пакет» и загружать транслятор становится проще и быстрее.

Каллисто-2 (черновик 9) сперва выводит на экран приглашение, символ "@", после чего отображает по символу на каждую нажатую клавишу.

Брать здесь:
http://the-hacker.ru/2017/Callisto2-d10.zip

Клавиатура становится серьёзней — в Каллисто-2 заработал цифровой режим. Теперь кнопка "3" даёт литеру "3", а последовательное нажатие кнопок "F 3" даёт литеру "#". Разумеется, это совместимо с автоповтором и очередью клавиатуры, важными нововведениями Каллисто-2. Нажав кнопку "F" и удерживая кнопку "3", мы получим автоповтор литеры "#".

Раскладка практически повторяет Каллисто Классик. Небольшие отличия вызваны лучшей продуманностью второй реализации алфавитно-цифровой клавиатуры для «Электроники МК-161». Например, "П" даёт "!", а "F П" даёт "?" — это освободило кнопку "К" для будущих применений.

Литера "|" теперь вводится "F В↑", а литера "↵" переехала на "F ВВОД". Клавиши выбора сейчас дают свои «старшие» коды, а «младшие» коды получаются при использовании префикса "F".

Пока в качестве префиксной клавиши "F" можно использовать любую другую спецкнопку — РУС/ЛАТ и т.п. Но это ненадолго, алфавитные режимы на подходе. Тестовое приложение осталось нетронутым. Хотя драйвер клавиатуры выдаёт правильные коды "Cx" и "F Cx", для редактирования строки их пока никто не использует.

Напомню, что для запуска Каллисто-2 в «Электронику» надо передать три файла — mkp, mkb и mkd.

Каллисто-2, черновик 11: http://the-hacker.ru/2017/Callisto2-d11.zip

Тестовая программа теперь выводит приглашение ">", в остальном без изменений. Зато драйвер клавиатуры завершён. В-основном он повторяет клавиатуру Каллисто Классик, но удалось воплотить две мои древние задумки. В цифровом режиме клавиша "K" работает, как Control — например "K S" вводит ^S, управляющий символ с кодом 19 и графическим изображением «знак паузы».

Также в цифровом режиме комбинация префиксных клавиш "F K" позволяет ввести любой символ по его шестнадцатеричному коду. Например, "F K 1 3" это ещё один способ ввести тот же самый «знак паузы». Клавиши выбора (и они же с клавишей "F") в цифровом и латинском режимах дают одинаковые служебные коды. Это позволит использовать их, например, для перемещения курсора.

Чтобы реализовать всё это богатство, в ассемблере МК-161 введены метки с возможностью ссылок вперёд. Подробней я объяснял эту тему в Контакте. Над метками я ещё немного поработаю напильником, но они уже вполне работоспособны.

Каллисто-2, черновик 13: http://the-hacker.ru/2018/Callisto2-d13.zip

Благодаря поддержке русских фортеров начал переход к ALSO/ONLY, пока на уровне исходного кода. Слова кросс-компилятора теперь растасованы по спискам/словарям. Реализованные примитивы получили картинку стека. Добавлено несколько новых слов. Одно из них, слово TYPE , выводит титульную строку перед приглашением, с номером версии черновика.

Но для юзера изменений мало. По прежнему нажимаемые клавиши выводятся на индикатор, ничего нового. Напоминаю, что для запуска Каллисто-2 надо передать на МК-161 весь пакет полностью, а не только MKP. Компилируется Каллисто-2 с помощь SP-Forth 4.20

Фрагмент исходного кода. После code идёт каллистянское имя, после скобок реализация на языке ПМК:

\ Арифметика
code 1+  ( x -- x+1 )    1 +  next;
code 1-  ( x -- x-1 )    1 -  next;
code 2+  ( x -- x+2 )    2 +  next;
code 2-  ( x -- x-2 )    2 -  next;
code 2×  ( x -- x×2 )    В↑ +  next;
code 2/  ( x -- x/2 )    2 ÷ К[x]  next;
code +   ( y x -- y+x )  +  jdrop2 БП;
code -   ( y x -- y-x )  -  jdrop2 БП;
code ×   ( y x -- y×x )  ×  jdrop2 БП;
code ÷   ( y x -- y÷x )  ÷  jdrop2 БП;
code /   ( y x -- y/x )  ÷ К[x]  jdrop2 БП;

Каллисто-2, черновик 14: http://the-hacker.ru/2018/Callisto2-d14.zip

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

С точки зрения юзера вводимые клавиши выводятся на индикатор, как раньше. Зато теперь куда больше управляющих символов поддерживается. В режиме NUM комбинация ^L (K–) очищает экран, ^J (K8) переходит на строчку вниз, ^G (K БП) звонок и т.д.

В том же режиме NUM работает FK и две цифры шестнадцатеричного кода символа. Буквы A, B, C, D, E и F это кнопки ШГ влево, В/О, С/П, K, ИП и П — они такие же в режиме ЛАТ. Надо лишь помнить, что С/П я пока не отключал и при нажатии на эту кнопку МК-161 перестаёт выполнять черновик.

Кнопка Выход (она же К стрелка влево) завершает выполнение программы. И да, добавил GPL в архив.

Каллисто-2, черновик 15: http://the-hacker.ru/2018/Callisto2-d15.zip

Сегодня задышал новый ACCEPT

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

ACCEPT будет работать через вспомогательное слово (ACCEPT) — которое позволяет редактировать заготовку строки. Это большой шаг к улучшению редактора экранов Каллисто. В Каллисто Классик редактировать экраны на борту было можно, но во входящем в комплект редакторе (другого никто не написал) при любом изменении строки приходилось набивать её заново. Теперь (ACCEPT) позволит вносить нужные изменения с клавиатуры ЭКВМ, не перебивая строку целиком.

В ближайших планах сделать комбинации клавиш для уборки строки в карман (F ↓) и вставки её оттуда (F↑) — как в Лексиконе. Карман отнимет 92 байта драгоценной байтовой памяти, но должен добавить удобств при разработке приложений на борту МК-161.

Каллисто-2, черновик 16: http://the-hacker.ru/2018/Callisto2-d16.zip

Часть ненужного кода закомментировал. Исправил ряд ошибок и провёл первую оптимизацию ACCEPT

Удалось избавиться от R20, весь ACCEPT аккуратно уложился в традиционные советские регистры. Ещё остался баг — при перемещении курсора в конец строки иногда он появляется не там, где нужно. Клавиша «влево» возвращает курсор на место.

Интересно, что пришлось реализовать уникальную языковую конструкцию tails … then для хвостовой рекурсии. Пример использования см. в AccCTL. Но это в языке ПМК. Не факт, что она войдёт в Каллисто.

Каллисто-2, черновик 17: http://the-hacker.ru/2018/Callisto2-d17.zip

Исправление ошибок и оптимизация ACCEPT

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

Каллисто-2, черновик 18: http://the-hacker.ru/2018/Callisto2-d18.zip

Заработал ACCEPT — полностью. Теперь буду оптимизировать, но почти все задумки и хотелки реализованы. Клавиши редактирования строки:
← → Переместить курсор на одну позицию влево / вправо
F← F→ Переместить курсор в начало / конец строки
↑ ↓ Переместить курсор на 8 позиций влево / вправо
Сх (BS) Удалить литеру слева от курсора
F Сх (F BS) Удалить все литеры справа от курсора
F ↓ Очистить строку, забрав её в карман
F ↑ Вставить карман в текущую позицию курсора
ВВОД Завершает редактирование строки

Клавиши редактирования можно комбинировать. Например, F← F Сх удалит всю входную строку, не меняя содержимое кармана.

Карман сохраняется между вызовами ACCEPT и хранит не только литеры, но и позицию курсора. Туда, например, можно занести длинное слово и вставить его несколько раз. Если вам нужно продолжить редактирование строки после её сохранения в карман, используйте комбинацию F↓ F↑

Ну и несколько советов по клавиатуре. «Стрелки» не работают в русском режиме, на них «висят» русские буквы. Если надо ввести в строку сами «стрелки», нажмите перед ними в режиме NUM кнопку K. Например, литера ↑ вводится комбинацией K↑

Также напоминаю, что кнопка С/П останавливает программу.

Черновик 18 — значительный прогресс в сравнении с Каллисто Классик, где помимо клавиши ВВОД было всего две клавиши редактирования — удалить последний введённый символ (Cx) и очистить всю строку (F Cx).

Каллисто-2, черновик 20: http://the-hacker.ru/2018/Callisto2-d20.zip

Представляю одно из главных нововведений Каллисто-2 — хэш-функцию. Черновик 20 вводит строку с клавиатуры, потом выводит на индикатор её и её хэш.

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

  1. Большие и малые буквы не отличаются ни в русском, ни в английском алфавитах. У имён TRUE , True и true хэш одинаков: 56118436.
  2. Хэшируются только три буквы имени — первые два символа и один последний.
  3. Хэш-функция учитывает длину имени. Поэтому АБВГ и АБГ имеют разные хэши 4708 и 4707, несмотря на одинаковые символы в начале и конце.

AtH wrote: Хэш-функция учитывает длину имени. Поэтому АБВГ и АБГ имеют разные хэши 4708 и 4707, несмотря на одинаковые символы в начале и конце.

АБВГ и АББГ будут иметь одинаковый хэш?

---------------------------
Истина где-то рядом
www.litres.ru/vitaliy-samurov/dozvonitsya-do-devy/

Да. Если два имени имеют одинаковую длину, их первые два символа и последний совпадают — хэш-функция даст одинаковые значения. Такова цена быстродействия.

Тем не менее, это существенно лучше MSX BASIC’а, где переменные различались по первым двум символам. Там AB1 и AB2 обращались к одной переменной AB, в Каллисто-2 это три разных слова.

Каллисто-2, черновик 21: http://the-hacker.ru/2018/Callisto2-d21.zip

80 уже реализованных примитивов получили свои «десятичные заголовки», записанные в регистрах ЭКВМ с номерами 100-179. Это важный шаг по направлению к альфа-версии Каллисто-2. Для сравнения — в Каллисто Классик 298 слов.

Два 4-значных числа перед #code это хэш имени, рассчитанный словом HASH на «железной» МК-161. При программировании «на борту» эти хэши МК-161 будет вычислять самостоятельно и незаметно для владельца. Хочется ещё раз поблагодарить разработчиков «Электроники МК-161». Разрабатывать и отлаживать Каллисто, пользуясь настоящим физическим калькулятором — одно удовольствие. Прямо чувствуешь, как на глазах зарождается ПМК мечты.

Поле CFA и соответствующая ему свёртка с адресом обработчика (ещё одно know how Каллисто-2) генерируются автоматически. На прежнем уровне технологий, когда Каллисто писалась на MK.EXE, такие автоматические вычисления во время компиляции транслятора были бы невозможны. Поэтому второе спасибо — разработчикам СПФ.

\ Арифметика
0022 7170 #code 1+  ( x -- x+1 )    1 +   next;
0022 7234 #code 1-  ( x -- x-1 )    1 -   next;
0023 1778 #code 2+  ( x -- x+2 )    2 +   next;
0023 1842 #code 2-  ( x -- x-2 )    2 -   next;
0023 3570 #code 2×  ( x -- x×2 )    В↑ +  next;
0023 1906 #code 2/  ( x -- x/2 )    2 ÷ К[x]  next;
…

\ Примитивы МК-161
0000 4161 #code √    ( p -- x )    F√    next;
0035 2706 #code LN   ( p -- x )    Fln   next;
0035 2482 #code LG   ( p -- x )    Flg   next;
0040 8994 #code X²   ( x -- p )    Fx²   next;
0032 1474 #code Eˣ   ( x -- p )    Feˣ   next;
3273 8755 #code 10ˣ  ( x -- p )    F10ˣ  next;
9330 7267 #code |X|  ( x -- p )    К|x|  next;

Посмотрел, спасибо. На TI-84+ доступен ассемблер, что упростило задачу. Мой первый Форт тоже где-то в таком возрасте был написан.

В целом же проект менее серьёзен. Нет плавучки и собственно калькулятора, вокруг которого построена Каллисто. Документация не завершена. Поддержки русского языка нет и вряд ли будет. Входная строка чуть лучше Каллисто Классик, но похуже Каллисто-2. Редактор экранный, но пока не разбивает редактируемый текст на строки.

Каллисто решила две большие вещи. Совместимость «снизу вверх» с языком МК-61, а также выход из «песочницы» МК-161. Для большинства приложений, где быстродействие не критично, разработчикам будет достаточно Каллисто.

Форт для TI-84+ предоставляет быстродействующую, но целочисленную замену TI-BASIC.