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:
@@ -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:224–229]).
|
||||
|
||||
### 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:855–858]: «Бит 1 номера означает выбор доступа к порту или памяти ISA, а бит 2 определяет к какому из двух слотов осуществляется доступ.»
|
||||
- Через управляющие порты [Parinov.txt:798–857]: (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:1385–1394]:
|
||||
```
|
||||
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
File diff suppressed because it is too large
Load Diff
+1082
File diff suppressed because it is too large
Load Diff
@@ -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`
|
||||
@@ -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:317–322].
|
||||
|
||||
---
|
||||
|
||||
## 5.2 Режимы адресации видео-ОЗУ
|
||||
|
||||
Видео-ОЗУ может адресоваться двумя способами — **спектрумовским** и
|
||||
**графическим** [IvanMak.txt:296–300]. Спектрумовский режим используется для
|
||||
Spectrum-совместимого вывода и загрузки знакогенераторов; графический — для
|
||||
всех остальных видеорежимов (320×256×256, 640×256×16, текст 80×32).
|
||||
|
||||
### 5.2.1 Спектрумовский режим адресации
|
||||
|
||||
В этом режиме VRAM разбивается на **32 блока по 8 КБ**. Адрес блока задаётся
|
||||
через порт `RGADR` (`PORT_Y`, `#89`):
|
||||
|
||||
| Бит | Назначение |
|
||||
|-----|-----------|
|
||||
| 4..0 | Номер блока (0..31) |
|
||||
| 5 | Не используется |
|
||||
| 6 | Запрет вывода (1 = отключить спектрумовский вывод) |
|
||||
| 7 | Разрешение 16-КБ страницы (1 = два блока в `#4000..#7FFF`) |
|
||||
|
||||
Бит 0 RGADR вместе с битом 1 порта `#7FFD` определяет чётность подключаемого
|
||||
блока VRAM: чётный RGADR → блок N в `#4000..#5FFF`, блок N+1 в `#C000..#DFFF`;
|
||||
нечётный → наоборот [IvanMak.txt:333–339].
|
||||
|
||||
Для записи в определённую пару спектрумовских блоков:
|
||||
1. Записать номер блока в `RGADR` (`OUT (#89),A`).
|
||||
2. Убедиться, что в окне (`#4000` или `#C000`) стоит подходящая страница
|
||||
основного ОЗУ (любая, кроме `#50..#5F`).
|
||||
3. Чтение/запись по спектрумовским адресам (`#4000..#5FFF`,
|
||||
`#C000..#DFFF`) попадает в VRAM через текущий блок.
|
||||
|
||||
**Выключение спектрумовского вывода:** Если программа не использует
|
||||
Spectrum-совместимую графику, `RGADR` рекомендуется установить в `#C0..#FF`
|
||||
(бит 6 = 1). В этом случае вывод в VRAM через спектрумовский режим не
|
||||
производится [IvanMak.txt:346–348].
|
||||
|
||||
### 5.2.2 Графический режим адресации
|
||||
|
||||
В графическом режиме видео-ОЗУ организовано как матрица **256 строк
|
||||
(rows) × 1024 байта** [IvanMak.txt:357–358]. Адресация:
|
||||
|
||||
```
|
||||
VRAM_адрес = (RGADR << 10) | (Z80_A[9:0])
|
||||
где RGADR[7:0] = Y (номер строки, 0..255)
|
||||
Z80_A[9:0] = X (смещение в строке, 0..1023)
|
||||
```
|
||||
|
||||
Страницы `#50..#5F` при маппинге в любое окно Z80 включают графическую
|
||||
адресацию. При этом младшие 4 бита номера страницы не влияют на адрес
|
||||
памяти, а задают подрежим вывода (§5.3).
|
||||
|
||||
**Важная особенность:** Z80-адрес внутри окна (биты A[13:10] для окна W3)
|
||||
**игнорируется** — весь 16-КБ диапазон окна отображает **одну и ту же
|
||||
строку**, выбранную `RGADR`. Доступ к другим строкам — только через смену
|
||||
`RGADR`. Это означает, что утверждение из SprinterGraphics programming.txt
|
||||
о доступе к строкам 18..31 через адреса `#C400..#FC00` **неверно**.
|
||||
|
||||
**Структура 1-КБ строки (1024 байта):**
|
||||
|
||||
| Смещение в строке | Назначение |
|
||||
|-------------------|-----------|
|
||||
| `#000..#13F` (0..319) | Экранная страница 0 (первые 320 байт) |
|
||||
| `#140..#27F` (320..639) | Экранная страница 1 (следующие 320 байт) |
|
||||
| `#280..#3FF` (640..1023) | Не используется / данные палитры |
|
||||
|
||||
Две экранные страницы (0 и 1) переключаются битом 0 порта `RGMOD` [IvanMak.txt:409].
|
||||
|
||||
**Работа с адресацией из программы:**
|
||||
|
||||
```asm
|
||||
; Установить страницу VRAM (0x50) в W3
|
||||
IN A, (#E2) ; сохранить текущую W3
|
||||
LD (old_page), A
|
||||
LD A, #50
|
||||
OUT (#E2), A ; W3 = VRAM страница 0x50
|
||||
|
||||
; Выбрать строку Y
|
||||
LD A, Y ; Y = 0..255
|
||||
OUT (#89), A ; RGADR = Y
|
||||
|
||||
; Чтение/запись пикселя (X,Y) для экранной страницы 0
|
||||
LD HL, #C000 + X ; X = 0..319
|
||||
LD (HL), colour ; запись байта пикселя
|
||||
|
||||
; Восстановить страницу
|
||||
LD A, (old_page)
|
||||
OUT (#E2), A
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5.3 Подрежимы вывода (страницы `#50..#5F`)
|
||||
|
||||
Биты 2 и 3 номера страницы (из диапазона `#50..#5F`) задают подрежимы вывода
|
||||
[IvanMak.txt:364–386]:
|
||||
|
||||
| Бит | Страницы | Эффект |
|
||||
|-----|----------|--------|
|
||||
| 3 | `#58..#5F` | **Прозрачный цвет** — запись байта `#FF` игнорируется (для спрайтов) |
|
||||
| 2 | `#54..#57`, `#5C..#5F` | **Без тени** — запись только в VRAM, не в основное ОЗУ (для курсора мыши) |
|
||||
|
||||
Биты 0 и 1 должны быть 0 для совместимости с будущими прошивками
|
||||
[IvanMak.txt:384–386].
|
||||
|
||||
---
|
||||
|
||||
## 5.4 Теневая память (Shadow RAM) и двойная запись
|
||||
|
||||
Видео-ОЗУ Спринтера является теневой памятью по отношению к основному ОЗУ
|
||||
[IvanMak.txt:317–322]. Видеоконтроллер **всегда** читает изображение из VRAM
|
||||
для вывода на экран; основное ОЗУ в формировании изображения не участвует.
|
||||
Однако при записи через графические банки `#50..#5F` поведение зависит от
|
||||
выбранного подрежима:
|
||||
|
||||
- **Банк `0x50` (normal):** запись идёт **одновременно** в VRAM и в
|
||||
соответствующую область основного ОЗУ. Чтение из того же Z80-адреса
|
||||
возвращает данные из основного ОЗУ, а не из VRAM — VRAM для процессора
|
||||
на чтение не видна.
|
||||
- **Банк `0x54` (noshadow):** запись — только в VRAM, основное ОЗУ не
|
||||
изменяется. Чтение — из основного ОЗУ (там хранится «фон»).
|
||||
- **Банк `0x58` (transparent):** как normal, но байт `#FF` не пишется.
|
||||
- **Банк `0x5C` (sprite):** transparent + noshadow.
|
||||
- **Обычные банки (не `#50..#5F`):** никакого доступа к VRAM нет,
|
||||
чтение/запись идут напрямую в основное ОЗУ.
|
||||
|
||||
**Зачем это нужно:**
|
||||
|
||||
1. **Восстановление после переключения видеорежима:** данные в основном ОЗУ
|
||||
остаются нетронутыми, так что при возврате в графический режим экран можно
|
||||
восстановить без перерисовки [IvanMak.txt:325].
|
||||
2. **Heal спрайтов** (libbgi): фон, на который был выведен спрайт в банке
|
||||
`GFX_BANK_SPRITE` (`0x5C`, без тени), остался в основном ОЗУ. После
|
||||
перемещения спрайта фон копируется из основного ОЗУ обратно в VRAM
|
||||
(операция heal), стирая спрайт.
|
||||
3. **Курсор мыши** без сохранения/восстановления: временный вывод через
|
||||
`GFX_BANK_NOSHADOW` (`0x5C`) — в основном ОЗУ данные под курсором не
|
||||
портятся, достаточно при следующем обновлении просто перерисовать фон.
|
||||
|
||||
**Режимы записи (см. §5.3):**
|
||||
|
||||
| Режим | Пишет в VRAM | Пишет в осн. ОЗУ | Применение |
|
||||
|-------|:---:|:---:|-----------|
|
||||
| `0x50` (normal) | Да | Да | Обычный вывод |
|
||||
| `0x54` (noshadow) | Да | **Нет** | временные эффекты |
|
||||
| `0x58` (transparent) | Да (кроме `#FF`) | Да | Спрайты с прозрачностью без heal |
|
||||
| `0x5C` (sprite) | Да (кроме `#FF`) | **Нет** | Курсор, спрайты (прозрачность + heal) |
|
||||
|
||||
---
|
||||
|
||||
## 5.5 Видеорежимы
|
||||
|
||||
Система поддерживает независимую установку режима для каждого квадратика
|
||||
8×8 (или 16×8 для 640-режимов) на экране [IvanMak.txt:405–469].
|
||||
|
||||
### Режимы вывода
|
||||
|
||||
| Режим | Разрешение | Цветов | Описание |
|
||||
|-------|-----------|--------|----------|
|
||||
| ZX-40 | 320×256 | 16 | Текстовый 40×32, Spectrum-совместимый |
|
||||
| ZX-80 | 640×256 | 16 | Текстовый 80×32, до 36 знакогенераторов |
|
||||
| GR-256-8 | 320×256 | 256 | Графический, 1 байт/пиксель |
|
||||
| GR-16-16 | 640×256 | 16 | Графический, 4 бита/пиксель |
|
||||
|
||||
### Формат пикселей
|
||||
|
||||
**GR-256-8 (320×256×256):** один байт = один пиксель. Строка содержит
|
||||
320 байт для экранной страницы 0 (смещения `#000..#13F`) и 320 байт для
|
||||
страницы 1 (`#140..#27F`). Полный экран: 320 × 256 = 81 920 байт на страницу.
|
||||
|
||||
**GR-16-16 (640×256×16):** один байт = два пикселя: младший полубайт —
|
||||
левый/первый пиксель, старший — правый/второй. Строка содержит 320 байт на
|
||||
экранную страницу, что даёт 640 пикселей (320 × 2). Структура строки та же:
|
||||
320 байт на страницу 0, 320 на страницу 1.
|
||||
|
||||
### Установка режима
|
||||
|
||||
Режим задаётся 4 байтами `Mode0..Mode3` в области режимов VRAM
|
||||
(`#0300..#039F`). Полное описание формата Modei — [IvanMak.txt:448–469].
|
||||
|
||||
Для переключения видеорежима из программ используется функция DSS `SETVMOD`
|
||||
(50h) [DiskSyscalls.txt:345–349]:
|
||||
|
||||
| A (режим) | Описание |
|
||||
|-----------|----------|
|
||||
| 02h | Текстовый 40×32×16 |
|
||||
| 03h | Текстовый 80×32×16 |
|
||||
| 81h | Графический 320×256×256 |
|
||||
| 82h | Графический 640×256×16 |
|
||||
|
||||
B — страница экрана (0/1). Вызов: `RST 10h` с C=50h. Флаг C = ошибка
|
||||
(например, режим не поддерживается данным монитором).
|
||||
|
||||
---
|
||||
|
||||
## 5.6 Палитра
|
||||
|
||||
8 палитр по 256 цветов, каждая занимает 1 КБ в VRAM по адресам
|
||||
`#03E0..#03FE` [IvanMak.txt:540–568].
|
||||
|
||||
| Адреса | Палитра | Назначение |
|
||||
|--------|---------|-----------|
|
||||
| `#03E0..#03E2` | Граф. 0 | Графические режимы |
|
||||
| `#03E4..#03E6` | Граф. 1 | —//— |
|
||||
| `#03E8..#03EA` | Граф. 2 | —//— |
|
||||
| `#03EC..#03EE` | Граф. 3 | —//— |
|
||||
| `#03F0..#03F2` | Текст. 4 | Цвет бумаги |
|
||||
| `#03F4..#03F6` | Текст. 5 | Цвет символа |
|
||||
| `#03F8..#03FA` | Текст. 6 | Цвет мерцания бумаги |
|
||||
| `#03FC..#03FE` | Текст. 7 | Цвет мерцания символа |
|
||||
|
||||
Каждый четвёртый байт в каждой палитре не используется — не может попасть
|
||||
на ЦАП [IvanMak.txt:545–547]. Выбор палитры для каждого квадратика — через
|
||||
биты 7..6 байта Mode1 [BIOS_v3.txt:348].
|
||||
|
||||
> **Примечание:** Architecture.txt упоминает всего 5 палитр (4 графические +
|
||||
> 1 текстовая), но IvanMak описывает все 8: 4 графические (0–3) и 4 текстовые
|
||||
> (4–7: бумага, символ, мерцание бумаги, мерцание символа)
|
||||
> [IvanMak.txt:547–548, 561–568].
|
||||
|
||||
---
|
||||
|
||||
## 5.7 Структура VRAM в терминах BIOS
|
||||
|
||||
При использовании BIOS распределение VRAM [IvanMak.txt:387–404]:
|
||||
|
||||
| Адреса (линии) | Назначение |
|
||||
|----------------|-----------|
|
||||
| `#0000..#003F` | Спектрумовский экран (блоки 0..1) |
|
||||
| `#0040..#017F` | Первый графический экран (блоки 2..11) |
|
||||
| `#0180..#02BF` | Второй графический экран (блоки 12..21) |
|
||||
| `#02C0..#02FF` | Знакогенераторы текстового режима |
|
||||
| `#0300..#039F` | Область описания режимов экрана |
|
||||
| `#03A0..#03DF` | Зарезервировано |
|
||||
| `#03E0..#03FF` | Палитра |
|
||||
|
||||
---
|
||||
|
||||
## 5.8 Заблуждения и неподтверждённое
|
||||
|
||||
**Миф о строках 18–31:** В документе SprinterGraphics programming.txt
|
||||
утверждается, что после выбора строки Y через RGADR, по адресам
|
||||
`#C400..#FC00` доступны строки Y+1..Y+15 (с шагом 1 КБ). В эмуляторе MAME
|
||||
это **не работает** — весь 16-КБ диапазон страницы `#50..#5F` отображает
|
||||
только строку Y, независимо от бит A[13:10] адреса Z80. Требуется проверка
|
||||
на реальном Sprinter Sp2000.
|
||||
|
||||
---
|
||||
|
||||
## 5.9 Кросс-ссылки
|
||||
|
||||
- Палитра и видеорежимы BIOS: `02-bios.md §2.7`
|
||||
- SETVMOD (DSS): `03-dss.md §3.10`
|
||||
- Акселератор: `06-accel.md`
|
||||
- Быстрое ОЗУ и конфликт с акселератором: `04-memory.md §4.6`
|
||||
- Порты RGADR/RGMOD: `11-ports.md`
|
||||
- Баги акселератора: `12-bugs.md`
|
||||
- Проектные документы: `sprite-api-design.md`, `accel-fill-budget.md`
|
||||
@@ -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:810–848].
|
||||
|
||||
| Инструкция | Код | Действие |
|
||||
|-----------|:---:|----------|
|
||||
| `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:822–823], [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:840–843]:
|
||||
|
||||
```
|
||||
Время ≈ время команды без акселератора + число_байт / 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:844–846].
|
||||
|
||||
**Новая прошивка:** акселератор может работать с EI. По приходу прерывания
|
||||
он отключается, а по `RETI` включается обратно [IvanMak.txt:846–848].
|
||||
Использовать этот режим следует с осторожностью — без проверки на реальном
|
||||
железе неизвестно, какая версия прошивки установлена.
|
||||
|
||||
---
|
||||
|
||||
## 6.7 Кросс-ссылки
|
||||
|
||||
- Баги акселератора: `12-bugs.md`
|
||||
- Использование акселератора в libbgi: `sprite-api-design.md`
|
||||
- Ограничение скорости: `accel-fill-budget.md`
|
||||
- Fast RAM и конфликт с портом CBL: `04-memory.md §4.6`
|
||||
@@ -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:1469–1473 |
|
||||
| IM1 | Используется DSS для своих обработчиков | — |
|
||||
| IM1 | Fast-RAM секция предполагает обработчик по `#0038` | Parinov.txt:601 |
|
||||
| IM2 | Рекомендован при выставленных прерываниях от CBL | Parinov.txt:762–763 |
|
||||
|
||||
> **Примечание:** разные подсистемы рекомендуют разные режимы. IM2 предпочтителен при интенсивной работе с прерываниями (CBL, BIOS). IM1 используется DSS по умолчанию.
|
||||
|
||||
## 7.2 Кадровые прерывания (INT)
|
||||
|
||||
Генерируются в момент прохождения 8-й строки квадратика (настраивается через бит 0 порта `#FE`). Положение INT подстраивается под стандарт Pentagon (320 строк) или Scorpion (312 строк).
|
||||
|
||||
> **Мышь — есть ли аппаратные прерывания?** [Parinov.txt:956] утверждает: «От мыши прерывания не приходят. Сделать можно, но сейчас их нет.» [ProgrammerManual.txt:1784–1786] описывает драйвер мыши, где «каждое нажатие и отпускание клавиш или перемещение мыши вызывает прерывание», и документирует функцию «80h MOUSE HARDWARE INTERRUPT» [ProgrammerManual.txt:1930–1937]. 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:844–846, Parinov.txt:954 |
|
||||
| Новый | EI/RETI: по INT акселератор отключается, по RETI включается | IvanMak.txt:846–848 |
|
||||
|
||||
> **Примечание:** 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`
|
||||
@@ -0,0 +1,197 @@
|
||||
# 8. Ввод-вывод
|
||||
|
||||
## 8.1 Клавиатура и мышь
|
||||
|
||||
Клавиатура и мышь вынесены в отдельный документ: `09-input.md`.
|
||||
|
||||
Сводная информация по портам и прерываниям — `09-input.md §§9.1–9.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:1270–1274]: 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:914–920]
|
||||
|
||||
### 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:958–972].
|
||||
|
||||
**Противоречие: HDD — разные адреса для чтения и записи.**
|
||||
> - [IvanMak.txt:1366]: кратко: «#xx50..#xx55 – порты HDD»
|
||||
> - [Parinov.txt:958–959]: таблица с разными адресами для 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-коды 0x1c–0x1e.
|
||||
|
||||
| Z80-адрес | DCP код | Функция |
|
||||
|-----------|---------|---------|
|
||||
| `#DFBD` | 0x1d | Запись адреса регистра CMOS |
|
||||
| `#FFBD` | 0x1c | Чтение данных из выбранного регистра |
|
||||
| `#BFBD` | 0x1e | Запись данных в выбранный регистр |
|
||||
|
||||
При отсутствии микросхемы CMOS эмулируется BIOS [BIOS_v3.txt:308–310].
|
||||
|
||||
**Карта регистров 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) | биты (чт) |
|
||||
| 0x0e–0x7f | 114 байт NV RAM | пользовательские |
|
||||
|
||||
---
|
||||
|
||||
## 8.4 Джойстик
|
||||
|
||||
**Два Kempston-совместимых джойстика** [sprinter.cpp:1106–1175]:
|
||||
|
||||
- **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:861–868]: команды `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:1136–1140].
|
||||
|
||||
---
|
||||
|
||||
## 8.5 Параллельный порт (принтер)
|
||||
|
||||
Centronics-совместимый через ППЛМ. BIOS-функции печати: 082h–08Ch
|
||||
(см. `02-bios.md`).
|
||||
|
||||
---
|
||||
|
||||
## 8.6 Шина ISA
|
||||
|
||||
Два 8-битных ISA-слота на частоте X_SP/5 (~7 МГц). Доступ — через
|
||||
DCP-декодер и страницы памяти.
|
||||
|
||||
**Управляющие порты ISA (DCP 0xD0–0xDF, 0xF8–0xFF):**
|
||||
|
||||
| Бит | Назначение |
|
||||
|:---:|-----------|
|
||||
| 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:1032–1039].
|
||||
|
||||
**Memory-маппинг ISA:** При pg3 & 0xF9 == 0xD0 (бит 10 окна W3 = 1,
|
||||
BANK_ISA_MASK) обращения к окну W3 (`#C000–#FFFF`) направляются на ISA-шину
|
||||
вместо RAM [sprinter.cpp:178–181, 530–532]. Длина — 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`
|
||||
@@ -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=30h–37h [DiskSyscalls.txt:30h–37h].
|
||||
|
||||
**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`
|
||||
@@ -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:632–634].
|
||||
|
||||
**На Sp2000 все три компонента присутствуют в основной прошивке ППЛМ.**
|
||||
CBL включается через порт `#4E` (бит 7 = 1). При выключенном CBL (бит 7 = 0)
|
||||
работает обычный 8-bit COVOX [IvanMak.txt:662–666].
|
||||
|
||||
## 10.2 GM80C760 (AY-3-8910)
|
||||
|
||||
### 10.2.1 Реализация
|
||||
|
||||
AY-функция реализована на микросхеме **GM80C760** (ППЛМ ALTERA EP1K30),
|
||||
AY-3-8910/8912 совместимая. Это не отдельная дискретная микросхема
|
||||
[IvanMak.txt:636–637].
|
||||
|
||||
На EP1K30 (Sp2000) реализована **3-я версия** AY. Включает три голоса,
|
||||
шум и генератор огибающей (envelope). В формирователе огибающей обнаружена
|
||||
небольшая ошибка, детали не документированы [IvanMak.txt:224–229],
|
||||
[12-bugs.md §11.2].
|
||||
|
||||
### 10.2.2 Порты
|
||||
|
||||
| Порт | Назначение |
|
||||
|------|-----------|
|
||||
| `#BFFD` | AY-8910 — запись номера регистра (address) |
|
||||
| `#FFFD` | AY-8910 — чтение/запись данных регистра (data) |
|
||||
|
||||
Внутренние номера в карте дешифратора ППЛМ: `90h` (`#BFFD`), `91h` (`#FFFD`)
|
||||
[IvanMak.txt:1298–1299].
|
||||
|
||||
### 10.2.3 Программирование
|
||||
|
||||
Программирование — **стандартное для AY-3-8910/8912**
|
||||
[IvanMak.txt:636–637]:
|
||||
|
||||
```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:850–851], [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:692–693].
|
||||
|
||||
> **Примечание:** IvanMak.txt упоминает его как 8-битный, но Parinov.txt явно
|
||||
> указывает 16-битный доступ. Современный код использует `OUT (C),A`.
|
||||
|
||||
**Биты порта `#4E`** [Parinov.txt:695–698]:
|
||||
|
||||
| Бит | Мнемоника | Назначение |
|
||||
|-----|-----------|-----------|
|
||||
| 7 | **CBL_ON** | 1 = CBL включён, 0 = обычный COVOX |
|
||||
| 6 | **STEREO** | 1 = стерео, 0 = моно |
|
||||
| 5 | **16BIT** | 1 = 16-битные сэмплы, 0 = 8-битные |
|
||||
| 4 | **IRQ_EN** | 1 = включить прерывания от CBL |
|
||||
| 3–0 | **FREQ** | Частота дискретизации (см. таблицу) |
|
||||
|
||||
### 10.4.3 Частоты дискретизации
|
||||
|
||||
[Parinov.txt:700–718]:
|
||||
|
||||
| Код | Частота | Примечание |
|
||||
|:---:|---------|-----------|
|
||||
| 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:767–783]:
|
||||
|
||||
| Режим | Нулевой уровень | Размер блока | Формат данных |
|
||||
|-------|:---------------:|:------------:|--------------|
|
||||
| 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:758–760]:
|
||||
|
||||
- Счётчик 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:720–724]:
|
||||
|
||||
| Бит | Назначение |
|
||||
|-----|-----------|
|
||||
| 7 | **CBL data request** — 1 = CBL запрашивает новую порцию данных |
|
||||
| 5 | **Frame sync** — кадровый импульс (4 мс длиной, 20 мс период) |
|
||||
|
||||
> **Примечание:** В MAME при выключенном CBL бит 7 порта #FE всегда = 1.
|
||||
> Это следует учитывать при разработке обработчика прерываний
|
||||
> [`im2_isr_design.md:26–31`].
|
||||
|
||||
**Противоречие** [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:762–764].
|
||||
- **Вектор прерывания CBL — `#FF`** (как и у клавиатуры, и у кадрового).
|
||||
Отличать — по биту 7 порта `#FE` [`sprinterIntLib.asm:24–26`].
|
||||
|
||||
**Обработчик прерываний на 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:727–731].
|
||||
|
||||
```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:270–277`].
|
||||
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:639–640].
|
||||
|
||||
```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:763–772].
|
||||
|
||||
Параметры проекта:
|
||||
- 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`
|
||||
@@ -0,0 +1,103 @@
|
||||
# 11. Карта портов
|
||||
|
||||
## 11.1 Системные порты Z84C15 (внутренние)
|
||||
|
||||
Эти адреса изменить невозможно — находятся вне ППЛМ [IvanMak.txt:869–870].
|
||||
|
||||
| Порт | Назначение | Доступ |
|
||||
|------|-----------|--------|
|
||||
| `#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 (0–2), RAM/ROM select, lock | IvanMak.txt:1343 |
|
||||
| `#1FFD` | Расширенный: W0 page (0–2), 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`
|
||||
@@ -0,0 +1,54 @@
|
||||
# 12. Баги BIOS, DSS и железа Sp2000
|
||||
|
||||
## 12.1 DRV_VERIFY (54h) не существует
|
||||
|
||||
Функция `54h DRV_VERIFY` описана во всей документации BIOS, но в реальности отсутствует — всегда возвращает CF=1.
|
||||
|
||||
> [bugs.txt:58–59]: «Нет биосной функции "54h" (DRV_VERIFY) верификации секторов, описанной в документации. Поэтому она всегда возвращает установленный флаг "Carry".»
|
||||
|
||||
Источники, содержащие описание несуществующей функции:
|
||||
- [BIOS_v3.txt:258–261]
|
||||
- [IvanMak.txt:2198–2210]
|
||||
|
||||
## 12.2 AY-3-8910 — ошибка в формирователе огибающей
|
||||
|
||||
Третья версия AY в ППЛМ Sp2000 содержит ошибку в схеме формирователя огибающей (envelope generator). Детали не документированы.
|
||||
|
||||
> [IvanMak.txt:224–229]: «Третья версия схемы AY ... включает в себя ... генератор огибающей. ... В схеме формирователя огибающей обнаружена небольшая ошибка. ... В следующей версии AY предполагается данный недостаток исключить.»
|
||||
|
||||
## 12.3 Акселератор — конфликт с прерываниями
|
||||
|
||||
При работе акселератора система команд Z80 сильно меняется, что может приводить к сбоям в обработчиках прерываний.
|
||||
|
||||
> [IvanMak.txt:844–846]: «Отключение прерываний во время работы акселератора необходимо, так как в этот момент сильно меняется система команд процессора и программа на прерывании не сможет работать нормально.»
|
||||
|
||||
Новая прошивка акселератора позволяет работать с прерываниями — при приходе INT акселератор отключается и включается обратно по RETI [IvanMak.txt:846–848]. Без тестирования на реальном железе неизвестно, какая версия прошивки установлена.
|
||||
|
||||
## 12.4 Быстрое ОЗУ — конфликт с COVOX
|
||||
|
||||
Порт `#FB` используется как для включения КЭШ-ОЗУ (IN), так и для вывода данных в COVOX (OUT). Если КЭШ-ОЗУ включено, запись в COVOX может давать неожиданные результаты.
|
||||
|
||||
> [IvanMak.txt:850–851, 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`
|
||||
@@ -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 | 2000–2001 |
|
||||
| 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 | 2000–2001 |
|
||||
| sp2022 | 122 | 2022–2024 |
|
||||
| sp2022d | 66 | 2022–2024 |
|
||||
| sp2000s | 44 | 2001–2002 |
|
||||
| sp2022s | 43 | 2022–2024 |
|
||||
| sp2024d | 6 | 2024+ |
|
||||
| sp2024du | 4 | 2024+ (план) |
|
||||
| sp2022i | 3 | 2022–2024 |
|
||||
| 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 (2000–2001). 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`
|
||||
@@ -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 |
|
||||
Reference in New Issue
Block a user