Вложений: 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 назад у меня не хватило бы опыта на подобное…
Теперь работает LOOP 2…9 и GOTO 3…9
Цитата:
Сообщение от
hitomi2500
Идея сама по себе интересная, но в вашей реализации непрактичная. Запоминать каждую контекстную расшифровку первых 6 букв алфавита - это не сильно проще чем учить опкоды классических восьмибитников (для B у вас уже в первом посте SUB, Bigger и Buffer).
Этo издержки языковых барьеров и технологий.
А правило довольно простое и описывается в несколько строчек:
Код:
00 HLT - Формальный останов: Переход на 0000
nn ADD Ri,BCD - Приращение двоично-десятичной константы
na alu Ri,Tn - Операция АЛУ над Приёмником с Источником
Ri USE Ri - Выбор Индекса в группе Регистров
RT USE Ri,Tj - Выбор операндов для АЛУ-операций
RE EXT Ri - Экстракция (чтение) данных из памяти
RF FIX Ri - Фиксация (запись) результата в память
Eo Eo - Переход на адрес Eo00: E000..E700
Ec Ecnd - Условное выполнение: Execute by condition
F0 FO - Завершение Функции: Function Over
Fh Fh - Вызов Функции по адресу Fh00: F100..FF00
где
Код:
R - Приёмник (Receiver)
T - Источник (Translator)
c - Индекс условия
h - Шестнадцатеричная тетрада, отличная от нуля
i - Десятичный индекс регистра. Если является частью кода - обновляется
j - Десятичный индекс регистра-источника, выбранный раннее
n - Десятичный индекс регистра-источника, используемый временно на период операции
o - Восьмеричный индекс
cnd=F - False / NE / NZ - Фальш, не Ноль
cnd=E - Equal / E / Z - Истина или Ноль
cnd=D - Dry / NC - Сухой результат без Переноса
cnd=C - Carry / C - Перенос
cnd=B - Bigger / NS - Бит Знака сброшен, результат Больше нуля
cnd=A - Among / S - Число было среди интервала
cnd=9 - / PE - Чётный паритет (просто запомнить, так как операция редко используется)
cnd=8 - / PO - Нечётный паритет (просто запомнить, так как операция редко используется)
alu=A - Add
alu=B - suB
alu=C - Conjunct (and)
alu=D - Disjunct (or)
alu=E - Exclusive or (Eor / xor)
Просто, документации нормальной я не составил, так как у меня туго с изложением технических тонкостей в гуманитарном стиле.
(Я ни раз здесь подчёркивал, что процессор этот именно для хардкоршика и фаната дампов, но система команд - гуманитарно-интуитивная. Не стоит думать, что система команд для гуманитариев. Просто она такая, как именно мне удобна. Я её за уши подтягивал к гуманитарному виду, при этом оставаясь в нище хардкорщика. И она выглядит так, как представляется мною в идеале…)
Цитата:
Сообщение от
hitomi2500
Плюс резервировать опкоды под десятичные константы тоже странно - самые часто используемые константы это 0, +1 и -1, остальные излишни мне кажется.
А Befunge/BrainF*ck мало? Ещё и WhiteSpace есть, который аппаратно тоже можно реализовать как процессор для блондинок: Каждая строчка - стих!
Цитата:
Сообщение от
hitomi2500
Поэтому надо смотреть на более серьёзные синтетические языки с коротким словом и малым числом букв.
И это я делал, даже в Verilog'е описывал что-то. Процессор использует ПЗУ на 2 Кб, где закодировано, как реагировать на ASCII-символ.
Например, «1scrn = 1keybd + (128 - 0x80)» аппаратно переваривает как «1 байт ячейки scrn загрузить 1 байтом ячейки keybd с выражением».
То есть, первые цифры формируют режим доступа, буквами кодируется адрес, а знаками - управляется АЛУ и пр…
Можете не верить, но я занимался вопросом аппаратной реализации такого процессора.
Причём, даже находил способ чтения имени ячейки «keybd» за 1 такт через чтение 64-битного слова и каскадом ПЗУ с обратной связью, чтобы сформировать цепь букв и определить длину.
В LogiSim такое будет слишком сложно строить!
Цитата:
Сообщение от
Lethargeek
эээ, зачем вообще 7 одинаковых сложений за 7 (на самом деле больше) тактов? это сдвиг младшего бита в старшую позицию штоле? вместо and + одна прокрутка вправо...
Реализовал, но схема получилась чуть путанее…
Нужно ещё перераспределить блоки графически, так как я ошибочно расположил АЛУ у выхода с регистрового файла чисто из соображений «два операнда входит - один результат выходит».
На деле же это оказалось большой ошибкой, так как именно из регистрового файла выходит несколько каналов с данными, но на входе - очень много управляющих сигналов!
Теперь коды 02…09 загружают регистр повтора. Сдвиговый регистр пропускает первый цикл и несколько раз начинает со второго цикла. Тем самым, операции с доступом к памяти с циклами 3 и 4 работают.
Интересно получилось с инструкциями E8…EF - условным выполнением: В таком режиме цикла разрешается счёт указателя команд, но не происходит выборки. Тем самым, по условию можно пропустить несколько инструкций. Например:
Код:
0000 AA A1 1E |EOR A1,A1 ; Очистить A1
0003 05 EF |EF 5 ; Условное исполнение инструкций до пятой, как «IF !ZF THEN ON N GOTO 5,6,7,8,9»
0005 A1 A2 A3 A4 | - - - ; Эти инструкции игнорируются
0009 A5 |USE A5 ; Здесь счётчик игнора очищается
000A 03 85 |REP3(A5+85) ; Здесь три раза прибавится 85
Тем самым, появились такие трюки, как «ленивое выражение».
Даже если сейчас на меня обрушится куча критики, скажу, что в схеме это почти ничем существенным не усложнилось. За то программный уровень намного упростился!
Вложений: 2
Нормализованный Эскиз Схемы
Цитата:
Сообщение от
Lethargeek
кароч, понял, что еще мне напоминает необходимость помнить контекст при кодинге - программирование эффективных вычислений на форте
https://www.youtube.com/watch?v=5hhbGBlP3_4
Очень долго провозился с перераспределением функциональных блоков.
Теперь схема графически выглядит менее путаней и более последовательной.
А в маленькой масштабе напоминает кристалл микросхемы.
Кое-где даёт сбой…
При манипуляции джойстиком симуляция может прерваться (глюк LogiSim?).
А при печати на клавиатуре может улететь в режим останова с перемигиванием лампочек для без нажатия на Забой…
Почему-то даже в ручном шаговом режиме часть шин уходит в неопределённость (я не про АЛУ). Думаю, LogiSim не тянет…
Подправил схему и чуточку дописал описание:
Код:
Кодирование алгоритма малой степени сложности доступно пользователю с базовыми
навыками редактирования таблиц дампа и не представляет особой сложности в силу
максимально осмысленного кодирования всех инструкций в шестнадцатеричном виде.
------------------------------------------------------------------------------
|Код команд / диапазоны|Группа |Описания, замечания, комментарий
-----------------------|----------|-------------------------------------------
00 |HLT |Прекращение счёта указателем команд IP
02-09 |REP 2-9 |Префикс повтора/пропуска операции n-раз
10-99 01 |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-устройства с непосредственным
использованием в качестве операндов. Не рекомендуется активно использовать эту
группу в любых вычислительных действиях, так как нет гарантии работы программ.
Префикс REP используется для повтора любой операции на нужные n-тактов дольше.
Исключение представляет условная группа Ecnd, которая исполняет n-ую команду в
очереди, если условие ЛОЖНО.
******************************************************************************
* Примеры *
******************************************************************************
AA A1 1E |EOR A1,A1 ;Очистка по Исключающему Или (sf pf cf ZF)
AA A1 2E |EOR A1,A2 ;Исключающее Или A1 с A2 (?? ?? ?? ??)
AB A1 1A |EOR A1,B1 ;Исключающее Или A1 с B1 (?? ?? ?? ??)
AB A1 2A |EOR A1,B2 ;Исключающее Или A1 с B2 (?? ?? ?? ??)
AA A1 1E AB 2A |MOV A1,B2 ;Присвоение Исключающим Или (sf pf cf ZF)
AA A1 34 |SUM A1,34 ;Инкремент на константу (-- -- -- --)
AA A1 02 34 |SUM A1,2*34;Расширенный инкремент (-- -- -- --)
F8 |CALL 0xF800 ;Вызов подпрограммы
03 F8 |CALL 0xF803 ;Вызов подпрограммы с пропуском команд
F0 |RET ;Возврат из подпрограммы
03 F0 |RET 3 ;Возврат с переходом на команду #3
03 EC |EC 3 ;Условное выполнение по CF по команду #3
******************************************************************************
0000 03 EE A1 A2 A3 |IF ZF THEN {A1 A2 A3} ELSE A3
0005 03 EF A1 A2 A3 |IF ZF THEN A3 ELSE {A1 A2 A3}
000A 03 E0 A1 A2 A3 |GOSUB E003:A1:A2:A3
E003 03 F0 |RETURN TO A3
******************************************************************************
Вложений: 3
Дешифратор команд в комбинаторике
Чтoбы быть последовательным и честным, решил развернуть дешифратор команд из прошивки ПЗУ в элементарную комбинаторику.
Так в полной мере можно оценить простоту разработанной мною системы команд.
Правда, перевод BCD в Hex потребует двух сумматоров и одним встроенным в АЛУ сумматором не обойтись… Может, придётся удлинить цикл на ещё один такт… Это дело конкретной реализации…
К сожалению, не знаю, к какому классу архитектуры можно отнести всё это.
Для CISC - всё слишком примитивно.
Для RISC - не все команды просты своей логикой: Комбинация «03 F8» переходит на адрес F800 и пропускает 3 инструкции до адреса F803. Логически, это понятно и просто. Но реализация через счёт пропускаемых операций с режимом пропуска - уже сложно для понимания и выходит за рамки технологии RISC.
С другой стороны и к MISC отнести в полной мере не получается из-за отсутствия стека как такового…
(Операции PUSH/POP реализуются программным способом с "танцами под бубен"!)
Доработки
Немного подправил схему и логику…
Теперь комбинация «03 F8» переходит на адрес F830 по логике «Строка #3 дампа по адресу F800»…
Программировать стало легче, но программная реализация стека реализуется чудовищным кодом, так как её нельзя оформить в подпрограмму.
Почему так выходит: По плану, как уже писал выше, данный процессор задумывался основанием на ядро к x80-CISC в версии, где CISC-инструкция считывается и разворачивается в RISC-подпрограмму. Потому, получается, что поддержка внутреннего стека в рамках RISC не нужна, так как внешний стек через порты «D0…D9» будет реализовываться в CISC на внешнюю память…
Это плохо и не удобно для построения самостоятельной системы на данном процессоре и требует введения отдельных команд через резервные линии дешифратора…
Примерка кода
Если строить мой CISC x80 на базе данного ядра с прошивкой всех 32768 команд, то сам RISC-код будет всегда начинаться с адреса 0000 в ПЗУ с Гарвардским доступом. Если прикинуть и развернуть одну из операций, то получится примерно следующее:
Код:
x80: 54 |MOV AL,BL ; Команда x80
========================================================================
0000 DD D1 1E 02 88|MOV D1,0xB0 ; Регистр адреса ячейки контекста
0005 AA A1 1E AD 2D|MOV A1,D2 ; Считываем содержимое
000A DD 1E 02 80|MOV D1,0xA0 ; Регистр переключаем с BL на AL
000F DA D2 1D |OR D2,A1 ; Записываем данные
0012 00 |HLT ; Итого - 19 команд / 19 тактов
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Вместе с выборкой MOV AL,BL - 22 такта
Ужасная производительность!!!
P.S.: Получается, строить внутренности x80 на данном процессоре слишком накладно и бесперспективно.
Работу над данной версией процессора в качестве ядра приостанавливаю, но не ставлю крест: Быть может, кому-нибудь пригодится как опытный образец…
Попробую посмотреть в сторону VLIW с длинной машинного кода под 32 бита.
Вложений: 1
Дорабатывать схему становится тяжелее: Нужно просто нарабатывать код
Цитата:
Сообщение от
hitomi2500
Проект с его участием далёк до завершения
B OpenCores имеется?
Цитата:
Сообщение от
hitomi2500
если есть желание посмотреть, могу поделиться.
Конечно есть!
Цитата:
Сообщение от
hitomi2500
всё-таки больше ориентировано на ПЛИС чем на дискретную логику.
В пост-апокалипсис не добыть…
Кстати, устранил мелкие ошибки в схеме:
Операции «BE»/«CE» считывали данные из памяти преждевременно, из-за чего в регистры «Bn»/«Cn» попадали хаотические данные, так как многократно считывался байта адреса, на который и указывал сам регистр. Вентиль «2-И» всё исправил…
Код:
B0 C0 BE|MOV B0,B0:C0 ;Ячейка считывалась многократно и рандомно…
Наконец-то добавил самостоятельную «MOV» операцию прямо в АЛУ-группу:
Код:
; было…
A1 AA 1E|EOR A1,A1
AC 3D|OR A1,C3
; стало…
A1 AC 3F|MOV A1,C3
Что мешало? Концепция! Думал сунуть команды битовых сдвигов в ту группу, но пришлось отдать её под «MOV», так как свистопляска достала…
Также и с префиксом «REP 2…9» не всё так гладко:
Код:
AC A1 07 2A|ADD A1,C2*7 ; Префиксом 07 (REP 7) сложение повторяется 7 раз
07 3B|SUB A1,C3*7 ; Вычитаение 7 раз
07 4C|AND (A1,C4) ; Чушь!!! Зачем маскировать 7 раз???
07 5D|OR (A1,C5) ; Чушь!!! Эти операции в повторе бессмысленны!
07 6E|EOR (A1,C6) ; Чушь!!! Чётное число повторов возвращают биты обратно!
07 7E|MOV (A1,C7) ; Чушь!!! Какой смысл в таком присваивании 7 раз?
B5 C5 07 AE|MOV A1,B5:C5; Чушь!!! Семь раз считывать из памяти???
07 AF|MOV B5:C5,A1; Чушь!!! Семь раз записывать в память???
07 A1|USE A1 ; Чушь!!! Семь раз выбирать индекс регистра???
07 AB|USE A1,B5 ; Чушь!!! Семь раз выбирать группу операндов???
Думаю, под повтором нужно подключать иную логику. Например, внедрить операции «SHL»/«SHR» или «BIT»…
В общем, хоть таблица команд вроде бы и забита вся, но резервных комбинаций очень много получается под префиксом повтора!
Хоть механизмы пре-/пост-инкремента/декремента вводи, как в 68k… В этом случае коды 02…09 будут уже не префиксом «REP n», а каким-нибудь «MODE x»…
Сделать инкремент/декремент - лишь заменить регистры B₀…₉ и C₀…₉ на счётчики. За часик управиться можно, в перспективе…
Но, это точно выдавит процессор из класса RISC!
В файле «cnd_lib.ram» наконец-то появился код с командами «CALL»/«RET»/«JMP»/«Jcnd» с привязкой к стеку. Теперь можно вызвать подпрограммы вложением до сотни раз.
Операции «PUSH»/«POP» пока не описаны, но это достаточно легко реализуемо.
P.S.: В схему добавил два десятичных счётчика: Один считает такты до операции «00-HLT» в оперативном режиме, второй - фиксирует последний максимум…
Вложений: 1
x80-дизассемблер в Logisim
Цитата:
Сообщение от
hitomi2500
Если возникнет желание разбираться с верилогом, то по нему очень много и справочного и образовательного материала в интернете, на русском в том числе.
Вoт частичная модель моего процессора…
Но она такая кривая, что нужно переписывать с чистого листа!
В самом начале темы я уже пояснил, что в перспективе данный процессор станет ядром того процессора: CISC с RISC-ядром.
И все архитектурные решения - свои: Никакой лицензионной зависимости ни от кого!
Кстати, ниже архив - пародия на целевой процессор: Частичный дизассемблер…
В схеме - как бы всё красиво и последовательно. А в Verilog - тихий ужас!
Переименовал «кодовое название»…
Дo сих пор описываемый и разрабатываемый здесь процессор не имел никакого названия.
Если x80 формально задумывался как тот же x86, но 8-битный и с более нормальной (с моей точки зрения) таблицей команд. То в качестве возможного ядра для RISC-сердцевины CISC-оболочки x80 данный процессор получился безымянным как черновой вариант первой схемы в Logisim просто как прикол…
Однако, неделю назад всё-таки задумался о «кодовом названии», так как архитектура в целом получилась:- уникальной: до сих пор не было процессора с машинным кодом «а поговорить?»
- самодостаточной: концептуально процессор очень гибок в самых неожиданных местах
- независимой: никакого copy-paste не было и любое схематическое решение я могу обосновать
Тем самым, получилась совершенно самостоятельная ветка, которую можно развивать, усложняя систему команд (я про странные сочетания, типа «03 AE» или «03 C3»)…
И вот неделю назад, просмотрев один фильм 1982 года, решил вдруг этому фильму представить тёску…:v2_dizzy_indy:
P.S.: Судя по первой реакции социальных сетей, Verilog-проект всё же придётся разворачивать…:v2_dizzy_fire:
Вложений: 1
Эмулятор моего виртуального процессора
Эмулятор
Написал и более-менее отладил эмулятор (Вложение 74808):- 3700…37C6: Оболочка («РАДИО-86РК¹» / «СПЕЦИАЛИСТ²» / «ОРИОН-128³»)
- 3838…3863: Сам псевдо-код для эмулятора
- 3870…38FF: Поддержка совместимости между разными ПК (¹-²-³ и ZX-Spectrum 48Kb) для печати символа и ввода с клавиатуры
- 3900…3A99: Собственно, код самой эмуляции (поддерживаются практически все инструкции)
- 3ADA…3C7F: Дизассемблер (декодирует практически все команды)
- 3C80…3CFF: Заглушка портов УВВ (вывод сообщений о попытках доступа к портам)
Оболочка в первую очередь разрабатывалась под РАДИО-86РК, где и отлаживалось всё.
Адрес эмулятора 3870…3CFF выбран не случайно, так как ZX-Spectrum 48 Kb в ROM#2 по этим адресам имеются FF.
То есть, всё разрабатывалось, чтобы код прошить прямо в ПЗУ и не требовалось что-либо грузить с ленты.:v2_dizzy_sleep2:
Итого
Таким образом, свою идею персонального процессора я реализовал:- Рабочим эскизом в Logisim
- Эмулятором на JavaScript
- Моделью на Verilog с перспективой реализации в ПЛИС/FPGA
- Эмулятором под процессор i8080/z80
В ходе разработки данного эмулятора решил некоторые концептуальные проблемы и белые пятна архитектуры: Теперь нужно доработать эскизы Logisim/Verilog.- Инструкция ARG D,D теперь запрещена и работает как DBG. Тем самым, из-за её упразднения уже никак нельзя выполнить инструкцию, типа «MOV D1,D2» (непосредственная пересылка из порта #2 в порт #1), так как появилась инструкция DBG
- Инструкции JNS/JPO/JNC/JNZ упразднены и на их месте теперь CMS/CMO/CMC/CMZ - инверсия соответствующих флажков. Теперь «JNC» - это «CMC+JC»
- Наконец-то в адресации появился авто инкремент/декремент для организации стека: Так как в качестве индексного регистра неразумно указывать регистр порта УВВ, теперь в рамках индексной адресации они и работают в качестве счётчиков (считает только D₉, остальные D₀…₈ лишь определяют направление счёта и смещение)
- Некоторые комбинации так и не определены. Условно они обозначаются как инструкции EXA/EXB/EXC/EXD/EXE
Теперь предстоит данный код эмулятора/дизассемблера вписать в ZX-ROM и аккуратненько прогнать в EmuZWin…:v2_dizzy_snowball2: