Эмулятор архитектуры AVR - MariEliseeva/project GitHub Wiki

Эмулятор архитектуры AVR

Комментарии ко второй попытке

Про тесты

make test - собирает юнит-тесты
./bin/test - запуск юнит-тестов.
Если тесты проходят, то будет выведено "All tests passed.",
иначе - сколько тестов не прошли, сколько всего тестов было, где именно произошла ошибка.

Также есть два теста, проверяющих программу целиком: первый проверяет выполняются ли основные команды микроконтроллеров, второй считает число Фибоначчи.
Их запуск (после сборки - make):
./avr -test f_test/input
./avr -test f_test/input_fib
После каждого запуска в файле f_test/output появляется результат выполнения программы.
Ожидаемый результат для первого теста - f_test/output_res, для второго - f_test/output_fib_res.

Про pull request

Работающий код находится на ветке branch_with_project
Сделан pull request от это ветки к пустой - empty_branch
(На master branch тоже работающий код, но без pull request)

Постановка задачи и идея решения

Постановка задачи:

Нужно придумать формат, в котором можно описать команды для микроконтроллеров AVR, а также сделать эмулятор, который по этому описанию сможет выполнять команды. Также нужно чтобы эмулятор не только выполнял команды, но и возвращал какую-то информацию про выполнение.

Идея решения:

Эмулятор умеет выполнять простые действия: присваивать значения, проверять истинность условия, вычислять арифметические выражения. Через эти действия можно выразить все команды.

Описание решения

Эмулятор читает описание команд и для каждого имени запоминает аргументы и инструкции. Затем читает файл с кодом и запоминает для каждой строчки название команды в ней и переданные значения. Потом вызывает метод, выполняющий команды, начиная с первой строчки. Метод возвращает к какой строчке перейти после выполнения.

Внутри - создается unordered_map, который по имени аргумента, заданном в описании, возвращает его значение - если константа, или номер регистра - если регистр. Затем последовательно выполняются необходимые действия.

Каждое действие - это какое-нибудь условие (его может не быть), затем выражение, в котором какое-то значение куда-либо присваивается.

Поэтому в каждом действии вычисляется значение условного выражения - если есть. Далее вычисляется правая часть равенства, полученное значение присваивается в левую.

После выполнения команды программный счётчик (PC) увеличивается на 1 и его значение возвращается в main.

Описание порядка сборки и тестирования приложения, примеры

Информация, которая доступна после или во время выполнения - время работы, какие регистры изменялись, просмотр выбранных пользователем регистров. Также возможна остановка после указанных пользователем строк либо после каждой строки. При остановке тоже можно запросить информацию.

make - сборка, ./avr - запуск
make clean - удаление файлов *o, avr

Описание:

В первой строке файла с описанием находится число - размер памяти микроконтроллера в байтах. Минимальный размер - 64. Если передать значение меньше, то ошибки не произойдёт - будет автоматически задан размер 64.

Во второй строке - время в микросекундах, за которое выполняется один такт на микроконтроллере.

Далее идут строчки с описаниями команд в формате: "Имя команды", затем через пробел перечисление аргументов (аргументы перечисляются через запятую) либо "-", если у данной команды нет аргументов. Далее через запятую инструкции, которые необходимо выполнить. И в конце число - сколько тактов занимает эта команда на микроконтроллере.
Описание команды заканчивается переводом строки.

Все имена команд - разные.

Аргументы: либо номера регистров, либо константы.
Регистры описываются в виде двух символов: большая буква R и еще одна маленькая латинская буква (например Rr, Rd).
Константы описываются как K8 (8 бит), K6(6 бит), b(3 бита), s(3 бита), P(6 бит), k(неизвестное кол-во бит, определяется как-то внутри программы), q(6 бит).

Описание действий: левая часть, равно, правая часть. В левую часть присваивается значение выражения из правой. Можно добавлять условие: в начале строки if(), в скобках выражение, которое вычисляется: 0 - false, не 0 - true.

Можно присваивать в регистры, переданные как аргументы, в регистры по номеру, в регистровые пары RZ, RY, RX, в биты регистра SREG: флаги C, Z, N, V, S ,H, T, I, можно присваивать по адресу в памяти (например (k) - адрес, заданный константой k или (RZ) - адрес, записанный в RZ), в PC - программный счётчик, в какой-то определённый бит регистра (Rr(3) например), также есть STACK - в микроконтроллере он в конце памяти.

Присваиваемое значение или выражение внутри if() - арифметические выражения, операнды которого - вышеперечисленные варианты + переданные константы или просто числа.

Код:

Новая команда - с новой строки
Формат: Имя, пробел, аргументы через запятую. Если среди аргументов есть константа, то можно передавать константное выражение (2+2 например).

Используемые операции для выражений: +, -, *, /, |, &, ||, &&, ==, <, >, !, ~, ^. Унарного минуса нет, но можно написать 0-x, если хочется получить число -x.

⚠️ **GitHub.com Fallback** ⚠️