- PVSM.RU - https://www.pvsm.ru -
Наконец-то можно запустить в моём компьютере на электромагнитных реле программу длиннее одной инструкции. Сейчас в нём есть ПЗУ на 8 команд, процессор с АЛУ и 8 восьмибитных регистров (один из которых PC).
Всего процессор поддерживает 5 групп инструкций: Арифметико-логические операции (ALU), Загрузка числа в регистр (MOVI), пересылка между регистрами (MOV), Остановка работы (HALT), Работа с памятью (LDST). Но есть нюансы…
Кроме этих 5 групп, в описании [1] зарезервирован код для операции NOP, хотя она никак и не декодируется процессором. В реальности все незадействованные комбинации будут работать как NOP.
Что можно сделать с таким набором команд, если там нет даже переходов? Так как PC входит в регистровый файл наравне с остальными регистрами (A, B, C, D, M, S, L), то и все операции с ним делаются так же, как и с другими регистрами. Тогда загрузка целого числа в PC — это переход по адресу.
Два поля инструкции MOVI — это регистр и 8-битный непосредственный операнд. Все команды у меня 16-битные для упрощения загрузки их из памяти, декодирования, а также программирования в машинном коде. Код инструкции MOVI выглядит так: 1cccLddd iiiiiiii
Поле i — записываемое в регистр значение, поле d — какой регистр изменяется, 1 — по этому биту мы понимаем, что перед нами именно инструкция MOVI.
Остаётся 4 бита. 3 из них ( c ) отданы под условия при которых инструкция выполняется. Всего задействованы 7 комбинаций: переход всегда, по включенному/выключенному флагу нуля, флагу переноса, флагу знака. Восьмая комбинация не используется.
Последний оставшийся бит (L) позволяет реализовать команду вызова подпрограммы. Если этот бит установлен, то инструкция записывает в регистр L адрес следующей инструкции. Получается как во всяких ARM и MIPS — вызов процедуры это просто переход с записью адреса следующей инструкции в специальный регистр. Чтобы из процедуры вернуться, надо это это значение снова скопировать в PC. Поэтому никакой отдельной команды RET нам не нужно.
Но тогда понадобится инструкция копирования одного регистра в другой — MOV. Вообще-то её можно было бы реализовать с помощью АЛУ (например, как ADD D, S, 0 или OR D, S, S), но я сразу об этом не подумал. Плюс в получившемся решении тоже есть — меньше изнашиваются реле в модуле АЛУ, так как оно задействуется только для арифметических и логических операций, а также не портятся флаги при обычных пересылках.
Сама команда MOV ничем не примечательна, кроме одного побочного эффекта, связанного с дизайном схемы компьютера. Алгоритм её работы такой: обнулить регистр-приёмник, подключить регистр-источник и приёмник к одной шине, чтобы у приёмника тоже включились реле там, где они уже включены в источнике. Из-за этого команды пересылки в регистр из самого себя будут работать не так, как NOP, а как обнуление регистра.
Самое интересное спрятано в этой категории — вся арифметика и логические операции, но здесь определением типа операции занимается непосредственно АЛУ. На входе у него код операции, 2 регистра или регистр + непосредственное значение, на выходе — один регистр. Чтобы не получилось как с MOV, АЛУ внутри содержит теневой регистр, в который записывается результат вычислений. Поэтому операндами арифметико-логических команд могут быть любые регистры в любых сочетаниях.
Общий формат команды такой:
01bbbddd ixxxryyy - бинарные операции ADD, ADC, SUB, SBC, AND, OR, XOR
01111ddd -xxxruu0 - унарные операции NOT, SHR, ROR, RCR
Здесь d — код выходного регистра, x, y — коды входных регистров, b — тип бинарной операции, u — тип унарной операции. Если установлен флаг i, то три бита yyy используются как непосредственный второй операнд команды. Так удобнее прибавлять/вычитать небольшие константы.
Сдвиговые операции работают как у Z80, а не как у i386 — сдвигают только на один бит. Сдвига влево нет, потому что можно обойтись сложением для всего, кроме циклического сдвига. Ну а циклический сдвиг влево делается за две инструкции:
ADD A, A, A
ADC A, A, 0
АЛУ хранит три флага последней операции — перенос, ноль, знак. Причём меняются они только тогда, когда АЛУ выполняет очередную команду и не портятся остальными инструкциями. При желании флаги можно вернуть даже из функции.
Не всегда удобно перезаписывать регистр, чтобы получить значения флагов. Чтобы сделать команду типа CMP или TST как у i386, надо сбросить бит r в коде инструкции АЛУ. Тогда результат вычисления останется только в теневом регистре (чтобы можно было посчитать флаги), а обычные регистры не поменяются.
HALT — команда для остановки работы компьютера. Останавливается работа тактового генератора, всё замирает. Можно продолжить работу со следующей команды, нажав кнопку «старт».
Ещё есть пара инструкций для работы с памятью (чтение/запись по адресу в регистре и по непосредственному адресу). Но так как из памяти сейчас есть только 8 слов ПЗУ, то толку от этих инструкций пока немного.
ПЗУ по задумке занимает 64 адреса из всей восьмибитной шины. По каждому адресу можно считывать 16 бит при выборке команды или 8 младших бит этой команды при выборке данных.
Ячейка ПЗУ состоит из двух DIP-переключателей. Так можно легко набирать программу, а также проверять что «записано» в ячейках. Напротив каждой инструкции есть светодиод для наблюдения за ходом выполнения программы.
Проблема «неожиданно» возникла, когда я забыл учесть, что ток может идти через ключ в обе стороны. Поэтому при выборке одной ячейки к шине могли подключиться сразу несколько других:
Пришлось заказать новый комплект плат, в которых я уже предусмотрел место под диоды. Правда пайка теперь занимает намного больше времени, потому что на каждые 8 ячеек ПЗУ надо припаять 128 SMD-диодов.
Пока я написал только программу для вычисления чисел Фибоначчи:
1000 0001 0000 0001 00: movi B, 1
0100 1010 0001 1000 01: add C, B, A
0001 1000 0001 0000 02: mov A, B
0001 1001 0010 0000 03: mov B, C
1000 0111 0000 0001 04: jmp 01
Заняло всего 5 слов из имеющихся 8, а значит можно придумать программу и посложнее, но интересных идей пока нет.
» Страница проекта на github [2]
» Подробное описание системы команд [1]
» Первая часть описания [3]
» Вторая часть описания [4]
» Третья часть описания [5]
Автор: Dovgaluk
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/nenormal-noe-programmirovanie/258363
Ссылки в тексте:
[1] описании: https://github.com/Dovgalyuk/Relay/wiki/Architecture
[2] Страница проекта на github: https://github.com/Dovgalyuk/Relay
[3] Первая часть описания: https://habrahabr.ru/post/220865/
[4] Вторая часть описания: https://habrahabr.ru/post/258337/
[5] Третья часть описания: https://habrahabr.ru/post/318500/
[6] Источник: https://habrahabr.ru/post/331208/
Нажмите здесь для печати.