Итaк, скачал LogiSim Evolution и обнаружил, что он не читает корректно файлы оригинального LogiSim. Но сам Evolution поддерживает модули с VHDL и прошивку FPGA, что демонстрируется на видео: Спойлер Правда, у меня всё это дело не пошло, так как кроме Icarus Verilog пока ничего не имеется. А так как схемы приходится перерисовывать вновь, то я блок выборки команд («Читалку») перерисовал и закончил… Было это: Спойлер Стало это: Спойлер Если раньше для пробы в регистр IA я просто записывал биты с компаратора, то теперь в IA записывается маска с комплексной комбинаторики и с помощью этого возможна поддержка практически всех команд x80. При этом, обошлось без ПЗУ. Полноценный эмулятор x80 я пишу который год. Но проблема в том, что в один прекрасный момент он перестал нормально работать. И одним только откатом обойтись нельзя было, так как дело в самой концепции. Спойлер Эмулятор управляется так: F1 - один шаг отладчика F4 - пуск на всю скорость Alt+1…7 - выбор префикса для переключения таблицы команд и изучения её в деталях Alt+8/9/0 - выбор префикса режима (Micro/Loop/Wait) Alt-P/T - переход к полям Pointer/Translator для ввода инструкций ассемблера. При этом отображается и дамп регистрового файла Основная проблема в том, что эмулятор не поддерживает префикс с кодом «00» в режиме Ядра… Дело в том, что архитектура x80 задумана так, чтобы единственной привелегированной инструкцией была команда/префикс HLT: Для приложений код 00 - HLT, а для Системного Ядра - Префикс №0. И вот эмулятор этот префикс, оказывается, не поддерживает и так просто ввести его поддержку, как оказалось, нельзя! Падает вся система команд. Однако, вернёмся к схемам… После замены компаратора на комбинаторику видно, что получается строго три ступени вентилей на пути к регистрам и примерные задержки можно относительно легко оценить для пиковой производительности. Получается целых 19 бит на схему дешифратора команд, так как помимо 12 от IC и IB, идут ещё 3 от IA и 4 от регистра состояния: SKIP - режим префикса SKIP для пропуска команд. Да, в x80 предусмотрены команды, которые исполняются иначе, когда их надо просто пропустить EACH - режим префикса LOOP для повтора одной команды n раз. Так, «LOOP ADD» работает как умножение… Префикс работает и с RET, и с JMP, и с CALL, переключаясь в SKIP, чтобы после входа/выхода из подпрограммы пропустить n подметок для выбора подфункций. То есть, если в MS-DOS вызов «INT 21h» был кучей проверок AH через CMP-JZ, то в x80 «LOOP CALL» сам пропускает n команд JMP неявным префиксом SKIP (просто «LOOP+CALL» обрабатывается как «CALL+SKIIP») DLY - режим префикса WAIT. Тот же LOOP, но цикл прерывается флагом CF. Только из-под Wait можно обратиться к медленным устройствам ввода/вывода и узнать точное значение задержки. А «WAIT SUB» работает как деление… SYS - признак Ring #0 для кода ядра операционной системы Тем самым, узел выборки команды делает практически всё, чтобы выполнить любые экзотические сочетания кодов. Так, для x86 коды «EB FE» и «EB FF» являются экзотикой с замыканием «JMP» на себя. А в x80 это просто префикс «WAIT» и команда «RET» соответственно, так как в прикладном коде они обильно не используются и отдельно не засоряют таблицу команд. И уже на стадии выборки команды из памяти вылавливаются случаи замыкания и превращаются в особые префиксы регистра IB, условно названными постфиксами… Удивительно, но в эмуляторе логику этой схемки повторить, оказалось, не так легко. Это обрушивается, буквально, всю систему команд! То есть, из таблицы исчезли все команды, так как генератор массива не был рассчитан на то, что код 00 будет тоже префиксом, но в режиме ядра. Через него индексная адресация памяти превращается в адресацию ячеек регистрового файла. Если раньше, на стадии дизайна эмулятора, я код 00 под ядром задумывал как единственную команду доступа к регистровому файлу, то после дизайна схемы выборки команд понял, что можно 00 оформить под супер-префикс. Поэтому в эмуляторе это всё и обрушило! Хотя на уровне схемы всё упростилось и появилась дополнительная гибкость для работы с регистровым файлом… P.S.: Короче, такие вот дела…
Вчерa весь вечер потратил на перенос схемы с LogiSim в Proteus… Так как многие логические элементы изображаются фигурными и слишком крупно, пришлось изрядно потрудиться и над IEC-дизайном. Почему-то в LogiSim с этим особых проблем не возникало, тогда как в OrCAD и Proteus дефолтная графика слишком по-детсадовски огромна! Не удалось применить микросхемы одной серии и пришлось смешивать S/ALS/F/HC/HCT, что уже довольно не хорошо! А когда почти закончил, ахнул от величины схемы в корпусах: 20 микросхем! Почему почти? Один бит (самый старший в ID на LogiSim-дизайне) не смог никуда разместить! Отдельно ТМ2 добавлять - тоже не очень красиво, так как помимо тактового входа требуется ещё разрешающий. А это требует вентилей опять же… И U19/U20 корпусами выдались как знаменитый ИД3! В общем, теперь сижу и думаю… По-своему красиво было бы процессор свой живьём собирать отдельными платками-модулями для каскадной сборки. А с другой стороны - никак не ожидал, что модуль выборки команд получится таким концентрированным, объёмным и сложным… P.S.: Два месяца прошло, а чем серьёзнее я хватаюсь за идею, тем больше разочарования и ошеломительных подробностей…
Подогнaл эмулятор под новые реалии… Идеология Напомню, что опираясь на опыт коллег (PICO-8, MegaProcessor, MyCPU, Gigatron и т.д…), собственными окольными путями пытаюсь построить собственный процессор без предрассудков: Мне не нужно запустить архитектуру с колена, чтобы состряпать хоть что-нибудь и это поехало лампочками мигать и фракталы Мандельброта строить… План прост по-идее, но сложен в перспективе, так как локально планируется переразработать всю линейку архитектуры Intel с нуля. А именно, так как i8080 и i8086 программно никак не совместимы, а система команд обоих оставляет желать лучшего, то поставил план разработать 8-битную архитектуру с расширением до 16 бит или до 32, причём с программной совместимостью в обе стороны… Ошибки Intel прослеживаются с самого начала: На уровне машинного кода i8080 и i8080 абсолютно несовместимы На уровне ассемблера совместимость частичная, хоть и заявлялось о ней Поддерживаются рудиментарные команды (i8080: 32/3A - STA/LDA; i8086: A0/A1/A2/A3), которые все не перечислишь, но в современном защищённом режиме их наличие - бессмысленно Гибриды типа NEC V20 пытались поправить ситуацию, но всё оказалось безнадёжным Тем самым, был просто взят процессор i8080 во всей его красе и система команд была перераспределена из восьмеричной в шестнадцатеричную и удалены команды с 16-битными константами. И даже можно увидеть ту же систему команд i8080: Но это не совсем так. Система команд прорабатывалась в гуманитарном русле так, чтобы дампом байт-кодом можно было легко как прочитать алгоритм, так и набить его. А это значит, что никакой аппаратной экономии на реализации дешифрации команд не соблюдается, чтобы сам код команды в большинстве своём являлся и смысловой мнемоникой. Код BC -> логика «Branch by Carry» -> команда «JC» Код BE -> логика «Branch by Equal» -> команда «JZ» Код CF -> команда инверсии флага CF -> команда « CMC»… Так как в перспективе, если ядро строить на RISC-процессоре, нету абсолютно никакого смысла портить стройную таблицу команд в угоду тактического упрощения схемы декодирования кода команд. Перезагрузка В связи с карантином я всё-таки взялся за доработку своего JS-эмулятора в HTML и подогнал его под новый план. А именно… Чтобы в процессоре поддерживалась многозадачность на уровне регистрового файла с переключаемыми контекстами, необходимо иметь команды для управления служебными регистрами. В IA-32 для этого ввели привилегированные команды в общую систему команд. В моём процессоре код 00 в приложении является командой останова «HLT». Но на уровне супервизора останов, как таковой, не требуется. Тем самым, код 00 в режиме ядра является «супер-префиксом», через который можно программировать критические регистры. И разработанный мною эмулятор под этот «супер-префикс» оказалось не так просто переделать, на что ушло трое суток! Тем не менее, эмулятор заработал, но минимальный BIOS под него не готов, чтобы запустить тот же Тетрис… Скрепя сердце, добавил однобайтовые LOOP/SKIP-команды. Теперь кодом «E4 DA» работает как «RAR AL,4» в цикле. Но, если команде «MOV AL,[SI+7]» добавить цикл, то цикл превращается в префикс и команду «MOV AL,[SI+reg+7]», чем достигается уже значительная гибкость. Тем самым, команда, с учётом всех префиксов, может достигать длины до четырёх байтов. Аппаратная реализация Как программисты-электронщики, можете понимать, что порою программная реализация несколько сложнее аппаратной. К примеру, буфер экрана ZX-Spectrum с его нелинейной адресацией массива пикселей программно требует кучи сдвигов, тогда как в FPGA это вопрос перенаправления сигналов на уровне переназначения проводов шин. Правда, представленная выше схема выборки команды уже требует доработки, так как без выборки префикса она даёт код 8, а с «супер-префиксом» - код 0. Это сильно путает таблицу истинности casex дешифратора команд, потому необходимо просто поменять местами коды 0 и 8 добавлением вентилей. Но, в целом, эскиз схемы, выполненный средствами JavaScript, вполне оправдал себя и показал свою работоспособность. Что я записал, ради прикола, в видео с аппаратным дизассемблером.
Думaю, за неделю мне удалось продвинуться вперёд к реализации своей мечты. Если помните, я крайне критически отношусь к инженерам в плане их художественных чувств: Мне не нравится эстетическая сторона таблиц команд многих процессоров, так как инженеры вообще не думают об эстетике машинного кода, который потом будет использоваться многими десятилетиями. А так как мой CISC x80 продумывается именно с позиции эстетики, таблица команд у него интуитивно понятная и прозрачна, хотя и имеет некоторые нюансы и исключения. И было бы проще пытаться реализовать его на RISC-ядре, чтобы любой код можно было прошить легко. Но какой процессор тогда использовать за ядро? Ведь предлагаемые процессоры нужно ещё и научиться программировать! Тем более, их система команд никак не интуитивно понятная. А значит, идеологически это будет уже минусом! Задался я вопросом разработки своего RISC-процессора с интуитивно ясной системой команд, где отдельные нибблы байт-кода обозначают аббревиатуру закодированной инструкции. Дело это оказалось не очень простым и я удалил всему этому более года… Основное положение Процессор задумывался таким, чтобы для написания программы не требовался никакой транслятор типа ассемблера. А опытный программист мог бы в любом редакторе дампа как написать свой код, так и понять уже написанное в русле WYSIWYG - что видится, то и означает. Тем самым, сначала был построен регистровый файл из четырёх групп, по 10 регистров в каждой. A0…A9 - десять регистров аккумуляторов (A0 - статус АЛУ с флажками) B0…B9 - десять регистров указателей базы для доступа к ячейкам памяти C0…C9 - десять регистров счётчиков байтов в памяти по указанным базам D0…D9 - десять внешних устройств со скоростным непосредственным доступом Первая схема не позволяла обратиться одновременно к значениям двух регистров одной группы и это значительно усложняло программирование, снижая производительность и гибкость. Потому я занялся разработкой двухпортовых групп. Узел управления шинами и выборки команд из памяти я долго отлаживал отдельно. В конце-концов обошёлся лаконичным решением на сдвиговом регистре и мудрёной комбинаторики. Дешифратор команд я сначала рассчитывал на большее количество - до 28. Потому сейчас он выглядит у меня несколько странным и избыточным. Теперь я понял, что достаточно обойтись одним дешифратором без ИЛИ-НЕ вентилей. Но переделывать пока не хочется, так как потребуется перебивать таблицу прошивки ПЗУ с определением команд. Система команд управляет всем процессом в машинном коде на понятном для оператора WYSIWYG-языке и составляет следующие команды: 00 - HLT (команда останова упразднена, но работает как расширенный код) 01…99 - BCD-код десятичных чисел 1…99 приращиваемый к активному аккумулятору 0A…9F - АЛУ-операция над активным аккумулятором и вторым аргументом с индексом 0…9 A0…A9; B0…B9; C0…C9; D0…D9 - переключения индекса в заданной группе регистров AA…AD; BA…BD; CA…CD; DA…DD - выбор состава операндов для АЛУ-операций AE / BE / CE / DE - экстракция данных из ОЗУ в заданную группу AF / BF / CF / DF - фиксация данных из регистра указанной группы в ОЗУ E8…EF - условное выполнение следующей операции (execute by: Carry, Equal, Fiction…) F0 - завершение текущей подпрограммы (Function Over) E0…E7 и F1…FF - переход на адрес E000…E700 или F100…FF00 соответственно Тем самым, это - и есть вся система команд! Например, вот чуточку кода для прояснения кодирования алгоритмов: Код (Text): ; Инкремент регистра A7 на единицу AA |USE A,A ; Группа операндов A,A A7 |USE A7 ; Индекс аккумулятора - A7 01 |ADD A7,1 ; Прибавляем BCD-константу ; Декремент регистра C9 на единицу CC |USE C,C ; Группа операндов C,C C9 |USE C9 ; Индекс аккумулятора - C9 85 |ADD C9,85 ; Прибавляем BCD-константу (+85) 85 |ADD C9,85 ; Прибавляем BCD-константу (+170) 85|ADD C9,85 ; Прибавляем BCD-константу (+255) ; Копирование значения из B0 в A9 AA |USE A,A ; Группа операндов A,A A9 |USE A9 ; Индекс аккумулятора - A9 9E |EOR A9,A9 ; Очищаем A9 AB |USE A,B ; Группа операндов A,B 0D|OR A9,B0 ; Дизъюнкция A9 и B0 (старший ниббл - 0) ; Те же операции, но в более краткой форме ассемблера AA A7 01 |INC A7 CC C9 85 85 85|DEC C9 AA A9 9E AB 0D|MOV A9,B0 ; Пример вызова подпрограммы и возврата из неё F012 F1 |F1 ; Вызов Функции по 0xF100: B0 <= 0xF0; C0 <= 0x12 F013 00 |HLT ; Останов: Переход на 0x0000; B0 <= 0xF0; C0 <= 0x13 .... .. ............ F100 CC C0 01 |INC C0 ; Теперь в B0:C0 будет значение 0xF013 F103 B0 F0 |JMP B0:C0 ; Переход по B0:C0, а в B0:C0 помещается адрес 0xF104 Ниже в архиве файл с HTML-дизассемблером (эмулятор не написал, так как работы схемы интереснее выглядит), который поможет вникнуть в систему команд. А так же в архиве имеется сама схема для LogiSim с прошивками ПЗУ и ОЗУ. Пока сложную программу я ещё не написал, так как оттачивал и упрощал всю систему команд в целом. Дешифрация команд производится на элементах ИЛИ-НЕ по матрице в ПЗУ и изначально рассчитывалось всё 24 группы команд. Однако, практика показала, что достаточно иметь и 10 групп. P.S.: Тем самым, я убедился, что и RISC-архитектуру можно спроектировать с красивой и прозрачной системой команд!
Может быть набор команд красив и прозрачен, но ужасно перегружен избыточной информацией. У тебя 4 группы операндов, это кодируется 2мя битами, ты используешь 8, 10 номеров регистров (странный выбор), это кодируется 4мя, но ты используешь все 8. В итоге всего лишь инкремент регистра занимает 24 бита. Если так прямо хочется без ассемблера писать, тот же нибл, то есть один шестнадцатиричный разряд, вполне себе нагляден и удобен в этом плане.
И этo Вы мне говорите в XXI веке??? Когда чудные файлы конфигурации *.ini/*.inf заменяют повсеместно на громоздкий *.xml? Когда давным давно похоронили формат музыкальных партитур Sol20, известный у нас некогда как Музыкальная Система РАДИО-86РК и который заменили на MusicXML, где одну несчастную ноту описываешь килобайтом тегов? О чём я и говорю! У меня таки нибблами и оперируется всё… То есть, такая гадость, как эзотерика битовых полей, пронизывающая буквально все известные архитектуры, должна поддерживаться безоговорочно вот так? Код (Text): IIII DS TR DSID TRID - 16 бит 1010.10.01.0010.0001 = ADD A2,D1 IIII - Инструкция DS - Группа регистров назначения TR - Группа регистров-трансляторов DSID - Индекс регистра назначения TRID - Индекс регистра-транслятора Не достаточно ли того, что релейный BrainF*ck-компьютер можно запускать в серийное производство с полным Google-финансированием? Помнится, в x64 коды однобайтового инкремента/декремента (0x40…0x4F) упразднились давным-давно… Просто я сделал то, что давно кто-то должен был сделать… Хватит эзотерики битовых полей в машинном коду XXI века! Если добыть ещё К1533ИР39, то число всех микросхем данного процессора сократится и составит примерно 40 ТТЛ-корпусов… А купив 512 штук подобных переключателей можно собрать их в электромеханический дамп на 256 байтов для имитации ПЗУ. Тогда уж реально голыми руками можно кодировать нибблами всю программу загрузочной части памяти… Сейчас занимаюсь доработкой Verilog-модели (в Quartus получается примерно 395 ALM) и пытаюсь эмулятор хоть какой-то сделать. Накидал структурную схему…
Я за 10 лет копания в микроконтроллерах только месяца три назад впервые увидел чтоб был применен такой, где аж 8 мегабайт внутреннего флеша. Обычно выкручивались с максимум 2мя внутренними 2мя во внешей флешке. Это в XXI веке-то. Довольно много, но если проскалировать длины инструкций в 3-4 раза, просто потому что так хочется, можно смело делить в уме объем флешки на 3-4. Это в XXI веке, когда писать прошивки даже на цэ уже моветон, будущее за перетаскиванием иконок в конструкторе. Если кто-то и должен был однажды сделать архитектуру, которую можно программировать в нех-редакторе, то явно не в XXI веке.
Пoдчиняясь настроениям многих, я 20 лет прокопался в i8080/z80 и не согласен, что z80 или 6502 - идеальны. Хотя, энтузиасты собирают: Фокус данного KISC-процессора в том, что его Logisim-схему я за год перерисовывал раз 5 с чистого листа, лишь чтобы вид схемы был внешне красивее. При этом, могу сказать, что Fetch-модуль - очень запутанный, так как модуль контроля в него вклинился и нужно потихоньку их разделять. Запутанный - не значит сложный, так как по Verilog можно судить, что ничего чрезмерно сложного нет в моей архитектуре - 386 синтезируемых строчек кода… То есть, имея в наличии всего 2 дефицитные микросхемы, можно из 40 ТТЛ корпусов собрать то, что не требует ассемблера! В условиях постапокалипсиса не нужно даже иметь таблицу команд под носом, так как вдумавшись в её смысл 1 раз, она легко запоминается. И она - наращивается: до 106 своих однобайтовых инструкций добавляется легко, как подпрограммы. Итого - имеем: Легко собирается на коленке за неделю Легко программируется голым байт-кодом Лесли 8 битов мало - наращиваем регистровый файл до 16, 24 или 32 бит, так как регистровый файл - живёт отдельно. Но при 16 битах получается уже до 4 Гб памяти из-за адресации по Bn:Cn-парам. Тем самым, однобайтовые команды остаются, но внутренняя разрядность увеличивается (трюк i8088) В прикреплённом эмуляторе код процессора транслируется прямо в JavaScript-запись: Хочу попробовать сделать не просто эмулятор, а подобие Java-машины. Тем самым, теоретически, можно добиться очень высокой производительности в браузере, если решить проблему ветвлений, как рвущих всю цепь эмуляции… P.S.: Архитектура получилась «Just must to be…» и переделывать её уже нет смысла: Почти эталон того, как могли бы начинать делать паровые процессоры в XIX веке.