Вложений: 2
x80 - RISC-ядро с интуитивной системой команд для x80-CISC
Eсли x80 мною разрабатывается долго и нудно как CISC с системой команд интуитивного кодирования, то данный здесь процессор представляется RISC-архитектурой со «сквозным интуитивным» набором команд.
Процессор выполнен в русле акына - «что вижу, то имею» - WYSYWYG на уровне байт-кода. Тем самым, для программирования на нём не нужен никакой транслятор.
Система команд- 0x00 означает HLT (как и в x80)
- 0x01…0x09, 0x10…0x19, 0x20…0x29, 0x30…0x39, 0x40…0x49, 0x50…0x59, 0x60…0x69, 0x70…0x79, 0x80…0x89, 0x90…0x99 - непосредственный двоично-десятичный операнд 1…99, заносимый в текущий аккумулятор двоичной величиной 0x01…0x63
- 0x0A - ADD; 0x0B - SUB; 0x0E - EOR
- 0x0C - AND (Conjunction)
- 0x0D - OR (Disjunction)
- 0x0F - CMP (Flags)
- 0xA1…0xA9 - выбор индекса регистра A (A₁…A₉)
- 0xB1…0xB9 - выбор индекса регистра B (B₁…B₉)
- 0xC1…0xC9 - выбор индекса регистра C (C₁…C₉)
- 0xAA / 0xAB / 0xAC - выбор группы операндов: A,A; A,B; A,C
- 0xBA / 0xBB / 0xBC - выбор группы операндов: B,A; B,B; B,C
- 0xCA / 0xCB / 0xCC - выбор группы операндов: C,A; C,B; C,C
- 0xAD - занесение значений операндов в регистр адреса ADdress
- 0xBE - извлечение данных из буфера (Buffer Extract: register = [ADdress])
- 0xBF - заполнение буфера данными (Buffer Fill: [ADdress] = register)
- 0xCF - инверсия флага CF (Carry Flag)
- 0xD0 - метка цикла DO (ADDR = IP)
- 0xDA / 0xDB / 0xDC / 0xDD / 0xDE / 0xDF - условное выполнение (Do if Among / Bigger / Carry / Discarry / Equal / Fiction)
- 0xEB - переход на адрес (Execute Buffer pointed by ADdress)
То есть, как и в x80, здесь та же самая концепция: Какими символами машинный код кодируется, такая и аббревиатура команды.
Практически, это и есть вся система команд!
(Инструкция EB комбинированная: Вместе с переходом на ADdress, она помещает адрес возврата в ADdress. А так как этот регистр доступен только на запись командой AD, то сбрасываются индексы регистров на B₀ и C₀, через которые можно и прочитать регистр ADdress.)
Например, такая программа:
Код:
// Исходный код
*(BYTE *)0x76D0 = '*';
// Промежуточный код
*(BYTE *)MAKEWORD(0xD0, 0x76) = 0x2A;
// Развёрнутый код
*(BYTE *)(AD = MAKEWORD(B8 = 52 << 2, A9 = 59 << 1)) = (A1 = 40);
кодируется таким дампом:
Код:
.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .A .B .C .D .E .F
0000 A9 B8 AA 59 0A BB 52 0A 0A AB AD A1 40 BF 00 ..
И по байтам её можно представить вот так:
Код:
0000 A9 : A₉ ; Using A#9
0001 B8 : B₈ ; Using B#8
0002 AA : A₉,A₉ ; Reciever A#9, Translator A#9
0003 59 :SET A₉,59 ; Load 59 to receiver A#9
0004 0A :ADD A₉,A₉ ; A₉=118=0x76
0005 BB : B₈,B₈ ; Receiver B#8, Translator B#8
0006 52 :SET B₈,52 ; Load 52 to receiver B#8
0007 0A :ADD B₈,B₈ ; B₈=104=0x68
0008 0A :ADD B₈,B₈ ; B₈=208=0xD0
0009 AB : A₉,B₈ ; Hi-Byte A#9, Lo-Byte B#8
000A AD :ADR A₉,B₈ ; ADDR=MAKEWORD(B₈,A₉)
000B A1 : A₁ ; Receiver A#1
000C 40 :SET A₁,40 ; A₁ = 0x2A = '*'
000D BF :BF A₁ ; Buffer Flush
000E 00 :HLT ; Halt
Ниже в архиве исходные файлы для LogiSim.
У кого симулятора нет - снимок схемы.
(Сначала я начал писать JavaScript-эмулятор. Но идея задуманного процессора показалась настолько простой, что вместо часов писанины в Блокноте я потратил недели в LogiSim и остался доволен.
Потому, могу огорчить далёких от электроники пользователей: Эмулятора нет, так как занимаюсь эмулятором x80 и нет сил заниматься другими проектами! Хотя если я решу таки строить x80 на RISC-ядре, то эмулятор данного простейшего дружелюбного процессора войдёт в состав эмулятора.)
Некоторые нюансы
Сначала схема была выполнена по Гарвадской архитектуре, код программы хранился в отдельном банке памяти и на выполнение одной инструкции уходило по одному такту. Естественно, подобных готовых схем в интернете пруд пруди и я решил немного усложнить себе жизнь. Собственно, Пристонскую архитектуру работы с памятью я реализовывал несколько недель, так как очень долго въезжал в тему и отлаживал схемы. Естественно, я не пользовался никаким готовыми решения и гордо шагал по граблям!
Регистровый файл выполнен максимально развёрнуто из трёх дешифраторов и 27 регистров. Опять таки, можно было просто использовать готовые микросхемы памяти, но это было скучно и хотелось сделать максимально развёрнутый вариант процессора, где всё элементарно, понятно и просто, где каждый регистр подсвечивается лампочкой и может иметь отдельную шину данных для управления каким-нибудь устройством.
То есть, если собрать данный процессор собачником на ТТЛ-рассыпухе, то можно сократить размер регистрового файла и регистр C7 использовать драйвером двигателей, а регистр B6 заменить джойстиком!
Дешифратор команд выполнен так, чтобы обойтись одним вентилем 3-ИЛИ на команду. Тем самым, система команд легко наращивается программированием ПЗУ с добавлением любой группы команд в любой участок таблицы. Всего можно закодировать 24 различные группы команд. В схеме используется лишь 12.
Особенностью системы команд является именно сквозное смысловое кодирование, где шестнадцатеричное представление команды напоминает аббревиатуру команды. Если бы ни стремление достичь этого, данную схему я бы просто не взялся разрабатывать!
Это нужно понимать, если решите добавлять свои команды/!\
Была идея добавить ещё группу команд - 0x1A…0x1F, 0x2A…0x2F, 0x3A…0x3F, … … … … …, 0x9A…0x9F.
Они могут служить для повышения гибкости АЛУ-операций, где цифра выбирает индекс регистра-источника.
Например, сейчас нельзя выполнить сложение двух регистров одной группы, типа «ADD A₆,A₁».
Чтобы разрешить данные операции, можно было бы закодировать эту инструкцию кодом 0x1A: 0xAA 0xA6 0x1A.
Но, это требует добавления дополнительных мультиплексеров и усложняет схему.
А так как данная схема выполнена в стиле простоты и минимализма, то данной группы операций в ней не предусмотрено.
P.S.: Тем самым, как автор CISC-системы команд с эстетическим расположением инструкций, я реализовал и RISC-вариант с эстетическим набором команд.
Это я к тому, что и простое можно сделать красивым, не уродуя таблицу команд в угоду каких-то аппаратных издержек.
И на ТТЛ-макетке такой процессор можно собрать при практическом желании.
Вложений: 2
x80-RISC: Более инженерно-художественный вариант
Пoлностью перерисовал всю схему с нуля, потратив трое суток.
Теперь, вся схема чётко разбита на разные узлы.
- «Регистровый файл»: Содержит 30 РОН, среди которых 3 особых
- «Выборка кода/данных»: Считывает код команды, считывает/записывает данные
- «Дешифратор Команд»: Пока декодирует 10 разных групп команд
- «АЛУ»: Совершает 5 действий
- «Условный блок»: Пропускает следующую команду, если условие ложно
Система команд чуточку изменилась, утратив адресную команду «AD» и «CMP», но АЛУ-операции напрямую индексируют источник.
Схема более лучше спланирована с нуля и нарисована с третьей попытки. С большого расстояния выглядит красиво и напооминает кристалл микросхемы.
Теперь A₀ хранит флаги статуса АЛУ.
А регистры B₀ и C₀ хранят старший и младший байты соответственно, где B₀ - Base, C₀ - Counter.
Теперь, двоично-десятичные числа 1…99 не просто помещаются в активный регистр, а дополняют его через сложение.
Например, такие трюки:
Код:
AA A5 5E 6E :MOV A5,A6 - 8 тактов
---------------------------
AA :USE A ,A
A5 :USE A5,A5
5E :XOR A5,A5
6E :XOR A5,A6
BB B7 7E 85 85 85:MOV B7,255 - 12 тактов
----------------------------
BB :USE B ,B
B7 :USE B7,B7
7E :XOR B7,B7
85 :ADD B7,85
85 :ADD B7,85
85:ADD B7,85
Схема выполнена в максимально синхронном стиле и визуально получилась достаточно красивой!
P.S.: Тем самым, я убедился, что система команд может быть интуитивно прозрачной, простой и вполне достаточной!
Вложений: 2
x80-RISC: Стабильный инженерно-художественный вариант
Всe эти дни я усердно работал над своим RISC-процессором.
Упростил его до предела в рамках выбранной концепции.
Теперь основных групп команд сократилось до девяти, включая группу АЛУ.
Регистровый файл расширен с трёх до четырёх групп регистров общего назначения.
Четвёртая D-группа представляется внешними устройствами - Devices, что позволяет обращаться к устройствам типа клавиатура или джойстик непосредственно и в скором порядке, как кэш-периферия первого уровня с мгновенным доступом. Более медленные устройства требуется проецировать в адресное пространство памяти.
Тем самым, процессор теоретически пригоден для построения любого автомата, типа «Ну, Погоди!», «Тетриса» или «Лунохода».
Конечно, демонстрационный код довольно прост и скуден. Но он демонстрирует базовые возможности процессора и взаимодействие с периферией.
В архиве имеется также HTML-файл дизассемблера, который поможет поверхностно вникнуть в принципы кодирования команд.
Код:
Система команд процессорного устройства разрабатывалась максимально прозрачной
для понимания на уровне машинного кода в своём шестнадцатеричном представлении
как есть визуальным сочетанием своих нибблов в форме элементарных аббревиатур.
Кодирование алгоритма малой степени сложности доступно пользователю с базовыми
навыками редактирования таблиц дампа и не представляет особой сложности в силу
максимально осмысленного кодирования всех инструкций в шестнадцатеричном виде.
------------------------------------------------------------------------------
|Код команд / диапазоны|Группа |Описания, замечания, комментарий
-----------------------|----------|-------------------------------------------
00 |HLT |Прекращение счёта указателем команд IP
01-99 |ADD Ri,BCD|Двоично-десятичное накопление в регистр
0A-9F |ALU Ri,Tk |Операция АЛУ с комбинацией аргументов
A0-A9 B0-B9 C0-C9 D0-D9|REG Rn |Установка индекса активного регистра группы
AA-AD BA-BD CA-CD DA-DD|ARG Ri,Tj |Выбор комбинации аргументов операциям АЛУ
AE BE CE DE |EXT Ri |Экстракция данных из внешнего ОЗУ в регистр
AF BF CF DF |FIX Ri |Фиксация значения регистра во внешнее ОЗУ
E0-E7 |EX0-7 |Переход на адрес 0xE000-0xE700
E8-EF |Ecnd |Выполнение следующей команды по условию
F0 |FIN |Завершение с переходом на адрес Базы:Счёта
F1-FF |FN1-15 |Переход на адрес 0xF000-0xFF00
------------------------------------------------------------------------------
(n - устанавливаемый индекс, указанный битами команды)
(i или j - индекс, установленный раннее)
(k - индекс регистра временно берётся из старшего ниббла кода команды)
Группы регистров A0-A9, B0-B9 и C0-C9 составляют внутренний регистровый файл с
безусловным доступом к ним на программном уровне. Регистры B0-B9 хранят "Базу"
для обращения к памяти блоком в 256 байт, а регистры C0-C9 - счёт байта блока.
Инструкция с кодом F0 помещает текущий адрес указателя инструкций из IP в B0 и
C0, а значения из Bi и Cj помещает в IP, производя переход на адрес Bi:Cj. Тем
самым, можно обращаться к коду подпрограмм и знать адрес возврата через B0:C0.
Группу регистров D0-D9 составляют внешние Device-устройства с непосредственным
использованием в качестве операндов. Не рекомендуется активно использовать эту
группу в любых вычислительных действиях, так как нет гарантии работы программ.
Простой - не значит тупой!
Цитата:
Сообщение от
Lethargeek
это какой-то неправильный "риск" - часть "команд" фактически префиксы
Сaму схему в симуляторе хоть запускали?
А то получается как книжку повертеть так-сяк, да картинки пролистнуть.
Цитата:
Сообщение от
Lethargeek
то есть реальные команды по сути сложные
Когда я впервые столкнулся с RISC'ами, то не понимал, за что их хвалят. Так как за 1 такт они выполняют по одной инструкции и для выполнения CISC-эквивалента потребуется пусть 5 инструкций, хотя та же CISC инструкция кодируется одним кодом и требует те же 5 тактов.
Так что, считаю, что у меня RISC-идеология никак не пострадала.
И уверен, что в рамках LogiSim этот процессор один из самых функциональных, представленный одной целостной схемой из стандартных примитивов.
Цитата:
Сообщение от
Lethargeek
пока вижу единственный вероятный плюс - получился бы в железе простым, возможно
По моим предварительным подсчётам…- буферов ЛП11 - более 100 штук
- регистров ИР23 - более 40 штук
- вентилей ЛА3 - более 30 штук
- мультиплексеров КП11 - около 20 штук
- мультиплексеров КП2 - около 25 штук
- дешифраторов ИД10 - около 10 штук
- прочей логики - более 10 штук…
Итого, порядка 250 корпусов…
В принципе, не так уж и много получается…
(Учитывая то, что регистровый файл можно и не реализовывать целиком, но это скажется на программной гибкости…)
Интересно было бы в Proteus'е всё это дело исполнить и там всё поточнее будет.
Да и печатные платы развести можно.
Прошу не забывать, что основная особенность процессора в том, что набор команд размещается в таблице не в стиле Пикассо (куда кистью ляпнул - тот код и дал), а с максимальным смысловым кодированием!
Кстати, так как группа команд с кодами E0…E7 и F1…FF совершают прыжки в стиле i8080-RST (адрес подпрограммы кодируется самим кодом команды: E0 прыгает на E000), то когда я исключал HLT-команду как таковую и перенёс в группу RST, сначала хотел задать ей адрес F000. Но потом подумал, что переход на 0000 - тоже не плохо.
Потому сейчас код по 0000 сначала проверяет адрес возврата в регистрах B0:C0 и если это был прыжок откуда-то, то работает как HLT - бесконечный цикл.
Тем самым, стековые макрокоманды написать можно и нормальные CALL/JMP по адресам E000…FF00.
P.S.: Думаю, процессор в целом получился «простым, но не тупым» и пройдёт тест Тьюринга.
Учитывая, что лет 10 назад у меня не хватило бы опыта на подобное…