Войти
Эзотерический поискСтатьи

CLŒVER

Автор:

Технология


Сам по себе CLŒVER не имеет вычислительных средств.
Архитектура организуется подобно Forth-процессорам - со стеком (формальным).
Однако, стек, как таковой, не используется. Как в языке СИ++ имеется механизм перезагрузки операторов.
Так как для любительских проектов не требуется 4Gb памяти, верхние ячейки используются под арифметику.
Допустим, нам нужно настроить оператор сложения - "+". Мы привязываем токен этого оператора на нужный адрес.
Если в листинге встретилась запись 4x += 4y, процессор сначала считывает данные из двух ячеек - x и y, затем передаёт их значения по нужным адресам АЛУ-стека, а действие "+=" выполняет считыванием из назначенного вектора.
Чтобы это понять, представьте, что мы подключили к процессору внешние три микросхемы: два регистра и сумматор.
Схема дешифратора настроена, чтобы адрес 0x0A000000 активировал первый регистр, а 0x0B000000 - второй регистр.
Сумматор входами подключен к выходам этих двух регистров, а выход сумматора через буфферный регистр доступен по адресу 0x0C000000.
Тем самым, изначально процессор понимает лишь оператор присвоения - "=".
Так, запись 4x += 2y развернётся в микропрограмму из нескольких операций:
1) 4[0x0A000000] = 4x эквивалент (DWORD*)0x0A000000 = x;
2) 4[0x0B000000] = 2y эквивалент (WORD*)0x0B000000 = y;
3) 4x = 4[0x0C000000] эквивалент x = (DWORD*)0x0C000000;

Можно заметить, что таким образом процессор чем-то напоминает язык ПРОЛОГ: Никаких вычислительных действий не производит.
Просто пересылает данные с одних ячеек в другие.
Именно в таком качестве он мною и задумывался. Чтобы производить потоковую пересылку из одних ячеек в другие.
Все операции, даже элементарные AND, OR, XOR и т.д. должны производиться внешней логикой (ПЛИС).

Технические решения

AIM: Два бита RS-Триггера с двумя устойчивыми состояниями и одним расширенным;
BID: Два бита счётчика Джонсона для генерации фаз управляющего интерфейса;
Конструктивно сигналы управления READ и WRITE получаются OR-наложением текущих
состояний AIM и BID, что сильно упрощает узел управления. Здесь ниже находятся
три таблицы, поясняющие фазы трёх режимов: Чтения, записи и изолирования шины:
╔═════╦═════╦═════╤════╤════╤════════════════════════════════════════════════╗
║ AIM ║ BID ║ W|R │ADDR│DATA│DESCRIPTION OF WRITING STATE                    ║
╠═════╬═════╬═════╪════╪════╪════════════════════════════════════════════════╣
║2'b01║2'b11║ H-H │LOCK│-""-│ADDR <= vector, AIM <= next_aim                 ║
║2'b01║2'b10║ H-H │-""-│LOCK│DATA <= buffer                                  ║
║2'b01║2'b00║ L-H │-""-│-""-│                                                ║
║2'b01║2'b01║ L-H │-""-│FREE│                                                ║
╚═════╩═════╩═════╧════╧════╧════════════════════════════════════════════════╝
╔═════╦═════╦═════╤════╤════╤════════════════════════════════════════════════╗
║ AIM ║ BID ║ W|R │ADDR│DATA│DESCRIPTION OF READING STATE                    ║
╠═════╬═════╬═════╪════╪════╪════════════════════════════════════════════════╣
║2'b10║2'b11║ H-H │LOCK│FREE│ADDR <= vector, AIM <= next_aim                 ║
║2'b10║2'b10║ H-L │-""-│FREE│                                                ║
║2'b10║2'b00║ H-L │-""-│READ│buffer <= DATA                                  ║
║2'b10║2'b01║ H-H │-""-│FREE│                                                ║
╚═════╩═════╩═════╧════╧════╧════════════════════════════════════════════════╝
╔═════╦═════╦═════╤════╤════╤════════════════════════════════════════════════╗
║ AIM ║ BID ║ W|R │ADDR│DATA│DESCRIPTION OF CLOSED STATE                     ║
╠═════╬═════╬═════╪════╪════╪════════════════════════════════════════════════╣
║2'b11║2'b11║ H-H │FREE│FREE│AIM <= next_aim                                 ║
║2'b11║2'b10║ H-H │FREE│FREE│                                                ║
║2'b11║2'b00║ H-H │FREE│FREE│                                                ║
║2'b11║2'b01║ H-H │FREE│FREE│                                                ║
╚═════╩═════╩═════╧════╧════╧════════════════════════════════════════════════╝
Схематически может выглядить примерно вот так:
Изображение

Проект сейчас начал переписываться с нуля и застрял на блоке контроля шины.
Так, не совсем ясно, как реализовать обработку WAIT, BUSRQ, INT. С RESET более-менее разобрался.
Процессор не сразу сбрасывается по приходу RESET. Необходимо выждать некоторое время. Так как предусмотрен системный регистр-счётчик ___ss, первый байт которого подсчитывает, сколько операций выполнилось с момента прихода RESET. Программа может предотвратить перезагрузку, обнуляя счётчик.



Вычисления
В CLŒVER нету встроенного универсального АЛУ и все вычисления должны производиться на уровне периферии.
Для работы с внешними вычислителями выделен псевдо-стек с ячейками:
____0 -> Id:07777777700 -> hexId:0x3FFFFFC0 -> Vector:0xFFFFFF00
____1 -> Id:07777777701 -> hexId:0x3FFFFFC1 -> Vector:0xFFFFFF04
____2 -> Id:07777777702 -> hexId:0x3FFFFFC2 -> Vector:0xFFFFFF08
____3 -> Id:07777777703 -> hexId:0x3FFFFFC3 -> Vector:0xFFFFFF0C
____4 -> Id:07777777704 -> hexId:0x3FFFFFC4 -> Vector:0xFFFFFF10
____5 -> Id:07777777705 -> hexId:0x3FFFFFC5 -> Vector:0xFFFFFF14
____6 -> Id:07777777706 -> hexId:0x3FFFFFC6 -> Vector:0xFFFFFF18
____7 -> Id:07777777707 -> hexId:0x3FFFFFC7 -> Vector:0xFFFFFF1C
____8 -> Id:07777777710 -> hexId:0x3FFFFFC8 -> Vector:0xFFFFFF20
____9 -> Id:07777777711 -> hexId:0x3FFFFFC9 -> Vector:0xFFFFFF24
Десять внешних регистров дешифратором подключаются по указанным векторам...

Служебные регистры:

___pp -> Id:07777776060 -> hexId:0x3FFFFC30 -> Vector:0xFFFFF0C0 // Program Pointer
___ql -> Id:07777776154 -> hexId:0x3FFFFC6C -> Vector:0xFFFFF1B0 // Block Length
___qp -> Id:07777776160 -> hexId:0x3FFFFC70 -> Vector:0xFFFFF1C0 // Block Pointer
___qs -> Id:07777776163 -> hexId:0x3FFFFC73 -> Vector:0xFFFFF1CC // Block Stack

Таблица кодирования вектора по имени или выражению:

  ╔═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╦═╗
  ║p│q│r│s│t│u│v│w│x│y│z│G│H│I│J│_║3║
  ╟─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─╫─╢
  ║@│a│b│c│d│e│f│g│h│i│j│k│l│m│n│o║2║
  ╟─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─╫─╢
  ║P│Q│R│S│T│U│V│W│X│Y│Z│K│L│M│N│O║1║
  ╟─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─╫─╢
  ║0│1│2│3│4│5│6│7│8│9│A│B│C│D│E│F║0║
  ╠═╪═╪═╪═╪═╪═╪═╪═╪═╪═╪═╪═╪═╪═╪═╪═╬═╝
  ║?│!│~│#│$│%│&│^│|│-│*│+│<│=│>│/║
╔═╬═╪═╪═╪═╪═╪═╪═╪═█═╧═╧═╧═╧═╧═╧═╧═╝
║0║0│1│2│3│4│5│6│7║
╟─╫─┼─┼─┼─┼─┼─┼─┼─╢
║1║8│9│A│B│C│D│E│F║
╟─╫─┼─┼─┼─┼─┼─┼─┼─╢
║2║P│Q│R│S│T│U│V│W║
╟─╫─┼─┼─┼─┼─┼─┼─┼─╢
║3║X│Y│Z│K│L│M│N│O║
╟─╫─┼─┼─┼─┼─┼─┼─┼─╢
║4║@│a│b│c│d│e│f│g║
╟─╫─┼─┼─┼─┼─┼─┼─┼─╢
║5║h│i│j│k│l│m│n│o║
╟─╫─┼─┼─┼─┼─┼─┼─┼─╢
║6║p│q│r│s│t│u│v│w║
╟─╫─┼─┼─┼─┼─┼─┼─┼─╢
║7║x│y│z│G│H│I│J│_║
╚═╩═╧═╧═╧═╧═╧═╧═╧═╝
Например:
Оператор "+=" имеет код 0x00BD. Оператор "-=" - код 0x009D.
Вектор "DEBUG" имеет адрес 01516132573₈

Хотя, реально, принцип кодирования операторов несколько сложее. Так, первые три ниббла слова несут информацию об арифметических знаках. Но последний ниббл несёт информацию об операндах. Так, есть ли операнды слева или справа (унарная операция или бинарная) указывается в первых двух битах ниббла. Третий бит - имеет ли место присвоения. Четвёртый - обратная операция.
Тем самым, получается примерно следующее:

0x1007 -> ^y;
0x2007 -> x^;
0x3007 -> x^y;
0x5007 -> ^=y;
0x6007 -> x^=;
0x7007 -> x^=y;
0x9007 -> ^x;
0xA007 -> y^;
0xB007 -> y^x;
0xD007 -> ^=x;
0xE007 -> y^=;
0xF007 -> y^=x;
И позволяет кодировать операторы до четырёх символов длиной (x>>>y - 0x3EEE; x<<<=y - 0x7CCC). Конечно, первые 12 бит используются реально внешними устройствами обработки. Тогда как старшие 4 бита нужны для внутреннего дешифратора для корректной работы с операндами. Тем самым, используется всего до 4096 слов таблицы операторов, хранящей векторы обрабатывающих устройств.

Синтаксис несколько своеобразен. Хотя похож и на Python табулированием блочных операций. Специальных символов под комментарии нет и используется знак табуляции. Так, знаки табуляции в начале строки указывают на уровень вложенности блочных операций. Но, знаки табуляции после - обозначают комментарий. Например:

↵Label→Remark
↵→Main expressions→Remark
↵→→Nested expressions→Remark
↵→ →Remark
↵ →Remark
К тому же, предусматривается вставка служебным комментарий, подобно #-операторам препроцессора Си. Куда сам процессор сможет записывать служебную информацию для ускорения последующего исполнения определённых кусков кода. Например:
↵Label→Remark
↵→Main expressions→Remark
↵→→___ql=23→Size of nested block (start - '↵' symbol)
↵→→Nested expression...
⟝⟶
😶ꕁ😦ᓩ⍨ᓤﺕﺖ

Перевод строки - классические 0x0D + 0x0A, табуляция - 0x09.
Так, 0x0D - может быть командой на исполнение текущей конструкции. А 0x0A - командой сброса статуса конструкции.
Код 0x09 - инкремент счётчика вхождения в блок инструкций.
Технически, расстояние между 0D и 0A не критично и может быть любым. В частности, для служебной информации процессора. Вопрос лишь в том, что обычный текстовый редактор не сможет верно отобразить листинг. К чему я стремился с момента старта идеи.

На текущий момент всё заморозилось.
Нет достаточно ясных набросков некоторых ключевых моментов задумки.

Сейчас планируется ввести дополнительные 10 регистров управления векторами доступа в память.
В частности, если сначала задумывал 1x - как *(BYTE *)x, а 4y - *(DWORD *)y. То сейчас конструкцию 1x можно интерпретировать как использование 1-го регистра описания доступа к ресурсам через x.
Все те десять регистров можно гибко настраивать на доступ к памяти, к стеку, реализации SIMD-вычислений и пр...

Дело в том, что решение имеется, но ничего конкретно не ясно. Я - всего лишь любитель, а не инженер... Тут нужна коллективная работа, советы и предложения...

#Parser, #Processor, #Verilog

15 сентября 2012 (Обновление: 26 дек. 2014)

Комментарии [1]