Files
VGMPLAY.WMF/doc/03_WC_API_Reference.md

1151 lines
41 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WC API — Полный справочник функций
> Источники: `inc/wc_api.h` (1878 стр.), `asm/wc_api.s` (1339 стр.),
> `DiskRef/WC_History.txt` (история изменений API)
## Вызов функций
Все функции вызываются через точку доступа **#6006** (`JP` к диспетчеру):
```asm
WLD EQU #6006
; В регистр A загружается номер функции
; Остальные параметры - в соответствующие регистры
LD A, функция_номер
JP WLD
```
**Регистровые соглашения:**
- **Портит**: AF, BC, DE, HL, IX
- **Сохраняет**: IY, AF’, BC’, DE’, HL’, SP
- Функции с параметром в **A’** используют `EX AF,AF'` перед вызовом
> ⚠️ **Win 3 (#C000) сбрасывается** на текстовую страницу после **каждого** вызова
> `CALL #6006`. Плагин обязан повторить `mngcvpl()`/`mngc_pl()` после любого API-вызова.
## Категории функций
1. [Управление памятью](#управление-памятью)
2. [Работа с окнами](#работа-с-окнами)
3. [Работа с клавиатурой](#работа-с-клавиатурой)
4. [Файловые операции](#файловые-операции)
5. [Работа с графикой](#работа-с-графикой)
6. [Системные функции](#системные-функции)
7. [DMA операции](#dma-операции)
8. [Константы и структуры](#константы-и-структуры)
9. [Таблица кодов функций](#таблица-кодов-функций)
---
## Управление памятью
### #00 - MNGC_PL
Включение страницы плагина на #C000
**Вход:**
- A' - номер страницы (от 0)
- #FF - страница с фонтом (нельзя использовать #E000-#FFFF!)
- #FE - первый текстовый экран (с панелями)
**Пример:**
```asm
MNGC_PL: EXA
LD A,0 ; Страница 0
CALL WLD
EXA
RET
```
### #78 - MNG0_PL
Включение страницы плагина на #0000
**Вход:**
- A' - номер страницы (от 0)
**Важно:** Все структуры для файловых функций должны лежать в #8000-#FFFF!
### #79 - MNG8_PL
Включение страницы плагина на #8000
**Вход:**
- A' - номер страницы (от 0)
---
## Работа с окнами
### Структура окна (SOW - Structure Of Window)
```asm
; Базовая структура (для типа 0)
SOW:
DB 0 ; +0: Флаги окна
DB 0 ; +1: Маска цвета курсора
DB 255 ; +2: X позиция (255=центр)
DB 255 ; +3: Y позиция (255=центр)
DB 40 ; +4: Ширина (0=весь экран)
DB 20 ; +5: Высота (0=весь экран)
DB %01111111 ; +6: Цвет (PAPER+INK)
DB 0 ; +7: Резерв (всегда 0)
DW #0000 ; +8: Адрес буфера (#0000=не выведено, #FFFF=без буфера)
DB 0 ; +10: Линия разделитель 1
DB 0 ; +11: Линия разделитель 2 (смещение снизу)
DB 1 ; +12: Позиция курсора (от 1)
DB 20 ; +13: Нижний ограничитель
DB %01011000 ; +14: Цвет курсора
DB %01111111 ; +15: Цвет под курсором
```
**Флаги окна (+0):**
```
[7]: %1 - окно с тенью
[6]: %1 - курсор во всю ширину
[5]: резерв
[4]: %1 - окно с инверсной шапкой
[3-0]: Тип окна:
0 - стандартное окно, рамки 1-го типа
1 - окно с заголовками и текстом (без курсора)
2 - окно с заголовками и текстом + курсор
3 - стандартное окно, рамки 2-го типа
4 - окно с заголовками (рамки 2-го типа)
5 - окно с заголовками + курсор (рамки 2-го типа)
6 - стандартное окно, рамки 3-го типа
7 - окно с заголовками (рамки 3-го типа)
8 - окно с заголовками + курсор (рамки 3-го типа)
```
### #01 - PRWOW
Вывод окна на экран
**Вход:**
- IX - адрес структуры окна (SOW) в #8000-#BFFF или #0000-#3FFF
**Примечание:** Включает основной TXT экран в #C000 и оставляет его по выходу!
### #02 - RRESB
Стирание окна (восстановление информации)
**Вход:**
- IX - адрес SOW
**Примечание:** Включает основной TXT экран в #C000!
### #03 - PRSRW
Печать строки в окне
**Вход:**
- IX - адрес SOW
- HL - адрес текста (в #8000-#BFFF или #0000-#3FFF)
- D - Y координата
- E - X координата
- BC - длина строки
### #04 - PRIAT
Выставление цвета (после PRSRW)
**Вход:**
- A' - цвет (PAPER+INK)
- Использует координаты и длину из PRSRW
### #05 - GADRW
Получение адреса в окне
**Вход:**
- IX - адрес SOW
- D - Y координата
- E - X координата
**Выход:**
- HL - адрес в памяти
### #06 - CURSOR
Печать курсора
**Вход:**
- IX - адрес SOW
### #07 - CURSER
Стирание курсора
**Вход:**
- IX - адрес SOW
### #0B - TXTPR
Вывод текста с разметкой в окне
**Вход:**
- IX - адрес SOW
- HL - адрес текста (в #8000-#BFFF или #0000-#3FFF)
- D - Y (внутри окна)
- E - X (внутри окна)
**Выход:**
- D - Y (следующая строка)
- E - X (без изменений)
**Коды разметки текста:**
```
#00 - конец строки и абзаца
#00,#00 - разделитель между сообщениями
#0B,XX - сдвиг вправо на XX символов
#0C,YY - сдвиг вниз на YY строк
#0D - перенос строки
#0E - центрирование строки
#09 - инверсия цвета
#01-#08 - цвет чернил (1=синий, 7=белый, 8=черный)
#01-#08,#01-#08 - папер+инк
#FE,XXXX - ссылка на строку (XXXX - адрес)
```
---
## Работа с клавиатурой
Все функции возвращают **NZ** если клавиша нажата, **Z** если нет.
| Функция | Код | Клавиша |
|---------|-----|---------|
| SPKE | #10 | SPACE |
| UPPP | #11 | UP Arrow |
| DWWW | #12 | DOWN Arrow |
| LFFF | #13 | LEFT Arrow |
| RGGG | #14 | RIGHT Arrow |
| TABK | #15 | TAB |
| ENKE | #16 | ENTER |
| ESC | #17 | ESCAPE |
| BSPC | #18 | BACKSPACE |
| PGU | #19 | PAGE UP |
| PGD | #1A | PAGE DOWN |
| HOME | #1B | HOME |
| END | #1C | END |
| F1-F10 | #1D-#26 | F1-F10 |
| ALT | #27 | ALT |
| SHIFT| #28 | SHIFT |
| CTRL | #29 | CTRL |
| DEL | #2B | DELETE |
| INS | #55 | INSERT |
| CAPS | #2C | CAPS LOCK |
| ANYK | #2D | Любая клавиша |
| USPO | #2E | Пауза до отпускания клавиш |
| NUSP | #2F | Ожидание любой клавиши |
### #2A - KBSCN
Сканирование клавиатуры
**Вход:**
- A' - режим обработки
- #00 - учитывает SHIFT, CAPS, ENG/RUS (вызывать 1 раз в фрейм)
- #01 - всегда выдает код из таблицы (можно вызывать много раз)
**Выход:**
- NZ: A - код клавиши
- Z: A - #00 (неизвестная клавиша) или #FF (буфер пуст)
**Пример:**
```asm
WAIT_KEY:
EI
HALT
LD A,1
CALL KBSCN
CP 'm' ; Ждем 'm'
JR NZ,WAIT_KEY
```
---
## Файловые операции
### #30 - LOAD512
Потоковая загрузка файла
**Вход:**
- HL - адрес буфера
- B - количество блоков (по 512 байт)
**Выход:**
- HL - новое значение адреса
- A - #0F если конец файла
### #31 - SAVE512
Потоковая запись файла
**Вход:**
- HL - адрес буфера
- B - количество блоков (по 512 байт)
**Выход:**
- HL - новое значение адреса
- A - #0F если конец файла
### #32 - GIPAGPL
Позиционирование на начало файла
Устанавливает указатель на начало файла, переданного плагину.
### #3B - FENTRY
Поиск файла/каталога
**Вход:**
- HL - адрес структуры: flag(1), name(1-255), #00
- flag: #00 = файл, #10 = каталог
**Выход:**
- Z - файл не найден
- NZ - файл найден, [DE,HL] = размер файла
- Вызовите GFILE/GDIR для активации
**Пример:**
```asm
LD HL,FILE_STRUCT
LD A,#3B
CALL WLD
JR Z,NOT_FOUND
; Файл найден
CALL GFILE ; Активировать файл
...
FILE_STRUCT:
DB #00 ; Файл
DB "music.vgm",0
```
### #3E - GFILE
Активация найденного файла
Устанавливает указатель на начало файла, найденного FENTRY.
### #3F - GDIR
Активация найденного каталога
Делает каталог, найденный FENTRY, активным.
### #48 - MKfile
Создание файла
**Вход:**
- HL - адрес структуры: flag(1), length(4), name(1-255), #00
**Выход:**
- A - код ошибки
- Z - файл создан
- NZ - ошибка
### #39 - STREAM
Работа с потоками
**Вход:**
- D - команда:
- #FF - активировать root dir
- #FE - клонировать поток в #00 и #01
- #FD - активировать поток INI файла
- #00/#01 - номер потока, требует BC
- BC (для #00/#01):
- B - устройство (0=SD, 1=IDE Master, 2=IDE Slave)
- C - раздел
- #FFFF - просто включить поток
**Выход:**
- Z - поток активен
- NZ - ошибка
---
## Работа с графикой
### #40 - MNGV_PL
Включение видео страницы
**Вход:**
- A' - номер видео страницы:
- #00 - основной экран (TXT)
- #01 - видео буфер 1 (16 страниц)
- #02 - видео буфер 2 (16 страниц)
- #03 - видео буфер 3 (16 страниц)
- #04 - видео буфер 4 (16 страниц)
### #41 - MNGCVPL
Включение страницы видео буфера на #C000
**Вход:**
- A' - номер страницы:
- #00-#0F - из буфера 1
- #10-#1F - из буфера 2
- #20-#2F - из буфера 3
- #30-#3F - из буфера 4
### #42 - GVmod
Включение видео режима
**Вход:**
- A' - видео режим:
```
[7-6]: Разрешение
%00 - 256x192
%01 - 320x200
%10 - 320x240
%11 - 360x288
[1-0]: Тип
%00 - ZX
%01 - 16c
%10 - 256c
%11 - txt
```
---
## Системные функции
### #0E - TURBOPL
Управление частотой процессора
**Вход:**
- B - выбор Z80/AY:
- #00 (`WC_TURBO_CPU`) - частота Z80:
- C = %00 (3.5 МГц), %01 (7 МГц), %10 (14 МГц), %11 (28 МГц)
- #01 (`WC_TURBO_AY`) - частота AY:
- C = %00 (1.75 МГц), %01 (1.7733 МГц), %10 (3.5 МГц), %11 (3.546 МГц)
- #FF (`WC_TURBO_RESTORE`) - восстановить значения из настроек WC
> AY частоты 1.7733/3.546 МГц — это NTSC-кварц (315/88 МГц ÷ 2).
### #0F - GEDPL
Восстановление текстового режима
**Важно:** Обязательно вызывать при запуске плагина!
Восстанавливает палитру, оффсеты, включает TXT режим.
**Примечание:** Гробит область #1000-#1447!
### #56 - INT_PL
Работа с прерываниями
**Вход:**
- A' - команда:
- #00 - отключить все INT функции
- #01 - отключить обновление времени
- #02 - отключить опрос PS/2 клавиатуры
- #FF - установить обработчик INT от плагина
- HL - адрес обработчика (#8000-#BFFE)
**Примечание:** Все параметры восстанавливаются при выходе из плагина.
### #53 - PRM_PL
Запрос параметров запуска
**Вход:**
- A' - номер параметра (1-8)
**Выход:**
- Z - параметр не найден
- NZ - параметр получен
- A - номер выбранной опции (1-10)
---
## DMA операции
### #0D - DMAPL
Работа с DMA
**Инициализация:**
- A' = #00: инит S и D (BHL=Source, CDE=Destination)
- A' = #01: инит S (BHL)
- A' = #02: инит D (CDE)
- A' = #05: DMA_T (B = количество бёрстов, 0=1...255=256)
- A' = #06: DMA_N (B = размер бёрста)
Формат B/C для #00-#02:
```
[7]: %1 - страница из блока плагина (0-5)
%0 - страница из видео буферов (0-63)
[6-0]: номер страницы
```
**Запуск:**
- A' = #FC: RAM→RAM
- A' = #FE: RAM→RAM с ожиданием
- A' = #FF: ожидание готовности DMA
**Выход:**
- Z - операция завершена
- NZ - DMA не готов
**Пример:**
```asm
; Копирование 4KB из страницы 0 в страницу 1
LD B,#80 ; Страница 0 плагина
LD HL,#8000 ; Адрес источника
LD C,#81 ; Страница 1 плагина
LD DE,#8000 ; Адрес назначения
EXA
LD A,#00 ; Инит S и D
CALL WLD
LD A,#05
LD B,8 ; 8 бёрстов
CALL WLD
LD A,#06
LD B,255 ; По 512 байт
CALL WLD
LD A,#FE ; Запуск с ожиданием
CALL WLD
EXA
```
## Макросы для удобства
```asm
; Определения для вызова функций
WLD EQU #6006
; Окна
PRWOW MACRO
LD A,1
JP WLD
ENDM
RRESB MACRO
LD A,2
JP WLD
ENDM
; Клавиатура
ESC MACRO
LD A,#17
JP WLD
ENDM
ENKE MACRO
LD A,#16
JP WLD
ENDM
; Файлы
LOAD512 MACRO
LD A,#30
JP WLD
ENDM
GEDPL MACRO
LD A,#0F
JP WLD
ENDM
```
---
## C API (SDCC)
> Источник: `src_sdcc/inc/wc_api.h` + `src_sdcc/asm/wc_api.s`
> Компилятор: SDCC 4.x, соглашение **sdcccall(1)**
### Соглашение вызова sdcccall(1)
| Аргумент | Тип | Регистр |
|----------|-------------|----------|
| 1-й | `uint8_t` | `A` |
| 1-й | `uint16_t` / указатель | `HL` |
| 2-й | `uint16_t` / указатель | `DE` |
| 3-й+ | любой | стек (callee-cleans) |
| Возврат | `uint8_t` | `A` |
| Возврат | `uint16_t` | `HL` |
WC API **портит**: `AF, BC, DE, HL, IX` при каждом вызове.
WC API **сохраняет**: `IY, AF', BC', DE', HL', SP`.
---
### Управление памятью (страницы)
```c
// Переключить окно #C000 на логическую страницу плагина N
void wc_mngc_pl(uint8_t page);
// Переключить окно #0000 на логическую страницу плагина N
void wc_mng0_pl(uint8_t page);
// Переключить окно #8000 на логическую страницу плагина N
void wc_mng8_pl(uint8_t page);
// Переключить окно #C000 на VPL-страницу мегабуфера N (физич. = WC_PAGE_TVBPG + N)
void wc_mngcvpl(uint8_t vpage);
// Переключить видеобуфер (WC_VIDEO_TXT / WC_VIDEO_BUF1..4)
void wc_mngv_pl(uint8_t mode);
```
> ⚠️ После **любого** вызова WC API окно `#C000` сбрасывается на текстовую страницу!
> Если плагин работал с `mngcvpl()`, после каждого UI-вызова нужно снова вызвать `mngcvpl()`.
---
### Отображение / UI
```c
// Восстановить дисплей WC (TXT-режим, панели)
// ⚠ Затирает #1000–#1447 в окне 0!
void wc_gedpl(void);
// Нарисовать окно
void wc_prwow(wc_window_t *win);
// Убрать окно (восстановить фон из RESB)
void wc_rresb(wc_window_t *win);
// Прокрутить область окна
void wc_scrlwow(wc_window_t *win, uint8_t y, uint8_t x,
uint8_t h, uint8_t w, uint8_t flags);
// Вывести строку с разметкой WC в окно
// Возвращает: номер строки после последнего символа
uint8_t wc_txtpr(wc_window_t *win, const char *str, uint8_t y, uint8_t x);
// Вывести сообщение (несколько абзацев, разделённых 0x00 0x00)
uint8_t wc_mezz(wc_window_t *win, uint8_t msg_num,
const char *str, uint8_t y, uint8_t x);
// Вывести строку без разметки (raw)
void wc_prsrw(wc_window_t *win, const char *str,
uint8_t y, uint8_t x, uint16_t len);
// Вывести строку без разметки с заданным атрибутом цвета
void wc_prsrw_attr(wc_window_t *win, const char *str,
uint8_t y, uint8_t x, uint16_t len, uint8_t attr);
// Получить адрес экрана по позиции в окне
uint16_t wc_gadrw(wc_window_t *win, uint8_t y, uint8_t x);
// Показать/убрать курсор
void wc_cursor(wc_window_t *win);
void wc_curser(wc_window_t *win);
// Диалог Yes/No или Ok/Cancel
// mode: WC_YN_YES_NO, WC_YN_OK_CANCEL, WC_YN_POLL, WC_YN_EXIT
// Возвращает: 0=нет/отмена, 1=да/ок (при POLL: текущий выбор)
uint8_t wc_yn(uint8_t mode);
// Ввод строки в окне
void wc_istr(wc_window_t *win, uint8_t mode);
// Вставить символ val по адресу addr в текстовой памяти
void wc_nork(uint16_t addr, uint8_t val);
```
---
### Клавиатура
```c
// Опрос конкретной клавиши (возвращает 1 если нажата)
uint8_t wc_key_space(void);
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);
uint8_t wc_key_enter(void);
uint8_t wc_key_esc(void);
uint8_t wc_key_bspc(void);
uint8_t wc_key_pgup(void);
uint8_t wc_key_pgdn(void);
uint8_t wc_key_home(void);
uint8_t wc_key_end(void);
uint8_t wc_key_f1(void);
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);
// Модификаторы (без автоповтора)
uint8_t wc_key_alt(void);
uint8_t wc_key_shift(void);
uint8_t wc_key_ctrl(void);
// Прочие клавиши
uint8_t wc_key_del(void);
uint8_t wc_key_ins(void);
uint8_t wc_key_caps(void);
uint8_t wc_key_any(void); // любая клавиша нажата (без автоповтора)
// Ждать нажатия любой клавиши, вернуть скан-код
uint8_t wc_key_wait_any(void);
// Ждать отпускания всех клавиш
void wc_key_wait_release(void);
// Получить скан-код нажатой клавиши
// mode: WC_KBSCN_NORMAL (с учётом SHIFT/CL/Lang) или WC_KBSCN_RAW
uint8_t wc_kbscn(uint8_t mode);
```
---
### Файловые операции
Все буферы и строки файловых функций **обязаны** быть в `#8000–#FFFF`
(WC ремапит `#0000–#7FFF` внутри FAT-операций).
```c
// Прочитать blocks×512 байт по адресу dest из открытого файла
// Возвращает: 0=OK, WC_EOF=конец файла, иное=ошибка
uint8_t wc_load512(uint16_t dest, uint8_t blocks);
// Прочитать blocks×256 байт по адресу dest
uint8_t wc_load256(uint16_t dest, uint8_t blocks);
// Записать blocks×512 байт по адресу src в открытый файл
void wc_save512(uint16_t src, uint8_t blocks);
// Пропустить sectors×512 байт в открытом файле (без чтения)
void wc_loadnone(uint8_t sectors);
// Сменить поток (контекст файловой операции)
// mode: WC_STREAM_ROOT, WC_STREAM_CLONE, WC_STREAM_WCDIR, 0/1
void wc_stream(uint8_t mode);
// Управление каталогом (WC_ADIR_SEEK_START, WC_ADIR_RESET_NEXT)
void wc_adir(uint8_t mode);
// Открыть файл по имени в текущем каталоге
// name_with_flag: [1 байт флагов][имя][0]
// Возвращает: 0=не найден, ненулевое=найден
uint8_t wc_fentry(uint16_t name_with_flag);
// Найти следующий файл в каталоге
// flags: [7]=только короткие имена, [1:0]=00 все/01 файлы/10 каталоги
// Возвращает: 0 (Z=1)=конец каталога, ненулевое=найден
uint8_t wc_findnext(uint16_t entry_buf, uint8_t flags);
// Открыть файл, найденный последним wc_fentry()
void wc_gfile(void);
// Войти в каталог, найденный последним wc_fentry()
void wc_gdir(void);
// Создать файл: [1 байт флагов][длина][имя][0]
uint8_t wc_mkfile(uint16_t name_with_flag);
// Создать каталог
uint8_t wc_mkdir(uint16_t name);
// Переименовать файл/каталог
uint8_t wc_rename(uint16_t old_name, uint16_t new_name);
// Удалить файл
uint8_t wc_delfl(uint16_t name_with_flag);
// Перейти к началу файла плагина (позиционировать поток на первый блок)
void wc_gipagpl(void);
// Прочитать FAT ENTRY (32 байта) файла в буфер по адресу addr
void wc_tentry(uint16_t addr);
// Обойти цепочку секторов, записать список секторов в buf..bufend
void wc_chtosep(uint16_t buf, uint16_t bufend);
// Получить заголовок помеченного файла
// panel = IX структура панели WC, filenum = номер файла, namebuf = буфер
void wc_tmrkdfl(uint16_t panel, uint16_t filenum, uint16_t namebuf);
```
---
### Графика и видео
```c
// Переключить видеорежим: WC_VIDEO_TXT / WC_VIDEO_BUF1..4
void wc_mngv_pl(uint8_t mode);
// Отобразить видеостраницу vpage (0x00–0x3F) на окно #C000
void wc_mngcvpl(uint8_t vpage);
// Отобразить видеостраницу vpage на окно #0000
// ⚠ GEDPL (~wc_gedpl) затирает #1000–#1447 — не хранить данные там!
void wc_mng0vpl(uint8_t vpage);
// Отобразить видеостраницу vpage на окно #8000
void wc_mng8vpl(uint8_t vpage);
// Установить видеорежим TSConfig
// mode: TSCONF_VM_* | TSCONF_RRES_* (байт VConfig)
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);
// Установить страницу графики тайловой плоскости (plane=0 или 1)
void wc_gvtl(uint8_t plane, uint8_t page);
// Установить страницу графики спрайтов
void wc_gvsgp(uint8_t page);
```
---
### DMA
```c
// Настройка и запуск DMA TSConfig.
// Подфункции:
// 0x00 — src+dst: B=src_page, HL=src_addr, C=dst_page, DE=dst_addr
// 0x01 — только src; 0x02 — только dst
// 0x05 — DMA_T; 0x06 — DMA_N; 0x07 — T+N
// 0xFC — RAM→RAM (с ожиданием) 0xFB — BLT→RAM
// 0xFA — FILL 0xF9 — RAM→CRAM (палитра)
// 0xF8 — RAM→SFILE (спрайты) 0xFD — запустить без ожидания
// 0xFE — запустить с ожиданием 0xFF — ждать готовности DMA
void wc_dmapl(uint8_t subfunc);
```
---
### Системные функции
```c
// Прерывания (WC_INT_DISABLE_ALL / NO_TIME / NO_PS2 / PLUGIN)
// При WC_INT_PLUGIN — следующий вызов wc_int_pl_handler() задаёт адрес
void wc_int_pl(uint8_t mode);
// Установить адрес обработчика ISR плагина (после wc_int_pl(WC_INT_PLUGIN))
void wc_int_pl_handler(uint16_t handler_addr);
// Управление CPU/AY частотой
// mode: WC_TURBO_CPU (param 0=3.5, 1=7, 2=14, 3=28 МГц)
// WC_TURBO_AY (param 0=1.750, 1=1.773, 2=3.5, 3=3.546 МГц)
// WC_TURBO_RESTORE (0xFF) — восстановить из настроек WC
void wc_turbopl(uint8_t mode, uint8_t param);
// Получить параметр из INI-файла плагина
// param_num: 0-based номер параметра
// Возвращает: номер опции (0-based), 0xFF если параметр не задан
uint8_t wc_prm_pl(uint8_t param_num);
// Резидентный JP на другую страницу плагина (без возврата!)
// page: номер страницы (от 0), addr: адрес в #8000–#BFFF
void wc_resident_jump(uint8_t page, uint16_t addr);
// Резидентный CALL на другую страницу плагина (с возвратом)
// Сохраняет все регистры кроме A и HL
void wc_resident_call(uint8_t page, uint16_t addr);
// Заполнить буфер символом c (аналог memset)
void wc_strset(char *dsr, uint16_t len, char c);
```
---
### Системные переменные (прямой доступ по адресу)
```c
// Читаются напрямую, без вызова WC API:
extern volatile uint8_t wc_exit_code; // #8000 − записать перед return из main()
// 0=ESC, 1=не распознан, 2=следующий,
// 3=перечитать каталог, 4=предыдущий
#define WC_SYS_ABT (*(volatile uint8_t*)0x6004) // 1 = был нажат ESC
#define WC_SYS_ENT (*(volatile uint8_t*)0x6005) // 1 = был нажат ENTER
#define WC_SYS_TMN (*(volatile uint16_t*)0x6009) // таймер INT (инкремент каждый INT)
#define WC_SYS_HEI (*(volatile uint8_t*)0x600E) // высота TXT-экрана (25/30/36)
#define WC_SYS_PG0 (*(volatile uint8_t*)0x6000) // текущая страница окна #0000
#define WC_SYS_PGC (*(volatile uint8_t*)0x6003) // текущая страница окна #C000
```
---
### Пример минимального плагина (SDCC C)
```c
#include "inc/wc_api.h"
#include "inc/types.h"
// Структура окна в DATA (0x8000+)
static wc_window_t g_win;
// Код выхода (WC читает A при RET из main)
uint8_t wc_exit_code;
int main(void) {
// --- Настройка окна ---
g_win.type = WC_WIN_SINGLE;
g_win.cur_mask = 0x07;
g_win.x = 255; // по центру
g_win.y = 255;
g_win.width = 40;
g_win.height = 8;
g_win.color = WC_COLOR(WC_BLACK, WC_BRIGHT_WHITE);
g_win.buf_addr = 0x0000; // автосохранение фона
// --- Отрисовка UI ---
wc_gedpl();
wc_prwow(&g_win);
wc_txtpr(&g_win, "Hello from plugin!", 1, 1);
// --- Главный цикл ---
while (1) {
if (wc_key_esc()) break;
if (wc_key_enter()) {
// ... какое-то действие
}
}
// --- Выход ---
wc_rresb(&g_win);
wc_gedpl();
wc_exit_code = 0; // 0 = нормальный выход (ESC)
return 0;
}
```
---
## Константы и структуры
### Цветовая палитра (EGA-совместимая)
```c
#define WC_COLOR(bg, fg) ((uint8_t)(((bg) << 4) | (fg)))
#define WC_BLACK 0 #define WC_DARK_GRAY 8
#define WC_BLUE 1 #define WC_BRIGHT_BLUE 9
#define WC_RED 2 #define WC_BRIGHT_RED 10
#define WC_MAGENTA 3 #define WC_BRIGHT_MAGENTA 11
#define WC_GREEN 4 #define WC_BRIGHT_GREEN 12
#define WC_CYAN 5 #define WC_BRIGHT_CYAN 13
#define WC_YELLOW 6 #define WC_BRIGHT_YELLOW 14
#define WC_WHITE 7 #define WC_BRIGHT_WHITE 15
```
### Стили окон
| Константа | Значение | Описание |
|-----------|----------|----------|
| `WC_WIN_NO_BORDER` | 0x00 | Без рамки, со стандартным курсором |
| `WC_WIN_SINGLE` | 0x01 | Одинарная рамка, без курсора |
| `WC_WIN_DOUBLE` | 0x02 | Двойная рамка + курсор |
| `WC_WIN_TYPE3`..`TYPE8` | 0x03..0x08 | Рамки 2/3 типа ± курсор/заголовки |
**Флаги (OR с типом):**
| Флаг | Значение | Описание |
|------|----------|----------|
| `WC_WIN_HEADER` | 0x10 | Инверсный заголовок сверху |
| `WC_WIN_WIDE_CURSOR` | 0x40 | Курсор на всю ширину |
| `WC_WIN_SHADOW` | 0x80 | Тень у окна |
### Структура `wc_window_t` (16 байт)
```c
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: WC_COLOR(bg, fg) */
uint8_t _reserved; /* +7: ВСЕГДА 0! */
uint16_t buf_addr; /* +8: буфер фона (0=авто, 0xFFFF=без буфера)*/
uint8_t divider1; /* +10: разделитель 1 (смещение от верха) */
uint8_t divider2; /* +11: разделитель 2 (смещение от низа) */
uint8_t cursor_pos; /* +12: позиция курсора (от 1) */
uint8_t cursor_bot; /* +13: нижний ограничитель курсора */
uint8_t cursor_clr; /* +14: цвет курсора */
uint8_t under_clr; /* +15: цвет под курсором */
} wc_window_t;
```
> Авто-центрирование (x=255, y=255) работает для режимов 80×25, 80×30, 90×36.
> Добавлено в WC v1.02.
### Структура FAT-записи (32 байта)
```c
typedef struct {
uint8_t name[11]; /* +0: короткое имя 8.3 (без точки) */
uint8_t attr; /* +11: атрибуты FAT (см. WC_FAT_ATTR_*) */
uint8_t _res1; /* +12: NTRes */
uint8_t crt_time_ms; /* +13: время создания (0.1 сек) */
uint16_t crt_time; /* +14: время создания (FAT format) */
uint16_t crt_date; /* +16: дата создания */
uint16_t acc_date; /* +18: дата доступа */
uint16_t cluster_hi; /* +20: старшее слово кластера */
uint16_t mod_time; /* +22: время модификации */
uint16_t mod_date; /* +24: дата модификации */
uint16_t cluster_lo; /* +26: младшее слово кластера */
uint32_t file_size; /* +28: размер файла */
} wc_fat_entry_t;
```
**Атрибуты FAT:**
| Константа | Значение | Описание |
|-----------|----------|----------|
| `WC_FAT_ATTR_RDONLY` | 0x01 | Только чтение |
| `WC_FAT_ATTR_HIDDEN` | 0x02 | Скрытый |
| `WC_FAT_ATTR_SYSTEM` | 0x04 | Системный |
| `WC_FAT_ATTR_VOLLBL` | 0x08 | Метка тома |
| `WC_FAT_ATTR_DIR` | 0x10 | Каталог |
| `WC_FAT_ATTR_ARCHIVE` | 0x20 | Архивный |
| `WC_FAT_ATTR_LFN` | 0x0F | LFN-запись (RDONLY\|HIDDEN\|SYSTEM\|VOLLBL) |
### Структура FindNext
```c
typedef struct {
uint32_t size; /* опционально, если WC_FIND_WITH_SIZE */
uint16_t date; /* опционально, если WC_FIND_WITH_DATE */
uint16_t time; /* опционально, если WC_FIND_WITH_TIME */
uint8_t flag; /* 0x10=каталог, 0x00=файл */
char name[1]; /* имя, z-string (длина переменная) */
} wc_findnext_entry_t;
```
**Флаги для `wc_findnext(entry_buf, flags)`:**
| Константа | Значение | Описание |
|-----------|----------|----------|
| `WC_FIND_ALL` | 0x00 | Все записи |
| `WC_FIND_FILES` | 0x01 | Только файлы |
| `WC_FIND_DIRS` | 0x02 | Только каталоги |
| `WC_FIND_WITH_SIZE` | 0x04 | Включить поле size |
| `WC_FIND_WITH_DATE` | 0x08 | Включить поле date |
| `WC_FIND_WITH_TIME` | 0x10 | Включить поле time |
| `WC_FIND_FULL` | 0x1C | Все опциональные поля |
| `WC_FIND_SHORT_ONLY` | 0x80 | Только короткие имена 8.3 |
### Коды ошибок файловых операций
| Константа | Значение | Описание |
|-----------|----------|----------|
| `WC_EOF` | 0x0F | Конец файла / конец цепочки |
| `WC_ERR_LONG_NAME` | 1 | Недопустимое длинное имя |
| `WC_ERR_SHORT_IDX` | 2 | Короткое имя требует индекса |
| `WC_ERR_LONG_EXISTS` | 3 | Длинное имя уже существует |
| `WC_ERR_SHORT_EXISTS` | 4 | Короткое имя уже существует |
| `WC_ERR_NOT_FOUND` | 8 | Файл/каталог не найден |
| `WC_ERR_NO_SPACE` | 16 | Нет свободного места |
| `WC_ERR_UNKNOWN` | 255 | Неизвестная ошибка |
### Константы скроллинга (`wc_scrlwow`)
| Константа | Значение | Описание |
|-----------|----------|----------|
| `WC_SCRL_DOWN` | 0x00 | Прокрутка вниз |
| `WC_SCRL_UP` | 0x01 | Прокрутка вверх |
| `WC_SCRL_WITH_ATTRS` | 0x80 | Прокручивать и атрибуты |
| `WC_SCRL_CLEAR_SRC` | 0x40 | Очистить источник после сдвига |
### Константы потоков (`wc_stream`)
| Константа | Значение | Описание |
|-----------|----------|----------|
| `WC_STREAM_ROOT` | 0xFF | Корневой каталог |
| `WC_STREAM_CLONE` | 0xFE | Клонировать текущий поток в #00 и #01 |
| `WC_STREAM_WCDIR` | 0xFD | Каталог WC (для INI) |
| 0x00, 0x01 | — | Выбрать поток 0 или 1 |
### Константы видеобуферов
| Константа | Значение | Описание |
|-----------|----------|----------|
| `WC_VIDEO_TXT` | 0x00 | Текстовый режим WC |
| `WC_VIDEO_BUF1` | 0x01 | Видеобуфер 1 (стр. #20–#2F) |
| `WC_VIDEO_BUF2` | 0x02 | Видеобуфер 2 (стр. #30–#3F) |
| `WC_VIDEO_BUF3` | 0x03 | Видеобуфер 3 (стр. #40–#4F) |
| `WC_VIDEO_BUF4` | 0x04 | Видеобуфер 4 (стр. #50–#5F) |
> Мегабуфер (64 стр.) и видеобуферы **пересекаются** физически:
> VPL-страница N = физическая `WC_PAGE_TVBPG + N` = `#20 + N`.
### Размеры TXT-экрана
| Константа | Значение |
|-----------|----------|
| `WC_SCREEN_80x25` | 25 |
| `WC_SCREEN_80x30` | 30 |
| `WC_SCREEN_90x36` | 36 |
---
## Таблица кодов функций
> Полный маппинг ASM → WC API code → C wrapper
| Код A | ASM | C функция | Параметр в A' (EXA)? | Примечание |
|-------|-----|-----------|----------------------|------------|
| #00 | MNGC_PL | `wc_mngc_pl(page)` | **Да** (page) | #FF=font, #FE=TXT |
| #01 | PRWOW | `wc_prwow(win)` | — | IX=win |
| #02 | RRESB | `wc_rresb(win)` | — | IX=win |
| #03 | PRSRW | `wc_prsrw(win,str,y,x,len)` | — | |
| #04 | PRIAT | (часть prsrw_attr) | **Да** (color) | Вызывается сразу после #03 |
| #05 | GADRW | `wc_gadrw(win,y,x)` | — | → HL=addr |
| #06 | CURSOR | `wc_cursor(win)` | — | |
| #07 | CURSER | `wc_curser(win)` | — | |
| #08 | YN | `wc_yn(mode)` | **Да** (mode) | |
| #09 | ISTR | `wc_istr(win,mode)` | **Да** (mode) | |
| #0A | NORK | `wc_nork(addr,val)` | **Да** (val) | |
| #0B | TXTPR | `wc_txtpr(win,str,y,x)` | — | → A=next_y |
| #0C | MEZZ | `wc_mezz(win,msg,str,y,x)` | **Да** (msg_num) | |
| #0D | DMAPL | `wc_dmapl(subfunc)` | **Да** (subfunc) | |
| #0E | TURBOPL | `wc_turbopl(mode,param)` | — | B=mode, C=param |
| #0F | GEDPL | `wc_gedpl()` | — | ⚠ Портит #1000–#1447 |
| #10..#29 | Keys | `wc_key_*()` | — | → NZ=нажата |
| #2A | KBSCN | `wc_kbscn(mode)` | **Да** (mode) | |
| #2B | DEL | `wc_key_del()` | — | |
| #2C | CAPS | `wc_key_caps()` | — | |
| #2D | ANYK | `wc_key_any()` | — | |
| #2E | USPO | `wc_key_wait_release()` | — | |
| #2F | NUSP | `wc_key_wait_any()` | — | |
| #30 | LOAD512 | `wc_load512(dest,blocks)` | — | B=blocks |
| #31 | SAVE512 | `wc_save512(src,blocks)` | — | |
| #32 | GIPAGPL | `wc_gipagpl()` | — | |
| #33 | TENTRY | `wc_tentry(addr)` | — | |
| #34 | CHTOSEP | `wc_chtosep(buf,bufend)` | — | |
| #36 | TMRKDFL | `wc_tmrkdfl(panel,fnum,buf)` | — | |
| #38 | ADIR | `wc_adir(mode)` | **Да** (mode) | |
| #39 | STREAM | `wc_stream(mode)` | — | D=mode |
| #3A | FINDNEXT | `wc_findnext(buf,flags)` | **Да** (flags) | |
| #3B | FENTRY | `wc_fentry(name)` | — | → Z/NZ |
| #3C | LOAD256 | `wc_load256(dest,blocks)` | — | |
| #3D | LOADNONE | `wc_loadnone(sectors)` | — | B=sectors |
| #3E | GFILE | `wc_gfile()` | — | |
| #3F | GDIR | `wc_gdir()` | — | |
| #40 | MNGV_PL | `wc_mngv_pl(mode)` | **Да** (mode) | |
| #41 | MNGCVPL | `wc_mngcvpl(vpage)` | **Да** (vpage) | |
| #42 | GVmod | `wc_gvmod(mode)` | **Да** (mode) | |
| #43 | GYOFF | `wc_gyoff(y)` | — | HL=y |
| #44 | GXOFF | `wc_gxoff(x)` | — | HL=x |
| #45 | GVtm | `wc_gvtm(page)` | — | C=page |
| #46 | GVtl | `wc_gvtl(plane,page)` | — | B=plane,C=page |
| #47 | GVsgp | `wc_gvsgp(page)` | — | C=page |
| #48 | MKfile | `wc_mkfile(name)` | — | |
| #49 | MKdir | `wc_mkdir(name)` | — | |
| #4A | RENAME | `wc_rename(old,new)` | — | |
| #4B | DELFL | `wc_delfl(name)` | — | |
| #4E | MNG0_PL | `wc_mng0_pl(page)` | **Да** (page) | |
| #4F | MNG8_PL | `wc_mng8_pl(page)` | **Да** (page) | |
| #50 | MNG0VPL | `wc_mng0vpl(vpage)` | **Да** (vpage) | |
| #51 | MNG8VPL | `wc_mng8vpl(vpage)` | **Да** (vpage) | |
| #53 | PRM_PL | `wc_prm_pl(param)` | **Да** (param) | → Z=нет, NZ: A=opt |
| #54 | SCRLWOW | `wc_scrlwow(win,y,x,h,w,fl)` | **Да** (flags) | |
| #55 | INS | `wc_key_ins()` | — | |
| #56 | INT_PL | `wc_int_pl(mode)` | **Да** (mode) | |
| — | PLRESAD | `wc_resident_jump(p,addr)` | — | CALL #6020, JP |
| — | PLRESCALL | `wc_resident_call(p,addr)` | — | CALL #6028 |
| — | STRSET | `wc_strset(dst,len,c)` | — | Утилита (LDIR) |