# 5. Графика и видеосистема

## 5.1 Общие сведения

Видеосистема Sprinter Sp2000 реализована в ППЛМ. Видео-ОЗУ — 256 КБ
(512 КБ на некоторых платах [Architecture.txt:17]).

| Параметр | Значение |
|---|---|
| VRAM | 256 КБ, независимая микросхема (не часть RAM SIMM) |
| Физические страницы | `#50..#5F` (16 страниц × 16 КБ), фиксировано в железе |
| Видеорежимы | ZX-40, ZX-80, GR-256-8, GR-16-16 |
| Палитра | 8 палитр × 256 цветов из 16 млн (RGB, BGR) |
| Видеовыход | CGA-монитор, RGB, TV (SCART) |

**Теневая память (Shadow RAM):** Видео-ОЗУ Спринтера является теневой памятью
(§5.4). Программа управляет режимом записи через номер подключаемой страницы
(§5.3): банк `0x50` пишет одновременно в VRAM и в основное ОЗУ; банк `0x54`
пишет только в VRAM, не трогая ОЗУ. На экране **всегда** отображается
содержимое VRAM, независимо от режима записи [IvanMak.txt:317–322].

---

## 5.2 Режимы адресации видео-ОЗУ

Видео-ОЗУ может адресоваться двумя способами — **спектрумовским** и
**графическим** [IvanMak.txt:296–300]. Спектрумовский режим используется для
Spectrum-совместимого вывода и загрузки знакогенераторов; графический — для
всех остальных видеорежимов (320×256×256, 640×256×16, текст 80×32).

### 5.2.1 Спектрумовский режим адресации

В этом режиме VRAM разбивается на **32 блока по 8 КБ**. Адрес блока задаётся
через порт `RGADR` (`PORT_Y`, `#89`):

| Бит | Назначение |
|-----|-----------|
| 4..0 | Номер блока (0..31) |
| 5 | Не используется |
| 6 | Запрет вывода (1 = отключить спектрумовский вывод) |
| 7 | Разрешение 16-КБ страницы (1 = два блока в `#4000..#7FFF`) |

Бит 0 RGADR вместе с битом 1 порта `#7FFD` определяет чётность подключаемого
блока VRAM: чётный RGADR → блок N в `#4000..#5FFF`, блок N+1 в `#C000..#DFFF`;
нечётный → наоборот [IvanMak.txt:333–339].

Для записи в определённую пару спектрумовских блоков:
1. Записать номер блока в `RGADR` (`OUT (#89),A`).
2. Убедиться, что в окне (`#4000` или `#C000`) стоит подходящая страница
   основного ОЗУ (любая, кроме `#50..#5F`).
3. Чтение/запись по спектрумовским адресам (`#4000..#5FFF`,
   `#C000..#DFFF`) попадает в VRAM через текущий блок.

**Выключение спектрумовского вывода:** Если программа не использует
Spectrum-совместимую графику, `RGADR` рекомендуется установить в `#C0..#FF`
(бит 6 = 1). В этом случае вывод в VRAM через спектрумовский режим не
производится [IvanMak.txt:346–348].

### 5.2.2 Графический режим адресации

В графическом режиме видео-ОЗУ организовано как матрица **256 строк
(rows) × 1024 байта** [IvanMak.txt:357–358]. Адресация:

```
VRAM_адрес = (RGADR << 10) | (Z80_A[9:0])
  где RGADR[7:0] = Y (номер строки, 0..255)
      Z80_A[9:0] = X (смещение в строке, 0..1023)
```

Страницы `#50..#5F` при маппинге в любое окно Z80 включают графическую
адресацию. При этом младшие 4 бита номера страницы не влияют на адрес
памяти, а задают подрежим вывода (§5.3).

**Важная особенность:** Z80-адрес внутри окна (биты A[13:10] для окна W3)
**игнорируется** — весь 16-КБ диапазон окна отображает **одну и ту же
строку**, выбранную `RGADR`. Доступ к другим строкам — только через смену
`RGADR`. Это означает, что утверждение из SprinterGraphics programming.txt
о доступе к строкам 18..31 через адреса `#C400..#FC00` **неверно**.

**Структура 1-КБ строки (1024 байта):**

| Смещение в строке | Назначение |
|-------------------|-----------|
| `#000..#13F` (0..319) | Экранная страница 0 (первые 320 байт) |
| `#140..#27F` (320..639) | Экранная страница 1 (следующие 320 байт) |
| `#280..#3FF` (640..1023) | Не используется / данные палитры |

Две экранные страницы (0 и 1) переключаются битом 0 порта `RGMOD` [IvanMak.txt:409].

**Работа с адресацией из программы:**

```asm
; Установить страницу VRAM (0x50) в W3
IN    A, (#E2)          ; сохранить текущую W3
LD    (old_page), A
LD    A, #50
OUT   (#E2), A          ; W3 = VRAM страница 0x50

; Выбрать строку Y
LD    A, Y              ; Y = 0..255
OUT   (#89), A          ; RGADR = Y

; Чтение/запись пикселя (X,Y) для экранной страницы 0
LD    HL, #C000 + X     ; X = 0..319
LD    (HL), colour      ; запись байта пикселя

; Восстановить страницу
LD    A, (old_page)
OUT   (#E2), A
```

---

## 5.3 Подрежимы вывода (страницы `#50..#5F`)

Биты 2 и 3 номера страницы (из диапазона `#50..#5F`) задают подрежимы вывода
[IvanMak.txt:364–386]:

| Бит | Страницы | Эффект |
|-----|----------|--------|
| 3 | `#58..#5F` | **Прозрачный цвет** — запись байта `#FF` игнорируется (для спрайтов) |
| 2 | `#54..#57`, `#5C..#5F` | **Без тени** — запись только в VRAM, не в основное ОЗУ (для курсора мыши) |

Биты 0 и 1 должны быть 0 для совместимости с будущими прошивками
[IvanMak.txt:384–386].

---

## 5.4 Теневая память (Shadow RAM) и двойная запись

Видео-ОЗУ Спринтера является теневой памятью по отношению к основному ОЗУ
[IvanMak.txt:317–322]. Видеоконтроллер **всегда** читает изображение из VRAM
для вывода на экран; основное ОЗУ в формировании изображения не участвует.
Однако при записи через графические банки `#50..#5F` поведение зависит от
выбранного подрежима:

- **Банк `0x50` (normal):** запись идёт **одновременно** в VRAM и в
  соответствующую область основного ОЗУ. Чтение из того же Z80-адреса
  возвращает данные из основного ОЗУ, а не из VRAM — VRAM для процессора
  на чтение не видна.
- **Банк `0x54` (noshadow):** запись — только в VRAM, основное ОЗУ не
  изменяется. Чтение — из основного ОЗУ (там хранится «фон»).
- **Банк `0x58` (transparent):** как normal, но байт `#FF` не пишется.
- **Банк `0x5C` (sprite):** transparent + noshadow.
- **Обычные банки (не `#50..#5F`):** никакого доступа к VRAM нет,
  чтение/запись идут напрямую в основное ОЗУ.

**Зачем это нужно:**

1. **Восстановление после переключения видеорежима:** данные в основном ОЗУ
   остаются нетронутыми, так что при возврате в графический режим экран можно
   восстановить без перерисовки [IvanMak.txt:325].
2. **Heal спрайтов** (libbgi): фон, на который был выведен спрайт в банке
   `GFX_BANK_SPRITE` (`0x5C`, без тени), остался в основном ОЗУ. После
   перемещения спрайта фон копируется из основного ОЗУ обратно в VRAM
   (операция heal), стирая спрайт.
3. **Курсор мыши** без сохранения/восстановления: временный вывод через
   `GFX_BANK_NOSHADOW` (`0x5C`) — в основном ОЗУ данные под курсором не
   портятся, достаточно при следующем обновлении просто перерисовать фон.

**Режимы записи (см. §5.3):**

| Режим | Пишет в VRAM | Пишет в осн. ОЗУ | Применение |
|-------|:---:|:---:|-----------|
| `0x50` (normal) | Да | Да | Обычный вывод |
| `0x54` (noshadow) | Да | **Нет** | временные эффекты |
| `0x58` (transparent) | Да (кроме `#FF`) | Да | Спрайты с прозрачностью без heal |
| `0x5C` (sprite) | Да (кроме `#FF`) | **Нет** | Курсор, спрайты (прозрачность + heal) |

---

## 5.5 Видеорежимы

Система поддерживает независимую установку режима для каждого квадратика
8×8 (или 16×8 для 640-режимов) на экране [IvanMak.txt:405–469].

### Режимы вывода

| Режим | Разрешение | Цветов | Описание |
|-------|-----------|--------|----------|
| ZX-40 | 320×256 | 16 | Текстовый 40×32, Spectrum-совместимый |
| ZX-80 | 640×256 | 16 | Текстовый 80×32, до 36 знакогенераторов |
| GR-256-8 | 320×256 | 256 | Графический, 1 байт/пиксель |
| GR-16-16 | 640×256 | 16 | Графический, 4 бита/пиксель |

### Формат пикселей

**GR-256-8 (320×256×256):** один байт = один пиксель. Строка содержит
320 байт для экранной страницы 0 (смещения `#000..#13F`) и 320 байт для
страницы 1 (`#140..#27F`). Полный экран: 320 × 256 = 81 920 байт на страницу.

**GR-16-16 (640×256×16):** один байт = два пикселя: младший полубайт —
левый/первый пиксель, старший — правый/второй. Строка содержит 320 байт на
экранную страницу, что даёт 640 пикселей (320 × 2). Структура строки та же:
320 байт на страницу 0, 320 на страницу 1.

### Установка режима

Режим задаётся 4 байтами `Mode0..Mode3` в области режимов VRAM
(`#0300..#039F`). Полное описание формата Modei — [IvanMak.txt:448–469].

Для переключения видеорежима из программ используется функция DSS `SETVMOD`
(50h) [DiskSyscalls.txt:345–349]:

| A (режим) | Описание |
|-----------|----------|
| 02h | Текстовый 40×32×16 |
| 03h | Текстовый 80×32×16 |
| 81h | Графический 320×256×256 |
| 82h | Графический 640×256×16 |

B — страница экрана (0/1). Вызов: `RST 10h` с C=50h. Флаг C = ошибка
(например, режим не поддерживается данным монитором).

---

## 5.6 Палитра

8 палитр по 256 цветов, каждая занимает 1 КБ в VRAM по адресам
`#03E0..#03FE` [IvanMak.txt:540–568].

| Адреса | Палитра | Назначение |
|--------|---------|-----------|
| `#03E0..#03E2` | Граф. 0 | Графические режимы |
| `#03E4..#03E6` | Граф. 1 | —//— |
| `#03E8..#03EA` | Граф. 2 | —//— |
| `#03EC..#03EE` | Граф. 3 | —//— |
| `#03F0..#03F2` | Текст. 4 | Цвет бумаги |
| `#03F4..#03F6` | Текст. 5 | Цвет символа |
| `#03F8..#03FA` | Текст. 6 | Цвет мерцания бумаги |
| `#03FC..#03FE` | Текст. 7 | Цвет мерцания символа |

Каждый четвёртый байт в каждой палитре не используется — не может попасть
на ЦАП [IvanMak.txt:545–547]. Выбор палитры для каждого квадратика — через
биты 7..6 байта Mode1 [BIOS_v3.txt:348].

> **Примечание:** Architecture.txt упоминает всего 5 палитр (4 графические +
> 1 текстовая), но IvanMak описывает все 8: 4 графические (0–3) и 4 текстовые
> (4–7: бумага, символ, мерцание бумаги, мерцание символа)
> [IvanMak.txt:547–548, 561–568].

---

## 5.7 Структура VRAM в терминах BIOS

При использовании BIOS распределение VRAM [IvanMak.txt:387–404]:

| Адреса (линии) | Назначение |
|----------------|-----------|
| `#0000..#003F` | Спектрумовский экран (блоки 0..1) |
| `#0040..#017F` | Первый графический экран (блоки 2..11) |
| `#0180..#02BF` | Второй графический экран (блоки 12..21) |
| `#02C0..#02FF` | Знакогенераторы текстового режима |
| `#0300..#039F` | Область описания режимов экрана |
| `#03A0..#03DF` | Зарезервировано |
| `#03E0..#03FF` | Палитра |

---

## 5.8 Заблуждения и неподтверждённое

**Миф о строках 18–31:** В документе SprinterGraphics programming.txt
утверждается, что после выбора строки Y через RGADR, по адресам
`#C400..#FC00` доступны строки Y+1..Y+15 (с шагом 1 КБ). В эмуляторе MAME
это **не работает** — весь 16-КБ диапазон страницы `#50..#5F` отображает
только строку Y, независимо от бит A[13:10] адреса Z80. Требуется проверка
на реальном Sprinter Sp2000.

---

## 5.9 Кросс-ссылки

- Палитра и видеорежимы BIOS: `02-bios.md §2.7`
- SETVMOD (DSS): `03-dss.md §3.10`
- Акселератор: `06-accel.md`
- Быстрое ОЗУ и конфликт с акселератором: `04-memory.md §4.6`
- Порты RGADR/RGMOD: `11-ports.md`
- Баги акселератора: `12-bugs.md`
- Проектные документы: `sprite-api-design.md`, `accel-fill-budget.md`
