Files
Sprinter-SDCC/applications/Volkov/docs/commander-architecture.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

40 KiB
Raw Blame History

Sprinter Commander: архитектура

Статус: P1/P2 подтверждены; одностраничная модель панели P3 реализована, проходит граничные проверки DSS

Связанные документы: требования, клавиши и команды, план разработки, платформенные пробы P1, экранный backend P2, результаты P2.1, результаты skeleton P2

1. Цели архитектуры

Архитектура должна позволить получить небольшой технический PoC, не создавая тупиков для полной версии. Главные ограничения задаются не исходным VC, а платформой Sprinter:

  • Z80 имеет 64-КБ адресное пространство;
  • W0 занят DSS/BIOS;
  • стек обязан находиться в W2;
  • полный список двух панелей не помещается вместе с кодом в near-память;
  • код полной версии потребует банков;
  • DSS имеет критический предел в восемь открытых файлов;
  • текстовый экран удобно восстанавливать непосредственно из EMM-страницы.

2. Принятые архитектурные решения

ADR-001. Новая реализация, а не перенос

Commander пишется на C для SDCC. VC 4.05/4.99 используются как описание поведения и состава функций, Dos Navigator — как источник архитектурных идей. Зависимости от DOS interrupt API, сегментной модели x86, PSP, DTA, TSR, overlays, XMS и EMS в код проекта не переносятся.

ADR-002. Лёгкий цикл событий вместо оконного framework

Приложение имеет один цикл событий, набор символьных команд и явное состояние экрана. Иерархия объектов наподобие Turbo Vision не используется.

Причины:

  • меньше резидентного кода и данных;
  • нет виртуальных методов и потоковой сериализации объектов;
  • проще анализировать банковские вызовы;
  • легче гарантировать освобождение ресурсов.

ADR-003. Целевой режим памяти — big

PoC собирается с --memory big --safe:

  • W0 0x00000x3FFF — DSS/BIOS;
  • W1 0x40000x7FFF — переключаемые банки кода;
  • W2 0x80000xBFFF — HOME, DATA/BSS, heap и стек;
  • W3 0xC0000xFFFF — EMM-страницы данных.

Если первоначальный skeleton временно собирается без банков, это не меняет контрактов модулей. До принятия PoC должна быть проверена именно сборка big.

ADR-004. Панели, экран и рабочая область копирования хранятся в EMM

Начиная с P4 PoC выделяет один блок из четырёх последовательных 16-КБ страниц. P2/P3 использовали первые три страницы; четвёртая заранее резервируется текущим ScApp, чтобы копирование не увеличивало W2 и не меняло схему памяти во время операции:

Логическая страница Назначение Использование
0 записи левой панели до 640 ScDirEntry, 1024 байта резерва
1 записи правой панели до 640 ScDirEntry, 1024 байта резерва
2 экранный буфер первые 5120 байт
3 рабочая область copy job первые 4096 байт в PoC

Допускается выделение четырёх отдельных блоков, если эксперимент покажет проблему с последовательным блоком, но внешний интерфейс хранилища от этого не меняется.

ADR-005. Запрещены долгоживущие указатели на W3

Указатель в диапазон 0xC0000xFFFF действителен только внутри функции, которая явно владеет отображением W3. После выхода из неё указатель считается недействительным.

Ни PanelState, ни ScApp, ни длительная операция не содержат near-указатель на содержимое EMM. Они хранят физическую страницу и смещение.

ADR-006. Экран строится как модель ячеек

Каждая экранная ячейка представлена двумя байтами (символ, атрибут). Формат совпадает с подтверждённым форматом ESTEX WINREST:

typedef struct {
    uint8_t ch;
    uint8_t attr;
} ScCell;

Полный экран занимает 80 * 32 * 2 = 5120 байт. Renderer изменяет EMM-буфер, помечает строки грязными, а backend выводит либо диапазон строк, либо весь экран. Backend использует координатные ESTEX/BIOS-функции; основной пакетный путь — проверенный WINREST. Прямой доступ к VRAM не используется.

Renderer использует смысловые роли атрибутов (frame, title, active, passive, error), а не числа палитры. Модуль sc_theme, подтверждённый пробой P2.2, назначает ролям разные атрибуты, сохраняет затрагиваемые записи четырёх планов и восстанавливает их при cleanup. Это не меняет формат ScCell или API renderer. Системные BIOS/ESTEX-вызовы палитры разрешены; запрещён только обход системного экранного API через прямую адресацию VRAM и оконные дескрипторы BIOS.

Дескрипторы BIOS WIN_OPEN/WIN_CLOSE/WIN_*_WIN не используются: BIOS хранит только один описатель окна 0. Слово WIN в ESTEX WINREST означает область экрана и не делает эту функцию частью BIOS window manager.

ADR-007. Источник файлов отделён от панели

Панель не вызывает ffirst/fnext напрямую. Она работает через модуль источника. В PoC реализован только SC_SOURCE_REAL_FS.

Вместо таблицы виртуальных функций используется kind и обычный диспетчер:

typedef enum {
    SC_SOURCE_REAL_FS = 0,
    SC_SOURCE_SEARCH,
    SC_SOURCE_ARCHIVE
} ScSourceKind;

Такой подход не создаёт near/far function pointers и упрощает размещение реализаций по банкам. SEARCH и ARCHIVE до соответствующих этапов должны возвращать внутреннюю ошибку SC_ERR_UNSUPPORTED, которая на границе платформы при необходимости отображается как ESTEX EUNKOP.

ADR-008. Длительные операции являются jobs

Копирование, а позднее удаление, поиск и подсчёт размеров, оформляются как конечные автоматы:

INIT -> PREPARE -> RUN_CHUNK -> PRE_COMMIT -> COMMIT -> DONE
                    |              |           |
                    +-> CANCEL ----+-----------+
                    +-> ERROR -----+-----------+

Один шаг не должен надолго захватывать управление. Между блоками приложение может обновить прогресс и проверить отмену. Даже последний успешно записанный блок завершает только RUN_CHUNK: отдельный вызов переводит job через PRE_COMMIT к атомарному rename. Поэтому Esc, полученный после отображения N/N, всё ещё успевает закрыть и удалить temp до появления целевого файла.

ADR-009. Viewer, editor и setup сначала отдельные программы

Основной Commander отвечает за панели и операции с файлами. Просмотрщик, редактор и настройка первоначально запускаются через EXEC как отдельные .EXE. Это уменьшает HOME, число банков и последствия ошибки компонента.

После 1.0 они могут быть интегрированы банками, если измерения покажут реальную пользу.

3. Слои системы

+------------------------------------------------------+
| app: main loop, mode, active panel, command dispatch |
+----------------------+-------------------------------+
| panels/model         | UI/dialogs/status             |
+----------------------+-------------------------------+
| sources              | renderer/screen buffer        |
+----------------------+-------------------------------+
| jobs: copy/...       | storage: EMM/page access      |
+----------------------+-------------------------------+
| platform: ESTEX, keyboard, exec, screen, filesystem  |
+------------------------------------------------------+
| libc + Sprinter DSS/BIOS                             |
+------------------------------------------------------+

Зависимости направлены вниз. platform не знает о панелях; storage не показывает сообщения; renderer не читает файловую систему.

4. Предлагаемая структура исходников

Makefile
src/
  sprcmd.c              точка входа и аварийная очистка
  sc_app.c              главный цикл и состояние приложения
  sc_command.c          преобразование событий в команды и dispatch
  sc_input.c            клавиатурные события
  sc_screen.c           EMM framebuffer и dirty rows
  sc_video_system.c     координатный вывод ESTEX/BIOS без оконных ID
  sc_draw.c             рамки, строки, числа, сокращение путей
  sc_panel.c            состояние и поведение панели
  sc_panel_draw.c       представление панели
  sc_dir_store.c        записи каталога в EMM
  sc_sort.c             сравнение и сортировка записей
  sc_source.c           диспетчер источников
  sc_source_fs.c        настоящий каталог DSS
  sc_copy_job.c         PoC-копирование одного файла
  sc_copy_ui.c          банковая оркестрация F5 и прогресс
  sc_dialog.c           сообщения и подтверждения
  sc_path.c             безопасная работа с путями 8.3
  sc_error.c            нормализация errno/ESTEX ошибок
  sc_platform_exec.c    ESTEX EXEC/WAIT
  sc_platform_screen.c  wrappers WINREST/WRCHAR/SCROLL и screen mode
include/
  sc_app.h
  sc_command.h
  sc_glyphs.h          raw-коды CP866 для рамок и стрелок
  sc_input.h
  sc_screen.h
  sc_panel.h
  sc_store.h
  sc_source.h
  sc_job.h
  sc_path.h
  sc_platform.h
banks/
  bank1_panel.c         чтение/сортировка/обновление панелей
  bank2_fileops.c       копирование и диалоги операции
tests/
  ...                   target-тесты и данные для MAME
docs/
  ...

Граница файлов может уточняться по карте линковки. Нельзя объединять всё в один большой модуль: SDCC/линкер должны иметь возможность не тянуть лишний код и разнести холодные функции по банкам.

5. Состояние приложения

5.1. ScApp

В W2 хранится единственный объект состояния:

typedef struct {
    ScPanel panels[2];
    uint8_t active_panel;
    uint8_t running;
    uint8_t video_mode_saved;
    uint8_t original_video_mode;
    uint8_t emm_block;
    uint8_t panel_page[2];
    uint8_t screen_page;
    ScJob   job;
    int16_t last_error;
} ScApp;

Фактическое определение может отличаться, но следующие инварианты обязательны:

  • active_panel равен 0 или 1;
  • обе панели ссылаются на разные EMM-страницы;
  • job либо неактивен, либо является единственным владельцем своих fd;
  • номера блоков и страниц обнуляются сразу после освобождения;
  • cleanup можно вызвать после любой частично завершённой стадии init.

5.2. ScPanel

typedef struct {
    char       path[256];
    uint16_t   count;
    uint16_t   cursor;
    uint16_t   top;
    uint32_t   total_size;
    uint8_t    source_kind;
    uint8_t    phys_page;
    uint8_t    truncated;
    uint8_t    dirty;
} ScPanel;

Ограничения:

  • cursor < count, если count != 0;
  • cursor == 0, если count == 0;
  • top <= cursor;
  • видимый курсор лежит в диапазоне top..top+26;
  • count <= 640 для всей линейки 0.1–1.0;
  • path всегда завершён нулём.

6. Хранилище каталогов

Публичный интерфейс не возвращает указатель в W3:

int sc_store_get(const ScPanel *panel, uint16_t index, ScDirEntry *out);
int sc_store_put(ScPanel *panel, uint16_t index, const ScDirEntry *entry);
void sc_store_clear(ScPanel *panel);

Для пакетных операций допускается закрытая функция, которая отображает страницу на короткое время. Она должна:

  1. Сохранить текущую страницу W3.
  2. Подключить страницу панели.
  3. Выполнить только вычисления над памятью.
  4. Не вызывать ESTEX, renderer, банковский dispatch или пользовательский callback.
  5. Восстановить W3 перед возвратом.

Сортировка PoC должна быть нерекурсивной и не использовать callback qsort, чтобы избежать лишнего кода и банковских переходов. Предпочтительный первый вариант — Shell sort над одной отображённой страницей.

7. Чтение настоящего каталога

Последовательность sc_source_fs_scan():

  1. Проверить и нормализовать путь.
  2. Сохранить имя записи под курсором, если панель уже заполнена.
  3. Очистить счётчики панели, но не освобождать её страницу.
  4. При необходимости добавить синтетическую запись ...
  5. Выполнить ffirst("*.*")/fnext с одним общим 256-байтовым near-буфером. Шаблон * запрещён: P1 и P3 подтвердили, что DSS считает его именем без расширения и не возвращает обычные NAME.EXT.
  6. Пропустить . и .. от DSS.
  7. Преобразовать ffblk_t в ScDirEntry и последовательно записать в EMM.
  8. При достижении 640 записей установить truncated и немедленно закончить scan: следующий F_FIRST сам переинициализирует глобальный итератор DSS.
  9. На стабильном DSS 1.71 код 35 означает, что закончилась единственная 16-КБ страница кэша каталога, а не весь каталог. Принять уже прочитанные записи, установить truncated и добавить последней красную виртуальную запись >>> MORE... с флагом SC_ENTRY_DSS_LIMIT. Она занимает один слот, не является файлом и не участвует в файловых операциях.
  10. Отсортировать записи: .., каталоги, файлы, маркер ограничения; внутри обычных групп применить ключ и направление конкретной панели.
  11. Найти прежнее имя и восстановить курсор.
  12. Пометить панель и её экранные строки грязными.

Переборы двух панелей никогда не активны одновременно. ffblk_t не хранится в EMM и не является частью состояния панели. Причина и варианты снятия предела DSS разобраны в dss-large-directories.md.

Флаг SC_ENTRY_SELECTED хранится в самой 24-байтовой EMM-записи и переезжает вместе с ней при сортировке. Резидентная ScPanel содержит только счётчик и 32-битную сумму выбранных обычных файлов. .. и виртуальные маркеры никогда не выбираются; refresh в текущем срезе 0.2 явно сбрасывает выбор и статистику. Одиночный Insert может менять флаг каталога, но все групповые операции +, -, * сначала отбрасывают FA_DIREC и никогда не меняют ранее установленный на каталоге флаг.

Маски +/- используют ASCII case-insensitive matcher с * и ? только для файлов; специальный DOS-шаблон *.* совпадает также с именами файлов без точки. Редактор маски является общей координатной модальной поверхностью в BANK2: он рисует поле в экранной EMM-модели, поддерживает insertion, Backspace, Delete, Left/Right/Home/End и не создаёт BIOS-окно.

F6/F7 используют тот же editor и один validator компонента DOS 8.3. Локальный F6 не передаёт полные пути в DSS RENAME: отдельный банковый helper сохраняет CWD в резидентный scratch, входит в каталог панели, проверяет отсутствие target, вызывает rename(old_basename, new_basename) и восстанавливает CWD. Перезапись существующей записи запрещена до системного вызова.

F8 без выбора удаляет один объект после подтверждения: unlink для файла и rmdir для пустого каталога. Непустой каталог и виртуальная запись не запускают разрушительную операцию. При наличии выбора F8 одним подтверждением сначала удаляет выбранные файлы верхнего уровня, затем обходит все выбранные directory roots общей BFS-очередью, удаляет найденные файлы и выполняет rmdir каталогов обратным проходом. При ошибке или Esc уже выполненные действия не откатываются; CWD и EMM-страница освобождаются.

Групповой F5 проходит EMM-store по индексам и передаёт sc_copy_begin/step только записи с одновременно установленным SC_ENTRY_SELECTED и снятым FA_DIREC. Между файлами долговременный указатель W3 не сохраняется. При ошибке уже committed-файлы остаются, активный temp удаляется прежней job; это первая зафиксированная политика частично успешной группы.

F5 одного текущего каталога использует sc_tree: на время операции он выделяет отдельную EMM-страницу с BFS-очередью до 1008 каталогов. Узел хранит только parent-index, компонент DOS 8.3 и depth; путь восстанавливается перед действием. Первый 256-байтовый диапазон страницы хранит исходный CWD. Глубина ограничена 32, а путь — 255 символами. Файлы по-прежнему проходят через единственную 4-КБ copy-page. Existing target не merge-ится; target внутри source запрещается до создания root. Групповой F5 добавляет все выбранные каталоги верхнего уровня как независимые roots той же очереди после завершения выбранных top-level файлов.

8. Renderer

8.1. Интерфейс

Минимальные операции:

void sc_screen_clear(uint8_t attr);
void sc_screen_cell(uint8_t x, uint8_t y, uint8_t ch, uint8_t attr);
void sc_screen_text(uint8_t x, uint8_t y, const char *s, uint8_t attr,
                    uint8_t max_width);
void sc_screen_fill(uint8_t x, uint8_t y, uint8_t width,
                    uint8_t ch, uint8_t attr);
int  sc_screen_scroll_rows(uint8_t x, uint8_t y, uint8_t width,
                           uint8_t height, int8_t delta);
void sc_screen_mark_rows(uint8_t first, uint8_t count);
int  sc_screen_flush(void);

Экранный буфер — источник истины. Диалог рисуется в тот же буфер поверх панелей. Для PoC допустима перерисовка панелей после закрытия диалога вместо отдельного стека сохранённых окон.

8.2. Обновление

  • Dirty mask занимает 32 бита в W2.
  • Изменение курсора помечает старую и новую строку.
  • Прокрутка панели помечает строки 1–27 её половины экрана.
  • При изменении top ровно на одну строку sc_screen_scroll_rows() сдвигает одновременно EMM-модель и экранный прямоугольник, затем renderer строит только открытую строку. PgUp/PgDn и большой скачок делают полный redraw области панели.
  • Смена каталога перерисовывает соответствующую половину и общие строки 29–31.
  • Полный sc_video_present_full() используется после запуска, возврата из .EXE и крупных изменений.
  • sc_video_present_rect() группирует соседние грязные строки.

App-local WINREST wrapper проверен P1-пробой Commander: полный экран 80x32 и окно 20x2 из offset 0x2000 восстановились корректно. P2.1 затем подтвердил полную сверку через RDCHAR, оба направления прямоугольного scroll и 1000 операций. Координатный backend принят как основной пакетный способ вывода; ограничения и артефакты описаны в результатах P2.1.

9. Ввод и команды

sc_input.c преобразует getkey() и kbd_mod_state() в ScKeyEvent:

typedef struct {
    uint8_t ascii;
    uint8_t scan;
    uint8_t modifiers;
} ScKeyEvent;

Модификаторы хранят только Shift, Ctrl и Alt; состояния CapsLock, NumLock и Rus/Lat не участвуют в выборе команды.

P1 установил особенность DSS: при модифицированной клавише бит 7 raw scan-кода установлен. Например, Ctrl+R даёт 93, Ctrl+PgUp — D9, Alt+F1 — BB. sc_input нормализует их в 13, 59, 3B через scan & 0x7F, но только после чтения compact modifiers. Таблица команд никогда не содержит raw-коды с битом 7.

sc_command.c превращает событие в ScCommand. Остальные модули не должны сравнивать scan-коды непосредственно. Команды описаны в commander-keymap.md.

В MAME kbd_mod_state() в момент возврата getkey() сохранил активный модификатор: compact Ctrl=02, Alt=04, Shift=01. Для переносимости управляющие ASCII-коды (Ctrl+R и подобные) всё равно имеют явные алиасы, не зависящие от live-состояния.

10. Копирование как конечный автомат

Состояния PoC:

IDLE
  -> VALIDATE
  -> CREATE_TEMP
  -> OPEN_SOURCE
  -> COPY_CHUNK <----+
  -> CLOSE_FILES     |
  -> RENAME_TEMP     |
  -> REFRESH          |
  -> DONE             |
                      |
COPY_CHUNK -----------+  пока done < total
  |-> CANCEL -> CLEANUP -> DONE
  +-> ERROR  -> CLEANUP -> DONE

Правила:

  • конечное имя проверяется до создания temp;
  • temp создаётся в целевом каталоге с O_CREAT|O_EXCL;
  • имя temp имеет форму ~SCxxxx.TMP и перебирается с ограниченным числом попыток;
  • рабочая область находится в отдельной EMM-странице и временно отображается в W3; 4-КБ массива в W2 и изменяемого буфера в банке кода нет;
  • начальный логический размер блока — 4096 байт, чтобы между блоками часто обновлять прогресс и проверять отмену; после измерений он может быть увеличен вплоть до размера страницы;
  • чтение выполняется существующим bank_read_page() прямо из открытого fd в страницу; для записи нужен симметричный bank_write_page(), который сохраняет и восстанавливает отображение W3;
  • открыто не более двух fd;
  • успешность write() определяется его библиотечным контрактом, а не сырым DE ESTEX;
  • при short write оставшаяся часть блока дописывается или операция завершается ошибкой;
  • после успешного закрытия temp конечное имя проверяется повторно, и только затем temp переименовывается в него;
  • FAT date/time задаются temp через PUT_D_T перед close; после rename конечное имя получает исходные R/H/S/A через ATTRIB;
  • ошибка после rename помечается как ошибка финализации уже committed-файла, а не как полное отсутствие результата;
  • любое завершение проходит через единый cleanup;
  • после успеха перечитывается пассивная панель.

P19 добавляет policy существующего файла. Safe overwrite сначала переводит старый target в уникальный ~SBxxxx.BAK, затем commit-ит temp. При отказе второго rename backup возвращается на место вместе с исходными атрибутами; после успешных метаданных нового target backup удаляется. overwrite all и skip all — локальное состояние одного F5. Readonly не наследует молча overwrite all, а повторно показывает choice-dialog.

Для версии 0.2 этот автомат расширяется очередью файлов, обходом каталогов, политиками overwrite/skip/rename и сохранением метаданных.

11. Запуск дочерней программы

Последовательность:

  1. Завершить или запретить активный job.
  2. Сформировать проверенный абсолютный путь .EXE.
  3. Запомнить активную панель, курсоры и ожидаемый CWD; временно сделать путь активной панели текущим каталогом child.
  4. Выполнить синхронный ESTEX EXEC с B=1 и сразу сохранить его результат до других вызовов libc.
  5. Восстановить ожидаемые диск и CWD.
  6. Повторно установить текстовый режим 80x32 и палитру Commander, не меняя сохранённую палитру для финального shutdown.
  7. Перечитать обе панели: внешняя программа потенциально могла изменить оба их каталога.
  8. Полностью вывести экран из screen page.
  9. При ошибке показать её штатной строкой состояния Commander.

P1 подтвердил контракт wrapper: C-сигнатура p1_exec(uint8_t path_mode, const char *path) получает mode в A и path в DE, затем перекладывает их в B и HL для ESTEX. B=0 с коротким именем и B=1 с явным относительным путём работают; probe получил 0x5A. В Commander низкоуровневый sc_platform_exec(path) фиксирует B=1, принимает путь в HL по __sdcccall(1) и возвращает код завершения как int в DE.

11.1. Командная строка и Ctrl+O в 1.0

В VC 4.05/4.99 Ctrl+O переключает панели и user screen, а редактор DosBuf работает вместе с prompt и историей. Dos Navigator дополнительно показывает самостоятельный TCommandLine с горизонтальной прокруткой и историей. На Sprinter родительская DSS-shell приостановлена, поэтому её нельзя превратить в интерактивный фон простым скрытием панелей.

Поэтому 1.0 использует собственный pseudo-shell:

  • однострочный prompt на экране панелей и полноэкранный режим делят один редактор, историю и модель текущего каталога;
  • Ctrl+O переключает режимы; возврат к панелям полностью строит их из ScPanel, поэтому отдельная копия экрана панелей не нужна;
  • builtin-команды минимум cd, смена диска, dir, cls, pwd, help;
  • внешняя команда запускается через подтверждённый ESTEX EXEC; после возврата pseudo-shell восстанавливает видеорежим, CWD и свою экранную модель;
  • вывод и скролл идут через тот же безоконный screen backend; прямой VRAM и BIOS window manager не используются;
  • полноэкранные ячейки могут повторно использовать текущую screen page. До фиксации поведения внешнего .EXE отдельной пробой проверяется WINCOPY.

12. Ошибки и владение ресурсами

Низкий уровень возвращает 0/-1 и устанавливает errno. UI не анализирует Carry Flag или регистры DSS.

Каждый ресурс имеет одного владельца:

Ресурс Владелец
общий EMM-блок PoC ScApp
физическая страница панели ScPanel, без права освобождения блока
экранная страница sc_screen, без права освобождения блока
рабочая страница копирования ScApp/copy job, без права освобождения блока
fd источника и temp активный ScCopyJob
исходный видеорежим ScApp
временно отображённая W3 текущая функция storage/screen

Cleanup выполняется в обратном порядке инициализации. Нельзя прятать владение fd или EMM-блоком в локальном static-состоянии модуля.

13. Предварительная карта кода

HOME/W2 содержит только постоянно необходимое:

  • crt0, банковские трамплины и используемую libc;
  • init/cleanup;
  • главный цикл;
  • ввод и базовый dispatch;
  • EMM accessors;
  • screen flush;
  • критическую обработку ошибок.

Предварительные банки:

Банк PoC Полная версия
1 panel scan, sort, redraw model панели, сортировки, режимы панели
2 copy job, operation dialog копирование/перемещение/удаление
3 не нужен меню, конфигурация, история
4 не нужен поиск и дерево
5 не нужен архивные/виртуальные источники

Номер банка является деталью сборки, а не публичным ABI. Банковские модули не должны хранить долгоживущие payload-данные в локальном сегменте банка. Краткоживущий ffblk_t является обычным near-буфером; закреплять его в хвосте W1 бессмысленно, поскольку граница больших каталогов находится внутри DSS.

После каждой сборки проверяются:

  • размер HOME вместе с DATA/BSS и heap;
  • запас каждого банка до 16 КБ;
  • отсутствие прямых вызовов в чужой банк;
  • расположение трамплинов;
  • стек W2 при всех вызовах ESTEX.

14. Эволюция после PoC

Версия 0.2

  • одностраничное хранилище остаётся ограничено 640 записями;
  • выбранные файлы и маски;
  • очередь операций;
  • рекурсивный обход;
  • local rename, mkdir, recursive group copy/delete выполнены; group move и защитная policy остаются;
  • транзакционная перезапись файлов и conflict-policy выполнены; directory merge и delete/move policy остаются;
  • атрибуты и время обычных файлов выполнены; метаданные каталогов — позже.

Версия 0.4

  • командная строка, история и полноэкранный pseudo-shell по Ctrl+O;
  • associations/user menu;
  • внешний viewer/editor/setup;
  • конфигурационный файл;
  • переключение дисков.

Версия 0.6

  • quick view и info source;
  • дерево и поиск;
  • фильтры и сравнение каталогов;
  • подсчёт размеров каталогов;
  • описания файлов.

Версия 0.8+

  • SC_SOURCE_SEARCH как виртуальная панель;
  • SC_SOURCE_ARCHIVE;
  • протокол внешних helper-программ;
  • мышь, помощь, локализация;
  • измеренная оптимизация кэшей и renderer.

Версия 2.0+

  • динамическое выделение EMM-страниц панели;
  • предел 1024/2048 или отсутствие продуктового предела после измерений;
  • межстраничная сортировка без полной копии каталога в W2;
  • деградация при нехватке EMM и тесты частично выделенных цепочек страниц.

15. Архитектурные запреты

  • Нельзя вызывать DSS при стеке вне W2.
  • Нельзя держать одновременно восемь файловых дескрипторов.
  • Нельзя сохранять W3 pointer в состоянии приложения.
  • Нельзя менять W1 вручную из банковской функции.
  • Нельзя вызывать чужой код при оставленной временной странице W3.
  • Нельзя выполнять разрушительную операцию без известного cleanup-path.
  • Нельзя смешивать вывод через printf с экранной моделью во время работы UI.
  • Нельзя добавлять функцию DN только потому, что она присутствует в DN; каждая функция должна соответствовать roadmap Commander.