1884 lines
118 KiB
C
1884 lines
118 KiB
C
/**
|
||
* @file wc_api.h
|
||
* @brief Полное API Wild Commander (WC) для SDCC Z80
|
||
* @version 5.0
|
||
*
|
||
* Самодостаточная библиотека: зависит только от types.h.
|
||
* Реализация: asm/wc_api.s (ASM-обёртки вокруг CALL 0x6006).
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* МЕХАНИЗМ ВЫЗОВА
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Единственная точка входа ко всем функциям WC:
|
||
*
|
||
* CALL 0x6006 ; A = номер функции, остальные регистры — аргументы
|
||
*
|
||
* WC минимально гробит: AF, BC, DE, HL, IX (при каждом вызове!)
|
||
* WC сохраняет: IY, AF', BC', DE', HL', SP
|
||
*
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* СОГЛАШЕНИЕ ВЫЗОВА (sdcccall(1), SDCC 4.x)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Первый аргумент: uint8 → A
|
||
* uint16 / ptr → HL (ВАЖНО: именно HL, не DE!)
|
||
* Второй аргумент: uint16 / ptr → DE
|
||
* Остальные: на стек, крайний правый аргумент первым (push)
|
||
* callee обязан очистить стек сам (callee-cleans)
|
||
* Возврат: uint8 → A; uint16 → HL
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* СТАРТОВЫЕ УСЛОВИЯ ПЛАГИНА
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* WC вызывает плагин как CALL #8000. На входе:
|
||
*
|
||
* A = тип вызова:
|
||
* 0x00 — по расширению файла
|
||
* 0x01 — при загрузке плагина (по ENTER)
|
||
* 0x02 — по таймеру скринсейвера / из меню F10
|
||
* 0x03 — из меню запуска плагинов (F10)
|
||
* 0x04 — из меню выбора просмотрщика (Shift+F3 / Shift+Enter)
|
||
* 0x12 — по F2
|
||
* 0x14 — по F4
|
||
* [DE,HL] = размер файла (DE = старший, HL = младший; 32-бит)
|
||
* BC = адрес имени файла: name(1−255), 0x00 (только для 0x00/0x04/0x14)
|
||
* IX = адрес структуры активной панели (нужен для некоторых функций!)
|
||
*
|
||
* Дополнительно для 0x00/0x04/0x12/0x14:
|
||
* A' — номер расширения (0–31), по которому файл передан плагину
|
||
* DE' — количество файлов/каталогов в активной панели (включая "..")
|
||
* HL' — номер объекта из панели (от 1)
|
||
* если HL' == DE', переход на следующий файл не имеет смысла
|
||
*
|
||
* Значение A при выходе из плагина (записывать в wc_exit_code):
|
||
* 0 — выход (ESC)
|
||
* 1 — файл не распознан, передать другому просмотрщику/плагину
|
||
* (только для типа вызова 0x00)
|
||
* 2 — перейти к следующему файлу в каталоге (только 0x00)
|
||
* 3 — перечитать каталог (не для типов 0x01, 0x02)
|
||
* 4 — перейти к предыдущему файлу в каталоге (только 0x00)
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* КАРТА АДРЕСНОГО ПРОСТРАНСТВА CPU (4 окна × 16 КБ)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* TSConfig даёт CPU 64 КБ через 4 переключаемых окна, каждое может
|
||
* отображать любую из 256 физических страниц (по 16 КБ = 4 МБ всего).
|
||
* Текущие номера страниц читаются из #6000–#6003 (WC_SYS_PG0–PGC).
|
||
*
|
||
* Адреса CPU Окно Назначение при работе плагина
|
||
* ─────────────── ────── ──────────────────────────────────────────
|
||
* #0000 – #3FFF Win 0 ★ Плагин может переключать через mng0_pl()
|
||
* По умолчанию: TXT-буфер / системная стр.
|
||
* WC API: сохраняет и восстанавливает при
|
||
* каждом CALL #6006 (P8000 dispatch)
|
||
* ⚠ GEDPL затирает область #1000–#1447!
|
||
* ⚠ Нельзя хранить здесь параметры для WC API
|
||
* (SOW-структуры, строки, буферы файлов),
|
||
* т.к. WC ремапит это окно внутри вызовов.
|
||
* ✓ Можно использовать для своих данных МЕЖДУ
|
||
* вызовами WC (например, VGM-буферы).
|
||
*
|
||
* #4000 – #7FFF Win 1 ✖ СИСТЕМНАЯ ОБЛАСТЬ — НЕ ТРОГАТЬ!
|
||
* Содержит: FAT engine (#4000+), стек WC,
|
||
* ядро WC, точка входа API (#6006).
|
||
* Плагин НЕ имеет права ремапить это окно.
|
||
*
|
||
* #8000 – #BFFF Win 2 ★ КОД И ДАННЫЕ ПЛАГИНА
|
||
* WC загружает сюда .WMF-файл при запуске.
|
||
* Точка входа: CALL #8000.
|
||
* WC API: сохраняет/восстанавливает страницу
|
||
* при каждом вызове P8000.
|
||
* ✓ Структуры SOW, строки для UI-функций,
|
||
* буферы файловых операций — всё здесь.
|
||
* Рекомендуемая раскладка SDCC:
|
||
* #8000–#B7FF CODE (до 14 КБ)
|
||
* #B800–#BFFF DATA (до 2 КБ)
|
||
*
|
||
* #C000 – #FFFF Win 3 ★ Плагин может переключать через mngc_pl()
|
||
* ⚠ WC API СБРАСЫВАЕТ это окно на TXT-стр.
|
||
* (#00) при КАЖДОМ вызове P8000 и
|
||
* НЕ ВОССТАНАВЛИВАЕТ после возврата!
|
||
* → После любого вызова UI-функции (gedpl,
|
||
* prwow, txtpr, rresb...) плагин обязан
|
||
* заново вызвать mngc_pl() если ему нужны
|
||
* свои данные в #C000–#FFFF.
|
||
* ✓ Удобно для загрузки данных:
|
||
* mngcvpl(N) → load512(0xC000, 32)
|
||
* загружает 16 КБ в VPL-страницу N.
|
||
* ✓ Через mng0_pl() потом можно прочитать
|
||
* ту же страницу в #0000–#3FFF.
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* МЕХАНИЗМ P8000 DISPATCH (внутренний CALL #6006)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* При каждом вызове WC API (CALL #6006) происходит:
|
||
*
|
||
* 1. Сохранение текущей страницы Win 0 → переменная PG0BU
|
||
* 2. Сохранение IX → переменная IXBU
|
||
* 3. Установка Win 3 (#C000) = TXT-страница (#00 / MTXPG)
|
||
* 4. Выполнение запрошенной функции WC
|
||
* 5. Восстановление Win 0 из PG0BU
|
||
* 6. Восстановление IX из IXBU
|
||
* 7. RET к плагину
|
||
*
|
||
* Важные следствия:
|
||
* • Win 0: после вызова — та же страница, что была до вызова ✓
|
||
* • Win 3: после вызова — ВСЕГДА TXT-страница (#00) ✗
|
||
* • IX: сохраняется через вызов (но A, BC, DE, HL — портятся!)
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* БУФЕР СОХРАНЕНИЯ ОКОН (RESB — страница #1D)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* WC использует страницу #1D (WC_PAGE_RESB) как стек для сохранения
|
||
* фона под окнами. Размер — 16 КБ, что хватает для нескольких окон.
|
||
*
|
||
* Поле buf_addr в структуре SOW (wc_window_t):
|
||
*
|
||
* 0x0000 → "Автоматическое выделение" — WC при вызове prwow()
|
||
* сохранит фон в RESB-стек и запишет реальный адрес.
|
||
* При rresb() — фон будет корректно восстановлен.
|
||
* ЭТО РЕКОМЕНДУЕМОЕ ЗНАЧЕНИЕ. Все штатные плагины
|
||
* WC (gsplayer, mounter, clock и т.д.) используют 0.
|
||
*
|
||
* 0xFFFF → "Не сохранять фон" — prwow() нарисует окно поверх,
|
||
* но rresb() не сможет восстановить содержимое.
|
||
* Используется только если фон не нужен (fullscreen).
|
||
*
|
||
* иное → ручной адрес буфера (не рекомендуется).
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* GEDPL — ПОВРЕЖДЕНИЕ ОБЛАСТИ #1000–#1447
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Функция wc_gedpl() (восстановление дисплея WC) при работе
|
||
* затирает область #1000–#1447 (1096 байт) в окне 0.
|
||
* Это используется для внутренних буферов восстановления палитры
|
||
* и атрибутов текстового экрана.
|
||
*
|
||
* Последствия для плагина:
|
||
* • Нельзя хранить критичные данные по адресам #1000–#1447
|
||
* • Если плагин использует #0000–#3FFF через mng0_pl(),
|
||
* данные в этом диапазоне будут повреждены после gedpl()
|
||
* • Безопасные области в Win 0: #0000–#0FFF и #1448–#3FFF
|
||
* (но только МЕЖДУ вызовами WC API, не во время!)
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* АДРЕСНЫЕ ОГРАНИЧЕНИЯ ПАРАМЕТРОВ WC API
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Структуры и буферы, передаваемые в функции WC, ОБЯЗАНЫ находиться
|
||
* в определённых адресных диапазонах:
|
||
*
|
||
* Файловые функции (load512, save512, fentry, mkfile, findnext...):
|
||
* Буферы и имена файлов: #8000–#FFFF
|
||
* (WC ремапит Win 0 и Win 1 для FAT — #0000–#7FFF недоступен!)
|
||
*
|
||
* UI функции (prwow, txtpr, rresb, scrlwow, mezz...):
|
||
* Структура SOW: #8000–#BFFF (предпочтительно)
|
||
* Строки текста: #8000–#BFFF
|
||
* (Win 3 сброшен на TXT — #C000+ тоже допустим, но это TXT-стр.)
|
||
*
|
||
* Общее правило: размещайте ВСЕ данные WC API в #8000–#BFFF.
|
||
* Это единственный диапазон, гарантированно стабильный во время
|
||
* и после любых вызовов WC API.
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* МНОГОСТРАНИЧНЫЕ ПЛАГИНЫ (до 64 страниц)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Плагин может занимать до 64 страниц (#61–#A0) в пуле WC.
|
||
* Для переключения между страницами используются резиденты:
|
||
*
|
||
* Резидент перехода (#6020, PLRESAD):
|
||
* A=номер страницы (0=первая), HL=адрес → JP (HL)
|
||
* Точка невозврата: управление передаётся навсегда.
|
||
*
|
||
* Резидент вызова (#6028, PLRESCALL):
|
||
* A=номер страницы, HL=адрес → CALL (HL), затем возврат
|
||
* Сохраняет все регистры кроме A и HL.
|
||
*
|
||
* Функции mng0_pl(page) и mngc_pl(page) принимают ЛОГИЧЕСКИЙ
|
||
* номер страницы (от 0), WC добавляет базу PLGPG (#61) автоматически.
|
||
*
|
||
* Типичная архитектура многостраничного плагина:
|
||
* Стр. 0: код + данные (постоянно в #8000–#BFFF)
|
||
* Стр. 1+: данные, загружаемые в #0000 через mng0_pl()
|
||
* или в #C000 через mngc_pl() / mngcvpl()
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* РЕКОМЕНДУЕМАЯ РАСКЛАДКА ПАМЯТИ SDCC-ПЛАГИНА
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Адреса Содержимое
|
||
* ─────────────── ───────────────────────────────────────────────
|
||
* #0000 – #3FFF VGM/данные через mng0_pl() (только между
|
||
* вызовами WC! GEDPL затирает #1000–#1447)
|
||
* #4000 – #7FFF ✖ WC SYSTEM — не трогать
|
||
* #8000 – #B7FF _CODE: код плагина (до 14 КБ)
|
||
* #B800 – #BFFF _DATA: переменные, SOW, строки (до 2 КБ)
|
||
* #C000 – #FFFF Загрузка данных через mngcvpl()/mngc_pl()
|
||
* (сбрасывается WC после каждого API-вызова!)
|
||
*
|
||
* build.bat: sdcc --code-loc 0x8000 --data-loc 0xB800
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* СИСТЕМНЫЕ ПЕРЕМЕННЫЕ WC (читаются напрямую по фиксированным адресам)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* #6000 [4] — номера страниц в окнах #0000, #4000, #8000, #C000
|
||
* #6004 [1] — ABT: 1 = был нажат ESC
|
||
* #6005 [1] — ENT: 1 = был нажат ENTER
|
||
* #6009 [2] — TMN: таймер INT (uint16_t, инкрементируется каждым INT)
|
||
* #600D [1] — CNFv: тип ЦАП/видео:
|
||
* 0=ШИМ/IDE, 1=3-bit VDAC, 2=4-bit VDAC,
|
||
* 3=5-bit VDAC, 7=VDAC2 (FT812)
|
||
* #600E [1] — HEI: высота текстового экрана в строках (25 / 30 / 36)
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* СТРУКТУРА SOW — Structure Of Window (16 байт)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Поле type (+0):
|
||
* [7] = 1 → тень вокруг окна
|
||
* [6] = 1 → курсор во всю ширину окна
|
||
* [5] = зарезервировано
|
||
* [4] = 1 → шапка-заголовок (инверсная строка вверху)
|
||
* [3:0] = стиль рамки:
|
||
* 0 — без рамки (стандартное окно, рамка 1-го типа)
|
||
* 1 — с заголовками и текстом (рамка 1-го типа, без курсора)
|
||
* 2 — с заголовками и текстом + курсор (рамка 1-го типа)
|
||
* 3 — стандартное окно, рамка 2-го типа
|
||
* 4 — с заголовками и текстом (рамка 2-го типа, без курсора)
|
||
* 5 — с заголовками и текстом + курсор (рамка 2-го типа)
|
||
* 6 — стандартное окно, рамка 3-го типа
|
||
* 7 — с заголовками и текстом (рамка 3-го типа, без курсора)
|
||
* 8 — с заголовками и текстом + курсор (рамка 3-го типа)
|
||
*
|
||
* Примечание: WC заменяет x=255→реальное значение при первом рисовании;
|
||
* аналогично y=255, width=0, height=0.
|
||
*
|
||
* Поле buf_addr (+8): — см. раздел «БУФЕР СОХРАНЕНИЯ ОКОН (RESB)»
|
||
* 0x0000 — авто-выделение в RESB-стеке (РЕКОМЕНДУЕТСЯ!)
|
||
* 0xFFFF — не сохранять фон (нельзя восстановить через rresb)
|
||
* иное — ручной адрес буфера (не рекомендуется)
|
||
*
|
||
* Линии-разделители (+10, +11):
|
||
* Задают Y-смещение от нижнего края окна.
|
||
* Если != 0, WC рисует горизонтальную линию внутри рамки.
|
||
*
|
||
* Поля +12–+15 зависят от стиля (type[3:0]):
|
||
* Стиль 0/3/6 (стандартное окно):
|
||
* +12 — позиция курсора (от 1)
|
||
* +13 — нижний ограничитель курсора
|
||
* +14 — цвет курсора (накладывается по маске cur_mask)
|
||
* +15 — цвет окна под курсором
|
||
* Стиль 1/4/7 (заголовочное окно без курсора):
|
||
* +12,+13 — адрес строки верхнего заголовка (0 = не выводить)
|
||
* +14,+15 — адрес строки нижнего заголовка (0 = не выводить)
|
||
*
|
||
* Адресные ограничения: структура SOW должна находиться в
|
||
* #8000–#BFFF или #0000–#3FFF (недоступна из #C000!).
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* ТЕКСТОВАЯ РАЗМЕТКА (для TXTPR, MEZZ, PRWOW)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Строки могут содержать управляющие коды:
|
||
*
|
||
* 0x00 — конец строки и абзаца
|
||
* 0x00, 0x00 — разделитель сообщений (только для MEZZ)
|
||
* 0xFE, lo, hi — ссылка на строку по адресу lo|hi<<8
|
||
* (абзацы связывать бесполезно — выводит только первую строку)
|
||
* 0x01–0x08 — цвет символов (INK): 1=синий ... 7=белый, 8=чёрный
|
||
* 0x01–0x08, 0x01–0x08— цвет PAPER+INK (первый=фон, второй=символ)
|
||
* если оба одинаковы → ярко-фоновый INK
|
||
* 0x09 — инверсия цвета (PAPER ↔ INK)
|
||
* 0x0B, XX — сдвиг вправо на XX символов
|
||
* 0x0C, YY — сдвиг вниз на YY строк (X и цвет не трогает)
|
||
* 0x0D — перенос строки, INK → фоновый цвет
|
||
* 0x0E — центрирование строки (X сбрасывается)
|
||
* не работает если строка >= ширины окна
|
||
* или если есть ссылка (#FE)
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* АТРИБУТ ЦВЕТА (EGA-формат, 1 байт)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* [7:4] = BACKGROUND (фон): 16 цветов (0–15)
|
||
* [3:0] = FOREGROUND (текст): 16 цветов (0–15)
|
||
*
|
||
* Кодировка YGRB (Bright, Green, Red, Blue):
|
||
* 0=чёрный, 1=синий, 2=красный, 3=пурпурный,
|
||
* 4=зелёный, 5=циановый, 6=жёлтый, 7=белый,
|
||
* 8=тёмно-серый, 9..15 = яркие варианты 1..7
|
||
*
|
||
* Используй макрос WC_COLOR(bg, fg) и константы WC_BLACK..WC_BRIGHT_WHITE
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* ПРИМЕР ИСПОЛЬЗОВАНИЯ
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* #include "wc_api.h"
|
||
*
|
||
* static wc_window_t win;
|
||
*
|
||
* void show_message(void) {
|
||
* win.type = WC_WIN_SINGLE; // однолинейная рамка
|
||
* win.cur_mask = 0x07;
|
||
* win.x = 255; win.y = 255; // по центру
|
||
* win.width = 40; win.height = 5;
|
||
* win.color = WC_COLOR(WC_BLACK, WC_BRIGHT_WHITE);
|
||
* win.buf_addr = 0xFFFF; // без сохранения фона
|
||
*
|
||
* wc_gedpl(); // восстановить дисплей WC
|
||
* wc_prwow(&win); // нарисовать окно
|
||
* wc_txtpr(&win, "Hello!", 1, 1); // вывести текст
|
||
* wc_key_wait_any(); // ждать любую клавишу
|
||
* wc_rresb(&win); // убрать окно
|
||
* }
|
||
*
|
||
* void load_data(void) {
|
||
* uint8_t rc;
|
||
* wc_mngcvpl(0); // VPL-страница 0 → #C000
|
||
* rc = wc_load512(0xC000, 32); // загрузить 16384 байт
|
||
* if (rc && rc != WC_EOF) { } // error
|
||
* }
|
||
*/
|
||
|
||
#ifndef WC_API_H
|
||
#define WC_API_H
|
||
|
||
#include "types.h"
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* Константы
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
#define WC_ENTRY 0x6006 /* адрес точки входа WC */
|
||
|
||
/* Стили рамки окна (type[3:0]): стандартные окна с курсором */
|
||
#define WC_WIN_NO_BORDER 0x00 /* без рамки, стандартное с курсором */
|
||
#define WC_WIN_SINGLE 0x01 /* однолинейная рамка, без курсора */
|
||
#define WC_WIN_DOUBLE 0x02 /* двойная рамка + курсор */
|
||
#define WC_WIN_TYPE3 0x03 /* рамка 2-го типа, с курсором */
|
||
#define WC_WIN_TYPE4 0x04 /* рамка 2-го типа, с заголовком/текстом, без курсора */
|
||
#define WC_WIN_TYPE5 0x05 /* рамка 2-го типа + курсор */
|
||
#define WC_WIN_TYPE6 0x06 /* рамка 3-го типа, с курсором */
|
||
#define WC_WIN_TYPE7 0x07 /* рамка 3-го типа, с заголовком/текстом, без курсора */
|
||
#define WC_WIN_TYPE8 0x08 /* рамка 3-го типа + курсор */
|
||
|
||
/* Флаги type[7:4] */
|
||
#define WC_WIN_HEADER 0x10 /* инверсная строка-заголовок вверху */
|
||
#define WC_WIN_WIDE_CURSOR 0x40 /* курсор на всю ширину окна */
|
||
#define WC_WIN_SHADOW 0x80 /* тень вокруг окна */
|
||
|
||
/* wc_yn() mode */
|
||
#define WC_YN_OK_CANCEL 0x01
|
||
#define WC_YN_YES_NO 0x02
|
||
#define WC_YN_POLL 0x00 /* опросить без ожидания */
|
||
#define WC_YN_EXIT 0xFF /* закрыть меню YN */
|
||
|
||
/* wc_kbscn() mode */
|
||
#define WC_KBSCN_NORMAL 0x00 /* учитывать SHIFT / CL / Lang */
|
||
#define WC_KBSCN_RAW 0x01 /* сырой скан-код */
|
||
|
||
/* wc_mngv_pl() mode */
|
||
#define WC_VIDEO_TXT 0x00 /* текстовый режим WC */
|
||
#define WC_VIDEO_BUF1 0x01 /* видеобуфер 1 */
|
||
#define WC_VIDEO_BUF2 0x02
|
||
#define WC_VIDEO_BUF3 0x03
|
||
#define WC_VIDEO_BUF4 0x04
|
||
|
||
/* wc_adir() mode */
|
||
#define WC_ADIR_SEEK_START 0x00 /* установить позицию на начало */
|
||
#define WC_ADIR_RESET_NEXT 0x01 /* сброс FindNext */
|
||
|
||
/* wc_stream() mode */
|
||
#define WC_STREAM_ROOT 0xFF /* корневой поток */
|
||
#define WC_STREAM_CLONE 0xFE /* клонировать текущий поток */
|
||
#define WC_STREAM_WCDIR 0xFD /* каталог WC */
|
||
/* 0x00, 0x01 = номер потока 0 или 1 */
|
||
|
||
/* wc_int_pl() mode */
|
||
#define WC_INT_DISABLE_ALL 0x00 /* отключить все прерывания WC */
|
||
#define WC_INT_NO_TIME 0x01 /* отключить таймерное INT WC */
|
||
#define WC_INT_NO_PS2 0x02 /* отключить PS/2 INT WC */
|
||
#define WC_INT_PLUGIN 0xFF /* установить обработчик плагина */
|
||
|
||
/* wc_turbopl() mode */
|
||
#define WC_TURBO_CPU 0x00 /* B=0: настройка CPU; C=частота */
|
||
#define WC_TURBO_AY 0x01 /* B=1: AY частота */
|
||
#define WC_TURBO_RESTORE 0xFF /* восстановить оригинальный режим */
|
||
|
||
/* Коды ошибок файловых операций */
|
||
#define WC_EOF 0x0F /* конец файла / конец цепочки (LOAD512) — не ошибка! */
|
||
|
||
/* Флаги типа файла (wc_fentry, wc_mkfile, wc_delfl, wc_rename) */
|
||
#define WC_FILE_FLAG 0x00 /* объект является файлом */
|
||
#define WC_DIR_FLAG 0x10 /* объект является каталогом */
|
||
|
||
/* Коды ошибок FAT-операций */
|
||
#define WC_ERR_LONG_NAME 1 /* длинное имя некорректно */
|
||
#define WC_ERR_SHORT_IDX 2 /* короткое имя требует индекса */
|
||
#define WC_ERR_LONG_EXISTS 3 /* длинное имя уже существует */
|
||
#define WC_ERR_SHORT_EXISTS 4 /* короткое имя уже существует */
|
||
#define WC_ERR_NOT_FOUND 8 /* источник не найден */
|
||
#define WC_ERR_NO_SPACE 16 /* нет свободного места */
|
||
#define WC_ERR_UNKNOWN 255 /* неизвестная ошибка */
|
||
|
||
/* Константы прокрутки wc_scrlwow (flags) */
|
||
#define WC_SCRL_DOWN 0x00 /* направление — вниз */
|
||
#define WC_SCRL_UP 0x01 /* направление — вверх */
|
||
/* правка/влево (0x02, 0x03) зарезервированы, не работают */
|
||
#define WC_SCRL_WITH_ATTRS 0x80 /* прокручивать атрибуты вместе с символами */
|
||
#define WC_SCRL_CLEAR_SRC 0x40 /* очищать исходную позицию после прокрутки */
|
||
/* [5:2] = шаг: 0=1 символ, 0xF=16 символов (сдвинуть на N+1) */
|
||
/* При step=0 и без флагов [7:2] — автоматически использует DMA */
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* СТРАНИЦЫ ПАМЯТИ WC (физические номера страниц #00–#FF)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
/* Текстовые экраны */
|
||
#define WC_PAGE_MTXPG 0x00 /* основной текстовый экран */
|
||
#define WC_PAGE_FONT0 0x01 /* шрифт основного TXT + Hrust/MegaLZ*/
|
||
#define WC_PAGE_BUFPG 0x08 /* второй текстовый экран / буфер */
|
||
#define WC_PAGE_FONT1 0x09 /* шрифт второго TXT */
|
||
|
||
/* Код WC */
|
||
#define WC_PAGE_CODE 0x02 /* основной код WC (#8000–#AFFF) */
|
||
#define WC_PAGE_FAT_ENGINE 0x05 /* FAT engine (#4000) + stack + код */
|
||
|
||
/* Каталоги панелей */
|
||
#define WC_PAGE_CTZPG 0x0B /* начало каталога LEFT панели */
|
||
#define WC_PAGE_CAT_LEFT 0x0B /* стр. #0B-#13 = 9 стр. */
|
||
#define WC_PAGE_CAT_RIGHT 0x14 /* стр. #14-#1C = 9 стр. */
|
||
#define WC_CAT_MAX_PAGES 9 /* макс. страниц на каталог */
|
||
#define WC_PAGE_RESB 0x1D /* буфер сохранения окон */
|
||
#define WC_PAGE_CPPG1 0x1E /* позиции каталога LEFT */
|
||
#define WC_PAGE_CPPG2 0x1F /* позиции каталога RIGHT */
|
||
|
||
/* Megabuffer / видеобуферы */
|
||
#define WC_PAGE_TVBPG 0x20 /* начало MEGABUFFER (64 стр.) */
|
||
#define WC_PAGE_TVEPG 0x5F /* конец MEGABUFFER */
|
||
#define WC_PAGE_GV1 0x20 /* видеобуфер 1 (16 стр.) */
|
||
#define WC_PAGE_GV2 0x30 /* видеобуфер 2 (16 стр.) */
|
||
#define WC_PAGE_GV3 0x40 /* видеобуфер 3 (16 стр.) */
|
||
#define WC_PAGE_GV4 0x50 /* видеобуфер 4 (16 стр.) */
|
||
#define WC_VIDEO_PAGES_PER_BUF 16 /* страниц в одном видеобуфере */
|
||
|
||
/* Плагины */
|
||
#define WC_PAGE_PLHPG 0x60 /* заголовки плагинов (96) */
|
||
#define WC_PAGE_PLGPG 0x61 /* начало кода плагинов (97) */
|
||
#define WC_PAGE_PLEPG 0xA0 /* конец кода плагинов (160) */
|
||
#define WC_PLUGIN_MAX_PAGES 64 /* макс. страниц для всех плагинов */
|
||
|
||
/* TAP */
|
||
#define WC_PAGE_TAP_START 0xA1 /* смонтированный TAP-файл */
|
||
#define WC_PAGE_TAP_END 0xBF /* конец TAP (31 стр.) */
|
||
|
||
/* vDOS RAM Disk */
|
||
#define WC_PAGE_VDOS_RAM 0xC0 /* начало RAM-диска vDOS */
|
||
#define WC_PAGE_VDOS_END 0xE7 /* конец RAM-диска (40 стр. = 640 КБ) */
|
||
#define WC_PAGE_VDOS_FREE 0xE8 /* свободные стр. (#E8–#EF) */
|
||
|
||
/* Системные потоки */
|
||
#define WC_PAGE_PNLPG 0xF0 /* поток ЛЕВОЙ панели */
|
||
#define WC_PAGE_PNL_RIGHT 0xF1 /* поток ПРАВОЙ панели */
|
||
#define WC_PAGE_INIPG 0xF2 /* поток плагина #00 / INI */
|
||
#define WC_PAGE_STRPG 0xF3 /* поток плагина #01 */
|
||
#define WC_PAGE_DBPG 0xF4 /* буфер SPG-загрузчика */
|
||
#define WC_PAGE_D5PG 0xF5 /* загрузочная стр. 5 */
|
||
#define WC_PAGE_D2PG 0xF6 /* загрузочная стр. 2 */
|
||
#define WC_PAGE_RPPG 0xF7 /* пути панелей + флаг активной */
|
||
|
||
/* vDOS системные */
|
||
#define WC_PAGE_VROM_START 0xF8 /* Virtual ROM (4 стр.) */
|
||
#define WC_PAGE_VROM_END 0xFB
|
||
#define WC_PAGE_VDOS_TABLES 0xFC /* vDOS Tables (#FC–#FD) */
|
||
#define WC_PAGE_VDOS_DRV 0xFE /* vDOS Drivers */
|
||
#define WC_PAGE_VDOS_TRAPS 0xFF /* vDOS Traps */
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* СИСТЕМНАЯ ОБЛАСТЬ WC (#6000–#602F)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
#define WC_SYS_PG0 0x6000 /* [1] страница в окне #0000 */
|
||
#define WC_SYS_PG4 0x6001 /* [1] страница в окне #4000 */
|
||
#define WC_SYS_PG8 0x6002 /* [1] страница в окне #8000 */
|
||
#define WC_SYS_PGC 0x6003 /* [1] страница в окне #C000 */
|
||
#define WC_SYS_ABT 0x6004 /* [1] ABT: флаг ESC (1=нажат) */
|
||
#define WC_SYS_ENT 0x6005 /* [1] ENT: флаг ENTER (1=нажат) */
|
||
#define WC_SYS_FUN 0x6006 /* [3] API entry point (JP instr) */
|
||
#define WC_SYS_TMN 0x6009 /* [2] таймер INT (uint16, ++/frame) */
|
||
#define WC_SYS_FEP 0x600B /* [1] страница FAT engine в окне 0 */
|
||
#define WC_SYS_XPP 0x600C /* [1] сохранённая страница */
|
||
#define WC_SYS_CNFV 0x600D /* [1] конфиг видео (%000–%111) */
|
||
#define WC_SYS_HEI 0x600E /* [1] высота экрана (25/30/36) */
|
||
#define WC_SYS_TXTMD 0x600F /* [1] текстовый режим */
|
||
#define WC_SYS_INIFLG 0x6010 /* [1] INI загружен */
|
||
#define WC_SYS_RSQBC 0x6011 /* [2] RSQ buffer counter */
|
||
#define WC_SYS_RSQB2 0x6013 /* [2] RSQ buffer 2 */
|
||
#define WC_SYS_SDBSF 0x6015 /* [1] SD1 driver state */
|
||
#define WC_SYS_SDBSF2 0x6016 /* [1] SD2 driver state */
|
||
#define WC_SYS_F3ENTFL 0x6017 /* [1] F3/ENTER execution flag */
|
||
#define WC_SYS_FEP2 0x6018 /* [2] FAT engine page extra */
|
||
#define WC_SYS_PLRESAD 0x6020 /* [8] резидент перехода (JP page+HL) */
|
||
#define WC_SYS_PLRESCALL 0x6028 /* [8] резидент вызова (CALL page+HL) */
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* КОДЫ УСТРОЙСТВ (для wc_stream, регистр B)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
#define WC_DEV_SD_ZC 0 /* SD (Z-Controller) */
|
||
#define WC_DEV_IDE_NEMO_M 1 /* IDE Nemo Master */
|
||
#define WC_DEV_IDE_NEMO_S 2 /* IDE Nemo Slave */
|
||
#define WC_DEV_SD_NGS 3 /* SD (NeoGS) */
|
||
#define WC_DEV_IDE_SMUC_M 4 /* IDE SMUC Master */
|
||
#define WC_DEV_IDE_SMUC_S 5 /* IDE SMUC Slave */
|
||
#define WC_DEV_SD2_ZC 6 /* SD2 (Z-Controller) */
|
||
#define WC_DEV_COUNT 7 /* всего устройств */
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* КОНФИГУРАЦИЯ ВИДЕО (CNFv, #600D)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
#ifndef WC_CNFV_PWM
|
||
#define WC_CNFV_PWM 0 /* ШИМ (IDE) */
|
||
#endif
|
||
#ifndef WC_CNFV_VDAC3
|
||
#define WC_CNFV_VDAC3 1 /* 3-bit VDAC */
|
||
#endif
|
||
#ifndef WC_CNFV_VDAC4
|
||
#define WC_CNFV_VDAC4 2 /* 4-bit VDAC */
|
||
#endif
|
||
#ifndef WC_CNFV_VDAC5
|
||
#define WC_CNFV_VDAC5 3 /* 5-bit VDAC */
|
||
#endif
|
||
#ifndef WC_CNFV_VDAC2
|
||
#define WC_CNFV_VDAC2 7 /* VDAC2 (FT812) */
|
||
#endif
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* ВИДЕОРЕЖИМЫ TSConfig (для wc_gvmod)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
/* Разрешение [7:6] */
|
||
#define WC_RRES_256x192 0x00
|
||
#define WC_RRES_320x200 0x40
|
||
#define WC_RRES_320x240 0x80
|
||
#define WC_RRES_360x288 0xC0
|
||
|
||
/* Графический режим [1:0] */
|
||
#define WC_VMODE_ZX 0x00 /* ZX Spectrum (6912 байт) */
|
||
#define WC_VMODE_16C 0x01 /* 16 цветов (4 бит/пиксель) */
|
||
#define WC_VMODE_256C 0x02 /* 256 цветов (8 бит/пиксель) */
|
||
#define WC_VMODE_TXT 0x03 /* текстовый режим */
|
||
|
||
/* Прочие биты */
|
||
#define WC_VMODE_NOGFX 0x20 /* выключить графику */
|
||
#define WC_VMODE_NOTSU 0x10 /* выключить TSU */
|
||
|
||
/* Размеры текстового экрана */
|
||
#define WC_SCREEN_80x25 25
|
||
#define WC_SCREEN_80x30 30
|
||
#define WC_SCREEN_90x36 36
|
||
#define WC_SCREEN_W80 80
|
||
#define WC_SCREEN_W90 90
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* АППАРАТНЫЕ ПОРТЫ TSConfig (для __sfr / inline asm)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
#define WC_PORT_PW0 0x10AF /* Page Window 0 */
|
||
#define WC_PORT_PW1 0x11AF /* Page Window 1 */
|
||
#define WC_PORT_PW2 0x12AF /* Page Window 2 */
|
||
#define WC_PORT_PW3 0x13AF /* Page Window 3 */
|
||
#define WC_PORT_VMOD 0x00AF /* Video mode */
|
||
#define WC_PORT_VPAG 0x01AF /* Video page */
|
||
#define WC_PORT_VPAL 0x07AF /* Palette */
|
||
#define WC_PORT_BORDER 0x0FAF /* Border color */
|
||
#define WC_PORT_SYSCONF 0x20AF /* System config (turbo [1:0]) */
|
||
#define WC_PORT_CACHECONF 0x2BAF /* Cache config */
|
||
#define WC_PORT_FDDVIRT 0x29AF /* FDD Virtualization (vDOS) */
|
||
|
||
/* DMA порты */
|
||
#define WC_PORT_DMA_SL 0x1AAF /* DMA Source Low */
|
||
#define WC_PORT_DMA_SH 0x1BAF /* DMA Source High */
|
||
#define WC_PORT_DMA_SX 0x1CAF /* DMA Source Page */
|
||
#define WC_PORT_DMA_DL 0x1DAF /* DMA Dest Low */
|
||
#define WC_PORT_DMA_DH 0x1EAF /* DMA Dest High */
|
||
#define WC_PORT_DMA_DX 0x1FAF /* DMA Dest Page */
|
||
#define WC_PORT_DMA_N 0x26AF /* DMA burst size */
|
||
#define WC_PORT_DMA_C 0x27AF /* DMA command / status */
|
||
#define WC_PORT_DMA_T 0x28AF /* DMA burst count */
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* FAT32 ENTRY (стандартная 32-байтная структура каталога)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
typedef struct {
|
||
uint8_t name[11]; /* +0: короткое имя 8.3 (без точки) */
|
||
uint8_t attr; /* +11: атрибуты (EFLG) */
|
||
uint8_t _res1; /* +12: reserved (NTRes) */
|
||
uint8_t crt_time_ms; /* +13: время создания (0.1 сек) */
|
||
uint16_t crt_time; /* +14: время создания (FAT format) */
|
||
uint16_t crt_date; /* +16: дата создания (FAT format) */
|
||
uint16_t acc_date; /* +18: дата последнего доступа */
|
||
uint16_t cluster_hi; /* +20: старшее слово кластера (CLSDE) */
|
||
uint16_t mod_time; /* +22: время модификации */
|
||
uint16_t mod_date; /* +24: дата модификации */
|
||
uint16_t cluster_lo; /* +26: младшее слово кластера (CLSHL) */
|
||
uint32_t file_size; /* +28: размер файла (SIZIK) */
|
||
} wc_fat_entry_t;
|
||
|
||
/* Атрибуты FAT entry (attr поле) */
|
||
#define WC_FAT_ATTR_RDONLY 0x01 /* Read-only */
|
||
#define WC_FAT_ATTR_HIDDEN 0x02 /* Hidden */
|
||
#define WC_FAT_ATTR_SYSTEM 0x04 /* System */
|
||
#define WC_FAT_ATTR_VOLLBL 0x08 /* Volume label */
|
||
#define WC_FAT_ATTR_DIR 0x10 /* Directory */
|
||
#define WC_FAT_ATTR_ARCHIVE 0x20 /* Archive */
|
||
#define WC_FAT_ATTR_LFN 0x0F /* Long File Name entry */
|
||
|
||
/* Макросы для FAT date/time */
|
||
#define WC_FAT_TIME(h,m,s) (uint16_t)(((h)<<11)|((m)<<5)|((s)>>1))
|
||
#define WC_FAT_DATE(y,m,d) (uint16_t)((((y)-1980)<<9)|((m)<<5)|(d))
|
||
|
||
#define WC_FAT_TIME_HOUR(t) (((t) >> 11) & 0x1F)
|
||
#define WC_FAT_TIME_MIN(t) (((t) >> 5) & 0x3F)
|
||
#define WC_FAT_TIME_SEC(t) (((t) & 0x1F) << 1)
|
||
#define WC_FAT_DATE_YEAR(d) ((((d) >> 9) & 0x7F) + 1980)
|
||
#define WC_FAT_DATE_MONTH(d) (((d) >> 5) & 0x0F)
|
||
#define WC_FAT_DATE_DAY(d) ((d) & 0x1F)
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* FindNext выходной буфер (формат записи)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
/**
|
||
* Структура записи, возвращаемой wc_findnext.
|
||
* Порядок полей зависит от флагов (size/date/time опциональны).
|
||
* При всех включённых флагах ([4:2]=111):
|
||
*/
|
||
typedef struct {
|
||
uint32_t size; /* [2]=1: размер файла */
|
||
uint16_t date; /* [3]=1: дата создания (FAT формат) */
|
||
uint16_t time; /* [4]=1: время создания (FAT формат) */
|
||
uint8_t flag; /* Entry Flag: 0x10=DIR, 0x00=file */
|
||
char name[1]; /* имя файла (переменная длина, ZS) */
|
||
} wc_findnext_entry_t;
|
||
|
||
/* Флаги для wc_findnext */
|
||
#define WC_FIND_ALL 0x00 /* все записи [1:0]=00 */
|
||
#define WC_FIND_FILES 0x01 /* только файлы [1:0]=01 */
|
||
#define WC_FIND_DIRS 0x02 /* только каталоги [1:0]=10 */
|
||
#define WC_FIND_SHORT_ONLY 0x80 /* только короткие имена [7]=1 */
|
||
#define WC_FIND_WITH_SIZE 0x04 /* включить поле size [2]=1 */
|
||
#define WC_FIND_WITH_DATE 0x08 /* включить поле date [3]=1 */
|
||
#define WC_FIND_WITH_TIME 0x10 /* включить поле time [4]=1 */
|
||
#define WC_FIND_FULL (WC_FIND_WITH_SIZE | WC_FIND_WITH_DATE | WC_FIND_WITH_TIME)
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* КАТАЛОЖНАЯ ЗАПИСЬ ПАНЕЛИ WC (внутренний формат)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
/**
|
||
* INDEX entry (4 байта): ссылка из индекса на DATA entry.
|
||
*/
|
||
typedef struct {
|
||
uint8_t page; /* +0: логическая страница (0–8) */
|
||
uint16_t addr; /* +1: адрес в странице (#C000–#FDFF) */
|
||
uint8_t name_len; /* +3: длина имени */
|
||
} wc_cat_index_t;
|
||
|
||
/**
|
||
* DATA entry (переменная длина): полная запись файла в каталоге.
|
||
*/
|
||
typedef struct {
|
||
uint8_t mark; /* +0: Mark flags (бит 0: помечен) */
|
||
char ext[3]; /* +1: расширение (без точки) */
|
||
uint32_t cluster; /* +4: первый кластер FAT32 */
|
||
uint32_t size; /* +8: размер файла */
|
||
uint16_t date; /* +12: дата (FAT формат) */
|
||
uint16_t time; /* +14: время (FAT формат) */
|
||
uint8_t flag; /* +16: #10=файл, #00=каталог */
|
||
char name[1]; /* +17: имя (переменная длина, ZS) */
|
||
} wc_cat_data_t;
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* ЗАГОЛОВОК ПЛАГИНА (+0..+260)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
#define WC_PLUGIN_ID "WildCommanderMDL"
|
||
#define WC_PLUGIN_VERSION 0x10 /* текущая версия формата */
|
||
|
||
/* Типы вызова плагина (поле +197) */
|
||
#define WC_PCOND_EXT_ONLY 0x00 /* только по расширению */
|
||
#define WC_PCOND_ON_LOAD 0x01 /* при загрузке (ENTER) */
|
||
#define WC_PCOND_TIMER 0x02 /* по таймеру / F10 */
|
||
#define WC_PCOND_F10 0x03 /* из меню F10 */
|
||
#define WC_PCOND_VIEWER 0x04 /* из меню Shift+F3 */
|
||
#define WC_PCOND_F10_VIEW 0x05 /* F10 или Shift+F3 */
|
||
#define WC_PCOND_F10_F2 0x11 /* F10 или F2 */
|
||
#define WC_PCOND_F2 0x12 /* F2 */
|
||
#define WC_PCOND_F10_F4 0x13 /* F10 или F4 */
|
||
#define WC_PCOND_F4 0x14 /* F4 */
|
||
#define WC_PCOND_F10_V_F4 0x15 /* F10, Shift+F3 или F4 */
|
||
|
||
/* ──────────────────────────────────────────────────────────────────────
|
||
* DMA операции (коды для wc_dmapl и прямого доступа)
|
||
* ────────────────────────────────────────────────────────────────────── */
|
||
|
||
/* DMA device codes (биты [2:0] регистра DMA_C) */
|
||
#define WC_DMA_RAM_RAM 0x01 /* W=0: RAM→RAM copy */
|
||
#define WC_DMA_BLT_RAM 0x01 /* W=1: RAM blit (transparency) */
|
||
#define WC_DMA_SPI_RAM_R 0x02 /* W=0: SPI→RAM */
|
||
#define WC_DMA_SPI_RAM_W 0x02 /* W=1: RAM→SPI */
|
||
#define WC_DMA_IDE_RAM_R 0x03 /* W=0: IDE→RAM */
|
||
#define WC_DMA_IDE_RAM_W 0x03 /* W=1: RAM→IDE */
|
||
#define WC_DMA_FILL 0x04 /* W=0: FILL RAM */
|
||
#define WC_DMA_RAM_CRAM 0x04 /* W=1: RAM→CRAM (палитра) */
|
||
#define WC_DMA_RAM_SFILE 0x05 /* W=1: RAM→SFILE (спрайты) */
|
||
|
||
/* Подфункции dmapl (А' регистр) */
|
||
#define WC_DMA_INIT_SD 0x00 /* задать src + dst */
|
||
#define WC_DMA_INIT_SRC 0x01 /* задать только src */
|
||
#define WC_DMA_INIT_DST 0x02 /* задать только dst */
|
||
#define WC_DMA_INIT_SRC_WIN 0x03 /* src из окна WC */
|
||
#define WC_DMA_INIT_DST_WIN 0x04 /* dst из окна WC */
|
||
#define WC_DMA_SET_T 0x05 /* задать DMA_T */
|
||
#define WC_DMA_SET_N 0x06 /* задать DMA_N */
|
||
#define WC_DMA_SET_TN 0x07 /* задать DMA_T + DMA_N */
|
||
#define WC_DMA_ALIGN_SRC 0x08 /* выравнивание src */
|
||
#define WC_DMA_ALIGN_DST 0x09 /* выравнивание dst */
|
||
#define WC_DMA_ALIGN_SIZE 0x0A /* размер выравнивания */
|
||
#define WC_DMA_ALIGN_ALL 0x0B /* все параметры выравнивания */
|
||
#define WC_DMA_RUN_RAM 0xFC /* RAM→RAM с ожиданием */
|
||
#define WC_DMA_RUN_BLT 0xFB /* BLT→RAM */
|
||
#define WC_DMA_RUN_FILL 0xFA /* FILL */
|
||
#define WC_DMA_RUN_CRAM 0xF9 /* RAM→CRAM */
|
||
#define WC_DMA_RUN_SFILE 0xF8 /* RAM→SFILE */
|
||
#define WC_DMA_RUN_NOWAIT 0xFD /* запустить без ожидания */
|
||
#define WC_DMA_RUN_WAIT 0xFE /* запустить с ожиданием */
|
||
#define WC_DMA_BUSY_WAIT 0xFF /* ждать готовности DMA */
|
||
|
||
/* DMA page flags (для subfunc #00–#02: бит 7 регистров B/C) */
|
||
#define WC_DMA_PAGE_PLUGIN 0x80 /* страница из блока плагина (0–5) */
|
||
/* WC_DMA_PAGE_VIDEO 0x00 страница из видеобуферов (0–63) */
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* SOW — Structure of Window (16 байт)
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* КАРТА ПАМЯТИ TSConfig (4 МБ = 256 страниц × 16 КБ)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Z80 CPU имеет 4 окна по 16 КБ. Каждое окно может адресовать любую
|
||
* из 256 страниц (8-бит page register). Управление через порты:
|
||
*
|
||
* Окно 0: #0000–#3FFF порт PW0 = #10AF (при сбросе = #00)
|
||
* Окно 1: #4000–#7FFF порт PW1 = #11AF (при сбросе = #05)
|
||
* Окно 2: #8000–#BFFF порт PW2 = #12AF (при сбросе = #02)
|
||
* Окно 3: #C000–#FFFF порт PW3 = #13AF (при сбросе = #00)
|
||
*
|
||
* ┌─────────┬─────────┬─────────────────────────────────────────────┐
|
||
* │ Стр. │ Дес. │ Назначение │
|
||
* ├─────────┼─────────┼─────────────────────────────────────────────┤
|
||
* │ #00 │ 0 │ MTXPG — основной текстовый экран (TXT page) │
|
||
* │ #01 │ 1 │ Шрифт (основного TXT) + Hrust/MegaLZ │
|
||
* │ │ │ (#FE00+) │
|
||
* │ #02 │ 2 │ Основной код WC (#8000–#AFFF) │
|
||
* │ #03–04 │ 3–4 │ Не используются │
|
||
* │ #05 │ 5 │ FAT Engine (#4000) + Stack (#5BFF) + │
|
||
* │ │ │ код WC (#6000–#7FFF) │
|
||
* │ #06–07 │ 6–7 │ Не используются │
|
||
* │ #08 │ 8 │ BUFPG — второй текст. экран / буфер 16 КБ │
|
||
* │ #09 │ 9 │ Шрифт (второго TXT экрана) │
|
||
* │ #0A │ 10 │ (зарезервирован) │
|
||
* │ #0B–13 │ 11–19 │ CTZPG — каталог ЛЕВОЙ панели (9 стр.) │
|
||
* │ #14–1C │ 20–28 │ Каталог ПРАВОЙ панели (9 стр.) │
|
||
* │ #1D │ 29 │ RESB — буфер сохранения окон (WOW save) │
|
||
* │ #1E │ 30 │ CPPG1 — позиции каталога ЛЕВОЙ панели │
|
||
* │ #1F │ 31 │ CPPG2 — позиции каталога ПРАВОЙ панели │
|
||
* │ #20–5F │ 32–95 │ TVBPG — MEGABUFFER (1 МБ, 64 стр.) │
|
||
* │ #60 │ 96 │ PLHPG — заголовки плагинов (512 б каждый) │
|
||
* │ #61–A0 │ 97–160 │ PLGPG — код плагинов (до 1 МБ, 64 стр.) │
|
||
* │ #A1–BF │ 161–191 │ Смонтированный TAP-файл (31 стр.) │
|
||
* │ #C0–E7 │ 192–231 │ vDOS RAM Disk (40 стр. = 640 КБ) │
|
||
* │ #E8–EF │ 232–239 │ Свободно (дополнит. дорожки RAM-диска) │
|
||
* │ #F0 │ 240 │ PNLPG — поток ЛЕВОЙ панели │
|
||
* │ #F1 │ 241 │ Поток ПРАВОЙ панели │
|
||
* │ #F2 │ 242 │ INIPG — поток плагина #00 / INI │
|
||
* │ #F3 │ 243 │ STRPG — поток плагина #01 │
|
||
* │ #F4 │ 244 │ DBPG — буфер SPG-загрузчика │
|
||
* │ #F5 │ 245 │ D5PG — загрузочная страница 5 │
|
||
* │ #F6 │ 246 │ D2PG — загрузочная страница 2 │
|
||
* │ #F7 │ 247 │ RPPG — пути панелей: │
|
||
* │ │ │ LEFT (#1000), RIGHT (#2000), │
|
||
* │ │ │ флаг активной панели (#1FFC) │
|
||
* │ #F8–FB │ 248–251 │ Virtual ROM (vDOS, системная прошивка) │
|
||
* │ #FC–FD │ 252–253 │ vDOS Tables (таблицы TR-DOS) │
|
||
* │ #FE │ 254 │ vDOS Drivers (драйверы дисководов) │
|
||
* │ #FF │ 255 │ vDOS Traps (перехватчик команд TR-DOS) │
|
||
* └─────────┴─────────┴─────────────────────────────────────────────┘
|
||
*
|
||
* ВИДЕОБУФЕРЫ (4 × 16 страниц = 256 КБ каждый, 1 МБ всего):
|
||
* Буфер 1: страницы #20–#2F (GVvPG=32)
|
||
* Буфер 2: страницы #30–#3F (GV2PG=48)
|
||
* Буфер 3: страницы #40–#4F (GV3PG=64)
|
||
* Буфер 4: страницы #50–#5F (GV4PG=80)
|
||
* (МEGABUFFER #20–#5F включает все 4 видеобуфера)
|
||
*
|
||
* Функция MNGCVPL (65): A' = 0x00–0x0F → buf1,
|
||
* A' = 0x10–0x1F → buf2,
|
||
* A' = 0x20–0x2F → buf3,
|
||
* A' = 0x30–0x3F → buf4
|
||
*
|
||
* ТЕКСТОВЫЙ ЭКРАН WC: страница #00 (MTXPG) занимает 2 страницы:
|
||
* стр. #00 = символы + атрибуты (EGA-формат: [7:4]=bg, [3:0]=fg)
|
||
* стр. #01 = шрифт 8×8 (используется TSConfig text mode)
|
||
* Размеры: 80×25, 80×30 или 90×36 (HEI = 25/30/36)
|
||
*
|
||
* АДРЕСНОЕ ПРОСТРАНСТВО процессора (runtime плагина):
|
||
* #0000–#3FFF Окно 0: обычно FAT engine / буферы (page #05)
|
||
* ⚠ #0000–#1FFF гробится FindNext!
|
||
* ⚠ #1000–#1447 гробится GEDPL!
|
||
* #4000–#5FFF Окно 1: FAT engine (page #05), код #6000–#7FFF
|
||
* #6000–#602F Системная область WC (переменные, API entry point)
|
||
* #8000–#BFFF Окно 2: код плагина (page из PLGPG)
|
||
* #C000–#FFFF Окно 3: переключаемая (TXT/данные/видео)
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* vDOS (Virtual DOS) — эмуляция TR-DOS на TSConfig
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* vDOS обеспечивает совместимость с TR-DOS (Beta Disk Interface) на
|
||
* аппаратном уровне TSConfig FPGA. Состоит из:
|
||
*
|
||
* Страница #FF — vDOS Traps:
|
||
* Перехватывает обращения Z80 к стандартным адресам TR-DOS ROM
|
||
* (#3D13, #3D2F и др.) и эмулирует дисковые операции.
|
||
*
|
||
* Страница #FE — vDOS Drivers:
|
||
* Низкоуровневые драйверы виртуального дисковода:
|
||
* чтение/запись секторов, форматирование, позиционирование.
|
||
*
|
||
* Страницы #FC–#FD — vDOS Tables:
|
||
* Таблицы трансляции: соответствие виртуальных дорожек/секторов
|
||
* физическим секторам на SD/IDE. Каталоги дисков A–D.
|
||
*
|
||
* Страницы #F8–#FB — Virtual ROM (4 × 16 КБ = 64 КБ):
|
||
* Прошивка: Service ROM, DOS ROM, 128 ROM, 48 ROM.
|
||
* Переключение через биты DOS/ROM128 в page register окна 0.
|
||
*
|
||
* Страницы #C0–#E7 — vDOS RAM Disk (40 × 16 КБ = 640 КБ):
|
||
* RAM-диск для эмуляции дисководов. SCL-образы распаковываются
|
||
* сюда целиком. TRD-образы монтируются напрямую с FAT32.
|
||
* Страницы #E8–#EF — резерв (дополнительные дорожки).
|
||
*
|
||
* Инициализация vDOS:
|
||
* vDOS инициализируется автоматически при старте TSConfig (прошивка).
|
||
* Плагин не может и не должен напрямую управлять vDOS — только
|
||
* через плагин MOUNTER (монтирование/размонтирование образов).
|
||
* Регистр FDDVirt (#29AF) управляет виртуализацией FDD на уровне FPGA.
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* FAT32 ENGINE — файловая подсистема WC
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* FAT-движок (KERNEL.ASM + CORE32.ASM) располагается на странице #05
|
||
* в адресах #4000–#5BFF (окно 1). Системная переменная FEP (#600B)
|
||
* хранит номер страницы FAT engine в окне #0000.
|
||
*
|
||
* Буферы FAT engine (адреса относительно окна 0, когда FEP=#05):
|
||
* #0000–#1FFF GENBU/NXTBU — общий буфер / буфер FindNext
|
||
* #3000–#31FF SECBU — секторный буфер (512 б)
|
||
* #3200–#33FF LOBU — буфер загрузки (512 б)
|
||
* #3400–#35FF LOBU2 — второй буфер загрузки (512 б)
|
||
* #3800+ DRVR — область драйвера устройства
|
||
*
|
||
* Jump Table FAT Engine (ORG #4000):
|
||
* +0 SELDEV (заглушка)
|
||
* +3 DEVINI — инициализация устройства
|
||
* +6 REINI (заглушка)
|
||
* +9 HDD — поиск FAT32 раздела
|
||
* +12 RDD — чтение секторов с позиционированием
|
||
* +15 SDD — запись секторов с позиционированием
|
||
* +18 GIPAG — позиционирование на первый кластер
|
||
* +21 LOAD512 — потоковое чтение (HL=addr, B=blocks)
|
||
* +24 SAVE512 — потоковая запись
|
||
* +27 DOS_SWP — выбор устройства + загрузка драйвера
|
||
* +30 GLSTCAT — установить активный каталог
|
||
* +33 TLSTCAT — получить кластер активного каталога
|
||
* +36 SRHFCL — найти свободный кластер
|
||
* +42 MKSG — создать FAT-цепочку
|
||
* +48 RFRH — обновить FSInfo
|
||
* +51 GENTRY — скопировать entry в буфер
|
||
* +54 TENTRY — скопировать entry из буфера
|
||
* +57 MKFILE — создать файл
|
||
* +60 MKDIR — создать каталог
|
||
* +63 DELFL — удалить файл/каталог
|
||
* +66 RENAME — переименовать
|
||
* +69 DLSG — удалить FAT-цепочку
|
||
* +72 CHTOSE — цепочка кластер→сектор
|
||
* +78 SRHDRN — поиск entry в каталоге
|
||
* +81 LOAD256 — чтение 256 байт
|
||
* +84 LOADNON — пропуск секторов
|
||
* +87 NXTETY — следующий entry (полный)
|
||
* +90 NXTETY2 — следующий entry (фильтрованный)
|
||
*
|
||
* FAT32 Directory Entry (32 байта, стандарт):
|
||
* +0 [11] — короткое имя 8.3
|
||
* +11 [1] — EFLG: атрибуты (0x10=DIR, 0x20=ARCHIVE, ...)
|
||
* +14 [2] — время создания (FAT time format)
|
||
* +16 [2] — дата создания (FAT date format)
|
||
* +20 [2] — CLSDE: старшее слово кластера
|
||
* +22 [2] — дата модификации
|
||
* +24 [2] — время модификации
|
||
* +26 [2] — CLSHL: младшее слово кластера
|
||
* +28 [4] — SIZIK: размер файла (32-бит LE)
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* ПОТОКОВАЯ ПОДСИСТЕМА (STREAM)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Каждый поток — полный FAT32-контекст (устройство, раздел, каталог).
|
||
* WC поддерживает 4 потока:
|
||
*
|
||
* Страница #F0 (PNLPG) — поток ЛЕВОЙ панели
|
||
* Страница #F1 — поток ПРАВОЙ панели
|
||
* Страница #F2 (INIPG) — поток плагина #00 / INI-файл
|
||
* Страница #F3 (STRPG) — поток плагина #01
|
||
*
|
||
* Типичный сценарий работы с файлами из плагина:
|
||
*
|
||
* // 1. Клонировать поток панели → потоки #00 и #01
|
||
* wc_stream(WC_STREAM_CLONE); // D=#FE
|
||
*
|
||
* // 2. Перейти в root
|
||
* wc_stream(WC_STREAM_ROOT); // D=#FF
|
||
*
|
||
* // 3. Найти файл
|
||
* static uint8_t buf[] = { WC_FILE_FLAG, 'm','y','f','i','l','e','.','t','x','t', 0 };
|
||
* if (wc_fentry((uint16_t)buf)) {
|
||
* wc_gfile(); // открыть файл
|
||
* wc_load512(0xC000, 32); // прочитать
|
||
* }
|
||
*
|
||
* Устройства (код в регистре B при создании потока):
|
||
* 0 — SD (Z-Controller)
|
||
* 1 — IDE Nemo Master
|
||
* 2 — IDE Nemo Slave
|
||
* 3 — SD (NeoGS)
|
||
* 4 — IDE SMUC Master
|
||
* 5 — IDE SMUC Slave
|
||
* 6 — SD2 (Z-Controller)
|
||
*
|
||
* ⚠ GDIR нельзя вызывать на потоке активной панели!
|
||
* ⚠ MKfile/MKdir/LOAD512/SAVE512/FENTRY разрушают кеш FindNext!
|
||
* ⚠ GIPAGPL можно использовать со STREAM только после клонирования!
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* КАТАЛОГ ПАНЕЛИ (CAT) — внутренняя структура WC
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Каждая панель хранит каталог до 4095 файлов в 9 страницах RAM:
|
||
* Левая: стр. #0B–#13 (CTZPG), позиции: стр. #1E (CPPG1)
|
||
* Правая: стр. #14–#1C, позиции: стр. #1F (CPPG2)
|
||
*
|
||
* INDEX entry (4 байта):
|
||
* +0 [1] — Логическая страница (0–8)
|
||
* +1 [2] — Адрес в странице (#C000–#FDFF)
|
||
* +3 [1] — Длина имени (без заголовка и терминатора)
|
||
*
|
||
* DATA entry (переменная длина):
|
||
* +0 [1] — Mark flags (бит 0: %1=помечен, %0=нет)
|
||
* +1 [3] — Расширение (без точки, верхний регистр)
|
||
* +4 [4] — Первый кластер FAT32
|
||
* +8 [4] — Размер файла
|
||
* +12 [2] — Дата (FAT формат)
|
||
* +14 [2] — Время (FAT формат)
|
||
* +16 [1] — Flag: #10=файл, #00=каталог (инвертировано для сортировки)
|
||
* +17 [1–255]— Имя файла ("file.bin" / "megadir")
|
||
* +xx [1] — Терминатор #00
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* ДРАЙВЕРЫ УСТРОЙСТВ
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Драйвер загружается в область DRVR (#3800) FAT engine.
|
||
* Jump Table драйвера:
|
||
* +0 SELDEV — выбор устройства (master/slave)
|
||
* +3 DEVINI — инициализация
|
||
* +6 REINI — переинициализация
|
||
* +9 XPOZI — установить позицию (LBA)
|
||
* +12 PROZ — альтернативная позиция
|
||
* +15 RDDSE — чтение секторов (HL=addr, A=count)
|
||
* +18 SDDSE — запись секторов (HL=addr, A=count)
|
||
* +21 RDD256 — чтение 256 байт
|
||
*
|
||
* SD Card порты (Z-Controller): CONF=#77, DATA=#57
|
||
* IDE SMUC порты: CMD=#FFBE, DRV=#FEBE,
|
||
* CYLH=#FDBE, CYLL=#FCBE, SECR=#FBBE
|
||
*
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* АППАРАТНЫЕ РЕГИСТРЫ TSConfig (частые)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* #00AF Vmod — видеорежим (RRES[7:6] | NOGFX | NOTSU | TYPE[1:0])
|
||
* #01AF Vpag — видеостраница
|
||
* #07AF Vpal — индекс палитры
|
||
* #0FAF BORDER — цвет бордюра
|
||
* #10AF PW0 — страница окна #0000
|
||
* #11AF PW1 — страница окна #4000
|
||
* #12AF PW2 — страница окна #8000
|
||
* #13AF PW3 — страница окна #C000
|
||
* #15AF Vfm — режим шрифта
|
||
* #16AF Vtm — страница Tile Map
|
||
* #17AF Vtl0 — Tile Layer 0
|
||
* #18AF Vtl1 — Tile Layer 1
|
||
* #19AF Vsgp — Sprite Graphics page
|
||
* #1AAF DMASL — DMA Source Low
|
||
* #1BAF DMASH — DMA Source High
|
||
* #1CAF DMASX — DMA Source Page
|
||
* #1DAF DMADL — DMA Dest Low
|
||
* #1EAF DMADH — DMA Dest High
|
||
* #1FAF DMADX — DMA Dest Page
|
||
* #20AF SYC — System Config (turbo bits [1:0])
|
||
* #26AF DMA_N — DMA burst size
|
||
* #27AF DMA_C — DMA command / status
|
||
* #28AF DMA_T — DMA burst count
|
||
* #29AF FDDVirt — FDD Virtualization (vDOS)
|
||
* #2BAF CYC — Cache Config (per-window enable)
|
||
*/
|
||
typedef struct {
|
||
uint8_t type; /* +0: стиль+флаги (WC_WIN_*) */
|
||
uint8_t cur_mask; /* +1: маска цвета курсора */
|
||
uint8_t x; /* +2: позиция X в символах (255=центр) */
|
||
uint8_t y; /* +3: позиция Y в символах (255=центр) */
|
||
uint8_t width; /* +4: ширина (0=весь экран) */
|
||
uint8_t height; /* +5: высота (0=весь экран) */
|
||
uint8_t color; /* +6: атрибут цвета (EGA: bg[7:4]|fg[3:0]) */
|
||
uint8_t _reserved; /* +7: ЗАРЕЗЕРВИРОВАНО (всегда 0!) */
|
||
uint16_t buf_addr; /* +8: адрес буфера фона (0xFFFF=нет) */
|
||
uint8_t divider1; /* +10: Y-смещение разделит. линии 1 от низа окна (0=нет) */
|
||
uint8_t divider2; /* +11: Y-смещение разделит. линии 2 от низа окна (0=нет) */
|
||
uint8_t _ext[12]; /* +12–15: расширение (заголовок/курсор) */
|
||
} wc_window_t;
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* Вспомогательный макрос инициализации окна
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
* Пример:
|
||
* static wc_window_t my_win = WC_WIN_INIT(1, 0, 5, 5, 30, 10, 0x47, 0xFFFF);
|
||
* (border=1, x=5, y=5, w=30, h=10, color=bright white on black, no buf)
|
||
*/
|
||
/* WC_WIN_INIT: инициализация структуры окна.
|
||
* Поля +12..+15 (_ext) = 0 → подходит для типов без курсора (SINGLE, DOUBLE).
|
||
* Для типов 0/3/6 (с курсором) нужно вручную инициализировать _ext[0..3].
|
||
*/
|
||
#define WC_WIN_INIT(style, flags, _x, _y, _w, _h, _color, _buf) \
|
||
{ (uint8_t)((style) | (flags)), 0x07, (_x), (_y), (_w), (_h), \
|
||
(_color), 0, (_buf), 0, 0, {0,0,0,0,0,0,0,0,0,0,0,0} }
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* INIT / СТРАНИЧНОЕ УПРАВЛЕНИЕ
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/**
|
||
* Переключить страницу плагина на адрес #C000.
|
||
* @param page номер страницы плагина:
|
||
* 0x00–0x3F — страницы RAM плагина
|
||
* 0xFF — страница с шрифтом WC (не использовать #E000–#FFFF!)
|
||
* 0xFE — первый текстовый экран WC
|
||
* Остальные страницы #8000 и #0000 при этом НЕ изменяются.
|
||
*/
|
||
void wc_mngc_pl(uint8_t page);
|
||
|
||
/** Отобразить страницу плагина (page) на адрес #0000 */
|
||
void wc_mng0_pl(uint8_t page);
|
||
|
||
/** Отобразить страницу плагина (page) на адрес #8000 */
|
||
void wc_mng8_pl(uint8_t page);
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* UI / ОКНА
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/**
|
||
* Восстановить дисплей WC: палитру, смещения, текстовый режим.
|
||
*
|
||
* Обязательно вызывать при старте плагина, прежде чем вызывать
|
||
* любые функции вывода окон (wc_prwow и т.д.).
|
||
*
|
||
* ⚠ ВНИМАНИЕ: ГРОБИТ область #1000–#1447 на странице, отображённой
|
||
* на #0000! Сохранить данные в этом диапазоне до вызова!
|
||
*
|
||
* НЕ переключает страницу в окне #0000–#3FFF.
|
||
* НЕ переключает страницу в окне #C000.
|
||
*/
|
||
void wc_gedpl(void);
|
||
|
||
/**
|
||
* Нарисовать окно win на экране (сохранить фон в buf_addr).
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата. Вызывать при 3.5 МГц!
|
||
*
|
||
* Структура win и строки заголовков должны находиться в #8000–#BFFF
|
||
* или #0000–#3FFF (не в #C000–#FFFF!).
|
||
*
|
||
* После первого вызова WC записывает реальный адрес буфера в win->buf_addr
|
||
* (если был 0). При buf_addr=0xFFFF фон не сохраняется.
|
||
*/
|
||
void wc_prwow(wc_window_t *win);
|
||
|
||
/**
|
||
* Удалить окно win с экрана (восстановить фон из buf_addr).
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата. Вызывать при 3.5 МГц!
|
||
*/
|
||
void wc_rresb(wc_window_t *win);
|
||
|
||
/**
|
||
* Напечатать строку str в окне win.
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата.
|
||
*
|
||
* @param y строка внутри окна (1-based от верха содержимого)
|
||
* @param x столбец внутри окна (1-based)
|
||
* @param len длина строки в символах
|
||
*
|
||
* Адрес win и строки str должны быть в #8000–#BFFF или #0000–#3FFF.
|
||
*/
|
||
void wc_prsrw(wc_window_t *win, const char *str, uint8_t y, uint8_t x, uint16_t len);
|
||
|
||
/**
|
||
* Напечатать строку str в окне win c атрибутом цвета attr (EGA-формат: bg[7:4] | fg[3:0]).
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата.
|
||
*
|
||
* @param y строка внутри окна (1-based от верха содержимого)
|
||
* @param x столбец внутри окна (1-based)
|
||
* @param len длина строки в символах
|
||
* @param attr EGA-атрибут: bg[7:4] | fg[3:0]
|
||
*
|
||
* Адрес win и строки str должны быть в #8000–#BFFF или #0000–#3FFF.
|
||
*/
|
||
void wc_prsrw_attr(wc_window_t *win, const char *str, uint8_t y, uint8_t x, uint16_t len, uint8_t attr);
|
||
|
||
/**
|
||
* Вернуть физический адрес ячейки символа (y, x) внутри окна win.
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата.
|
||
*
|
||
* @param y строка (1-based)
|
||
* @param x столбец (1-based)
|
||
* @return адрес байта символа в видеобуфере
|
||
*/
|
||
uint16_t wc_gadrw(wc_window_t *win, uint8_t y, uint8_t x);
|
||
|
||
/**
|
||
* Нарисовать курсор в текущей позиции окна win.
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата.
|
||
*/
|
||
void wc_cursor(wc_window_t *win);
|
||
|
||
/**
|
||
* Стереть курсор (восстановить исходный символ/атрибут).
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата.
|
||
*/
|
||
void wc_curser(wc_window_t *win);
|
||
|
||
/**
|
||
* Меню выбора Да/Нет или ОК/Отмена.
|
||
*
|
||
* Работа в цикле (вызывать раз в кадр):
|
||
* 1. wc_yn(WC_YN_OK_CANCEL) — инициализация меню "ОК / Отмена"
|
||
* 2. wc_yn(WC_YN_YES_NO) — инициализация меню "Да / Нет"
|
||
* 3. В цикле: wc_yn(WC_YN_POLL) — опросить и перерисовать кнопки
|
||
* (вызывать каждый кадр, пока не будет нажата клавиша)
|
||
* 4. wc_yn(WC_YN_EXIT) — закрыть меню (скрыть кнопки)
|
||
*
|
||
* После WC_YN_POLL:
|
||
* Z=1 → нажато ОК / Да (A = 0)
|
||
* Z=0 → нажато Отмена / Нет (A != 0)
|
||
* Если клавиша ещё не нажата — никакого результата нет,
|
||
* нужно продолжать вызывать WC_YN_POLL в следующих кадрах.
|
||
*
|
||
* @param mode WC_YN_OK_CANCEL (0x01), WC_YN_YES_NO (0x02),
|
||
* WC_YN_POLL (0x00), WC_YN_EXIT (0xFF)
|
||
* @return 0 = ОК/Да нажато или ещё не нажато (Z=1),
|
||
* ненулевое = Отмена/Нет (Z=0)
|
||
*/
|
||
uint8_t wc_yn(uint8_t mode);
|
||
|
||
/**
|
||
* Встроенный редактор строки ввода.
|
||
*
|
||
* Имеет несколько режимов работы (передаются как mode):
|
||
*
|
||
* 0xFF — инициализировать тип 0: редактировать экранный буфер.
|
||
* win=SOW, DE=CURMAX<<8|CURNOW (макс.длина и текущая позиция).
|
||
* Рисует курсор. Дальнейшие вызовы: 0x00 (опрос).
|
||
*
|
||
* 0x00 — опросить клавиатуру. Вызывать раз в кадр.
|
||
* Возврат: A=0 — продолжает ввод, A!=0 — завершён.
|
||
* HL = текущий адрес курсора на экране.
|
||
*
|
||
* 0x01 — завершить ввод: стереть курсор.
|
||
* HL = адрес курсора на экране.
|
||
*
|
||
* 0xFD — инициализировать тип 2: редактировать буфер в памяти.
|
||
* HL=addr буфера, HL'=размер буфера,
|
||
* D=Y, E=X (позиция на экране),
|
||
* BC=CURMAX<<8|CURNOW.
|
||
*
|
||
* 0x02 — перерисовать блок редактора (обновить экран из буфера).
|
||
*
|
||
* 0xFE — инициализировать индикаторы (CAPS/INS/Lang/OVR).
|
||
* H=0: нижний заголовок, H=1: верхний.
|
||
*
|
||
* 0x03 — обновить индикаторы (вызывать раз в кадр).
|
||
*
|
||
* 0xFC — опросить состояние Caps/Ins/Ctrl+Shift.
|
||
* Возврат A: [7]=OVR, [6]=CAPS, [1:0]=язык.
|
||
*
|
||
* ⚠ НЕЛЬЗЯ одновременно вызывать 0x00 и 0xFC в одном кадре!
|
||
*
|
||
* @param win SOW-структура окна
|
||
* @param mode режим (0xFF, 0x00, 0x01, 0xFD, 0x02, 0xFE, 0x03, 0xFC)
|
||
*/
|
||
void wc_istr(wc_window_t *win, uint8_t mode);
|
||
|
||
/**
|
||
* Записать байт val в виде 2 шестнадцатеричных символов в экранный буфер.
|
||
* @param addr адрес в видеопамяти (в текущем экранном буфере)
|
||
* @param val значение, которое нужно отобразить как HEX (00–FF)
|
||
*
|
||
* Используется, например, для вывода шестнадцатеричного редактора.
|
||
*/
|
||
void wc_nork(uint16_t addr, uint8_t val);
|
||
|
||
/**
|
||
* Напечатать форматированный текст str в окне win начиная с (y, x).
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата. Вызывать при 3.5 МГц!
|
||
*
|
||
* Текст может содержать управляющие коды (см. раздел «Текстовая разметка»
|
||
* в заголовке файла): #0D (перенос строки), #0E (центрирование),
|
||
* #0B,XX (сдвиг вправо), #0C,YY (сдвиг вниз), #0x01-08 (цвета),
|
||
* #09 (инверсия), #FE,addr (ссылка).
|
||
*
|
||
* Структура win и строка str должны быть в #8000–#BFFF или #0000–#3FFF.
|
||
*
|
||
* @param y начальная строка в окне (1-based)
|
||
* @param x начальный столбец в окне (1-based)
|
||
* @return номер строки, следующей за последней напечатанной
|
||
*/
|
||
uint8_t wc_txtpr(wc_window_t *win, const char *str, uint8_t y, uint8_t x);
|
||
|
||
/**
|
||
* Напечатать n-е сообщение из блока текста str.
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата. Вызывать при 3.5 МГц!
|
||
*
|
||
* Блок состоит из абзацев, разделённых двойным нулём (0x00 0x00).
|
||
* msg_num задаёт, который по счёту абзац использовать (0-based).
|
||
*
|
||
* @param msg_num номер абзаца (0-based) в блоке текста
|
||
* @param str адрес начала текстового блока
|
||
* @param y начальная строка (1-based)
|
||
* @param x начальный столбец (1-based)
|
||
* @return номер строки после последней напечатанной
|
||
*/
|
||
uint8_t wc_mezz(wc_window_t *win, uint8_t msg_num, const char *str, uint8_t y, uint8_t x);
|
||
|
||
/**
|
||
* Прокрутить прямоугольную область внутри окна.
|
||
*
|
||
* ⚠ Включает основной текстовый экран на #C000 и оставляет его
|
||
* включённым после возврата. Вызывать при 3.5 МГц!
|
||
*
|
||
* Если step=0 и флаги [7:2] = 0 — автоматически используется DMA.
|
||
*
|
||
* @param y верхняя строка области (1-based)
|
||
* @param x левый столбец области (1-based)
|
||
* @param h высота области в строках
|
||
* @param w ширина области в символах
|
||
* @param flags битовые флаги:
|
||
* [7] = 1 → прокручивать атрибуты вместе с символами
|
||
* [6] = 1 → очистить исходную позицию после прокрутки
|
||
* [5:2] = шаг прокрутки (0=1 символ, 0xF=16 символов)
|
||
* [1:0] = направление: 00=вниз, 01=вверх, 10/11=зарезерв.
|
||
* При [7:2]=0 и step=0 DMA задействуется автоматически.
|
||
*/
|
||
void wc_scrlwow(wc_window_t *win, uint8_t y, uint8_t x, uint8_t h, uint8_t w, uint8_t flags);
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* КЛАВИАТУРА
|
||
* Все функции возвращают 0 = не нажато, ненулевое = нажато (или код клавиши).
|
||
* Автоповтор: у Space, стрелок, Tab, Enter, Bspc, F1-F10, Pgup/Pgdn, Home, End.
|
||
* Без автоповтора: Alt, Shift, Ctrl.
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
uint8_t wc_key_space(void); /* Space / Пробел */
|
||
uint8_t wc_key_up(void); /* Стрелка вверх */
|
||
uint8_t wc_key_down(void); /* Стрелка вниз */
|
||
uint8_t wc_key_left(void); /* Стрелка влево */
|
||
uint8_t wc_key_right(void); /* Стрелка вправо */
|
||
uint8_t wc_key_tab(void); /* Tab */
|
||
uint8_t wc_key_enter(void); /* Enter */
|
||
uint8_t wc_key_esc(void); /* Escape */
|
||
uint8_t wc_key_bspc(void); /* Backspace */
|
||
uint8_t wc_key_pgup(void); /* Page Up */
|
||
uint8_t wc_key_pgdn(void); /* Page Down */
|
||
uint8_t wc_key_home(void); /* Home */
|
||
uint8_t wc_key_end(void); /* End */
|
||
uint8_t wc_key_f1(void); /* F1 */
|
||
uint8_t wc_key_f2(void);
|
||
uint8_t wc_key_f3(void);
|
||
uint8_t wc_key_f4(void);
|
||
uint8_t wc_key_f5(void);
|
||
uint8_t wc_key_f6(void);
|
||
uint8_t wc_key_f7(void);
|
||
uint8_t wc_key_f8(void);
|
||
uint8_t wc_key_f9(void);
|
||
uint8_t wc_key_f10(void); /* F10 */
|
||
uint8_t wc_key_alt(void); /* Alt (без автоповтора) */
|
||
uint8_t wc_key_shift(void); /* Shift (без автоповтора) */
|
||
uint8_t wc_key_ctrl(void); /* Ctrl (без автоповтора) */
|
||
|
||
/**
|
||
* Сканировать клавиатуру, вернуть код нажатой клавиши.
|
||
* @param mode WC_KBSCN_NORMAL (с учётом SHIFT/CL/Lang) или WC_KBSCN_RAW
|
||
* @return код клавиши, 0 = ничего не нажато
|
||
*/
|
||
uint8_t wc_kbscn(uint8_t mode);
|
||
|
||
uint8_t wc_key_del(void); /* Delete */
|
||
uint8_t wc_key_caps(void); /* Caps Lock */
|
||
uint8_t wc_key_any(void); /* Любая клавиша */
|
||
void wc_key_wait_release(void); /* Ждать отпускания всех клавиш */
|
||
uint8_t wc_key_wait_any(void); /* Ждать нажатия любой клавиши */
|
||
uint8_t wc_key_ins(void); /* Insert */
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* ФАЙЛОВЫЕ ОПЕРАЦИИ
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/**
|
||
* Загрузить blocks блоков по 512 байт из текущего потока в dest.
|
||
*
|
||
* @param dest адрес буфера назначения
|
||
* @param blocks количество блоков (blocks * 512 = байт)
|
||
* @return A = 0 — ОК, продолжение
|
||
* A = WC_EOF (0x0F) — нормальный конец цепочки FAT
|
||
* (на последней секторной загрузке!)
|
||
* A = другое — реальная ошибка чтения
|
||
*
|
||
* HL при возврате = новое значение dest (указывает на следующий байт
|
||
* после загруженных данных).
|
||
*
|
||
* Пример проверки ошибок:
|
||
* rc = wc_load512(addr, n);
|
||
* if (rc && rc != WC_EOF) { } // I/O error
|
||
*/
|
||
uint8_t wc_load512(uint16_t dest, uint8_t blocks);
|
||
|
||
/**
|
||
* Сохранить blocks блоков по 512 байт из src в текущий поток.
|
||
*
|
||
* HL при возврате = новое значение src (указывает на следующий байт
|
||
* после сохранённых данных).
|
||
*
|
||
* @param src адрес буфера источника
|
||
* @param blocks количество блоков
|
||
*/
|
||
void wc_save512(uint16_t src, uint8_t blocks);
|
||
|
||
/**
|
||
* Перейти к началу файла плагина (позиционировать поток на первый блок).
|
||
* Используется после открытия файла WC для повторного чтения.
|
||
*/
|
||
void wc_gipagpl(void);
|
||
|
||
/** Прочитать ENTRY (32 байта) файла в буфер по адресу addr */
|
||
void wc_tentry(uint16_t addr);
|
||
|
||
/**
|
||
* Обойти цепочку секторов, записать в buf список секторов.
|
||
* @param buf адрес буфера назначения
|
||
* @param bufend адрес конца буфера
|
||
*/
|
||
void wc_chtosep(uint16_t buf, uint16_t bufend);
|
||
|
||
/**
|
||
* Получить заголовок помеченного файла.
|
||
* @param panel IX = структура панели WC
|
||
* @param filenum номер файла в каталоге
|
||
* @param namebuf буфер для имени файла
|
||
*/
|
||
void wc_tmrkdfl(uint16_t panel, uint16_t filenum, uint16_t namebuf);
|
||
|
||
/**
|
||
* Управление директорией / позиционирование.
|
||
* @param mode WC_ADIR_SEEK_START или WC_ADIR_RESET_NEXT
|
||
*/
|
||
void wc_adir(uint8_t mode);
|
||
|
||
/**
|
||
* Открыть/переключить файловый поток.
|
||
*
|
||
* Параметр mode задаёт тип потока (передаётся внутри в регистр D):
|
||
* WC_STREAM_ROOT (0xFF) — корневой поток FAT
|
||
* WC_STREAM_CLONE (0xFE) — клонировать текущий поток
|
||
* WC_STREAM_WCDIR (0xFD) — каталог WC
|
||
* 0x00 / 0x01 — номер потока 0 или 1
|
||
*
|
||
* Если BC = 0xFFFF --- только переключить поток без пересоздания.
|
||
* Если BC ≠ 0xFFFF --- создать или пересоздать поток.
|
||
* (BC сейчас захардкожено в wc_api.s; уточните, если нужен другой режим.)
|
||
*
|
||
* @param mode один из WC_STREAM_* или 0/1
|
||
*/
|
||
void wc_stream(uint8_t mode);
|
||
|
||
/**
|
||
* Найти следующий файл/каталог в текущей директории.
|
||
*
|
||
* ⚠ ВНИМАНИЕ: ГРОБИТ область #0000–#1FFF на странице с драйвером!
|
||
* Не вызывать, если в этом диапазоне хранятся важные данные!
|
||
*
|
||
* @param entry_buf адрес буфера для заголовка файла (32+ байт)
|
||
* @param flags фильтр:
|
||
* [7] = 1 → только короткие имена
|
||
* [4] = 1 → загрузить время создания
|
||
* [3] = 1 → загрузить дату создания
|
||
* [2] = 1 → загрузить размер файла
|
||
* [1:0] = 00 → все объекты; 01 → только файлы;
|
||
* 10 → только каталоги
|
||
* @return 0 (Z=1) = конец директории;
|
||
* ненулевое = найден файл/каталог
|
||
*/
|
||
uint8_t wc_findnext(uint16_t entry_buf, uint8_t flags);
|
||
|
||
/**
|
||
* Найти файл по имени в текущей директории.
|
||
* @param name_with_flag адрес строки вида: [1 байт флагов][имя][0]
|
||
* @return 0 = не найден, ненулевое = найден; после вызова DE=entry, HL=size
|
||
*/
|
||
uint8_t wc_fentry(uint16_t name_with_flag);
|
||
|
||
/** Пропустить n секторов по 512 байт в текущем потоке */
|
||
void wc_loadnone(uint8_t sectors);
|
||
|
||
/**
|
||
* Открыть файл, найденный последним wc_fentry().
|
||
* Позиционирует поток чтения на найденный файл.
|
||
*/
|
||
void wc_gfile(void);
|
||
|
||
/**
|
||
* Войти в каталог, найденный последним wc_fentry().
|
||
*/
|
||
void wc_gdir(void);
|
||
|
||
/**
|
||
* Создать файл.
|
||
* @param name_with_flag [1 байт флагов][длина][имя][0]
|
||
* @return 0 = OK, ненулевое = ошибка
|
||
*/
|
||
uint8_t wc_mkfile(uint16_t name_with_flag);
|
||
|
||
/**
|
||
* Создать каталог.
|
||
* @param name указатель на имя каталога (ZS-строка)
|
||
* @return 0 = OK, ненулевое = ошибка
|
||
*/
|
||
uint8_t wc_mkdir(uint16_t name);
|
||
|
||
/**
|
||
* Переименовать файл/каталог.
|
||
* @param old_name [1 байт флагов][старое имя][0]
|
||
* @param new_name [новое имя][0]
|
||
* @return 0 = OK (Z), ненулевое = ошибка
|
||
*/
|
||
uint8_t wc_rename(uint16_t old_name, uint16_t new_name);
|
||
|
||
/**
|
||
* Удалить файл.
|
||
* @param name_with_flag [1 байт флагов][имя][0]
|
||
* @return 0 = OK (Z), ненулевое = ошибка
|
||
*/
|
||
uint8_t wc_delfl(uint16_t name_with_flag);
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* ГРАФИКА
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/**
|
||
* Переключить видеорежим.
|
||
* @param mode WC_VIDEO_TXT / WC_VIDEO_BUF1..4
|
||
*/
|
||
void wc_mngv_pl(uint8_t mode);
|
||
|
||
/**
|
||
* Отобразить видеостраницу vpage на адрес #C000.
|
||
* @param vpage номер страницы (0x00–0x3F)
|
||
*/
|
||
void wc_mngcvpl(uint8_t vpage);
|
||
|
||
/**
|
||
* Установить видеорежим TSConfig.
|
||
* @param mode байт VConfig (TSCONF_VM_* | TSCONF_RRES_* | ...)
|
||
*/
|
||
void wc_gvmod(uint8_t mode);
|
||
|
||
/** Установить Y-смещение прокрутки графики */
|
||
void wc_gyoff(uint16_t y);
|
||
|
||
/** Установить X-смещение прокрутки графики */
|
||
void wc_gxoff(uint16_t x);
|
||
|
||
/** Установить страницу тайловой карты */
|
||
void wc_gvtm(uint8_t page);
|
||
|
||
/**
|
||
* Установить страницу графики тайловой плоскости.
|
||
* @param plane 0 = плоскость 0, 1 = плоскость 1
|
||
* @param page номер страницы
|
||
*/
|
||
void wc_gvtl(uint8_t plane, uint8_t page);
|
||
|
||
/** Установить страницу графики спрайтов */
|
||
void wc_gvsgp(uint8_t page);
|
||
|
||
/** Отобразить видеостраницу vpage на адрес #0000 */
|
||
void wc_mng0vpl(uint8_t vpage);
|
||
|
||
/** Отобразить видеостраницу vpage на адрес #8000 */
|
||
void wc_mng8vpl(uint8_t vpage);
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* DMA
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/**
|
||
* Настройка и запуск DMA TSConfig.
|
||
*
|
||
* Подфункции DMA (передаются как subfunc):
|
||
*
|
||
* Конфигурация:
|
||
* 0x00 — задать src+dst: B=src_page, HL=src_addr, C=dst_page, DE=dst_addr
|
||
* 0x01 — задать только src
|
||
* 0x02 — задать только dst
|
||
* 0x03 — src из координат окна (адрес → окно WC)
|
||
* 0x04 — dst из координат окна
|
||
* 0x05 — задать DMA_T (тип тайла/спрайта)
|
||
* 0x06 — задать DMA_N (число объектов)
|
||
* 0x07 — задать T + N
|
||
* 0x08 — выравнивание источника
|
||
* 0x09 — выравнивание назначения
|
||
* 0x0A — выравнивание размера
|
||
* 0x0B — задать все параметры
|
||
*
|
||
* Запуск:
|
||
* 0xFC — RAM→RAM (с ожиданием завершения)
|
||
* 0xFB — BLT→RAM
|
||
* 0xFA — FILL (заполнение)
|
||
* 0xF9 — RAM→CRAM (палитра)
|
||
* 0xF8 — RAM→SFILE (спрайты)
|
||
* 0xFD — запустить без ожидания (следует вызвать 0xFF для синхронизации)
|
||
* 0xFE — запустить с ожиданием
|
||
* 0xFF — ждать готовности DMA (busy-wait)
|
||
*
|
||
* Обычная последовательность:
|
||
* // Настройка src/dst выполняется перед вызовом через регистры SDCC
|
||
* wc_dmapl(0xFC); // запустить и подождать
|
||
*/
|
||
void wc_dmapl(uint8_t subfunc);
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* РАЗНОЕ
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/**
|
||
* Управление тактовой частотой CPU или AY через WC.
|
||
*
|
||
* WC управляет своими собственными настройками турбо и НЕ влияет
|
||
* на отображение экрана. Никаких конфликтов с WC по выбору частоты нет.
|
||
* WC запоминает выбранный режим и восстанавливает его при 0xFF.
|
||
*
|
||
* @param mode WC_TURBO_CPU (0x00) — выбрать частоту процессора:
|
||
* param = 0: 3.5 МГц
|
||
* param = 1: 7 МГц
|
||
* param = 2: 14 МГц ← для быстрых вычислений
|
||
* param = 3: 28 МГц
|
||
* WC_TURBO_AY (0x01) — выбрать частоту AY:
|
||
* param = 0: 1.750 МГц
|
||
* param = 1: 1.773 МГц
|
||
* param = 2: 3.5 МГц
|
||
* param = 3: 3.546 МГц
|
||
* WC_TURBO_RESTORE (0xFF) — восстановить режимы CPU+AY
|
||
* из настроек WC (игнорирует param)
|
||
*
|
||
* @param param параметр частоты (0–3); игнорируется при RESTORE
|
||
*/
|
||
void wc_turbopl(uint8_t mode, uint8_t param);
|
||
|
||
/**
|
||
* Получить параметр из INI-файла плагина.
|
||
* @param param_num номер параметра
|
||
* @return номер опции (0-based), 0xFF если параметр не задан
|
||
*/
|
||
uint8_t wc_prm_pl(uint8_t param_num);
|
||
|
||
/**
|
||
* Управление прерываниями WC.
|
||
*
|
||
* ⚠ По выходу из плагина (возврат из main) WC автоматически
|
||
* восстанавливает все параметры INT, установленные этой функцией!
|
||
*
|
||
* @param mode WC_INT_DISABLE_ALL (0x00) — отключить все прерывания WC
|
||
* WC_INT_NO_TIME (0x01) — отключить таймерное INT
|
||
* WC_INT_NO_PS2 (0x02) — отключить PS/2 INT
|
||
* WC_INT_PLUGIN (0xFF) — установить свой обработчик;
|
||
* в этом случае использовать wc_int_pl_handler(addr)
|
||
*/
|
||
void wc_int_pl(uint8_t mode);
|
||
|
||
/**
|
||
* Установить ASM-обработчик прерываний плагина.
|
||
* Вызывать после wc_int_pl(WC_INT_PLUGIN).
|
||
*
|
||
* Обработчик должен заканчиваться на RET (не RETI).
|
||
* Всё, что нужно сохранить — регистры; стек WC НЕ менять.
|
||
*
|
||
* @param handler_addr адрес ASM-обработчика в памяти плагина.
|
||
*/
|
||
void wc_int_pl_handler(uint16_t handler_addr);
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* ВСПОМОГАТЕЛЬНЫЕ МАКРОСЫ
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/**
|
||
* Атрибут цвета (EGA-формат): bg[7:4] | fg[3:0]
|
||
* @param bg цвет фона (0–15)
|
||
* @param fg цвет текста (0–15)
|
||
* Пример: WC_COLOR(WC_BLUE, WC_BRIGHT_WHITE) = 0x1F
|
||
*/
|
||
#define WC_COLOR(bg, fg) ((uint8_t)(((bg) << 4) | (fg)))
|
||
|
||
/* 16 цветов (YGRB: Bright, Green, Red, Blue) */
|
||
#define WC_BLACK 0
|
||
#define WC_BLUE 1
|
||
#define WC_RED 2
|
||
#define WC_MAGENTA 3
|
||
#define WC_GREEN 4
|
||
#define WC_CYAN 5
|
||
#define WC_YELLOW 6
|
||
#define WC_WHITE 7
|
||
#define WC_DARK_GRAY 8
|
||
#define WC_BRIGHT_BLUE 9
|
||
#define WC_BRIGHT_RED 10
|
||
#define WC_BRIGHT_MAGENTA 11
|
||
#define WC_BRIGHT_GREEN 12
|
||
#define WC_BRIGHT_CYAN 13
|
||
#define WC_BRIGHT_YELLOW 14
|
||
#define WC_BRIGHT_WHITE 15
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* Параметры плагина (заполняются crt0.s при вызове плагина WC)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Передаются WC через регистры:
|
||
* A' → wc_file_ext (индекс расширения в списке WC)
|
||
* BC → wc_file_name (указатель на z-строку с именем файла)
|
||
* HL → wc_file_size (младшее слово, 16 бит)
|
||
* DE → wc_file_size+2 (старшее слово, 16 бит; для файлов > 64 КБ)
|
||
*
|
||
* wc_file_size занимает 4 байта в _DATA (32-bit LE):
|
||
* lo = *(uint16_t *)&wc_file_size
|
||
* hi = *((uint16_t *)&wc_file_size + 1)
|
||
*/
|
||
extern uint8_t wc_file_ext; /* индекс расширения */
|
||
extern char * wc_file_name; /* char *: указатель на имя файла */
|
||
extern uint32_t wc_file_size; /* 32-bit LE: [+0]=lo, [+2]=hi */
|
||
|
||
/* Код возврата плагина: запись в wc_exit_code перед return из main() */
|
||
extern uint8_t wc_exit_code;
|
||
|
||
/** Номер текущего объекта в панели (от 1). Передаётся WC в HL'. */
|
||
extern uint16_t wc_file_idx;
|
||
/** Количество объектов в панели (включая ".."). Передаётся WC в DE'.
|
||
* Если wc_file_idx == wc_file_count — это последний файл. */
|
||
extern uint16_t wc_file_count;
|
||
|
||
#define WC_EXIT_ESC 0 /* закрыть плагин / выйти (стоп) */
|
||
#define WC_EXIT_UNRECOGNIZED 1 /* файл не распознан → другому плагину */
|
||
#define WC_EXIT_NEXT 2 /* перейти к следующему файлу */
|
||
#define WC_EXIT_RELOAD_DIR 3 /* перечитать каталог WC */
|
||
#define WC_EXIT_PREV 4 /* перейти к предыдущему файлу */
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* СИСТЕМНЫЕ ПЕРЕМЕННЫЕ — inline чтение через volatile-указатели
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Эти макросы читают системную область WC (#6000+) напрямую:
|
||
*/
|
||
|
||
/** Текущая страница в окне 0 (#0000–#3FFF) */
|
||
#define wc_get_pg0() (*(volatile uint8_t *)WC_SYS_PG0)
|
||
/** Текущая страница в окне 1 (#4000–#7FFF) */
|
||
#define wc_get_pg4() (*(volatile uint8_t *)WC_SYS_PG4)
|
||
/** Текущая страница в окне 2 (#8000–#BFFF) */
|
||
#define wc_get_pg8() (*(volatile uint8_t *)WC_SYS_PG8)
|
||
/** Текущая страница в окне 3 (#C000–#FFFF) */
|
||
#define wc_get_pgc() (*(volatile uint8_t *)WC_SYS_PGC)
|
||
|
||
/** Флаг ESC (ABT): 1 = пользователь нажал ESC */
|
||
#define wc_get_abt() (*(volatile uint8_t *)WC_SYS_ABT)
|
||
/** Флаг ENTER (ENT): 1 = пользователь нажал ENTER */
|
||
#define wc_get_ent() (*(volatile uint8_t *)WC_SYS_ENT)
|
||
|
||
/** Таймер INT (инкрементируется каждым прерыванием) */
|
||
#define wc_get_timer() (*(volatile uint16_t *)WC_SYS_TMN)
|
||
|
||
/** Страница FAT engine в окне 0 */
|
||
#define wc_get_fep() (*(volatile uint8_t *)WC_SYS_FEP)
|
||
|
||
/** Конфигурация видео (CNFv): 0=PWM, 1=3bit, ..., 7=VDAC2 */
|
||
#define wc_get_cnfv() (*(volatile uint8_t *)WC_SYS_CNFV)
|
||
|
||
/** Высота экрана в строках (25, 30 или 36) */
|
||
#define wc_get_height() (*(volatile uint8_t *)WC_SYS_HEI)
|
||
|
||
/** Текстовый режим (TXTmd) */
|
||
#define wc_get_txtmode() (*(volatile uint8_t *)WC_SYS_TXTMD)
|
||
|
||
/** SD1 driver state */
|
||
#define wc_get_sd1_state() (*(volatile uint8_t *)WC_SYS_SDBSF)
|
||
/** SD2 driver state */
|
||
#define wc_get_sd2_state() (*(volatile uint8_t *)WC_SYS_SDBSF2)
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* ВСПОМОГАТЕЛЬНЫЕ МАКРОСЫ ДЛЯ FAT
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/**
|
||
* Собрать 32-битный кластер из двух 16-битных полей FAT entry.
|
||
* @param hi cluster_hi (CLSDE, +20)
|
||
* @param lo cluster_lo (CLSHL, +26)
|
||
*/
|
||
#define WC_FAT_CLUSTER(hi, lo) ((uint32_t)(hi) << 16 | (uint32_t)(lo))
|
||
|
||
/**
|
||
* Построить буфер с флагом для wc_fentry / wc_mkfile / wc_delfl.
|
||
* Пример:
|
||
* static uint8_t buf[] = WC_FAT_NAME(WC_FILE_FLAG, "readme.txt");
|
||
* Раскрывается в: { 0x00, 'r','e','a','d','m','e','.','t','x','t', 0 }
|
||
*/
|
||
#define WC_FAT_NAME(flag, name) { (flag), name "\0" }
|
||
|
||
/**
|
||
* Построить буфер для wc_mkfile (flag + size + name).
|
||
* Пример:
|
||
* static uint8_t buf[32];
|
||
* wc_mkfile_buf(buf, 1024, "output.bin");
|
||
*/
|
||
#define wc_mkfile_buf(buf, sz, nm) do { \
|
||
(buf)[0] = WC_FILE_FLAG; \
|
||
*(uint32_t*)&(buf)[1] = (uint32_t)(sz); \
|
||
uint8_t _i = 0; \
|
||
while ((nm)[_i]) { (buf)[5 + _i] = (nm)[_i]; _i++; } \
|
||
(buf)[5 + _i] = 0; \
|
||
} while(0)
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* РЕЗИДЕНТНЫЙ ПЕРЕХОД / ВЫЗОВ (для многостраничных плагинов)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* Для плагинов, занимающих несколько страниц в #8000–#BFFF:
|
||
*
|
||
* Резидент перехода (#6020):
|
||
* A = номер страницы плагина (от 0)
|
||
* HL = адрес перехода (#8000–#BFFF)
|
||
* Выполняет: переключение страницы в окне 2, JP (HL)
|
||
*
|
||
* Резидент вызова (#6028):
|
||
* A = номер страницы плагина (от 0)
|
||
* HL = адрес вызова (#8000–#BFFF)
|
||
* Выполняет: переключение, CALL (HL), возврат обратно
|
||
* Сохраняет все регистры кроме A и HL!
|
||
*
|
||
* Пример:
|
||
* // Вызвать функцию load_data на странице 2 плагина
|
||
* wc_resident_call(2, (uint16_t)&load_data);
|
||
*/
|
||
|
||
/** Перейти (JP) в код на другой странице плагина (без возврата!) */
|
||
void wc_resident_jump(uint8_t page, uint16_t addr);
|
||
|
||
/** Вызвать (CALL) код на другой странице плагина (с возвратом) */
|
||
void wc_resident_call(uint8_t page, uint16_t addr);
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* LOAD256 / LOADNONE (дополнительные файловые функции)
|
||
* ══════════════════════════════════════════════════════════════════════ */
|
||
|
||
/**
|
||
* Загрузить blocks блоков по 256 байт (используется видео плеером).
|
||
* Параметры и возврат аналогичны wc_load512.
|
||
*/
|
||
uint8_t wc_load256(uint16_t dest, uint8_t blocks);
|
||
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
* MNG0VPL / MNG8VPL (видеостраницы в другие окна)
|
||
* ══════════════════════════════════════════════════════════════════════
|
||
*
|
||
* ⚠ MNG0VPL (Win 0, #0000–#3FFF):
|
||
* — WC API сохраняет/восстанавливает Win 0 при каждом CALL #6006
|
||
* — Но GEDPL затирает #1000–#1447!
|
||
* — Нельзя передавать через #0000–#3FFF параметры WC-функциям
|
||
* (SOW, строки, буферы), т.к. WC ремапит окно внутри вызова
|
||
* — Безопасно для данных плагина МЕЖДУ вызовами WC API
|
||
*
|
||
* ⚠ MNGCVPL (Win 3, #C000–#FFFF):
|
||
* — WC API сбрасывает Win 3 на TXT-страницу (#00) при выходе
|
||
* из КАЖДОГО вызова P8000 и НЕ восстанавливает!
|
||
* — После любого CALL #6006 нужно заново вызвать mngc_pl()
|
||
* — Удобно для загрузки: mngcvpl(N) → load512(0xC000, 32)
|
||
*
|
||
* См. разделы «КАРТА АДРЕСНОГО ПРОСТРАНСТВА» и «P8000 DISPATCH».
|
||
*/
|
||
|
||
|
||
|
||
|
||
|
||
|
||
void wc_strset(char *dsr, uint16_t len, char c);
|
||
|
||
|
||
#endif /* WC_API_H */
|