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
+531
View File
@@ -0,0 +1,531 @@
/**
* @file tsconf.h
* @brief Полный справочник регистров TSConfig (TSL FPGA-ускоритель ZX Spectrum)
* @version 2.0
*
* Самодостаточная библиотека: зависит только от types.h.
* Подходит для любого TSConfig-проекта на SDCC Z80.
*
* ═══════════════════════════════════════════════════════════════════
* АРХИТЕКТУРА ПОРТОВ
* ═══════════════════════════════════════════════════════════════════
*
* Все порты TSConfig адресуются по схеме: (REG_NUM << 8) | 0xAF
* Запись: OUT (C),A где BC = порт.
*
* На ASM:
* LD BC, TSCONF_PORT_SYSCONFIG ; BC = 0x20AF
* LD A, TSCONF_CPU_14MHZ
* OUT (C), A
*
* На C:
* tsconf_out(TSCONF_PORT_SYSCONFIG, TSCONF_CPU_14MHZ);
*
* Макросы-обёртки (конец файла) упрощают типичные операции:
* tsconf_set_cpu(TSCONF_CPU_14MHZ);
* tsconf_set_border(1);
* tsconf_set_frame_int(100, 0);
*
* ═══════════════════════════════════════════════════════════════════
* ТАЙМИНГИ TV-РЕЖИМА (Pentagon-128)
* ═══════════════════════════════════════════════════════════════════
*
* Строк в кадре: 320 (0–319)
* Строки 0–31: вертикальное гашение
* Строки 32–319: видимая область (бордер + пиксели)
*
* Пикселей в строке: 448 (7 МГц), = 224 T-states при 3.5 МГц
* Пиксели 0–87: горизонтальное гашение
* Пиксели 88–447: видимая область
*
* T-states в кадре: 320 × 224 = 71680 T
*
* ══════════════════════════════════════════════════════════════════════
* ПРЕРЫВАНИЯ (IM2)
* ══════════════════════════════════════════════════════════════════════
*
* Три источника, каждый выставляет свой вектор на шину данных:
* FRAME (#FF, приоритет 0) — совпадение растровых счётчиков
* с регистрами HSINT/VSINT
* LINE (#FD, приоритет 1) — каждая строка при HCNT = 0
* DMA (#FB, приоритет 2) — конец DMA-транзакции
*
* HSINT = HCNT[8:1]: горизонтальная позиция (0–223). >223 = выкл.
* VSINTL/VSINTH = VCNT[8:0]: вертикальная строка (0–319). >319 = выкл.
*
* VINT_INC[3:0] в VSINTH: автоинкремент VCNT после каждого FRAME-INT
* (позволяет менять строку прерывания без записи в порты).
*
* ═══════════════════════════════════════════════════════════════════
* ВИДЕО
* ═══════════════════════════════════════════════════════════════════
*
* VM[1:0]: 00=ZX (256x192, атрибуты), 01=16c, 10=256c, 11=txt
* RRES[1:0]: 00=256x192, 01=320x200, 10=320x240, 11=360x288
*
* ═══════════════════════════════════════════════════════════════════
* DMA
* ═══════════════════════════════════════════════════════════════════
*
* Адрес = 22-бит: [X(8)][H(6)][L(7)][0] — младший бит всегда 0.
*
* ═══════════════════════════════════════════════════════════════════
* ПРИМЕР (минимальный)
* ═══════════════════════════════════════════════════════════════════
*
* #include "tsconf.h"
*
* void demo(void) {
* tsconf_set_cpu(TSCONF_CPU_14MHZ); // 14 МГц
* tsconf_set_border(2); // красный бордюр
* tsconf_set_vconfig(TSCONF_VM_ZX // ZX-режим
* | TSCONF_RRES_256x192); // 256x192
* tsconf_set_frame_int(100, 0); // INT на строке 100
* tsconf_set_intmask(TSCONF_INT_FRAME); // только FRAME
* tsconf_set_cpu(TSCONF_CPU_3_5MHZ); // вернуть 3.5
* }
*/
#ifndef TSCONF_H
#define TSCONF_H
#include "types.h"
/* ══════════════════════════════════════════════════════════════════════
* Макрос формирования адреса порта
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT(reg) (((uint16_t)(reg) << 8) | 0xAF)
/* ══════════════════════════════════════════════════════════════════════
* ВИДЕО — VConfig (#00AF)
* W: RRES[1:0] | - | NOGFX | NOTSU | GFXOVR* | FT_EN** | VM[1:0]
* R: - | PWR_UP | - | FDRVER | VDVER[2:0]
* * только VDAC, ** только VDAC2. Сброс: 0x00
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_VCONFIG TSCONF_PORT(0x00)
/* VM[1:0] — видеорежим */
#define TSCONF_VM_ZX 0x00 /* ZX-Spectrum, 256×192, атрибуты */
#define TSCONF_VM_16C 0x01 /* 16 цветов, 4 бита/пиксель */
#define TSCONF_VM_256C 0x02 /* 256 цветов, 8 бит/пиксель */
#define TSCONF_VM_TXT 0x03 /* Текстовый режим */
#define TSCONF_VM_MASK 0x03
/* FT_EN, GFXOVR, NOTSU, NOGFX */
#define TSCONF_VC_FT_EN 0x04 /* FT812 enable (VDAC2) */
#define TSCONF_VC_GFXOVR 0x08 /* GFX поверх TSU (VDAC) */
#define TSCONF_VC_NOTSU 0x10 /* Отключить TSU-графику */
#define TSCONF_VC_NOGFX 0x20 /* Отключить основную графику */
/* RRES[1:0] — разрешение экрана */
#define TSCONF_RRES_256x192 (0x00 << 6)
#define TSCONF_RRES_320x200 (0x01 << 6)
#define TSCONF_RRES_320x240 (0x02 << 6)
#define TSCONF_RRES_360x288 (0x03 << 6)
#define TSCONF_RRES_MASK (0x03 << 6)
/* R: Status (то же адрес #00AF, чтение) */
#define TSCONF_STATUS_VDVER_MASK 0x07
#define TSCONF_STATUS_FDRVER 0x10
#define TSCONF_STATUS_PWR_UP 0x40
#define TSCONF_VDVER_2BIT_PWM 0x00
#define TSCONF_VDVER_3BIT 0x01
#define TSCONF_VDVER_4BIT 0x02
#define TSCONF_VDVER_5BIT 0x03
#define TSCONF_VDVER_VDAC2 0x07
/* ── VPage (#01AF): адрес видеостраницы RA[21:14] ─────────────────── */
#define TSCONF_PORT_VPAGE TSCONF_PORT(0x01)
/* ── GXOffsL (#02AF), GXOffsH (#03AF): X-смещение графики ─────────── */
#define TSCONF_PORT_GXOFFSL TSCONF_PORT(0x02) /* XO[7:0] */
#define TSCONF_PORT_GXOFFSH TSCONF_PORT(0x03) /* бит 0 = XO[8] */
/* ── GYOffsL (#04AF), GYOffsH (#05AF): Y-смещение графики ─────────── */
#define TSCONF_PORT_GYOFFSL TSCONF_PORT(0x04) /* YO[7:0] */
#define TSCONF_PORT_GYOFFSH TSCONF_PORT(0x05) /* бит 0 = YO[8] */
/* ── TSConfig (#06AF): включение tile/sprite движка ────────────────── */
#define TSCONF_PORT_TSCONFIG TSCONF_PORT(0x06)
#define TSCONF_TS_EXT 0x01 /* TSU 360×288 (не ZX-Evo) */
#define TSCONF_T0Z_EN 0x04 /* Тайл [0] виден (плоск. 0) */
#define TSCONF_T1Z_EN 0x08 /* Тайл [0] виден (плоск. 1) */
#define TSCONF_T0_EN 0x20 /* Tile-layer 0 enable */
#define TSCONF_T1_EN 0x40 /* Tile-layer 1 enable */
#define TSCONF_S_EN 0x80 /* Sprite layers enable */
/* ── PalSel (#07AF): выбор палитр ──────────────────────────────────── */
/* GPAL[7:4] | T0PAL[7:6] | T1PAL[7:6]. Сброс = 0x0F */
#define TSCONF_PORT_PALSEL TSCONF_PORT(0x07)
/* ── Border (#0FAF): цвет бордюра ──────────────────────────────────── */
#define TSCONF_PORT_BORDER TSCONF_PORT(0x0F)
/* ══════════════════════════════════════════════════════════════════════
* УПРАВЛЕНИЕ ПАМЯТЬЮ
* ══════════════════════════════════════════════════════════════════════
* RA[21:14] — номер 16KB-страницы DRAM
* Page0 = W (write-only), Page1 = W, Page2 = RW, Page3 = RW
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_PAGE0 TSCONF_PORT(0x10) /* окно #0000, W */
#define TSCONF_PORT_PAGE1 TSCONF_PORT(0x11) /* окно #4000, W */
#define TSCONF_PORT_PAGE2 TSCONF_PORT(0x12) /* окно #8000, RW */
#define TSCONF_PORT_PAGE3 TSCONF_PORT(0x13) /* окно #C000, RW */
/* ── FMAddr (#14AF): адрес Font Maps ───────────────────────────────── */
#define TSCONF_PORT_FMADDR TSCONF_PORT(0x14)
#define TSCONF_FMADDR_EN 0x10 /* бит 4 = FM_EN. Биты 3:0 = A[15:12] */
/* ── TMPage (#15AF): страница TileMap ──────────────────────────────── */
#define TSCONF_PORT_TMPAGE TSCONF_PORT(0x15) /* RA[21:14] */
/* ── T0GPage (#16AF): страница графики тайлов плоскости 0 ──────────── */
#define TSCONF_PORT_T0GPAGE TSCONF_PORT(0x16) /* RA[21:17] */
/* ── T1GPage (#17AF): страница графики тайлов плоскости 1 ──────────── */
#define TSCONF_PORT_T1GPAGE TSCONF_PORT(0x17) /* RA[21:17] */
/* ── SGPage (#18AF): страница графики спрайтов ─────────────────────── */
#define TSCONF_PORT_SGPAGE TSCONF_PORT(0x18) /* RA[21:17] */
/* ══════════════════════════════════════════════════════════════════════
* DMA — адреса источника и назначения
* Адрес = 22-бит: [X(8)][H(6)][L(7)][0]
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_DMASADDRL TSCONF_PORT(0x19) /* Source RA[7:1] */
#define TSCONF_PORT_DMASADDRH TSCONF_PORT(0x1A) /* Source RA[13:8] */
#define TSCONF_PORT_DMASADDRX TSCONF_PORT(0x1B) /* Source RA[21:14] */
#define TSCONF_PORT_DMADADDRL TSCONF_PORT(0x1C) /* Dest RA[7:1] */
#define TSCONF_PORT_DMADADDRH TSCONF_PORT(0x1D) /* Dest RA[13:8] */
#define TSCONF_PORT_DMADADDRX TSCONF_PORT(0x1E) /* Dest RA[21:14] */
#define TSCONF_PORT_DMAWPDEV TSCONF_PORT(0x25) /* DMA Wait Port Dev */
#define TSCONF_PORT_DMALEN TSCONF_PORT(0x26) /* Burst Length [7:0] */
#define TSCONF_PORT_DMACTRL TSCONF_PORT(0x27) /* Ctrl W / Status R */
#define TSCONF_PORT_DMANUM TSCONF_PORT(0x28) /* Bursts Num [7:0] */
#define TSCONF_PORT_DMANUMH TSCONF_PORT(0x2C) /* Bursts Num [9:8] */
#define TSCONF_PORT_DMAWPADDR TSCONF_PORT(0x2D) /* Wait Port Addr */
/* DMACtrl W — DDEV[3:0]: режим DMA */
#define TSCONF_DMA_RAM_RAM 0x09 /* RAM→RAM copy */
#define TSCONF_DMA_BLT1_RAM 0x89 /* RAM→RAM, пропуск нулей (OPT=1) */
#define TSCONF_DMA_FILL 0x21 /* Fill: src → dest*N */
#define TSCONF_DMA_RAM_CRAM 0xA1 /* RAM→CRAM (палитра) */
#define TSCONF_DMA_SPI_RAM 0x11 /* SPI→RAM */
#define TSCONF_DMA_RAM_SPI 0x91 /* RAM→SPI */
#define TSCONF_DMA_IDE_RAM 0x19 /* IDE→RAM */
#define TSCONF_DMA_RAM_IDE 0x99 /* RAM→IDE */
#define TSCONF_DMA_FDD_RAM 0x29 /* FDD→RAM */
#define TSCONF_DMA_RAM_WTP 0xB9 /* RAM→Wait Port */
#define TSCONF_DMA_WTP_RAM 0x39 /* Wait Port→RAM */
#define TSCONF_DMA_BLT2_RAM 0x31 /* Блиттер с аддером */
/* DMACtrl — флаги */
#define TSCONF_DMA_ASZ_256 0x00 /* Выравнивание 256 байт */
#define TSCONF_DMA_ASZ_512 0x04 /* Выравнивание 512 байт */
#define TSCONF_DMA_D_ALGN 0x08 /* Выравнивание назначения */
#define TSCONF_DMA_S_ALGN 0x10 /* Выравнивание источника */
/* R: DMAStatus */
#define TSCONF_DMA_ACT 0x80 /* DMA активна */
/* DMAWPDev */
#define TSCONF_DMAWP_GLUCLOCK 0x00
#define TSCONF_DMAWP_COMPORT 0x01
/* ══════════════════════════════════════════════════════════════════════
* СИСТЕМНАЯ КОНФИГУРАЦИЯ
* ══════════════════════════════════════════════════════════════════════ */
/* ── SysConfig (#20AF): частота CPU и кэш ──────────────────────────── */
#define TSCONF_PORT_SYSCONFIG TSCONF_PORT(0x20)
#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 /* Включить кэш (все 4 окна) */
/* ── MemConfig (#21AF) ────────────────────────────────────────────────
* ROM128: бит 0 = то же что бит 4 в #7FFD (BootROM/Basic)
* W0_WE: разрешить запись в окно #0000
* !W0_MAP: 0=маппинг через Page0, 1=стандартная страница 0
* W0_RAM: 0=ROM, 1=RAM в #0000
* LCK128: режим блокировки 128K-совместимости
* ──────────────────────────────────────────────────────────────────── */
#define TSCONF_PORT_MEMCONFIG TSCONF_PORT(0x21)
#define TSCONF_MEM_ROM128 0x01
#define TSCONF_MEM_W0_WE 0x02
#define TSCONF_MEM_W0_MAP_DIS 0x04
#define TSCONF_MEM_W0_RAM 0x08
#define TSCONF_MEM_LCK128_512K 0x00 /* 512K, биты 7:6 #7FFD=Page3[4:3] */
#define TSCONF_MEM_LCK128_128K 0x40 /* 128K, биты 7:6 #7FFD=00 */
#define TSCONF_MEM_LCK128_AUTO 0x80 /* Auto (!a[13]) */
#define TSCONF_MEM_LCK128_1M 0xC0 /* 1024K */
/* ══════════════════════════════════════════════════════════════════════
* ПРЕРЫВАНИЯ — позиция FRAME-INT
* ══════════════════════════════════════════════════════════════════════ */
/* ── HSINT (#22AF): горизонтальная позиция ─────────────────────────── */
/* HCNT[8:1] в диапазоне 0–223; >223 = выключить INT в этой строке */
#define TSCONF_PORT_HSINT TSCONF_PORT(0x22)
#define TSCONF_HSINT_OFF 0xFF
/* ── VSINTL (#23AF): вертикальная позиция [7:0] ────────────────────── */
/* VCNT[7:0]; строки 0–319; >319 = FRAME-INT выключен */
#define TSCONF_PORT_VSINTL TSCONF_PORT(0x23)
/* ── VSINTH (#24AF): вертикальная позиция [8] + автоинкремент ──────── */
/* Бит 0 = VCNT[8]; биты [7:4] = VINT_INC[3:0] */
/* VINT_INC: после каждого FRAME-INT → VCNT += VINT_INC (0 = нет) */
#define TSCONF_PORT_VSINTH TSCONF_PORT(0x24)
#define TSCONF_VSINTH_VCNT8 0x01
#define TSCONF_VSINTH_INC_MASK 0xF0
#define TSCONF_VSINTH_INC(n) (((n) & 0x0F) << 4)
/* ── INTMask (#2AAF): маска прерываний ─────────────────────────────── */
/* Сброс: 0x01 (только FRAME включён) */
#define TSCONF_PORT_INTMASK TSCONF_PORT(0x2A)
#define TSCONF_INT_FRAME 0x01
#define TSCONF_INT_LINE 0x02
#define TSCONF_INT_DMA 0x04
#define TSCONF_INT_WTP 0x08
/* Векторы IM2 (значение на шине данных при прерывании) */
#define TSCONF_IVEC_FRAME 0xFF
#define TSCONF_IVEC_LINE 0xFD
#define TSCONF_IVEC_DMA 0xFB
/* ══════════════════════════════════════════════════════════════════════
* КЭШ — CacheConfig (#2BAF)
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_CACHECONFIG TSCONF_PORT(0x2B)
#define TSCONF_CACHE_EN_0000 0x01
#define TSCONF_CACHE_EN_4000 0x02
#define TSCONF_CACHE_EN_8000 0x04
#define TSCONF_CACHE_EN_C000 0x08
#define TSCONF_CACHE_ALL 0x0F
#define TSCONF_CACHE_NONE 0x00
/* ══════════════════════════════════════════════════════════════════════
* FDD VIRTUAL DRIVE — FDDVirt (#29AF)
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_FDDVIRT TSCONF_PORT(0x29)
#define TSCONF_FDD_A 0x01
#define TSCONF_FDD_B 0x02
#define TSCONF_FDD_C 0x04
#define TSCONF_FDD_D 0x08
#define TSCONF_FDD_VG_OPEN 0x80
/* ══════════════════════════════════════════════════════════════════════
* ТАЙЛОВЫЕ ПЛОСКОСТИ — смещения
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_T0XOFFSL TSCONF_PORT(0x40)
#define TSCONF_PORT_T0XOFFSH TSCONF_PORT(0x41)
#define TSCONF_PORT_T0YOFFSL TSCONF_PORT(0x42)
#define TSCONF_PORT_T0YOFFSH TSCONF_PORT(0x43)
#define TSCONF_PORT_T1XOFFSL TSCONF_PORT(0x44)
#define TSCONF_PORT_T1XOFFSH TSCONF_PORT(0x45)
#define TSCONF_PORT_T1YOFFSL TSCONF_PORT(0x46)
#define TSCONF_PORT_T1YOFFSH TSCONF_PORT(0x47)
/* ══════════════════════════════════════════════════════════════════════
* HUS — Hurricane Sound Engine (#80AF–#87AF)
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_HUSCTRL TSCONF_PORT(0x80) /* W: управление */
#define TSCONF_PORT_HUSSAMPRATE TSCONF_PORT(0x81) /* W: SR[7:0] (1750k/(SR+1)) */
#define TSCONF_PORT_HUSTICKRATEL TSCONF_PORT(0x82) /* W: TR[7:0] */
#define TSCONF_PORT_HUSTICKRATEH TSCONF_PORT(0x83) /* W: TR[9:8] */
#define TSCONF_PORT_HUSRLD0 TSCONF_PORT(0x84) /* Reload ch 0–7 */
#define TSCONF_PORT_HUSRLD1 TSCONF_PORT(0x85) /* Reload ch 8–15 */
#define TSCONF_PORT_HUSRLD2 TSCONF_PORT(0x86)
#define TSCONF_PORT_HUSRLD3 TSCONF_PORT(0x87)
/* R: HUSStatus (#80AF) */
#define TSCONF_HUS_ACT 0x01
#define TSCONF_HUS_TICK 0x02 /* сбрасывается при чтении */
#define TSCONF_HUS_HALF 0x40 /* буфер наполовину пуст */
#define TSCONF_HUS_EMPTY 0x80
/* W: HUSControl */
#define TSCONF_HUS_PAUSE 0x02
#define TSCONF_HUS_RESET 0x80
/* ══════════════════════════════════════════════════════════════════════
* OPL3 (YMF262) — порты на шине TSConfig
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_OPL3_ADDR0 0x00C4
#define TSCONF_PORT_OPL3_DATA0 0x00C5
#define TSCONF_PORT_OPL3_ADDR1 0x00C6
#define TSCONF_PORT_OPL3_DATA1 0x00C7
/* ══════════════════════════════════════════════════════════════════════
* AY-3-8910 / YM2149 — стандартные порты ZX Spectrum 128
* ══════════════════════════════════════════════════════════════════════
* #FFFD — выбор регистра (W) / чтение данных (R)
* #BFFD — запись данных (W)
*
* TurboSound (два AY): запись в #FFFD значения #FF/#FE выбирает чип:
* #FF → чип 0 (первый AY); #FE → чип 1 (второй AY).
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_AY_ADDR 0xFFFD /* register select / read */
#define TSCONF_PORT_AY_DATA 0xBFFD /* data write */
#define TSCONF_AY_TS_CHIP0 0xFF /* TurboSound: select chip 0 */
#define TSCONF_AY_TS_CHIP1 0xFE /* TurboSound: select chip 1 */
/* ══════════════════════════════════════════════════════════════════════
* SAA1099 — порты SAM Coupé / ZX-совместимые
* ══════════════════════════════════════════════════════════════════════
* #01FF — выбор регистра (address write)
* #00FF — запись данных (data write)
* Второй SAA1099 (если есть):
* #01FE — выбор регистра
* #00FE — запись данных
* ══════════════════════════════════════════════════════════════════════ */
#define TSCONF_PORT_SAA_ADDR 0x01FF /* SAA1099 #1 address */
#define TSCONF_PORT_SAA_DATA 0x00FF /* SAA1099 #1 data */
#define TSCONF_PORT_SAA2_ADDR 0x01FE /* SAA1099 #2 address */
#define TSCONF_PORT_SAA2_DATA 0x00FE /* SAA1099 #2 data */
/* ══════════════════════════════════════════════════════════════════════
* WC СИСТЕМНЫЕ ПЕРЕМЕННЫЕ — адреса в ROM-области ядра WC
* ══════════════════════════════════════════════════════════════════════ */
#define WC_ADDR_PAGES 0x6000 /* [3 байта] страницы #0000,#4000,#8000 */
#define WC_ADDR_ABT 0x6004 /* флаг ESC */
#define WC_ADDR_ENT 0x6005 /* флаг ENTER */
#define WC_ADDR_TMN 0x6009 /* таймер (инкр. по INT), uint16 */
#define WC_ADDR_CNFV 0x600D /* версия конфигурации */
#define WC_ADDR_HEI 0x600E /* высота экрана (25/30/36 строк) */
#define WC_CNFV_PWM 0x00
#define WC_CNFV_3BIT 0x01
#define WC_CNFV_4BIT 0x02
#define WC_CNFV_5BIT 0x03
#define WC_CNFV_VDAC2 0x07
/* ══════════════════════════════════════════════════════════════════════
* SFR — прямой доступ к портам из SDCC-C
* ══════════════════════════════════════════════════════════════════════
*
* __sfr __at 0xNN — 8-bit port: out (N), a / in a, (N)
* __sfr __banked __at 0xNNNN — 16-bit port: ld bc,#NNNN; out (c),a
*
* Не создают переменных/символов — чисто compile-time mapping.
* Присваивание sfr_xxx = val; генерирует inline OUT.
* Чтение val = sfr_xxx; генерирует inline IN.
* ══════════════════════════════════════════════════════════════════════ */
/* --- Стандартный ZX Spectrum: 8-bit порт ----------------------------- */
__sfr __at 0xFE sfr_zx_fe; /* border / keyboard */
/* --- TSConfig регистры (addr = reg<<8 | 0xAF) ----------------------- */
__sfr __banked __at 0x00AF sfr_vconfig; /* VConfig */
__sfr __banked __at 0x01AF sfr_vpage; /* VPage */
__sfr __banked __at 0x02AF sfr_gxoffsl; /* GXOffsL */
__sfr __banked __at 0x03AF sfr_gxoffsh; /* GXOffsH */
__sfr __banked __at 0x04AF sfr_gyoffsl; /* GYOffsL */
__sfr __banked __at 0x05AF sfr_gyoffsh; /* GYOffsH */
__sfr __banked __at 0x06AF sfr_tsconfig; /* TSConfig */
__sfr __banked __at 0x07AF sfr_palsel; /* PalSel */
__sfr __banked __at 0x0FAF sfr_border; /* Border Color */
__sfr __banked __at 0x10AF sfr_page0; /* Page0 (#0000) */
__sfr __banked __at 0x11AF sfr_page1; /* Page1 (#4000) */
__sfr __banked __at 0x12AF sfr_page2; /* Page2 (#8000) */
__sfr __banked __at 0x13AF sfr_page3; /* Page3 (#C000) */
__sfr __banked __at 0x14AF sfr_fmaddr; /* FMAddr */
__sfr __banked __at 0x15AF sfr_tmpage; /* TMPage */
__sfr __banked __at 0x16AF sfr_t0gpage; /* T0GPage */
__sfr __banked __at 0x17AF sfr_t1gpage; /* T1GPage */
__sfr __banked __at 0x18AF sfr_sgpage; /* SGPage */
__sfr __banked __at 0x20AF sfr_sysconfig; /* SysConfig (CPU) */
__sfr __banked __at 0x21AF sfr_memconfig; /* MemConfig */
__sfr __banked __at 0x22AF sfr_hsint; /* HSINT */
__sfr __banked __at 0x23AF sfr_vsintl; /* VSINTL */
__sfr __banked __at 0x24AF sfr_vsinth; /* VSINTH */
__sfr __banked __at 0x2AAF sfr_intmask; /* INTMask */
__sfr __banked __at 0x2BAF sfr_cacheconfig; /* CacheConfig */
__sfr __banked __at 0x29AF sfr_fddvirt; /* FDDVirt */
/* --- DMA --- */
__sfr __banked __at 0x1AAF sfr_dmasaddrh; /* DMA Src Addr H */
__sfr __banked __at 0x1BAF sfr_dmasaddrx; /* DMA Src Addr X */
__sfr __banked __at 0x19AF sfr_dmasaddrl; /* DMA Src Addr L */
__sfr __banked __at 0x1CAF sfr_dmadaddrl; /* DMA Dst Addr L */
__sfr __banked __at 0x1DAF sfr_dmadaddrh; /* DMA Dst Addr H */
__sfr __banked __at 0x1EAF sfr_dmadaddrx; /* DMA Dst Addr X */
__sfr __banked __at 0x26AF sfr_dmalen; /* DMA Burst Length */
__sfr __banked __at 0x27AF sfr_dmactrl; /* DMA Ctrl / Status */
__sfr __banked __at 0x28AF sfr_dmanum; /* DMA Bursts Num L */
__sfr __banked __at 0x2CAF sfr_dmanumh; /* DMA Bursts Num H */
/* --- OPL3 (YMF262) --- */
__sfr __banked __at 0x00C4 sfr_opl3_addr0; /* Bank0 address */
__sfr __banked __at 0x00C5 sfr_opl3_data0; /* Bank0 data */
__sfr __banked __at 0x00C6 sfr_opl3_addr1; /* Bank1 address */
__sfr __banked __at 0x00C7 sfr_opl3_data1; /* Bank1 data */
/* --- AY-3-8910 / YM2149 --- */
__sfr __banked __at 0xFFFD sfr_ay_addr; /* reg select / read */
__sfr __banked __at 0xBFFD sfr_ay_data; /* data write */
/* --- SAA1099 --- */
__sfr __banked __at 0x01FF sfr_saa_addr; /* SAA1099 #1 address */
__sfr __banked __at 0x00FF sfr_saa_data; /* SAA1099 #1 data */
__sfr __banked __at 0x01FE sfr_saa2_addr; /* SAA1099 #2 address */
__sfr __banked __at 0x00FE sfr_saa2_data; /* SAA1099 #2 data */
/* ══════════════════════════════════════════════════════════════════════
* ФУНКЦИИ — обёртки
* ══════════════════════════════════════════════════════════════════════ */
/** Запись значения в произвольный TSConfig-порт (asm, для динамических адресов)
* @param port TSCONF_PORT(reg)
* @param val значение */
extern void tsconf_out(uint16_t port, uint8_t val);
/* ── Удобные макросы (через __sfr — inline, без call) ────────────────── */
/** Установить скорость CPU (TSCONF_CPU_3_5MHZ / 7MHZ / 14MHZ) */
#define tsconf_set_cpu(speed) \
(sfr_sysconfig = (uint8_t)((speed) & TSCONF_CPU_MASK))
/** Установить скорость CPU с управлением кэшем */
#define tsconf_set_cpu_cache(speed, cache_en) \
(sfr_sysconfig = (uint8_t)(((speed) & TSCONF_CPU_MASK) | ((cache_en) ? TSCONF_CACHE_EN : 0)))
/** Установить маску прерываний (OR нужных TSCONF_INT_*) */
#define tsconf_set_intmask(mask) \
(sfr_intmask = (uint8_t)(mask))
/** Настроить позицию FRAME-INT: line=0–319, hpos=0–223 */
#define tsconf_set_frame_int(line, hpos) do { \
sfr_vsinth = (uint8_t)(((line) >> 8) & 0x01); \
sfr_vsintl = (uint8_t)((line) & 0xFF); \
sfr_hsint = (uint8_t)(hpos); \
} while(0)
/** Выключить FRAME-INT полностью */
#define tsconf_disable_frame_int() \
(sfr_hsint = TSCONF_HSINT_OFF)
/** Настроить кэш по окнам: маска из TSCONF_CACHE_EN_* */
#define tsconf_set_cache(mask) \
(sfr_cacheconfig = (uint8_t)(mask))
/** Установить цвет бордюра (TSConfig-регистр) */
#define tsconf_set_border(color) \
(sfr_border = (uint8_t)(color))
/** Подключить видеостраницу (номер 0–63) на адрес #C000 */
#define tsconf_set_vpage(page) \
(sfr_vpage = (uint8_t)(page))
/** Установить видеорежим (OR из TSCONF_VM_*, TSCONF_RRES_*, TSCONF_VC_*) */
#define tsconf_set_vconfig(cfg) \
(sfr_vconfig = (uint8_t)(cfg))
/** Подключить RAM-страницу page на окно #C000 (Page3) */
#define tsconf_set_page3(page) \
(sfr_page3 = (uint8_t)(page))
/** Подключить RAM-страницу page на окно #8000 (Page2) */
#define tsconf_set_page2(page) \
(sfr_page2 = (uint8_t)(page))
#endif /* TSCONF_H */