# Sprinter Commander: экранный backend P2 Статус: ядро P2.1 и многоцветная тема P2.2 прошли MAME; аппаратная проверка, восстановление после child и измерение времени ожидаются. Связанные документы: [архитектура](commander-architecture.md), [требования](commander-requirements.md), [roadmap](commander-roadmap.md), [результаты P1](p1-platform-probes.md), [результаты P2.1](p2-screen-probe-results.md), [результаты P2.2](p2-palette-results.md) ## 1. Решение Commander не использует систему оконных дескрипторов BIOS (`WIN_OPEN`, `WIN_CLOSE`, `WIN_COPY_WIN`, `WIN_RESTORE_WIN`). Текущий BIOS хранит только один описатель с идентификатором 0; открытие нового окна уничтожает прежнее состояние. Диалоги, панели и меню поэтому являются прямоугольниками внутри собственной модели экрана Commander, а не окнами BIOS. Целевой backend выводит в координаты полного экрана через системные функции, но не открывает и не переключает BIOS-окна. Основной пакетный примитив — ESTEX `WINREST`; для специальных операций доступны координатные `WRCHAR`, `CLEAR` и `SCROLL`. Прямой доступ к VRAM не используется. ## 2. Что уже доказано P1 и `examples/mdview2` подтвердили формат логического буфера: ```text (char, attr), по строкам, stride = width * 2, без padding ``` `WINREST` корректно выводит полный экран, отдельную строку и прямоугольник из ненулевого смещения EMM-страницы. Эта функция ESTEX не создаёт BIOS-окно и не использует его идентификатор; слово `WIN` здесь означает прямоугольную область текущего экрана. `mdview2` — полезный образец полноэкранного приложения: состояние документа принадлежит программе, строки материала выводятся из собственного кэша, а status/menu рисуются координатными примитивами. Commander сохраняет этот принцип, но выносит способ вывода в отдельный backend. ## 3. Почему используем системный координатный вывод - DSS/BIOS уже знают реальное устройство текстового режима, знакогенератора, активной screen page и системной палитры. - `WINREST` выводит сразу прямоугольник из EMM, поэтому не требуется RST на каждую ячейку. - Координатные ESTEX-функции не используют идентификатор глобального окна. - После возврата из child достаточно снова установить 80x32 и вывести всю экранную модель. - Один путь работает и в MAME, и на реальном Sprinter без предположений о внутренней раскладке VRAM. ## 4. Граница между оконными и безоконными функциями Запрещены функции управления глобальными окнами, где передаётся window ID: `WIN_OPEN`, `WIN_CLOSE`, `WIN_COPY_WIN`, `WIN_RESTORE_WIN`, `WIN_MOVE_WIN`. Они зависят от единственного поддерживаемого описателя 0. Разрешены: - ESTEX `WINREST 5Ah` — прямоугольник `(row, col, height, width)`, EMM page и source address, без window ID; - ESTEX `WRCHAR 58h`, `CLEAR 56h`, `SCROLL 55h` — абсолютные координаты активной screen page; - BIOS `LP_SET_PLACE`/`LP_PRINT_*`/`LP_CLS_WIN*` — только как пакетные оптимизации для глобального экрана, без открытия новых окон. Системные вызовы чтения и записи текстовой палитры также разрешены. Их отсутствие в P2.1 — способ изолировать экранный backend, а не архитектурный запрет. Выделенный модуль темы использует их для полного save/set/restore; контракт подтверждён P2.2. Чтобы renderer не зависел от текущего cursor/place, основным остаётся `WINREST`. Если применяется BIOS `LP_*`, backend всегда сам устанавливает place непосредственно перед операцией и не оставляет его частью состояния UI. ## 5. Палитра и FLASH У Sprinter атрибут — индекс в четыре текстовых палитровых плана: paper, ink, flash-paper и flash-ink. Сигнал FLASH переключает пары глобально. Чтобы тема Commander не мигала, для каждого используемого атрибута normal-paper и flash-paper задаются одинаково, как и normal-ink с flash-ink. Первый pattern P1 с raw-атрибутами `0x11..0x17` действительно содержал blue-on-blue. Это ошибка выбора атрибутов, а не нестабильность палитры; арифметическое построение атрибутов для UI поэтому по-прежнему запрещено. Прежняя гипотеза о пропадающих цветных строках была вызвана неверным предпросмотром PNG. Проверка декодированных файлов показала, что именованные цветные кадры P1 и три диагностических кадра P2.1 пиксельно идентичны. P2.2 отдельно проверил шесть цветовых атрибутов: - сохранены все 24 исходные записи (6 атрибутов × 4 плана); - установлены одинаковые normal/FLASH-пары; - обратное чтение дало `PASS (0 mismatches)`; - пять временных кадров имеют одинаковый viewport Sprinter; - перед выходом исходные записи восстановлены. Единственное изменение между двумя полными PNG находилось в служебной панели MAME: 42 пикселя LED `Drive A`. Элементы layout вне viewport Sprinter в экранных сравнениях не учитываются. Подробности — в [результатах P2.2](p2-palette-results.md). ## 6. Интерфейс backend Минимальный интерфейс не раскрывает ESTEX/BIOS остальным модулям: ```c int sc_video_init(void); void sc_video_shutdown(void); int sc_video_present_full(uint8_t emm_page); int sc_video_present_rect(uint8_t emm_page, uint16_t offset, uint8_t row, uint8_t col, uint8_t height, uint8_t width); int sc_video_scroll_rect(uint8_t row, uint8_t col, uint8_t height, uint8_t width, int8_t delta); ``` `sc_screen` строит `(char, attr)` в EMM и вызывает backend. Он не вызывает `WIN_OPEN`, `WRCHAR`, `WINREST` или BIOS непосредственно. Единственная реализация PoC — `sc_video_system.c`; выбор конкретного системного примитива остаётся внутри неё. ## 7. Вертикальный текстовый scroll `mdview2` использует эффективную схему для перемещения на одну строку: ```text Down: scroll(rect, UP) → нарисовать новую нижнюю строку Up: scroll(rect, DOWN) → нарисовать новую верхнюю строку PgUp/PgDn/Home/End → полный redraw области ``` Его viewport — `(col=0, row=1, width=80, height=30)`. Вызов libc `scroll()` обращается к ESTEX `SCROLL 55h`, который сдвигает прямоугольник активной screen page на одну строку. Он не использует идентификатор окна BIOS и совместим с решением не применять window descriptors. Исходники `mdview2` и контракт ESTEX не доказывают, что операция реализована аппаратным регистром видеоконтроллера: для документации это **системный прямоугольный scroll**, пока не появится измерение или исходник DSS. Возможный глобальный аппаратный сдвиг начала экрана для Commander всё равно неудобен — он одновременно сдвинет рамки и обе панели. Реализация `sc_video_scroll_rect()` делегирует прямоугольник ESTEX; это не создаёт зависимости от BIOS-окон. Для Commander эта оптимизация применяется только когда `top` панели изменился ровно на один. Прямоугольники — внутренности панелей без рамок: ```text left: col=1, row=1, width=38, height=27 right: col=41, row=1, width=38, height=27 ``` Точные размеры уточняются renderer-геометрией, но центральный разделитель, заголовок, footer и пассивная панель не должны входить в scroll rectangle. Экранный EMM-буфер остаётся источником истины. Поэтому `sc_screen_scroll_rows()` сначала сдвигает соответствующие `(char, attr)` в модели и строит открытую строку, затем вызывает `sc_video_scroll_rect()` и выводит эту строку. Системный scroll без синхронизации модели запрещён: после диалога или EXEC полный redraw иначе вернул бы старые строки. Fallback при любой неопределённости — present всех 27 строк активной панели. P2.1 должен проверить четыре границы прямоугольника, оба направления, верх и низ списка, 1000 последовательных scroll и неизменность соседней панели. ## 8. Псевдографика и CP866 `mdview2` подтверждает стандартный light box-drawing набор CP866/CP437: | Имя | Код | Глиф | Имя | Код | Глиф | |---|---:|:---:|---|---:|:---:| | `SC_G_H` | `C4` | ─ | `SC_G_V` | `B3` | │ | | `SC_G_TL` | `DA` | ┌ | `SC_G_TR` | `BF` | ┐ | | `SC_G_BL` | `C0` | └ | `SC_G_BR` | `D9` | ┘ | | `SC_G_TM` | `C2` | ┬ | `SC_G_BM` | `C1` | ┴ | | `SC_G_ML` | `C3` | ├ | `SC_G_MR` | `B4` | ┤ | | `SC_G_X` | `C5` | ┼ | | | | Стрелки для подсказок, если понадобятся: Up=`18`, Down=`19`, Right=`1A`, Left=`1B`. Это управляющий диапазон ASCII, поэтому такие байты нельзя передавать через API, интерпретирующий CR/LF/BEL/Esc. Они кладутся как raw glyph непосредственно в `ScCell`. Правила Commander: - все коды сосредоточены в `sc_glyphs.h`, чисел `0xB3` по renderer-модулям быть не должно; - исходная рамка строится из глифов, а не из UTF-8-литералов; - строки UI хранятся в CP866 или проходят явную build-time конвертацию; - border test рисует все 11 соединений и четыре стрелки; - атрибут каждого глифа задаётся через `COLOR(fg, bg)`; - при координатном raw-выводе символы `<0x20` считаются глифами, а не командами. Для PoC достаточно одинарных рамок. Двойные рамки VC-класса добавляются после проверки полного набора соединений, чтобы не смешивать несовместимые single/double junctions. Расширенный набор, уже подтверждённый таблицей конвертации `mdview2`, можно зарезервировать для прогресса, отметок и будущих тем: | Имя | Код | Глиф | Назначение | |---|---:|:---:|---| | `SC_G_SHADE_LIGHT` | `B0` | ░ | светлая заливка | | `SC_G_SHADE_MEDIUM` | `B1` | ▒ | средняя заливка | | `SC_G_SHADE_DARK` | `B2` | ▓ | тёмная заливка | | `SC_G_BLOCK` | `DB` | █ | полный блок | | `SC_G_HALF_UP` | `DF` | ▀ | верхняя половина | | `SC_G_HALF_DOWN` | `DC` | ▄ | нижняя половина | | `SC_G_HALF_LEFT` | `DD` | ▌ | левая половина | | `SC_G_HALF_RIGHT` | `DE` | ▐ | правая половина | | `SC_G_BULLET` | `F9` | ∙ | маркер | | `SC_G_CHECK` | `FB` | √ | отметка | | `SC_G_SQUARE` | `FE` | ■ | квадрат | `mdview2_help.c` рисует рамку этими кодами через `wrchar()` и BIOS fill- функции. Commander заимствует таблицу глифов и геометрию, но обращается к ним только через `ScCell`/`sc_video`: текущий cursor/place не становится частью модели интерфейса. ## 9. Coordinate-screen probe P2.1 Отдельный `tests/p2_screen/p2screen.exe` выполнен в MAME 0.287 / BIOS 3.06: 1. Режим 80x32 и одна EMM-страница экранной модели — `PASS`. 2. Полный экран одним `WINREST` с полной сверкой через `RDCHAR` — `PASS`. 3. Прямоугольник 20x2 из offset `0x2000` — `PASS`. 4. Две рамки и таблица CP866-глифов — `PASS` визуально и по `RDCHAR`. 5. Левая панель вверх и правая панель вниз — `PASS`; рамки и соседние клетки совпали с моделью. 6. Синхронизация EMM-модели после системного `SCROLL` — `PASS`. 7. 1000 чередующихся однострочных scroll с итоговой полной сверкой — `PASS`. 8. Сохранение W3 вокруг `WINREST`, `RDCHAR` и `SCROLL` — `PASS`. 9. Один системный атрибут стабилен в трёх временных фазах — `PASS`, кадры пиксельно идентичны. 10. Шесть атрибутов и четыре палитровых плана — `PASS` отдельной пробой P2.2. Остались отдельные проверки, не нужные для начала skeleton: 11. Повторить полную инициализацию после child, изменившего видеорежим. 12. Сравнить время полного, однострочного и scroll-вывода. 13. Повторить принятый сценарий на реальном Sprinter. Подробные значения и кадры приведены в [результатах P2.1](p2-screen-probe-results.md). ## 10. Критерий выбора Системный backend принят для реализации skeleton по результату MAME, потому что: - совпадает с EMM-моделью по символам и атрибутам; - изолирует палитру в модуле темы и сохраняет отображение W3; - частичное обновление не затрагивает соседние клетки; - scroll прямоугольника не двигает рамку и пассивную панель; - все псевдографические соединения совпадают с CP866; - базовый системный атрибут стабилен во времени; - код не обращается к `RGADR`, `RGMOD` и VRAM-банкам напрямую. До аппаратного принятия backend остаются прогон на реальном Sprinter и повторная инициализация после EXEC. Многоцветность подтверждена отдельным критерием P2.2 и не выводится из результата P2.1.