# Wild Commander — Обзор Системы Плагинов > Версия документа: 2.0 — дополнена по результатам анализа исходников > Источники: `inc/wc_api.h`, `asm/wc_api.s`, `asm/crt0.s`, `DiskRef/Help.txt`, `DiskRef/WC_History.txt` ## Введение Wild Commander (WC) — файловый менеджер с системой плагинов для платформы **TS-Configuration** (ZX Spectrum Evo). Выполняет роль основной оболочки и загрузчика для работы с FAT32-дисками, SD-картами и IDE. WC запускается из BootROM / vDOS и предоставляет: - Двухпанельный интерфейс (80 × 25/30/36 TXT-режим) - FAT32 (длинные и короткие имена до 255 символов) - Систему плагинов (.WMF) с горячей загрузкой/выгрузкой - Поддержку устройств: SD (Z-Controller), IDE NEMO, IDE SMUC, NeoGS SD - Встроенный просмотрщик (F3): TXT, HEX, TGA, SCR, Gigascreen, MGS — до 1 МБ - Мультиязычность (ENG / RUS, переключение CTRL+SHIFT) ### Версии | Компонент | Версия | Примечание | |-----------|--------|------------| | WC | 1.10 (03.08.2025) | Последняя из `WC_History.txt` | | Plugin System | **#10** | Формат заголовка `.WMF` | | Идентификатор | `WildCommanderMDL` | 16 байт, offset +16 в заголовке | ## Общая концепция Плагины WC (.WMF файлы) — модульные расширения, выполняемые в адресном пространстве Z80. Поддерживают до **64 страниц** (1 МБ) кода/данных. Типичные области применения: - Просмотр файлов различных форматов (BMP, GIF, ILBM, SCR) - Воспроизведение музыки и видео (VGM, MOD, WAV, MP3/GS) - Редактирование файлов (TXT Editor с подсветкой синтаксиса) - Работа с ROM/Flash (ROM_PROG) - Монтирование образов дисков (MOUNTER: TRD, TAP, FDI) - Утилиты (часы, скринсейвер, компилятор, дамп памяти) ## Типы запуска плагинов При запуске плагина, в регистр **A** передается тип вызова: | Код | Константа (C) | Описание | |-----|---------------|----------| | #00 | `WC_PCOND_EXT_ONLY` | По расширению файла (ENTER / F3) | | #01 | `WC_PCOND_ON_LOAD` | При первой загрузке плагина (ENTER) | | #02 | `WC_PCOND_TIMER` | По таймеру скринсейвера + меню F10 | | #03 | `WC_PCOND_F10` | Из меню запуска плагинов (F10) | | #04 | `WC_PCOND_VIEWER` | Из меню вьювера (SHIFT+F3 / SHIFT+ENTER) | | #05 | `WC_PCOND_F10_VIEW` | F10 + SHIFT+F3 | | #11 | `WC_PCOND_F10_F2` | F10 + F2 | | #12 | `WC_PCOND_F2` | По нажатию F2 | | #13 | `WC_PCOND_F10_F4` | F10 + F4 | | #14 | `WC_PCOND_F4` | По нажатию F4 | | #15 | `WC_PCOND_F10_V_F4` | F10 + SHIFT+F3 + F4 | > **Примечание:** Все плагины также вызываются по расширению, если расширения > указаны в блоке расширений заголовка (offset +64). ENTER и F3 разделены > начиная с WC v1.00 — флаг +63 определяет, какой из них запускает плагин. ## Входные параметры при запуске WC делает `CALL #8000`. В `crt0.s` (SDCC) входные регистры сохраняются в глобальные переменные автоматически. ```asm ; Входные параметры: A - тип вызова (см. таблицу выше) [DE,HL] - длина файла в байтах (DE=hi16, HL=lo16) BC - адрес строки с именем файла (для типов #00, #04, #14) формат: name(1-255), 0 (длинное FAT имя) IX - адрес структуры активной панели ; Альтернативные регистры (только для #00,#04,#12,#14): A' - номер расширения (0-31) для типа #00 DE' - количество файлов/каталогов в панели (включая "..") HL' - номер объекта из панели (от 1) ``` В SDCC-плагине (`crt0.s` автоматически): ```c extern uint8_t wc_file_ext; // ← A' (номер расширения) extern char * wc_file_name; // ← BC (указатель на имя) extern uint32_t wc_file_size; // ← [DE,HL] (32-бит размер) ``` ## Коды возврата из плагина При выходе из плагина регистр **A** определяет действие WC: | A | Константа (C) | Действие | |---|---------------|----------| | 0 | `WC_EXIT_ESC` | Просто выход (ESC) | | 1 | `WC_EXIT_UNRECOGNIZED` | Файл не опознан → передать другому плагину (тип #00) | | 2 | `WC_EXIT_NEXT` | Перейти на следующий файл (тип #00) | | 3 | `WC_EXIT_RELOAD_DIR` | Перечитать каталог | | 4 | `WC_EXIT_PREV` | Перейти на предыдущий файл (тип #00) | В SDCC-плагине: `wc_exit_code = 0; return 0;` — `crt0.s` считывает `wc_exit_code` в A перед `RET` обратно в WC. > **Код 2/4 (NEXT/PREV):** WC вызывает тот же плагин повторно с другим > файлом. `crt0.s` заново обнуляет BSS (`_DATA`) и копирует инициализаторы > (`_INITIALIZER → _INITIALIZED`), поэтому все `static` переменные сбросятся. ## Системные адреса > Источник: `src_sdcc/inc/wc_api.h`, раздел «СИСТЕМНЫЕ ПЕРЕМЕННЫЕ WC» | Адрес | Константа | Размер | Описание | |---------------|--------------|--------|---------------------------------------------------| | `#6000` | `WC_SYS_PG0` | 1 | Текущая страница в окне #0000 | | `#6001` | `WC_SYS_PG4` | 1 | Текущая страница в окне #4000 | | `#6002` | `WC_SYS_PG8` | 1 | Текущая страница в окне #8000 | | `#6003` | `WC_SYS_PGC` | 1 | Текущая страница в окне #C000 | | `#6004` | `WC_SYS_ABT` | 1 | 1 = был нажат ESC | | `#6005` | `WC_SYS_ENT` | 1 | 1 = был нажат ENTER | | `#6006` | `WC_SYS_FUN` | 3 | **Точка входа WC API** (JP к диспетчеру) | | `#6009` | `WC_SYS_TMN` | 2 | Таймер INT (uint16_t, ++/кадр ≈50 Гц) | | `#600B` | `WC_SYS_FEP` | 1 | Страница FAT-движка в окне 0 | | `#600C` | `WC_SYS_XPP` | 1 | Сохранённая страница | | `#600D` | `WC_SYS_CNFV`| 1 | ЦАП: 0=PWM, 1=3bit, 2=4bit, 3=5bit, 7=VDAC2/FT812 | | `#600E` | `WC_SYS_HEI` | 1 | Высота TXT-экрана: 25 / 30 / 36 | | `#600F` | `WC_SYS_TXTMD`| 1 | Текущий видеорежим WC (0=TXT) | | `#6010` | `WC_SYS_INIFLG`| 1 | Флаг загрузки INI-конфигурации | | `#6011` | `WC_SYS_RSQBC`| 2 | RSQ буфер-счётчик | | `#6013` | `WC_SYS_RSQB2`| 2 | RSQ буфер 2 | | `#6015` | `WC_SYS_SDBSF`| 1 | Состояние SD1 драйвера | | `#6016` | `WC_SYS_SDBSF2`| 1 | Состояние SD2 драйвера | | `#6017` | `WC_SYS_F3ENTFL`| 1 | Флаг F3/ENTER для файловых операций | | `#6018` | `WC_SYS_FEP2`| 2 | FAT engine page extra | | `#6020` | `WC_SYS_PLRESAD`| 8 | Резидент перехода: A=страница, HL=адрес → JP(HL) | | `#6028` | `WC_SYS_PLRESCALL`| 8 | Резидент вызова: A=страница, HL=адрес → CALL(HL) | | `#8000` | — | — | **Точка входа плагина** (WC делает CALL #8000) | Чтение из C: ```c #define WC_SYS_ABT (*(volatile uint8_t*)0x6004) #define WC_SYS_TMN (*(volatile uint16_t*)0x6009) #define WC_SYS_HEI (*(volatile uint8_t*)0x600E) // Или через макросы wc_api.h: uint8_t h = wc_get_height(); // 25/30/36 uint16_t t = wc_get_timer(); // кадровый счётчик uint8_t esc = wc_get_abt(); // 1 = ESC нажат ``` ## Вызов API функций Все функции WC вызываются через точку доступа #6006: ```asm WLD EQU #6006 ; Пример вызова функции PRWOW (вывод окна) PRWOW LD A,1 JP WLD ; Пример вызова ESC (проверка нажатия ESC) ESC LD A,#17 JP WLD ``` **Регистровые соглашения WC API:** - Вход: **A** = номер функции, остальные параметры в регистрах (см. справочник) - Некоторые функции используют **A'** (альтернативный A через `EX AF,AF'`) - **Портит**: AF, BC, DE, HL, IX - **Сохраняет**: IY, AF', BC', DE', HL', SP > ⚠️ **IX сохраняется** диспетчером P8000, но **AF, BC, DE, HL портятся** > при каждом вызове `CALL #6006`. --- ## Карта памяти (физические страницы) > Источник: `wc_api.h` — полная таблица `WC_PAGE_*` | Страницы | Константа | Назначение | |----------|-----------|------------| | `#00` | `WC_PAGE_MTXPG` | Основной текстовый экран (TXT) | | `#01` | `WC_PAGE_FONT0` | Шрифт основного TXT + Hrust/MegaLZ | | `#02` | `WC_PAGE_CODE` | Код WC (ядро) | | `#05` | `WC_PAGE_FAT_ENGINE` | FAT движок + стек + данные | | `#08` | `WC_PAGE_BUFPG` | 2-й текстовый экран / буфер | | `#09` | `WC_PAGE_FONT1` | Шрифт для 2-го TXT | | `#0B–#13` | `WC_PAGE_CAT_LEFT` | Каталог левой панели (9 стр.) | | `#14–#1C` | `WC_PAGE_CAT_RIGHT` | Каталог правой панели (9 стр.) | | `#1D` | `WC_PAGE_RESB` | Буфер сохранения окон (RESB) | | `#1E` | `WC_PAGE_CPPG1` | Позиции левой панели | | `#1F` | `WC_PAGE_CPPG2` | Позиции правой панели | | **#20–#5F** | **`WC_PAGE_TVBPG`** | **Мегабуфер (64 стр. = 1 МБ)**, он же видео: | | `#20–#2F` | `WC_PAGE_GV1` | — видеобуфер 1 (16 стр.) | | `#30–#3F` | `WC_PAGE_GV2` | — видеобуфер 2 | | `#40–#4F` | `WC_PAGE_GV3` | — видеобуфер 3 | | `#50–#5F` | `WC_PAGE_GV4` | — видеобуфер 4 | | `#60` | `WC_PAGE_PLHPG` | Заголовки плагинов | | **#61–#A0** | **`WC_PAGE_PLGPG`** | **Код/данные плагинов (до 64 стр.)** | | `#A1–#BF` | `WC_PAGE_TAP_START` | TAP-область (31 стр. = 496 КБ) | | `#C0–#E7` | `WC_PAGE_VDOS_RAM` | vDOS RAM-диск (40 стр. = 640 КБ) | | `#E8–#EF` | `WC_PAGE_VDOS_FREE` | Свободные страницы | | `#F0` | `WC_PAGE_PNLPG` | Поток левой панели | | `#F1` | `WC_PAGE_PNL_RIGHT` | Поток правой панели | | `#F2` | `WC_PAGE_INIPG` | INI-поток (плагин #00) | | `#F3` | `WC_PAGE_STRPG` | Поток плагина #01 | | `#F4–#F7` | — | SPG loader, boot pages (5,2), panel paths | | `#F8–#FB` | `WC_PAGE_VROM_START` | Виртуальный ROM (4 стр.) | | `#FC–#FF` | — | vDOS: таблицы, драйверы, трапы | > **Плагин видит:** свои заказанные страницы (0..N) через `wc_mngc_pl()` / > `wc_mng0_pl()` / `wc_mng8_pl()`. Физическая нумерация скрыта — WC > маппит логическую страницу N плагина в `WC_PAGE_PLGPG + N`. --- ## Поддерживаемые устройства хранения | Код | Константа | Устройство | |-----|-----------|------------| | 0 | `WC_DEV_SD_ZC` | SD-карта (Z-Controller) | | 1 | `WC_DEV_IDE_NEMO_M` | IDE Nemo — Master | | 2 | `WC_DEV_IDE_NEMO_S` | IDE Nemo — Slave | | 3 | `WC_DEV_SD_NGS` | SD-карта (NeoGS) | | 4 | `WC_DEV_IDE_SMUC_M` | IDE SMUC — Master | | 5 | `WC_DEV_IDE_SMUC_S` | IDE SMUC — Slave | | 6 | `WC_DEV_SD2_ZC` | Вторая SD (Z-Controller SD2) | --- ## Работа со страницами памяти ### Логическая нумерация Плагин запрашивает N страниц в заголовке (offset +34). WC выделяет их из пула `#61–#A0`. Плагин обращается по **логическому** номеру 0..N−1. ### Окна CPU и функции маппинга | Окно | Адреса | Функция ASM | Функция C | Примечание | |------|--------|-------------|-----------|------------| | Win 0 | `#0000–#3FFF` | `MNG0_PL` (#4E) | `wc_mng0_pl(page)` | ⚠ Данные для WC API нельзя класть сюда | | Win 2 | `#8000–#BFFF` | `MNG8_PL` (#4F) | `wc_mng8_pl(page)` | Код плагина — обычно стартовая страница | | Win 3 | `#C000–#FFFF` | `MNGC_PL` (#00) | `wc_mngc_pl(page)` | ⚠ Сбрасывается после КАЖДОГО вызова WC API | Специальные значения для `MNGC_PL`: - `#FF` — шрифтовая страница (нельзя писать в `#E000–#FFFF`!) - `#FE` — первый текстовый экран (с панелями WC) ### Резидент перехода (#6020) Переключает страницу плагина и делает **безвозвратный** JP: ```c // C: никогда не вернётся в вызывающий код void wc_resident_jump(uint8_t page, uint16_t addr); ``` ```asm ; ASM: A = страница (0..N-1), HL = адрес (#8000–#BFFF) LD A,1 LD HL,#8000 CALL #6020 ; → WC переключает Win2 на стр.1, JP (HL) ``` ### Резидент вызова (#6028) Вызывает код в другой странице плагина **с возвратом**: ```c void wc_resident_call(uint8_t page, uint16_t addr); ``` ```asm ; ASM: A = страница, HL = адрес. Сохраняет всё кроме A,HL. LD A,2 LD HL,#A000 CALL #6028 ; → WC переключает, CALL (HL), возвращает стр. назад ``` > Добавлено в WC v1.09 (31.07.2024). До этого многостраничные плагины > требовали прямой OUT в порт Page2 (#12AF). --- ## Важные замечания 1. **При входе в плагин может быть любой экран!** Обязательно вызывайте `GEDPL` (#0F) / `wc_gedpl()` для переключения на текстовый режим. 2. **Вызывать GEDPL лучше после анализа файла**, когда убедились что файл подходит для плагина (и вернули `wc_exit_code = 1` если нет). 3. **Обязательно сохраняйте IX** при входе в плагин, если планируете использовать файловые функции. 4. **⚠ Win3 (#C000) сбрасывается после каждого вызова WC API!** Внутри `CALL #6006` WC переключает окно `#C000` на текстовую страницу и **не восстанавливает** его. Если плагин работал через `mngcvpl()` / `mngc_pl()`, он **обязан** повторить маппинг после любого UI-вызова (`gedpl`, `prwow`, `txtpr`, `rresb`, `load512` и т.д.). 5. **GEDPL затирает #1000–#1447 в окне 0** — нельзя хранить данные в этой области. 6. **Буферы и строки для файловых функций** (`load512`, `fentry`, `findnext`, и т.д.) **обязаны** быть в `#8000–#FFFF`. WC ремапит `#0000–#7FFF` под FAT-движок внутри каждого файлового вызова. 7. **FindNext портит #0000–#1FFF** на странице драйвера — не хранить данные там при итерации по каталогу. 8. **WC API портит регистры:** AF, BC, DE, HL, IX. Сохраняет: IY, AF', BC', DE', HL', SP. Это верно для **всех** функций через `CALL #6006`. 9. **Стек не настраивается** — плагин использует стек WC (в Win 1, `#4000–#7FFF`). Стек WC достаточно глубокий для обычных плагинов, но рекурсия требует осторожности. --- ## Горячие клавиши WC (для пользователя) > Источник: `DiskRef/Help.txt` | Клавиша | Действие | |---------|----------| | ENTER | Войти в каталог / запустить .WMF / просмотреть файл | | F3 | Встроенный просмотрщик (TXT/HEX/TGA/SCR/MGS, до 1 МБ) | | SHIFT+F3/SHIFT+ENTER | Меню выбора вьювера (плагин с `WC_PCOND_VIEWER`) | | F2 | Пользовательское меню (из `wc.mnu`) | | F4 | Редактирование / выбор текстового редактора | | F5 | Копирование отмеченных файлов в другую панель | | F6 | Переименование файла/каталога | | F7 | Создание каталога | | F8 / DEL | Удаление отмеченных файлов | | F9 | Настройки INI (авто-создаёт каталог WC на загрузочном устройстве) | | F10 | Меню запуска/удаления плагинов | | TAB | Переключение между панелями | | SPACE / INSERT | Отметить файл/каталог | | * | Инвертировать выделение | | ALT+F1/F2 | Выбор диска для левой/правой панели | | CTRL+F3 | Сортировка по имени | | CTRL+F4 | Сортировка по расширению | | CTRL+F6 | Сортировка по размеру | | CTRL+R | Обновить каталог | | CTRL+A | Выделить все объекты | | CTRL+SHIFT | Переключение ENG/RUS | --- ## Примеры плагинов В каталоге `DiskRef/WC/` находятся скомпилированные плагины WC: | Файл | Назначение | |------|------------| | `GSPLAYER.WMF` | Плеер для GS (MP3, MOD, WAV) | | `WPLAYER.WMF` | Музыкальный плеер с плейлистами | | `VGMPLAY.WMF` | VGM плеер (OPL3/AY/SAA) — этот проект | | `TXTEDIT.WMF` | Текстовый редактор с подсветкой синтаксиса | | `BMPV.WMF` | Просмотрщик BMP | | `GIFVIEW.WMF` | Просмотрщик GIF | | `ILBMVIEW.WMF` | Просмотрщик IFF/ILBM | | `FTVIEW.WMF` | Просмотрщик FT-шрифтов | | `MOUNTER.WMF` | Монтирование TRD/TAP/FDI образов | | `ROM_PROG.WMF` | Программатор ROM/Flash | | `SCRSAVER.WMF` | Скринсейвер (тип вызова `WC_PCOND_TIMER`) | | `CLOCK.WMF` | Часы | | `SETIME.WMF` | Установка времени | | `COMPILER.WMF` | Компилятор | | `RE.WMF` | Ассемблер/отладчик | --- ## Ссылки на другие разделы документации - [02_Plugin_Header_Structure.md](02_Plugin_Header_Structure.md) — формат 512-байтного заголовка - [03_WC_API_Reference.md](03_WC_API_Reference.md) — полный справочник функций - [04_TSConfig_Platform.md](04_TSConfig_Platform.md) — аппаратная платформа, порты, регистры - [06_Example_Plugin.md](06_Example_Plugin.md) — примеры плагинов на ASM и SDCC C