:h1.Язык Ассемблера
:p.
Эта электронная книга содержит описание команд языка Ассемблера, позволяющего
написать и отладить ядро операционной системы реального времени вместе со всеми
драйверами, которые потребуются ей для дальнейшей работы. Транзисторные цепочки
могут быть написаны на языке VHDL или Verilog, так что полученный исполняемый 
код будет способен работать на программируемых логических интегральных схемах 
(ПЛИС), которые будут выглядеть в точности так же, как микропроцессоры, но не 
будут способны работать с высокой тактовой частотой.
.br
:artwork align='center' name='0001-Intro\Images\OS2WarpLogo.bmp'.
.br
Вполне возможно, что полученные транзисторные цепочки позволили бы создать и 
настоящий микропроцессор, который был бы способен работать с любыми внешними 
устройствами, включая оперативную память, но заранее трудно выяснить, сколько
он будет стоить: вполне возможно, что новый микропроцессор может быть создан, 
но не может быть продан (во всяком случае, сейчас), так что в книге нигде 
прямо не сказано, что речь идёт о микропроцессоре.

:p.
Достаточно и того, что язык Ассемблера был проверен во время его изобретения.

.*

:h2.Краткая статистика
:p.
За долгие годы, для того, чтобы выполнять программы на языках высокого уровня, 
было изобретено около трёхсот команд:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Statistics-1.rc'.
:font facename=default.

:p.
Если делать их на ПЛИС, почти половина из них будут нужны для того, чтобы 
выполнять код с других процессоров (в режиме двоичной трансляции). В конце
концов, когда команды оказались слишком длинными, поиск зашёл в тупик - но 
был продолжен, чтобы не пропустить ни одной команды.

:p.
В пересчёте на различные правила доступа к данным в памяти и режимы адресации 
(то есть "регистр-регистр", "регистр-память", "регистр-константа" и так далее), 
точек входа в арифметико-логическое устройство ("ALU") оказалось более тысячи:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Statistics-2.rc'.
:font facename=default.

:p.
При этом короткие, средние и длинные команды (от 16 до 64 разрядов) получили
тем больше точек входа, чем длиннее команда: это связано с тем, что у длинных
команд оказалось больше режимов адресации, которые задаются в виде флажков в 
заголовке каждой команды.

:p.
Всё это привело к поиску других наборов команд, они оказались RISC-подобными
и потребовали около сотни команд и двух сотен точек входа.

.*

:h2.Пример на двух языках
:p.
Примеры на языке Ассемблера уже были в книге "OS/2 API Research", но имеет
смысл повторить их здесь ещё раз. Итак, допустим, на языке высокого уровня
была написана функция "abs()", вот так:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Sample-1.rc'.
:font facename=default.

:p.
Теперь запишем её на языке Ассемблера:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Sample-2.rc'.
:font facename=default.

:p.
Как видно, здесь рассчитывается разность между двумя числами, а затем, если
она оказалась меньше нуля, знак числа в регистре изменяется на противоположный 
с помощью команды "NEG".

:p.
Двойная запись на языке Ассемблера и C-подобном языке (в столбике справа) 
помогает улучшить читаемость кода. Теперь команда "branch on zero" никого 
не сбивает с толку.

.*

:h2.Как это могло бы выглядеть снаружи
:p.
Микросхема ПЛИС, установленная на печатную плату, выглядит примерно так:
.br
:artwork align='center' name='0001-Intro\Images\FireBee-1.bmp'.
.br
И, как известно, выполнение на ПЛИС подразумевает работу с низкой тактовой 
частотой (так что в новый набор команд имело бы смысл добавить команды для 
одновременного выполнения на нескольких исполнителях внутри одного большого 
арифметико-логического устройства, "ALU"), и к тому же большинство ПЛИС имеют 
высокую цену. То, что будет на них работать, не удастся продать до тех пор, 
пока исполняемый код не начнёт запускаться на настоящих процессорах из кремния. 
И всё же, печатную плату с установленной на ней ПЛИС можно закрыть в корпус, 
который расположить на столе:
.br
:artwork align='center' name='0001-Intro\Images\FireBee-2.bmp'.
.br
Как видно, после упаковки в корпус всё это выглядит как обыкновенный 
компьютер (только медленный и очень дорогой), и на него даже может быть
установлен настоящий компьютер в плоском корпусе (или хотя бы ноутбук) с 
переключением экранов. Для того, чтобы работать с одним экраном, плата с 
установленной на ней ПЛИС передаёт видео-вывод настоящему компьютеру и 
получает от него ввод от клавиатуры и мыши.

.*

:h2.И как всё это скорее всего будет выглядеть
:p.
Как язык Ассемблера для процессора AMD64.

:p.
Да-да, именно так: скорее всего в итоге будет получен язык Ассемблера, 
позволяющий создавать код низкого уровня, работающий на процессорах AMD64.

:p.
Когда речь заходит о том, чтобы выполнять программный код, написанный для
операционной системы OS/2, надо не забывать не только о том, что возможно
сделать - но и о том, что никогда не удалось бы сделать. Мало кому удалось
бы сохранить совместимость с командами процессора i386.

:p.
Всё, что возможно - это забрать 386-й процессор с собой.

:p.
Со всеми его командами для вызова функций, порядком разрядов и режимами 
адресации.

:p.
С его флажками "больше/меньше/равно", сопроцессором на восемь регистров, 
таблицами GDT/LDT и загрузкой констант из хвоста команды.

:p.
Это кажется странным: для того, чтобы изобрести простейший язык Ассемблера,
надо залезть на один (и даже более) уровень ниже и вначале изобрести новый 
набор команд для несуществующего микропроцессора... но похоже, что именно 
так и создаются языки, понятные и человеку, и вычислительной машине.

:p.
Пусть это будет "Ассемблер с отступами" - в общем-то, этого достаточно.

.*

:h2.Немного об указателях и SIMD-командах
:p.
По мере написания этих текстов (а также изучения команд, найденных в самых 
разных микропроцессорах) мне всё больше кажется, что команды:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\SIMD_x86-1.rc'.
:font facename=default.

:p.
Надо бы заменить на команды:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\SIMD_x86-2.rc'.
:font facename=default.

:p.
Где первым параметром был бы любой регистр, константа "N" увеличивала бы 
указатель, а в регистрах "E(AX/BX/CX/DX)" задавалось бы его наибольшее 
значение. 

:p.
И объявить их SIMD-командами ("single instruction, multiple data").

:p.
Давно пора...

.*

:h2.Как можно более раннее обнаружение ошибок
:p.
Где бы пригодился такой язык - он нужен для того, чтобы написать загрузчик, 
он же "Boot Loader", и "Platform-Specific Driver", он же PSD-драйвер - то 
есть прослойку между ядром операционной системы (со всеми драйверами, которые 
выполняются вместе с ним) и оборудованием: контроллером портов и прерываний, 
переключателем потоков (он может быть и аппаратным) и другими электронными 
устройствами, которые будут разными на разных архитектурах. 

:p.
Загрузчик выполняется в режиме прямого доступа к памяти (то есть работает 
с физическими адресами) и высоким уровнем привилегий (у него вместо указателей 
на таблицы GDT и LDT заданы значения "-1" и "0", и ему доступны любые команды), 
а PSD-драйвер выполняется в защищённом режиме (то есть работает с логическими 
адресами) и тоже с высоким уровнем привилегий (у него есть указатели на таблицы 
GDT и LDT в одном из невидимых регистров, и указатель на таблицу GDT повышает 
ему уровень привилегий), при этом PSD-драйвер выглядит внешне как часть KEE API 
(сокращение от "Kernel Execution Environment" в OS/2). В самом начале своей работы 
загрузчик не может ничего напечатать на экран, и PSD-драйвер тоже этого не может 
(всё, что ему доступно - записать число в порт и включить лампочки на внешней
плате), так что проверки во время выполнения команд будут очень полезны.

:p.
На первый взгляд, вокруг полным-полно тех, кто знает Ассемблер... Но знать 
какой-либо язык программирования - это одно, а приезжать каждый день на работу 
и кодировать на этом языке - совсем другое. В случае с командами x86 станут 
помехой даже флажки состояния "conditional flags".

:p.
Должно быть очевидно, что создать новый процессор, и при этом втиснуть его в 
современные рыночные цены - очень трудно (как и купить и доработать готовый, 
не имея завода по производству полупроводников: керамика, из которой состоит
корпус процессора, стоит довольно дорого - и вряд ли что-то изменится даже в 
отдалённом будущем). Но в деле отлова ошибок в программном коде - выполнение
на ПЛИС выглядит как "работа под отладчиком", только в данном случае отладчик
был бы написан на языке VHDL или Verilog.

.*

:h2.Одновременное выполнение команд
:p.
Команды могут быть отмечены флажками "выполнять на том же или на отдельном 
исполнителе внутри арифметико-логического устройства" - или, другими словами, 
собраны в пакеты: поток может запросить от 1 до 4-х исполнителей одновременно, 
и получить 4 или 2 (если другие 2 заняты). 

:p.
Тогда, например, команда сложения с проверками "от..до" могла бы выполняться
таким образом:
:ol.
:li.Действие (исполнитель номер 1 внутри ALU),
:li.Проверка_от (исполнитель номер 1 внутри ALU), проверка_до (исполнитель 
номер 2 внутри ALU),
:li.Объединение_флажков_"И" (исполнитель номер 1 внутри ALU) и пропуск 
следующей команды, если флажки не дали логические значение "истина",
:li.Переход к обработчику ошибок или выбрасывание исключения (исполнитель 
номер 1 внутри ALU).
:eol.
.br
Как видно, это действие удаётся закодировать без команд перехода, которые 
останавливали бы ход выполнения (команда перехода вперёд очищает ALU и не 
позволяет выбрать из очереди следующую команду, что вызывает потерю одного 
или нескольких тактов процессора). Для того, чтобы ещё ускорить проверки, 
можно воспользоваться командой сравнения, где задать условие "пропустить 
следующую команду, если число попадает в заданные границы".

:p.
Доступ к регистрам из нескольких исполнителей команд на чтение: он возможен, 
если сделать регистры больше, и записывать в них числа несколько раз, 2 или 
4. Так можно сохранять целые числа и указатели, а числа с точкой потребуют 
более широких регистров.

.*

:h2.Поддерживаемые форматы команд
:p.
Как нетрудно заметить на примере вычислительных команд, многие из них имеют
один и тот же вид и в основном повторяют друг друга. Для того, чтобы их было
легче разбирать и выполнять, их удобно разделить по так называемым форматам 
команд.

:p.
Для начала были собраны все команды со всех известных микропроцессоров - и
все они были упакованы в форматы, повторяющие друг друга.

:p.
Первый разряд во всех командах равен единице, а 17-й всегда равен нулю, даже
с учётом констант "immediate" - так что во время загрузки команд сразу видно, 
где их заголовки, а где данные. Этот нехитрый приём позволит сократить длину 
транзисторных цепочек при разборе команды.

:p.
Номер исполнителя внутри ALU располагается сразу же за этой ведущей единицей, 
а затем идёт признак формата и команда с данными.

:p.
В старших разрядах формата могут быть заданы флажки: "это длинная команда,
она была полностью выбрана из кеша первого уровня, но за ней ещё записана
константа, так что команду надо раскодировать в регистры ASM Temporary и 
выполнить как макро-команду", а также правила доступа к данным в памяти - 
например, "это команда, которой нужна константа immediate из области кода, 
записанная сразу же за ней, и они помещаются в 64 разряда, так что константу 
можно забрать вместе с командой и отправить на вход арифметико-логического 
устройства, чтобы выполнить её сразу же".

:p.
Формат команды может быть коротким и длинным, что позволит закодировать их 
более гибко. Чем чаще встречается команда, тем меньше байтов она занимает.

:p.
Краткий формат получила команда, выполняющая копирование данных из одного
регистра в другой (они могут появиться перед вызовом функции), а также 
команда загрузки константы:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-16-00-1.rc'.
:font facename=default.

:p.
Команды вызова функций и возврата из них тоже пусть будут краткими:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-16-00-2.rc'.
:font facename=default.

:p.
А также команды для загрузки констант:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-16-01-1.rc'.
:font facename=default.

:p.
И команды, выполняющие объединение флажков "истина/ложь" в регистрах:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-16-01-2.rc'.
:font facename=default.

:p.
А также команды увеличения/уменьшения регистра на единицу и команды
"спрятать/восстановить регистр из стека регистров":

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-16-02-1.rc'.
:font facename=default.

:p.
И другие действия с регистрами и стеком, команды для вызова функций 
и возврата из них:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-16-02-4.rc'.
:font facename=default.

:p.
Команды в кратком формате с одним параметром:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-16-03-1.rc'.
:font facename=default.

:p.
И команды в кратком формате без параметров:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-16-03-4.rc'.
:font facename=default.

:p.
Команды для чтения/записи и сравнения данных:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-04-1.rc'.
:font facename=default.

:p.
Вычислительные действия:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-04-2.rc'.
:font facename=default.

:p.
Действия с указателями и вызовы функций:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-04-3.rc'.
:font facename=default.

:p.
Вычисления с плавающей точкой:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-04-4.rc'.
:font facename=default.

:p.
Копирование данных:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-05-1.rc'.
:font facename=default.

:p.
Вычислительные действия:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-05-2.rc'.
:font facename=default.

:p.
Действия с разрядами:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-05-3.rc'.
:font facename=default.

:p.
Действия в памяти:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-05-4.rc'.
:font facename=default.

:p.
Вычисления:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-06-1.rc'.
:font facename=default.

:p.
И ещё вычисления:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-06-2.rc'.
:font facename=default.

:p.
Команды сравнения и копирования регистров:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-06-3.rc'.
:font facename=default.

:p.
Переходы вперёд и сдвиг регистрового окна:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-06-4.rc'.
:font facename=default.

:p.
Вычислительные действия:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-07-1.rc'.
:font facename=default.

:p.
Сброс флажков, чтение/запись или действия с разрядами:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-07-2.rc'.
:font facename=default.

:p.
Преобразование целого числа в число с точкой и округление до целого:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-07-3.rc'.
:font facename=default.

:p.
Действия с разрядами:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-32-07-4.rc'.
:font facename=default.

:p.
Вычислительные действия:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-08-1.rc'.
:font facename=default.

:p.
Вычислительные действия:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-08-2.rc'.
:font facename=default.

:p.
Чтение и запись, сдвиг вершины стека переменных, команды сравнения:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-08-3.rc'.
:font facename=default.

:p.
Команды сравнения и действия с указателями:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-08-4.rc'.
:font facename=default.

:p.
Вычисления:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-08-5.rc'.
:font facename=default.

:p.
Переходы вперёд и загрузка констант:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-08-6.rc'.
:font facename=default.

:p.
Операторы цикла:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-08-7.rc'.
:font facename=default.

:p.
Действия с указателями:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-08-8.rc'.
:font facename=default.

:p.
Вычисления:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-09-1.rc'.
:font facename=default.

:p.
Действия с разрядами:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-09-2.rc'.
:font facename=default.

:p.
Команды сравнения и ввода/вывода, а также заполнение областей памяти
нулями:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-09-3.rc'.
:font facename=default.

:p.
Вычислительные действия, преобразование чисел, действия с указателями
и округление до целого:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-09-4.rc'.
:font facename=default.

:p.
Вызовы функций:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-09-5.rc'.
:font facename=default.

:p.
Действия с разрядами:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-09-6.rc'.
:font facename=default.

:p.
Переходы вперёд и вызовы функций:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-09-7.rc'.
:font facename=default.

:p.
Отправка и обработка прерываний:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-09-8.rc'.
:font facename=default.

:p.
Команды чтения/записи:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-12-1.rc'.
:font facename=default.

:p.
Вычисления:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-12-2.rc'.
:font facename=default.

:p.
Сравнение, действия с разрядами, сдвиг регистровых окон:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-12-3.rc'.
:font facename=default.

:p.
Действия в указателями и переключение потоков на уровне ядра 
операционной системы:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-12-4.rc'.
:font facename=default.

:p.
Вычисления и действия с указателями:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-12-5.rc'.
:font facename=default.

:p.
Команды чтения/записи:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-12-6.rc'.
:font facename=default.

:p.
Действия с указателями, переходы и вызовы функций:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-12-7.rc'.
:font facename=default.

:p.
Операторы цикла:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-12-8.rc'.
:font facename=default.

.*

:h2.Незанятые форматы команд
:p.
Более четверти всех возможных форматов команд оказались ничем не 
заняты. Если там что-нибудь появится - это действие будет выполнено
как макро-команда.

:p.
Команды средней длины:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-10-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-10-2.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-10-3.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-10-4.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-10-5.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-10-6.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-10-7.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-10-8.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-11-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-11-2.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-11-3.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-11-4.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-11-5.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-11-6.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-11-7.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-48-11-8.rc'.
:font facename=default.

:p.
И длинные команды:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-13-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-13-2.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-13-3.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-13-4.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-13-5.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-13-6.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-13-7.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-13-8.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-14-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-14-2.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-14-3.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-14-4.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-14-5.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-14-6.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-14-7.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-14-8.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-15-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-15-2.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-15-3.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-15-4.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-15-5.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-15-6.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-15-7.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-64-15-8.rc'.
:font facename=default.

.*

:h2.Краткие форматы команд
:p.
После того, как поиск всех известных команд был завершён (и когда
они были упакованы в форматы, показанные в предыдущей главе), стало
ясно, что их можно (и нужно) разделить на более простые действия - 
так появились RISC-подобные команды. Они имеют одну и ту же длину,
а в их заголовке задаётся номер формата.

:p.
Переходы и вызов функций:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-RISC-01-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-RISC-01-2.rc'.
:font facename=default.

:p.
Чтение и запись:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-RISC-02-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-RISC-02-2.rc'.
:font facename=default.

:p.
Вычисления:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-RISC-03-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-RISC-03-2.rc'.
:font facename=default.

:p.
Вычисления:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-RISC-04-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-RISC-04-2.rc'.
:font facename=default.

:p.
И более краткий формат, позволяющий сжать исполняемый код, а также
создавать микрокод, который выполнялся бы внутри микропроцессора и 
выглядел бы снаружи как обыкновенная команда:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-MCD-01-1.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-MCD-01-3-sparse.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-MCD-01-2.rc'.
:font facename=default.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Format-MCD-01-4-sparse.rc'.
:font facename=default.

.*

:h2.Правила доступа, часть первая
:p.
Во всех командах действует правило: в качестве назначения должен быть 
задан регистр, а у команд чтения/записи - адрес, то есть указатель на 
место в памяти (как число и ограничение или как целое число).

:p.
При этом в командах могут быть заданы константы "immediate" (в самой
команде или в байтах после команды), а на процессорах i386 задавались
ещё и указатели на данные в памяти (в том числе и со смещением в виде 
ещё одной константы), чтобы читать данные из памяти перед выполнением 
команды. 

:p.
В самом простом случае эти сочетания можно было бы задать примерно так:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Mode-1.rc'.
:font facename=default.

:p.
А также:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Mode-2.rc'.
:font facename=default.

:p.
Тогда длинные константы в командах будут выбраны из кеша процессора, 
что во многих случаях будет работать с высокой скоростью: чтение и 
действие могут быть поставлены в очередь как две простейшие команды
(для этого очередь должна будет запоминать их блоками по N команд в 
каждом) и выполнены на одном и том же исполнителе внутри ALU как два
действия - одно за другим.

:p.
Если же данных в кеше первого уровня не окажется, процессор перейдёт 
к ожиданию, пока они будут получены (из кеша второго уровня, где тоже
возможен переход к ожиданию, на этот раз ответа от контроллера памяти).

:p.
Кеш первого уровня должен будет получить как логический, так и физический 
адрес, и в том случае, если его не окажется в таблице быстрого пересчёта 
адресов Tagged TLB, процессор перейдёт к выполнению макро-команды, которая 
найдёт или прочитает адрес из кеша (и возможно, тоже перейдёт к ожиданию), 
затем добавит его в таблицу быстрого пересчёта адресов Tagged TLB, а затем 
прочитает данные (из кеша или из памяти) и отправит их в регистр.

:p.
При этом у микропроцессора нет команд, где выполнялось бы два и более
обращений к памяти (например, чтение и запись), поскольку они в любом 
случае остановили бы выполнение, а в большинстве случаев - вызвали бы 
выполнение макро-команды. В том числе, команды для доступа к памяти не 
выполняют два действия за один раз (даже чтение).

.*

:h2.Правила доступа, часть вторая
:p.
В примере в предыдущей главе под все возможные режимы было занято 8 
разрядов - и такого их количества в заголовках команд не оказалось. 
Так появился другой приём: флажки в заголовке каждой команды.

:p.
В самом простом случае они могут быть заданы примерно так:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Mode-3.rc'.
:font facename=default.

:p.
А также:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Mode-4.rc'.
:font facename=default.

:p.
А ещё лучше, если бы короткие команды имели один флажок, а более 
длинные - два, три или четыре. Тогда редкие правила доступа к данным
были бы вынесены в длинные форматы, а наиболее часто используемые - 
остались бы в кратких форматах и не занимали бы разряды в командах.

:p.
То есть:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Mode-5.rc'.
:font facename=default.

:p.
А также:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Mode-6.rc'.
:font facename=default.

:p.
В командах средней длины также задаётся флажок "d_size", который 
либо равен нулю (и в таком случае данные надо брать из последнего 
параметра команды, где записана константа "immediate"), либо задаёт 
длину константы после команды (и тогда её старшие разряды записаны в 
последнем параметре, а её младшие разряды - в байтах после команды). 

:p.
Этот приём оказался удобен для записи команд целочисленной арифметики, 
где часто встречаются короткие константы ("умножить регистр на два"), 
но могут появиться и длинные ("прибавить к регистру 24-разрядное число"), 
и будут нужны режимы "RMI" ("прибавить к регистру число по указателю 
со смещением"), а также "RMII" и другие.

:p.
Кроме того, в длинных командах в их заголовках есть флажки "W" и "N":
первый означает, что действие должно быть выполнено в регистрах далеко
за границей регистрового окна (они заменяют "регистры сопроцессора" на
других архитектурах), а второй так нигде и не понадобился.

:p.
RISC-подобные команды не имеют таких флажков: там в любом случае надо
вначале прочитать данные из памяти, а затем выполнять действие с ними.
Сами команды ничего из памяти не читают.

.*

:h2.Об "открытых технологиях"
:p.
И длинный текст о том, что последние лет 20 называют "открытыми
технологиями", которые якобы вот-вот приведут нас всех в светлое 
будущее. На сегодняшний день они сводятся к двум приёмам:
:ol.
:li.Паразитировать на том, что осталось от DEC, Sun, AT<&>T и других 
(уже давно ничего не осталось),
:li.Следить за тем, чтобы никто не имел никакой собственности (ну разве
что кроме авторов Rust и systemd).
:eol.
.br
Пока что "открытые технологии" привели кодерков на помойку.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\JSTCO-1.rc'.
:font facename=default.

:p.
Всё это, впрочем, никакого значения не имеет. Религиозная секта давно 
уже здесь, и ведёт себя как "пожрать всё, что только можно, запутать 
всё, до чего успели дотянуться, да так, чтобы после нас разобраться 
невозможно было": не в языке - так в системе сборки, не в ней - так 
в системе контроля версий, не в них - так в командной строке... Но,
как уже не раз повторяли в Интернете, запутывание кода работает до 
первой утечки памяти (где-то в священных текстах), а дальше - вот вам 
отладчик и сверхурочные часы по выходным. Главное - верьте, что это 
не вы там кодом срали (вы - гении, у вас шаблоны проектирования в 
командной строке), а это кто-то другой вам в код насрал.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\JSTCO-2.rc'.
:font facename=default.

:p.
Ещё можно согласиться с тем, что имеет смысл усложнить на пустом 
месте описания прав доступа или файлы с настройками (так что программе 
будет нужен администратор) или файлы с описанием диалоговых окошек (и 
теперь для их исправления будет нужна отдельная должность - аж целый 
верстальщик), но от этого, как ни странно, есть и польза: больше народу
трудоустроили... Но вот борьба за власть в системе контроля версий - 
от неё одни убытки, причём всем. И тем не менее, "открытые" исходные 
тексты в большинстве своём остались (или были брошены) как раз в 
таком состоянии.

:p.
Написанного религиозными (и тихо и буйно помешанными) стало уже так 
много, что самое время задать вопрос: кто разрушает их мозги - токсоплазма 
или грибок аспергилла (оба микроорганизма засветились как паразиты, и многие 
"умненькие" - всего лишь их носители, только и всего), или у них нарушения 
с детства (то, что всё это с детства закладывалось - и так понятно), скорее 
всего из-за употребления коровьего молока (как выяснилось недавно, казеин A1 
опасен для мозга: об этом книги написаны). То, что посредники с их "готовыми 
решениями" делают наценку 250% с откатом 80%, знают уже все. То, что "товарищей 
писателей" набирают с ближайшей мусорной свалки - тоже. И то, что у них крыша 
протекает - не осталось тайной ни для кого...

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\JSTCO-3.rc'.
:font facename=default.

:p.
Не трогайте зашедшие в тупик технологии, что бы там ни говорили об их 
мнимом превосходстве, что они "новые" и даже "самые новые". Всё дело в 
ценах, а не в загадочных символах на экране компьютера. И с ценами-то 
как раз дела обстоят не лучшим образом. Хронически больным не нужны 
деньги - зарплата в 25-30% от средней их полностью устраивает: им и 
не надо больше!

:p.
Бесполезно и улучшать остающиеся от них геологические пласты, заставляя 
их работать хоть как-то. Полученный в итоге "открытый код" не может быть 
приведён в надлежащий вид даже за десятилетия. Всё это уже видели и не 
один раз... а, подождите, ещё одного процессора как раз и недоставало.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\JSTCO-4.rc'.
:font facename=default.

:p.
:artwork align='center' name='0001-Intro\Images\WCFF.bmp'.
.br

.*

:h2.Статистика по зарплатам
:p.
В следующем примере выполняется подсчёт среднего арифметического по
заработным платам, выбираемым из массива структур данных. Указатель
на него и его длина передаются в регистрах R1 и R2, а рассчитанное 
среднее запоминается в регистре "R0":

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Salary-1.rc'.
:font facename=default.

:p.
Тип структуры задаётся таким образом:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Salary-2.rc'.
:font facename=default.
