Компьютерная архитектура iiixmish2
Введение
[править]Определения
[править]- Регистр процессора
- Регистр процессора — это поле определённой длины, которое находится в памяти процессора. Доступ к регистру очень быстр, его содержимое можно сохранить в память и обратно. Бывает как доступен из программы, так и нет.
- Язык ассемблера
Код на Си и как он может выглядеть на языке ассемблера (переменная variable по адресу 8699999) variable = 5;
mov %R_FA_0%, 5 isv %R_FA_0%, 8699999
- Ассемблерная директива
- Ассемблерная директива («псевдокоманда») — это, можно сказать, команда ассемблера, а не компьютера. Директивы влияют на компиляцию программы. Примеры в Makexm2c —
.goto
,.ascii
и.def
.
Учебник
[править]Данный учебник учит программированию на Makexm2c.
Makexm2c
[править]Makexm2c — это язык ассемблера, предназначенный для создания программ для виртуальной машины «iiixmish2».[1] Если Вы являетесь опытным программистом, то можете найти Makexm2c более лёгким, чем другие низкоуровневые языки.
iiixmish2
[править]Iiixmish2 — это 32-разрядная виртуальная машина со своими командами и др. Она имеет 10 миллионов ячеек памяти, 44 пользовательских регистров, 8 регистров для потоков, 2000 ячеек видеопамяти, более 30 команд и экран 640 × 480 (но может отображаться меньше).[2]
Ниже представлены названия iiixmish2-инструкций и соответствующие signed char
-опкоды[3]:
Название | Код операции |
---|---|
NOP[4] |
-1 |
ADD |
-2 |
SUB |
-3 |
MOV |
-4 |
ILD |
-5 |
VLD |
-6 |
LD |
-7 |
ISV |
-8 |
VSV |
-9 |
SLP |
-10 |
IFA |
-11 |
IFB |
-12 |
IFC |
-13 |
IFD |
-14 |
UPDD |
-15 |
OFF |
-16 |
VRST |
-17 |
JMP |
-18 |
END |
-19 |
SEL |
-20 |
MUL |
-21 |
DIV |
-22 |
LSLP |
-23 |
CUR |
-24 |
VSTR |
-25 |
INC |
-26 |
DEC |
-27 |
TNP |
-28 |
MOD |
-29 |
EXP |
-30 |
MOV2 |
-31 |
TH1 |
-32 |
TH2 |
-33 |
TH3 |
-34 |
MOV3 |
-35 |
VSVAN |
-36 |
IFE |
-37 |
LSHIFT |
-38 |
RSHIFT |
-39 |
XOR , OR , AND |
-40, -41, -42 |
Получение необходимого
[править]Скачайте свободную реализацию iiixmish2 здесь, а также средства для разработки программ на Makexm2c здесь (makexm2c-tools).
Распакуйте полученные архивы. Скомпилируйте программы, используя OpenJDK 17. В Debian, Вы можете установить его, выполнив следующую команду:
$ sudo apt install openjdk-17-jdk
Выполните java --version
.
Синтаксис
[править]Makexm2c-программы могут состоять из команд:
<название> [<аргумент 0>[[,] <аргумент 1>]…]
, псевдокоманд (директив):
.<название> [<аргумент 0>[ <аргумент 1>]]
, меток:
<название>:
и комментариев.
К регистрам можно подставлять «UR» (UR0, UR1…).
Теперь мы можем написать программу «Hello, world!», она будет выводить на экран виртуальной машины «Hello, world!» (перевод — «Всем привет!», а буквально — «Здравствуй, мир!»). Программа подобна загрузчику: она выполняется практически сразу после запуска машины и не требует для своей работы операционной системы.
Создайте файл «hello.asm» и вставьте в него следующее:
vstr 0000, "Hello, world!"
updd
Это код на Makexm2c, переведите его в код, понятный виртуальной машине iiixmish2, используя ассемблер из makexm2c-tools:
$ java downadow.makexm2c_tools.main.Assembler hello.asm hello
Отлично! Запустите iiixmish2, передав полученный файл:
$ java downadow.iiixmish2.main.Iiixmish2 hello --no-communication
Параметр --no-communication отключает, возможно, губительную для SSD-дисков коммуникацию. Если требуется, опустите данный параметр, включение и выключение коммуникации контролируется клавишами F2 и F3.[5]
Код нашей программы состоит из двух команд — vstr
и updd
.
vstr
[править]Команда vstr
нужна для вывода строки на экран. Конечно, это можно сделать и без неё, но с ней это делается проще и эффективнее: сокращается размер программы. Имеет два аргумента:
Синтаксис | Описание |
---|---|
ЦЦЦЦ (Ц — цифра) |
Адрес ячейки видеопамяти, с которого будет располагаться строка |
"СТРОКА" |
СТРОКА для вывода |
updd
[править]Команда для обновления («перерисовки») экрана.
Регистры
[править]Как уже было сказано ранее, iiixmish2 имеет 44 пользовательских регистров (п. реги́стры) и 8 для потоков.
2, 3 и 4 п. регистры предназначены для обновления экрана, п. регистр 1 хранит нажатую клавишу. Избегайте использования п. регистров 5, 7, 9 и 11, т. к. они могут использоваться некоторыми командами (например, vstr
и vrst
).[3]
Присваивание
[править]Команда mov
сохраняет число в п. регистр, число не должно превышать один байт. Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
АДРЕС п. регистра, который должен принять ЧИСЛО |
ЧИСЛО |
ЧИСЛО для сохранения |
Пример использования:
mov UR10, 64
Также можно вставлять 'СИМВОЛ'
вместо числа, пример:
mov UR10, 'j'
то же, что и
mov UR10, 106
Сложение
[править]Команда add
складывает два п. регистра, сохраняет результат в п. регистр. Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра, содержащего первое слагаемое |
ЧИСЛО |
адрес п. регистра, содержащего второе слагаемое |
ЧИСЛО |
адрес п. регистра, в который следует поместить сумму |
Пример использования:
add UR0 UR6, UR9
Запятые между аргументами и «UR» к адресам, — необязательны.
Вычитание
[править]Команда sub
вычитает из п. регистра значение другого п. регистра, результат сохраняется в п. регистр.
Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра, содержащего уменьшаемое |
ЧИСЛО |
адрес п. регистра, содержащего вычитаемое |
ЧИСЛО |
адрес п. регистра, в который следует поместить разность |
Пример использования:
sub UR6 UR8, UR0
Загрузка
[править]Команда ld
загружает значение п. регистра в другой п. регистр.
Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра, который следует загрузить в ДРУГОЙ п. регистр |
ЧИСЛО |
адрес ДРУГОГО п. регистра |
Пример использования:
ld UR1, UR0
Умножение
[править]Команда mul
умножает п. регистр на другой п. регистр, результат сохраняется в п. регистр.
Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра, содержащего множимое |
ЧИСЛО |
адрес п. регистра, содержащего множитель |
ЧИСЛО |
адрес п. регистра, в который следует поместить произведение |
Пример использования:
mul UR6 UR8, UR0
Деление
[править]Команда div
делит п. регистр на другой п. регистр, результат сохраняется в п. регистр.
Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра, содержащего делимое |
ЧИСЛО |
адрес п. регистра, содержащего делитель |
ЧИСЛО |
адрес п. регистра, в который следует поместить частное |
Пример использования:
div UR6 UR8, UR0
Получение остатка от деления
[править]Команда mod
делит п. регистр на другой п. регистр, остаток сохраняется в п. регистр.
Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра, содержащего делимое |
ЧИСЛО |
адрес п. регистра, содержащего делитель |
ЧИСЛО |
адрес п. регистра, в который следует поместить остаток |
Пример использования:
mod UR0 UR29, UR8
Команда inc
увеличивает п. регистр на единицу. Пример использования:
inc UR0
Команда dec
уменьшает п. регистр на единицу. Пример использования:
dec UR0
Изменение знака
[править]Команда tnp
изменяет знак п. регистра, пример использования:
tnp UR14
Пример:
exp UR0 UR6, UR8
mov2
[править]Команда mov2
выполняет то же, что и mov
, но размер второго аргумента увеличен до шести байтов.
Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра |
ЦЦЦЦЦЦЦ |
число для сохранения |
Пример использования:
mov2 UR0, 0004985
mov3
[править]Команда mov3
«склеивает» п. регистры как строки, сохраняет результат в п. регистр.
Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра, в который следует сохранить результат |
ЧИСЛО |
адрес первого п. регистра для «склеивания» |
ЧИСЛО |
адрес второго п. регистра для «склеивания» |
ЧИСЛО |
адрес третьего п. регистра для «склеивания» |
ЧИСЛО |
адрес четвёртого п. регистра для «склеивания» |
ЧИСЛО |
адрес пятого п. регистра для «склеивания» |
ЧИСЛО |
адрес шестого п. регистра для «склеивания» |
Пример использования:
mov3 UR0, UR29 UR28 UR27 UR26 UR25 UR24
Сдвиг
[править]Следующий код выполняет операцию вида UR20 << UR19 (сдвиг битов влево) и сохраняет результат в UR8:
lshift UR20 UR19, UR8
UR8 = UR20 >> UR19
:
rshift UR20 UR19, UR8
Для побитовых XOR, OR и AND, используйте одноимённые инструкции.
Генерация числа
[править]Команда sel
выбирает число от нуля до ОПРЕДЕЛЁННОГО числа минус один, результат сохраняет в п. регистр.
Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра, содержащего ОПРЕДЕЛЁННОЕ число |
ЧИСЛО |
адрес п. регистра, в который следует сохранить результат |
Пример использования:
sel UR0, UR12
Получение времени
[править]Операция time
копирует в заданный регистр кол-во миллисекунд, приблизительно начиная от запуска процессора. Принимает один аргумент. trst
сбрасывает время.
Комментарии
[править]Коммента́рии — это тексты в коде программы, которые не влияют на её работу, но, как правило, помогают лучше понять её. В Makexm2c нет обязательного спецсимвола, который отличал бы комментарии от команд.[6]
Ме́тки — в Makexm2c — это мнемоники, которые ставятся в определённые места в коде программы. Обращение к метке вставляет на месте обращения адрес, по которому располагается эта метка в двоичной форме программы. Пример:
метка:
nop
nop
mov2 UR0, <метка>
Для обращения, название метки, заключённое в <
и >
, вставляется в нужное место в программе.
Для создания именованных констант используется директива .def
, пример:
.def %CONST% "0"
создаст именованную константу «CONST» со значением «0».
Обращение к именованным константам отличается от обращения к меткам лишь тем, что название заключается в %
, а не <
и >
.
Задание
Потренируйтесь с пройденными командами.
В iiixmish2 есть команды для создания условных переходов. Рассмотрим, как использовать их в Makexm2c.
Равно
[править]В iiixmish2 нет инструкций вроде BRz, BRn и т. д., ветвление реализуется посредством команд IFA, IFB, IFC, IFD и IFE. Для создания перехода вроде «если значение п. регистра А равно значению регистра Б, то выполнить переход на <значение п. регистра В>», воспользуйтесь следующей конструкцией:
if АДРЕС0 == АДРЕС1, АДРЕС2
Название | Описание |
---|---|
АДРЕС0 |
адрес первого п. регистра для сравнения |
АДРЕС1 |
адрес второго п. регистра для сравнения |
АДРЕС2 |
адрес п. регистра, на значение которого нужно перейти |
Ясно? Идём дальше.
Неравно
[править]if АДРЕС0 != АДРЕС1, АДРЕС2
Больше
[править]if АДРЕС0 > АДРЕС1, АДРЕС2
Меньше
[править]if АДРЕС0 < АДРЕС1, АДРЕС2
Равно ×2
[править]if АДРЕС0 == АДРЕС1 && АДРЕС2 == АДРЕС3, АДРЕС4
(если п. регистры АДРЕС0
и АДРЕС1
равны, п. регистры АДРЕС2
и АДРЕС3
равны, то выполнить переход на <значение п. регистра АДРЕС4
>)
Видеопамять
[править]Как уже говорилось во введении, iiixmish2 имеет 2000 ячеек видеопамяти.
Почти все ячейки видеопамяти могут отображаться на экране. Последние две ячейки, — 1998-ая и 1999-ая, — хранят параметр цвета для фона и параметр цвета для отображаемых ячеек видеопамяти. Возможные цвета[3]:
Значение | Цвет |
---|---|
1 | белый |
2 | зелёный |
3 | голубой или синий |
4 | тёмно-зелёный |
5 | серый |
6 | красный |
7 | жёлтый |
иное | чёрный |
Пример изменения цвета отображаемых ячеек видеопамяти на жёлтый:
mov UR0, 7
vsv UR0, 1999
Для загрузки значения из видеопамяти в п. регистр, используйте команду vld
. Её аргументы:
Синтаксис | Описание |
---|---|
ЦЦЦЦ |
адрес ячейки видеопамяти для загрузки |
ЧИСЛО |
адрес п. регистра-приёмника |
Пример использования:
vld 0001, UR8
Для сохранения значения п. регистра в ячейку видеопамяти, используйте vsv
. Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра для сохранения |
ЦЦЦЦ |
адрес нужной ячейки видеопамяти |
Пример использования:
vsv UR0, 0063
Для сохранения значения п. регистра в видеопамять как число, используйте vsvan
. Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра для сохранения |
ЦЦЦЦ |
адрес ячейки видеопамяти, с которой следует начать запись |
Пример использования:
vsvan UR0, 0000
Вы также можете вписывать адрес п. регистра вместо ЦЦЦЦ
в аргументах этих команд (такое поддерживается в Makexm2c). Так, vsv UR0, UR16
сохранит содержимое п. регистра 0 в яч. видеопамяти, адрес которой находится в регистре 16.
Вы можете печатать разными цветами! Для этого, измените ячейку видеопамяти, на месте которой будет изменение цвета последующих, на 255 плюс нужное значение цвета.[3]
Текст в самой нижней строке отображается полужирным.
Задание
Напишите программу, которая складывает два числа и выводит результат на экран.
Память
[править]Программы iiixmish2 загружаются в его па́мять (насколько это возможно).[3]
Команда ild
предназначена для загрузки значений из памяти в п. регистры. Аргументы:
Синтаксис | Описание |
---|---|
ЦЦЦЦЦЦЦ |
адрес ячейки памяти для загрузки |
ЧИСЛО |
адрес п. регистра-приёмника. |
Пример использования:
ild 6001900, UR0
Для сохранения значения п. регистра в память, используйте isv
. Аргументы:
Синтаксис | Описание |
---|---|
ЧИСЛО |
адрес п. регистра для сохранения |
ЦЦЦЦЦЦЦ |
адрес нужной ячейки памяти |
Пример использования:
isv UR10, 0999999
Вы можете вписывать адрес п. регистра вместо ЦЦЦЦЦЦЦ
в аргументах этих команд.
Многопоточность
[править]В iiixmish2 встроены команды TH1
, TH2
и TH3
. Используя их, вы можете выполнять задачи одновременно. Эти команды имеют один аргумент — адрес п. регистра, со значения которого следует начать новую задачу.[3] Пример программы:
mov2 UR0, <thread>
th1 UR0
end
thread:
vstr 0000, "OK!"
updd
Недостаток vstr
[править]Максимальное значение символа в vstr
-строке ограничено одним байтом[3], т. е. вы не можете печатать дополнительные символы на экран iiixmish2, используя эту команду (например, буквы русского алфавита). Длина vstr-строки не должна превышать один знаковый байт (signed char
).
Но есть Java-программа Print, которая поставляется с выпуском makexm2c-tools. Использование[7]:
$ java downadow.makexm2c_tools.main.Print [-r|--user-register АДРЕС] [-a|--address АДРЕС] "СТРОКА"
Эта программа выводит Makexm2c-код, который должен выводить любой доступный символ на экран iiixmish2; но код, который он создаёт, нехорош, т. к. программа не оптимизирует сохранение в видеопамять повторяющихся символов, из-за чего код получается большим.
Задание
Напишите программу, которая выводит «Здравствуй, мир!», используя Print из makexm2c-tools.
Простая программа
[править]Ниже представлен пример программы, в которой пользователь может вводить данные. То, что от символа «;» до конца строки будет комментарием.
mov UR29, 30
mov2 UR28, <main>
main:
; ждать 30 миллисекунд
lslp UR29
; если клавиша не была нажата, то перейти к main
if UR1 == UR0, UR28
; сохраняем клавишу (указателем текущей ячейки будет п. регистр 27)
vsv UR1, UR27
; увеличиваем указатель
inc UR27
; сбрасываем нажатую клавишу
mov UR1, 0
; обновляем экран
updd
; переход к main
jmp UR28
Задание
Измените программу так, чтобы фон стал белым, а текст, вводимый пользователем, — чёрным. Помните, как собирать и запускать программы?
Ещё директивы
[править].ascii <mem0> "hello world"
приказывает ассемблеру записать строку «hello world», начиная с яч. <mem0> (адрес метки mem0). .goto +100
приказывает перейти ассемблеру на 100 яч. больше, это похоже на 100 nop'ов. .byte ЧИСЛО
вставит десятичное ЧИСЛО. .orig 1000
выполнит переход к ячейке 1000.
Общение с другими компьютерами
[править]Iiixmish2 и другие компьютеры (включая ЭВМ, на котором выполняется iiixmish2) могут «общаться» через файлы коммуникации. Данные, которые передал компьютер, сохраняются в памяти iiixmish2, начиная с адреса 9999872. Чтобы ответить, запишите краткий ответ, начиная с адреса 9999000.
Это последний раздел изучения. В нём описываются команды slp
, off
, vrst
и end
.
slp
[править]slp
ждёт <значение п. регистра А> секунд (для миллисекунд есть lslp
). Пример использования:
slp UR0
off
[править]off
завершает работу iiixmish2.
vrst
[править]vrst
заменяет значения почти всех ячеек видеопамяти на неотображаемое (0), предназначение — убрать текст с экрана. Не путайте его с vstr
.
end
[править]Если цикл выполнения памяти встретит команду end
, то он должен будет завершиться.
Задание
Напишите программу, которая должна завершиться тогда, когда пользователь нажмёт какую-нибудь клавишу.