Add OPL4 playback and analyzer support

This commit is contained in:
2026-09-15 14:59:29 +03:00
commit 1686838e03
553 changed files with 50524 additions and 0 deletions
+658
View File
@@ -0,0 +1,658 @@
# TSConfig Platform Reference
> Источники: `inc/tsconf.h` (532 стр.), `inc/wc_api.h` (системные константы),
> [TSConfig Wiki](https://github.com/tslabs/zx-evo)
## Обзор платформы
TS-Configuration (TSConfig) — расширенная конфигурация на базе **ZX Evolution**
(Большой Спектрум / ZX Evo), реализованная в FPGA (Altera/Xilinx).
| Параметр | Значение |
|-----------|----------|
| CPU | Z80 @ 3.5 / 7 / 14 / 28 МГц |
| RAM | до 4096 КБ (256 страниц × 16 КБ) |
| ROM | до 512 КБ (32 страницы) |
| Видео | до 360×288, 256 цветов, TXT 80/90 столбцов |
| Спрайты | До 85 на строку, 8×8–64×64, 3 плоскости |
| Тайлы | 2 плоскости, 8×8 |
| DMA | Аппаратный контроллер (RAM↔RAM, RAM↔SPI/IDE, FILL, CRAM, SFILE) |
| Кэш | 512 байт, по-оконно |
| Звук | AY-3-8910 (TurboSound: 2 чипа), OPL3 (YMF262), SAA1099 ×2, HUS |
| Хранилище | SD (Z-Controller, NeoGS), IDE (NEMO, SMUC), FAT32 |
| Совместимость | Pentagon-128/512/1024, порт #7FFD |
## Память
### Страничная адресация
Процессор Z80 адресует 64 КБ памяти, разделенные на 4 окна по 16 КБ:
| Окно | Адреса CPU | Регистр страницы | R/W | Reset |
|------|------------|------------------|-----|-------|
| 0 | #0000..#3FFF | Page0 | W | #00 |
| 1 | #4000..#7FFF | Page1 | W | #05 |
| 2 | #8000..#BFFF | Page2 | R/W | #02 |
| 3 | #C000..#FFFF | Page3 | R/W | #00 |
**Доступно:**
- RAM: до 4096 КБ (256 страниц по 16 КБ)
- ROM: до 512 КБ (32 страницы по 16 КБ)
### Регистры управления памятью
Доступ к регистрам через порты **#nnAF**, где nn - номер регистра.
#### MemConfig (регистр #07)
```
Биты:
7:6 - LCK128[1:0] - режим порта #7FFD
5:4 - резерв
3 - W0_RAM - выбор ROM/RAM в окне 0
2 - !W0_MAP - режим маппинга окна 0
1 - W0_WE - разрешение записи в окно 0
0 - ROM128 - выбор страниц маппинга
```
#### Page0..3 (регистры #10-#13)
8-битные регистры, содержащие номер страницы для соответствующего окна.
## Порты ввода-вывода
### Схема адресации портов
TSConfig использует порты с адресом **#nnAF**, где:
- Младшие 8 бит (A0-A7) = #AF
- Старшие 8 бит (A8-A15) = номер регистра (nn)
### Базовые регистры TSConfig
> Источник: `src_sdcc/inc/tsconf.h` — `#define TSCONF_PORT(reg) (((uint16_t)(reg) << 8) | 0xAF)`
| Порт | Константа | R/W | Описание |
|---------|----------------------------|-----|-------------------------------------|
| `#00AF` | `TSCONF_PORT_VCONFIG` | RW | VConfig: видеорежим (VM, RRES) |
| `#01AF` | `TSCONF_PORT_VPAGE` | W | VPage: страница видеобуфера |
| `#02AF` | `TSCONF_PORT_GXOFFSL` | W | GFX X offset (low) |
| `#03AF` | `TSCONF_PORT_GXOFFSH` | W | GFX X offset (high) |
| `#04AF` | `TSCONF_PORT_GYOFFSL` | W | GFX Y offset (low) |
| `#05AF` | `TSCONF_PORT_GYOFFSH` | W | GFX Y offset (high) |
| `#06AF` | `TSCONF_PORT_TSCONFIG` | W | TSConfig: tile/sprite engine |
| `#07AF` | `TSCONF_PORT_PALSEL` | W | PalSel: выбор палитры |
| `#0FAF` | `TSCONF_PORT_BORDER` | W | Border: цвет бордюра (биты 2:0) |
| `#10AF` | `TSCONF_PORT_PAGE0` | **W** | **Page0: страница окна #0000** |
| `#11AF` | `TSCONF_PORT_PAGE1` | **W** | **Page1: страница окна #4000** |
| `#12AF` | `TSCONF_PORT_PAGE2` | **RW** | **Page2: страница окна #8000** |
| `#13AF` | `TSCONF_PORT_PAGE3` | **RW** | **Page3: страница окна #C000** |
| `#14AF` | `TSCONF_PORT_FMADDR` | W | Font Maps |
| `#15AF` | `TSCONF_PORT_TMPAGE` | W | TileMap page |
| `#16AF` | `TSCONF_PORT_T0GPAGE` | W | Tile plane 0 gfx page |
| `#17AF` | `TSCONF_PORT_T1GPAGE` | W | Tile plane 1 gfx page |
| `#18AF` | `TSCONF_PORT_SGPAGE` | W | Sprite gfx page |
| `#20AF` | `TSCONF_PORT_SYSCONFIG` | W | **SysConfig: CPU freq + кэш** |
| `#21AF` | `TSCONF_PORT_MEMCONFIG` | W | MemConfig: режим памяти |
| `#22AF` | `TSCONF_PORT_HSINT` | W | FRAME-INT: горизонт. позиция |
| `#23AF` | `TSCONF_PORT_VSINTL` | W | FRAME-INT: вертик. позиция (low) |
| `#24AF` | `TSCONF_PORT_VSINTH` | W | FRAME-INT: вертик. позиция (high) + auto-inc |
| `#29AF` | `TSCONF_PORT_FDDVIRT` | W | FDD виртуализация |
| `#2AAF` | `TSCONF_PORT_INTMASK` | W | **INTMask: маска прерываний** |
| `#2BAF` | `TSCONF_PORT_CACHECONFIG` | W | **CacheConfig: кэш по окнам** |
#### Порты тайловых смещений
| Порт | Описание |
|------|----------|
| `#40AF`/`#41AF` | Tile plane 0: X offset (lo/hi) |
| `#42AF`/`#43AF` | Tile plane 0: Y offset (lo/hi) |
| `#44AF`/`#45AF` | Tile plane 1: X offset (lo/hi) |
| `#46AF`/`#47AF` | Tile plane 1: Y offset (lo/hi) |
#### Порты DMA
| Порт | Константа | Описание |
|------|-----------|----------|
| `#19AF` | `TSCONF_PORT_DMASADDRL` | Source addr low |
| `#1AAF` | `TSCONF_PORT_DMASADDRH` | Source addr high |
| `#1BAF` | `TSCONF_PORT_DMASADDRX` | Source page (extended) |
| `#1CAF` | `TSCONF_PORT_DMADADDRL` | Dest addr low |
| `#1DAF` | `TSCONF_PORT_DMADADDRH` | Dest addr high |
| `#1EAF` | `TSCONF_PORT_DMADADDRX` | Dest page (extended) |
| `#25AF` | `TSCONF_PORT_DMAWPDEV` | Wait Port device |
| `#26AF` | `TSCONF_PORT_DMALEN` | Burst length |
| `#27AF` | `TSCONF_PORT_DMACTRL` | Control (W) / Status (R) |
| `#28AF` | `TSCONF_PORT_DMANUM` | Bursts num (low) |
| `#2CAF` | `TSCONF_PORT_DMANUMH` | Bursts num (high) |
| `#2DAF` | `TSCONF_PORT_DMAWPADDR` | Wait Port addr |
> ⚠️ **Частая ошибка:** Page0–Page3 = `#10AF`–`#13AF`, SysConfig = `#20AF`.
> Не путать с VConfig (`#00AF`) или VPage (`#01AF`)!
### Порты OPL3 — YMF262
**OPL3 чип располагается по портам #C4–#C7:**
| Порт | Константа | Назначение |
|-------|-----------|------------|
| `#C4` | `TSCONF_PORT_OPL3_ADDR0` | Bank 0: регистр адреса |
| `#C5` | `TSCONF_PORT_OPL3_DATA0` | Bank 0: данные |
| `#C6` | `TSCONF_PORT_OPL3_ADDR1` | Bank 1: регистр адреса |
| `#C7` | `TSCONF_PORT_OPL3_DATA1` | Bank 1: данные |
**Регистр NEW (Bank 1, reg 0x05):**
- `NEW=1` (0x01) → OPL3 mode: биты L/R в регистрах `C0–C8` управляют маршрутизацией звука
- `NEW=0` (0x00) → OPL2-compat: L+R всегда активны (обязательно для файлов OPL2/OPL1!)
```c
// inc/opl3.h
void opl3_write_b0(uint8_t reg, uint8_t data); // Bank 0 (#C4/#C5)
void opl3_write_b1(uint8_t reg, uint8_t data); // Bank 1 (#C6/#C7)
void opl3_init(void); // сброс + NEW=1
// Для OPL2/OPL1 VGM: после opl3_init() нужно:
opl3_write_b1(0x05, 0x00); // NEW=0 — иначе тишина!
```
### Порты AY-3-8910 / YM2149
| Порт | Константа | Назначение |
|---------|-----------|------------|
| `#FFFD` | `TSCONF_PORT_AY_ADDR` | Регистр адреса / чтение (`OUT/IN`) |
| `#BFFD` | `TSCONF_PORT_AY_DATA` | Запись данных |
**TurboSound (два AY):** второй чип выбирается через порт `#FFFD`:
- `OUT (#FFFD), #FF` (= `TSCONF_AY_TS_CHIP0`) → чип 0 (основной)
- `OUT (#FFFD), #FE` (= `TSCONF_AY_TS_CHIP1`) → чип 1
**Частоты AY** (управление через `wc_turbopl(WC_TURBO_AY, param)`):
| param | Частота | Примечание |
|-------|---------|------------|
| 0 | 1,750,000 Гц | Стандарт TSConfig / Pentagon |
| 1 | 1,773,400 Гц | NTSC-кварц (315/88 МГц ÷ 2) |
| 2 | 3,500,000 Гц | Удвоенная |
| 3 | 3,546,800 Гц | Удвоенная NTSC |
### Порты SAA1099 — MultiSound card
| Чип | Данные | Адрес | Константы |
|------|--------|-------|-----------|
| SAA1 | `#00FF` | `#01FF` | `TSCONF_PORT_SAA_DATA/ADDR` |
| SAA2 | `#00FE` | `#01FE` | `TSCONF_PORT_SAA2_DATA/ADDR` |
> Некоторые источники указывают SAA2 по портам `#02FF`/`#03FF` — это
> зависит от реализации MultiSound платы. В `tsconf.h` используются
> `#00FE`/`#01FE`.
**Пример записи в регистр OPL3:**
```asm
; Запись в регистр банка 0
LD BC,#C4 ; Порт адреса
LD A,reg ; Номер регистра
OUT (C),A
LD B,#C5 ; Порт данных
LD A,value ; Значение
OUT (C),A
; Запись в регистр банка 1
LD BC,#C6 ; Порт адреса банка 1
LD A,reg ; Номер регистра
OUT (C),A
LD B,#C7 ; Порт данных банка 1
LD A,value ; Значение
OUT (C),A
```
## Процессор
### Частоты CPU
| Режим | Частота | SysConfig [1:0] | Константа |
|--------|---------|-----------------|----------|
| 00 | 3.5 МГц | `00` | `TSCONF_CPU_3_5MHZ` |
| 01 | 7.0 МГц | `01` | `TSCONF_CPU_7MHZ` |
| 10 | 14.0 МГц | `10` | `TSCONF_CPU_14MHZ` |
| 11 | 28.0 МГц | `11` | (non-standard, не все FPGA) |
> В WC API `wc_turbopl(WC_TURBO_CPU, param)` поддерживает
> param 0–3 (3.5/7/14/28 МГц).
Управление через регистр **SysConfig #20AF** (биты 1:0):
```c
// tsconf.h
#define TSCONF_CPU_3_5MHZ 0x00
#define TSCONF_CPU_7MHZ 0x01
#define TSCONF_CPU_14MHZ 0x02
#define TSCONF_CPU_MASK 0x03
#define TSCONF_CACHE_EN 0x04 // бит 2 — глобальный кэш
// Convenience macros:
tsconf_set_cpu(TSCONF_CPU_14MHZ); // только CPU
tsconf_set_cpu_cache(TSCONF_CPU_14MHZ, TSCONF_CACHE_EN); // CPU + кэш
```
### Кэш
512 байт кэш-памяти для ускорения работы на 14/28 МГц.
**Глобально:** бит 2 регистра **SysConfig** (`TSCONF_CACHE_EN`).
**По-оконно:** регистр **CacheConfig #2BAF**:
| Константа | Значение | Описание |
|-----------|----------|----------|
| `TSCONF_CACHE_EN_0000` | 0x01 | Кэш для #0000–#3FFF |
| `TSCONF_CACHE_EN_4000` | 0x02 | Кэш для #4000–#7FFF |
| `TSCONF_CACHE_EN_8000` | 0x04 | Кэш для #8000–#BFFF |
| `TSCONF_CACHE_EN_C000` | 0x08 | Кэш для #C000–#FFFF |
| `TSCONF_CACHE_ALL` | 0x0F | Все окна |
| `TSCONF_CACHE_NONE` | 0x00 | Кэш выключен |
```c
tsconf_set_cache(TSCONF_CACHE_EN_8000 | TSCONF_CACHE_EN_C000);
```
**Важно:** После DMA операций необходима **инвалидация кэша**:
```asm
; Инвалидация: 512 байт LDIR на себя
LD HL,#FE00
LD DE,#FE00
LD BC,#0200
LDIR
```
## Прерывания
### Источники прерываний
TSConfig поддерживает несколько источников INT:
| Источник | Бит | IM2 вектор | Константа |
|----------|-----|------------|-----------|
| FRAME | 0 | `#FF` (`TSCONF_IVEC_FRAME`) | `TSCONF_INT_FRAME` |
| LINE | 1 | `#FD` (`TSCONF_IVEC_LINE`) | `TSCONF_INT_LINE` |
| DMA | 2 | `#FB` (`TSCONF_IVEC_DMA`) | `TSCONF_INT_DMA` |
| WTP | 3 | — | `TSCONF_INT_WTP` |
### Регистр маски прерываний (INTMask #2AAF)
```
Биты:
3 - WTP (Wait Port) interrupt enable
2 - DMA interrupt enable
1 - LINE interrupt enable
0 - FRAME interrupt enable
Reset: #01 (только FRAME включен)
```
```c
tsconf_set_intmask(TSCONF_INT_FRAME | TSCONF_INT_LINE);
```
### Позиционирование FRAME-INT
```c
// Задать вертикальную строку и горизонтальную позицию
tsconf_set_frame_int(vline, hpos);
// Отключить
tsconf_disable_frame_int();
// Авто-инкремент VCNT (для множественных INT в кадре):
// VSINTH[7:4] = auto-increment value
#define TSCONF_VSINTH_INC(n) ((n) << 4)
```
---
## MemConfig (#21AF) — Конфигурация памяти
| Константа | Значение | Описание |
|-----------|----------|----------|
| `TSCONF_MEM_ROM128` | 0x01 | Выбор банка ROM (= бит 4 порта #7FFD) |
| `TSCONF_MEM_W0_WE` | 0x02 | Разрешить запись в окно #0000 |
| `TSCONF_MEM_W0_MAP_DIS` | 0x04 | Отключить маппинг через Page0 |
| `TSCONF_MEM_W0_RAM` | 0x08 | RAM вместо ROM в окне #0000 |
| `TSCONF_MEM_LCK128_512K` | 0x00 | Pentagon-512 режим |
| `TSCONF_MEM_LCK128_128K` | 0x40 | Pentagon-128 режим |
| `TSCONF_MEM_LCK128_AUTO` | 0x80 | Авто-определение |
| `TSCONF_MEM_LCK128_1M` | 0xC0 | Расширенный 1 МБ |
---
## TSU — Tile/Sprite Engine (#06AF)
| Константа | Значение | Описание |
|-----------|----------|----------|
| `TSCONF_TS_EXT` | 0x01 | TSU 360×288 (extended) |
| `TSCONF_T0Z_EN` | 0x04 | Tile[0] visible (plane 0) |
| `TSCONF_T1Z_EN` | 0x08 | Tile[0] visible (plane 1) |
| `TSCONF_T0_EN` | 0x20 | Tile layer 0 enable |
| `TSCONF_T1_EN` | 0x40 | Tile layer 1 enable |
| `TSCONF_S_EN` | 0x80 | Sprite layers enable |
---
## HUS — Hurricane Sound Engine
> Порты `#80AF`–`#87AF` (есть не на всех FPGA-прошивках)
HUS — аппаратный звуковой движок TSConfig для воспроизведения
PCM-сэмплов из RAM с DMA.
| Порт | Константа | Описание |
|------|-----------|----------|
| `#80AF` | `TSCONF_PORT_HUSCTRL` | Control (W) / Status (R) |
| `#81AF` | `TSCONF_PORT_HUSSAMPRATE` | Sample Rate: 1,750,000 / (SR+1) |
| `#82AF` | `TSCONF_PORT_HUSTICKRATEL` | Tick Rate (low) |
| `#83AF` | `TSCONF_PORT_HUSTICKRATEH` | Tick Rate (high) |
| `#84AF`–`#87AF` | `TSCONF_PORT_HUSRLD0`–`3` | Reload ch 0–31 |
**Биты статуса (чтение #80AF):**
| Константа | Бит | Описание |
|-----------|-----|----------|
| `TSCONF_HUS_ACT` | 0 | 1 = HUS активен |
| `TSCONF_HUS_TICK` | 1 | 1 = tick event |
| `TSCONF_HUS_HALF` | 6 | 1 = полбуфера |
| `TSCONF_HUS_EMPTY` | 7 | 1 = буфер пуст |
**Управление (запись #80AF):**
| Константа | Значение | Описание |
|-----------|----------|----------|
| `TSCONF_HUS_PAUSE` | 0x02 | Пауза воспроизведения |
| `TSCONF_HUS_RESET` | 0x80 | Сброс HUS |
### ISR плагина — собственный таймер
Плагин может зарегистрировать собственный ISR через
`wc_int_pl(WC_INT_PLUGIN)` + `wc_int_pl_handler(addr)`.
В VGM-плеере ISR настраивается через **перехват** вектора IM2
(FRAME INT, вектор `#5BFF`) с высокой частотой вызова.
POS_TABLE задаёт позиции INT-триггеров в кадре:
| Вариант | ISR_FREQ | T-states/тик | Тиков/кадр | VGM_SAMPLE_SHIFT | Семплов/тик |
|---------|----------|-------------|------------|------------------|---------|
| Quarter | **683 Гц** | 5120 T | 14 | 6 (44100/64) | 64 |
| Half | 1367 Гц | 2560 T | 28 | 5 (44100/32) | 32 |
| Full | 2734 Гц | 1280 T | 56 | 4 (44100/16) | 16 |
Конфигурация варианта хранится в `inc/variant_cfg.h`:
```c
// variant_cfg.h (текущий вариант)
#define ISR_FREQ 683
#define ISR_TICKS_PER_FRAME 14 // 683/50≈14
#define VGM_SAMPLE_SHIFT 6 // 44100 >> 6 = 689 ≈ 683
#define VGM_SAMPLE_MASK 0x3Fu
#define VGM_FILL_CMD_BUDGET 32 // команд за один yield
#define VARIANT_POS_ENTRIES 14 // записей в pos_table
#define VARIANT_POS_STEP 5120 // T-states между INT
```
### Механизм pos_table
`pos_table` — кольцевой буфер позиций INT в кадре.
Каждая запись: 5 байт `[VSINTH, VSINTL, HSINT, next_ptr_lo, next_ptr_hi]`.
ISR выводит 3 байта через OUTI (порты VSINTH/VSINTL/HSINT),
затем переходит по next_ptr к следующей записи.
Генерируется скриптом `scripts/gen_pos_table.js`.
### Частота прерываний TSConfig (FRAME)
- FRAME: зависит от видео режима
- 50 Гц (312 строк PAL)
- 60 Гц (262 строки NTSC)
- ~48.8 Гц (320 строк Pentagon)
## DMA Контроллер
TSConfig имеет аппаратный DMA для быстрого копирования/заполнения данных.
### Режимы DMA (регистр DMACTRL #27AF)
| Константа | Значение | Описание |
|-----------|----------|----------|
| `TSCONF_DMA_RAM_RAM` | 0x09 | RAM → RAM копирование |
| `TSCONF_DMA_BLT1_RAM` | 0x89 | RAM → RAM с пропуском нулей (transparency) |
| `TSCONF_DMA_BLT2_RAM` | 0x31 | Blitter с aдером |
| `TSCONF_DMA_FILL` | 0x21 | Заполнение RAM |
| `TSCONF_DMA_RAM_CRAM` | 0xA1 | RAM → CRAM (палитра, RGB555) |
| `TSCONF_DMA_RAM_SFILE` | — | RAM → Sprite File |
| `TSCONF_DMA_SPI_RAM` | 0x11 | SPI → RAM (чтение SD) |
| `TSCONF_DMA_RAM_SPI` | 0x91 | RAM → SPI (запись SD) |
| `TSCONF_DMA_IDE_RAM` | 0x19 | IDE → RAM |
| `TSCONF_DMA_RAM_IDE` | 0x99 | RAM → IDE |
| `TSCONF_DMA_FDD_RAM` | 0x29 | FDD → RAM |
| `TSCONF_DMA_RAM_WTP` | 0xB9 | RAM → Wait Port |
| `TSCONF_DMA_WTP_RAM` | 0x39 | Wait Port → RAM |
### Флаги DMA
| Константа | Значение | Описание |
|-----------|----------|----------|
| `TSCONF_DMA_ASZ_256` | 0x00 | Выравнивание 256 байт |
| `TSCONF_DMA_ASZ_512` | 0x04 | Выравнивание 512 байт |
| `TSCONF_DMA_D_ALGN` | 0x08 | Выравнивание приёмника |
| `TSCONF_DMA_S_ALGN` | 0x10 | Выравнивание источника |
| `TSCONF_DMA_ACT` | 0x80 | DMA active (бит статуса при чтении) |
### Wait Port Device (#25AF)
| Константа | Значение | Описание |
|-----------|----------|----------|
| `TSCONF_DMAWP_GLUCLOCK` | 0x00 | GluClock |
| `TSCONF_DMAWP_COMPORT` | 0x01 | COM-порт |
### Основные регистры DMA
> Порты DMA описаны выше в таблице портов. Основные:
| Регистр | Порт | Описание |
|---------|------|----------|
| DMA_SAL/H/X | `#19AF`/`#1AAF`/`#1BAF` | Адрес + страница источника |
| DMA_DAL/H/X | `#1CAF`/`#1DAF`/`#1EAF` | Адрес + страница приёмника |
| DMA_LEN | `#26AF` | Размер бёрста (N) |
| DMA_NUM/H | `#28AF`/`#2CAF` | Количество бёрстов (T) |
| DMA_CTRL | `#27AF` | Режим + запуск (W) / статус (R) |
### Пример DMA через WC API (C)
```c
// Копирование 4 КБ из стр. 0 плагина (#8000) в стр. 1 (#8000)
wc_dmapl(WC_DMA_INIT_SD); // потребует B,C,HL,DE в регистрах
wc_dmapl(WC_DMA_SET_TN); // B=бёрсты, C=размер бёрста
wc_dmapl(WC_DMA_RUN_RAM); // запуск RAM→RAM с ожиданием
```
---
## Использование портов из SDCC
`tsconf.h` объявляет все порты как `__sfr __banked` переменные для
прямого ввода/вывода без `__asm`:
```c
// Примеры:
sfr_page2 = 5; // OUT (#12AF), 5
sfr_sysconfig = TSCONF_CPU_14MHZ; // OUT (#20AF), 2
sfr_border = 2; // OUT (#0FAF), 2
sfr_opl3_addr0 = 0x20; // OUT (#00C4), 0x20
sfr_opl3_data0 = 0xFF; // OUT (#00C5), 0xFF
// Чтение:
uint8_t page = sfr_page2; // IN A,(#12AF)
```
Полный список: `sfr_vconfig`, `sfr_vpage`, `sfr_gxoffsl/h`, `sfr_gyoffsl/h`,
`sfr_tsconfig`, `sfr_palsel`, `sfr_border`, `sfr_page0`–`sfr_page3`,
`sfr_sysconfig`, `sfr_memconfig`, `sfr_intmask`, `sfr_cacheconfig`,
`sfr_dmasaddrh/l/x`, `sfr_dmadaddrh/l/x`, `sfr_dmalen`, `sfr_dmactrl`,
`sfr_dmanum/h`, `sfr_opl3_addr0/data0/addr1/data1`, `sfr_ay_addr/data`,
`sfr_saa_addr/data`, `sfr_saa2_addr/data`.
## Видео система
### Видео режимы (VConfig #00AF)
| Режим | Константа | Разрешения | Цвета |
|-------|-----------|------------|-------|
| ZX | `TSCONF_VM_ZX` (0x00) | 256×192 | 16 (атрибуты) |
| 16c | `TSCONF_VM_16C` (0x01) | 256..360 | 16 (4 bpp) |
| 256c | `TSCONF_VM_256C` (0x02) | 256..360 | 256 (8 bpp) |
| TXT | `TSCONF_VM_TXT` (0x03) | 80×25, 80×30, 90×36 | 256 |
**Разрешения:**
| Константа | Значение | Пиксели |
|-----------|----------|---------|
| `TSCONF_RRES_256x192` | 0x00 | 256×192 |
| `TSCONF_RRES_320x200` | 0x40 | 320×200 |
| `TSCONF_RRES_320x240` | 0x80 | 320×240 |
| `TSCONF_RRES_360x288` | 0xC0 | 360×288 |
**Прочие биты VConfig:**
| Константа | Бит | Описание |
|-----------|-----|----------|
| `TSCONF_VC_FT_EN` | 2 | FT812 enable (VDAC2) |
| `TSCONF_VC_GFXOVR` | 3 | GFX over TSU |
| `TSCONF_VC_NOTSU` | 4 | Отключить TSU graphics |
| `TSCONF_VC_NOGFX` | 5 | Отключить main graphics |
**Чтение VConfig (статус):**
| Константа | Значение | Описание |
|-----------|----------|----------|
| `TSCONF_VDVER_2BIT_PWM` | 0x00 | 2-бит ЦАП (ШИМ) |
| `TSCONF_VDVER_3BIT` | 0x01 | 3-бит |
| `TSCONF_VDVER_4BIT` | 0x02 | 4-бит |
| `TSCONF_VDVER_5BIT` | 0x03 | 5-бит |
| `TSCONF_VDVER_VDAC2` | 0x07 | VDAC2 / FT812 |
| `TSCONF_STATUS_PWR_UP` | 0x40 | Після включення |
### Палитра
256 ячеек палитры, формат RGB555 (15 бит цвета).
### Спрайты
- До 85 спрайтов на строку
- Размеры: 8x8 до 64x64 пикселей
- До 3 плоскостей спрайтов
- До 16 палитр на строку
## Совместимость с Pentagon-128
### Порт #7FFD
```
Биты:
7:6 - дополнительные биты страницы (512K/1024K)
5 - LOCK (блокировка переключения)
4 - ROM128 (выбор ROM)
3 - SCR (экран 5 или 7)
2:0 - номер страницы для #C000
```
### Режимы совместимости (MemConfig [7:6])
| LCK128 | Режим | Описание |
|--------|-------|----------|
| 00 | Pentagon-512 | `TSCONF_MEM_LCK128_512K` |
| 01 | Pentagon-128 | `TSCONF_MEM_LCK128_128K` |
| 10 | Авто | `TSCONF_MEM_LCK128_AUTO` |
| 11 | 1024 КБ | `TSCONF_MEM_LCK128_1M` |
---
## FDD виртуализация (#29AF)
TSConfig позволяет виртуализировать FDD-приводы (для TRD/TAP):
| Константа | Значение | Описание |
|-----------|----------|----------|
| `TSCONF_FDD_A` | 0x01 | Привод A |
| `TSCONF_FDD_B` | 0x02 | Привод B |
| `TSCONF_FDD_C` | 0x04 | Привод C |
| `TSCONF_FDD_D` | 0x08 | Привод D |
| `TSCONF_FDD_VG_OPEN` | 0x80 | Открыть VG93 |
---
## Файловая система
WC работает через FAT32:
- **SD-карты**: Z-Controller (основной), NeoGS SD
- **IDE**: NEMO (Master/Slave), SMUC (Master/Slave)
- **Длинные имена**: до 255 символов (с WC v0.73)
- **Каталоги**: >4095 записей (с WC v1.05)
---
## Полезные ссылки
- TSConfig спецификация: https://github.com/tslabs/zx-evo
- Регистры TSConfig: [src_sdcc/inc/tsconf.h](../src_sdcc/inc/tsconf.h)
- WC API: [src_sdcc/inc/wc_api.h](../src_sdcc/inc/wc_api.h)
- ISR конфигурация: [src_sdcc/inc/variant_cfg.h](../src_sdcc/inc/variant_cfg.h)
## Пример инициализации для плагина
```asm
; Базовая инициализация для музыкального плагина
INIT_PLUGIN:
; Сохранить текущее состояние
LD A,(#6002) ; Страница в окне 2
PUSH AF
LD A,(#6003) ; Страница в окне 3
PUSH AF
; Восстановить TXT режим
LD A,#0F
CALL WLD ; GEDPL
; Установить частоту CPU
LD B,#00 ; Z80 frequency
LD C,%01 ; 7 MHz
LD A,#0E
CALL WLD ; TURBOPL
; Настроить прерывания
LD HL,INT_HANDLER
EXA
LD A,#FF
CALL WLD ; INT_PL
EXA
; Инициализация OPL3
CALL INIT_OPL3
RET
; Обработчик прерываний
INT_HANDLER:
PUSH AF, BC, DE, HL
; Ваш код обработки музыки
CALL UPDATE_MUSIC
POP HL, DE, BC, AF
EI
RETI
; Инициализация OPL3
INIT_OPL3:
; Сброс OPL3
LD BC,#C4
XOR A
OUT (C),A
LD B,#C5
OUT (C),A
; Дополнительная инициализация...
RET
```