Makexm2c

завершено на 100%
Материал из Викиучебника — открытых книг для открытого мира


Makexm2c

учебник по языку ассе́мблера Makexm2c



Введение[править]

Учебник[править]

Данный учебник учит программированию на Makexm2c.

Makexm2c[править]

Makexm2c — это язык ассемблера, предназначенный для создания программ для виртуальной машины «iiixmish2».[1]

iiixmish2[править]

Iiixmish2 — это виртуальная машина со своими командами и др. Она имеет 10 миллионов ячеек памяти, 30 пользовательских регистров, 8 регистров для потоков, 2000 ячеек видеопамяти, более 30 команд и экран 640×480 (но может отображаться меньше).[2] Iiixmish2 имеет команду NOP, но она не выполняется и ничего не делает.

Получение необходимого[править]

Скачайте свободную реализацию iiixmish2 здесь, а также средства для разработки программ на Makexm2c здесь (makexm2c-tools). Вы соглашаетесь использовать их, соблюдая Downadow License 7.

Распакуйте полученные архивы. Скомпилируйте программы, используя OpenJDK 17.

Вам потребуется среда для запуска Java-программ, вы можете установить пакет openjdk-17-jre с его зависимостями в Debian:

$ sudo apt install openjdk-17-jre

Выполните java --version; если команда не будет найдена, то что-то пошло не так.

«Hello, world!»[править]

Теперь мы можем написать программу «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-дисков коммуникацию.

Команды[3][4][править]

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

vstr[править]

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

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

updd[править]

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

Регистры[править]

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

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

Операции[3][4][править]

Присваивание[править]

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

Генерация числа[править]

Команда sel выбирает число от нуля до ОПРЕДЕЛЁННОГО числа минус один, результат сохраняет в п. регистр. Аргументы:

Синтаксис Описание
ЧИСЛО адрес п. регистра, содержащего ОПРЕДЕЛЁННОЕ число
ЧИСЛО адрес п. регистра, в который следует сохранить результат

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

sel UR0, UR12

Комментарии[править]

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

Метки[3][править]

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

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

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

Именованные константы[3][править]

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

.def %CONST% "0"

создаст именованную константу «CONST» со значением «0».

Обращение к именованным константам отличается от обращения к меткам лишь тем, что название заключается в %, а не < и >.

Ветвление[3][4][править]

Задание

Потренируйтесь с пройденными командами.


В iiixmish2 есть команды для создания условных переходов. Рассмотрим, как использовать их в Makexm2c.

Равно[править]

Для создания перехода вроде «если значение п. регистра А равно значению регистра Б, то выполнить переход на <значение п. регистра В>», воспользуйтесь следующей конструкцией:

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-ая, — хранят параметр цвета для фона и параметр цвета для отображаемых ячеек видеопамяти. Возможные цвета[4]:

Значение Цвет
1 белый
2 зелёный
3 голубой или синий
4 тёмно-зелёный
5 серый
6 красный
7 жёлтый
иное чёрный


Пример изменения цвета отображаемых ячеек видеопамяти на жёлтый:

mov UR0, 7
vsv UR0, 1999

Загрузка и сохранение[3][4][править]

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

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

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

vld 0001, UR8


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

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

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

vsv UR0, 0063


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

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

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

vsvan UR0, 0000


Вы также можете вписывать адрес п. регистра вместо ЦЦЦЦ в аргументах этих команд.

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

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

Задание

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

Вывод линий[править]

Для вывода линии, дайте значение цвета (отличное от нуля) ячейке видеопамяти 1900 + НОМЕР_ЛИНИИ * 5 и дайте x1, y1, x2, y2 (например, 200, 100, 280, 101) следующим ячейкам после неё.

Память[править]

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

Пользовательских регистров слишком мало, чтобы хранить в них хотя бы строку из 32-ух символов; поэтому вам следует хранить большинство значений в памяти.

Загрузка и сохранение[3][4][править]

Команда ild предназначена для загрузки значений из памяти в п. регистры. Аргументы:

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

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

ild 6001900, UR0

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

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

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

isv UR10, 0999999


Вы можете вписывать адрес п. регистра вместо ЦЦЦЦЦЦЦ в аргументах этих команд.

Многопоточность[править]

В iiixmish2 встроены команды TH1, TH2 и TH3. Используя их, вы можете выполнять задачи одновременно. Эти команды имеют один аргумент — адрес п. регистра, со значения которого следует начать новую задачу.[4] Пример программы:

mov2 UR0, <thread>
th1 UR0
end
thread:
    vstr 0000, "OK!"
    updd

Недостаток vstr[править]

Максимальное значение символа в vstr-строке ограничено одним байтом[4], т. е. вы не можете печатать дополнительные символы на экран iiixmish2, используя эту команду (например, буквы русского алфавита).

Но есть Java-программа Print, которая поставляется с выпуском makexm2c-tools. Использование[5]:

$ 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 и .goto[править]

.ascii <mem0> "hello world" приказывает ассемблеру записать строку «hello world», начиная с яч. <mem0>. .goto +100 приказывает перейти ассемблеру на 100 яч. больше, это похоже на 100 nop'ов.

Общение с другими компьютерами[править]

Iiixmish2 и другие компьютеры (включая ЭВМ, на котором выполняется iiixmish2) могут «общаться» через файлы коммуникации. Данные, которые передал компьютер, сохраняются в памяти iiixmish2, начиная с адреса 9999872. Чтобы ответить, запишите краткий ответ, начиная с адреса 9999000.

Ещё команды[3][править]

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

slp[править]

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

slp UR0

off[править]

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

vrst[править]

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

end[править]

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


Задание

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

См. также[править]

  1. Репозиторий mkxm2cc
  2. Репозиторий операционной системы Xmtwolime и др.

Примечания[править]