Вы также можете прочитать этот README на английском.
Если вы хотите написать программу на языке этого ассемблера, потом запусть ассемблинг вашего кода и, наконец, процессор, то для этого вам понадобится сделать следующие шаги:
-
- Скачайте все содержимое папки с exe'шниками.
-
- Теперь, чтобы написать код, вам необходимо ознакомится с синтаксисом и особенностями ассемблера. Это можно сделать здесь
-
- Чтобы сразу запустить и ассемблинг и CPU есть два способа (через консоль и через make_all.exe):
- 3.1) При помощи консоли:
- 3.1.1) Запустите консоль в скаченной папке. Это можно сделать следующим образом:
- 3.1.2) Теперь в открывшейся консоли необходимо написать
make_all.exe имя_файла_с_кодом
. Имя_файла_с_кодом можно и не указывать, только тогда assemlber будет ассемблировать файл с именем user_code[for_user].asm. Если же указать имя файла, то и ассемблировать он будет, соответственно, его.
- 3.2) При помощи make_all.exe. Для этого просто запустите(откройте) его. Минус этого способа заключается в том, что вы не сможете аргументом указать какой файл ассемблировать. Если же такой необходимости нет, то это вполне юзабельный способ.
-
- Если была получена какая-либо ошибка при ассемблировании или исполнении, то вы получите об этом сообщение, это ошибка будет отображена в DUMP_ASSEM или DUMP_CPU соответственно.
В данном проекте были реализованные следующие основные понятие: ассемблирование команд в машинный код , симуляция работы центрального обрабатывающего устройства (CPU), а так же дизассемблирование машинного кода обратно в ассемблерные команды.
Для того, чтобы быть в курсе всего, что происходит настоятельно рекомендуем для начала ознакомится с этим проектом. Это необходимо так как процессор, реализованный в этом проекте, стековый, а значит stack является его основной частью.
В этом проекте мы реализовали симуляцию работы процессора. То есть как ассемблируются команды в код и как он исполняется процессором. Под процессором мы понимаем симуляцию его работы. Для наглядность можете ознакомиться со списком вещей, которые реализованны в этом проекте.
- [Assembler]
- Обработка первоначального текста
- Обрабатывать разные случаи текста
- Без комментариев
- С комментариями
- С пустыми строками
- С лишними разделительными знаками
- Обработка меток с самого начала
- Через массив из структур меток, то есть двухпроходного считывание
- Обрабатывать разные случаи текста
- Кодировка команд в ассемблерный код.
- Сделать кодировку биективной
- Обеспечить работу с различными типами данных
- Через классы, то есть переписать проект на C++
- Реализовать работу с типом данных double
- Обеспечить работу с регистрами
- Биективная кодировка
- Обработка меток
- Биективная кодировка меток
- Условные переходы
- Биективное кодирование условных переходов
- Функции
- Рекурсия
- Бинарное кодирование
- RAM
- Видеопамять.
- Обработка первоначального текста
- [CPU]
- Обеспечить считывание ассемблерного кода из файла
- Реализация работу CPU через Stack для большей эффективности и мобильности
- Использоть собственную библиотеку для работы со Stack'ом
- Сделать возможным работу с основными командами
-
push 66, push rix
- add, mul, sub, div
- sin, cos, ln, log2, log10, pow, sqrt
- in, out
- jmp, je, jae, jab, jbe, ja, jb
- hlt
- mov, neq, in rix
- call function:
-
- Однозначность результата обработки при исходном коде.
- Поддержка Рекурсии.
- Распознавание бинарного кодирования.
- RAM.
- Видеопамять.
- [Disassembler]
- Обработка закодированных команд.
- Дизассемблирование кодов команд в коды.
- Биективный дизассемблинг.
- Получать из кодов меток названия самих меток (возможно немного преобразованных, но после обратного ассемблинга ассемблерный код остается такой же).
- Поддержка разных типов данных.
- [Make_all]
Прошу заметить, что примеры ассемблерных программ уже есть в этом репозитории, они находятся в этой папке. Однако я считаю, что необходимо примести пару примеров особо интересных программ с пояснением как они работают.
- [Факториал]
push 9 ; факториал какого числа будем считать pop rax ; заносим это число в регистр rax push 1 ; начальное значение факториала pop rbx ; регистр rbx будет хранить результат работа программы call :Factorial ; вызываем функцию факториала, после ее завершения в rbx будет значение ; факториала искомого числа (в данном примере это 9) push rbx ; перед концом программы занесем значение результата в стек, чтобы можно ; было посмотреть его в CPU_DUMP hlt Factorial: push 0 ; граничное значние rax (rax в этом случае, это счетчик) push rax ; само значение в rax je :END ; проверка на граничное условие, чтобы перейти на метку END: ; то есть если изначальное число (9) стало 0, то мы посчитали факториал. push rax ; Если rax != 0, то факториал не посчитать, и нужно считать дальше push rbx ; теперь в стеке лежит rax и rab mul ; умножаем их между собой pop rbx ; а результат обратно в счетчик факотриала push rax ; теперь rax, который отвечает за счетчик факториала кладем в стек push 1 ; а именно пушим в стек 1 sub ; отнимаем pop rax ; результат обратно в счетчик (то есть мы уменьшили его на 1) call :Factorial ; уходим в рекурсию, то есть опять вызываем функцию Factorial END: ret ; Выходим из функции
- [Решение квадратного уравнения]
in ; ввод с клавиатуры в коэф. a in ; ввод с клавиатуры в коэф. b in ; ввод с клавиатуры в коэф. c jmp :DISCK ; идем на вычисление значения дискриминанта GOOD: ; метка, означающая, что дискриминант >= 0 push rbx ; заносим в стек значение коэф. b push -1 ; заносим в стек -1 для того, чтобы посчитать -b mul ; -b push rdx ; пушим в стек значеник rdx(который хранит значение дискриминанта) sqr ; корень из discr add ; -b + корень из discr push 2 ; пушим 2 push rax ; пушим rax, отвечающий за коэф. a mul ; 2a div ; (-b + корень из discr)/2a = x1 push rbx ; АНАЛОГИЧНЫЕ ДЕЙСТВИЯ, только в дальнейшем вычислим x2 push -1 ; .. mul ; -b push rdx ; заносим значение дискриминанта sqr ; корень из discr sub ; -b - корень из discr push 2 ; пушим 2 push rax ; пушим rax (то есть коэф. 2) mul ; 2a div ; )-b - корень из discr)/2a = x2 ; Теперь в стеке хранятся x1 и x2, их значения можно посмотреть в DUMP_CPU EXIT: hlt DISCK: ; Здесь будем вычислять коэффициент pop rcx ; Достаем из стека значение для коэф. c pop rbx ; b pop rax ; a push rbx ; заносим коэф. b чтобы вычислить b^2 push 2 ; заносим в стек 2 pow ; b^2 push rax ; заносим коэф. a push rcx ; b mul ; умножаем их, чтобы получить ac push 4 ; заносим 4 mul ; получаем 4ac sub ; отнимаем и получаем b^2 - 4ac pop rdx ; кладем из стека в rdx (теперь этот регистр отвечает за знач. дискриминанта) push rdx ; заносим в стек значение дискриминанта чтобы сравнить его на валидность push 0 ; валидность -- это >= 0, поэтому пушим в стек 0 jae :GOOD ; jae -- это >=, поэтому в случае этого переходим на метку GOOD jmp :EXIT ; в противном случае переходим на выход.