Хабрахабр

Аскота 170 — механический компьютер и советский палеоэндемик

В мире наступили восьмидесятые. IBM захватывал рынок профессиональных компьютеров своими PC и PC XT — родоначальниками всех современных настольных компьютеров. Джобс одну за другой выпускал новые модели Apple. Commodore 64 и ZX Spectrum гремели по миру. А в это время в советском блоке продолжали выпускаться Ascota 170 — механические компьютеры родом из начала пятидесятых. Почему-то, в рунете (да и в остальном интернете тоже) мало говорят об этих удивительных машинах, едва ли не единственных серийно (больше трёхсот тысяч с 1955 до 1983 годов) выпускавшихся Тьюринг-полных механических компьютерах. Я и сам о них узнал только тогда, когда Аскота случайно попала мне в руки.
Надеюсь, моя статья сможет изменить это.

К сожалению, машины эти обычно здоровенные, а музея бесконечного размера у меня нет, поэтому брать приходится только самое интересное.
Моя Аскота закончила считать квадратный корень из 2.
Вообще, я — коллекционер механических счётных машин. Что Сергею и сказал. Вот и когда Сергей Фролов поинтересовался, ли нужна ли мне Аскота, я пару минут погуглил и выяснил, что Аскотами назывались весьма скучные и примитивные машинки, которые не стоят занимаемого ими места. Я погуглил ещё раз, и был пленён. К счастью, Сергей ответил, что речь не просто об Аскоте, а об особо редкой модели 170.

К сожалению, общение с продавцом на Авито показало, что Аскота некомплектная, поэтому брать её бесполезно. Оказалось, что мне предлагают одну из сложнейших когда либо производившихся механических машин, бухгалтерский счётный автомат, программируемый с помощью «гвоздей», вбиваемых в специальную доску молотком. Здесь заканчивается предыстория и начинается, собственно история. Потом на Авито появилась ещё одна половинка Аскоты (продавец мне больше часа пытался доказать, что она целая, а не половинка), потом вопрос завис на год… А потом мне написал первый продавец, и сказал, что нашёл недостающие части!

Но «программируемая» — понятие растяжимое, и перед покупкой я попытался что-нибудь узнать о её возможностях. Конечно, к этому моменту я прочитал, что Аскота-170 — вроде как программируемая машина. Одну из них, тоненькую брошюрку про методы применения, я купил на Авито — но понял из неё, увы, немного — в основном, то, что машина постоянно работает в цикле и как-то поддерживает переходы. К счастью, это оказалось несложно: Аскоты поставлялись в СССР массово, и про них выпускали десятки книг. Весь двадцатый век туда стекаются обязательные экземпляры выпускавшихся у нас книг, и книги про Аскоты там должны быть. Не знаю, что бы я делал с этой информацией — но мне в голову пришла идея: на станции метро Библиотека имени Ленина находится Библиотека имени Ленина! Больше того, оказалось, что за последние десятилетия режим работы библиотеки сильно смягчился, и сегодня любой желающий может прийти и отфотографировать книги на непрофессиональный фотоаппарат. Действительно, в электронном каталоге Ленинки нашлось больше трёх сотен книг с упоминанием Аскоты 170.

А сам взялся за детальное штудирование учебников. На радостях я перефотографировал несколько десятков книг, и примерно понял из них, что Аскота может, и немедленно купил её.

Возможности Аскоты 170

Читать эти книги было непросто: мало того, что они описывали программирование машины, разработанной задолго до появления первого языка высокого уровня, Фортрана. Так они ещё и написаны были в бухгалтерских терминах. В общем, представьте, что вам нужно изучать учебник по 1С: Ассемблер, написанный на старославянском, и вы примерно поймёте масштаб стоявшей передо мной проблемы. Достаточно сказать, что факт наличия условного оператора я смог установить только потому, что специально его искал. А разобраться, как он работает, удалось только после изучения конструкции соответствующих узлов и ряда экспериментов.

У Аскоты есть условные операторы! Да! И вообще всё, что нужно для работы полноценного компьютера общего назначения! И команды перехода!

Пользоваться буду придуманным мною С-подобным псевдокодом — совершенно не похожим на тот, что использовался в старых учебниках, но куда более понятным сегодня. Давайте я расскажу об этом чуть подробнее.

При этом печатающий узел скользит вдоль бумаги, а узел чтения программной команды — относительно программной доски с дырочками, в которые вставлены шпиньки-стопсы — примерно как в барабане музыкальной шкатулки. Итак, при работе каретка машины движется справа налево относительно тела машины — как на обычной печатной машинке. А если узел чтения не находит стопс остановки до конца каретки, то каретка автоматически перемещается до упора вправо, и сканирование начинается заново — такой вот основной цикл, в котором бесконечно крутится программа. В какой-то момент узел чтения находит колонный стопс, означающий «здесь надо остановиться и что-то сделать», останавливается и делает то, что требуют остальные стопсы этой колонки и нажатые оператором клавиши.

Вертикальный сверху — колонный, остальные — программные.
Один столбец стопсов.

За один шаг может выполняться несколько команд. На практике, таких остановок «надо что-то сделать», то есть шагов программы, может быть около 50 на одну доску. Например, вот такой код занимает всего один шаг:

if (I>0)

Как видите, машина активно обращается к регистрам; регистры — это ряды шестерёнок в теле машины, так что память программы (доска со стопсами) отделена от памяти данных (рядов шестерёнок регистров). Итого, у машины ~50 шагов командной памяти (~0,3 кБ) и 56 целочисленных регистров по 12 десятичных разрядов (ещё 0.3 кБ).

Одновременно выполняется пара вариантов сравнения с нулём и несколько вариантов команд перехода. За один шаг машина может прочитать один регистр, распечатать его содержимое, прибавить или отнять его к нескольким другим регистрам и обнулить.

Увы, несмотря на сложность и богатство машинного кода, у него есть несколько неприятных ограничений:

У машины нет команд для умножения и деления. 1.

Команда умножения есть у большинства более простых бухгалтерских машин но разработчики Аскоты уже в начале 1950-х понимали, что дни механики сочтены, и вместо медленного и неуклюжего механического умножителя предусмотрели возможность подключения внешнего математического модуля. Как ни странно, это не бага, это фича. Уже в конце 1950-х вместо него стали использоваться ламповые модули R12 (монстры размером с небольшой шкаф, весом в 200 килограммов и потреблением в полтора киловатта), с 1962 выпускались небольшие (с маленький системный блок) транзисторные умножители, а к моменту схода с конвейера моего экземпляра Аскоты стали использоваться крошечные умножители-делители на микросхемах. И действительно, упоминания внешнего механического умножителя для Аскоты встречается в старых учебниках, но ни одной его реальной фотографии (или, тем более, реального экземпляра) не сохранилось. В общем, хорошо, что мне достался экземпляр без умножения-деления: обидно было бы получить вместо полностью механического компьютера банальный электронный калькулятор на микросхемах.

Машина не умеет смещать число на разряд вправо или влево. 2.

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

Количество меток перехода ограничено. 3.

Звучит неплохо, но, при программировании достаточно сложного алгоритма хватает этого в обрез. В программе могут быть метки backward1, backward2, forward1 и forward2, причём каждая — по несколько раз, шаги программы могут быть помечены как выполняемые по программе 1, по программе 2 и по обеим.

Нет поддержки массивов и непрямой адресации. 4.

Только вдумайтесь: есть 50 шагов программы, за каждый шаг можно прочитать (и распечатать) только один регистр — и регистров, при этом, 56! У Аскоты много регистров. То есть, напрямую адресовать все регистры в автоматическом режиме, без выбора номера регистра с клавиатуры, невозможно в принципе.

И, в принципе, у Аскоты для этого всё есть: пятьдесят регистров организованы в виде пяти вращающихся барабанов по десять регистров, и для инкрементной адресации достаточно было добавить команду поворота барабана на один шаг вперёд. Обычно это проблема решается с помощью разных вариантов непрямой адресации — например, сначала вы задаёте номер регистра (ptr=&R00), а затем, в цикле, раз за разом увеличиваете его (ptr++). Но не сделали, почему-то. Для обсчёта стопок многострочных документов это была бы очень востребованная функция. Если кто-нибудь вспомнит более ранний немецкий компьютер с инкрементной адресацией — подскажите, пожалуйста. Единственное объяснение, которое мне пришло в голову — возможно, к началу 1950-х ещё не изобрели инкрементную адресацию.

Живая Аскота!

Пока я разбирался с особенностями программирования, компьютер пришёл ко мне из Омска. После неизбежной перебранки с грузчиками я поставил его посреди комнаты, обстучал молотком ржавчину, полил механизм смесью масла и керосина и попробовал включить.


Аскота (справа) была очень большая


И очень грязная

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

Я завесил половину интернета объявлениями о поиске опытного наладчика, нашёл нескольких человек, которые сорок лет назад немного имели с Аскотами дело, но, увы, чинить пришлось самому. Следующий месяц прошёл в ремонте. Я напечатал на 3D принтере ручку для ручного вращения управляющего вала, научился отключать залипшие счётчики, выгреб из механизма ещё несколько кусков особо злостной еловой коры, нашёл и разработал полдюжины залипших соединений, починил полдюжины отказавших пружин.


Откуда тут кора?!

Я прогуливал работу неделями, с утра до вечера рылся в руководстве по наладке, ища причину очередной неисправности, ловил на лестничной площадке спамеров, за сто рублей помогавших мне временно перевернуть машину кверху ногами… И, наконец, дошёл до момента, когда на машине удалось запустить «Hello world!».


Переключаем Аскоту в режим печатной машинки, и набираем «НЕЛЛО ШОРЛД».

Давайте лучше бессмертных кроликов считать. Хм, нет, это слишком просто.

Предположим, месяц назад у нас не было кроликов, а сегодня мы купили на рынке пару крольчат.

Через месяц они вырастают в пару взрослых кроликов.

Итого, две пары. Ещё через месяц пара даёт потомство, и мы получаем пару взрослых кроликов и пару крольчат.

Итого, три пары, две взрослых и одна дети. Ещё через месяц пара взрослых опять даёт потомство, а крольчата прошлой пары подрастают и становятся взрослыми.

Итого, у нас пять пар, все кролики, бывшие у нас месяц назад, взрослые, а все, которые были взрослыми, дали по паре потомства. Ещё через месяц две пары взрослых дают две пары потомства, а крольчата прошлого месяца вырастают.

И так далее.

Эту задачку в начале XIII века исследовал итальянский математик Фибоначчи, в честь которого получившийся ряд чисел назван рядом Фибоначчи:

0 1 1 1+1=2 1+2=3 2+3=5 3+5=8 5+8=13 8+13=21…

Это просто. Давайте рассчитаем его на Аскоте. Тогда программа будет выглядеть так: Пусть в регистре I у нас находится нечётный член ряда (для начала, первый), в регистре II — чётный (для начала, нулевой).

1: read I; II+=; prn(); //Программа №1: Читаем регистр I, прибавляем его значение к регистру II и распечатываем. 1: read II; I+=; prn(); newline; goto backward1; // Программа №1: Читаем регистр II, прибавляем его значение к регистру I и распечатываем. Затем сдвигаем бумагу на следующую строку и возвращаемся к началу программы.

Программу надо вручную ассемблировать, а потом вбить стопсы в нужные дырочки программной доски. Получится вот что:

1 0/0 12/4 14/3
1 12/3 14/4 17/4 33/4

Стопс в ряду 12 управляют регистром II: 12/3 вызывает чтение регистра, а 12/4 — добавление к нему прочитанного числа. Здесь единичка в начале означает колонный стопс типа 1, заставляющий машину остановиться для выполнения этих шагов по программе №1, 0/0 (установленный в ряд №0 стопс типа 0) заставляет машину искать колонные стопсы начиная с этой точки. Печать прочитанного числа происходит автоматически, если только не установлен специальный стопс 5/3, отключающий печать. Аналогично, 14/3 вызывает чтение регистра I, а 14/4 — добавление к нему прочитанного. 17/4 проворачивает валик каретки на один шаг, а 33/4 запускает возврат каретки (этот стопс можно не ставить, тогда каретка проскользнёт до конца, и возврат каретки запустится автоматически).

Но в первый раз я этого не сделал, и мне пришлось постоянно жать клавишу запуска.
По хорошему, в обе строки надо добавить ещё 15/6R, тогда сразу после окончания шага машина начинает выполнять следующий.

Я был в восторге! Как ни странно, программа запустилась с первого раза.

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

1: read I; clr; //для начала очищаем все переменные
1: read II; clr;
1: read III; clr;
1: read IV; clr;
1: read K; clr;//останавливаемся и даём пользователю ввести единицу.
1: stop; read kbd; IV+=; K+=; prn(); clr;//записываем единицу в IV (она нужна будет для инкремента) и в K (начнём с первого члена ряда). Заодно печатаем её - она будет запросом для ввода первого члена ряда.
1: stop; read kbd; I+=; prn(); clr; // записали первый член ряда в I.
1: read IV; K+=;
1: read K; prn();// печатаем запрос на ввод второго члена ряда.
1: stop; read kbd; II+=; I+=; prn(); clr; // записали второй член ряда в II. Заодно в I теперь I+II, то есть третий член ряда.
backward1: 12: read IV, K+=; // увеличиваем на единицу номер текущего члена ряда - для начала, он станет равен 3. Обратите внимание, этот шаг выполняется и по программе №1, и по программе №2.
2: read II; I+=; III+=; goto prog1; goto forward; //на первом цикле этот шаг обходим, потому что у него метка программы №2, а не №1. А на втором цикле из II читается четвёртый член, который записывается в пустой III и прибавляется к I (в I был третий, стал пятый). После этого мы снова переходим к программе №1 и прыгаем вперёд, к этапу печати.
1: read I; II+=; III+=; goto prog2; // На первом цикле в I третий член, в II - второй. В сумме, соответственно, получается четвёртый (он оказывается в II). В III записываем текущий I - третий. И переходим к программе №2.
forward1: 12: read III; prn(); clr; // печатаем текущий член ряда - для начала I+II, а там видно будет. Обнуляем III. Обратите внимание, этот и следующий шаги выполняются и по программе №1, и по программе №2.
12: read k; prn(); newline; goto backward1; // Печатаем номер шага, переводим строку, возвращаемся назад.

Я запустил программу, и машину благополучно заклинило, потому что я до этого не пользовался регистром К, а в нём был очередной кусок коры. Нде. Кусок коры убрал, счётчик отключил, машину расклинил. И заработало же!

Я решил, что машина уже окончательно работает, нужно только набить какой-нибудь красивый алгоритм, чтобы похвастаться на Хабре, и можно писать отчёт. Например, Стэнли Френкель, если верить мистеру Фейнману, учил табулятор считать арктангенс. Чем я хуже? То есть понятно, чем хуже, но вдруг?

На Stackowerflow предложили вариант расчёта логарифма, слишком сложный для Аскоты, в Библиотеке имени Ленина нашлись нашлась пара брошюрок с несколькими интересными алгоритмами — но они тоже оказались нам с Аскотой не по зубам. Увы, подходящих алгоритмов я не нашёл. В конце концов, я плюнул на тригонометрию и логарифмы, и решил считать банальный квадратный корень.

Из формулы суммы членов арифметической прогрессии получается, что сумма первых n нечётных чисел = n^2. Вообще, квадратный корень считается легко. Из чего следует

$n=\sqrt{\sum\limits_{i=0}^n(2n+1)}$

Откуда сравнительно легко выводится алгоритм вычисления квадратного корня, использовавшийся с начала 1950-х годов арифмометрами с автоматическим вычислением квадратных корней фирмы Friden — вот тут немного подробнее. Правда, этот алгоритм тоже требует сдвигов на разряд, но только на разряд вверх (сдвиг на разряд вверх, то есть умножение на десять, можно организовать как ряд сложений, а сдвиг на разряд вниз с помощью возможностей Аскоты практически нереализуем).

Но из-за количества операций, требуемых при сдвиге вверх, в 50 шагов он не укладывался. Первый вариант программы я написал за вечер. Не заработало.
Перепроверил, нашёл несколько мелких ошибок. Пришлось оптимизировать, вычисляя два разных сдвига одними командами, потом исправлять ошибки, потом отлаживать программу на листе бумаги, опять исправлять ошибки, опять отлаживать… Где-то через неделю дело дошло до ассемблирования, набивки в программную доску и пробного запуска. Не заработало. Исправил. Исправил, не заработало. Перечитал книжки, выяснил, что неправильно понял одну тонкость программирования. Не заработало. Перепроверил, нашёл ещё ошибку. Исправил. Перепроверил, понял, что не исправил мелкую неисправность в машине. И отладил, наконец! Не заработало… В общем, ещё неделю я налаживал программу в железе.

Разве что регистры не все, но регистры я отдельно проверял. Надеюсь, после этого серьёзных непонятых тонкостей программирования и неполадок машины не осталось, потому что программа вычисления квадратного корня использует, кажется, все вычислительные и логические функции, которые есть в машине.

Что в результате и что дальше?

В результате, во-первых, у меня есть рабочая Аскота-170.

Аскоты использовались у нас, минимум, до конца 80-х годов, и их малую известность я могу объяснить только тем, что мало кто понимал, насколько они круты, а владельцы складов не понимали, насколько ценные вещи им попадались. Во-вторых, надеюсь, этой статьёй я сделал её более известной в рунете. Возможно, статья исправит эту ситуацию.

Надеюсь, это тоже послужит популяризации Аскоты, и поможет наладчикам, которым удастся достать её после меня. В-третьих, я создал на своём сайте раздел про Аскоту, в котором выложил руководство по программированию, некоторые советы по наладке механизма, книги, модели для 3D печати, коды программ и так далее.

Так вот, получилось, что я потратил под две сотни рабочих часов без учёта прокрастинации. В-четвёртых, в ходе работы я старался учитывать потраченное Аскоту время в табличке. Наверное, можно в резюме вписать, да?

С другой стороны, осталась пара нерешённых задач.

Как я уже сказал, придумать или найти подходящий алгоритм сам я не смог, но если кто-нибудь из читателей статьи предложит мне (в комментариях, в личке или на почту me[а]alple.net) какой-нибудь подходящий алгоритм (в псевдокоде вроде того, что есть для квадратного корня), я обязательно постараюсь реализовать его в железе, и снять про это видео. Во-первых, я так и не сделал программы для расчета чего-нибудь крутого, вроде тригонометрических функций, рациональных степеней или логарифмов.

При этом, у меня такое впечатление, что её собирались сделать, но так и не сделали — никак иначе я не могу объяснить существование регистров III/IV. Во-вторых, как я уже говорил, Аскоте очень не хватает команды сдвига на разряд.

про регистры

Наибольшее их число, 55 (+1 в клавиатуре) как раз в моей версии. Выпускались разновидности Аскоты с разным набором регистров. По функциям похож на I и II, плюс имеет защиту от случайного сброса. Вот их список:
Регистр клавиатуры, в котором временно хранится введённое на клавиатуре число.
Регистры I и II — универсальные, полностью независимые, управляемые автоматически и с клавиатуры, поддерживающие отрицательные числа и логические операции.
Регистр K — контрольный, для контроля безошибочности работы оператора и машины. Не работают с отрицательными числами и меньше используются в логических операциях, имеют некоторые технические ограничения взаимного подключения, нормально управляются с клавиатуры и автоматически.
И те самые загадочные регистры III/IV — по возможностям они близки к накапливающим, но с клавиатуры управляются очень-очень плохо.
При этом, регистры III/IV имеют свой собственный механизм подключения, независимый от накапливающих регистров. С клавиатуры не управляется, но для контрольного регистра это скорее достоинство.
Накапливающие регистры — те самые, в барабанах по 10 штук. Собственно, эта система осталась от одной из более примитивных моделей Аскоты, у которой кроме регистров I, II, III, IV и K ничего не было — но зачем их оставили?

Я думаю, что они предполагались именно как регистры сдвига на разряд. Потому что достаточно сцепить их рядом диагональных шестерёнок, и мы получим устройство сдвига: записываем, скажем, в III число, и получаем в IV его же, но сдвинутым на разряд влево.

Я представляю себе это как-то так:


Вот тут вы можете покрутить 3D модель.
А вот тут — посмотреть, как счётчики выглядят вживую.

Полупрозрачный клин — детали устройства счётчика. На картинке — жёлтые шестерёнки — счётчики III и IV (например к красным подключены первый разряд III-1 и второй разряд IV-2).

Если собрать такую систему, то для сдвига на разряд влево достаточно будет записать нужное число в IV и прочитать его из III. Красные шестерёнки — та самая отсутствующая система сдвига, поворачивающая шестерёнку III-1 при повороте IV-2, и наоборот.

Получается достаточно сложная конструкция, придумать которую я не могу. Сложность в том, что при работе шестерёнки счётчиков не только вращаются, но и движутся вверх-вниз (примерно на свой радиус), и механизм должен это движение поддерживать.

Было бы здорово, если бы кто-нибудь, умеющий проектировать лучше меня, за разумные средства взялся бы придумать мне такую систему для печати на принтере, или изготовил бы её в железе — с уточнениями и предложениями, опять же, пишите в комментарии, в личку или на почту me[а]alple.net.

Больше подробностей вы можете найти у меня на сайте, в разделе про Аскоту.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть