docs: справочники по железу Sprinter + правка gfx_scroll_h

- docs/new/ — сводные справочники (архитектура, BIOS, DSS, память,
  графика, акселератор, IRQ, порты, ввод, звук, известные баги);
- docs/Original/ — первоисточники, из которых они собраны (BIOS, Estex
  DSS, мануалы, описание акселератора), + Форум.doc/.docx в reference;
- libbgi/common/gfx_scroll_h.c — обход бага скролла при ширине >256
  (правка автора: шаг банды 255 и продвижение указателей на cw; старый
  вариант с 256 оставлен закомментированным с TODO);
- удалён applications/PoP/roomtest/hang_variants.png — рабочая раскладка
  из разбора позы виса, в репозитории ей не место.

Большие архивы (docs/extra ~568 МБ, docs/sources с вложенными git-репо
~68 МБ) в коммит НЕ включены — см. обсуждение.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 18:26:31 +03:00
parent 1214785a56
commit 64ce6339eb
32 changed files with 23762 additions and 3 deletions
+272
View File
@@ -0,0 +1,272 @@
# 1. Архитектура компьютера Sprinter Sp2000
## 1.1 Общие сведения
ZX Sprinter — универсальный компьютер на базе 8-битного процессора Z80. Основой является перепрограммируемая логическая матрица (ППЛМ/CPLD/FPGA), что обеспечивает гибкую изменяемую архитектуру — конфигурация схемы может меняться непосредственно во время работы.
Материнская плата — Sp2000 (разработана в конце 2000 г.).
| Параметр | Значение |
|---|---|
| Процессор | Z84C15 (Z80-совместимый, внутренние PIO/SIO/CTC) |
| Тактовая частота | 21 МГц (turbo) / 3.5 МГц (slow) |
| ОЗУ (main) | 4 МБ (72-pin SIMM) |
| Быстрое ОЗУ (КЭШ-ОЗУ) | 64 КБ (SRAM, без wait states) |
| ПЗУ | 256 КБ (8 страниц по 32 КБ) |
| Видео-ОЗУ | 256 КБ |
| Контроллер дисков | КР1818ВГ93 (аналог WD1793) |
| Поддержка НЖМД | IDE/AT |
| Контроллер клавиатуры | AT-совместимая (101 key), PS/2 |
| Контроллер мыши | Serial MS-Mouse (RS-232 через Z84C15 SIO) |
| Слоты расширения | 2 × ISA-8 |
| Звук | AY-3-8910 (в ППЛМ), 16-бит ЦАП TDA1543 (COVOX + AY) |
| COVOX-Blaster (CBL) | 16-bit с буферным ОЗУ 256 байт, 15/22 кГц |
| CMOS-часы | Dallas DS12887A (опционально, эмулируется при отсутствии) |
| Видеовыход | Аналоговый CGA-монитор, RGB, TV (SCART) |
## 1.2 Системная архитектура
Упрощённая структура:
```
┌─────────────┐
┌──────────┐ │ ISA-8 │
│ Принтер │ │ слот 1..2 │
│ Мышь │ └──────┬──────┘
│ Джойстик │ │
└─────┬────┘ ┌─────┴──────┐
│ │ Буферы и │
┌─────┴──────┐ │ дешифраторы│
│ Z84C15 │ └──────┬─────┘
│ (CPU + │◄─────────┤
│ PIO/SIO/ ├──────────┤
│ CTC) ├──────────┤
└─────┬──────┘ │
│ ┌────┴──────────┐
┌─────┴──────┐ │ EP1K30QC208 │
│ ROM 256K │◄───►│ (CPLD/FPGA) │◄───► VRAM 256K
│ Cache 64K │ │ │◄───► Main RAM
└────────────┘ │ │
│ AY-3-8910 │
│ COVOX/CBL │
│ Accel. │
└──────┬────────┘
┌───┴───┐
│TDA1543│
│ ЦАП │
└───────┘
```
Периферия (FDD, HDD, Kempston, клавиатура AT) подключается через ППЛМ. Вспомогательная ППЛМ (EPM7064 на Sp2000) обеспечивает синхронизацию и начальный запуск. Дешифрация адресов портов выполняется через ППЛМ, что позволяет перепрограммировать адреса портов.
## 1.3 ППЛМ и загрузка конфигураций
### Механизм конфигурирования
При включении или RESET информация в ППЛМ стирается. ППЛМ переходит в режим ожидания загрузки блока данных конфигурации. Процессор отключён от периферии, в его адресное пространство включено ПЗУ и возможно КЭШ-ОЗУ. Любая запись процессора в адресное пространство в этот момент записывает данные в ППЛМ.
Программа загрузчика в ПЗУ:
1. Проверяет флаг в КЭШ-ОЗУ по смещению `#80` (последняя страница КЭШа)
2. Если флаг (строка `ACEX_30K_LOADING`) установлен → загружает конфигурацию из КЭШ-ОЗУ (смещение `#100`)
3. Если флаг сброшен → загружает конфигурацию из ПЗУ
### Смена конфигурации программно
1. Загрузить файл прошивки в последнюю страницу КЭШ-ОЗУ (смещение `#100`)
2. Записать флаг `ACEX_30K_LOADING` по смещению `#80`
3. Выполнить программный сброс записью в страницу RESET_PAGE (`#A0`),
4. После сброса загрузчик находит флаг, загружает прошивку в ППЛМ и стирает флаг
При аппаратном RESET флаг отсутствует — загружается начальная конфигурация из ПЗУ.
### Ограничения
- Внутренний формат данных ППЛМ — закрытая информация Altera
- Программа разводки схем — MAX+Plus II — не работает на ZX-Spectrum/Sprinter (требуется PC)
## 1.4 Конфигурации ППЛМ
### Sprinter-1
Максимально совместима с ZX-Spectrum. Включает:
- Режимы Spectrum-128/Scorpion-256/Pentagon-512
- Расширенная память до 4 МБ
- Расширенный экран: Spectrum, Text-80×32, Graf-320×256×256
- Контроллер дисковода (ВГ93), контроллер IDE
- AT-клавиатура, подключённая как ZX-Keyboard (через порт `#FE`)
- COVOX 8-bit
- AY-3-8910 (доступен)
### Sprinter-2
Требования к совместимости жёстче. Добавляет:
- Акселератор операций с ОЗУ (fill, copy, AND, OR, XOR)
- AT-клавиатура через внутренний последовательный порт Z84C15 (сканкоды, не ZX-матрица)
### ZX-Spectrum+AY
Максимальное приближение к ZX-Spectrum-128/256. AY-3-8910 (3-я версия, в ППЛМ): 3 голоса, шум, амплитуда, огибающая (обнаружена ошибка в формирователе огибающей [IvanMak.txt:224229]).
### Game-1
На базе Sprinter-2. Акселератор без логических функций. COVOX-Blaster (15 кГц).
### DooM
Развитие Game-1. Акселератор с аппаратным растяжением/сжатием вертикальных и горизонтальных линий.
### Video
Похожа на Game-1, добавлена возможность передачи данных с HDD прямо в видео-память. Режим `GR-256-4×4` — 160×128 с аппаратным удвоением пикселя.
### Плата Sp2000
Конфигурации Sprinter-1, Sprinter-2 и ZX+AY объединены в одну прошивку. Переключение — через системный порт. Game-1, DooM, Video также планируется свести в одну.
## 1.5 Система памяти (обзор)
Адресное пространство Z80 (64 КБ) разделено на 4 окна по 16 КБ:
| Окно | Адреса | Название | Назначение (по умолчанию) |
|---|---|---|---|
| W0 | `#0000..#3FFF` | PAGE0 | ПЗУ (системное) |
| W1 | `#4000..#7FFF` | PAGE1 | ОЗУ, страница 5 |
| W2 | `#8000..#BFFF` | PAGE2 | ОЗУ, страница 2 |
| W3 | `#C000..#FFFF` | PAGE3 | ОЗУ, любая страница (0..N) |
Основная память — 4..64 МБ — делится на блоки по 16 КБ. Управление через порты страниц (`#82`, `#A2`, `#C2`, `#E2` для окон 0..3). ПЗУ: `#E0..#EF`. КЭШ-ОЗУ: `#F0..#FF`.
Детально — `04-memory.md`.
## 1.6 Видеосистема (обзор)
Основа — ППЛМ + 256 КБ видео-ОЗУ. Два режима адресации VRAM:
- **Спектрумовский** — экран 32 блока по 8 КБ, адрес через RGADR
- **Графический** — 256 строк × 1024 байта, линейная адресация; страницы `#50..#5F`
Режимы вывода (задаются для каждого квадратика 8×8):
- ZX-40 — текстовый 40×32 (Spectrum-совместимый)
- ZX-80 — текстовый 80×32, до 36 знакогенераторов
- GR-256-8 — графический 320×256×256 цветов
- GR-16-16 — графический 640×256×16 цветов
Палитра: 8 палитр по 256 цветов из 16 млн. Цвет: 3 байта RGB (BGR) на цвет.
четыре из этих восьми палитр используются для графических режимов и оставшиеся четыре для текстовой палитры — 4 текстовые палитры (paper, ink, flash-paper, flash-ink) по адресам `#03F0..#03FE`.
Детально — `05-graphics.md`.
## 1.7 Акселератор (обзор)
Акселератор — быстрое внутреннее ОЗУ в ППЛМ. Присутствует в Sprinter-2 и выше. Управляется через NOP-команды процессора (`LD D,D`, `LD L,L`, `LD C,C` и др.), которые ППЛМ распознаёт как инструкции акселератора.
Операции: fill, copy, AND, OR, XOR.
**время копирования полного экрана.** - «~1.2 инта» (~24 мс при 50 Гц)
**формула скорости.**
«Время работы акселератора = число пересылаемых байт / 7000000 (секунд)»
**акселератор и прерывания.** требуется DI/EI (акселератор сильно меняет систему команд).
Детально — `06-accel.md`.
## 1.8 Быстрое ОЗУ (КЭШ-ОЗУ)
64 КБ SRAM с доступом без wait states на частоте 21 МГц. Физические страницы `#F0..#FF`, реально 4 страницы по 16 КБ.
Подключается через порт `#FB` (стандартный Pentagon-овский), чтение `IN A,(#FB)` — включает, `IN A,(#7B)` — выключает.
Ограничения:
- Несовместимо с акселератором
- Не сохраняется между процессами
- Конфликт с COVOX по порту `#FB`
- На Sp2000 используется для загрузки прошивок ППЛМ и как временное хранилище
Детально — `04-memory.md`.
## 1.9 ISA-слоты
Два 8-битных ISA-слота.
Возможны два способа доступа к ISA — вероятно, разные конфигурации ППЛМ:
- Через страницы памяти `#D0..#DF` [IvanMak.txt:855858]: «Бит 1 номера означает выбор доступа к порту или памяти ISA, а бит 2 определяет к какому из двух слотов осуществляется доступ.»
- Через управляющие порты [Parinov.txt:798857]: (1) запись `#10` в порт `1FFDh`, (2) запись управляющего байта в порт `0E2h` (бит D2=слот, D1=порт/память), (3) использование порта `9FBDh` для старших адресов.
## 1.10 Звук (обзор)
COVOX: ЦАП TDA1543 — 16-битный стерео, COVOX — 8-битный, реально используется 10 бит для одновременного вывода COVOX и AY.
**порт CBL.**
«Порт управления: 004Eh (16-bit port!!!, писать только через OUT (C),reg)» — 16-бит, требуется `OUT (C),A`.
Компоненты звукового тракта:
- **16-битный ЦАП TDA1543** (реально 10 бит) — подключён к ППЛМ
- **AY-3-8910** — эмуляция в ППЛМ (3-я версия: 3 голоса + шум + огибающая)
- **COVOX 8-bit** — порты `#FB` / `#4F`, через TDA1543
- **Бипер** — бит 3 порта `#FE`
- **COVOX-Blaster (CBL)** — COVOX с буферным ОЗУ 256 байт, 15/22 кГц. Управление порт `#4E`
Детально — `08-io.md`.
## 1.11 Клавиатура (обзор)
В Sprinter-1 — ZX-клавиатурная матрица через порт `#FE`. В Sprinter-2 и выше — AT-клавиатура через внутренний SIO Z84C15 (порты `#18`/`#19`). Сканкоды напрямую, FIFO на 3 байта.
Детально — `08-io.md`.
## 1.12 Мышь
Microsoft Mouse (2 кнопки) через последовательный порт Z84C15. Порт команд: `#1B`, порт данных: `#1A`.
Детально — `08-io.md`.
## 1.13 Дисковая подсистема
- **FDD**: КР1818ВГ93 (WD1793). Порт `#1F` перенаправляется на `#0F` в ПЗУ. Поддержка 720 КБ / 1.44 МБ.
- **HDD**: IDE/AT. Порты `#XX50..#XX55`, регистры `#20..#29`.
- **CMOS Dallas DS12887A**: порты `#FFBD` (read), `#BFBD` (write), `#DFBD` (address).
Детально — `08-io.md`.
## 1.14 Система прерываний (обзор)
Поддерживаются IM1 и IM2. Генерация INT — через бит 0 порта `#FE`. CTC Z84C15 — таймер, SIO — клавиатура. ISA-слоты — IRQ через PIO порт B (`#1F`).
Детально — `07-irq.md`.
## 1.15 Сброс и старт машины
Программный сброс (без перезагрузки ППЛМ) [IvanMak.txt:13851394]:
```
DI
LD A, 16
LD BC, 1FFDh
OUT (C), A
LD A, 0A0h
OUT (PAGE3), A ; PAGE3 = #E2
LD (0C000h), A ; в этот момент происходит RESET
DI
HALT
```
Сброс с перезагрузкой ППЛМ — через функции BIOS (`02-bios.md`). Аппаратный RESET — начальная конфигурация из ПЗУ.
## 1.16 Плата Sp2000 — особенности
- Конфигурации объединены в две прошивки ППЛМ (Sprinter-1+Sprinter-2+ZX+AY — одна; Game-1+DooM+Video — другая)
- AY-сопроцессор доступен и в Sprinter-1, и в Sprinter-2
- ОЗУ: 72-pin SIMM, от 4 до 64 МБ
- Внутренние порты Z84C15: `#10..#1F`, `#EE`, `#EF`, `#F0`, `#F1`, `#F4` — их адреса вне ППЛМ
- Обнаружена ошибка в формирователе огибающей AY (3-я версия)
## 1.17 Кросс-ссылки
- BIOS: `02-bios.md`
- DSS/ESTEX: `03-dss.md`
- Память, режимы, банки: `04-memory.md`
- Видео, палитра: `05-graphics.md`
- Акселератор: `06-accel.md`
- Прерывания: `07-irq.md`
- Диски, джойстик, принтер, ISA: `08-io.md`
- Клавиатура, мышь: `09-input.md`
- Звук: `10-sound.md`
- Карта портов: `11-ports.md`
- Баги: `12-bugs.md`
+1234
View File
File diff suppressed because it is too large Load Diff
+1082
View File
File diff suppressed because it is too large Load Diff
+387
View File
@@ -0,0 +1,387 @@
# 4. Управление памятью Sprinter Sp2000
## 4.1 Аппаратная модель памяти
Z80 видит 64 КБ, разбитые на **четыре окна (window) по 16 КБ**. Каждое окно независимо маппится на физическую страницу (page) ОЗУ или ПЗУ через порт-регистр страницы:
| Окно | Адреса | Порт страницы | Назначение |
|------|--------|---------------|------------|
| W0 | `#0000..#3FFF` | `#82` (PAGE0, ROM.SLOT0) | RST-обработчики, BIOS/DSS ядро |
| W1 | `#4000..#7FFF` | `#A2` (SLOT1, PAGE1) | Приложение |
| W2 | `#8000..#BFFF` | `#C2` (SLOT2, PAGE2) | **Стек — обязательно здесь** |
| W3 | `#C000..#FFFF` | `#E2` (SLOT3, PAGE3) | Разделяемые страницы DSS, графика, резидентный код |
- Запись в порт `#82`/`#A2`/`#C2`/`#E2` меняет физическую страницу окна; чтение возвращает текущую.
- Для совместимости со старыми моделями (ZX-Spectrum 128, Scorpion, Pentagon) работают также порты `#7FFD`, `#1FFD`, `#DFFD`, `#EFF7`:
| Порт | Описание |
|------|----------|
| `#7FFD` | Биты 0-2: страница W3; бит 3: выбор ПЗУ (0=DOS, 1=Basic/48) |
| `#1FFD` | Биты 0-2: страница W0; бит 3: дополнительная память; бит 4: турбо |
| `#DFFD` | Страница W1 (Pentagon, когда бит 5 порта `#7FFD`=0) |
| `#EFF7` | Страница W2 (Pentagon) |
> **Страница `#FF`:** если окно не выделено программе (образ меньше 16/32 КБ), DSS маппит его на специальную страницу `#FF`. Чтение даёт `#FF`, запись игнорируется. Это ключевая причина «молчаливой» порчи данных — см. §4.9.
> **Физические страницы:** порты `#82`/`#A2`/`#C2`/`#E2` адресуют физические 16-КБ страницы в адресном пространстве Sprinter. Диапазон страниц зависит от установленной памяти (обычно 0..127 для 2 МБ, 0..255 для 4 МБ). Старшие страницы заняты видео-ОЗУ и ПЗУ.
---
## 4.2 Окно W0 (#0000..#3FFF) — системное
W0 — критическое окно: в нём живут обработчики `RST 08h` (BIOS), `RST 10h` (DSS/ESTEX) и `RST 18h` (BIOS-EXP). Пока в W0 стоит системная страница, вызовы доступны.
**ROM/RAM switching:**
| Действие | Код |
|----------|-----|
| Включить ПЗУ в W0 | `OUT (#7C),A` (SYS_PORT.ROM) |
| Выключить ПЗУ, вернуть ОЗУ | `OUT (#3C),A` (SYS_PORT.RAM) |
При включённом ПЗУ в W0 отображается системная страница BIOS. Для вызова RST-функций W0 должен быть в ПЗУ — BIOS сам переключает его при входе через `RST 08h`.
**Требования к прерываниям:**
Sprinter работает в режиме **IM1** — вектор прерывания фиксирован на `#0038` (всегда в ПЗУ/ОЗУ W0). Обработчик EXP.asm по адресу `#0038`:
1. Переключает W3 на SYS_PAGE.
2. Проверяет флаг `INT_ID` = `#AA`.
3. Если есть пользовательский обработчик — вызывает его (адрес из SYS_PAGE).
4. Восстанавливает W3, `EI`, `RETI`.
Регистр `I` инициализирован в `#3F` (наследие ZX-Spectrum), но при IM1 не используется для диспетчеризации. Если программа переключается в **IM2**`I` и расположение таблицы векторов определяются программой произвольно, стандартного расположения нет.
**DSS и W0:** при вызове `RST 10h` DSS переключает W0 на свою рабочую страницу (COREPAGE = 4), выполняет функцию и восстанавливает W0. Если в W0 до вызова была ОЗУ, DSS восстановит её; если ПЗУ — вернёт ПЗУ.
**Практические рекомендации:**
- Для вызова системных функций держите W0 в ПЗУ (или не заботьтесь — RST 08h и RST 10h его переключат сами).
- При IM1 (режим по умолчанию) прерывание идёт на `#0038` — это ПЗУ, переключение W0 не требуется.
- При IM2 программа сама управляет таблицей векторов — не забывайте про `DI`/`EI` при переключении W0.
**Размещение своей RAM-страницы в W0:**
Если программе нужно дополнительное окно (например, для атласов спрайтов или кода,
не требующего системных вызовов), можно временно маппить свою страницу в W0. Для
безопасной работы страница должна содержать корректную таблицу RST-векторов в
первые `#40` байт:
| Адрес | Инструкция | Назначение |
|-------|-----------|------------|
| `#0000` | `JP boot` или `RST 00h` (обычно не используется) | |
| `#0008` | `JP rst08_stub` | RST 08h — BIOS |
| `#0010` | `JP rst10_stub` | RST 10h — ESTEX/DSS |
| `#0018` | `JP rst18_stub` | RST 18h — BIOS-EXP |
| `#0020..#0030` | `JP _w0_unused_stub` | RST 20h-30h — не используются |
| `#0038` | `JP isr_stub` | IM1 (RST 38h) |
| `#0066` | `RETN` или `JP nmi_stub` | NMI |
Каждый стаб (в этой же странице, выше `#40`) выполняет одну задачу: сохранить
текущий номер страницы W0, переключить W0 обратно на ПЗУ (`OUT (#7C),A`
SYS_PORT.ROM), выполнить настоящий системный вызов, после чего восстановить
страницу программы и вернуться к исходному caller'у. Типовой паттерн для ESTEX
(`RST 10h`):
```asm
rst10_stub:
IN A, (#82) ; сохранить свою страницу W0
PUSH AF
OUT (#7C), A ; включить ПЗУ в W0 (SYS_PORT.ROM)
; теперь в W0 — системная страница, RST 10h будет обработан корректно
RST #10 ; вызвать настоящий ESTEX (DSS сам переключит W0
; на COREPAGE и восстановит ПЗУ на выходе)
POP BC
LD A, B
OUT (#82), A ; вернуть свою страницу в W0
RET ; возврат к исходному caller'у
```
Такой же паттерн для RST 08h и RST 18h. Для IM1 (`RST 38h`) — аналогично, но
прерывание может прийти в любой момент, поэтому критические секции (своя
страница в W0) обязаны быть обёрнуты в `DI`/`EI` (или проверять вложенность
через счётчик), иначе повторное прерывание при уже замапленной странице
попадёт в стаб, а не в EXP.asm.
**Важно:** пока в W0 стоит ваша страница, системные вызовы (`RST 08h`/`10h`/`18h`)
проходят через стабы и работают корректно, но с накладными расходами
(~10+ тактов на каждый вызов). Код на странице не должен вызывать DSS/BIOS
напрямую — только через RST. При этом сам стаб не должен использовать
RST-инструкции, так как они адресуют W0, который в момент вызова стаба
всё ещё содержит вашу страницу, а не ПЗУ — сначала переключите ПЗУ через
`OUT (#7C),A`.
Перед первым маппингом своей страницы в W0 сохраните текущее значение порта
`#82` (`IN A,(#82)` — оно даёт номер системной/ПЗУ-страницы). Эта страница
понадобится стабам для восстановления после вызова во время прерываний,
когда ПЗУ уже может быть в W0, а стаб не успел его переключить.
Подтверждённая реализация: `tests/w0page` (см. `sprite-api-design.md §9в`).
---
## 4.3 Окно W1 (#4000..#7FFF) — приложение
W1 — основное окно для кода и данных приложения. По умолчанию содержит страницу 5 (RAM, инициализируется BIOS).
**Использование BIOS/DSS:**
BIOS и DSS могут **временно** переключать W1 на свою рабочую страницу. Это происходит:
- При файловых операциях DSS: чтении FAT, загрузке секторов — DSS маппит одну из страниц разделяемого пула в W1 (DIRPAGE, FATPAGE, TXTPAGE, DRVPAGE).
- При графических операциях BIOS: `PIC_FN2`/`PIC_FN3` (блоковые копии) могут переключать W1 на страницу видео-ОЗУ.
- **Важно:** перед возвратом из вызова BIOS/DSS **восстанавливает** предыдущую страницу W1. Типовой паттерн в исходниках DSS:
```asm
IN A,(SLOT1) ; сохранить текущую страницу W1
PUSH AF
... работа с разделяемым буфером ...
POP BC
LD C,SLOT1
OUT (C),B ; восстановить W1
```
Для вызывающей программы переключение W1 полностью прозрачно — после возврата из любой функции DSS/BIOS содержимое W1 идентично тому, что было до вызова.
**Практические рекомендации:**
- Размещайте код и данные в W1, рассчитывая, что он остаётся стабильным между вызовами.
- При длительных файловых операциях (последовательный `READ` больших объёмов) W1 может быть затронут только в моменты внутреннего обращения DSS к FAT/буферам, но не во время собственно чтения данных в буфер программы.
- Если нужно гарантированно сохранить данные через вызов DSS — используйте W2, который BIOS/DSS **никогда не трогают**.
---
## 4.4 Окно W2 (#8000..#BFFF) — стек (критично)
W2 — **единственное окно, которое BIOS и DSS гарантированно не трогают**. Поэтому стек ОБЯЗАН находиться здесь:
- **SP ≤ #BFFF** при вызовах DSS (`RST 10h`).
- **SP ≥ #8000** при вызовах BIOS (`RST 08h`).
- Пересечение → стек в `#8000..#BFFF`.
- По умолчанию SP инициализируется в `#BFFE` (значение из EXE-заголовка, §4.7).
**Почему W2 — единственное стабильное окно:**
| Окно | Может быть переключено BIOS/DSS | Почему |
|------|--------------------------------|--------|
| W0 | Да | DSS переключает на COREPAGE при `RST 10h`; BIOS переключает на ПЗУ |
| W1 | Да, временно | DSS маппит разделяемые буферы для FAT/директорий; BIOS при графических операциях — и **восстанавливает** перед возвратом |
| W2 | **Нет** | **Никогда. Стек должен быть доступен всегда.** |
| W3 | Да, временно | DSS маппит разделяемые буферы; BIOS при графике переключает на видео-ОЗУ; оба **восстанавливают** исходную страницу перед возвратом |
**EXEC и W2:** при загрузке новой программы (`EXEC`, функция 40h) DSS сохраняет страницу W2 в EXSTACK (вместе с W1 и W3). После завершения программы (`EXIT`, функция 41h) W2 восстанавливается.
**Практические рекомендации:**
- Размещайте стек строго в W2. Стандартное значение `SP = #BFFE` — начало стека с запасом ~14 КБ до `#8000`. Можно уменьшить, если программа неглубокая.
- W1 и W3 при вызовах DSS и BIOS **сохраняются и восстанавливаются** (см. §4.3, §4.5), но W2 — единственное окно, которое **никогда не трогается** ни DSS, ни BIOS.
- Если программе нужно больше памяти, чем даёт W2 (например, для хранения больших массивов), выделяйте блоки через DSS `GETMEM` (функция 3Dh) и мапьте их в W1 или W3.
---
## 4.5 Окно W3 (#C000..#FFFF) — разделяемые страницы
W3 — окно, в которое DSS временно маппит страницы своего разделяемого пула для дисковых буферов и служебных данных (адрес `#C000`):
| Страница | Назначение | Адрес в W3 |
|----------|------------|-------------|
| DIRPAGE (0) | Буфер директории | `#C000` |
| FATPAGE (1) | Кеш FAT | `#C000` |
| TXTPAGE / ENVPAGE (2) | Буфер строки/окружения | `#C000..` (PATH_PNT_ARRAY `#FC80`, ENVTEMP `#FE00`) |
| DRVPAGE (3) | Страница драйвера | `#C000` |
| COREPAGE (4) | Ядро DSS (маппится в W0 при `RST 10h`) | — |
**DSS СОХРАНЯЕТ и ВОССТАНАВЛИВАЕТ W3** после каждой операции. Типовой паттерн в исходниках:
```asm
IN A,(SLOT3) ; сохранить текущую страницу W3
PUSH AF
... работа с разделяемым буфером ...
POP BC
LD C,SLOT3
OUT (C),B ; восстановить W3
```
Это означает, что для вызывающей программы переключение W3 полностью прозрачно — после возврата из любой функции DSS содержимое W3 идентично тому, что было до вызова.
**Какие функции трогают W3:**
Функции, обращающиеся к файловой системе, временно маппят разделяемые страницы в W3: поиск файла (`F_FIRST`/`F_NEXT`), чтение FAT (`OPEN`, `READ`, `WRITE`), работа с каталогами (`CHDIR`, `MKDIR`), буферы драйвера диска. Функции без дисковой активности (`VERSION`, `CURDISK`, `WAITKEY`, `LOCATE`, `SYSTIME`, `ENVIRON` и т.п.) W3 не трогают вообще.
BIOS при графических операциях также временно переключает W3 на страницы видео-ОЗУ (например, `PIC_SET_PAL`, `PIC_FN2`) — и тоже восстанавливает.
**Практические рекомендации:**
- W3 можно использовать для данных программы — после возврата из любой функции DSS содержимое W3 не меняется.
- Единственное исключение — `EXEC` (функция 40h): она загружает новую программу, и W3 получает страницы загруженного образа. Это ожидаемое поведение.
- Если программа не вызывает дисковых и графических функций — W3 полностью стабилен.
- **Стек нельзя размещать в W3** — не потому что W3 «теряется», а потому что переключение W3 происходит ВО ВРЕМЯ вызова. Если `SP` указывает на W3, то в момент, когда DSS временно маппит свой буфер, все push/pop внутри DSS будут обращаться к буферной странице, а не к данным программы. Кроме того, при прерывании IM1 обработчик EXP.asm сам переключает W3 на SYS_PAGE — что также сломает стек, если он в W3.
---
## 4.6 Физическая память и страницы
Физическая память Sprinter — не сплошной массив RAM. Разные области адресного
пространства зарезервированы под видео-ОЗУ, ПЗУ и кеш. Номер страницы — это
значение, которое записывается в порт окна (`#82`/`#A2`/`#C2`/`#E2`);
8-битный порт даёт **256 значений** (`#00..#FF`).
**Фиксированная карта страниц:**
| Диапазон | Страниц | Назначение |
|----------|---------|------------|
| `#00..#4F` (0..79) | 80 (1,25 МБ) | RAM общего назначения |
| `#50..#5F` (80..95) | **16 (256 КБ)** | **Видео-ОЗУ (VRAM) — фиксировано в железе** |
| `#60..#DF` (96..223) | 128 (2 МБ) | RAM общего назначения (верхний диапазон) |
| `#E0..#EF` (224..239) | **16 (256 КБ)** | **ПЗУ: BIOS + EXP + ZX ROMs + bitstream — фиксировано** |
| `#F0..#FF` (240..255) | 16 (256 КБ) | **Fast RAM (кеш) / системные страницы** |
**Выделенные страницы:**
| Страница | Назначение |
|----------|------------|
| `4` | **COREPAGE** — ядро DSS (маппится в W0 при `RST 10h`) |
| `5` | Стандартная страница приложения W1 (по умолчанию) |
| `#41` (65) | **Spec_Page** — сохранение состояния при soft-reset [EXP.asm:859,1019] |
| `#FE` (254) | **SYS_PAGE** — системные данные BIOS (INT_ID, INT_ADRESS, буферы) [MAIN.asm:58] |
| `#FF` (255) | **Dummy-страница**: чтение → `#FF`, запись игнорируется |
**Ключевые моменты:**
- **VRAM (`#50..#5F`) фиксирована аппаратно**, независимо от объёма RAM. Эти
16 страниц не являются частью RAM SIMM — это отдельная микросхема 256 КБ.
Биты 2-3 номера страницы кодируют режим записи: `#50` normal, `#54` без
ОЗУ-тени, `#58` прозрачный (байт `#FF` не пишется), `#5C` оба режима.
- **ПЗУ (`#E0..#EF`)** — 256 КБ флеш-памяти с BIOS, EXP, ZX Spectrum 48/128 ROM,
TR-DOS, логотипом и битстримом для CPLD.
- **Fast RAM (`#F0..#FF`)** — до 512 КБ быстрого SRAM (0 wait-states),
доступна через порт `#FB`. `#FE` (SYS_PAGE) и `#FF` (dummy) — часть этого
диапазона. При включённом кеше порт `#FB` конфликтует с CBL-звуком.
- Для 2 МБ RAM: `#60..` заполнены до `#7F` (32 стр. = 512 КБ); остаток
`#80..#DF` — неиспользуемые страницы (отображаются как `#FF`).
- Для 4 МБ RAM: `#60..#DF` целиком заполнены RAM (128 стр. = 2 МБ).
> **Нумерация:** порты `#82`/`#A2`/`#C2`/`#E2` дают прямой доступ по
> физическому номеру (#00..#FF). Порты `#7FFD`/`#1FFD` (совместимость с
> ZX-Spectrum 128) используют сквозную нумерацию: номер в `#7FFD` (0..7)
> маппится на физические страницы видеоОЗУ `#50..#5F` младшими 3 битами;
> для работы с произвольными страницами используйте порты `#82`/`#A2`/`#C2`/`#E2`.
---
## 4.7 EXE-файл: формат и загрузка
Загрузка исполняемых файлов выполняется функцией DSS `EXEC` (40h). Формат EXE-файла:
**Заголовок (512 байт):**
| Смещение | Размер | Поле | Описание |
|----------|--------|------|----------|
| +0 | 3 | `EXE_EXT` | Сигнатура `"EXE"` |
| +3 | 1 | `VERSION` | Минимальная версия DSS (1 = v1.xx, 0 = без пути/аргументов) |
| +4 | 2 | `OFFCOD1` | Младшее слово смещения образа в файле |
| +6 | 2 | `OFFCOD2` | Старшее слово смещения (OFFCOD2 << 16 + OFFCOD1 = offset) |
| +8 | 2 | `LOADER` | Размер первичного загрузчика (0 = весь образ сразу) |
| +10 | 6 | `RESERVED` | Зарезервировано |
| +16 | 2 | `LD_ADDR` | Адрес загрузки (`#4100..#FFFF`, старший байт маскирован `#3F`) |
| +18 | 2 | `PC_REG` | Точка входа (entry point) |
| +20 | 2 | `SP_REG` | Начальный SP (по умолчанию `#BFFE`) |
| +22 | 1 | `UnUsedPoint` | Не используется |
| +23 | 489 | `RESERVED2` | Зарезервировано (обнуляется; используется как временный стек EXEC) |
**Процесс загрузки (EXEC, функция 40h):**
1. Открыть файл на чтение.
2. Считать 512-байтный заголовок в буфер ядра.
3. Проверить сигнатуру `"EXE"` и версию (≥ минимальной 1).
4. Если `LOADER=0`: seek на смещение `OFFCOD2:OFFCOD1`, считать весь образ по адресу `LD_ADDR`.
5. Если `LOADER>0`: считать только первичный загрузчик по адресу `LD_ADDR` (он дочитает остальные сегменты).
6. Выделить блок памяти через `GETMEM` (функция 3Dh), зарегистрировать в таблице RAM.
7. Сохранить текущие страницы окон (SLOT1-3) в EXSTACK.
8. Определить, сколько страниц нужно, и замаппить их через `SETWIN1`/`SETWIN2`/`SETWIN3`:
- Если `LD_ADDR ≥ #C000`: маппится только W3.
- Если `LD_ADDR ≥ #8000`: маппятся W2 и W3.
- Иначе: маппятся W1, W2 и W3.
9. Построить **PSP** (Program Segment Prefix) — блок данных сразу ниже `LD_ADDR`:
- `LD_ADDR-3`: файловый манипулятор (file handle).
- `LD_ADDR-2`: идентификатор блока памяти.
- `LD_ADDR-1`: номер задачи.
- `LD_ADDR+0`: размер CLP (командной строки).
- `LD_ADDR+1..+128`: CLP-буфер.
- После CLP: строка пути `"A:\DIR\FILE.EXE",0`.
10. Установить SP из заголовка (`SP_REG`), сохранить IX → адрес PSP.
11. Если `VERSION=0` — установить текущий каталог из пути PSP.
12. Затолкать в стек адрес возврата (RETFAR к DSS), **EI**, JP на точку входа.
**Multi-bank EXE:**
При наличии нескольких банков (`LOADER>0`) файл устроен так:
```
[512-байт заголовок] [HOME-сегмент] [Банк 1 (16 КБ)] [Банк 2 (16 КБ)] ...
```
- HOME-сегмент: образ, загружаемый DSS по `LD_ADDR`.
- Банки: 16-КБ блоки, каждый на своей физической странице.
- `LOADER` = размер HOME-сегмента (DSS загружает только его; первичный загрузчик сам дочитывает банки через `READ` из оставшегося открытым файла).
---
## 4.8 Прерывания и память
**Обработчик IM1 (`RST 38h`):**
Вектор фиксирован на `#0038` (W0). Реализация в EXP.asm:
1. Переключает W3 на SYS_PAGE (BIOS).
2. Проверяет флаг `INT_ID` = `#AA` (установлен при инициализации BIOS).
3. Если флаг совпадает — вызывает пользовательский обработчик, адрес которого хранится в SYS_PAGE (`INT_ADDRESS`, `INT_PAGE`).
4. После возврата восстанавливает W3 и выполняет `EI; RETI`.
Это позволяет пользовательским программам устанавливать свои обработчики INT без полного перехвата вектора.
**Обработчик IM1 (системный):**
При возникновении прерывания Z80 исполняет `RST 38h` → вызов по адресу `#0038`. Реализация в EXP.asm (всегда доступна, т.к. `#0038` в W0):
1. Переключает W3 на SYS_PAGE (BIOS).
2. Проверяет флаг `INT_ID` = `#AA` (установлен при инициализации BIOS).
3. Если флаг совпадает — вызывает пользовательский обработчик, адрес и страница которого хранятся в SYS_PAGE (`INT_ADDRESS`, `INT_PAGE`). Это позволяет программам устанавливать свои ISR без полного перехвата вектора.
4. После возврата восстанавливает W3 и выполняет `EI; RETI`.
**Обработчик IM2 (опционально, для продвинутых программ):**
Sprinter по умолчанию не использует IM2. Исходники содержат шаблон `IM2_INT.asm` для программ, желающих переключиться на IM2:
1. Сохраняет AF, BC, DE, HL, IX, IY и теневые регистры.
2. Включает ПЗУ (`OUT (#7C),A`) — KEYSCAN требует ПЗУ в W0.
3. Вызывает KEYSCAN (опрос AT-клавиатуры).
4. Восстанавливает все регистры, `EI`, `RETI`.
При переходе на IM2 программа сама выбирает значение `I` и размещает таблицу векторов в соответствующем диапазоне памяти.
**Рекомендации:**
- Если программа не использует прерывания — держите W0 в ПЗУ.
- Если программа использует IM1 — можно переопределить обработчик через структуру в SYS_PAGE (флаг `INT_ID`, поля `INT_ADDRESS`/`INT_PAGE`).
- Если программа использует IM2 — переключение полностью на ответственности программы; ядро Sprinter не предоставляет стандартного расположения таблицы векторов.
---
## 4.9 Типовые грабли
- **Данные читаются как `#FF` / не сохраняются** — код или данные попали в незамапленное окно (страница `#FF`). Причина: образ программы меньше 16 КБ, DSS выделил только одну страницу, а код/данные распределены линкером в незамапленные окна. Лечение: убедитесь, что код и данные укладываются в одно окно, или явно выделяйте и мапьте остальные окна через `GETMEM`/`SETWIN1`-`SETWIN3`.
- **Крэш при вызове RST при нестандартном W0** — если перед вызовом W0 содержал произвольную страницу ОЗУ, DSS при `RST 10h` переключит его, но может не восстановить корректно. Решение: перед вызовом RST включите ПЗУ (`OUT (#7C),A`), если не уверены в состоянии W0.
- **Стек в W3 (не-рабочий вариант)** — если стек размещён в W3, при любом дисковом вызове W3 будет переключён на разделяемый буфер DSS, и стековые данные будут забиты. Результат: мгновенное зависание при возврате из функции. Единственное рабочее место для стека — W2.
- **CBL не работает при включённом кеше** — порт `#FB` используется как кеш-память (Fast RAM) и как порт CBL-звука. Если кеш включён, запись в `#FB` уходит в кеш, а не в CBL. Детали: `11-ports.md`, `12-bugs.md`.
- **Прерывание уходит не туда при IM2** — если программа переключилась в IM2 с неинициализированной таблицей векторов, любое прерывание приведёт к исполнению мусора. Решение: используйте IM1 (режим по умолчанию) или инициализируйте таблицу перед переключением.
- **Не путать W3 с «теряется после вызова»** — многие источники утверждают, что DSS сбрасывает W3. На самом деле DSS **сохраняет и восстанавливает** W3 после каждой операции. Стек всё равно нельзя размещать в W3 (см. §4.5), но для данных W3 полностью стабилен между вызовами. Если ваша программа полагается на старый миф — проверьте код.
---
## 4.10 Кросс-ссылки
- Порты страниц и детали регистров: `11-ports.md`
- BIOS (графика, окна): `02-bios.md`
- DSS/ESTEX (EXEC, GETMEM, SETWIN): `03-dss.md`
- Прерывания: `07-irq.md`
- Баги (CBL vs кеш, порт #FB): `12-bugs.md`
- EXE-формат и PSР: `memory/exe-format.md`
+279
View File
@@ -0,0 +1,279 @@
# 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:317322].
---
## 5.2 Режимы адресации видео-ОЗУ
Видео-ОЗУ может адресоваться двумя способами — **спектрумовским** и
**графическим** [IvanMak.txt:296300]. Спектрумовский режим используется для
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:333339].
Для записи в определённую пару спектрумовских блоков:
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:346348].
### 5.2.2 Графический режим адресации
В графическом режиме видео-ОЗУ организовано как матрица **256 строк
(rows) × 1024 байта** [IvanMak.txt:357358]. Адресация:
```
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:364386]:
| Бит | Страницы | Эффект |
|-----|----------|--------|
| 3 | `#58..#5F` | **Прозрачный цвет** — запись байта `#FF` игнорируется (для спрайтов) |
| 2 | `#54..#57`, `#5C..#5F` | **Без тени** — запись только в VRAM, не в основное ОЗУ (для курсора мыши) |
Биты 0 и 1 должны быть 0 для совместимости с будущими прошивками
[IvanMak.txt:384386].
---
## 5.4 Теневая память (Shadow RAM) и двойная запись
Видео-ОЗУ Спринтера является теневой памятью по отношению к основному ОЗУ
[IvanMak.txt:317322]. Видеоконтроллер **всегда** читает изображение из 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:405469].
### Режимы вывода
| Режим | Разрешение | Цветов | Описание |
|-------|-----------|--------|----------|
| 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:448469].
Для переключения видеорежима из программ используется функция DSS `SETVMOD`
(50h) [DiskSyscalls.txt:345349]:
| 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:540568].
| Адреса | Палитра | Назначение |
|--------|---------|-----------|
| `#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:545547]. Выбор палитры для каждого квадратика — через
биты 7..6 байта Mode1 [BIOS_v3.txt:348].
> **Примечание:** Architecture.txt упоминает всего 5 палитр (4 графические +
> 1 текстовая), но IvanMak описывает все 8: 4 графические (0–3) и 4 текстовые
> (4–7: бумага, символ, мерцание бумаги, мерцание символа)
> [IvanMak.txt:547548, 561568].
---
## 5.7 Структура VRAM в терминах BIOS
При использовании BIOS распределение VRAM [IvanMak.txt:387404]:
| Адреса (линии) | Назначение |
|----------------|-----------|
| `#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`
+221
View File
@@ -0,0 +1,221 @@
# 6. Акселератор
## 6.1 Общие сведения
Акселератор — внутреннее устройство, реализованное в ППЛМ. Присутствует почти
во всех конфигурациях Sprinter (Sprinter-2 и выше). Предназначен для ускорения
пересылки блоков данных между RAM и VRAM (до физического предела скорости ОЗУ).
Не поддерживает ПЗУ и Fast RAM [accelerator_doc.txt:5].
**Возможности:**
- Быстрая заливка горизонтальной или вертикальной линии экрана (1..256 пикселей)
одним цветом; в режиме 640×256 — линия 1..512 пикселей.
- Быстрое копирование горизонтальной или вертикальной линии (1..256 пикселей).
- Логические операции AND, OR, XOR с блоками данных.
**Внутренняя память:** 256 байт в ППЛМ. Данные загружаются в эту память,
затем копируются в выбранный участок RAM/VRAM. Операция копирования может
повторяться многократно — это позволяет заполнять экран текстурой без
перезагрузки данных.
**Автоматический инкремент адреса:**
- **Горизонтальные** операции (`LD L,L` — копирование, `LD C,C` — заливка):
акселератор автоматически инкрементирует регистр HL (адрес приёмника) на
каждом шаге. Для копирования источник (DE) также инкрементируется.
- **Вертикальные** операции (`LD A,A` — копирование, `LD E,E` — заливка):
акселератор автоматически меняет порт `RGADR` (`#89`) — координату Y.
После завершения операции `RGADR` содержит новое значение
(Y + размер_блока, если не было переполнения).
- **Комбинированный** режим (горизонтальный источник + вертикальный приёмник):
сначала загружается байт из последовательных данных, затем выполняется
вертикальная запись. `RGADR` инкрементируется; регистр-источник (DE)
тоже инкрементируется — можно последовательно читать спрайт и рисовать
его вертикальными строками (§6.3, пример «Спрайт»).
## 6.2 Команды
Акселератор управляется специальными инструкциями Z80, которые выполняются
как NOP обычным процессором, но распознаются ППЛМ [IvanMak.txt:810848].
| Инструкция | Код | Действие |
|-----------|:---:|----------|
| `LD B,B` | `#40` | **Выключить** акселератор |
| `LD D,D` | `#52` | **Включить** + режим «задать размер блока» |
| `LD A,size` | `#3E size` | Установить размер блока (сразу после `LD D,D`) |
| `LD C,C` | `#4F` | **Горизонтальная заливка** одним байтом |
| `LD E,E` | `#5B` | **Вертикальная заливка** одним байтом |
| `LD L,L` | `#6D` | **Горизонтальное копирование** блока |
| `LD A,A` | `#7F` | **Вертикальное копирование** блока |
| `LD H,H` | `#64` | Зарезервировано |
**Логические операции** (AND, OR, XOR) выполняются командами
`AND (HL)`, `OR (HL)`, `XOR (HL)` после загрузки блока в память акселератора.
## 6.3 Примеры
### Копирование экрана (страница 0 → страница 1)
```asm
; страница VRAM уже открыта по адресу #C000
LD HL, #C000 ; адрес начала линии первого экрана
LD DE, #C140 ; адрес начала линии второго экрана
LD BC, #140 ; длина строки по горизонтали (320)
DI ; запретить прерывания
LD D,D ; включить акселератор: режим размера блока
LD A, 0 ; размер блока = 256 байт (0 = 256)
LD A,A ; вертикальное копирование
LDIR ; копировать
LD B,B ; выключить акселератор
EI ; разрешить прерывания
```
Время исполнения: ~1.2 прерывания (~24–26 мс на полный экран)
[IvanMak.txt:822823], [accelerator_doc.txt:37].
### Заливка блока одним цветом
```asm
LD DE, #C000 + X ; X — смещение по горизонтали
LD A, Y
OUT (#89), A ; RGADR = Y
DI
LD D,D ; режим размера блока
LD A, width ; ширина блока
LD B,B ; стоп
LD A, colour ; цвет заливки
LD C,C ; горизонтальная заливка
LD (DE), A ; залить
LD B,B ; стоп
EI
```
### XOR блока данных
```asm
LD HL, addr_1
LD DE, xor_data
DI
LD D,D
LD A, 0 ; 256 байт
LD L,L ; горизонтальное копирование
LD A, (DE) ; загрузить блок в память акселератора
XOR (HL) ; XOR с данными в RAM
LD (HL), A ; сохранить результат
LD B,B ; стоп
EI
```
### Копирование вертикальной линии с разделением load/write
Загрузка байта в буфер акселератора и запись из буфера в VRAM разнесены —
между ними можно выполнять произвольный код (например, сменить Y).
Буфер акселератора и размер блока **сохраняются** между включениями и
выключениями (`LD B,B`), что позволяет гибко разделять чтение
и запись.
```asm
LD HL, #C000 + X1 ; источник
LD DE, #C000 + X2 ; приёмник
DI
LD D,D ; акселератор вкл, режим размера
LD A, size ; размер блока
LD B,B ; выключить (размер запомнен)
LD A, Y1
OUT (#89), A ; RGADR = Y1
LD A,A ; вертикальное копирование
LD A, (HL) ; загрузить байт из (HL) в буфер акселератора
LD B,B ; выключить (буфер запомнен)
LD A, Y2
OUT (#89), A ; RGADR = Y2 (смена Y между load и write)
LD A,A ; вертикальное копирование
LD (DE), A ; записать буфер в (DE) — акселератор пишет
; вертикальную линию size пикселей
LD B,B ; выключить
EI
```
### Спрайт вертикальными строками из последовательных данных
Спрайт хранится как последовательность байт вертикальных линий. Для каждой
колонки спрайта: загружается байт из последовательных данных, затем
акселератор пишет его вертикально (автоинкремент `RGADR`). После завершения
колонки — сдвиг по X (`INC HL`) и повтор.
```asm
LD DE, sprite_data ; DE → последовательные данные спрайта
LD HL, #C000 + X_COORD ; HL → начальная позиция на экране
LD B, sprite_width ; ширина спрайта в колонках
LD D,D ; акселератор вкл, режим размера
LD A, sprite_height ; высота одной вертикальной линии
LD B,B ; акселератор выключили (размер акселератор запомнил)
row:
LD A, Y_COORD
OUT (#89), A ; RGADR = стартовая Y
DI
LD L,L ; режим «загрузить из последовательных данных»
LD A, (DE) ; загрузить байт спрайта в буфер акселератора
LD A,A ; вертикальное копирование
LD (HL), A ; записать — акселератор копирует байт
; вертикально, RGADR++ на каждом шаге
LD B,B ; выключить акселератор
EI
INC HL ; следующая колонка по X
DJNZ row
```
## 6.4 Скорость
Время работы акселератора ограничено только физической скоростью ОЗУ
[IvanMak.txt:840843]:
```
Время ≈ время команды без акселератора + число_байт / 7 000 000 (сек)
```
## 6.5 Комбинированный режим: общая схема
Общий паттерн для работы с акселератором в комбинированном режиме
(горизонтальный источник + вертикальный приёмник):
```
LD D,D ; 1. Включить акселератор, режим размера
LD A, size ; 2. Задать размер блока (1..256)
LD L,L ; 3. Режим «горизонтальный источник»
<чтение байта> ; 4. Загрузить байт в буфер акселератора (LD A,(DE) и т.п.)
LD A,A ; 5. Режим «вертикальный приёмник»
<запись байта> ; 6. Записать — акселератор делает вертикальное копирование
; с автоинкрементом RGADR и приёмника
LD B,B ; 7. Выключить акселератор
```
После шага 6 `RGADR` содержит Y + size, HL — X + 1 (если был `INC HL`).
## 6.6 Прерывания
**Старая прошивка:** DI обязателен на время работы акселератора — система
команд Z80 сильно меняется, и ISR не сможет корректно выполниться
[IvanMak.txt:844846].
**Новая прошивка:** акселератор может работать с EI. По приходу прерывания
он отключается, а по `RETI` включается обратно [IvanMak.txt:846848].
Использовать этот режим следует с осторожностью — без проверки на реальном
железе неизвестно, какая версия прошивки установлена.
---
## 6.7 Кросс-ссылки
- Баги акселератора: `12-bugs.md`
- Использование акселератора в libbgi: `sprite-api-design.md`
- Ограничение скорости: `accel-fill-budget.md`
- Fast RAM и конфликт с портом CBL: `04-memory.md §4.6`
+92
View File
@@ -0,0 +1,92 @@
# 7. Прерывания (IRQ)
## 7.1 Общие сведения
Sprinter Sp2000 поддерживает режимы прерываний IM1 и IM2.
### Источники прерываний
| Источник | Происхождение | Описание |
|----------|---------------|----------|
| Кадровые (INT) | Видеоконтроллер | Квадратик экрана в 8-й линии |
| CTC | Z84C15 | Таймерные прерывания |
| SIO | Z84C15 | AT-клавиатура |
| PIO | Z84C15 (бит 0 порта B, `#1F`) | ISA-слоты |
| CBL | COVOX-Blaster | Запрос данных |
### Различение источников
Кадровые и клавиатурные прерывания приходят с вектором `0FFh` [Parinov.txt:956]. Способ различения:
- Клавиатура выставляет бит 0 в порте `19h` — признак приёма байта [Parinov.txt:1049]
- Если бит 0 порта `19h` не установлен — прерывание кадровое
> **Примечание:** [Parinov.txt:956] описывает альтернативный метод — «отличать по биту приема байта в порте клавиатуры». Оба метода сводятся к проверке бита 0 в порте `19h`.
### Выбор режима прерываний (IM1 vs IM2)
| Режим | Контекст | Источник |
|-------|----------|----------|
| IM2 | Рекомендован для работы с BIOS через RST | IvanMak.txt:14691473 |
| IM1 | Используется DSS для своих обработчиков | — |
| IM1 | Fast-RAM секция предполагает обработчик по `#0038` | Parinov.txt:601 |
| IM2 | Рекомендован при выставленных прерываниях от CBL | Parinov.txt:762763 |
> **Примечание:** разные подсистемы рекомендуют разные режимы. IM2 предпочтителен при интенсивной работе с прерываниями (CBL, BIOS). IM1 используется DSS по умолчанию.
## 7.2 Кадровые прерывания (INT)
Генерируются в момент прохождения 8-й строки квадратика (настраивается через бит 0 порта `#FE`). Положение INT подстраивается под стандарт Pentagon (320 строк) или Scorpion (312 строк).
> **Мышь — есть ли аппаратные прерывания?** [Parinov.txt:956] утверждает: «От мыши прерывания не приходят. Сделать можно, но сейчас их нет.» [ProgrammerManual.txt:17841786] описывает драйвер мыши, где «каждое нажатие и отпускание клавиш или перемещение мыши вызывает прерывание», и документирует функцию «80h MOUSE HARDWARE INTERRUPT» [ProgrammerManual.txt:19301937]. Parinov (разработчик драйвера) отрицает их наличие — возможно, ProgrammerManual описывает планируемую функциональность.
## 7.3 CTC (Z84C15)
Таймер CTC используется для:
- Генерации периодических прерываний
- Задания частоты CBL (COVOX-Blaster)
- Синхронизации звука
## 7.4 SIO (Z84C15)
Внутренний SIO Z84C15 обслуживает:
- AT-клавиатуру (порты `#18`/`#19`)
- RS-232 (для мыши и других последовательных устройств)
## 7.5 IM1 — вектор #0038
Стандартный Z80-режим. Все INT ведут на адрес `#0038`. Используется DSS для своих обработчиков.
## 7.6 IM2 — таблица векторов
IM2 использует таблицу векторов (256 байт) в фиксированной странице (обычно W3). Вектор прерывания — `0FFh`.
Для работы IM2 требуется:
1. Таблица векторов в резиденте (W3)
2. Регистр I = старший байт адреса таблицы
3. Каждый вектор — адрес обработчика (2 байта)
## 7.7 Акселератор и прерывания
При работе акселератора система команд Z80 сильно меняется.
| Режим | Описание | Источник |
|-------|----------|----------|
| Старый | DI обязателен | IvanMak.txt:844846, Parinov.txt:954 |
| Новый | EI/RETI: по INT акселератор отключается, по RETI включается | IvanMak.txt:846848 |
> **Примечание:** IvanMak описывает два режима (старый — DI, новая прошивка — EI/RETI). Parinov знает только старый. Без тестирования на железе неизвестно, какая версия прошивки установлена.
## 7.8 Цепочка обработчиков
TODO (проектный `im2_isr_design.md`): цепочка irq_install/remove, FPS-делитель, обработчики клавиатуры.
## 7.9 Кросс-ссылки
- Порты прерываний: `11-ports.md`
- Проектный документ по IM2/ISR: `im2_isr_design.md`
- Клавиатура: `09-input.md §9.1`
- CBL (прерывания): `10-sound.md §9.4.6`
+197
View File
@@ -0,0 +1,197 @@
# 8. Ввод-вывод
## 8.1 Клавиатура и мышь
Клавиатура и мышь вынесены в отдельный документ: `09-input.md`.
Сводная информация по портам и прерываниям — `09-input.md §§9.19.6`.
## 8.2 Звук
Звуковая подсистема (AY-3-8910, COVOX, COVOX-Blaster, бипер) вынесена
в отдельный документ: `10-sound.md`.
Сводная карта звуковых портов: `11-ports.md §11.6`.
## 8.3 Дисковая подсистема
### 8.3.1 FDD (WD1793 / КР1818ВГ93)
Контроллер дисковода — стандартный Beta Disk Interface (WD1793).
Аппаратное перенаправление `#1F → #0F` (см. §8.4).
**Регистры (по данным MAME sprinter.cpp):**
| Z80-адрес | Регистр |
|-----------|---------|
| `#0F` | Status (чт) / Command (зп) |
| `#1F` | —//— (аппаратный ремап на `#0F`) |
| `#3F` | Track |
| `#5F` | Sector |
| `#7F` | Data |
| `#FF` | Drive Control (выбор дисковода) |
**Противоречие: адресация регистров ВГ93.**
> - [IvanMak.txt:12701274]: 4 регистра + `#FF` — управление дисководом.
> - [Parinov.txt:963]: 3 регистра (data-регистр `#7F` пропущен).
>
> MAME реализует полный набор по IvanMak: Status/Command (`#0F`), Track (`#3F`),
> Sector (`#5F`), Data (`#7F`). Data-регистр важен — через него читаются/пишутся
> сектора. Parinov, вероятно, упустил его.
**Turbo-режим FDD (DCP 0x16/0x17, биты):**
- Бит 0 = скорость (0=норм, 1=турбо)
- Бит 1 = отключение FDD [sprinter.cpp:914920]
### 8.3.2 HDD (IDE/ATA)
Два ATA-интерфейса: первичный и вторичный. Доступ — через DCP-декодер
(внутренние коды 0x20–0x2b).
**Регистры ATA CS0 (по sprinter.cpp):**
| DCP код | Z80-адрес (старш.) | Регистр |
|---------|-------------------|---------|
| 0x20 | `#xx50` | Data (16-bit через защёлку байтов) |
| 0x21 | `#xx51` | Error (чт) / Features (зп) |
| 0x22 | `#xx52` | Sector Count |
| 0x23 | `#xx53` | Sector Number |
| 0x24 | `#xx54` | Cylinder Low |
| 0x25 | `#xx55` | Cylinder High |
| 0x26 | `#xx56` | Device/Head |
| 0x27 | `#xx57` | Status (чт) / Command (зп) |
| 0x28 | `#xx58` | Alt Status (чт) / Device Control (зп) (CS1) |
| 0x2a | HDD1 select (вторичный) |
| 0x2b | HDD2 select (первичный) |
**16-битный data-порт:** MAME реализует защёлку байтов: чтение `#xx50`
возвращает младший байт (bit8=0), затем старший (bit8=1) [sprinter.cpp:958972].
**Противоречие: HDD — разные адреса для чтения и записи.**
> - [IvanMak.txt:1366]: кратко: «#xx50..#xx55 порты HDD»
> - [Parinov.txt:958959]: таблица с разными адресами для R/W:
> `0050h` (чт) / `0150h` (зп) — data, `4053h` (чт) / `4153h` (зп) — status/command.
>
> MAME использует единую карту DCP-кодов (0x20–0x28) без разделения R/W.
> Parinov описывает реальное поведение на Sprinter-2, где адресная линия A8
> управляет направлением — это внешняя особенность конкретной ППЛМ-прошивки.
> IvanMak упрощает до базовых DCP-кодов.
Доступ к IDE открыт в режиме Sprinter-ZX, в режимах Pentagon/Scorpion — закрыт.
### 8.3.3 CMOS (Dallas DS12887A)
Микросхема DS12887A (RTC + 114 байт NV RAM). Совместима с MC146818A.
Доступ через DCP-коды 0x1c0x1e.
| Z80-адрес | DCP код | Функция |
|-----------|---------|---------|
| `#DFBD` | 0x1d | Запись адреса регистра CMOS |
| `#FFBD` | 0x1c | Чтение данных из выбранного регистра |
| `#BFBD` | 0x1e | Запись данных в выбранный регистр |
При отсутствии микросхемы CMOS эмулируется BIOS [BIOS_v3.txt:308310].
**Карта регистров RTC (совместимо с MC146818A):**
| Рег. | Назначение | Формат |
|------|-----------|--------|
| 0x00 | Секунды | BCD |
| 0x01 | Секунды (будильник) | BCD |
| 0x02 | Минуты | BCD |
| 0x03 | Минуты (будильник) | BCD |
| 0x04 | Часы | BCD |
| 0x05 | Часы (будильник) | BCD |
| 0x06 | День недели (1=воскресенье) | BCD |
| 0x07 | Число | BCD |
| 0x08 | Месяц | BCD |
| 0x09 | Год | BCD |
| 0x0a | Регистр A (UIP, divider, rate) | биты |
| 0x0b | Регистр B (SET, PIE, AIE, UIE, SQWE, DM, 24/12, DSE) | биты |
| 0x0c | Регистр C (IRQF, PF, AF, UF) | биты (чт) |
| 0x0d | Регистр D (VRT) | биты (чт) |
| 0x0e0x7f | 114 байт NV RAM | пользовательские |
---
## 8.4 Джойстик
**Два Kempston-совместимых джойстика** [sprinter.cpp:11061175]:
- **JOY1** — через CIO_DTRB (DCP 0x15, совмещён с Beta state при чтении)
- **JOY2** — через PIO PB
**Формат данных (Kempston):**
| Бит | Кнопка |
|:---:|--------|
| 0 | Вправо |
| 1 | Влево |
| 2 | Вниз |
| 3 | Вверх |
| 4 | Fire |
| 5 | — |
| 6 | — |
| 7 | — |
**Противоречие: джойстик #1F vs #0F.**
> - [IvanMak.txt:1344]: «#1F,#0F — RD_KEMPS — порт джойстика.
> В Sprinter-1 порт #1F аппаратно переадресуется на порт #0F.»
> - [IvanMak.txt:861868]: команды `OUT (#1F),A` не срабатывают
> из-за перенаправления. Надо использовать `LD BC,#1F : OUT (C),A`.
>
> В Sprinter-1 включено аппаратное перенаправление `#1F → #0F`,
> из-за чего `IN A,(#1F)` не читает джойстик. MAME подтверждает:
> на Sp2000 (`m_cnf` bit 0) перенаправление отключается
> [sprinter.cpp:1106]. Ремап действует только на запись: при OUT
> порт `#1F` маппится на `#0F` через DCP [sprinter.cpp:1080].
JOY2 читается через PIO port A [sprinter.cpp:11361140].
---
## 8.5 Параллельный порт (принтер)
Centronics-совместимый через ППЛМ. BIOS-функции печати: 082h–08Ch
(см. `02-bios.md`).
---
## 8.6 Шина ISA
Два 8-битных ISA-слота на частоте X_SP/5 (~7 МГц). Доступ — через
DCP-декодер и страницы памяти.
**Управляющие порты ISA (DCP 0xD00xDF, 0xF80xFF):**
| Бит | Назначение |
|:---:|-----------|
| 2 | 0 = ISA memory access, 1 = ISA I/O access |
| 1 | Выбор слота (0 = slot 0, 1 = slot 1) |
Адресное расширение: `m_isa_addr_ext` (запись через DCP 0x1b) — биты
расширения адреса для ISA-циклов [sprinter.cpp:10321039].
**Memory-маппинг ISA:** При pg3 & 0xF9 == 0xD0 (бит 10 окна W3 = 1,
BANK_ISA_MASK) обращения к окну W3 (`#C000#FFFF`) направляются на ISA-шину
вместо RAM [sprinter.cpp:178181, 530532]. Длина — 16 КБ.
**I/O-доступ к ISA:** через тот же DCP-декодер. Устройства устанавливают
сигнал `m_io_input_wait` = true при совпадении адреса.
> **Примечание:** В MAME есть TODO: «ISA memory slots» — ISA memory-циклы
> пока не эмулируются [sprinter.cpp:576]. На реальном Sprinter поддержка
> зависит от прошивки ППЛМ.
Слот 0 обычно занят ZX-Bus-адаптером [sprinter.cpp:26].
---
## 8.7 Кросс-ссылки
- BIOS-функции: `02-bios.md`
- Клавиатура, мышь: `09-input.md`
- Звук: `10-sound.md`
- Порты: `11-ports.md`
- Акселератор: `06-accel.md`
- Прерывания: `07-irq.md`
+595
View File
@@ -0,0 +1,595 @@
# 9. Клавиатура и мышь
## 9.1 Общие сведения
Клавиатура Sprinter — AT-совместимая (101 key, PS/2). В Sprinter-1
дополнительно присутствует ZX-клавиатурная матрица через порт `#FE`
(скан-код через AT-контроллер преобразуется в ZX-матрицу). Sprinter-2+
использует AT-клавиатуру через внутренний SIO Z84C15 (канал A).
Мышь — Microsoft Serial Mouse (2 кнопки) через RS-232 на SIO-B (канал B
Z84C15).
### Порты SIO
| Порт | Назначение |
|------|-----------|
| `#18` | SIO-A data — клавиатура |
| `#19` | SIO-A control — статус/управление |
| `#1A` | SIO-B data — мышь |
| `#1B` | SIO-B control — мышь |
Бит 0 порта `#19` — признак прерывания от клавиатуры (используется в IM2
для различения источников с общим вектором `#FF`).
### Прерывания
Клавиатура и мышь работают в IM2, общий вектор `#FF` (совместно с
кадровым и CBL). Различение источника — по портам SIO и флаговым битам
(`07-irq.md §7.2`).
---
## 9.2 Клавиатура: BIOS и ESTEX
### FN_KBD_OUT (BIOS $EA)
Отправляет байт непосредственно на AT-клавиатуру [BIOS_v3.txt:0EAh].
```
Вход: C = $EA
A = байт команды/данных для AT-клавиатуры
Выход: нет
```
Используется для низкоуровневой настройки клавиатуры (LED-индикаторы,
повтор, задержка).
### ESTEX: функции клавиатуры (30h–37h)
Через `RST 10h` с C=30h37h [DiskSyscalls.txt:30h37h].
**WAITKEY (30h):** ждёт нажатия, возвращает код.
```
Вход: C = 30h
Выход: A = код символа
D = скан-код
E = ASCII-код (0 для функциональных клавиш)
```
**SCANKEY (31h):** опрос без ожидания.
```
Вход: C = 31h
Выход: A = код символа (0 если нажатий нет)
D = скан-код
E = ASCII-код
```
**ECHOKEY (32h):** ждёт + эхо-вывод.
```
Вход: C = 32h
Выход: A = код символа
D = скан-код
E = ASCII-код
```
**CTRLKEY (33h):** состояние модификаторов и режимов. libc: `kbd_mod_state()`.
```
Вход: C = 33h
Выход: C = mode (биты режимов — см. ниже)
B = shift (биты зажатых модификаторов)
```
| Бит C | Режим |
|-------|-------|
| 0 | РУС/ЛАТ (0=ЛАТ, 1=РУС) |
| 1 | NumLock |
| 2 | ScrollLock |
| 3 | CapsLock |
| 4 | Insert |
| Бит B | Модификатор |
|-------|------------|
| 0 | Left Shift |
| 1 | Right Shift |
| 2 | Ctrl (любой) |
| 3 | Alt (любой) |
| 4 | Left Ctrl |
| 5 | Left Alt |
| 6 | Right Ctrl |
| 7 | Right Alt |
**K_CLEAR (35h):** сбросить буфер клавиатуры.
```
Вход: C = 35h
```
**K_SETUP (36h):** настройка раскладки. [DiskSyscalls.txt:36h]
```
Вход: C = 36h
A = 0 — получить текущий номер раскладки
A = 1 — установить раскладку по номеру из B
A = 2 — получить имя текущей раскладки (адрес HL)
Выход: при A=0: A = номер раскладки
при A=2: HL = адрес строки с именем
```
| Номер | Раскладка |
|-------|----------|
| 0 | Английская (US) |
| 1 | Русская |
| 2 | Английская (UK) |
| 3 | Украинская |
Переключение раскладки по Ctrl+Space (если не переназначено).
**TESTKEY (37h):** тест на нажатие (без извлечения из буфера).
```
Вход: C = 37h
Выход: A = код символа (0 если нет)
D = скан-код
E = ASCII-код
```
---
## 9.3 Клавиатура: необработанный (raw) доступ
Штатный DSS (WAITKEY/SCANKEY/CTRLKEY) даёт событийный интерфейс —
нажатия, а не состояния клавиш. Для игр и real-time приложений требуется
чтение **зажатых клавиш в каждый момент**. Это реализуется через
перехват SIO-A напрямую в обработчике IM2, минуя DSS.
### 9.3.1 Принцип
1. Установить свой обработчик IM2 (общий вектор `#FF`).
2. В обработчике читать байты с SIO-A (порт `#18`), декодировать
PS/2 Scan Code Set 2, обновлять битовую карту held-состояний.
3. Основной код по кадровому прерыванию (или раз в кадр) читает карту
опросом — без ожидания.
4. DSS не получает байт с клавиатуры, пока обработчик их забирает.
Для восстановления нормального ввода — временно отключить перехват.
### 9.3.2 SIO-A и прерывания
SIO-A (порт данных `#18`, управление `#19`) работает в IM2.
**Инициализация SIO-A** (выполняется BIOS при загрузке, повторно не требуется):
| WR | Значение | Эффект |
|:--|:---------|--------|
| WR0 | `0x10` | Сброс RR1 (ошибка) |
| WR1 | `0x07` | Прерывания по Rx готовности |
| WR3 | `0xC1` | Rx 8 бит, без CRC |
| WR4 | `0x44` | ×1 клок, 1 стоп-бит, без паритета |
| WR5 | `0xEA` | Tx 8 бит, DTR+RTS=1 |
**Различение в IM2:** при входе в обработчик проверить бит 0 порта `#19`.
Если 0 — прерывание не от SIO-A (кадровое, CBL — пропустить).
### 9.3.3 PS/2 Scan Code Set 2 — протокол
SIO-A передаёт скан-коды PS/2 Set 2. Каждый байт с порта `#18`
один байт протокола. Размер сообщения:
| Последовательность | Значение |
|:------------------|:---------|
| `<code>` | Make — клавиша нажата (код < 0xF0) |
| `0xF0 <code>` | Break — клавиша отпущена |
| `0xE0 <code>` | Extended — расширенная клавиша (стрелки, RAlt, RCtrl) |
| `0xE0 0xF0 <code>` | Extended break |
Make-байт устанавливает бит клавиши в held-карте.
Break-байт сбрасывает.
**FSM декодирования (2 состояния):**
```
PEND_MAKE:
получить байт B
if B == 0xF0 → переход PEND_BREAK
if B == 0xE0 → переход PEND_EXT, Bзап = B
иначе → make(B)
PEND_BREAK:
получить байт B
переход PEND_MAKE
if (ext_flag) → break_ext(B); ext_flag = 0
иначе → break(B)
PEND_EXT:
получить байт B
if B == 0xF0 → ext_flag = 1, переход PEND_BREAK_EXT
иначе → make_ext(B); переход PEND_MAKE
PEND_BREAK_EXT:
получить байт B
ext_flag = 0
break_ext(B)
переход PEND_MAKE
```
### 9.3.4 Битовая карта held-состояний
Массив 128 байт (1024 бита для кодов 0..1023, расширенные — с битом
`0x0100`).
Простая реализация:
```asm
; HL = code (0..0x1FF)
; IX = base адреса карты
LD A, H
AND A, 0x07 ; номер бита 8..10
LD D, A
LD A, L
RRCA ; HL/8 (3 сдвига)
RRCA
RRCA
AND A, 0x1F
LD L, A
LD A, H
AND A, 0x07
ADD A, A ; +8*...
ADD A, A
ADD A, A
ADD A, L
LD L, A
LD H, 0x00
ADD IX, HL ; IX = &bitmap[code / 8]
LD A, D
INC A
LD B, A ; B = номер бита в байте + 1
XOR A
SCF ; carry=1 для make, 0 для break
RL A
DJNZ $-2 ; A = 1 << (code & 7)
; make: OR (IX), A ; break: CPL + AND (IX), A
```
### 9.3.5 Overrun recovery
SIO FIFO глубиной 3 байта. Если обработчик прерывания не успевает
забрать байты (длинная DI-секция, акселератор), FIFO переполняется —
RR1 bit5 = 1. С этого момента цепочка make+break нарушена, возможны
залипшие клавиши.
**Алгоритм восстановления:**
1. Обнаружить overrun (читать SIO RR1, бит 5).
2. Сбросить held-карту **всех клавиш, кроме**:
| Код PS/2 | Клавиша | Почему |
|:--------:|:--------|:-------|
| `0x12` | Left Shift | PS/2 автоповтор — только последняя |
| `0x59` | Right Shift | нажатая клавиша. Если сбросить |
| `0x14` | Left Ctrl | модификатор, он не восстановится до |
| `0x11` | Left Alt | физического отпускания. Игра «теряет» |
| `0xE014` | Right Ctrl | шифт/контрол/альт при каждом overrun. |
| `0xE011` | Right Alt | |
3. Взвести флаг «был overrun» — основной код может проигнорировать
held-состояние на этот кадр.
### 9.3.6 Координация с DSS
Пока обработчик забирает байты с SIO-A, FIFO пуст — DSS не видит
клавиатуру. Для вызова DSS-функций (консоль, диалоговые окна):
1. Переключить флаг «raw active = 0» в IM2-обработчике.
2. Обработчик начинает пропускать байты в DSS (JP `0038h` или
через штатный трамплин).
3. После завершения ввода — переключить флаг обратно.
**Внимание:** если обработчик просто перестаёт читать SIO-A, но не
возвращает управление DSS, порт SIO-A перестанет генерировать
прерывания (FIFO полон, Rx готов = 0). Для корректной передачи
управления нужно разрешить DSS-обработчику читать SIO-A.
### 9.3.7 Пример: минимальный raw-обработчик
```asm
; Флаги: raw_active = 1 — перехватывать, 0 — пропускать в DSS
; Карта: kbd_held — 128 байт, занулена при старте
; FSM: kbd_state — 0=PEND_MAKE, 1=PEND_BREAK, 2=PEND_EXT, 3=PEND_BREAK_EXT
; kbd_ext — флаг extended (0/1)
KBD_ISR:
; Проверить, что прерывание от SIO-A
IN A, (#19) ; SIO-A RR0
BIT 0, A ; бит 0 = прерывание от SIO-A?
RET Z ; нет — пропустить
IN A, (#18) ; прочитать байт скан-кода
BIT raw_active ; перехват активен?
JP Z, DSS_IRQ ; нет — пусть DSS обработает
; FSM: текущее состояние в kbd_state
LD HL, kbd_state
LD A, (HL)
AND A, 3
JP Z, .pend_make
DEC A
JP Z, .pend_break
DEC A
JP Z, .pend_ext
; .pend_break_ext
LD (HL), 0 ; → PEND_MAKE
LD A, B ; код клавиши
CALL break_ext
EI
RETI
.pend_make:
LD A, B ; байт с SIO-A (уже в B из IN)
CP 0xF0
JR Z, .set_break
CP 0xE0
JR Z, .set_ext
CALL make ; обычный make
LD (HL), 0 ; остаёмся PEND_MAKE
EI
RETI
.set_break:
LD (HL), 1 ; → PEND_BREAK
EI
RETI
.set_ext:
LD (HL), 2 ; → PEND_EXT
EI
RETI
.pend_break:
LD (HL), 0 ; → PEND_MAKE
CALL break
EI
RETI
.pend_ext:
LD A, B
CP 0xF0
JR Z, .set_ext_break
CALL make_ext
LD (HL), 0
EI
RETI
.set_ext_break:
LD (HL), 3 ; → PEND_BREAK_EXT
EI
RETI
```
Размер кода — ~60 байт.
---
## 9.4 Мышь
Драйвер мыши установлен в системном shell Sprinter и доступен через
SST-вызов `RST 30h`.
### 9.4.1 SST-функции мыши
Вызов: `RST 30h` с A = номер функции. Выход в зависимости от функции
(см. таблицу).
| № | Назначение | Вход | Выход |
|:-:|:-----------|:-----|:------|
| `$00` | Инициализация | A=$00 | — |
| `$01` | Показать курсор | A=$01 | — |
| `$02` | Спрятать курсор | A=$02 | — |
| `$03` | Читать состояние | A=$03 | DE=X, HL=Y, A=buttons (b0=left, b1=right) |
| `$04` | Переместить курсор | A=$04, DE=X, HL=Y | — |
| `$05` | Установить границы X | A=$05, DE=min, HL=max | — |
| `$06` | Установить границы Y | A=$06, DE=min, HL=max | — |
| `$07` | Вид курсора (текст) | A=$07, DE=sym_and:sym_xor, HL=attr_and:attr_xor | — |
| `$09` | Загрузить курсор (граф.) | A=$09, IX=pointer | — |
| `$0B` | Прочитать курсор | A=$0B | IX=pointer (копия) |
| `$0C` | Чувствительность X | A=$0C, D=value (1..255) | — |
| `$0D` | Чувствительность Y | A=$0D, D=value (1..255) | — |
| `$0E` | Прочитать чувств. X | A=$0E | D=value |
| `$0F` | Прочитать чувств. Y | A=$0F | D=value |
| `$11` | Уведомить о смене режима | A=$11, D=режим (0=текст, 1=граф-256, 2=граф-16) | — |
**Пример: прочитать состояние мыши в asm:**
```asm
LD A, $03 ; READ
RST 30h
; DE = X, HL = Y, A = buttons
LD (mouse_x), DE
LD (mouse_y), HL
AND A, 3
LD (mouse_btn), A
```
### 9.4.2 Чувствительность
Значение — **делитель**: драйвер считает N raw-шагов мыши, прежде чем
сдвинуть курсор на 1 пиксель. **Меньше = быстрее** (чувствительнее).
Рекомендуемое начальное значение: 2 по обеим осям.
```asm
LD A, $0C ; SET_SENS_H
LD D, 2
RST 30h
LD A, $0D ; SET_SENS_V
LD D, 2
RST 30h
```
### 9.4.3 Порядок инициализации
После загрузки драйвер мыши уже инициализирован shell. Если программа
начинает «с чистого листа» (без shell), инициализация обязательна:
```asm
LD A, $00 ; INIT — инициализировать драйвер
RST 30h
LD A, $05 ; BOUNDS_X: границы экрана
LD DE, 0
LD HL, 319 ; для 320×256
RST 30h
LD A, $06 ; BOUNDS_Y
LD DE, 0
LD HL, 255
RST 30h
LD A, $01 ; SHOW — показать курсор
RST 30h
```
### 9.4.4 Смена видеорежима
После переключения видеорежима (графический → текстовый и обратно)
обязательно вызвать `$11`:
```asm
LD A, $11
LD D, 1 ; 0=текст, 1=граф-256, 2=граф-16
RST 30h
```
Иначе драйвер применяет старые координаты, и курсор рисуется
неправильно.
### 9.4.5 Прямой доступ к SIO-B (raw mouse)
Мышь подключена через SIO-B (порты `#1A`/`#1B`), Microsoft Serial Mouse,
1200 бод 7E1. Если программа хочет читать мышь напрямую, минуя
SST-драйвер (например для нестандартного протокола или экономии на
SST), SIO-B нужно инициализировать самостоятельно:
**Инициализация SIO-B (1200 7E1):**
```asm
LD HL, .sio_init
LD B, 6
LD C, #1B ; SIO-B control
OTIR
JR .done
.sio_init:
DB #10 ; WR0: сброс RR1
DB #04 ; WR1: прерывания выкл
DB #44 ; WR4: ×1 клок, 1 стоп, без паритета
DB #C1 ; WR3: Rx 8 бит
DB #EA ; WR5: Tx 8 бит, DTR+RTS=1
DB #15 ; WR0: сброс ошибки + выбран RR1
.done:
```
**Чтение байта с мыши (опрос, без прерываний):**
```asm
IN A, (#1B) ; SIO-B RR0
BIT 0, A ; бит 0 = Rx готов?
JR Z, .no_data
IN A, (#1A) ; прочитать байт
; обработать ...
```
**Формат пакета Microsoft Serial Mouse:**
Длина: 3 байта.
| Байт | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|:----:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 0 | 1 | 0 | 0 | 0 | L | R | Y7 | Y6 |
| 1 | 0 | X6 | X5 | X4 | X3 | X2 | X1 | X0 |
| 2 | 0 | Y5 | Y4 | Y3 | Y2 | Y1 | Y0 | X7 |
- Координаты X/Y — **относительные** (приращения с последнего пакета), знаковые.
- `X7` — старший бит X (знак), `X6..X0` — младшие.
- `Y7..Y6` — старшие биты Y, `Y5..Y0` — младшие.
- `L` — левая кнопка (1 = нажата), `R` — правая.
**Декодирование:**
```asm
; B = байт 0, C = байт 1, D = байт 2
; X:
LD A, C ; байт 1: X6..X0
LD E, A
LD A, D ; байт 2: X7
RLCA
RLCA
AND A, 0x80
OR A, E ; A = X (7 бит + знак)
; знаковое расширение в HL
LD L, A
RLCA
SBC A, A
LD H, A ; HL = X (знаковое 16-бит)
; Y:
LD A, B ; байт 0: Y7..Y6
RLCA
RLCA ; A[1:0] = Y7..Y6
AND A, 0xC0
LD E, A
LD A, D ; байт 2: Y5..Y0
RLCA
RLCA ; A[7:2] = Y5..Y0
AND A, 0xFC
OR A, E ; A = Y (7 бит + знак)
; знаковое расширение в DE
LD E, A
RLCA
SBC A, A
LD D, A ; DE = Y (знаковое 16-бит)
; Кнопки:
LD A, B
AND A, 0x30 ; биты L (4) и R (5)
RRCA ; A = 0..3
RRCA
RRCA
RRCA
LD (buttons), A
```
---
## 9.5 Особенности игровой клавиатуры
Документ: `kbd-games.md`. Ниже — ключевые паттерны для реализации.
- **Held-state vs edge-detect:** DSS — событийный (сообщает только момент
нажатия). Raw-канал (§9.3) — state-based (зажата/не зажата прямо сейчас).
Играм нужен второй.
- **Sync once per frame:** раз в кадр (по кадровому прерыванию) проверять
held-карту. Между кадрами карта обновляется только в IM2-обработчике.
- **Edge-detect:** для одноразовых действий (прыжок, выстрел) — запоминать
предыдущее held-состояние и сравнивать:
```
pressed = held & ~prev_held
prev_held = held
```
- **Типоматик:** игнорировать повторные make, пока не придёт break.
Реализация: при make — установить бит только если он ещё не был
установлен; при break — сбросить.
- **Автоотмена (reject):** если за кадр нажато больше N клавиш (например
4) — игнорировать все (защита от баунса и мусора).
- **Recovery:** при overrun — очистить held-карту всех клавиш, кроме
модификаторов (LShift 0x12, RShift 0x59, LCtrl 0x14, LAlt 0x11,
RCtrl 0xE014, RAlt 0xE011).
---
## 9.6 Кросс-ссылки
- Прерывания (IM2, вектор #FF): `07-irq.md §7.2`
- DSS-функции клавиатуры: `03-dss.md §3.6`
- BIOS FN_KBD_OUT: `02-bios.md §2.7`
- Порт клавиатуры `#FE`: `11-ports.md §11.3`
- Игровая клавиатура: `kbd-games.md`
- Баги: `12-bugs.md`
- SIO и порты прерываний: `11-ports.md §11.2`
+377
View File
@@ -0,0 +1,377 @@
# 10. Звук
## 10.1 Общие сведения
> Документ описывает звуковую подсистему платы **Sp2000** и более новых моделей.
> Информация о Sprinter-97 не рассматривается.
Звуковая подсистема Sprinter Sp2000 включает три компонента:
| Компонент | Тип | Описание |
|-----------|-----|----------|
| GM80C760 (AY-3-8910 совм.) | Музыкальный сопроцессор | 3 голоса + шум + огибающая, эмуляция в ППЛМ |
| COVOX | 8-битный ЦАП | Прямой вывод сэмплов через порт `#FB`/`#4F` |
| CBL (COVOX-Blaster) | COVOX с буфером | 256 байт буфера, прерывания, разные режимы |
Весь звук выводится через **16-битный ЦАП TDA1543** (двухканальный, стерео).
Реально используется 10 бит для одновременного смешивания 8-bit COVOX и AY
[IvanMak.txt:632634].
**На Sp2000 все три компонента присутствуют в основной прошивке ППЛМ.**
CBL включается через порт `#4E` (бит 7 = 1). При выключенном CBL (бит 7 = 0)
работает обычный 8-bit COVOX [IvanMak.txt:662666].
## 10.2 GM80C760 (AY-3-8910)
### 10.2.1 Реализация
AY-функция реализована на микросхеме **GM80C760** (ППЛМ ALTERA EP1K30),
AY-3-8910/8912 совместимая. Это не отдельная дискретная микросхема
[IvanMak.txt:636637].
На EP1K30 (Sp2000) реализована **3-я версия** AY. Включает три голоса,
шум и генератор огибающей (envelope). В формирователе огибающей обнаружена
небольшая ошибка, детали не документированы [IvanMak.txt:224229],
[12-bugs.md §11.2].
### 10.2.2 Порты
| Порт | Назначение |
|------|-----------|
| `#BFFD` | AY-8910 — запись номера регистра (address) |
| `#FFFD` | AY-8910 — чтение/запись данных регистра (data) |
Внутренние номера в карте дешифратора ППЛМ: `90h` (`#BFFD`), `91h` (`#FFFD`)
[IvanMak.txt:12981299].
### 10.2.3 Программирование
Программирование — **стандартное для AY-3-8910/8912**
[IvanMak.txt:636637]:
```asm
; Установить регистр AY
LD BC, #BFFD
OUT (C), A ; A = номер регистра (0..15)
LD BC, #FFFD
OUT (C), A ; A = значение
; Прочитать регистр AY (3-я версия)
LD BC, #BFFD
OUT (C), A ; A = номер регистра
LD BC, #FFFD
IN A, (C) ; читать данные
```
**Регистры AY-3-8910** (стандартные):
| № | Назначение |
|:-:|-----------|
| 0 | Частота канала A (младший байт) |
| 1 | Частота канала A (старшие 4 бита) |
| 2 | Частота канала B (младший байт) |
| 3 | Частота канала B (старшие 4 бита) |
| 4 | Частота канала C (младший байт) |
| 5 | Частота канала C (старшие 4 бита) |
| 6 | Период шума |
| 7 | Микшер (включение каналов и шума) |
| 8 | Громкость A |
| 9 | Громкость B |
| 10 | Громкость C |
| 11 | Период огибающей (младший байт) |
| 12 | Период огибающей (старшие 8 бит) |
| 13 | Форма огибающей |
| 14 | Порт I/O A (не используется на Sprinter) |
| 15 | Порт I/O B (не используется на Sprinter) |
**Стерео:** AY имеет два выходных канала, но в стандартной конфигурации
Sprinter оба канала получают монофонический сигнал.
---
## 10.3 COVOX (8-бит)
### 10.3.1 Порты
| Порт | Назначение |
|------|-----------|
| `#FB` | COVOX data (он же порт включения КЭШ-ОЗУ по IN) |
| `#4F` | COVOX data (альтернативный адрес) |
[IvanMak.txt:642, 1347]
### 10.3.2 Программирование
Простейший вывод сэмплов — последовательная запись байтов в порт `#FB`
или `#4F`:
```asm
; Цикл вывода сэмплов (8 бит, моно)
LD HL, sample_data
LD BC, sample_length
loop:
LD A, (HL)
OUT (#FB), A
INC HL
DEC BC
LD A, B
OR C
JR NZ, loop
```
### 10.3.3 Конфликт с Fast RAM (КЭШ-ОЗУ)
Порт `#FB` используется **для двух целей**:
- `OUT (#FB), A` — запись в COVOX
- `IN A, (#FB)` — включение КЭШ-ОЗУ
Если КЭШ-ОЗУ включено, запись в `#FB` уходит в кэш, а не в COVOX.
Перед работой с COVOX кэш нужно отключать: `IN A, (#7B)`
[IvanMak.txt:850851], [12-bugs.md §11.4].
---
## 10.4 COVOX-Blaster (CBL)
### 10.4.1 Общее описание
**CBL (COVOX-Blaster)** — COVOX с буферным ОЗУ на **256 байт**. Позволяет
выводить звук поблочно, освобождая процессор для другой работы
[IvanMak.txt:647], [Parinov.txt:688].
### 10.4.2 Порт управления `#4E`
**Порт `#4E` — 16-битный! Только через `OUT (C),A`** (с `LD BC,004Eh`)
[Parinov.txt:692693].
> **Примечание:** IvanMak.txt упоминает его как 8-битный, но Parinov.txt явно
> указывает 16-битный доступ. Современный код использует `OUT (C),A`.
**Биты порта `#4E`** [Parinov.txt:695698]:
| Бит | Мнемоника | Назначение |
|-----|-----------|-----------|
| 7 | **CBL_ON** | 1 = CBL включён, 0 = обычный COVOX |
| 6 | **STEREO** | 1 = стерео, 0 = моно |
| 5 | **16BIT** | 1 = 16-битные сэмплы, 0 = 8-битные |
| 4 | **IRQ_EN** | 1 = включить прерывания от CBL |
| 30 | **FREQ** | Частота дискретизации (см. таблицу) |
### 10.4.3 Частоты дискретизации
[Parinov.txt:700718]:
| Код | Частота | Примечание |
|:---:|---------|-----------|
| 0 | 16 kHz | старые режимы, **НЕ ИСПОЛЬЗОВАТЬ** |
| 1 | 22 kHz | старые режимы, **НЕ ИСПОЛЬЗОВАТЬ** |
| 2–7 | — | зарезервировано |
| **8** | **7.8125 kHz** | mono/stereo, 8/16-bit |
| **9** | **10.9375 kHz** | mono/stereo, 8/16-bit |
| **A** | **15.625 kHz** | mono/stereo, 8/16-bit |
| **B** | **21.875 kHz** | mono/stereo, 8/16-bit |
| **C** | **31.25 kHz** | mono/stereo, 8/16-bit |
| **D** | **43.75 kHz** | mono/stereo, 8/16-bit |
| **E** | **54.6875 kHz** | mono/stereo, 8/16-bit |
| **F** | **109.375 kHz** | mono/stereo, 8/16-bit |
> **Важно:** коды 0 и 1 — старые режимы из первых прошивок, несовместимы с
> новыми режимами (8–F). Использовать только коды 8–F.
### 10.4.4 Режимы и формат данных
[Parinov.txt:767783]:
| Режим | Нулевой уровень | Размер блока | Формат данных |
|-------|:---------------:|:------------:|--------------|
| mono 8-bit | `80h` | 128 байт | `DB 80h, 81h, 7Fh, ...` |
| mono 16-bit | `0000h` | 256 байт | `DW 0, 1000, -1000, ...` |
| stereo 8-bit | `80h,80h` | 128 байт | `DB 80h,80h, 81h,80h, ...` (L, R чередуются) |
| stereo 16-bit | `0000h,0000h` | 256 байт | `DW 0,0, 1000,0, ...` (L, R чередуются) |
Формат данных выбран так, чтобы WAV-файлы можно было пересылать в CBL
простой `OTIR` [Parinov.txt:791].
### 10.4.5 Буфер CBL и механизм банок
CBL имеет буферное ОЗУ на **256 байт**, организованное как кольцевой буфер
[Parinov.txt:758760]:
- Счётчик CBL считает **«назад»** — из-за особенности команды `OUTI`, где `B`
уменьшается и попадает на A15..A8.
- Для 8-битных режимов буфер условно разбит на **две банки по 128 байт**.
- Для 16-битного режима блок = **256 байт** (весь буфер).
**Механизм работы:**
1. Процессор записывает блок данных (128 байт для 8-бит, 256 байт для 16-бит)
в буфер CBL.
2. Аппаратный счётчик CBL автоматически считывает данные из буфера и
отправляет в ЦАП на заданной частоте.
3. Бит 7 порта `#FE` указывает, какая банка сейчас выводится в ЦАП.
4. Когда банка переключается — CBL запрашивает следующую порцию данных
(через прерывание или polling).
5. Запрос данных возникает для **каждых 128 байт (256 в 16-битном режиме)**.
### 10.4.6 Порт статуса `#FE`
**Бит 7 порта `#FE`** — запрос данных для CBL [Parinov.txt:720724]:
| Бит | Назначение |
|-----|-----------|
| 7 | **CBL data request** — 1 = CBL запрашивает новую порцию данных |
| 5 | **Frame sync** — кадровый импульс (4 мс длиной, 20 мс период) |
> **Примечание:** В MAME при выключенном CBL бит 7 порта #FE всегда = 1.
> Это следует учитывать при разработке обработчика прерываний
> [`im2_isr_design.md:2631`].
**Противоречие** [08-io.md §8.3]:
- IvanMak.txt описывает бит 7 как старший бит счётчика CBL для polling
(определение, какая половина буфера выводится).
- Parinov.txt описывает его как запрос прерывания.
- Оба описывают одну физическую линию, но в разных режимах (polling vs interrupt).
### 10.4.7 Прерывания и IM2
- При включённых прерываниях CBL (бит 4 порта `#4E` = 1) необходим **режим IM 2**.
- Если остаться на IM1, DOS-процедура прерываний будет вызываться слишком часто,
что вызовет тормоза на высоких частотах [Parinov.txt:762764].
- **Вектор прерывания CBL — `#FF`** (как и у клавиатуры, и у кадрового).
Отличать — по биту 7 порта `#FE` [`sprinterIntLib.asm:2426`].
**Обработчик прерываний на IM2:**
```asm
; Проверка источника
IN A, (#FE)
RLCA ; бит 7 → CF
JR NC, not_cbl ; не CBL — на другой обработчик
; CBL запрашивает данные
LD BC, 804Fh ; B = 128 (счётчик), C = 4Fh (порт CBL data)
LD HL, next_block
OTIR ; вывести 128 байт в буфер CBL
...
```
### 10.4.8 Запись данных в CBL
**Способ 1: OTIR/OUTI через порт `#4F`**
```asm
LD BC, 804Fh ; B = 128 (счётчик), C = #4F (CBL data)
LD HL, data_block
OTIR ; вывести 128 байт
```
**Способ 2: через страницу ОЗУ `#FD` с акселератором**
Страница `#FD`, отображённая в окно `#C000`, аппаратно связана с буфером CBL.
Для 8-битного режима — записать 128 байт; для 16-битного — 256 байт
[Parinov.txt:727731].
```asm
; Запись блока данных в CBL через страницу #FD с акселератором
IN A, (#E2) ; сохранить текущую страницу W3
LD (.save_page), A
LD A, #FD
OUT (#E2), A ; W3 = страница CBL
LD DE, #C000 ; приёмник (CBL buffer)
LD B, 0 ; B = 0 → 256 байт (или 128 для 8-bit)
LD D,D ; ACC_ON: включить акселератор
LD L,L ; ACC_CopyBlock_Horizontal
LD A, (HL) ; загрузить байт в буфер акселератора
LD (DE), A ; записать в CBL
LD B,B ; ACC_OFF: выключить акселератор
LD A, (.save_page)
OUT (#E2), A ; восстановить страницу
```
### 10.4.9 Полный пример
Из `docs/samples/Пример для CBL.asm` [sprinterIntLib.asm]:
```asm
; Инициализация IM2
LD A, #BE
LD I, A ; таблица векторов по #BE00
IM 2
; Вектор прерывания CBL = #BEFF
; (Interrupt_Vector OR 0FFh)
; Включение CBL
LD BC, #4E
LD A, %10011000b ; bit7=1 CBL on, bit4=1 IRQ en, bits3-0=1000 = 7.8125 kHz
OUT (C), A
; В ISR:
; IN A, (#FE)
; RLCA
; JR NC, .NoSound
; ... копировать 128 байт через страницу #FD с акселератором
; После проигрывания:
; Установить NumberPage=2, подождать HALT
; Выключение CBL:
LD BC, #4E
LD A, 0
OUT (C), A
```
### 10.4.10 Известные проблемы
1. **CBL vs Fast RAM:** порт `#FB` используется и для COVOX/CBL, и для
включения КЭШ-ОЗУ (см. §10.3.3).
2. **Щелчок перед первым звуком:** известная проблема при старте CBL
[`TODO.md:263`].
3. **Помехи при движении мыши:** часть тиков прерываний, обслуживающих
CBL-насос, уходит на обслуживание мыши [`TODO.md:270277`].
4. **Порт #4E — 8-бит vs 16-бит:** IvanMak подразумевает 8-битный,
Parinov требует 16-битный `OUT (C),A` (см. §10.4.2).
5. **MAME: бит 7 порта #FE = 1 при выключенном CBL:** может вызвать
ложные срабатывания обработчика (см. §10.4.6).
---
## 10.5 Бипер
Стандартный Spectrum-бипер — бит 3 (в некоторых конфигурациях бит 5)
порта `#FE`. Выведен через ту же схему TDA1543, что COVOX и AY
[IvanMak.txt:639640].
```asm
; Включить бипер
LD A, %00001000 ; бит 3 = 1
OUT (#FE), A
; Выключить бипер
LD A, %00000000 ; бит 3 = 0
OUT (#FE), A
```
---
## 10.6 SSC (Sprinter Sound Card)
Разрабатывалась, но **не реализована** ни в одной прошивке Sp2000
из-за большого объёма ПЛМ [IvanMak.txt:763772].
Параметры проекта:
- 2 канала
- 16 восьмибитных голосов
- 256-байтные Wave-таблицы для каждого голоса
- 8-битный регулятор амплитуды
---
## 10.7 Кросс-ссылки
- Порты звука: `11-ports.md`
- Баги AY и CBL: `12-bugs.md`
- Fast RAM и конфликт с COVOX: `04-memory.md §4.6`
- 08-io.md (остальной ввод-вывод): `08-io.md`
+103
View File
@@ -0,0 +1,103 @@
# 11. Карта портов
## 11.1 Системные порты Z84C15 (внутренние)
Эти адреса изменить невозможно — находятся вне ППЛМ [IvanMak.txt:869870].
| Порт | Назначение | Доступ |
|------|-----------|--------|
| `#10` | SIO A data / CTC channel 0 | R/W |
| `#11` | SIO A control / CTC channel 1 | R/W |
| `#12` | SIO B data / CTC channel 2 | R/W |
| `#13` | SIO B control / CTC channel 3 | R/W |
| `#14` | PIO A data | R/W |
| `#15` | PIO A control | R/W |
| `#16` | PIO B data | R/W |
| `#17` | PIO B control | R/W |
| `#18` | SIO data channel A (клавиатура) | R/W |
| `#19` | SIO control channel A (статус клавиатуры) | R/W |
| `#1A` | SIO data channel B (мышь) | R/W |
| `#1B` | SIO control channel B (мышь) | R/W |
| `#1E` | PIO B бит 0 — IRQ от ISA | R |
| `#1F` | PIO B + джойстик (Kempston) | R/W |
| `#EE` | CTC channel 2 (альтернативный) | R/W |
| `#EF` | CTC channel 3 (альтернативный) | R/W |
| `#F0` | CTC channel 0 (альтернативный) | R/W |
| `#F1` | CTC channel 1 (альтернативный) | R/W |
| `#F4` | CTC — альтернативный доступ | |
## 11.2 Управление памятью
| Порт | Назначение | Источник |
|------|-----------|----------|
| `#7FFD` | Основной: W3 page (02), RAM/ROM select, lock | IvanMak.txt:1343 |
| `#1FFD` | Расширенный: W0 page (02), turbo, extended RAM, VRAM segment | IvanMak.txt:1345 |
| `#DFFD` | W1 page select (Pentagon-512) | IvanMak.txt:1346 |
| `#EFF7` | W2 page select (Pentagon-512) | IvanMak.txt:1346 |
| `#82` | W0 page (PAGE0) — всегда доступен | IvanMak.txt:1348 |
| `#A2` | W1 page (PAGE1) — всегда доступен | IvanMak.txt:1348 |
| `#C2` | W2 page (PAGE2) — всегда доступен | IvanMak.txt:1348 |
| `#E2` | W3 page (PAGE3) — всегда доступен | IvanMak.txt:1348 |
## 11.3 Видео
| Порт | Назначение | Источник |
|------|-----------|----------|
| `#89` | RGADR (PORT_Y) — номер строки/блока видео-ОЗУ | IvanMak.txt:1349 |
| `#C9` | RGMOD — страница режима экрана (бит 0: 0/1) | IvanMak.txt:1350 |
## 11.4 Управление конфигурацией/прошивкой
| Порт | Назначение | Источник |
|------|-----------|----------|
| `#FB` | Включение КЭШ-ОЗУ (IN), COVOX data | IvanMak.txt:1351 |
| `#7B` | Выключение КЭШ-ОЗУ (IN) | Parinov.txt:598 |
## 11.5 Дисковая подсистема
| Порт | Назначение | Источник |
|------|-----------|----------|
| `#0F` | ВГ93 Command/Status (после ремапинга #1F#0F) | IvanMak.txt:1270 |
| `#1F` | ВГ93 Command/Status (оригинал, ремапится) | IvanMak.txt:1344 |
| `#3F` | ВГ93 Track register | IvanMak.txt:1271 |
| `#5F` | ВГ93 Sector register | IvanMak.txt:1272 |
| `#7F` | ВГ93 Data register | IvanMak.txt:1273 |
| `#FF` | ВГ93 Drive Control (write); IRQ/джойстик (read) | IvanMak.txt:1274 |
| `#BD` | Переключение режима FDD (720K/1.44M) | IvanMak.txt:1347 |
| `xx50` | IDE Data | Parinov.txt:958 |
| `xx51` | IDE Error/Features | Parinov.txt:958 |
| `xx52` | IDE Sector Count | Parinov.txt:958 |
| `xx53` | IDE Sector Number | Parinov.txt:958 |
| `xx54` | IDE Cylinder Low | Parinov.txt:958 |
| `xx55` | IDE Cylinder High | Parinov.txt:958 |
| `4052h` (R) / `4152h` (W) | IDE Device/Head | Parinov.txt:959 |
| `4053h` (R) / `4153h` (W) | IDE Status/Command | Parinov.txt:959 |
| `FFBD` | CMOS data read | BIOS_v3.txt:308 |
| `BFBD` | CMOS data write | BIOS_v3.txt:308 |
| `DFBD` | CMOS address write | BIOS_v3.txt:308 |
## 11.6 Звук
| Порт | Назначение | Источник |
|------|-----------|----------|
| `#FB` | COVOX data (also КЭШ-ОЗУ enable) | IvanMak.txt:642 |
| `#4F` | COVOX/CBL data | IvanMak.txt:642 |
| `#4E` | CBL control (8/16-bit — см. `10-sound.md §9.4.2`) | IvanMak.txt:662, Parinov.txt:692 |
## 11.7 Джойстик и системные
| Порт | Назначение | Источник |
|------|-----------|----------|
| `#FE` | ZX-клавиатурная матрица, бипер, CBL статус | IvanMak.txt:1344 |
| `#1F` | Джойстик (Kempston) / PIO B | IvanMak.txt:1344 |
## 11.8 Кросс-ссылки
- BIOS-функции: `02-bios.md`
- DSS-функции: `03-dss.md`
- Управление памятью: `04-memory.md`
- Звук (AY, COVOX, CBL): `10-sound.md`
- Видео/палитра: `05-graphics.md`
- Прерывания: `07-irq.md`
- Детали I/O: `08-io.md`
- Баги: `12-bugs.md`
+54
View File
@@ -0,0 +1,54 @@
# 12. Баги BIOS, DSS и железа Sp2000
## 12.1 DRV_VERIFY (54h) не существует
Функция `54h DRV_VERIFY` описана во всей документации BIOS, но в реальности отсутствует — всегда возвращает CF=1.
> [bugs.txt:5859]: «Нет биосной функции "54h" (DRV_VERIFY) верификации секторов, описанной в документации. Поэтому она всегда возвращает установленный флаг "Carry".»
Источники, содержащие описание несуществующей функции:
- [BIOS_v3.txt:258261]
- [IvanMak.txt:21982210]
## 12.2 AY-3-8910 — ошибка в формирователе огибающей
Третья версия AY в ППЛМ Sp2000 содержит ошибку в схеме формирователя огибающей (envelope generator). Детали не документированы.
> [IvanMak.txt:224229]: «Третья версия схемы AY ... включает в себя ... генератор огибающей. ... В схеме формирователя огибающей обнаружена небольшая ошибка. ... В следующей версии AY предполагается данный недостаток исключить.»
## 12.3 Акселератор — конфликт с прерываниями
При работе акселератора система команд Z80 сильно меняется, что может приводить к сбоям в обработчиках прерываний.
> [IvanMak.txt:844846]: «Отключение прерываний во время работы акселератора необходимо, так как в этот момент сильно меняется система команд процессора и программа на прерывании не сможет работать нормально.»
Новая прошивка акселератора позволяет работать с прерываниями — при приходе INT акселератор отключается и включается обратно по RETI [IvanMak.txt:846848]. Без тестирования на реальном железе неизвестно, какая версия прошивки установлена.
## 12.4 Быстрое ОЗУ — конфликт с COVOX
Порт `#FB` используется как для включения КЭШ-ОЗУ (IN), так и для вывода данных в COVOX (OUT). Если КЭШ-ОЗУ включено, запись в COVOX может давать неожиданные результаты.
> [IvanMak.txt:850851, 642]
Перед вызовом RST или выходом в DOS КЭШ-ОЗУ обязательно отключать (`IN A,(#7B)`).
## 12.5 STA_VID — потеря старшего байта (0A8h?)
> [bugs.txt:33]: «В БИОСе в функции STA_VID (возможно 0A8h) теряется старший байт параметра. В v2.12 функцию рекомендуется вызывать с учетом этого.»
Относится к BIOS v2.12. Не проверялось, исправлено ли в v3.00.
## 12.6 Несовместимость с реальным железом — только MAME
Многие перечисленные баги и квирки зафиксированы в документации, но не подтверждены на реальном Sprinter Sp2000. Все тесты тулчейна выполняются в MAME. Актуальность багов для реального железа неизвестна.
> [TODO.md]: «Проверка на реальном железе — в планах»
## 12.7 Кросс-ссылки
- BIOS v3.00: `02-bios.md`
- DSS/ESTEX: `03-dss.md`
- Акселератор: `06-accel.md`
- Fast RAM: `04-memory.md §4.6`
- Проектный TODO: `TODO.md`
- Проектный список багов: `converted/bugs.txt`
+169
View File
@@ -0,0 +1,169 @@
# 13. Информация из Telegram-чатов (Sp2022 и развитие Sprinter)
## 13.1 Источники
Данные извлечены из 319 HTML-файлов чатов Telegram, выгруженных из чата по Sprinter (n/w). Обработано 317 602 сообщения, отфильтровано технических — 72 307 (15 МБ текста).
Основные авторы технических сообщений: RomanRom2, KromosS, solegstar, nzeemin, holub.
## 13.2 BIOS 3.06 / DSS 1.71.57
KromosS (23 января 2026): «I am running the DSS 1.71.57 / Bios 3.06».
Зафиксированные версии BIOS:
- 3.05 — предыдущая стабильная
- 3.06 — текущая, 23.01.2026
- Прошивка ППЛМ и ROM собираются через Intel Quartus
BIOS 3.06 собрана из ROM-файла, загружаемого через загрузчик. Процесс сборки:
1. Конфигурация ППЛМ через Quartus
2. Сборка ROM-образа (IS28F020 — 256 КБ flash)
3. Программирование через специальный загрузчик
## 13.3 Эволюция аппаратных платформ
RomanRom2 (11 ноября 2025) подробно описал историю развития Sprinter в 10 пунктах:
| Этап | Платформа | Описание | Период |
|------|-----------|----------|--------|
| 1 | Sp2000 | Оригинальная плата, 8 DIP VRAM | 20002001 |
| 2 | Sp2000s | Баг в разводке ALTERA: ISA зеркалированы | ~2001 |
| 3 | Sp2000s Light | Баг фикс с MGTF, ISA распаяны не полностью | ~2002 |
| 4 | Sp2021s | Новая ревизия от solegstar | ~2021 |
| 5 | Sp2022s/d | Собственный дизайн (Zeal Hardware / RomanRom2) | 2022 |
| 6+ | Sp2024d/du | Планируется, с USB-контроллером | ~2024 |
### Детали:
**Sp2000 (оригинал)**
- Плата 2000–2001 года
- ПЗУ 256 КБ, VRAM 256 КБ (8 DIP-микросхем)
- ALTERA ACEX 1K EP1K30
**Sp2000s**
- ALTERA-баг: в оригинальной плате зеркально разведены ISA-слоты, на Sp2000s исправлено
- Новый баг разводки: ISA адреса «перевёрнуты» — при устанавке платы в слот слоты просто не видятся. В Sp2000s Light фикс с MGTF (соединительная плата), один ISA-слот не распаян
**Sp2022 (Zeal Hardware)**
- Новая разработка на современной элементной базе
- Варианты: Sp2022s (Sp2000 layout, SMD), Sp2022d (две платы, digitized)
- SMD-компоненты, технология 2022 года
- Расширенная память, улучшенное питание
- Sp2022du — вариант с USB-контроллером (планируется для Sp2024)
**Sp2024**
- Sp2024d — следующее поколение
- Sp2024du — с интегрированным USB для клавиатуры/мыши
- Планируется USB-контроллер
### Sp2022 — модификации
| Модификация | Описание |
|-------------|----------|
| sp2022s | SMD, layout аналогичен Sp2000 |
| sp2022d | Две платы (digitized), расширенная память |
| sp2022d-black | Чёрная текстолит |
| sp2022release | Готовая плата для пользователей |
| sp2022m | Мобильная версия (будущее) |
| sp2022i | ITX-формфактор |
| sp2022atx | ATX-формфактор |
| sp2022t | Новая ревизия |
| sp2022du | С USB-контроллером |
## 13.4 Изменения компонентов
### ПЗУ и загрузка
- ROM: IS28F020 (256 КБ Flash, 5V)
- Загрузка через Quartus → ROM-образ → загрузчик
- ROM-файлы обсуждаются в чате
### VRAM
- Оригинал Sp2000: CY7C109D-10VXI (5V, 128K×8)
- Sp2022: CY7C1019DV33-10VXI (3.3V, 128K×8)
- Переход на 3.3V логику
### Video-DAC
- Sp2022: обсуждаются TDA8772 (трипл 8-бит video-DAC) или ADV7120/ADV7125
- Некоторые платы используют ADV7125 (трипл 10-бит) ???
### CMOS
- DS12887A (оригинал)
- На Sp2022 — замена на современный аналог
### КЭШ-ОЗУ
- W24512 (64K×8) — для Sp2022
### SDRAM
- Оригинал: 72-pin SIMM
- Sp2022: SDRAM (DDR) на плате
## 13.5 Аппаратные баги
### Sp2000s — ALTERA routing bug
При переразводке Sp2000 под Sp2000s допущена ошибка в разводке ALTERA (ACEХ 1K). ISA-адреса оказались «зеркальными» — при установке платы в слот половинка линий данных перевёрнута, из-за чего слоты не видятся CPU. Исправлено на Sp2000s Light с помощью MGTF (мезонинная плата-переходник).
### Sp2000s Light — ISA unsoldered
На Sp2000s Light один ISA-слот не распаян, второй — через MGTF.
### IDE active short
В некоторых ревизиях — короткое замыкание на линиях IDE при активном доступе. Требует подтягивающих резисторов.
### FDISK CHS-LBA
Типовые проблемы с разметкой дисков — ошибки пересчёта CHS в LBA в утилитах FDISK для Sprinter.
## 13.6 MAME-эмуляция
- holub разрабатывает форк MAME для Sprinter
- Timing issues: Z80 Z84C15 эмулируется не полностью (внутренние PIO/SIO/CTC)
- Работа над корректной эмуляцией Sp2022
## 13.7 Статистика по платформам
| Платформа | Упоминаний | Период |
|-----------|-----------|--------|
| sp2000 | 243 | 20002001 |
| sp2022 | 122 | 20222024 |
| sp2022d | 66 | 20222024 |
| sp2000s | 44 | 20012002 |
| sp2022s | 43 | 20222024 |
| sp2024d | 6 | 2024+ |
| sp2024du | 4 | 2024+ (план) |
| sp2022i | 3 | 20222024 |
| sp2022m | 1 | будущее |
## 13.8 Компонентная статистика
| Компонент | Упоминаний |
|-----------|-----------|
| Z80 | 1317 |
| USB | 800 |
| BIOS v3.xx | 813 |
| MAME | 496 |
| DDR | 172 |
| ACEX | 147 |
| ALTERA | 115 |
| CY7C | 82 |
| Z84C15 | 87 |
| TDA1543 | 55 |
| SDRAM | 48 |
| IS28F020 | 30+ |
| Quartus | упоминается |
## 13.9 Противоречия с docs/new/
### BIOS v3.06 / DSS 1.71.57
Основные источники (BIOS_v3.txt, IvanMak.txt) документируют BIOS 3.00, не 3.06. Версия 3.06 обнаружена только в Telegram. DSS 1.71.57 значительно новее, чем 1.60 в документации.
### Sp2022 — новое железо
Вся документация в docs/converted/, part2/ и reference/ описывает Sp2000 (20002001). Sp2022 — полностью новая платформа с современной элементной базой (SMD, 3.3V VRAM, USB, SDRAM). Документация отсутствует.
### Состав BIOS
Неизвестно, какие функции из IvanMak.txt (HDD, RAM-disk, конфигурационные, портовые) реализованы в BIOS 3.06, а какие нет. Также неизвестно, исправлены ли баги (DRV_VERIFY, AY envelope).
## 13.10 Кросс-ссылки
- Аппаратная архитектура Sp2000: `01-architecture.md`
- BIOS v3.00: `02-bios.md`
- Проектный TODO: `TODO.md`
- Сырые данные: `docs/tg/_messages.jsonl`, `docs/tg/_technical.txt`
- Фильтр: `docs/tg/_filter.py`
+112
View File
@@ -0,0 +1,112 @@
# INDEX — сводный указатель документации Sp2000
## Документы
| № | Файл | Содержание |
|---|------|-----------|
| 01 | `01-architecture.md` | Общая архитектура: процессор, ППЛМ, конфигурации, обзор памяти/видео/акселератора/звука/ISA/клавиатуры/мыши/дисков/прерываний |
| 02 | `02-bios.md` | BIOS v3.00: вызовы (RST 8/18h, CALL 3D13h), полная таблица функций, видео/палитра/диск/принтер |
| 03 | `03-dss.md` | DSS/ESTEX v1.60: файловые функции, диски, память, консоль, коды ошибок |
| 04 | `04-memory.md` | Память: 4 окна, страницы, порты (#7FFD/#1FFD/#DFFD/#EFF7), EXE-формат, Fast RAM |
| 05 | `05-graphics.md` | Графика: VRAM, адресация (спектрумовская/графическая), видеорежимы, палитра, shadow RAM |
| 06 | `06-accel.md` | Акселератор: команды, примеры, скорость, прерывания |
| 07 | `07-irq.md` | Прерывания: IM1/IM2, INT, CTC, SIO, CBL, цепочка обработчиков |
| 08 | `08-io.md` | Ввод-вывод: FDD, HDD, CMOS, джойстик, принтер, ISA, карта портов |
| 09 | `09-input.md` | Клавиатура (BIOS/DSS/raw) и мышь (RST 30h): API, протоколы, прерывания |
| 10 | `10-sound.md` | Звук: AY-3-8910, COVOX, COVOX-Blaster (CBL), бипер, SSC |
| 11 | `11-ports.md` | Сводная карта портов: Z84C15, память, видео, диски, звук, конфигурация |
| 12 | `12-bugs.md` | Баги: DRV_VERIFY, AY envelope, акселератор+IRQ, Fast RAM+COVOX |
| 13 | `13-telegram.md` | Telegram-чаты: BIOS 3.06, эволюция Sp2000→Sp2022, Sp2022 варианты, Sp2024, аппаратные баги, MAME |
## Противоречия — сводка
### Критические (меняют ABI)
| Тема | Файл | Источники |
|------|------|-----------|
| SETWIN2: 39h vs 3Ah | `03-dss.md` | DiskSyscalls.txt vs ProgrammerManual.txt |
| EXCMDLN subfunc 5: смещения | `03-dss.md` | Все источники дают неверные DE+3/DE+4 |
### Средние
| Тема | Файл | Источники |
|------|------|-----------|
| WIN_RESTORE_WIN: C=0B2h (опечатка) | `02-bios.md` | BIOS_v3.txt vs IvanMak.txt |
| WIN_MOVE_WIN: C=0B2h (опечатка) | `02-bios.md` | IvanMak.txt vs BIOS_v3.txt |
| WIN_GET_SYM: A=0 обязательно? | `02-bios.md` | Parinov.txt vs BIOS_v3.txt |
| PIC_SET_PAL: битфилд vs номер | `02-bios.md` | BIOS_v3.txt vs IvanMak.txt |
| LP_PRINT_SYM: 082h=(131) неверно | `02-bios.md` | Ошибка десятичной аннотации |
| FN_VERSION: значения BC | `02-bios.md` | BIOS_v3.txt vs IvanMak.txt |
### Низкие
| Тема | Файл | Источники |
|------|------|-----------|
| CBL порт 8/16-бит | `10-sound.md` | IvanMak vs Parinov |
| CBL bit7 #FE: статус vs IRQ | `10-sound.md` | IvanMak vs Parinov |
| Адресация ВГ93: #7F data reg | `08-io.md` | IvanMak vs Parinov; MAME подтверждает IvanMak |
| HDD: R/W разные адреса | `08-io.md` | IvanMak vs Parinov; MAME использует единую карту DCP |
| Джойстик #1F vs #0F | `08-io.md` | IvanMak: ремап #1F#0F; MAME на Sp2000 отключает |
## Кросс-ссылки между документами
```
01-architecture.md ← 02-bios.md (BIOS call conventions)
← 04-memory.md (memory overview)
← 05-graphics.md (video overview)
← 06-accel.md (accel overview)
← 07-irq.md (interrupt overview)
← 08-io.md (disk, joystick, printer, ISA overview)
← 09-input.md (keyboard, mouse overview)
← 10-sound.md (sound overview)
← 11-ports.md (ISA ports)
02-bios.md ← 05-graphics.md (PIC_SET_PAL, SET_MODE)
← 11-ports.md
← 12-bugs.md (DRV_VERIFY)
03-dss.md ← 04-memory.md (SETWIN/SETWIN1/SETWIN2)
← 11-ports.md
← 12-bugs.md
04-memory.md ← 06-accel.md (Fast RAM conflict with accel)
← 11-ports.md
← 03-dss.md (window functions)
05-graphics.md ← 02-bios.md (PIC_SET_PAL, SETVMOD)
← 06-accel.md (accelerator for fast pixel ops)
← 10-sound.md (CBL for video)
← 11-ports.md (RGADR, RGMOD)
07-irq.md ← 10-sound.md (CBL interrupt sources)
← 11-ports.md
← 08-io.md (disk I/O interrupt sources)
← 09-input.md (keyboard, mouse interrupt sources)
08-io.md ← 02-bios.md (printer functions)
← 09-input.md (keyboard, mouse moved here)
← 10-sound.md
← 11-ports.md
← 07-irq.md (mouse IRQ)
11-ports.md → все документы
```
## Проектные документы (не входят в docs/new/)
| Файл | Связь |
|------|-------|
| `memory-management.md` | C-specific memory models (legacy, перекрывается `04-memory.md`) |
| `fast_ram.md` | Детальный анализ Fast RAM — уточняет `04-memory.md §4.6` |
| `file-buffering-design.md` | FILE* дизайн — уточняет `03-dss.md` |
| `im2_isr_design.md` | IM2/ISR дизайн — уточняет `07-irq.md` |
| `sprite-api-design.md` | Спрайтовое расширение BGI |
| `kbd-games.md` | Клавиатура в играх — уточняет `09-input.md §9.5` |
| `libc-reference.md` | API libc |
| `libc-roadmap.md` | План работ по libc |
| `libc-split-asm-cases.md` | Правила сплита asm |
| `libc-headers.md` | Стратегия заголовков |
| `accel-fill-budget.md` | Бюджет тактов акселератора |
| `TODO.md` | Roadmap проекта |
| `bugs/` | Баг-репорт SDCC z80 |