Files
Sprinter-SDCC/applications/Volkov/docs/p1-platform-probes.md
T
snark13 8e389c03f8 Volkov: добавить Sprinter Commander
Реализовать двухпанельный Commander от платформенного PoC до этапов P6-P20: EMM-каталог, сортировку и выбор, операции с файлами и деревьями, транзакционное копирование, метаданные, политику конфликтов и предварительную проверку свободного места.

Добавить проектную документацию, HDD/MAME-сценарии и проверенные артефакты. Расширить libc операцией bank_write_page, исправлением режима O_RDONLY и связанными регрессионными проверками.
2026-09-10 10:45:30 +03:00

325 lines
18 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.
# Sprinter Commander: платформенные пробы P1
Статус: MAME 0.287 / BIOS 3.06 — `PASS`; проверка на реальном Sprinter ожидается
Связанные документы:
[требования](commander-requirements.md),
[архитектура](commander-architecture.md),
[клавиши](commander-keymap.md),
[roadmap](commander-roadmap.md),
[экранный backend P2](p2-screen-backend.md)
## 1. Назначение
Программа `p1probe.exe` объединяет платформенные проверки, которые должны
быть завершены до реализации UI Commander. Она не является ранней версией
Commander и не определяет его пользовательский интерфейс.
Исходники находятся в `tests/p1_platform/`.
Вторая программа, `p1child.exe`, используется только для проверки ESTEX
`EXEC`, возврата к родителю и кода завершения.
## 2. Ограничения безопасности
- Пробы не создают, не изменяют и не удаляют файлы.
- Каталожная проба выполняет только `getcwd`, `chdir(".")` и
`ffirst/fnext`.
- EMM-проба пишет только в выделенный ей блок из трёх страниц.
- Screen-проба пишет только в отдельную выделенную EMM-страницу.
- Дочерняя программа меняет видеорежим, но не пишет на диск.
- Проба не открывает файловые дескрипторы приложения напрямую.
- MAME не запускается целями `make` и `make all`.
Первый MAME-прогон выполнен 6 сентября 2026 года после отдельного согласования.
Все запуски использовали автоматически пересоздаваемый `mc.img`; исходные
дисковые образы не изменялись программами-пробами.
## 3. Состав
| Файл | Назначение |
|---|---|
| `p1probe.c` | меню, общие сообщения, последовательность тестов |
| `p1_sys.c` | app-local wrappers DSKINFO, EXEC, WAIT, WINREST |
| `p1_emm.c` | выделение трёх страниц и проверка границ |
| `p1_dir.c` | CURDIR/CHDIR/F_FIRST/F_NEXT и DSKINFO output |
| `p1_screen.c` | полный и частичный WINREST с ненулевым offset |
| `p1_keyboard.c` | вывод `ascii/scan/live modifiers` |
| `p1_exec_test.c` | два режима EXEC и проверка состояния родителя |
| `p1child.c` | дочерний EXE, меняющий режим на 40x32 и возвращающий `0x5A` |
| `mame_dump_keys.lua` | вывод карты полей AT-клавиатуры MAME |
| `mame_p1_keyboard.lua` | воспроизводимый ввод стрелок, F1–F10 и сочетаний |
| `Makefile` | сборка обоих EXE |
## 4. Сборка
```sh
cd applications/Volkov/tests/p1_platform
make
```
Диагностическая программа собирается в режиме `small --safe`. Это сделано
намеренно: P1 проверяет платформенные ABI и не должен одновременно отлаживать
банковую topology Commander. Сборка `big --safe` является критерием P2.
Дочерняя программа собирается как `tiny --safe`.
### Результат текущей сборки
`p1probe.exe`:
- `_CODE`: 11 062 байта;
- данные: 2 741 байт;
- файл EXE: 11 835 байт;
- heap после статики: 17 429 байт;
- стек: 1 279 байт.
`p1child.exe`:
- `_CODE`: 3 907 байт;
- данные: 849 байт;
- файл EXE: 4 453 байта;
- heap после статики: 10 092 байта;
- стек: 1 279 байт.
Компиляция выполнена без ошибок. Значения относятся к текущей диагностической
сборке и не являются бюджетом Commander.
## 5. Статическая проверка ABI
### 5.1. DSKINFO
Сигнатура:
```c
int p1_disk_info(uint8_t disk, P1DiskInfo *out);
```
Сгенерированный вызов передаёт `disk` в A, `out` в DE. Wrapper сохраняет IX,
а после RST сохраняет:
- A — sectors per cluster;
- HL — total clusters;
- DE — free clusters;
- BC — bytes per sector.
Размер `P1DiskInfo` проверяется typedef-assert и равен семи байтам.
### 5.2. EXEC
Сигнатура намеренно имеет 8-битный аргумент первым:
```c
int p1_exec(uint8_t path_mode, const char *path);
```
Для этого порядка SDCC передаёт `path_mode` в A и `path` в DE. Wrapper
перекладывает их в B и HL соответственно. Вариант
`p1_exec(const char *path, uint8_t mode)` был отвергнут после просмотра
сгенерированного ASM: второй 8-битный аргумент SDCC помещал на стек, а не в
DE.
На успехе A сохраняется как `p1_exec_exit_code`; на ошибке код из A проходит
через `__errno_set`.
### 5.3. WINREST
Wrapper повторяет уже подтверждённую раскладку `tests/winrest` и `mdview2`:
```text
A row
L column
SP+2 height
SP+3 width
SP+4 physical page
SP+5..6 offset in 16-KB page
```
IX сохраняется, перед RST устанавливается в `0xC000 + offset`. Сгенерированный
вызов проверен для полного экрана `32x80` и окна `2x20` с offset `0x2000`.
## 6. Меню `p1probe.exe`
| Клавиша | Проба | Автоматическая оценка |
|---|---|---|
| `1` | Каталог и F_FIRST/F_NEXT | да, плюс наблюдаемые коды |
| `2` | EMM: три страницы | да |
| `3` | WINREST full/partial | только завершение; изображение оценивается визуально |
| `4` | Клавиатурные коды | сбор наблюдений |
| `5` | EXEC и возврат | да для режима B=1 |
| `6` | DSKINFO текущего диска | да |
| `A` | Пробы 1, 2 и 6 | да |
| `0`/`Esc` | Выход | — |
## 7. Ожидаемые проверки
### 7.1. Каталог
Проба дважды перечисляет каталог по маскам `*.*` и `*`, печатает первые 20
записей и итоговые значения:
- число записей;
- наличие `.`;
- наличие `..`;
- `errno` последнего `fnext()`;
- совпадение результатов двух масок;
- сохранение CWD после `chdir(".")`.
Фактический результат DSS различается: `*.*` вернул обе записи с расширением,
а `*` завершился как пустой список с `ENOENT`. Поэтому `*.*` принят как
обязательный шаблон полного scan; совпадение масок не предполагается.
MAME-прогон установил фактическое завершение перечисления: `fnext()`
возвращает ошибку с `errno=3` (`ENOENT`). Код `0x0F` из старого описания DSS
для этой операции не подтверждён. Проба после измерения принимает только
`ENOENT`, чтобы возможная смена поведения не осталась незамеченной.
### 7.2. EMM
Проверяются:
- `mem_alloc_pages(3)`;
- три различных физических номера;
- первые 64 байта каждой страницы;
- последние 64 байта каждой страницы;
- независимые patterns страниц;
- восстановление `mem_info.free_pages` после освобождения блока.
### 7.3. Screen/WINREST
Первый вызов должен показать полный экран 80x32 с рамкой и цветными строками.
После клавиши второй вызов должен наложить окно 20x2 в позиции row 14,
column 30. Данные второго окна лежат по offset `0x2000`, поэтому тест
одновременно проверяет корректность IX.
Тест не открывает окно через BIOS: ESTEX WINREST здесь только копирует
прямоугольник в текущий текстовый экран. Повтор со снимками в `t=20` и `t=24`
без промежуточных вызовов подтвердил, что фон вне прямоугольника сохранён.
Первая версия pattern использовала арифметически полученные атрибуты
`0x11..0x17`. Верхняя граница `0x11` была обычным blue-on-blue, а часть
остальных сочетаний выглядела неоднозначно в разных моментах палитрового
цикла. Замечание о синих символах на синем фоне подтвердилось; raw-арифметика
атрибутов в UI запрещается.
После замены на именованные `COLOR(LIGHTBLUE..WHITE, BLUE)` полный экран и
частичное окно были видимы на кадрах `t=20` и `t=24`. Повторная проверка
исходных PNG установила, что их декодированные RGB-пиксели полностью
идентичны. Прежнее сообщение о чередовании P2 было ошибкой встроенного
предпросмотра, а не поведением MAME.
Отдельная проба P2.2 сохранила, установила, прочитала обратно и восстановила
шесть атрибутов во всех четырёх планах; многоцветная сцена осталась стабильной.
Строка P1-SCR-03 ниже подтверждена как `PASS`. Детали — в
[результатах P2.2](p2-palette-results.md).
### 7.4. Keyboard
Для 24 событий печатаются:
```text
ascii, scan, полное kbd_mod_state, compact Shift/Ctrl/Alt
```
`Esc` печатается последним и завершает сбор. В автоматическом MAME-сценарии
использован следующий набор из 24 событий:
- стрелки, Home/End, PgUp/PgDn;
- F1F10;
- Insert/Delete;
- Ctrl+R;
- Ctrl+PgUp;
- Alt+F1;
- Esc.
### 7.5. EXEC
Выполняются два случая:
1. `B=0`, `P1CHILD.EXE` — наблюдение short-name/PATH semantics.
2. `B=1`, `.\\P1CHILD.EXE` — обязательный случай PoC.
Дочерняя программа:
- переключается в 40x32;
- показывает свои W1/W2/W3 и CWD;
- ждёт клавишу;
- возвращает `0x5A`.
После возврата родитель проверяет:
- результат непосредственного EXEC;
- результат WAIT;
- восстановление W1/W2/W3;
- восстановление CWD;
- возможность вернуть 80x32 и продолжить работу.
Ошибка случая B=0 записывается как наблюдение и не проваливает PoC. Ошибка
B=1 проваливает тест.
## 8. Выполненный порядок первого прогона
1. `2` — EMM.
2. `6` — DSKINFO.
3. `1` — каталог.
4. `3` — WINREST.
5. `4` — клавиатура.
6. `5` — EXEC последним.
7. Повторно `2` в том же процессе после EXEC, чтобы проверить EMM.
8. Возврат в меню; независимые запуски дополнительно подтвердили повторный
старт программы.
Такой порядок сначала проверяет неразрушительные примитивы и оставляет
наиболее сложное переключение контекста на конец.
## 9. Таблица runtime-результатов
Окружение MAME: `mame.arm` 0.287 (`b0c4527c`), машина `sprinter`, BIOS `v3.06`, запуск
`p1probe.exe` с дискеты A:. `PENDING` в аппаратной колонке означает только
отсутствие прогона на реальном Sprinter и не отменяет результата MAME.
| ID | Проверка | MAME 0.287 / BIOS 3.06 | Реальный Sprinter | Артефакт |
|---|---|---|---|---|
| P1-DIR-01 | CWD и `chdir(".")` | PASS | PENDING | [результат](../artifacts/mame-p1/directory/strict-enoent.png) |
| P1-DIR-02 | `*.*` против `*` | PASS: `2` против `0`; полный scan использует только `*.*` | PENDING | [результат](../artifacts/mame-p1/directory/strict-enoent.png) |
| P1-DIR-03 | Код конца F_NEXT | PASS, `ENOENT=3` | PENDING | [строгая проверка](../artifacts/mame-p1/directory/strict-enoent.png) |
| P1-EMM-01 | Блок 3 страницы | PASS, страницы `EF/F0/F1` | PENDING | [результат](../artifacts/mame-p1/emm/result.png) |
| P1-EMM-02 | Границы страниц | PASS | PENDING | [результат](../artifacts/mame-p1/emm/result.png) |
| P1-EMM-03 | Счётчик после free | PASS, `221 → 221` | PENDING | [результат](../artifacts/mame-p1/emm/result.png) |
| P1-SCR-01 | Полный WINREST 80x32 | PASS, визуально | PENDING | [контрастный экран](../artifacts/mame-p1/winrest/full-contrast.png) |
| P1-SCR-02 | Offset WINREST | PASS, row 14 / col 30 / `0x2000` | PENDING | [фон и окно вместе](../artifacts/mame-p1/winrest/partial-contrast-stable.png) |
| P1-SCR-03 | Цветные атрибуты в двух моментах цикла | PASS, RGB кадров идентичен; P2.2 подтвердил 6 атрибутов × 4 плана | PENDING | [кадр 1](../artifacts/mame-p1/winrest/partial-flash-phase.png), [кадр 2](../artifacts/mame-p1/winrest/partial-contrast-stable.png), [P2.2](p2-palette-results.md) |
| P1-SCR-04 | Raw-атрибуты `0x11..0x17` | OBSERVED, raw-арифметика запрещена | PENDING | [неудачный исходный pattern](../artifacts/mame-p1/winrest/partial-phase-hidden.png) |
| P1-KBD-01 | Базовые scan-коды | PASS | PENDING | [таблица](../artifacts/mame-p1/keyboard-commander/sprinter/0002.png) |
| P1-KBD-02 | Ctrl/Alt modifiers | PASS | PENDING | [сочетания](../artifacts/mame-p1/keyboard-commander/sprinter/0003.png) |
| P1-EXE-01 | EXEC B=0 | PASS | PENDING | [результат](../artifacts/mame-p1/exec/result.png) |
| P1-EXE-02 | EXEC B=1 | PASS | PENDING | [результат](../artifacts/mame-p1/exec/result.png) |
| P1-EXE-03 | Exit/WAIT `0x5A` | PASS / PASS | PENDING | [результат](../artifacts/mame-p1/exec/result.png) |
| P1-EXE-04 | Восстановление W1/W2/W3 | PASS, `F3/F2/FF` | PENDING | [результат](../artifacts/mame-p1/exec/result.png) |
| P1-EXE-05 | EMM после двух EXEC | PASS | PENDING | [контроль](../artifacts/mame-p1/exec-then-emm/emm-result.png) |
| P1-DSK-01 | DSKINFO | PASS | PENDING | [результат](../artifacts/mame-p1/dskinfo/result.png) |
### 9.1. Зафиксированные значения
- DSKINFO: 1 сектор на кластер, 512 байт на сектор, 2847 кластеров всего,
2814 свободно.
- EMM до выделения: 256 страниц всего, 221 свободна; после освобождения
снова 221.
- Оба режима EXEC: `rc=0`, `errno=0`, непосредственный exit=`5A`, WAIT=`5A`.
- CWD до и после child: `\`; страницы W1/W2/W3 до и после: `F3/F2/FF`.
- Модифицированная клавиша приходит с установленным битом 7 scan-кода:
Ctrl+R=`93`, Ctrl+PgUp=`D9`, Alt+F1=`BB`. После `scan & 0x7F` получаются
базовые коды `13`, `59`, `3B`; compact modifiers равны `02`, `02`, `04`.
- Esc: `ascii=1B`, `scan=01`.
## 10. Условия завершения P1
MAME-часть P1 завершена: все обязательные строки имеют `PASS`, фактические
клавиатурные коды перенесены в keymap, завершение `fnext()` уточнено,
`EXEC B=1`/WAIT и EMM после child подтверждены, артефакты сохранены.
Проверка на реальном Sprinter остаётся желательной аппаратной валидацией,
но не блокирует переход к P2 и реализацию platform API PoC. Если реальное
железо даст расхождение, оно оформляется отдельным репро и не маскируется
адаптацией UI.