Чтo бывает, когда на месяц исчезает полноценный доступ в интернет?
x80-CPU - доработка:
Взялся допиливать свой x80-эмулятор спустя год. С неделю ушло на вникание в суть собственного JS-листинга.
За месяц доработал концепцию системы команд, устранил множество тупейщих глюков (вылавливал некоторые до 3-5 часов, топчась на месте всю ночь).
Что хочу сказать по поводу внесённых доработок и нововведений…
- У флагового регистра обычно возможны невозможные комбинации. Например, когда SF и ZF установлены, получается, что результат равен НУЛЮ и так же имеет знак МИНУС. Всего насчитывается 6 подобных нереальных комбинаций. Они используются для особых случаев. Таких, как повтор следующей инструкции n-раз или пропуск n-ого числа инструкций. Чем управляют инструкции SKIP/LOOP;
- Префиксированные инструкции HLT оформились в опции регистра или числа для разных операций. Так, перед CALL/INT можно указать, какой именно регистр нужно использовать, например, в печати символа, числа, адреса или сообщения;
- Инструкции PUSH/POP могут использовать и 8-битные РОН в рамках внутреннего мизерного стека / регистрового файла* (здесь пока всё сыро и требует много переработок исходника эмулятора).
* - детальнееCode: Select all
EX-Register
__ .0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .A .B .C .D .E .F
00:Ячейки управления распределением страниц памяти|RAM Dispatcher
10:Ячейки управления распределением страниц памяти|RAM Dispatcher
20:Ячейки управления ловушками в процессе отладки-|Debug Managing
30:Счётчики тактов, циклов, прерываний и т.д.-- --|Process Counters
40:JP>>LO>> ++ .. -- -- -- JP>>HI>> ++ .. -- -- --|JP-File
50:SP>>LO>> ++ .. -- -- -- SP>>HI>> ++ .. -- -- --|SP-File
60:BP>>LO>> ++ .. -- -- -- BP>>HI>> ++ .. -- -- --|BP-File
70:IP>>LO>> ++ .. -- -- -- IP>>HI>> ++ .. -- -- --|IP-File
80:SI>>LO>> ++ .. -- -- -- SI>>HI>> ++ .. -- -- --|SI-File
90:DI>>LO>> ++ .. -- -- -- DI>>HI>> ++ .. -- -- --|DI-File
A0:AL>>LO>>Стек истории -- AH>>HI>> ++ .. -- -- --|AX-File
B0:BL>>LO>>модификации- -- BH>>HI>> ++ .. -- -- --|BX-File
C0:CL>>LO>>всех РОН- -- -- CH>>HI>> ++ .. -- -- --|CX-File
D0:DL>>LO>> ++ .. -- -- -- DH>>HI>> ++ .. -- -- --|DX-File
E0:Стек конвейера с историей исполненных операций-|Execution Pipeline
F0:-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --|Execution Pipeline
+0:Зона особого назначения ???????????????????????|Service context
EX-Регистр - хранит контекст процессора.
Ячейками с 50h по DFh непосредственно связаны все РОН в режиме стекового файла с
глубиной до 8 уровней. Тем самым, когда какой-либо регистр изменяется, автоматом
история его изменений циклически сдвигается от ячейки с x0h/x8h к ячейке x7h/xFh
соответственно. Это позволяет в отладчике частично прокрутить историю исполнения
кода в обратном направлении. Так, ячейки 0-FFh доступны программе в произвольном
доступе. Ячейка +0 - это 256 управляющая ячейка управления переключением страниц
контекста, доступная только операционной системе, хранящая маску доступности для
остальных ячеек +1..+7 (257..263).
Битами этих сервисных ячеек можно "заморозить" историю контекста, чтобы получить
произвольный и точный доступ ко всем доступным моментам или сохранить контекст и
подготовить его для переключения к следующей задаче.
Подробнее:
HLT R/P: Фиксирует индекс РОН или регистровой пары в флаговом регистре для особых операций или управления повтором/пропуском/трюков;
HLT N: Фиксирует число 1-7 в флаговом регистре для особых операций или управления повтором/пропуском/трюков;
LOOP R: Управляющая инструкция LOOP CL выставляет флаги SF PF ZF, что фиксирует указатель инструкций IP на месте до автоматического обнуления CL. Так можно выполнить, например, инструкцию RCL AL нужное число раз, указываемым через CL;
LOOP N: Управляющая инструкция LOOP 5 выставляет флаги SF PF ZF, что фиксирует указатель инструкций IP на месте на период до 5 циклов. Всё это время, например, следующая инструкция RCL AL будет исполняться;
LOOP [R]: Управляющая инструкция LOOP [CL] выставляет флаги SF PF ZF, что фиксирует указатель инструкций IP на месте на период до 7 циклов, указаных тремя битами регистра. Так можно выполнить, например, инструкцию RCL AL нужное число раз, указываемым через CL;
SKIP R: Управляющая инструкция SKIP DL выставляет флаги SF ZF и сбрасывает PF, что блокирует шину фиксации результата на период до автоматического обнуления DL. Тем самым, все следующие операции продолжат дешифровываться, но не будут результативными;
SKIP N: Управляющая инструкция SKIP 7 выставляет флаги SF ZF и сбрасывает PF, что блокирует шину фиксации результата на период до 7 циклов. Тем самым, все следующие 7 операций дешифруются, но не будут результативными;
SKIP [R]: Управляющая инструкция SKIP [DL] выставляет флаги SF ZF и сбрасывает PF, что блокирует шину фиксации результата на период до 7 циклов, указаных тремя битами регистра. Тем самым, все следующие операции продолжат дешифровываться, но не будут результативными;
NOP N: Холостая операция с длительностью до 7 дополнительных тактов;
XCHG: Трюковая инструкция зеркального обмена всех битов в регистре, указаном через HLT R;
XCHG R: Трюковая инструкция обмена значениями указанного регистра с регистром, выбранном через HLT R;
XCHG P: Трюковая инструкция обмена значениями указанной регистровой пары с парой, выбранной через HLT P;
PUSH/POP: Трюковые операции (регистр не указан) используют регистровую пару, выбранную через HLT P;
INT 0-9: Обращение к функции прикладной программы. Используется общий регистр указателя на обработчик;
INT 10-79: Обращение к функциям системного API. Используется системный регистр указателя на BIOS-обработчик.
CALL/Ccnd: Замыкание вызова на саму себя изменяет флаги SF PF ZF, подобно трюковым SKIP/LOOP без указания регистра. Комбинация HLT R/P и CALL-замыкания - длинное подобие LOOP/SKIP.
Период тестирования:
На данный момент более-менее отладил дизассемблер, ассемблер и сам дешифратор команд.
Пока написал жалкое подобие BIOS с несколькими крошечными библиотеками:
INT 10-19 - функции работы с памятью (пока 0% написано);
INT 20-29 - функции работы с текстом (5%);
INT 30-39 - функции работы со звуком (1% - Beep);
INT 40-49 - функции работы с данными/математикой (0%);
INT 50-59 - функции работы оборудованием (0%);
INT 60-69 - функции работы с потоками/файлами (1% - GetChar/Inkey/IsPressed);
INT 70-79 - функции работы с дисплеем/окнами (10%).
В целом, проделанный труд доставляет некоторое удовольствие своей работой.
В самой BIOS работают несколько директив: (D)ump / (G)oto / (I)dle.
Idle просто дублирует поток с клавиатуры/буфера в окно собственного дисплея - тестирую производительность скроллинга и т.д.
Напомнить, про что шла речь давным-давноСистема команд i8080 была мнемонически подогнана под стиль x86 (MVI A,3 -> MOV AL,3; DAD D -> ADD BX,DX; XTHL -> XCHG IP,[SP] и т.д.) и пересортирована:
Code: Select all
00 - HLT (0 - завершает текстовые строки, заполняет значительную часть памяти и т.д.);
tr - MOV r,t (если t и r умещаются в восьмиричный диапазон, то t индексует регистр-транслятор данных в регистр-приёмник r: 40 - MOV [BX],AL / 04 - MOV AL,[BX]);
nn - prefix n (если младшая тетрада кода команды и старшая - равны и умещаются в восьмиричный диапазон, то это - префикс: 11 - Prefix BH/BP / 77 - Prefix DL/DX);
rC - AND AL,r (Conjunction - конъюнкция аккумулятора с регистром: 5C - AND AL,BL);
rD - OR AL,r (Disjunction - дизъюнкция аккумулятора с регистром: 6D - OR AL,CL);
Ar nn - MOV r,nn (загрузка байта в регистр: A7 34 - MOV DL,0x34);
Bc nn - Jc/Cc $+nn (Branch - условное ветвление: BC 09 - JC $+9 / BE FD - JE $-3);
Ep - PUSH ptr (Enter ptr to stack - код явно указывает на имя регистровой пары: EB - PUSH BX / EC - PUSH CX / ED - PUSH DX);
Fp - POP ptr (Fix ptr from stack: FC - POP CX);
Fn - INT n (Function 0-9 - прерывание на функцию n: F1 - INT 1 / F9 - INT 9);
FE - NOP (Fictive Execution - фиктивная холостая операция);
FF - RET (Function Final - завершение функции).
Если перед командой стоит префикс, она несколько изменяется:
Code: Select all
22 00 - HLT CH/SI (Hold CH/SI - захват регистра перед обращением к функции);
55 55 - HLT 5 (четыре одинаковые цифры - захват этой цифры для передачи функции);
22 5C - AND CH,BL (префикс подменяет аккумулятор нужным регистром);
11 6D - OR BH,CL;
77 A7 34 - MOV DL,[DX+0x34] (загрузка байта в регистр из памяти со смещением);
33 F5 - INT 35 (прерывание расширяется до индекса с десятками);
44 FE - NOP 4 (холостая операция продливается на 4 такта);
66 ED - SKIP 6 (Exclude by Data 6 - исключение результативности до 6 инструкций);
55 EC - SKIP BL (Exclude by Counter BL - используется регистр за счётчик);
33 EB - SKIP [DH] (Exclude by Buffered DH - значение счёта берётся из регистра);
77 FD - LOOP 7 (Force til Data 7 - форсировать инструкцию на 7 циклов);
B9 FE - WAIT (CALL замкнутая на себя - выполнение следующей инструкции в цикле (с декрементом регистра/счётчика) до прихода сигнала от внешнего устройства).
Тем самым, ассемблерно система команд сходится с i8086, что упростит перенос некоторых алгоритмов. А по режимам адресации почти не уступает i8086, что предлагает дополнительную гибкость кода, почти как у Z80.
Например, чтобы получить доступ к портам ввода/вывода, необходимо регистр BP выровнять под IP. Так как считывать/записывать данные косвенно по BP вблизи исполняемого кода нельзя, открывается окно на 256 портов.
Code: Select all
EB EC PortIn:PUSH BX,CX ; Запоминаем регистры
66 CF XCHG CL ; Узнаём предельный интервал ожидания
B1 +9 FB LEA BX,.input ; Выравниваемся по указателю команд
45 MOV BL,AL ; Устанавливаем индекс порта
11 55 XCHG BP,BX ; Открываем портовое окно через BP
4B SUB AL,AL ; Сбрасываем флаг переноса CF
66 00 HLT CL ; В ожидании используется CL
B9 FE WAIT ; Перевод процессора в цикл ожидания
11 A4 00 .input:MOV AL,[BP+0] ; Читаем порт до тех пор, пока CL > 0 и флаг CF равен внешнему сигналу
66 AA FF ADD CL,0xFF ; Если CL обнулён, значит готовности порта не дождались и CF обнуляем
11 55 XCHG BP,BX ; Восстанавливаем указатель
FC FB POP CX,BX ; А также все регистры
FF RET ; Возвращаемся
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EC GetKey:PUSH CX ; Процедура ожидания и ввода с клавиатуры
A5 21 MOV CL,0x21 ; Длительность ожидания - до 33
A4 60 .loop: MOV AL,0x60 ; Индекс порта клавиатуры
66 00 HLT CL ; Счётчик ожидания - CL
B9 DD CALL PortIn ; Вызываем процедуру чтения с порта
BD F8 JNC .loop ; Зацикливаемя до первого ввода с клавиатуры
FC POP CX ; Восстанавливаем регистр
FF RET ; Возвращаем код клавиши
Имеется ещё одна любопытная особенность: Так как я своими силами не могу реализовать полноценный конвейер с распараллеливанием под Verilog, концепция процессора подразумевает явный параллелизм и ускорение некоторых фрагментов алгоритмов.
Так как в файле контекста текущей задачи процессора всегда хранятся значения всех регистров и цепочки последних выполненных инструкций, то некоторые из цепочек можно объединить в одну инструкцию и выполнять в рамках статического доступа к файлу контекста. Тем самым, на каждую инструкцию будет затрачен всего 1 такт. Всего можно выполнить цепочку до 7 инструкций.
Никакой особой инструкции в системе команд для этого не предусматривается.
Сначала следует команда SKIP 1-7, которая пропустить даром следующие инструкции до 7 штук. Во время пропуска, все их коды сжимаются и попадают в отведённый буфер контекста.
Затем, после заполнения буфера нужными инструкциями, переходим к команде HLT 1-7/REG, чтобы зафиксировать продолжительность цикла.
После всего, следует операция WAIT для запуска цикла ожидания. За которой нужно обязательно указать префиксированную холостую операцию NOP 1-7.
Только в этом случае, после всех шагов, индекс операции NOP укажет, цепочку какой длины нужно выполнить в буфере контекста.
А так как операция цикла WAIT очень строгая и капризная, цикл в любой момент может прерваться, если флажки неправильно выставятся экспресс-операциями. За чем нужно строго следить.
Например, рассмотрим пример со скроллингом экрана вверх:
Code: Select all
; Исходный фрагмент кода скроллинга буфера экрана без оптимизации
;;;;;;;;;;;;;;;;;;;;;;;;;
...rows:ADD BX,CX ; Движемся циклом снизу вверх по экрану
MOV DL,AL ; Берём код затёртого символа строкой ниже
MOV AL,[BX] ; Считываем код затираемого символа
MOV [BX],DL ; Записываем затёртый ниже символ сюда
DEC DH ; Считаем число смещаемых символов в столбце
JNZ ...rows ; И циклом заставляем ползти символы вверх
Код специально построен так, чтобы в оконном режиме прокручивать произвольный прямоугольник. Как видно, код ничем не отличается и выглядит привычно. Правда, работает значительно медленнее, чем хотелось бы. Поэтому, переходим к рассмотрению следующего кода с оптимизацией:
Code: Select all
; Тот же фрагмент кода, но с оптимизацией
;;;;;;;;;;;;;;;;;;;;;;;;;
SKIP 4 ; Следующие 4 инструкции сейчас проигнорируются
ADD BX,CX ; 1.Движемся циклом снизу вверх по экрану
MOV DL,AL ; 2.Берём код затёртого символа строкой ниже
MOV AL,[BX] ; 3.Считываем код затираемого символа
MOV [BX],DL ; 4.Записываем затёртый ниже символ сюда
HLT DH ; Захват регистра за счётчик строк столбца
WAIT ; Активация режима ожидания с ограничением по времени - DH
NOP 4 ; Теперь пропущенные выше 4 инструкции из буфера
; будут выполняться циклом в турбо-режиме
Первое, на что можно обратить внимание - отсутствие метки и команды ветвления. Бинарно размер кода увеличился с 8 байтов до 13. Однако, так как теперь выполняется лишь одна операция NOP 4, прирост в скорости на экрана виден сразу примерно на 20%.
Естественно, имеются сильные ограничения. Например, в экспресс-цепочке нельзя использовать команды ветвления, программных прерываний, управления сменой режима.
Ограничения имеются и на константные операнды команд - они усекаются до 5 бит. Т.е. операнд 0x7C станет 0x0C, 0x82 - 0xF2. Что требует выносить все константы за границы самих инструкций, заранее загружая их в регистры.
А ограничение на цепочку до 7 инструкций - не такое уж существенное. Так как в ряде случаев достаточно обойтись и парой инструкций.
Так, аналог команды REP MOVSB от x86:
Code: Select all
SKIP 4 ; Следующие 4 инструкции пропускаем и помещаем в экспресс-буфер
MOV AL,[BX] ; 1.Читаем байт источника
INC BX ; 2.Двигаемся к следующему
MOV [DX],AL ; 3.Записываем байт в приёмник
INC DX ; 4.Подготавливаемся принимать дальше
HLT CL ; Счётчик количества копируемых данных - CL
WAIT ; Всё готово к началу цикла
NOP 4 ; Теперь данные скопируются несколько скорее
На скриншоте в архиве можно увидеть систему команд в действии эмуляции под Chrome.
Ниже - вся система команд (в левом верхнем углу числа +11..+77 означают код префикса перед этими командами:
0_7x80.gif
P.S.: К своей идее отношусь как к хитрой головоломке:
Когда вокруг меня все тычат пальцами в экраны своих андроидов с цветными камнями или монстрами, свои мозги тренирую в проработке собственного процессора и архитектуры
Скоро выложу эту текущую версию в свой GitHub (когда набросаю заготовку Тетриса или Ксоникса

).
1 декабря 2016
Чем мне нравятся форумы с похожими настройками, так это отключенными ограничителями редактирования собственных постов.
Спасибо Администрации

Так как это позволяет дополнять собственные мысли и при этом - не быть назойлевым, неприятно поднимая собственную тему снова и снова…
А те, кому тематика интересна, рано или поздно и так обнаружат дополнения…
Многие из интересных тем этого ресурса, как например "Троичный компьютер" или заказные троичные чипы, довольно интересны…
Но, как мне видится, главный недостаток многих тем в том, что основное большинство просто следит за продвижением идей или наблюдает за попытками их реализации. В подавляющем большинстве случаев - совершенно пассивно. Иначе, например, могли бы вместе сложиться копеичками и собрать на партию заказных микросхем. Правда, при условии, что кто-то их протестирует заранее в симуляторах и устранит очевидные ошибки…
Ну, да ладно, не мне вмешиваться в чужие дела…
По другому поводу я решил здесь изложить некоторые дополнения.
Дело в том, что в очередной раз пересматривая схему РЛК с
попыткой внесения незначительных изменений, заметил одну интересную вещь. Читал, что производство микросхем с цоколовкой, отличной от DIP-14 или DIP-40 в те времена было достаточно проблематичными. Хотя у M68000 насчитывалось целых 64 вывода… Ведь, например, встроить ПДП в сам процессор, как это было в Денди на 6502, было бы вполне реально, так как внутренние шины процессора и ПДП во многом идентичны, да и позволило бы избавиться от
глупого захвата шин с их задержками во времени.
Как я выше уже писал, в своих набросках процессора я возложил рутину ПДП на сам процессор. Причём, не простым набором счётчиков, а отдельным служебным процессом…
Вот с чем идёт битва и сложный стратегический процесс - так это порты! Ладно, многие предлагают устройствам отводить часть общего адресного пространства, как в РЛК, не заморачиваясь. Но, у Intel была одна любопытная идея, однако, реализованная крайне безобразно.
Речь идёт про Esc-инструкции. В документации процессора i8086 про Esc-инструкции говорится как об универсальных, которые могут применяться и математическим сопроцессором в частности. Хотя, из документации предполагалось менее конкретное их назначение. Но, как я понял, решение окончательно определить их за арифметику - просто загубило их изначальную универсальность.
Таким образом, на данный момент я работаю над тем, чтобы избавиться от
рудиментов портового доступа к УВВ и приблизиться к неким Esc-аналогам.
Выше я уже писал, что испытывал сложности с операциями повтора инструкций присвоения, как loop 7 + mov al,bl… Понятно, что бессмысленно много раз производить пересылку из регистра в регистр. И выход был найден.
Так, циклические LOOP-операции с MOV-пересылками работают подобно Esc-операциям из x86. Тем самым, если нужно передать или принять данные через регистры с УВВ, нужно просто указать в LOOP число параметров и разместить далее MOV-команды. Чем будет достигаться внедрение УВВ в саму систему команд процессора…
You do not have the required permissions to view the files attached to this post.