Перейти к содержанию

Компьютерная архитектура iiixmish2

завершено на 100%
Материал из Викиучебника — открытых книг для открытого мира
(перенаправлено с «Makexm2c и Xmtwolime»)


Введение

[править]

Определения

[править]
Регистр процессора
Регистр процессора — это поле определённой длины, которое находится в памяти процессора. Доступ к регистру очень быстр, его содержимое можно сохранить в память и обратно. Бывает как доступен из программы, так и нет.
Язык ассемблера
Код на Си и как он может выглядеть на языке ассемблера (переменная 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]

Команды[6][3]

[править]

Код нашей программы состоит из двух команд — vstr и updd.

Команда vstr нужна для вывода строки на экран. Конечно, это можно сделать и без неё, но с ней это делается проще и эффективнее: сокращается размер программы. Имеет два аргумента:

Синтаксис Описание
ЦЦЦЦ (Ц — цифра) Адрес ячейки видеопамяти, с которого будет располагаться строка
"СТРОКА" СТРОКА для вывода

Команда для обновления («перерисовки») экрана.

Регистры

[править]

Как уже было сказано ранее, iiixmish2 имеет 44 пользовательских регистров (п. реги́стры) и 8 для потоков.

2, 3 и 4 п. регистры предназначены для обновления экрана, п. регистр 1 хранит нажатую клавишу. Избегайте использования п. регистров 5, 7, 9 и 11, т. к. они могут использоваться некоторыми командами (например, vstr и vrst).[3]

Операции[6][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 выполняет то же, что и mov, но размер второго аргумента увеличен до шести байтов. Аргументы:

Синтаксис Описание
ЧИСЛО адрес п. регистра
ЦЦЦЦЦЦЦ число для сохранения

Пример использования:

mov2 UR0, 0004985

Команда 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

Комментарии

[править]

Коммента́рии — это тексты в коде программы, которые не влияют на её работу, но, как правило, помогают лучше понять её. В Makexm2c нет обязательного спецсимвола, который отличал бы комментарии от команд.[6]

Метки[6]

[править]

Ме́тки — в Makexm2c — это мнемоники, которые ставятся в определённые места в коде программы. Обращение к метке вставляет на месте обращения адрес, по которому располагается эта метка в двоичной форме программы. Пример:

метка:
    nop
    nop
    mov2 UR0, <метка>

Для обращения, название метки, заключённое в < и >, вставляется в нужное место в программе.

Именованные константы[6]

[править]

Для создания именованных констант используется директива .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

Загрузка и сохранение[6][3]

[править]

Для загрузки значения из видеопамяти в п. регистр, используйте команду vld. Её аргументы:

Синтаксис Описание
ЦЦЦЦ адрес ячейки видеопамяти для загрузки
ЧИСЛО адрес п. регистра-приёмника

Пример использования:

vld 0001, UR8


Для сохранения значения п. регистра в ячейку видеопамяти, используйте vsv. Аргументы:

Синтаксис Описание
ЧИСЛО адрес п. регистра для сохранения
ЦЦЦЦ адрес нужной ячейки видеопамяти

Пример использования:

vsv UR0, 0063


Для сохранения значения п. регистра в видеопамять как число, используйте vsvan. Аргументы:

Синтаксис Описание
ЧИСЛО адрес п. регистра для сохранения
ЦЦЦЦ адрес ячейки видеопамяти, с которой следует начать запись

Пример использования:

vsvan UR0, 0000


Вы также можете вписывать адрес п. регистра вместо ЦЦЦЦ в аргументах этих команд (такое поддерживается в Makexm2c). Так, vsv UR0, UR16 сохранит содержимое п. регистра 0 в яч. видеопамяти, адрес которой находится в регистре 16.

Вы можете печатать разными цветами! Для этого, измените ячейку видеопамяти, на месте которой будет изменение цвета последующих, на 255 плюс нужное значение цвета.[3]

Текст в самой нижней строке отображается полужирным.

Задание

Напишите программу, которая складывает два числа и выводит результат на экран.

Память

[править]

Программы iiixmish2 загружаются в его па́мять (насколько это возможно).[3]

Загрузка и сохранение[6][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.

Ещё команды[6]

[править]

Это последний раздел изучения. В нём описываются команды slp, off, vrst и end.

slp ждёт <значение п. регистра А> секунд (для миллисекунд есть lslp). Пример использования:

slp UR0

off завершает работу iiixmish2.

vrst заменяет значения почти всех ячеек видеопамяти на неотображаемое (0), предназначение — убрать текст с экрана. Не путайте его с vstr.

Если цикл выполнения памяти встретит команду end, то он должен будет завершиться.


Задание

Напишите программу, которая должна завершиться тогда, когда пользователь нажмёт какую-нибудь клавишу.

Примечания

[править]