Как стать автором
Обновить
3000.39
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Мой маленький триод: Ламповая ЭВМ — это магия

Время на прочтение25 мин
Количество просмотров25K
Экспериментальная 3U декатронная ячейка. Модуль декатрона А103 со схемой шифратора и переноса

Пришло время возобновить славную традицию ежегодного первоапрельского дайджеста по моим безумным вычислительным проектам. В прошлой трилогии [1], [2], [3] я рассказывал про создание де-факто самого быстрого в мире релейного компьютера BrainfuckPC. После трёх лет раздумий я наконец-то готов начать активную фазу строительства уникальной ламповой ЭВМ с кодовым названием DekatronPC.

Минутка истории


Прогулка по немецкому музею в г. Мюнхене за две недели до начала пандемии:

У ламповых ЭВМ был очень короткий век. Самым первым цифровым ламповым вычислителем считается — компьютер Атанасова — Берри, увидевший свет в 1942 году. Однако он не являлся программируемым и выполнял строго одну задачу — решение СЛАУ. Всемирно известный программируемый компьютер ЭНИАК на 17.5 тысячах ламп (а также 7 тыс. диодов и 1.5тыс. реле) — появился в 1945г. При этом уже в 1947 году был изобретён транзистор, а ещё через 6 лет — заработали первые прототипы транзисторных ЭВМ. В итоге уже к началу 60-х годов транзисторные компьютеры развивались семимильными шагами, с одновременным забвением ламповой вычислительной техники.

ЭНИАК. Национальный исторический памятник и музей Форт Силл. США

Очевидно, что за 60 лет в мире почти не осталось действующих ламповых машин, как минимум из-за ограниченного ресурса самих электронных ламп. В настоящий момент старейшей работающей ЭВМ является Harwell computer 1951 года постройки. Этот небольшой вычислительный комплекс построен на базе вакуумных ламп и газоразрядных декатронов, а также электромагнитных реле. Из-за реле, а также особенностей архитектуры при работе с декатронами, ЭВМ получилась очень медлительной, способной решать единицы операций в секунду. Однако, компьютер вышел весьма надёжным и был способен работать несколько суток подряд без сбоев. В 2012-м году машина была восстановлена и в настоящее время выставляется в Национальном музее вычислительной техники в Блетчли-парк, Англия.

МЭСМ является первой, экспериментальной ЭВМ созданной на территории СССР и запущенной в эксплуатацию в 1951г. Здесь я хочу обратить внимание, что машина состояла из 6000 ламп, из которых 3500 триодов и 2500 диодов. Это значит, что в машине активно использовалась диодная логика. Вспомним об этом факте при обсуждении схемотехники. В те же годы были созданы машины М1, М2 и М3, правда, согласно википедии, диодная логика в них уже была на полупроводниках.

Развешанные по стенам блоки МЭСМ и операторский пульт

Одной из наиболее известных отечественных ламповых серийных ЭВМ была малая машина Урал-1, построенная в 1956г. на базе 1000 ламп. Медленная (100 инструкций в секунду), но надёжная машина, один из экземпляров которой занимался расчётами моделирования траекторий ракет на космодроме Байконур. Низкое быстродействие машины является следствием использования магнитного барабана в роли ОЗУ с частотой вращения 100 об/сек. Полностью укомплектованная ЭВМ Урал-1, судя по всему, осталась только в политехническом музее в Москве. Также пара шкафов от машины сохранились на Байконуре.

Автор на фоне машины Урал-1 в запасниках политехнического музея, Москва

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

Унифицированные модули. Вид сзади (слева), сбоку(справа). Видны октальные ламповые панельки, монтажные колодки, макетные платы

С 1952г. начинается история ламповых машин серии БЭСМ — с быстродействием от 10 тыс. операций в секунду. Однако БЭСМ-4, выпущенная в 1965г. уже была транзисторной. А первые прототипы советских транзисторных ЭВМ создавались и раньше.

Что почитать
  • www.computer-museum.ru — шикарный сайт по советской вычислительной технике.
  • www.hnf.de/en/home.html — Сайт музея Heinz Nixdorf, г. Падерборн. Германия. Когда-нибудь я смонтирую видео оттуда.


Основы ламповой логики


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

Опираясь на альбомы схем отечественных и зарубежных ЭВМ, пробежимся по основным схемам построения ламповой логики. Как по мне, одними из лучших источников данных схем являются руководства по компьютерам IBM 604, IBM 650, и IBM 700.

▍ Инвертор


Усилительная лампа — например, триод или пентод — являются базовым кирпичиком при построении ламповой логики. Наиболее очевидным способом включения лампы является схема инвертора с общим катодом и нагрузочным анодным резистором. Если на управляющую сетку подать небольшое положительное смещение (здесь — +1В) — то лампа «откроется»: её внутреннее сопротивление будет минимальным, и выход «притянется» к земле, таким образом, на нём будет сигнал низкого уровня (+50В). Если же на сетку подать запирающее напряжение — в данном случае -50В — то лампа «закроется», её внутреннее сопротивление будет стремиться к бесконечности и на выходе будет сигнал высокого уровня.
Инвертор. IBM 604

Фактически инвертор уже реализует логическую операцию НЕ. Основной недостаток такой схемы заключается в несимметричной работе ключа. При подаче лог.1 лампа открывается и за счет низкого внутреннего сопротивления быстро разряжает ёмкость подключённой нагрузки, обеспечивая крутой спадающий фронт. Однако при подаче лог. 0 лампа закрывается, ее внутреннее сопротивление стремится к бесконечности и заряд ёмкости нагрузки происходит через анодный резистор. Его сопротивление существенно больше сопротивления открытой лампы — в итоге нарастающий фронт затягивается. Аналогично себя ведёт транзисторная схема с открытым коллектором. Будь у лампы комплиментарный ключ — можно было бы собрать двухтактные схемы и всё было бы намного проще, но это — физически невозможно. Частично проблема медленных нарастающих фронтов решается индуктивностью в цепи анода. Запасенная в индуктивности энергия кирпичом ударит в нагрузку, ускоряя закрытие лампы.

Если на один анодный резистор повесить сразу две лампы, то получится базисный логический элемент 2ИЛИ-НЕ (Стрелка Пирса), что означает возможность создания ламповой логической схемы любой конфигурации.


Логический элемент 2ИЛИ-НЕ

С помощью резистивных делителей на входе, а также отрицательного смещения в -100В, логические уровни +150 — +50В преобразовываются в сигналы +1 -50В необходимые для управляющей сетки. Конденсаторы в цепи делителей используются для компенсации паразитной сеточной ёмкости и корректируют нарастающие фронты управляющих сигналов. На выходе будет сигнал низкого уровня — +50В, если подать лог.1 на любой из входов элемента.

▍ Катодный повторитель


Катодный повторитель — ещё один вариант включения лампы. В этом случае катод лампы через резистор подключён к источнику отрицательного напряжения -100В. Сигнал на выходе по уровням напряжения будет примерно соответствовать входным — +25 — -25В на входе и +26 — -22В на выходе.
Катодный повторитель

Зачем он такой нужен? Как и эмиттерный повторитель на транзисторе — согласовать высокое выходное сопротивление с низким. Например, декатрон имеет анодный ток в 500мкА. Этого достаточно чтобы отобрать 10-20мкА для управления одной-двумя лампами без изменения режима работы разряда, но если нам надо подключить к декатрону 10-20 ламп — то без повторителя не обойтись.


Логическое ИЛИ на катодном повторителе

Если на один катодный резистор посадить сразу несколько ламп, то получится многовходовое ИЛИ. К сожалению, из-за коэффициента усиления по напряжению чуть меньше единицы, на одних катодных повторителях далеко не уедешь.

▍ Катодно-связанная логика


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

Дифф. каскад в роли логического элемента. Компьютер ACE от Алана Тьюринга

Несмотря на работу ламп в усилительном режиме и высокое быстродействие, сразу бросается в глаза удвоение ламп. С другой стороны, у дифф. каскада сразу два выхода — прямой и инверсный. Второй недостаток можно обнаружить, оценив схему сумматора на лампах:

Сумматор на дифф. каскадах

Не многовато ли тут напряжений смещения? Всё же удобно, когда в ЭВМ везде используются одни и те же уровни напряжения. Например, +150 — +50.

▍ Диодная логика


Описанные выше схемы включения ламп предлагают ограниченное количество логических элементов. Попробуем добавить на вход лампы логику на диодах в различных комбинациях. Диоды можно использовать и сами по себе, например, для создания многовходовых элементов И, ИЛИ. Несколько диодных плат в релейном компьютере BrainfuckPC использовались именно в качестве многовходовых ИЛИ. С одной стороны, они повышали быстродействие — по сравнению с релейным каскадом, требующим 300-400мкс времени на срабатывание реле, диоды работали мгновенно. С другой стороны, при напряжении питания реле в 5В и падения напряжения на германиевых диодах в 0,7В у меня были проблемы со стабильностью работы схемы — 86% питающего напряжения было недостаточно для обеспечения необходимой скорости срабатывания реле.


Диодные логические элементы И(слева), ИЛИ(справа)

В моей ЭВМ я планирую использовать диодную логику с инвертирующим усилителем или эмиттерным повторителем. В этом случае на диодах и подтягивающих резисторах собирается практически любая логическая схема, будь то многовходовое И, ИЛИ, а также их комбинации. Этот сигнал подаётся на усилитель и далее по схеме. Такой вариант прост в разработке, и довольно экономичен — напряжение и ток в диодной цепи небольшой, а значит, и потребляемая мощность по цепи управления будет низкая. Но главное — диоды требуют в полтора раза меньше мощности на накал. Например, сдвоенный диод 6Х7Б потребляет 1,9Вт по цепи 6.3В, в то время как сдвоенный триод 6Н17Б — 2,8Вт.

Различные схемы диодной логики с усилительным каскадом на лампе

Язык программирования brainfuck


Как и релейная машина, DekatronPC создаётся для выполнения программ, написанных, на, пожалуй, самом популярном эзотерическом языке программирования brainfuck.

Рис.2: Инструкции языка brainfuck

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

В языке 8 инструкций, которые крутятся вокруг 30 тысяч ячеек памяти данных разрядностью 8 бит.

  • С помощью инструкций < и > мы можем перемещаться по памяти данных влево или вправо, выбирая ту или иную ячейку данных. При этом память закольцована, т.е. ячейки с номерами 29999 и 0 являются соседними
  • Инструкциями + и - мы можем изменять значение в текущей ячейке данных на единицу вверх или вниз в диапазоне от 0 до 255.
  • С помощью инструкций . и , — реализуется интерактивность. С их помощью можно напечатать в консоли значение текущей ячейки данных, или ввести символ с терминала в ОЗУ.
  • Последние две инструкции [ и ] — используются для организации циклов. Всё что внутри скобок является телом цикла. Допускается вложенность циклов. На границах цикла проверяется состояние текущей ячейки данных. Если оно не равно нулю — необходимо выполнить тело цикла.

Существование компиляторов из языка C в brainfuck как бы намекает о том, что этих инструкций более чем достаточно для написания всего что угодно. Но плотность кода — никакущая. Для выполнения простейших операций, например, сложения значений двух ячеек памяти, требуется исполнить сотни инструкций brainfuck. Но почему новая ЭВМ называется DekatronPC, а не BrainfuckPC2.0?

Декатрон


Декатрон А103 со стеклянным баллоном и без него. Хорошо видны центральный анод и 30 катодов вокруг него

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

На самом деле декатрон является счётно-коммутаторным прибором. При подаче управляющих импульсов декатрон будет совершать операцию инкремента и декремента. Да эта лампа просто создана для языка brainfuck! Посудите сами — +1 и -1 к текущему значению, +1 и -1 к номеру ячейки данных, и +1 и -1 для счётчика инструкций — 6 инструкций из 8 можно реализовать на декатроне!

Перемещение тлеющего разряда в декатроне

Конструктивно декатрон представляет собой плоский диск анода, вокруг которого расположены 30 катодов. Десять из них — основные катоды — выведены на цоколь баллона (у счётных катодов на цоколь выведен только нулевой катод и общий). Ещё две группы по 10 подкатодов соединяются внутри баллона и равномерно располагаются по кругу — по одному подкатоду каждой группы между каждым катодом. После подачи напряжения на декатрон, между анодом и одним из основных катодов загорается тлеющий разряд. Подавая импульсы отрицательного напряжения определённой последовательности на подкатоды, мы можем перемещать разряд между катодами в любую сторону.

Один декатрон может считать от 0 до 9. Объединяя декатроны в цепочку, можно получить многоразрядные реверсивные счётчики. Например, счётчик на базе трёх декатронов способен считать от 0 до 999. С декатроном есть как минимум две проблемыособенности по сравнению со счётчиком на вакуумных лампах:

Во-первых, газонаполненные приборы очень медленные. Например, самый быстрый октальный декатрон А106 способен развить скорость счёта всего лишь в 100 тыс. импульсов в секунду. А самый быстрый сверхминиатюрный декатрон А110 — 1 млн. импульсов. В то же время на вакуумных лампах можно создать счётчики, работающие на существенно более высоких скоростях. С другой стороны, А110 у меня есть в необходимом количестве, да и достигнуть 1MIPS на лампах — ещё надо постараться.

Сверхминиатюрный коммутаторный декатрон А110 рядом с октальным декатроном А101. Скорость счёта до 1МГц

Во-вторых, декатрон мало того что считает от 0 до 9, так ещё и делает это в позиционном коде.
Так как вся адресация в машине всё же идёт в двоичных кодах, появляется необходимость шифратора позиционного кода в двоично-десятичный и обратно.
В первом случае всё относительно просто, нужно лишь 4 многовходовых ИЛИ и дело в шляпе. Тем более что выходной сигнал с декатрона +30 — 0В — с лёгкостью можно скорректировать до +10 — -20В и подавать на катодные повторители через диодную логику.

В итоге на разряд схемы считывания требуется 8 сдвоенных диодов и 2 сдвоенных триода.

Схема включения декатрона и схемы шифратора из позиционного кода в двоично-десятичный. На сдвоенных диодах реализовано многовходовое ИЛИ и катодный повторитель в роли усилителя сигнала

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

На то, чтобы записать нужное число в декатрон потребуется 29 сдвоенных триодов! 20 штук в роли логических И, 4 — на входные инверторы и ещё 5 — непосредственно на лампы, притягивающие катоды к -150В. В дополнение к этому ещё три лампы уйдут на схемы управления двумя подкатодами. За счёт этого общее количество ламп декатронного счётчика становится больше чем для варианта счётчика только на вакуумных лампах. Хорошо что не всё так плохо и схема записи на каждом декатроне мне не нужна.

Очень малая часть схемы записи. Слева схема двойного инвертирования со смещением логических уровней до -100 -200В, далее — 4-х входовое И с сигналом разрешения записи

А вот ещё одна особенность: двоично-десятичный код шириной в 4 бита, использует только 10 комбинаций из 16 возможных. В итоге имеем лишь 62.5% использования всего адресного пространства ОЗУ. Да, можно реализовать схему управления так, чтобы после 7 декатрон устанавливался в 0 и наоборот, переведя его таким образом в восьмеричный режим работы. Но схема управления декатронами настолько усложняется, что проще найти ещё пару кубов ферритовой памяти, чем городить огород с переносом. Он и так непрост и требует как минимум 6 сдвоенных диодов и 2 сдвоенных триода на каждый разряд для своей реализации.

В отличие от схем ламповой логики, у меня нет каких-либо источников, где я могу взять готовую схему управления декатроном. Приходится опираться на теорию работы декатрона и немного — на отдельные статьи 50-х годов про тот же Harwel Dekatron. Как итог — у меня нет гарантии, что схемы, описанные выше, будут работать именно так, как задумано. Да, на вакуумных лампах счётчики выйдут значительно проще, но я поставил задачу собрать их именно на декатронах со всеми сопутствующими проблемами.

Кстати, о Harwel Dekatron. Давайте внимательно рассмотрим схемотехнику базовой декатронной ячейки:



В центре схемы — непосредственно сам коммутаторный декатрон, правда, почему-то на целых 11 катодов. Каждый из них подтянут своим резистором к источнику отрицательного напряжения -16В. Сделано это, чтобы сигнал с неактивного катода запер диод логики и лампу шифратора. Лампа, в свою очередь, управляет обмоткой реле и сигнал уходит куда-то дальше. Схема считывания очень похожа на мою с тем лишь отличием, что тут не двоично-десятичная запись. Смотрите как подключены катоды декатронов к лампам шифратора. Их, кстати, пять, что даже для 11 катодов — много. Технически с каждым новым импульсом выходной сигнал будет изменяться ровно на 1 бит. Тут есть какая-то реданданси, о которой мне неизвестно.

Не менее интересным является схема записи нового числа в декатрон. Чтобы сделать это, замыкается один из 10 контактов реле, которые подключают определённый катод к входу какого-то усилителя считывания и декатрон сбрасывается в нуль с помощью схемы сброса. Далее на декатрон поступает ряд импульсов до тех пор, пока текущее значение в нём не сравняется с требуемым. Очень надеюсь, что равнозначность катодов всё же не только на бумаге и у меня получится записать любое число в декатрон, просто притянув нужный катод к -150В.

Поэтому в настоящий момент я занят сборкой экспериментальной декатронной ячейки на декатроне А103 и пальчиковых лампах 6Н15П и 6Х2П. В её задачу входит проверить эти схемы на вшивость. Для этого я использую именно пальчиковые, а не сверхминиатюрные лампы и навесной монтаж вместо печатных плат. После того как вся ячейка будет готова, а схемы управления — зафиксированы, я разработаю печатные платы и соберу модули уже на сверхминиатюрных лампах.

3d-модель экспериментальной декатронной ячейки

На данной модели представлены — слева направо:

  • Плата конвертера двоично-десятичного кода в позиционный,
  • Плата усилителей сигнала,
  • Плата декатрона, со схемой считывания и переноса разряда,
  • Плата стабилизаторов напряжения,
  • Блок трансформаторов питания.

Таки да — один разряд декатрона на пальчиковых лампах занимает 3U корпус глубиной 350мм. Всего декатронов 17. Всё же сверхминиатюрные лампы имеют смысл :)


Тёплая ламповая миниатюризация наглядно. Слева направо — октальные лампы 6Н13С и 6П9, пальчиковая лампа 6Н3П, сверхминиатюрная лампа 6Н17Б и стержневая лампа 1Ж17Б. Тут не хватает нувистора, он в два раза короче сверхминиатюрных ламп

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

Архитектура ламповой машины


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

Я поставил перед собой задачу построить самый быстрый ламповый компьютер на базе декатронных многоразрядных счётчиков, способный выполнять программы на языке brainfuck без какой-либо прекомпиляции — за что меня ругали в эпоху релейного компьютера. Хотя я всё же добавил несколько новых инструкций, которые можно реализовать на разработанной архитектуре. Из других условий — я неограничен в технологиях производства, но непосредственно в самой ЭВМ запрещено использование кремниевых полупроводников. Допускаются только германиевые диоды и селеновые столбы. Они были и в 51-м году. Использование, например, кенотронов в роли выпрямителей увеличит расчётное потребление машины примерно в 2 раза — с 10 до 20кВт. В цепи обвязки ферритовой памяти использование германиевых диодов в принципе не избежать — иначе один только блок памяти займёт серверную стойку. А то и две.

Архитектура ядра лампового компьютера

Структурно машину можно разбить на три больших блока:

  1. Instruction Ptr Block — Отвечает за выборку очередной инструкции из памяти программ.
  2. Address Ptr Block — Отвечает за исполнение инструкций касаемо данных — прогулки по памяти, изменение значения в ячейке, работа с терминалом
  3. Блок логики, контролирующий работу машины

Сами блоки состоят из модулей: многоразрядных реверсивных счётчиков, модулей памяти, буферов и т.п. Все эти базовые кирпичики имеют три линии управления: сигнал ЗАПРОС(Request), флаг ЗАНЯТ(Busy) и флаг ГОТОВ(Ready). По сигналу ЗАПРОС, модуль счётчика, например, начнёт считать адрес новой инструкции. По сигналу ЗАПРОС, модуль памяти, например, начинает выгружать данные по новому адресу. Тут-то уж зачем? Ну, если у нас только ферритовая память — то это ни к чему, а если ферритовая память работает в роли кэша для накопителей на магнитной ленте — то при смене кэш-линеек время выборки может быть увеличено.

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

Это было придумано потому, что найти даже 30кбайт ферритовой памяти ОЧЕНЬ проблематично. Вместе с этим НМЛ СМ5300 позволяет записать на ленту несколько мегабайт. И либо мы делаем ферритовую память на очень малый объём данных или программ, либо начинаем веселье.

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

А если серьёзно — я ещё не пытался воспроизвести эту логику в SystemVerilog для эмулятора. Но хочу попробовать. На это он и эмулятор, но об этом позднее. Совершенно не представляю, насколько это реально будет собрать в железе. Вероятно, для отсчёта номера ячейки в кэше при загрузке данных придётся делать ещё один счётчик.

В итоге каждый узел работает в режиме запрос-ожидание-ответ. У блоков есть такие же сигналы. Но и логика их обработки сложнее. Не могу однозначно ответить на вопрос насколько такой подход лучше или хуже обычного секвенсора. Я решил использовать его из-за сложности конечных автоматов каждых блоков.

▍ Instruction Ptr Block




Этот блок содержит два счётчика, модуль памяти программ и логику работы с циклами. Первый счётчик (IP Counter) на базе 6 декатронов определяет номер инструкции, которая считывается из памяти программ.

В дополнение к нему идёт счётчик глубины вложенности циклов (Loop Counter) — сумматора в будущем компьютере нет, а значит, начало или конец тела текущего цикла придётся искать вручную, банально шагая счётчиком инструкций назад (или вперёд) до тех пор, пока не будет найдено начало именно нашего цикла. Трёхразрядного счётчика будет более чем достаточно — в brainfuck-программах, написанных людьми, даже больше 20-30 уровней вложенности циклов — редкость.

Блок выборки инструкций, получив от блока логики сигнал ЗАПРОС, должен выдать следующую инструкцию на выходе. Дальнейшие действия блока зависят от текущей исполняемой инструкции. Если она не является условной — т.е. одна из +-<>., — то счётчику инструкций достаточно сделать +1, зачитать новую инструкцию из памяти программ и выдать её на выходной буфер. Делать это, кстати, можно одновременно с исполнением текущей инструкции в блоке данных. Да, тёплый ламповый конвейер — к моменту завершения текущей операции мы сможем сразу начать новую.

Сложности начинаются с инструкциями границ цикла. Надо обработать условную операцию и либо выполнить инструкции в теле цикла, либо нет. Вариантов тут четыре. Допустим, есть следующий код цикла, реализующий операцию MOV — Мы будем делать +1 в ячейке n+1, и -1 в ячейке n до тех пор, пока ячейка n не равна нулю.

[>+<-]

При выполнении этого цикла может быть четыре варианта действий:

  1. Мы на инструкции [ и текущая ячейка не равна нулю — нужно выполнить тело цикла.
  2. Мы на инструкции ] и текущая ячейка не равна нулю — нужно вернуться в начало цикла, чтобы выполнить его ещё раз.
  3. Мы на инструкции [ и текущая ячейка равна нулю — нужно промотать тело цикла, не выполняя его.
  4. Мы на инструкции ] и текущая ячейка равна нулю — выполнение цикла завершено просто идём дальше

Их можно обобщить в два варианта развития событий:

  • При вариантах 1 и 4 компьютер просто продолжает выполнять инструкции друг за другом.
  • Варианты 2 и 3 требуют промотать тело цикла. Счётчик будет считать либо назад(для варианта 2) либо вперёд(3) в поисках ответной скобки цикла.

Чтобы промотать тело цикла, нужно пошагово изменять значение счётчика инструкций, делать выборку инструкции по этому адресу и Не подавая её на выходной буфер, смотреть, что же за инструкция сидит по этому адресу. Например, если мы начали с открывающей скобки [, и идём вперёд — то при нахождении закрывающей скобки] промотку можно считать завершённой. Но вот в процессе промотки мы наткнулись на ещё одну открывающую скобку [ — от вложенного цикла. Тут-то и пригодится счётчик глубины вложенностей. В самом начале промотки на нашей оригинальной открывающей скобе [ делаем ему +1 и потом будем делать +1 всякий раз, встречая открывающую скобку [, и -1 встречая закрывающую скобку ]. Как только после очередной закрывающей скобки ] значение счётчика станет равным нулю — поиск можно останавливать — цикл мы промотали. Точно так же это работает и в обратную сторону, разве что скобки меняются местами.


Поиск начала цикла слева. Пошагово передвигаемся назад, изменяя значение счётчика вложенностей циклов

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

▍ Data Ptr Block




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

Один счётчик(AP Counter) считающий от 0 до 29999, будет определять номер текущей ячейки данных. Для чистого brainfuck необходимо будет сделать сброс старшего счётчика в нуль после 2 и наоборот. Один декатрон легко установить в нужное значение. Сложно прогнать сигналы переноса через все разряды.

По адресу этого счётчика происходит выборка данных из ОЗУ в четвёртый счётчик — Data Counter. Он умеет считать от 0 до 255. т.е. мы загружаем в декатрон наше старое значение, делаем инкремент или декремент и выгружаем данные обратно в память. Или же — мы можем напечатать текущее значение в терминале, или, минуя декатронный счётчик — занести число из терминала сразу в ОЗУ. Так как в программах на brainfuck инструкции инкремента/декремента ячейки ОЗУ и значения, как правило, идут группами, то это не значит, что потребуется постоянно загружать/выгружать данные в счётчик и обратно. Этого можно избежать, добавив флаг занятости ОЗУ.

Допустим, кусок программы на brainfuck выглядит так:

>>>>>+++++<<<<<

Без использования флага занятости машина будет загружать данные в счётчик Data после каждой инструкции > или <. И выгружать данные после каждой операции + или -. Таким образом, будет 10 операций чтения и 5 операций записи. А это всё — время. С флагом занятости, ЭВМ сделает ровно по одной операции чтения и записи:

  1. После выполнения пяти инструкций > AP Counter увеличится на 5
  2. Перед выполнением инструкции + Проверка флага занятости покажет, что он не взят. Значит, перед операцией инкремента данных нужно загрузить эти данные в счётчик
  3. После выполнения пяти инструкций + Data Counter увеличится на 5
  4. Перед выполнением инструкции < Проверка флага занятости покажет, что он взят. Значит, необходимо сначала выгрузить данные из счётчика Data в ОЗУ
  5. После выполнения пяти инструкций < AP Counter уменьшится на 5 до начального значения


▍ Какова цена счётчиков?


Примерная компоновка плат будущей машины. Слева плата декатронного счётчика, справа — модуль ламповой логики

На всю машину потребуется 17 декатронов. Из них, только 3 декатрона счётчика данных потребуют всю обвязку. Остальные три счётчика не требуют полной схемы записи. Достаточно дешёвой схемы сброса декатрона в нуль. Хотя для старшего разряда счётчика адреса требуется сбрасывать декатрон в 0 или 2 — чтобы после декремента нуля получить 29999.
Счётчик глубины вложенностей не требует даже схемы чтения! Достаточно лишь иметь один-единственный выход НУЛЬ.

По предварительным расчётам, на 4 счётчика требуется 214 сдвоенных диодов и 247 сдвоенных триодов. 461 сверхминиатюрная лампа (6Х7Б и 6Н17Б) требует 165А накала (1.1кВт) и до 1кВт анодных напряжений. Я постараюсь как можно сильнее снизить потребляемую мощность управления, так как из-за позиционного кода большая часть ламп будет находиться в неактивном режиме. Но 2кВт — есть 2кВт… А ведь это только половина будущей ламповой машины.

Необходимый, но недостаточный запас сверхминиатюрных ламп

Весь компьютер будет состоять из унифицированных плат размером 140х200мм, где на каждой плате будет размещаться по несколько логических элементов. Снизу располагается один или два разъёма ГРПМШ1-31, ответная часть которого предназначена для навесного монтажа. Как и в релейном компьютере эти платы будут вставляться в корзину и коммутироваться между собой месивом из проводов. В принципе все блоки ламповой машины будут выглядеть одинаково — 4U корпус длиной около 1000мм с откидными верхней и нижней крышками. В задней части — трансформаторные источники питания — каждый блок по максимуму будет стараться сам обеспечить себя питанием. Платы со сверхминиатюрными лампами будут установлены в три ряда, по 10-16 штук в каждом. Итого теоретическая ёмкость одного корпуса — до 1100 сверхминиатюрных ламп. На практике это число будет порядка 500 ламп на блок. Для качественного охлаждения в корпус будут встроены мощные серверные вентиляторы, продувающие его спереди назад. Выплюнуть 2кВт тепла из серверного корпуса — не очень сложная задача. Сложнее найти три раза по 2кВт в домашней розетке.

Примерная компоновка блока будущей машины

▍ Система команд


Переходим к системе команд. Первое, самое важное требование — чтобы инструкции в нём в точности соответствовали языку brainfuck. Второе — извне инструкции подаются ASCII символами — т.е. в натуральном виде, без трансляции и компиляции. Третье — внутри машина оперирует опкодами шириной в 4 бит, так как байта для 8 инструкций много, а 3 бит — мало. Надо ведь ещё и служебные инструкции насыпать. Как и в релейном компьютере, служебные инструкции здесь только те, что можно реализовать на разработанной архитектуре, но которые могут сыграть на руку при работе с машиной.

В итоге имеем следующие группы инструкций:

  • +-<>[]., — базовые 8 инструкций языка brainfuck.
  • {} — инструкции работы с циклами, но за условие берётся сигнал AP_Counter->isZero.
  • N(NOP) — пустая операция. Можно использовать для выравнивания кэш-линеек.
  • H(HALT) — операция останова машины. Добавляется либо в конце программы, либо в любом другом месте в роли точки останова — машину можно пустить дальше кнопкой на панели оператора. Необязательна, но желательна — без неё ЭВМ будет бежать по памяти программ вперёд до посинения.
  • RILA0 — инструкции сброса всей машины (Reset) или отдельных её счётчиков в ноль — соответственно, для IP, Loop, AP и Data Counter. Последнее можно использовать для быстрой очистки ячейки памяти вместо выполнения инструкций[-] — это самая базовая оптимизация в большинстве программных эмуляторов.
  • GS(Get/Set) инструкция явно копирует данные из памяти в счётчик и обратно, не изменяя флаг занятости.
  • DB(Debug/Brainfuck). Эти две инструкции переключают наборы команд из-за того, что перечисленные выше инструкции суммарно не влезут в 4 бит… Всего их при таком подходе может быть 30 штук.

Тут не хватает ещё нескольких инструкций, которые появятся по факту разработки, но теперь пара фокусов, которые дают новые инструкции:

Например, этот код пройдётся по всем ячейкам памяти данных и очистит их. Неплохой кусок кода для бутлоадера, не так ли? На чистом brainfuck это не так-то просто реализовать.

D //Выбор Debug ISA
A0> //Установка счётчика адреса в нуль, обнуление текущей ячейки данных и выбор следующей
  {   // Пока текущее значение счётчика адреса не равно нулю:
    0 >//Обнуление текущей ячейки данных и выбор следующей
  }
  B //Выбор Brainfuck ISA

А вот такая операция позволит копировать данные из одной ячейки в другую:

>>>> //Доходим до ячейки данных источника
G //Записываем значение из ячейки памяти в счётчик
>>>> //идём к ячейке данных приёмника
S //записываем значение из счётчика в ячейку памяти.

Можно ещё помнить, что в счётчике остаётся последнее значение, а значит, можно сделать и вот так:

+++++++>>>> //набили в счётчике число, переместились к другой ячейке и
S //записываем это же число из счётчика в другую ячейку памяти.

Знаете, как выглядит операция копирования на чистом brainfuck?

[->+>+<<]>>[-<<+>>]

Два цикла! Первый цикл уничтожает исходную ячейку, но создаёт две её копии. Второй — уничтожая одну копию, восстанавливает значение в исходной ячейке.

Но ещё раз отмечу — ламповая ЭВМ будет способна исполнить оригинальный код. Но разработанная архитектура позволяет сделать операцию копирования со сложностью O(1) вместо O(N) без использования лишних ячеек памяти и сэкономив пару десятков тысяч инструкций! Для машины, у которой общая производительность вряд ли достигнет 1MIPS — это существенно. У BrainfuckPC такого не было и не могло быть реализовано.

Эмулятор


Кусок RTL-синтеза блока инструкций. Функционально он работает

Релейный компьютер был очень простым — блок сумматора, четыре регистра, коммутаторы сигнала, и всё. Его блок логики представляет собой 16-ти позиционный секвенсор, а выполнение каждой инструкции выглядит как «t=1: Подать лог.1 на линию записи в регистр А, t=3: снять лог.1 на линии, t=5: подать лог.1 на линию записи в регистр Б, t=7: снять лог.1 на линии». И всё в таком духе. Не было никаких сомнений в его работоспособности, хотя и пришлось повозиться с таймингами из-за принципа работы секвенсора. Вся логика работы умещалась в голове. Другое дело, что с начала сборки и до первого включения блоков, прошло больше года.

С ламповым компьютером так просто уже не будет. Вся эта асинхронная, висящая на линиях ЗАПРОС-ОТВЕТ логика в голову уже не помещается. Просто нарисовать на листочке секвенсор с конечными автоматами, просчитав задержки — уже не получится. Нужна тяжёлая артиллерия. Имя ей — SystemVerilog

Поэтому первым физическим блоком ламповой ЭВМ будет её эмулятор на ПЛИС. Он решает несколько важных задач.

Во-первых, он позволяет создать функциональную модель будущего компьютера. У меня есть программная модель на С++, но это совсем не то что нужно. Функциональная модель позволяет сэмулировать поведение всех отдельных модулей ЭВМ. Банальный дебаг всех конечных автоматов, режимов выполнения инструкций и всего такого! Отладить будущую архитектуру, улучшить тайминги и вот это вот всё. Я не знаю детальной структурной схемы будущей машины и разработать её мне и помогает эмулятор. После создания функциональной модели эмулятор уже будет способен выполнять программы, а значит, от первого включения машины меня отделяет пара тысяч строк verilog-кода.

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

Плата ввода/вывода для эмулятора. 8 каналов на вход, 8 на выход. Поддержка до 8 плат на одном шлейфе и до двух шлейфов на эмулятор. Всего 128+128 каналов

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

DekatronPC challenge


Для первой статьи цикла по ламповой ЭВМ, пожалуй, хватит. Признаюсь — я очень много времени потратил на осознание того, как эта машина в принципе будет работать и выглядеть. Потому что пока я сам не пойму, что и как я буду делать — начинать страшно. Сейчас я знаю, как будут выглядеть блоки машины, модули ламповой логики, как всё это в целом будет взаимодействовать, но мне нужно преодолеть два важных этапа — Доделать эмулятор и собрать экспериментальную декатронную ячейку. Ну и подключить одно к другому, конечно же. После этого начнётся этап непосредственной сборки машины. Схемотехника отдельных модулей простая, сиди себе собирай сотню-другую печатных плат 140х200мм и сращивай всё воедино. Там уже никакой магии. У меня есть около тысячи сверхминиатюрных ламп, чего, как мне кажется, достаточно для реализации большей части машины. Но если у вас где-то завалялись сверхминиатюрки, особенно 6Н16Б и 6Н17Б — буду очень рад пополнить свои запасы. Это же касается и накальных трансформаторов — у меня их примерно на 2кВт, при расчётных 3.5.

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

За бортом данной статьи осталась тема ввода программ в компьютер. Я очень хочу приладить к ней считыватели перфолент, но пока ещё не до конца придумал, как я буду, собственно, заносить её в память программ. Хочется иметь возможность делать это одной кнопкой.

Из предположений: у меня должен быть некоторый бутлоадер в самом конце адресного пространства программ. Например, 10-20 инструкций начиная с адреса 999980. Сначала пойдёт кусок кода с очисткой памяти, что был выше, потом магический символ, отключающий выполнение инструкций, но оставляющий работу IP счётчика, который уже досчитал до 0. Теперь с каждым сигналом тактирования от считывателя перфолент новая инструкция записывается в память программ, а счётчик делает +1 до тех пор, пока с перфоленты не придёт команда СТОП. Теперь программа в памяти, нажимаем сброс счётчика инструкций в нуль и запускаем на исполнение.

Разумеется, у меня есть и накопители на магнитных лентах СМ5300.01, и пара считывателей перфолент, в т.ч. электромеханический, перфоратор перфолент, электромеханическая печатная машинка CONSUL 260, которая отлично подойдёт в роли терминала и, конечно же, кубы ферритовой памяти.

Кубы памяти типа КП128/17. 256 байт в каждом. 16 штук

Тем более что кубы памяти у меня особые — небольшие, залитые компаудом микросборки, внутри которых расположена стопка многоотверстных ферритовых пластин — младший брат памяти на ферритовых кольцах. Каждый такой кубик содержит безумные 256 байт данных. Предполагается, что на память программ уйдёт 6 модулей — в виде трёх кэш-линеек по два куба и 1024 инструкции в каждой кэш-линейке; а на память данных — 9 модулей — по три куба в трёх линейках и 768 ячеек данных в каждой кэш-линейке. К сожалению, кроме справочного листа на кубы, у меня больше ничего на них нет. Скорее всего, эмулятор будет в составе ЭВМ очень и очень долго и последним собранным блоком будет память.

Вместо заключения


image
Классическое зачем

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

Из прагматичных знаний лично я рекомендую следующие источники вдохновения:

  1. Й. Янсен Курс цифровой электроники в 4-х томах 1987.
  2. Харрис и Харрис — Цифровая схемотехника и архитектура компьютера.
  3. Цифровой синтез практический курс. под. ред. Романова и Панчула.
  4. Шевкопляс. Микропроцессорные структуры. Инженерные решения 1990.
  5. Handbook of electronic control circuits. By John Markus. 1959.

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 112: ↑112 и ↓0+112
Комментарии49

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds