Троичные вычисления
Итак, продолжаю цикл статей о разработке троичного вычислителя. В прошлый раз мы познакомились с самым базовым элементом: троичным (де-)мультиплексором, а также на его базе построили полу- и полный сумматор. В этот раз речь пойдёт о ячейках памяти.
В прошлой статье я подробно рассказал для чего мне это нужно: это будет демонстрационная железка. Не поленитесь, ознакомьтесь с моей мотивацией.
Итак, вот список опубликованных статей цикла (будет обновляться):
- Считаем до трёх: раз (троичный мультиплексор и сумматоры)
- Считаем до трёх: два (память)
- Считаем до трёх: три (счётчики)
- Считаем до трёх: четыре (однотритный вычислитель и система команд трёхтритного)
Напоминаю, что единственным строительным блоком вычислителя будет троичный мультиплексор. Вот фотография оригинального тримукса дизайна Александра Шабаршина и моего исполнения на поверхностном монтаже. Одна такая плата несёт на себе два троичных (де-)мультиплексора:
![](https://habrastorage.org/getpro/habr/post_images/bba/ae2/8a9/bbaae28a97ee41fbbdbad0f4480201ea.jpg)
Мой вариант тримукса для поверхностного монтажа задумывался для относительно лёгкого воспроизведения «на коленке»: плата хоть и двухсторонняя, но содержит всего 12 переходных отверстий. К слову сказать, на форуме nedopc.org пробегал вариант для сквозного монтажа без единого переходного отверстия:
![](https://habrastorage.org/getpro/habr/post_images/6f0/8df/905/6f08df905238b1e2b0a9bbf1dc224c3b.png)
Впрочем, он по-прежнему требует сверлить отверстия для выводов микросхем, так что мой вариант экономичнее :)
trimuxIO
Моя цель — не теоретизирование, но постройка вполне осязаемой железки. На данный момент я обзавёлся некоторым количеством мультиплексоров, которые испытываю на макетках. В прошлый раз все входы испытываемых схем из себя представляли джамперы на макетках, а выходы набор светодидов на той же самой макетке. Это довольно неудобно (особенно перетыкать входы), поэтому я усмотрел у Александра примерно такой дизайн одного входа-выхода:
![](https://habrastorage.org/getpro/habr/post_images/200/2ef/41f/2002ef41f7d2f4e04ed628f67bf403a6.png)
Каждый вход-выход несёт на себе один трёхпозиционный переключатель, который по умолчанию (среднее положение) слегка подтянут к 0V. Если пин используется для индикации выхода тримукса, то переключатель должен быть оставлен в среднем положении, и тогда тримукс перетянет слабую подтяжку к 0V. Эмиттерный повторитель обеспечивает надёжную индикацию даже самых слабых сигналов.
Если же пин нужно использовать на вход, то переключатель может быть подключен либо к +5V, либо к -5V. Резистор на 150Ohm защищает схему от короткого замыкания.
Тест-плата входов-выходов несёт на себе 9 абсолютно одинаковых схем:
![](https://habrastorage.org/getpro/habr/post_images/8d1/219/d4f/8d1219d4f47f34b31006184a371ce6c5.png)
Плата предназначена для лёгкого воспроизведения дома: она однослойная и не содержит ни одной перемычки. А вот так плата входа-выхода может быть подключена для тестирования, например, статической ячейки памяти:
![](https://habrastorage.org/getpro/habr/post_images/f68/f3d/f5d/f68f3df5d3ce3226a490bf539caf60e1.jpg)
Здесь три входа: C, A, B и один выход Q.
Статическая ячейка памяти (троичный триггер с запоминанием по уровню)
Давайте подключим два мультиплексора (напоминаю, они влезают на одну платку тримукса) следующим образом:
![](https://habrastorage.org/getpro/habr/post_images/4b0/283/fc4/4b0283fc40fb08c16ef1142a29284f2c.png)
Давайте договоримся о терминологии: тактируемые триггеры делятся на управляемые уровнем и управляемые фронтом. Сейчас мы говорим об управлении уровнем, а это означает, что при одном уровне тактового сигнала C (-1 или 1) триггер воспринимает входные сигналы (A или B, соответственно), а при другом (0) не воспринимает и остаётся в неизменном положении.
Наша схема представляет собой два мультиплексора, второй мультиплексор представляет собой просто прозрачный буфер, а первый (в зависимости от тактового сигнала C) выдаёт на вход второго либо А, либо B, либо сам выход буфера! Это означает следующее поведение: при C=-1 выход Q замыкается на вход A, при C=1 выход Q замыкается на вход B, а при C=0 выход Q поддерживается постоянным и входы A и B просто игнорируются. В тексте это может быть сумбурно, поэтому посмотрите следующее видео:
Динамическая ячейка памяти: троичный триггер с управлением фронтом
В отличие от управления уровнем, при управлении фронтом разрешение на переключение триггера даётся только в момент перепада тактового сигнала. В остальное время независимо от уровня тактового сигнала триггер не воспринимает входные сигналы и остаётся в неизменном состоянии.
Экскурс в хорошо изученную область
Давайте на минутку совершим путешествие в двоичный (бррр) мир, чтобы было чуть понятнее. В русскоязычной литературе ко всем подобным схемам применяется слово «триггер» (поправьте меня, я маску-то только нашёл). Двоичный триггер с управлением по уровню называется gated D-latch. Грубо говоря, у него есть два входа: D (данные) и E (enable). Единственный выход Q равен D если E=1, и сохраняет своё значение если E=0.
![](https://habrastorage.org/getpro/habr/post_images/f19/4f3/f2a/f194f3f2a5e42832aed2ecd55cb340e1.gif)
Триггер со срабатыванием по фронту (flip-flop) может быть построен из двух обычных защёлкок (gated D-latch) и одного инвертера:
Эта схема называется Master-slave edge-triggered D flip-flop.
Назад в троичный мир или терра (почти) инкогнита
Если мы хотим получить срабатывание по фронту тактирующего сигнала, мы точно так же, как и в двоичном мире, можем использовать две троичные защёлки и один эквивалент двоичного инвертера, как на этой схеме:
![](https://habrastorage.org/getpro/habr/post_images/a65/57d/da5/a6557dda59fdbd91116ddbb38ca2ceec.png)
Наша динамическая ячейка памяти имеет два входа: C и Am; она имеет один выход Qs. В двоичном мире инвертер генерирует второй сигнал со сдвинутой фазой, который тактирует ведомую защёлку. В нашей троичной схеме тактирующий сигнал расщепляется на два: min(C,0) и max(C,0), каждый из которых тактирует свою защёлку. Для того, чтобы сигнал Am дошёл до выхода Qs, нам необходимо подряд два восходящих фронта на сигнале C:
![](https://habrastorage.org/getpro/habr/post_images/fbe/c0c/04c/fbec0c04c6a0ec0685d9393a80adbb98.png)
Обратите внимание, что сразу после включения схемы до того, как сигнал С заметёт от минус единицы до единицы, выходной сигнал Qs имеет неопределённое значение. Инициализируйте свои переменные :)
К слову, обратите внимание, что и у ведущей, и у ведомой защёлок один из входов не используется. Это можно применить для быстрой инициализации памяти, но об этом в следующий раз.
Вот соответствующиее видео работы ячейки памяти с динамическим управлением:
Заключение
Мы рассмотрели два варианта ячеек памяти. Ячейка памяти с динамическим управлением — это основной элемент троичного счётчика, который мы рассмотрим в следующий раз. Потом поговорим про АЛУ и тому подобное. Разумеется, получить даже один килотрит памяти подобным образом — весьма затратное (если делать «на коленке») занятие, но поскольку у меня железяка будет предназначена для демонстрационных целей и с гораздо меньшим количеством памяти, то это не так и страшно.
Enjoy!