Ассемблер на Python: язык для своей машины
Паспорт модуля
| Параметр | Значение |
|---|---|
| Аудитория | 🟡🔴; пройден М13; Python на уровне функций и словарей |
| Аутентичная задача | избавиться от ручной адресации навсегда: писать программы с метками, транслировать в .hex и заливать в машину одной командой |
| Объём | 4 занятия × 90 мин |
| Оборудование | ПК с Python 3, машина из М13, RP2350-загрузчик |
| Ограничения | — |
Аутентичная задача. После модуля обучающиеся смогут: пройти полный тулчейн
prog.asm → asm.py → prog.hex → загрузка → исполнение и объяснить, зачем ассемблеру два прохода, — на примере боли из М13.Цели
| № | Обучающиеся … | Блум—Андерсон | Миллер | Проверка |
|---|---|---|---|---|
| 1 | объясняют проблему прямых ссылок и идею двух проходов | понимать | знает | квиз |
| 2 | реализуют ассемблер: мнемоники, метки, .org, .byte, вывод .hex | создавать | делает | тест-набор из 6 исходников, включая ошибочные |
| 3 | реализуют эмулятор ISA и сверяют его с железом | создавать/анализировать | делает | Фибоначчи: эмулятор и машина дают одинаковую последовательность OUT |
| 4 | проектируют осмысленные сообщения об ошибках | оценивать/создавать | делает | ревью: 3 класса ошибок диагностируются с номером строки |
Оценивание
Тест-набор трансляции (итог): корректные исходники → байт-в-байт эталонные .hex; исходники с неизвестной мнемоникой / дублем метки / переходом на несуществующую метку → внятная ошибка со строкой, а не трейсбек. Кросс-проверка эмулятор↔железо — обязательный пункт: расхождение считается находкой (чаще всего оно вскрывает недокументированное поведение микрокода — ценнейший разговор).
Путь и ядро
| № | Тема | Разминка | Ядро |
|---|---|---|---|
| 1 | Два прохода | «почему сдвинулся halt» (М13) | worked example: проход 1 собирает таблицу меток, проход 2 генерирует байты |
| 2 | Ассемблер | таблица опкодов по памяти | реализация + тест-набор |
| 3 | Эмулятор | 3 вопроса зан. 2 | цикл fetch-decode-execute на Python — те же фазы, что в микрокоде: третья встреча с ISA |
| 4 | Тулчейн | кумулятивный квиз М12–М14 | связка с загрузчиком М10; Фибоначчи с метками — сравнить читабельность с листингом М13 |
Скелет (учебный, обучающиеся достраивают):
OPS = {"NOP":0x00,"LDA":0x01,"ADD":0x02,"SUB":0x03,"STA":0x04,
"LDI":0x05,"JMP":0x06,"JC":0x07,"JZ":0x08,"OUT":0x0E,"HLT":0x0F}
NOARG = {"NOP","OUT","HLT"}
def assemble(lines):
labels, pc = {}, 0
for ln in cleaned(lines): # проход 1: адреса меток
if ln.endswith(":"): labels[ln[:-1]] = pc
else: pc += 1 if ln.split()[0] in NOARG else 2
out, pc = bytearray(), 0
for ln in cleaned(lines): # проход 2: кодогенерация
if ln.endswith(":"): continue
op, *arg = ln.split()
out.append(OPS[op]) # + диагностика KeyError -> "строка N: неизвестная мнемоника"
if op not in NOARG:
out.append(resolve(arg[0], labels)) # число 0x.. или метка
return outМетодический стержень: это третья реализация одной ISA (микрокод → эмулятор → далее Verilog). Интервальный возврат встроен в архитектуру программы: обучающийся не «повторяет материал», а переизобретает его в новом медиуме — глубочайшая форма retrieval practice.
Типичные ошибки: пути меток считаются во втором проходе «на лету» — прямые ссылки ломаются (возврат к идее двух проходов); LDI с адресом вместо константы — семантика перепутана (в тест-наборе есть ловушка на это); эмулятор флагов «почти как железо»: C после SUB — сверить с реальным поведением АЛУ М4 (нет заёма → C=1), расхождение эмулятора и макетки здесь — запланированный обучающий конфликт.
Уровни
Ассемблер с метками и .org/.byte, эмулятор, кросс-проверка.
Макросы или псевдокоманды (например, MOV через STA/LDA), дизассемблер для трасс М10, задача «умножение 8×8 → 16 бит» на своей ISA с минимизацией тактов.