Files
Sprinter-SDCC/applications/Volkov/docs/p2-screen-backend.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

18 KiB
Raw Blame History

Sprinter Commander: экранный backend P2

Статус: ядро P2.1 и многоцветная тема P2.2 прошли MAME; аппаратная проверка, восстановление после child и измерение времени ожидаются.

Связанные документы: архитектура, требования, roadmap, результаты P1, результаты P2.1, результаты P2.2

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 подтвердили формат логического буфера:

(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.

6. Интерфейс backend

Минимальный интерфейс не раскрывает ESTEX/BIOS остальным модулям:

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 использует эффективную схему для перемещения на одну строку:

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 панели изменился ровно на один. Прямоугольники — внутренности панелей без рамок:

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 с полной сверкой через RDCHARPASS.
  3. Прямоугольник 20x2 из offset 0x2000PASS.
  4. Две рамки и таблица CP866-глифов — PASS визуально и по RDCHAR.
  5. Левая панель вверх и правая панель вниз — PASS; рамки и соседние клетки совпали с моделью.
  6. Синхронизация EMM-модели после системного SCROLLPASS.
  7. 1000 чередующихся однострочных scroll с итоговой полной сверкой — PASS.
  8. Сохранение W3 вокруг WINREST, RDCHAR и SCROLLPASS.
  9. Один системный атрибут стабилен в трёх временных фазах — PASS, кадры пиксельно идентичны.
  10. Шесть атрибутов и четыре палитровых плана — PASS отдельной пробой P2.2.

Остались отдельные проверки, не нужные для начала skeleton:

  1. Повторить полную инициализацию после child, изменившего видеорежим.
  2. Сравнить время полного, однострочного и scroll-вывода.
  3. Повторить принятый сценарий на реальном Sprinter.

Подробные значения и кадры приведены в результатах P2.1.

10. Критерий выбора

Системный backend принят для реализации skeleton по результату MAME, потому что:

  • совпадает с EMM-моделью по символам и атрибутам;
  • изолирует палитру в модуле темы и сохраняет отображение W3;
  • частичное обновление не затрагивает соседние клетки;
  • scroll прямоугольника не двигает рамку и пассивную панель;
  • все псевдографические соединения совпадают с CP866;
  • базовый системный атрибут стабилен во времени;
  • код не обращается к RGADR, RGMOD и VRAM-банкам напрямую.

До аппаратного принятия backend остаются прогон на реальном Sprinter и повторная инициализация после EXEC. Многоцветность подтверждена отдельным критерием P2.2 и не выводится из результата P2.1.