− Скрыть
Если смотреть на системы команд разных процессоров, игнорируя особенности их архитектур, можно заметить нечто общее в организации их систем команд, в исключительном большинстве случаев делающее их программно несовместимыми. Везде наблюдается преобладающий фактор хаоса, порождённый фривольностью инженеров-разработчиков тех процессоров. Так как ещё со времён паровых механических машин Бебиджа не было разработано никакого некоего кодекса, в котором строго и чётко расписывались бы все правила проектирования архитектуры вычислительного устройства на всех уровнях, каждая ветка индустрии процессоров шла своим путём и порождала свои правила.
Позвольте мне упустить из внимания особенности архитектур, которые и без меня развивались и будут дальше усложняться. Хочу сосредоточиться лишь на том, что какими бы ни были процессор и его система команд, разработчику всегда нужно придумать систематизированное обозначение всей этой псевдо-хаотической абстрактной лабуды. Разработать мнемоническое обозначение команд, язык ассемблера и сборщик конкретного объектного кода. Так как пользователю, будь то домохозяйка или же программист сторонней компании, так ли иначе нужно будет как-то с этим работать. Программисту необходимо будет переварить всю эту мнемоническую кашу, а домохозяйке нужно будет мириться с ограниченной функциональностью и возможными багами используемой техники.
Здесь я попытаюсь изложить свои труды, практической целью которых стало стремление заполнить нишу, то пустое пространство, которое образовалось под высоким давлением ведущих индустриальных гигантов. Исторически сложилось так, что вся инженерия всегда и в первую очередь работает на военные интересы, где нету, выражаясь формально, ограничений на сложность разрабатываемых систем и финансовых затрат. В супер компьютерах давно уже не скупятся на длину машинного кода, чтобы получить относительно прозрачную и элементарную систему команд для переваривания конвейерами, а также для явного указания параллелизма. Главное там - надёжность и производительность. Всё, чем мы пользуемся в быту, от настольных компьютеров до карманных сотовых телефонов - лишь сильно сжатые праобразы супер ЭВМ с предельно компактными записями команд.
Здесь я попытаюсь описать на собственном опыте все сложности в разработке процессора, который не должен прогибать программиста под себя в каком-то смысле. Я попытаюсь избавить его от абстрактной системы команд. Процессор может получиться неприлично медленным и ограниченным. Но свои усилия я направлю на то, чтобы он работал с программой не как с каким-то очередным байт-кодом, а реальным листингом с вполне конкретными математическими записями и выражениями. Для того, чтобы избавить от всяких посредников, начиная от ассемблера и восходя до языков высокого уровня.
− Скрыть
Идея разработать собственный процессор с особенной системой команд, пересекающейся с ascii-таблицей, у меня возникла относительно недавно. Эдак, в 2008 году.
Однако, черновые наброски как в наборе заметок и правил, так и на уровне алгоритма, имели много нестыковок.
Но совсем недавно я наткнулся на статью, послуживщую сильным стимулом. Как там сказано, в оснащение входит встроенный интерпретатор Бейсика. Для меня это значит, что любая программа будет выполняться с тормозами.
Значит, как я для себя заключил, для любительских проектов, которые в перспективе не должны попасть на орбиту планеты, можно использовать любой процессор. Даже самый медленный, как мой аппаратный парсер.
Мне посоветовали установить компактный пакет Icarus Verilog. Благодаря чему я наконец-то смог перейти от теории к практике.
Хотя написанный в JavaScript эмулятор процессора функционирует с большими натяжками (об этом - ниже), но оказалось, что легче начать разрабатывать Verilog-листинг с нуля, чем портировать его со скрипта. Единственное, что пригодилось, это прошивка таблицы и мой приобретённый опыт.
Как я уже сказал, симулятор функционирует с натяжками. Прежде всего их создаёт непродуманность концепции в целом. Не сформирована до конца модель синтаксиса.
Хотя синтаксис приближён к языку Си (кстати, про Verilog говорится то же самое, хотя с Си схожесть довольно натянута), но имеются очень необычные формы записей. Что создаёт трудности в развитии синтаксиса.
Как правило, когда человек начинает заниматься чем-то новым, оказывается, что это нечто новое уже начинает жить собственной жизнью. Диктует свои правила, образует исключения.
В этом плане я понимаю разработчиков. Хотя синтаксис и объявляется Си-подобным, но к самому Си имеет есть косвенное отношение. Как язык php или даже C++, который стал самостоятельным языком с конфликтами с Си.
На форуме я открыл тему с этой идеей.
Правда, материал темы немного подстарился, так как идея сейчас достаточно скоро развивается и вносятся соответствующие коррективы.
На последок, хотел бы принести свои извинения администрации данного сайта, а также всем пользователям. Так как данная статья практически не имеет никакой ценности. Кроме как сугубо теоретического содержания.
Известно, что в процессорах Intel порты - костыли, чтобы компенсировать недостатоток, некогда, дифицитного адресного пространства. Сейчас, по-видимому, от этих пережитков избавились...
Как-то я подумал, что хорошо ведь придумали, что часть кода x86 (ESC) отдали под нужды сопроцессора (x87). Но, это было раньше. Сейчас это - де-факто. Так, ничего особенного (начиная с i80486)...
Я не раз делал попытки разработать систему команд, где каждое внешнее устройство, будь то ПДП или видеокарта, проецируется первым делом в систему команд. Т.е. когда процессор встречает незнакомую ему инструкцию, он даёт возможность обработать её другим устройствам. Включая и особенности указания векторов памяти, как в FPU-x87...
Выглядить это может примерно так (на примере с x86): Некоторые сегменты памяти объявляются как содержащие исполняемый код чуждой системы. Например, Java-машины или OpenCL. Тогда, когда инструкция CALL перейдёт в область того кода, процессор, вместо того, чтобы выполнять "бредо-код", укажет нужной "железяке" на необходимость выполнения тех инструкций.
Знаю, что это легко организовать с помощью исключений и других трюков. Но моя речь о том, чтобы сама система команд процессора включала бы возможность внедрения инструкций иного устройства.
Я не могу этого доказать и придётся верить мне на слово. Но ещё в 90-х, когда я знал о DOS лишь по справочнику, не говоря о Windows.
В голову пришла идея процессорной системы, где нижние 4Гб памяти выделяется под каждый процесс индивидуально. А остальные верхние адреса после 4Гб доступны как общие ресурсы.
0x0000000000..0x00FFFFFFFF: Память приложения
0x0100000000..0x01FFFFFFFF: Буфер консоли (терминал: клавиатура, дисплей, принтер)
0x0200000000..0x02FFFFFFFF: Буфер транзакций (сетевые транзакции; файловая система; межпроцессные; межпроцессорные)
...
Причём, система команд разрабатывалась так, чтобы все операции с данными структурировались. Код программы разбивался на объявления разных блоков на арифметику, транзакции и остальное. И в пределах блока инструкции выполнялись сопроцессором. Сопроцессоров много:
FPU: Арифметический процессор. Аналогия с x87. Но команды иные;
GPU: Графический процессор. В 90-е, когда я занимался этим, протокол графики ограничивался линиями, эллипсами и спрайтами;
SPU: Звуковой процессор. Компьютер ZX-Spectrum-128 с чипом Yamaha должен был выполнять его функцию;
WPU: Сетевой процессор. Компьютер с доступом в интернет...
Как видно, в моём случае я пытался сформулировать компьютерную систему, где центральный процессор относительно прост, но к нему подключаются очень много других процессоров (Z80, i8086, M68000), программы которых заточены под свой профиль.
Теперь я понимаю, что это относительно легко организовать в любой операционке...
Как человек, достаточно хорошо владеющий основами программирования машинного кода x86 могу заметить, что техника программирования на низком уровне ничем не отличается от языков программирования высокого уровня, таких как классические Fortran и Basic: Куча GOTO и GOSUB. Потому что, несмотря на то, что за прошедшие десятилетия частота процессоров возрасла на три порядка (от единиц мГц до нескольких гГц), технология построения программ не изменилась: Как был дамп инструкций, так он и остался...
Потому, если программа совершает переход на непредвиденный вектор, происходит сбой.
Первой попыткой была разработка системы команд, где подпрограммы объявляются явно и вызов их происходит не переходом по их адресу, а обращение к процедуре с известным идентификатором. Т.е. программа разбивалась на 4096 подпрограмм, которые также разбивались на 4096 субподпрограмм и т.д. Заранее строились таблицы с векторами на нужные процедуры. Как бы в x86 инструкция INT 0..255, но с использованием множества локальных таблиц.
Второй попыткой была организация системы команд, где наиболее редкие инструкции имеют более длинный код или составляются из отдельных команд (RISC?)...
Никаких CALL/JMP/RET, вместо которых - извлечение вектора из таблицы, занесение в стек и перенос в указатель инструкций. Причём, нет явного отличия трюка CALL и JMP. При переходе на новый вектор в стек адрес возврата не заносится. Для этого указатель инструкций IP имеет не 32 бита, а 256. И при переходе на иной адрес биты сдвигаются влево на 32 позиции. При возврате - вправо. Т.е. можно произвести до 6 вложенных вызовов и вернуться обратно. А старшие биты (32..255) в стеке должна сохранять сама подпрограмма.
Причём старшие биты (224..255) содержат вектор на обработчик исключений. И если совершить тупо 8 возвратов, управление получит системный код...