Files
Sprinter-SDCC/docs/mame-autotest.md
T
snark13 3bf50f7ff7 docs: единый справочник по автотестам в MAME; убрать метод AUTORUN.BAT
- docs/mame-autotest.md — исчерпывающий документ: запуск, ввод команд,
  скриншоты, завершение сессий, анализ, раскладка клавиатуры, все квирки.
  Одного этого документа достаточно, чтобы работать с MAME в режиме
  автотестирования.
- mame_interactive.py теперь единственный инструмент: авто-запускает exe
  вводом пути (a:\<exe>+Enter), --step опционален (доп. ввод в программу),
  умные дефолты снимков/таймаута.
- удалён mame_auto_test.py (старый метод через AUTORUN.BAT chainload) и
  все упоминания AUTORUN.BAT в доках; интерактивный ввод его заменил.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 16:41:45 +03:00

243 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Автотестирование в MAME
Единый справочник: как запускать программы Sprinter в эмуляторе MAME
**без участия человека**, вводить команды, снимать скриншоты, завершать
сессию и анализировать результат. Если нужно что-то про автотесты в
MAME — смотреть сюда.
Весь механизм собран в одном инструменте: **`toolchain/mame_interactive.py`**.
---
## 1. TL;DR
```bash
# собрать .exe (пример)
make -C tests/bgitest
# запустить в MAME, снять экран, выйти по таймауту
python3 toolchain/mame_interactive.py tests/bgitest/bgitest.exe \
--snap 12,14 --timeout 16
```
Инструмент сам:
1. проверит, что нет висящих копий MAME;
2. положит `.exe` на дискету A: (`mame/v306/IMG/mc.img`);
3. запустит MAME с драйвером `sprinter`;
4. дождётся приглашения `C:\>` и **напечатает `a:\bgitest.exe` + Enter**
(эмулируя нажатия клавиш);
5. снимет скриншоты в указанные секунды эмулированного времени;
6. завершит сессию по таймауту;
7. выведет пути к PNG-скриншотам.
Скриншоты лежат в `mame/v306/snap_auto/sprinter/` (`0000.png`, `0001.png`,
…). Их читает Claude визуально (инструментом Read) — текст с экрана
программно НЕ распознаётся.
---
## 2. Инструмент: `mame_interactive.py`
```
python3 toolchain/mame_interactive.py [exe] [--data f ...] \
[--launch-at T] [--step "T:TEXT" ...] [--snap t1,t2,...] [--timeout N]
```
| Аргумент | Назначение |
|----------|-----------|
| `exe` | `.exe` кладётся на A: и **авто-запускается** (печатается `a:\<exe>`+Enter в момент `--launch-at`). Без `exe` работаем на голой командной строке. |
| `--data f ...` | доп. файлы на дискету A: (данные для теста). |
| `--launch-at T` | секунда, когда печатается запуск `exe` (по умолчанию **8**). |
| `--step "T:TEXT"` | в момент `T` сек напечатать `TEXT`. Можно много раз — диалог с уже запущенной программой. В `TEXT`: `\n`=Enter, `\t`=Tab; заглавные и символы через Shift — автоматически. |
| `--snap t1,t2,...` | секунды эмуляции для скриншотов. По умолчанию: `launch_at+4` и `+6` (для `exe`), либо сразу после последнего ввода. |
| `--timeout N` | секунд эмуляции до принудительного выхода. По умолчанию — чуть позже последнего скриншота. |
**Важно:** все времена — это **секунды эмулированного времени от старта
машины** (не от нажатий, их «нет»). Загрузка DSS до `C:\>` занимает
~7 секунд, поэтому `--launch-at 8` и скриншоты с ~12 с.
### Типовые рецепты
```bash
# 1. Запустить тест и снять результат (самый частый случай)
python3 toolchain/mame_interactive.py tests/rt_test/rt_test.exe \
--snap 12,14 --timeout 16
# 2. Набрать команду на голой командной строке (без exe)
python3 toolchain/mame_interactive.py --step "8:dir\n" \
--snap 10,11 --timeout 12
# 3. Запустить программу и ответить на её ввод (например, выбор пункта меню)
python3 toolchain/mame_interactive.py tests/menu/menu.exe \
--step "13:2\n" --snap 15 --timeout 17
# 4. Тест с файлом-данными на дискете
python3 toolchain/mame_interactive.py examples/mdview2/mdview2.exe \
--data doc.md --step "13:mdview2 doc.md\n" --snap 16 --timeout 18
```
---
## 3. Как это работает внутри
### 3.1 Запуск MAME
Нативный `mame.arm` (arm64) в `mame/v306/`, драйвер `sprinter`, BIOS
v3.06. Полный набор аргументов зашит в `COMMON_ARGS` внутри скрипта:
две дискеты (A: наш `mc.img`, B: DSS 1.71u), два HDD-образа (система +
медиа), CD-ROM, ZX-Bus карта NeoGS, `-video opengl -window`,
`-snapshot_directory`, `-autoboot_script <сгенерированный .lua>`.
### 3.2 Ввод с клавиатуры — ключевой момент
У Sprinter в MAME **две** клавиатуры:
- `IO_LINE0..7` — легаси ZX-Spectrum-матрица (порт `0xFE`). DSS её для
командной строки **НЕ читает**.
- `root:kbd:ms_naturl`**настоящая AT/PS-2 клавиатура**, подключённая
последовательно к SIO Z84C015 (`sprinter.cpp:2037`). Именно её DSS
читает как поток scancode'ов.
Поэтому **не работают** (проверено многократно): `natkeyboard:post`,
`-autoboot_command`, а также `set_value` по полям `:IO_LINE*`. Всё это
бьёт в ZX-матрицу, которую DSS игнорирует.
**Работает** — прямое управление полями AT-клавиатуры из Lua:
```lua
manager.machine.ioport.ports[":kbd:ms_naturl:P1.4"].fields["D"]:set_value(1) -- нажать
... подождать ~0.06с ...
manager.machine.ioport.ports[":kbd:ms_naturl:P1.4"].fields["D"]:set_value(0) -- отпустить
```
`at_keyboard` сам сгенерит make/break scancode'ы → SIO → DSS.
Скрипт хранит раскладку `char → (порт, битовая маска)` (словарь `PHYS` +
`SHIFTED` для Shift-символов) и разворачивает строку в список
timed-событий `(время, порт, маска, значение)`. Backslash `\` в
AT-клавиатуре есть (поле `P2.1`/0x4) — путь `a:\name.exe` вводится
полностью.
### 3.3 Тайминг (Lua)
Генерируется `_interactive_gen.lua`, который через
`emu.register_periodic` на каждом кадре сверяет **эмулированное время** и
проигрывает события ввода, снимает скриншоты и завершает сессию.
Время берётся как `t.seconds + t.attoseconds/1e18`, потому что
`attotime.seconds`**целое** (дробную часть отбрасывает); если считать
по нему, все события схлопнутся в 1-секундную сетку.
Старт отсчёта — `emu.add_machine_reset_notifier` (НЕ `emu.register_start`
— он deprecated).
### 3.4 Скриншоты
`manager.machine.video:snapshot()` пишет PNG в каталог из
`-snapshot_directory` (`mame/v306/snap_auto/sprinter/`). Скрипт перед
запуском чистит этот каталог, потом печатает пути к готовым файлам.
Claude открывает их инструментом Read (визуальный анализ).
### 3.5 Завершение сессии
Два рубежа, чтобы MAME гарантированно не «завис»:
- в Lua: при `elapsed >= timeout``manager.machine:exit()` (чистый
выход);
- снаружи: shell-обёртка `timeout <N+8> ./mame.arm …` как страховка.
---
## 4. Предпосылки (окружение)
- **MAME**: `mame/v306/mame.arm` + образы в `mame/v306/IMG/`
(`mc.img` — наш перезаписываемый A:, `dss171u.img`, HDD `.chd`, CD
`.iso`). Каталог `mame/` целиком в `.gitignore` — поэтому инструмент
живёт в `toolchain/`, а не рядом с MAME.
- **Загрузка должна доходить до `C:\>`.** `system.bat` на системном
диске НЕ должен автоматически запускать Flex Navigator или приложение —
иначе мы не попадём на командную строку и ввод уйдёт в чужую программу.
(Это файл на HDD-образе, вне репозитория; правится один раз.)
- **Нет висящих копий MAME.** Несколько одновременных инстансов пишут в
один `mc.img` и дают недостоверный результат. Скрипт проверяет это сам
(`pgrep`), но при ручных запусках MAME — проверяйте `ps aux | grep mame`.
---
## 5. Как выбирать времена
- **Загрузка до `C:\>`:** ~7 секунд → `--launch-at 8` безопасно.
- **Набор пути `a:\name.exe`:** ~13 символов × 0.14с ≈ 1.8с → команда
уходит около 9.8с, программа стартует ~10с.
- **Скриншот:** давайте программе дорисоваться. Быстрая программа —
снимать с ~12с; если рисует долго/по частям, снимайте несколько кадров
(`--snap 12,16,20`) и смотрите, где картинка «дособралась».
- **Диалог с программой (`--step`):** времена шагов ставьте ПОСЛЕ старта
программы (например, запуск на 8с, ответ на ввод на 13–15с).
---
## 6. Анализ результата
- Скриншоты — **единственный** способ проверки: программного чтения
текстового/графического VRAM нет, OCR нет. Claude читает PNG глазами
(инструмент Read с картинкой).
- Лог MAME фильтруется по строкам `[interactive]` (моменты снимков и
выхода) — видно, в какие секунды сделаны кадры.
- Если картинка «не дособралась» — снять более поздний кадр (увеличить
`--snap`/`--timeout`).
---
## 7. Раскладка клавиатуры (справочно)
Раскладка снята дампом ioport-полей `:kbd:ms_naturl:*` живой машины.
Она зашита в `PHYS`/`SHIFTED` внутри `mame_interactive.py`. Поддержаны:
буквы (a–z, A–Z через Shift), цифры, пробел, Enter (`\n`), Tab (`\t`),
и символы ``- = [ ] \ ; ' , . / ` `` плюс их Shift-версии
`! @ # $ % ^ & * ( ) _ + { } | : " < > ? ~`.
Если понадобится клавиша вне списка — снять её поле дампом (пример
Lua-пробы ниже) и добавить в `PHYS`:
```lua
-- дамп всех полей клавиатуры в лог
for tag, port in pairs(manager.machine.ioport.ports) do
if tostring(tag):find("kbd") then
for fname, field in pairs(port.fields) do
print(string.format("%s mask=0x%x %q", tag, field.mask, fname))
end
end
end
```
---
## 8. Квирки и грабли (все, на которые уже наступали)
- **`attotime.seconds` — целое.** Субсекундный тайминг только через
`seconds + attoseconds/1e18`.
- **Автоповтор (typematic).** Клавишу держать коротко (~0.06с). Если
держать ~1с — `d` превратится в `dddddd`.
- **Слипание scancode'ов.** Между символами ~0.14с.
- **Не та клавиатура.** Ввод — только в `:kbd:ms_naturl`, НЕ в
`:IO_LINE*`, НЕ через `natkeyboard`/`-autoboot_command`.
- **Загрузка мимо `C:\>`.** Если `system.bat` что-то автозапускает —
ввод уходит в чужую программу; вернуть чистую командную строку.
- **Висящие копии MAME.** Всегда проверять перед запуском.
- **macOS-специфика (справочно):** известный баг MAME
(mamedev/mame#10612 — потеря ввода в fullscreen при движении мыши на
старте) к нам НЕ относится: работаем в `-window`, ввод скриптовый.
---
## 9. На будущее (заметки, ещё не в инструменте)
- **Быстрый накопитель.** Тестам, которым важна скорость диска (напр.
потоковое чтение), имеет смысл копировать файлы с медленной дискеты A:
на HDD `C:\TEMP` перед запуском.
- **Видео+звук.** MAME умеет писать AVI (`-aviwrite`) — для тестов с
анимацией/звуком, где скриншотов мало. Пока не подключено к скрипту.
- **Ручная отладка ввода.** Запуск MAME с `-console` даёт интерактивный
Lua-REPL — удобно нащупывать поля/тайминги вживую перед скриптованием.
- **Второй видеорежим/варианты BIOS** — при необходимости менять
`COMMON_ARGS`.
```