Слышали о семействе советских троичных ЭВМ «Сетунь»? А в политехническом музее бывали, машины видели? Нет? Да? Тогда вот вам эмулятор «Сетуни 70», чтобы посмотреть что к чему, разобраться и написать для нее свою программу.
Введение
Существующие публикации по теме семейства троичных ЭВМ «Сетунь» не отличаются информативностью и точностью, в целом дают только общее представление и по сути просто сообщают о том что такие машины были, не предоставляя никаких технических деталей. Что достаточно странно, поскольку в советские времена и в наше время авторами, конструкторами и пользователями «Сетуни» было напечатано достаточно много публикаций, напечатано с десяток книг. Были даже учебные материалы по ее программированию и применению этой машины для самых разных целей - от вычислений и обработки научных материалов до интерпретирующих программ и даже среды обучения программированию.
Есть весьма любопытные статьи, например, о реализации системы команд «Сетуни 70» на предыдущей модели «Сетуни» - 1959 года. Вам не слабо на машине всего с 81 восемнадцатиразрядным словом оперативной памяти, без ПЗУ и ОС, написать эмулятор системы команд куда более сложной и развитой архитектуры, в которой даже просто памяти почти в 20 раз больше? А они - справились! Причем без всяких многомегабайтовых прошивок, хитроумных сред программирования и невесть что оптимизирующих компиляторов.
Краткая предыстория появления эмулятора
Работа над эмулятором «Сетуни 70» идет давно: началась еще в 2001-м году, и последовательно велась на разных языка программирования с разным успехом из-за ограничений в знаниях архитектуры эмулируемой машины; недостатков, ограничений и синтаксиса языков. Некоторые из ограничений обходились легко, некоторые поддавались не просто. Скажем, в большинстве языков отсутствуют массивы с отрицательными индексами, из-за чего приходилось использовать смещения и городить проверки, в результате плодя ошибки и теряя львиную часть времени работы эмулятора впустую, попутно постоянно переводя смещения в адреса и обратно.
Зачем там отрицательные индексы? Машина ведь использует уравновешенную (симметричную) троичную систему счисления с цифрами {-1, 0, +1). Один разряд здесь называется трит. И хочешь не хочешь, таким способом представлены и выражены все параметры машины. Да вот хоть бы номера страниц памяти и номера слов в них пронумерованы от -13 до +13, а номера коротких ячеек от -40 до +40. Значение в 6-тритном трайте (это т.н. слог 18-разрядного троичного слова) представлено в диапазоне от -384 до +384. Ну а диапазон значений 18-разрядного троичного слова посчитайте сами.
Последовательность реализации и набор языков были следующими:
Ява,
Паскаль,
Си,
Си++
Ассемблер,
Хаскель,
Эльм,
Идрис,
Снова Си++,
И, наконец, дело пришло к Раст вместе с ИИ.
Одним из критериев было стремление уложиться в 2 тысячи строк кода, который, однако так ни разу и не был достигнут. В разное время выбор конкретного языка был продиктован желанием опробовать возможности языка в этой области. Самыми удобными в реализации оказались как ни странно Хаскель и Эльм, а самым простым и наглядным оказался Ассемблер.
Не подумайте что все это время я с утра до вечера только этим и занимался. Нет, у меня и другие дела есть, а к этой задаче я возвращался время от времени с перерывами в несколько месяцев и даже лет по мере пополнения знаний об архитектуре.
Трудности эмуляции недвоичных машин
Кроме синтаксиса, индексов и производительности есть еще хитроумная и не всеми осознаваемая логическая ловушка под названием «Эффективность представления» - своеобразная когнитивная деформация проявляющаяся у всех, кто считает двоичную систему счисления главной и «эталонной», пытаясь через нее выразить все остальные, не дав себе труда подумать об иных вариантах.
Если вы интересовались вопросом представления чисел в уравновешенной троичной системе счисления, то скорее всего знаете про два наиболее часто встречающихся варианта: «пара бит на один трит» и «знаковые слои» (что в принципе сводится к той же паре бит на один трит, но уже при иной организации). Думаю не ошибусь, сказав что все, кто задумывался об этом вопросе, рано или поздно к ним приходили. Можно легко впасть в ошибку и думать, - «Это же на 50% менее эффективное представление чем прямой двоичное!». Кажется что как ни крути, все остальные варианты еще менее эффективны. Но это ведь только если не думать об отрицательных числах (+1 разряд или еще больше), устойчивости к ошибкам (ну тут может быть и 1:1 с троичным), об округлении и обо всем остальном.
А если подумать, то оказывается что... больше бит на троичный разряд это вовсе не недостаток, а правильное и неизбежное направление. Дам несколько подсказок, а решение которое устроило по всем критериям, будет описано дальше.
Подсказка 1. Думать надо не о том как как хранить каждый разряд, а о том, зачем вам надо его хранить. Если посмотрите на программы, обрабатывающие какие-нибудь данные, то можно заметить что они как ни странно всего-то и делают что читают, модифицируют и куда-то записывают (заменяя или дополняя исходные) числа в заранее определенном диапазоне. Причем чтобы вы ни делали, вы никогда не сможете изменить заданного архитектурой машины диапазона или способа представления числа.
Подсказка 2. Сколько бы раз вы ни считали 2+2, то в любой целочисленной системе вы гарантированно получите 4. Каждый раз. Единственное полезное что вы можете получить в результате непрестанного счета 2+2 - поймать сбой питания, памяти, процессора или шины. Только зачем?
Подсказка 3. Считав откуда-то байт и сложив его с другим байтом, вы через какое-то время легко получите результат по значению превосходящий 8 двоичных разрядов, а записать его на место одного байта вы уже не сможете - либо потеряете часть данных, либо потребуется записать второй байт еще куда-то. Половину или полтора байта на место одного не запишете, он не никуда подвинется, не расширится и не сузится.
Подсказка 4. К сожалению, современный нам окружающий цифровой мир почти полностью двоичный, и в нашем случае всегда потребуется переводить двоичные цифры в троичные и наоборот.
Подсказка 5. Если вы думаете что один объявленный байт в структуре вашего кода после компиляции так и остается одним байтом в памяти при выполнении программы, то вы живете в мире фантазий - на самом деле один байт превращается в памяти в десятки, а иногда и в сотни байт.
Подсказка 6. Результат надо показывать человеку в каком-то понятном ему виде, часто это цифры или буквы. Результат работы любой программы всегда предназначен для человека. Возможно только в конце длинной цепочки, но происходит и об этом очень важно помнить.
Краткое описание архитектуры машины
ЭВМ «Сетунь 70» - это достаточно элегантная и простая по устройству стековая машина, но с нетипичной архитектурой. По крайней мере мне неизвестны похожие примеры работы с памятью.
Кроме того что машина хранит и обрабатывает данные в уравновешенном троичном коде стоит знать следующие особенности.
Память первого уровня
Оперативная и постоянная память машины невелики, всего 27 страниц по двадцать семь 18-разрядных слов. То есть всего-то 729 слов.
Из этих 27 страниц всего девять страниц отведены под оперативную память. Остальное это ПЗУ, куда записаны тесты, служебные подпрограммы и реализация макрокоманд (подробности ниже). То есть программно поменять мы можем всего 243 слова из имеющихся 729.
Интересно что страницы ОЗУ пронумерованы от -4 до +4, т.е. «сгруппированы» вокруг нуля, и сверху и снизу «окружены» страницами ПЗУ.
Одна из страниц ОЗУ отведена под стек процессора.
И это вся память. Не спешите падать духом и махать руками, лучше рассматривайте это как аналог кеш-памяти более-менее современного процессора, чем оно в принципе по современным представлениям и является.
В исходной архитектуре «Сетуни 70» уже заложена возможность увеличения числа страниц таким образом, что не придется переписывать старые программы. В наборе регистров есть три т.н. «регистра приписки», которые всегда указывают при выборке данных из страницы памяти в стек. Вместе с увеличением их разрядности увеличится и число адресуемых страниц.
Память второго уровня
Кроме оперативной памяти к машине может быть подключено два магнитных барабана, каждый емкостью около 19,5 мегатрайт (здесь "мега" надо читать по-человечески, по снованию 10). Вот ее-то и использует машина в качестве оперативной. В ней даже есть команды обмена целыми страницами первого уровня с магнитным барабаном. Что, кстати, для машин того времени это более-менее обычный подход.
Система прерываний
Среди прочего у машины есть схема определение ситуаций исчерпания и переполнения страниц памяти, по наступлению которых сохраняется контекст и вызывается подпрограмма обработки из ПЗУ. Причем в разных режимах вызываются разные обработчики. Например, если при последовательном выполнении кода пользовательской программы вы достигли конца страницы и произошла попытка считать данные за пределами страницы, то произойдет вызов обработчика из ПЗУ. Если в режиме макооопераций произойдет попытка выполнения еще одной макрооперации, то снова произойдет прерывание с переходом к обработчику.
Система команд
В составе системы команд есть т.н. слог-ссылка и еще 81 команда. Двадцать семи из них это макрокоманды которые реализуются программно, хранятся и вызываются из ПЗУ.
Слог-ссылка
Это операция копирования содержимого слова или части слова (6-тритных слогов) из страницы памяти в стек данных. Своего рода аналог команды Push какого-нибудь современного процессора.
Базовые команды
Набор из 27 команд работы с данными и стеком - арифметика, вращения, пересылка и т.д.
Системные команды
Включает в себя 27 команд загрузки данных в некоторые управляющие регистры, обращение к внешним устройствам и т.д.
Макрооперации или макрокоманды
Тоже 27 штук. Собственно, их реализация была записана в сменных страницах ПЗУ машины и выполнялась процессором при переходе в особый макро-режим. Предполагалось что при необходимости их можно сменить заменой плат соответствующих страниц памяти в машине и получить новый проблемно-ориентированный набор для выполнения специализированной задачи.
И как это работало?
Кажется что загружаемая программа, кроме самых простейших, выполняла роль диспетчера последовательности загрузки данных и кода с магнитного барабана и вызова системных обработчиков событий и сервисов операционной системы (ага, она там тоже была! - так и называлась «Операционная Система»).
А ведь на «Сетуни 70» были очень серьезные длинные программы (средства разработки, текстовый редактор, ассемблер, средства поддержки психофизического эксперимента, автоматизированная система обучения «Наставник» - обучала студентов МГУ иностранному языку и языкам программирования, принимала у них зачеты и экзамены), даже игры и все работало.
Собственно, написание программ в кодах процессора и работа напрямую с аппаратурой не предполагались. Вместо этого использовалась ранее написанная интерпретирующая программа, команды ОС или компилятор языка высокого уровня. Но если очень хочется, то можно было писать программы на ассемблере, которых было даже несколько штук.
Прочая периферия
Кроме магнитного барабана к «Сетуни 70» были подключены: считыватель и перфоратор перфолент, электрифицированная пишущая программно-управляемая машинка «Консул 254», выполнявшая роли клавиатуры и принтера. Кроме них через адаптер-приставку «Сетунь 72» подключались 27 выносных клавишных терминалов для приема зачетов и экзаменов. В одной или двух статьях упоминалось подключение к «Сетуни 70» цветного телевизора для проведения психофизического эксперимента.
Ну и всемогущая консоль управления с индикаторами и часами с помощью которой можно в любой момент остановить любую программу, исправить значения чисел хранящихся в оперативной памяти и запустить программу дальше.
Особенности реализации архитектуры машины «Сетунь 70»
Вернемся к эмулятору. Мой эмулятор написан для запуска в Ubuntu и реализует архитектуру второй модели семейства «Сетунь» - «Сетунь 70». Как я уже отмечал выше, она значительно сложнее, более гибкая и производительнее чем предыдущая.
Хочу обратить ваше внимание на тот факт, что под одним названием «Сетунь 70» существовали две заметно различающихся архитектуры машины:
ранняя, исходная или базовая 1970-го года (оттуда и 70 в названии) с одним стеком (для данных),
переработанная модификация примерно 1975-го года (поддержка идеи структурированного программирования).
Вторая отличается измененными режимами работы, появлением второго стека для хранения адресов возврата, несколькими замененными командами для поддержки структурированного программирования. В результате машина стала удобнее в программировании.
Об этом важно знать и помнить, т.к. программы предназначенные для работы на одной архитектуре скорее всего не будут работать на другой. Возможно за исключением самых простейших (умещающихся в одну страницу памяти и самодостаточных).
Мой эмулятор на данный момент реализует только раннюю модификацию, так как она чуть проще в понимании, освоении и реализации, чем поздняя модифицированная. Но в будущем конечно добавится и вторая.
Библиотека «Аналемма»
Собственно, библиотека Аналемма это то самое упомянутое мной выше решение, которое удовлетворяет всем критериям, которые были приведены выше как подсказки. Она позволяет снять или снизить проблемы представления чисел и падения производительности.
Почему аналемма? Потому что аналемма.
В определенных условиях аналемма бывает дискретна и симметрична.
Аналемма дает возможность хранить целые уравновешенные троичные числа в удобной для работы форме, производить с ними арифметические операции и преобразования представления без почти потери времени. На данный момент поддерживаются 3-, 6-, 9- и 18-разрядные числа.
Смысл достаточно прост и очевиден. Вместо того чтобы хранить в массиве какое-то представление значения самого троичного числа, тратить время на его поиск, выравнивание, преобразование, вычисление и обработку и т.д. мы поступаем следующим образом:
Создаем структуру-описатель числа для всех чисел заданной разрядности (по умолчанию это 729 для 6 разрядов). В каждом описателе есть поля для представлений, которые требовались при подготовке и тестировании эмулятора:
двоичное число (для обращения к внешнему миру из троичной программы),
двоично-кодированное троичное представление целиком (сейчас это «пара бит на трит»),
массив троичных разрядов по-отдельности,
номер первого ненулевого трита (по его знаку определяется знак всего числа, а если этот номер равен минус единице, значит это число - 0),
признак четности числа,
уравновешенное девятеричное представление числа с алфавитом {W, X,Y, Z, 0, 1,2, 3, 4},
строковое представление троичного числа с алфавитом {N,Z,P},
строковое девятеричное представление числа,
строковое десятичное представление числа,
строковое шестнадцатеричное представление числа.
Сама таблица создается один раз при сборке проекта. Вместо вычисления или хранения такого набора для каждого числа в массиве памяти или регистре мы просто храним там ссылку на экземпляр числа. Как это делать решит компилятор.
Да, каждое такое число в результате занимает немало места в памяти, но оно делает это всего один раз, а мы ссылаемся на него одним обычным двоичным адресом.
Кроме того мы не будем каждый раз вычислять значения арифметических операций, они тоже вычисляются при сборке и просто выбираются из подготовленной таблицы, если библиотека собрана для 3-, 6- и 9-разрадных трайтов. Если для 18-разрядов, то часть работы выполняется в процессе работы - иначе вместо скромных 4 мегабайт ссылок нам потребуется таблица в 17 гигабайт.
Библиотека сейчас хранит числа по принципу «достаточно просто для понимания» и при необходимости может быть оптимизирована для более компактного или более удобного представления. Может быть реализована аппаратно в качестве интерфейса или периферийного устройства.
В дальнейших версиях планируется поддержать составное представление 3-, 6- и 9-разрядов таким образом чтобы их можно было сочетать - и вместо всех 6 в массиве какие-то будут 3 и 9. А при необходимости будут переменно-разрядные пары 12 и 15 разрядов, вместо одно числа.
Уровень конфигурации архитектуры конкретной модели
Чтобы была возможность изменить архитектуру предусмотрел слой конфигурации, в которой задаются признаки команд и их мнемоники, расширяющие и дополняющие базовый набор структур Аналеммы. Кроме того задается набор символов и управляющих кодов для устройства символьного ввода-вывода («Консул 254»). С помощью слоя конфигурации можно будет переключаться с исходной на модифицированную архитектуру машины, кода ее реализация будет добавлена.
Ограничения эмулятора
Это одна из первых версий кода эмулятора, который уже начал более-менее работать, путь и в тепличных условиях. Он заведомо не полный, однако в общих чертах соответствует имеющемуся описанию архитектуры.
В реализации есть определенные допущения и упрощения, связанные с неполнотой описания архитектуры в области работы с периферийными устройствами, отсутствием стартовой прошивки и программ для проверки.
Пока не эмулируется фронтальная панель, ее индикаторы и пульт управления.
Можно сказать что это только начало. Но это очень хорошее начало.
Слушай, где эмулятор, а?
Да, если вам уже надоело читать, то берите код. Обратите внимание что эмулятор использует библиотеку, поэтому библиотека и эмулятор должны лежать на одном уровне рядом друг с другом.
1.Аналемма
https://github.com/Barmaleikin/analemma-core.git
2.Эмулятор
https://github.com/Barmaleikin/Setun-70.git
Соберите и протестируйте в Ubuntu сначала аналемму командами
cargo build --release && cargo run tests
Если все собралось и тесты прошли успешно, повторите их для эмулятора. Если при сборке эмулятора увидите ошибку что аналемма не найдена скорректируйте путь или просто скопируйте код эмулятора в папку по соседству с аналеммой и повторите сборку.
Запуск эмулятора
Если сборка прошла нормально, выполните команду:
cargo run --release
В результате вы должны увидеть строку:
Я СЕТУНЬ 70
После чего эмулятор заканчивает работу. Чтобы сделать что-нибудь «полезное» запустите командой:
cargo run --release -- echo
И теперь сможете «поработать» на машине - она принимает ввод с клавиатуры, фильтрует символы и игнорирует те, которых нет в кодировке машины, а те что есть выводит обратно в терминал. Например, в кодировке есть только заглавные буквы кириллического и латинского алфавитов.
Можете даже при запуске дать на ввод строку посмотреть что получится:
cargo run --release -- echo "УРА! ЗАРАБОТАЛО! заведут мотор и через 42 к-а-к... ЭТО ТОЧНО."
Что дальше?
На этом пока все, код предназначен для изучения и дальнейшего развития. Со временем работа будет продолжена, уже сейчас локальный код отличается от опубликованного, добавляется работа с перфолентой и «Консулом 254», эмулятор которого так же опубликован, но пока работает автономно без связи с эмулятором машины.
Если вы будете писать комментарии и захотите чтобы я вам ответил, напишите в начале фразу "Примите меня в игру:", так я буду знать что вы дочитали до конца.
Комментарии (2)

GerrAlt
07.09.2026 20:54Но это ведь только если не думать об отрицательных числах (+1 разряд или еще больше)
не понял почему обязательно +1 разряд? дополнение до двойки вроде как не имеет отдельного знакового разряда?
9a75sd
Примите меня в игру: а как тогда писать программы для данного эмулятора? Понимаю, что большинство языков программирования заточены именно под двоичную систему, но будет ли, например, компилятор Си для архитектуры Сетунь-70?