Практический экзамен
Для сдачи экзамена необходимо решить все домашние задания
Скачать, установить и запустить программу на Python3 (в некоторых дистрибутивах понадобится дополнительно установить модуль tkinter)
$ wget --content-disposition "http://uneex.ru/LecturesCMC/ArchitectureAssembler2019?action=AttachFile&do=get&target=grzad-0.0.1-py3-none-any.whl" $ pip3 install --user grzad-0.0.1-py3-none-any.whl $ python3 -m grzad
(в загружаемом образе для экзамена достаточно выполнить в консоли команду grzad )
- Следовать указаниям программы-генератора задач
- Это задача на рисование в MARS Bitmap Display
Не забыть включить в код решения (в качестве комментария) номер задания, иначе проверка может оказаться недействительной
Критерий качества: картинки MARS и задачки-генератора должны быть очень похожи
Offline-вариант
- Решить предыдущее задание (самостоятельно)
Решить задание Разряди бобму! (самостоятельно):
Разряди бобму! (исследовательская задача)
Оказывается, Digital Lab Sim умеет тоже работать по прерываниям, причём даже лучше. чем консоль.
Во-первых, если в регистр 0xffff0012 записать 0x80 (7-й бит) вместо бита строки, включится прерывание активации клавиши ( 11, т. е. 11-й бит 13-го регистра управляющего сопросессора Cause, 0x800). При этом для сканирования строк потом всё равно надо записывать туда 1,2,4 или 8 (точнее, 0x81, 0x82, 0x84 или 0x8, чтобы не запретить прерывание), но в этой задаче это не понадобится. Таким образом, активацию клавиши можно отловить обработчиком прерываний (в котором проверить, что 11-бит cause действительно 1).
Во-вторых, что ещё интереснее, если в регистр 0xffff0013 записать не 0 (например, 1), Digital Lab через каждые 30 выполненных Mars-ом инструкций будет генерировать прерывание № 10 (10-й бит регистра Cause, 0x400).
Таким образом можно:
- организовать какое-нибудь периодическое действие, например, смену значений в цифровом индикаторе каждые 3000 инструкций
- организовать асинхронную обработку нажатия на клавишу (всё равно какую)
Итак, задание. Написать программу, которая запускает обратный отчёт от 9 до 0 примерно посекундно и изображает соответствующие цифры на индикаторе (см. решение задачи «Осваиваем Digital Lab»). Если пользователь успел нажать клавишу, ему выводится одно сообщение (например. красивое окошко "Win!" с помощью syscall 55), а если не успел — другое (например, "Boom!"), после чего программа завершается.
Пример проигрыша (в качестве сообщения используется тот же индикатор, но это не обязательно, out0.ogv )
Подсказка 1: не забывайте нажимать Reset перед каждым запуском, а не то возможны артефакты.
Подсказка 2: Оба прерывания могут произойти одновременно, тогда в регистре Cause окажутся оба бита (0xc00 с возможными другими).
Как я решал эту задачу
- (необязательно) Вычислил примерное количество инструкций в секунду. Для этого
- запомнил с помощью sycall 30 текущее время в милисекундах (достаточно $a0)
- обнулил ($gp)
- разрешил прерывание по счётчику, уменьшающее ($gp) на 1 (так будет надо в дальнейшем)
- в цикле проверял, пока текущее время не превысит запомненное на 1000 (что примерно соответствует 1 секунде)
в ($gp) при этом оказалось отрицательное число обработанных прерываний, домножил его на -1, получил примерное количество прерываний счётчика в секунду, запомнил, домножил на 10 секунд, записал в ($gp)
- Обнулил 4($gp) — флаг срабатывания прерывания от кнопки, и разрешил прерывания от кнопки
- Запустил цикл, в котором:
- Если произошло прерывание от кнопки (ненулевой значение 4($gp)), показал пользователю "Win" и вышел
- Если в ($gp) лежит уже не положительное число (прерывание по счётчику, которое уменьшает на ! ($gp), никто не отменял ☺), показал пользователю "Boom" и вышел
- Поделил ($gp) на количество прерываний в секунду, получил номер цифры
- Если номер цифры не совпадает с предыдущим, взял новую цифру из массива (который я скопировал из «Осваиваем Digital Lab»), записал её в индикатор
- Обработчик прерываний
- проверяет бит 0x400 в Cause, и если да, уменьшает ($gp) на единицу
- проверяет бит 0x800 в Cause, и если да, записывает в 4($gp) какой-нибудь не 0 (например, этот самый 0x800)
Вообще-то всё