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

Эта книга повествует о написании программ под операционную систему Xmtwolime, используя возможности языка Си.

Mkxm2cc — это изменённый Си, предназначенный для написания программ под виртуальную машину iiixmish2.[1]

Сборка mkxm2cc-программы (которая написана для Xmtwolime)[1]:

  1. компиляция Си-компилятором
  2. запуск полученной программы с перенаправлением stdout в xmtwolime/software/имя_программы.s
  3. удаление программы, которая была получена после шага 1

Требования править

Пожалуйста, прочтите учебник по Xmtwolime. Заголовочные файлы библиотек можно поместить в /usr/include. Нужно иметь знания о языке программирования Си.

Первая программа править

Создайте файл hey.c со следующим содержимым:

#include <xmtwolime_mkxm2cc.h>

int main(void) {
    init("hey");
    
    aprint("Hello, world!", _OUT_ST);
    
    exit_app(EXIT_SUCCESS);
}

Это mkxm2cc-программа. Соберите её, а после систему. Запустите Xmtwolime, наберите в оболочке имя программы («hey»; оно должно быть длиной в три ASCII-символа), на экране должно появиться «Hello, world!».

Разбор кода[2] править

#include <xmtwolime_mkxm2cc.h> править

Это включает содержимое файла xmtwolime_mkxm2cc.h, содержащего главную библиотеку mkxm2cc для Xmtwolime-программ.

init("hey") править

Это вызывает функцию init(). Она должна быть первой функцией, которая вызывается в Вашей программе. «hey» — это имя программы.

aprint("Hello, world!", _OUT_ST) править

Это ложит ASCII-строку «Hello, world!» в видеопамять, начиная с _OUT_ST. Данная функция использует команду VSTR.

exit_app(EXIT_SUCCESS) править

Успешное завершение программы. Не забывайте использовать exit_app() или mexit_app(), чтобы завершить приложение и вернуть пользователя к оболочке!

Им. константы, которые следует знать править

Название Описание
_BLACK, _WHITE, _GREEN, _BLUE, _GREEN2, _GREY, _RED, _YELLOW коды цветов
_XREG п. регистр, который используется, например, функцией xprint()
_EQ, _NE, _GT, _LT операторы для вставки в ifmm() и ifmn()
_R_USER п. регистр, содержащий текущий UID
_ARGS_ST начало аргументов программы в видеопамяти
_OUT_ST начало вывода программы в видеопамяти
_ORDINARY_USER_SPACE_ST начало данных пользователя в памяти
_LINE_SIZE длина строки

Переменные править

Используйте alloc() для статического выделения памяти:

int var = alloc(1);        // целое число
addr_t array = alloc(64);  // array равен началу массива, в котором 64 элемента

Код free_mem(16) аналогичен alloc(-16).

Метки править

 

Всегда начинайте имена своих меток с названия программы!

Функции Описание
int L(char *_name) создание метки
int G(char *_target) и int Gm(uint32_t _maddr_with_target) переход к _target (оно может быть либо mov2-числом, либо <меткой>) или к [значение ячейки _maddr_with_target]

Работа с памятью править

 

Не передавайте параметры-числа mkxm2cc-функциям, если в них больше семи цифр!

Функции Описание
int neg(uint32_t _addr) и int negm(uint32_t _maddr_with_addr) изменить знак ячейки памяти; _maddr_with_addr должен быть адресом к ячейке памяти, которая содержит адрес
int mset(uint32_t _addr, uint32_t _value) и int simple_mset(uint32_t _addr, char _value) изменить содержимое ячейки памяти
int msetl(uint32_t _addr, char *_value) изменить содержимое ячейки памяти; _value может иметь форму «<МЕТКА>» (набирать точно так, как показано, кроме «МЕТКА»)
int mfill(uint32_t _addr, int _v, size_t _s) заполнить _s ячеек памяти числом _v, начиная с _addr
int mfill2(char *_start, int _v, char *_end) заполнить память числом _v от _start до _end; они могут иметь форму <меток> (например, «<abc_endif0>»)
int mcopy(uint32_t _addr_src, uint32_t _addr_dst), int mcopymn(uint32_t _maddr_with_srcaddr, uint32_t _addr_dst), int mcopynm(uint32_t _addr_src, uint32_t _maddr_with_dstaddr), int mcopymm(uint32_t _maddr_with_srcaddr, uint32_t _maddr_with_dstaddr), int mcopyll(char *_labeloraddr_src, char *_labeloraddr_dst), int mcopyln(char *_labeloraddr_src, uint32_t _addr_dst), int mcopynl(uint32_t _addr_src, char *_labeloraddr_dst) копировать содержимое одной ячейки памяти в другую; примеры: mcopymn(var, 8700001) копирует содержимое ячейки памяти, адрес которой находится в var, в яч. 8700001; mcopyll("<label1>", "<label2>") копирует содержимое ячейки <label1> в ячейку <label2>
size_t w_str(char *_s, uint32_t _startaddr) записать строку _s в память, начиная с ячейки _startaddr; возвращает длину строки
int inc(uint32_t _addr) и int dec(uint32_t _addr) инкремент и декремент
int strv(uint32_t _startvaddr, uint32_t _startmaddr, size_t _n) скопировать _n символов из видеопамяти, начиная с _startvaddr, в память, начиная с _startmaddr
int gen(uint32_t _max, uint32_t _dst_addr) генерация числа не больше _max и копирование его в память
int calcmm(uint32_t _addr1, char _op, uint32_t _addr2, uint32_t _resultaddr) и int calcmn(uint32_t _addr1, char _op, uint32_t _num, uint32_t _resultaddr) выполнение операции (сложение, вычитание, получение остатка от деления, деление, умножение, возведение в степень — '+', '-', '%', '/', '*', '^') над числами и сохранение результата в память; пример: calcmn(sum, '-', 2, sum) вычитает 2 из ячейки памяти sum и сохраняет результат в неё
int catv(uint32_t _startaddr, uint32_t _resultaddr, uint32_t _num) если _num равно 48: копировать число-строку из памяти в формате ЦЦЦЦЦЦ (например, 000129), начиная с _startaddr, в ячейку памяти _resultaddr; MT-Unsafe
int catv2(uint32_t _startaddr, uint32_t _resultaddr) копировать число-строку из памяти в формате {-/ }ЦЦЦЦЦЦЦ-0000129», « 8700000»…), начиная с _startaddr, в ячейку памяти _resultaddr; MT-Unsafe

Работа с пользовательскими регистрами править

int getreg(uint8_t _reg, uint32_t _maddr) и int toreg(uint32_t _maddr, uint8_t _reg) — загрузить п. регистр в память и обратно.

Функции xset(uint32_t), xinc() и xdec() выполняют действия над п. регистром _XREG.

Паузы править

slp(5) останавливает выполнение программы на пять секунд, mslp(var) делает паузу на столько секунд, сколько указано в ячейке памяти var. Для задержки в миллисекундах, используйте uslp() и muslp().

Ввод/вывод править

Функции Описание
int aprint(char *_s, uint32_t _addr) напечатать ASCII-строку
int get_c(uint32_t _vaddr, uint32_t _maddr) копировать символ из видеопамяти в память; сперва, указывается адрес в видеопамяти
int get_key(uint32_t _maddr) копировать нажатую клавишу в память
int get_char(int _maddr) ждать символ от пользователя и положить его в ячейку _maddr
int setcolor(uint8_t _bg, uint8_t _other) установить цвет фона и текста
int put_c(uint32_t _c, uint32_t _vaddr) записать символ _c в видеопамять
int put_mc(uint32_t _maddr, uint32_t _vaddr) записать содержимое ячейки памяти _maddr в ячейку видеопамяти _vaddr
int put_mcm(uint32_t _maddr, uint32_t _maddr_with_vaddr) записать содержимое ячейки памяти _maddr в ячейку видеопамяти, адрес которой хранится в яч. памяти _maddr_with_vaddr
int vclear() стереть почти всю видеопамять; исопльзует команду VRST
int xprint(char *_s, int _color) поместить строку в видеопамять с цветом _color (если он не ниже нуля), начиная со значения п. регистра _XREG
int xprintm(uint32_t _startaddr, size_t _size, int _color) аналогично предыдущей функции, но строка имеет длину _size и хранится в памяти, начиная с _startaddr
int xerr(char *_msg) xprint(_msg, _RED)
int xwarn(char *_msg) xprint(_msg, _YELLOW)

Функции put_n(), put_mn() и put_mnm(), подобны put_c(), put_mc() и put_mcm(), но они печатают «как число». Так, put_n(10, _OUT_ST + _LINE_SIZE) отобразит число десять на экран, начиная с яч. видеопамяти _OUT_ST + _LINE_SIZE. Функция upddisp() обновляет экран (используйте после put_c(), put_n()…). vcatv() и vcatv2() аналогичны catv() и catv2(), но число-строка должна быть в видеопамяти.

Задание

Перепишите первую программу так, чтобы она использовала xprint() вместо aprint()

Ветвление править

Условия в mkxm2cc создаются посредством ifmn(), ifmm(), mcomp() и vcomp().

Образец конструкции представлен ниже:

функция_ветвления(, "<Метка>");
    код
L("Метка");

Функции править

Функция Описание
int ifmm(uint32_t _addr1, char *_op, uint32_t _addr2, char *_else_start) сравнивает ячейки памяти _addr1 и _addr2, и, если проверка оказалась неудачна, переходит к _else_start; _op может быть "==", "!="

, ">" или "<"

int ifmn(uint32_t _addr1, char *_op, uint32_t _num, char *_else_start) сравнивает ячейку _addr1 с числом _num, и, если проверка оказалась неудачна, переходит к _else_start
size_t mcomp(uint32_t _addr, char *_s, char *_else_start) сравнивает строку в памяти, начиная с _addr, со строкой _s, и, если проверка оказалась неудачна, переходит к _else_start
size_t vcomp(uint32_t _addr, char *_s, char *_else_start) сравнивает строку в видеопамяти, начиная с _addr, со строкой _s, и, если проверка оказалась неудачна, переходит к _else_start

Безопасность править

Безопасность Xmtwolime и безопасность программ сильно связаны. Программы находятся в разделе system и имеют полный доступ к памяти, независимо от текущего UID. Создавайте безопасные программы!

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

int new_thrd(void *_function(), uint8_t _num) править

Данная функция «выполняет» _function в новом потоке _num. Не рекомендуется устанавливать _num отличным от 1.

Продолжаем изучение править

NOPS(_n) вставляет _n команд nop. Функция reboot() выполняет полную перезагрузку системы. halt() останавливает текущий поток.

exit_app(0) завершит программу с кодом 0. mexit_app(c) завершит программу с кодом, который хранится в ячейке c.

Программа ech.c править

#include <xmtwolime_mkxm2cc.h>

int main(void) {
    init("ech");
    
    addr_t args = alloc(_OUT_ST - _ARGS_ST);
    strv(_ARGS_ST, args, _OUT_ST - _ARGS_ST);
    xprintm(args, _OUT_ST - _ARGS_ST, -1);
    
    exit_app(0);
}

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

  1. Mkxm2cc-библиотека Graphics
  2. sys build.sh

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