64ce6339eb
- 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>
378 lines
16 KiB
Markdown
378 lines
16 KiB
Markdown
# 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`
|