Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ecf5ecfc14 | |||
| 4cffbc9aa4 | |||
| 24bb724c22 | |||
| eef6eebd8c | |||
| 3de8c7500c | |||
| 8e33cd07bc | |||
| a5773ab654 | |||
| 68b8fe5851 | |||
| 64ce6339eb |
@@ -113,3 +113,10 @@ mame/
|
|||||||
|
|
||||||
# Claude Code local settings (per-machine, not for the repo)
|
# Claude Code local settings (per-machine, not for the repo)
|
||||||
.claude/
|
.claude/
|
||||||
|
|
||||||
|
# Тяжёлые справочные материалы, НЕ версионируются: docs/extra — архивы
|
||||||
|
# исходников (~570 МБ, четыре почти одинаковых bad_apple), docs/sources —
|
||||||
|
# клоны чужих репозиториев (Sprinter-BIOS, Estex-DSS, SaymanNsk) со своими
|
||||||
|
# .git внутри (в коммите стали бы битыми gitlink-ссылками).
|
||||||
|
docs/extra/
|
||||||
|
docs/sources/
|
||||||
|
|||||||
@@ -0,0 +1,370 @@
|
|||||||
|
# roomtest — план v2: размер кода и раскладка по окнам/банкам/страницам
|
||||||
|
|
||||||
|
Статус: **план для отдельной сессии**, составлен 2026-07-29 по свежему замеру.
|
||||||
|
Заменяет `size_optimization_plan.md` (v1, 2026-07-21): часть его пунктов уже
|
||||||
|
сделана, часть опиралась на неверную модель банкинга. Документ самодостаточный
|
||||||
|
— рассчитан на старт с пустого контекста.
|
||||||
|
|
||||||
|
Повод: перед стражами и боёвкой (новый код ~5–8 КБ) надо понять, куда он
|
||||||
|
поместится, и заранее развести код так, чтобы банкованные модули не упёрлись в
|
||||||
|
ограничения окна W3.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Что уже сделано из v1 (не повторять)
|
||||||
|
|
||||||
|
- `--opt-code-size` и `--max-allocs 100000` **уже включены по умолчанию** в
|
||||||
|
`bin/sprinter-cc` (v1 §2.1 закрыт, выигрыш получен).
|
||||||
|
- Лишние блиты переднего слоя убраны (v1 §7 п.0): `fore_tile` больше не рисует
|
||||||
|
`bottom_id`, `_CODE` −388 Б.
|
||||||
|
- `gfx_blit_noclip` в libbgi (v1 §8 шаг 1): фоновые блиты в 2.9× дешевле.
|
||||||
|
- `--w3` как резидент окна 3 реализован и обкатан (memory `w3_resident_code`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. ЗАМЕР (сборка 2026-07-29, коммит 1214785)
|
||||||
|
|
||||||
|
Команда: `--memory small --gfx 256 --w3 pop_trob.c pop_map.c --w3 pop_bg.c`.
|
||||||
|
|
||||||
|
### 1.1 Окна
|
||||||
|
|
||||||
|
| Область | Занято | Свободно | Примечание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| W1+W2 `_CODE` | 24 881 Б | — | 0x4100…0xA231 |
|
||||||
|
| W1+W2 `_HOME`+`_GSINIT`+`_DATA`+`_BSS` | ~4 240 Б | — | до 0xB2E4 |
|
||||||
|
| **W1+W2 куча** | 0 (никто не malloc'ит) | **2 076 Б** | 0xB2E4…0xBB00 |
|
||||||
|
| W1+W2 стек | — | 1 279 Б | 0xBB00…0xBFFE |
|
||||||
|
| **W3 резидент** | 14 376 Б | **2 008 Б** | 0xC000…0xF828 |
|
||||||
|
| EMM-страницы | 37 атласов + 1 уровень | ~215 страниц свободно | `sprinter_emm_budget` |
|
||||||
|
|
||||||
|
**Итого запаса до стены: ≈ 4 КБ** (2 КБ в W1/W2 + 2 КБ в W3). Стражи туда
|
||||||
|
не влезут.
|
||||||
|
|
||||||
|
### 1.2 Код по модулям (точно, из `.rel`)
|
||||||
|
|
||||||
|
```
|
||||||
|
W1/W2 (_CODE 24 881): W3 резидент (_W3CODE 14 376):
|
||||||
|
pop_kid 6 963 pop_bg 11 643
|
||||||
|
pop_map 6 157 pop_trob 2 733
|
||||||
|
roomtest 2 583
|
||||||
|
pop_level 1 425
|
||||||
|
pop_ctrl 1 145
|
||||||
|
crt0 333
|
||||||
|
libc+libbgi ~6 275
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.3 Крупнейшие функции/данные (из `.lst`)
|
||||||
|
|
||||||
|
```
|
||||||
|
pop_bg : draw_tile 3080, other_overlay_tile 1146, wall_pattern 944,
|
||||||
|
mob_render 720, mob_tick_one 661, overlay_mid_tile 498,
|
||||||
|
fore_only_tile 409, climb_overlay_tile 391, tile_table 371
|
||||||
|
pop_map : check_loose_fall_on_kid 674, check_bumped 567, jump_up_or_grab 413,
|
||||||
|
get_tile 266, do_knock 243, check_press 238, check_leave 212
|
||||||
|
pop_kid : kid_seqtbl 2310 + kid_frames 1205 + kid_seq_off 230 = 3745 Б ДАННЫХ
|
||||||
|
(в _CODE!), собственно кода ~3.2 КБ
|
||||||
|
roomtest : enter_room+main ~2.1 КБ
|
||||||
|
pop_level: room_bg_ptr 1084 (+ 515 Б таблиц LINKLOC/LINKMAP в _DATA)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.4 `_DATA` (3 710 Б)
|
||||||
|
|
||||||
|
```
|
||||||
|
pop_trob 963 (room_modif[24][30] = 720 + trobs + rest-массивы)
|
||||||
|
pop_level 515 (копии LINKLOC/LINKMAP уровня)
|
||||||
|
pop_map 163, roomtest 141, pop_kid 130, pop_bg 115, pop_ctrl 13
|
||||||
|
libc: _irq_state 818, _kbdraw_state 515, _gfx_pal_buf 256, прочее ~200
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.5 Находки замера (мелкие, но чинить)
|
||||||
|
|
||||||
|
1. **`--w3` берёт ОДИН файл на флаг.** В `Makefile` написано
|
||||||
|
`--w3 pop_trob.c pop_map.c --w3 pop_bg.c`, и это значит «W3 = pop_trob и
|
||||||
|
pop_bg», а `pop_map.c` компилируется как обычный исходник в W1/W2. Судя по
|
||||||
|
`.sprinter-cc-roomtest/w3_pop_map.rel` (устаревший артефакт), когда-то
|
||||||
|
pop_map был в W3. **Решить осознанно** (см. §4) и записать явно:
|
||||||
|
`--w3 pop_trob.c --w3 pop_bg.c`.
|
||||||
|
2. `libc` тянет `_irq_state` 818 Б + `_kbdraw_state` 515 Б в `_DATA`.
|
||||||
|
`__irq_vec_buf` (513 Б) — таблица векторов IM2; `__kbdraw_down` (512 Б) —
|
||||||
|
битмап клавиш на 512 скан-кодов. Оба можно ужать (см. §5.4), это ~0.7 КБ
|
||||||
|
в самом дефицитном окне.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. ПРАВИЛА ПЛАТФОРМЫ, ОТ КОТОРЫХ ПЛЯШЕТ РАСКЛАДКА
|
||||||
|
|
||||||
|
Это главное, что изменилось по сравнению с v1: модель банкинга уточнена по
|
||||||
|
`bin/sprinter-cc` (справка `--w3`/`--bank`) и по коду libbgi.
|
||||||
|
|
||||||
|
**(R1) Резидент W3 (`--w3`) и банки W3 (`--bank`) делят одно окно.**
|
||||||
|
Резидент лежит на своей странице 0xC000…0xFFFF; трамплин на время вызова
|
||||||
|
`__banked` подменяет страницу W3 на банковую и возвращает резидентную назад.
|
||||||
|
|
||||||
|
**(R2) Из банка резидент W3 НЕДОСТИЖИМ — и транзитивно тоже.**
|
||||||
|
Пока исполняется банк, резидентной страницы в адресном пространстве нет.
|
||||||
|
Значит нельзя не только `bank → pop_bg()`, но и `bank → pop_map() → pop_bg()`.
|
||||||
|
**Это ключевое ограничение при выборе, что делать банком.**
|
||||||
|
|
||||||
|
**(R3) Резидент → банк работает** (через трамплин в W1), резидент → W1/W2 —
|
||||||
|
тоже.
|
||||||
|
|
||||||
|
**(R4) Графические примитивы libbgi звать можно откуда угодно.**
|
||||||
|
`_bgi_begin` читает текущую страницу W3 из порта 0xE2, а `_bgi_end` её
|
||||||
|
возвращает — то есть скобка корректна и из банка, и из резидента. Нельзя
|
||||||
|
только одно: **звать `_bgi_begin`/`_bgi_end` ИЗ кода, который сам лежит в W3**
|
||||||
|
(после подмены страницы исчезнет исполняемый код — проверено, белый экран).
|
||||||
|
Поэтому `pop_bg` (резидент W3) обязан пользоваться готовыми примитивами
|
||||||
|
(`gfx_blit*`, `bar`, …), а батчинг скобки на весь `draw_tile` (v1 §8 шаг 1)
|
||||||
|
для него **невозможен** без переноса самого `draw_tile` в W1/W2.
|
||||||
|
|
||||||
|
**(R5) `--w3` кладёт в W3 код И rodata модуля** (`--codeseg/--constseg
|
||||||
|
W3CODE`), а писучие статики оставляет в `_DATA` (W2). То есть `const`-таблицы
|
||||||
|
переносятся в W3 бесплатно вместе с модулем (так уже лежит `tile_table` 371 Б).
|
||||||
|
|
||||||
|
**(R6) Данные в EMM-странице читаются, только пока страница в окне.**
|
||||||
|
`gfx_w0_map(page)` / `gfx_w0_unmap()` — окно W0 (0x0000…0x3FFF), первые 0x100
|
||||||
|
занимает ISR-стаб. Так уже работает `pop_level`. Цена — пара `OUT` на
|
||||||
|
маппинг, поэтому годится для «пачками», а не для чтения по байту в горячем
|
||||||
|
цикле.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. ЧТО ДЕЛАТЬ НЕЛЬЗЯ (анти-паттерны, чтобы не потерять время)
|
||||||
|
|
||||||
|
- **Нельзя банковать `pop_bg`.** Он вызывается из pop_map, pop_trob, roomtest,
|
||||||
|
pop_kid — то есть из главного цикла на каждом кадре; плюс он сам держит
|
||||||
|
`tile_table` и всю отрисовку. Банк дал бы трамплин на каждый блит.
|
||||||
|
- **Нельзя банковать `pop_map`, пока `pop_map` зовёт `pop_bg`** (R2). Сейчас
|
||||||
|
зовёт: `pop_loose_tick` и компания (~30 вызовов графики).
|
||||||
|
- **Нельзя тащить `kid_frames` в EMM «в лоб»**: он читается несколько раз за
|
||||||
|
кадр из коллизии (`kid_cur_dx`/`kid_cur_flags` → `dx_weight`,
|
||||||
|
`char_x_forward_edge`, …). Нужен кэш кадра (см. §5.1) — иначе маппинг
|
||||||
|
страницы окажется в горячем пути.
|
||||||
|
- **Нельзя «причёсывать» семейство `draw_tile` ради экономии, не имея
|
||||||
|
пиксельного теста.** Мы неделю выравнивали слои по SDLPoP; любой рефактор
|
||||||
|
этой зоны проверять диффом страниц (заморозка кадра клавишей `1` + сравнение
|
||||||
|
VRAM обеих страниц, приём из memory `mame_mcp_bridge`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. ЦЕЛЕВАЯ РАСКЛАДКА
|
||||||
|
|
||||||
|
Принцип: **W3-резидент = «толстая графика, которую зовёт только главный цикл»;
|
||||||
|
W1/W2 = ядро, которое должно быть достижимо ОТОВСЮДУ (включая банки); банки =
|
||||||
|
новая холодная логика (стражи, боёвка, будущие уровни)**.
|
||||||
|
|
||||||
|
```
|
||||||
|
W1/W2 (всегда отображено) W3 резидент (стр. 0xC000) Банки W3
|
||||||
|
────────────────────────── ───────────────────────── ─────────
|
||||||
|
libc + libbgi pop_bg (отрисовка тайлов) guards.c
|
||||||
|
pop_kid (интерпретатор+рисование) pop_trob (анимации тайлов) fight.c
|
||||||
|
pop_map (коллизия/физика/предметы) pop_loose.c (loose+потолок) debug/roomnav
|
||||||
|
pop_geom (общая геометрия/тайлы) enter_room-часть roomtest?
|
||||||
|
pop_ctrl (ввод/диспетчер)
|
||||||
|
roomtest (главный цикл)
|
||||||
|
```
|
||||||
|
|
||||||
|
Почему так:
|
||||||
|
|
||||||
|
- **`pop_map` остаётся в W1/W2** — его зовут и главный цикл, и (в будущем)
|
||||||
|
банк стражей; в W3 его класть нельзя именно из-за R2. Для этого из него надо
|
||||||
|
вынести графическую часть (loose/потолок) — она уезжает в W3 к `pop_bg`
|
||||||
|
(§5.3). После выноса `pop_map` становится **чистой логикой без единого
|
||||||
|
вызова графики** — тот самый bank-safe API.
|
||||||
|
- **`pop_kid` остаётся в W1/W2**: `play_seq`/`kid_set_seq`/`Kid` нужны и
|
||||||
|
стражам (у стражей ТА ЖЕ seqtbl), а `kid_draw` зовёт только libbgi (R4).
|
||||||
|
- **`pop_trob` остаётся резидентом**: его зовёт только главный цикл, и он сам
|
||||||
|
зовёт `pop_bg` — идеальный житель W3.
|
||||||
|
- **Банк стражей не зовёт ничего из W3.** Рисование стражей — либо через
|
||||||
|
libbgi напрямую (R4), либо (лучше) резидентный `guard_draw()` в W1/W2 рядом
|
||||||
|
с `kid_draw`, а банк только считает состояние. Тот же приём мы уже
|
||||||
|
используем для `pop_item_taken`/`pop_loose_fell`/`pop_ceil_fell`: банк
|
||||||
|
выставляет флаг — резидент рисует.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. ПЛАН РАБОТ
|
||||||
|
|
||||||
|
Порядок выбран так, чтобы каждый шаг был проверяем отдельно и давал место
|
||||||
|
следующему.
|
||||||
|
|
||||||
|
### Шаг 1. `kid_data.h` (3 745 Б) → EMM-страница + порт `load_frame` — **самый большой выигрыш**
|
||||||
|
|
||||||
|
Сейчас `kid_seqtbl` (2310) + `kid_frames` (1205) + `kid_seq_off` (230) лежат в
|
||||||
|
`_CODE` окна W1/W2 — это 15 % всего дефицитного пространства.
|
||||||
|
|
||||||
|
Как переносить:
|
||||||
|
|
||||||
|
1. `pop_extract_kid_data.py` дополнительно пишет `kid_data.bin` (те же три
|
||||||
|
таблицы подряд, фиксированные смещения).
|
||||||
|
2. Грузим её в отдельную EMM-страницу тем же способом, что уровень
|
||||||
|
(`pop_level_load` — готовый образец), хэндл держим в `pop_kid`.
|
||||||
|
3. **Порт `load_frame` (seg006) и глобала `cur_frame`** — в оригинале ровно
|
||||||
|
так и сделано: раз за тик кадр копируется в структуру, а весь остальной код
|
||||||
|
читает `cur_frame`, а не таблицу. У нас `kid_cur_dx()/kid_cur_flags()`
|
||||||
|
станут чтением из `cur_frame` (5 байт в `_DATA`).
|
||||||
|
4. `play_seq` оборачивается в один `gfx_w0_map(kid_data_page)` … `unmap` на
|
||||||
|
вызов (в тике, не в отрисовке — конфликта с атласом в W0 нет).
|
||||||
|
|
||||||
|
Выигрыш: **−3 745 Б из W1/W2**, цена — один маппинг страницы за тик и 5 байт
|
||||||
|
`_DATA`. Дополнительный бонус: `load_frame`/`cur_frame` — шаг К СХОДСТВУ с
|
||||||
|
оригиналом, а не отход от него.
|
||||||
|
|
||||||
|
Риск: сломать `play_seq` (сердце анимации). Проверка: прогон по комнатам с
|
||||||
|
эталонными позами (вис, подтягивание, прыжки, подъём меча).
|
||||||
|
|
||||||
|
### Шаг 2. Модуль `pop_geom.c` — дедуп + bank-safe фундамент
|
||||||
|
|
||||||
|
Сейчас продублировано между модулями:
|
||||||
|
|
||||||
|
| что | где | сколько |
|
||||||
|
|---|---|---|
|
||||||
|
| `y_to_row`/`y_to_row_mod4` | pop_bg + pop_map | 2 копии |
|
||||||
|
| `char_dx_forward` | pop_kid + pop_map | 2 копии |
|
||||||
|
| `x_bump[20]` | pop_kid (uint8) + pop_map (int16) | 20 + 40 Б, РАЗНЫЕ типы |
|
||||||
|
| `y_land[5]` | pop_kid + pop_map | 10 + 10 Б |
|
||||||
|
| `tile_is_floor` | pop_map (+ проверка кодов в roomtest) | 2 места |
|
||||||
|
| 32-битный LCG `prandom` | pop_bg (`prandom`) + pop_trob (`trob_prandom`) | 2 копии по ~60 Б + 2 сида |
|
||||||
|
|
||||||
|
Собрать в один W1/W2-модуль `pop_geom.c`: таблицы `x_bump/y_land/dir_front/
|
||||||
|
dir_behind`, `y_to_row`, `char_dx_forward`, `get_tile_div_mod(_m7)`,
|
||||||
|
`tile_is_floor`, `prandom`. Выигрыш прямой — сотни байт (оценка 250–400 Б),
|
||||||
|
но главное — **это и есть тот «чистый» API, который потом сможет звать банк**
|
||||||
|
(R2): вся геометрия оказывается в W1/W2 по определению.
|
||||||
|
|
||||||
|
Осторожно: `prandom` у pop_bg и pop_trob — РАЗНЫЕ последовательности с разными
|
||||||
|
сидами (стены vs фазы факелов). Объединять функцию можно, **сиды — нет**:
|
||||||
|
передавать сид указателем/по индексу, иначе поедет раскладка кладки.
|
||||||
|
|
||||||
|
### Шаг 3. Вынести loose/потолок из `pop_map` в W3
|
||||||
|
|
||||||
|
`pop_map` — единственный модуль W1/W2, который зовёт графику, и делает это
|
||||||
|
ровно в одном логическом блоке: `pop_loose_tick` + `check_press` + `do_knock` +
|
||||||
|
`fell_on_your_head` + `check_loose_fall_on_kid` + плита-потолок (~1.4–2 КБ).
|
||||||
|
|
||||||
|
Вынести их в `pop_loose.c`, собираемый `--w3` рядом с `pop_bg`/`pop_trob`.
|
||||||
|
Тогда:
|
||||||
|
|
||||||
|
- `pop_map` = чистая логика (bank-safe, R2 соблюдён);
|
||||||
|
- W1/W2 худеет ещё на ~1.5–2 КБ;
|
||||||
|
- W3 растёт на столько же — а место там появится после шага 4.
|
||||||
|
|
||||||
|
### Шаг 4. Перебалансировка резидента W3
|
||||||
|
|
||||||
|
После шага 3 в W3 будет тесно (14.4 + 2 ≈ 16.4 КБ > 16 КБ). Разгружаем:
|
||||||
|
|
||||||
|
1. **`wall_pattern` (944 Б) + `mob_render`/`mob_tick_one` (1381 Б)** — кандидаты
|
||||||
|
на переезд в W1/W2: их зовёт только `pop_bg`/`pop_loose`, но сами они уже
|
||||||
|
пользуются только libbgi (R4), значит из W1/W2 работают и остаются
|
||||||
|
достижимыми из банка.
|
||||||
|
2. `tile_table` и мелкие const-таблицы pop_bg (371 + ~300 Б) можно унести в
|
||||||
|
EMM-страницу **уровня** (там ~13.8 КБ свободно) — но только если чтение
|
||||||
|
происходит под уже замапленной страницей. Сейчас `draw_tile` читает
|
||||||
|
`tile_table` ВНЕ W0-контекста → потребуется явный маппинг на тайл. **Не
|
||||||
|
делать раньше замера**: 30 тайлов на входе в комнату × map/unmap — терпимо,
|
||||||
|
а вот в покадровых редроях (пики/loose/кнопка) — уже горячий путь.
|
||||||
|
3. Если и этого мало — `enter_room` (~2.1 КБ, зовётся только при смене комнаты)
|
||||||
|
переносится в резидент W3 или в БАНК (он вызывается из главного цикла =
|
||||||
|
резидента, значит банк допустим по R3).
|
||||||
|
|
||||||
|
### Шаг 5. Данные
|
||||||
|
|
||||||
|
1. **`room_modif[24][30]` = 720 Б** (pop_trob, `_DATA`). Нужен произвольный
|
||||||
|
доступ каждый кадр (анимации, ворота) — в EMM не годится. Но 24 комнаты ×
|
||||||
|
30 байт хранятся ЦЕЛИКОМ, хотя одновременно живут modif'ы только текущей
|
||||||
|
комнаты и соседей по швам. Вариант: хранить полный массив в EMM-странице
|
||||||
|
уровня, а в `_DATA` держать кэш на 2–3 комнаты (свою + левого/правого
|
||||||
|
соседа) с записью обратно при смене комнаты. Выигрыш ~600 Б, цена —
|
||||||
|
аккуратность на швах (кнопка в одной комнате открывает ворота в другой).
|
||||||
|
**Делать последним** — это самая «тонкая» правка по семантике.
|
||||||
|
2. **`dl1[256]`+`dl2[256]` = 512 Б** (pop_level, `_DATA` — копии LINKLOC/
|
||||||
|
LINKMAP уровня) — читаются при нажатии кнопки
|
||||||
|
и при отрисовке нажатой кнопки. Кандидат на чтение прямо из страницы
|
||||||
|
уровня (она и так маппится) — но проверить, что `pop_doorlink2` не зовётся
|
||||||
|
из отрисовки в тот момент, когда в W0 атлас. Выигрыш ~500 Б.
|
||||||
|
3. **`_kbdraw_down[512]` 512 Б** (libc): проверено — это **байт на скан-код**
|
||||||
|
(`libc/kbd/_kbdraw_state.c`), хотя комментарий называет его битовой картой.
|
||||||
|
Упаковка в биты даёт −448 Б, но добавляет сдвиг/маску в ISR-трамплин и в
|
||||||
|
`kbd_raw_down`. Трогать осторожно: raw-клавиатура уже дважды была
|
||||||
|
источником залипаний (memory `kbd_raw_fifo_drain`,
|
||||||
|
`kbd_overrun_wipe_modifiers`) — правку сопровождать прогоном docs/kbd-games.
|
||||||
|
4. **`__irq_vec_buf` 513 Б** (libc IM2): таблица векторов обязана быть
|
||||||
|
выровнена и полна — не трогать.
|
||||||
|
|
||||||
|
### Шаг 6. Контракт банка стражей (проектируется ДО написания кода)
|
||||||
|
|
||||||
|
Когда дойдём до стражей:
|
||||||
|
|
||||||
|
- `guards.c` собирается `--bank 1=guards.c`, режим `huge` (или `big` с
|
||||||
|
`BANKED=W1`, если W3 окажется тесен для трамплинов).
|
||||||
|
- **Банк зовёт только:** `pop_map` (чистая логика после шага 3), `pop_kid`
|
||||||
|
(`play_seq`, `kid_set_seq`, `cur_frame`), `pop_geom`, libc/libbgi.
|
||||||
|
- **Банк НЕ зовёт:** `pop_bg`, `pop_trob`, `pop_loose` (резидент W3) — ни
|
||||||
|
прямо, ни через промежуточные функции. Нужна отрисовка — выставляет флаг,
|
||||||
|
рисует резидент (идиома `pop_item_taken`).
|
||||||
|
- Первым делом — **пробник** (`tests/` или `--bank` на пустышке): банк зовёт
|
||||||
|
`pop_map`-функцию, та зовёт libbgi-примитив; убедиться в MAME, что скобка
|
||||||
|
W3 корректно возвращает банковую страницу (R4) — это проверка модели, а не
|
||||||
|
веры в неё.
|
||||||
|
|
||||||
|
### Шаг 7. Мелкий дедуп в `pop_bg` (после того, как появится тест страниц)
|
||||||
|
|
||||||
|
- Пять функций-редроев (`pop_spike_redraw`, `pop_loose_shake_draw`,
|
||||||
|
`pop_floor_bake`, `pop_button_redraw`, `pop_leveldoor_redraw`) отличаются
|
||||||
|
только прямоугольником heal, банком и набором тайлов — свести к одному
|
||||||
|
параметризованному хелперу (оценка −150…250 Б).
|
||||||
|
- `env_b/wall_b/fore_b/pot_b` — четыре одинаковых обёртки над `blit_b`
|
||||||
|
(оставить: экономия единицы байт, читаемость дороже).
|
||||||
|
- `overlay_mid_tile` / `fore_only_tile` / `climb_overlay_tile` / `draw_tile`
|
||||||
|
— общая структура «взять code/lcode, посчитать x/dmy/dby, разобрать слои».
|
||||||
|
Тут экономия потенциально сотни байт, но это **та самая зона риска из §3** —
|
||||||
|
только с пиксельным диффом до/после и по одному слою за раз.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Ожидаемый итог
|
||||||
|
|
||||||
|
| Шаг | W1/W2 | W3 | Риск |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1. kid_data → EMM + load_frame | **−3 745** | — | средний (сердце анимации) |
|
||||||
|
| 2. pop_geom (дедуп) | −250…400 | — | низкий |
|
||||||
|
| 3. loose → W3 | −1 500…2 000 | +1 500…2 000 | низкий (перенос как есть) |
|
||||||
|
| 4. разгрузка W3 (wall_pattern, mob) | +2 300 | −2 300 | низкий |
|
||||||
|
| 5. данные (room_modif, LINKLOC, kbd) | −1 000…1 600 | — | средний/высокий |
|
||||||
|
| 7. дедуп редроев pop_bg | — | −150…250 | средний |
|
||||||
|
|
||||||
|
Суммарно: **W1/W2 освобождается ~4.5–6 КБ**, W3 остаётся примерно в нынешнем
|
||||||
|
объёме, но становится «правильно заполненным» — в нём только то, что банк
|
||||||
|
никогда не позовёт. Плюс открывается путь к банкам: стражи и боёвка получают
|
||||||
|
до 16 КБ на банк, не трогая резидент.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Как мерить и проверять (обязательно к каждому шагу)
|
||||||
|
|
||||||
|
1. **До/после по `.rel`** — точные размеры на модуль:
|
||||||
|
`for f in .sprinter-cc-roomtest/*.rel; do grep '^A ' $f; done`
|
||||||
|
(области `_CODE`/`_W3CODE`/`_DATA`). Итоги окон печатает сам `sprinter-cc`.
|
||||||
|
2. **Функции** — из `.lst` (метки `_name:` и адреса), скрипт в истории этой
|
||||||
|
сессии; полезно ловить «функция распухла после рефактора».
|
||||||
|
3. **MAME**: любой перенос кода между окнами/страницами — это класс «молча
|
||||||
|
ломается» (`sprinter_memory_modes`). Минимум: комната 1 (loose), 12
|
||||||
|
(вис/подтягивание), 15 (меч), 9 (дверь уровня), 6 (кнопка/ворота).
|
||||||
|
4. **Пиксельный дифф** для правок отрисовки: заморозить кадр (`1`), сравнить
|
||||||
|
обе страницы дабл-буфера через `vram` (см. memory `mame_mcp_bridge`) и/или
|
||||||
|
сверить с эталонным рендером `render_room.py`.
|
||||||
|
5. **Скорость** — после шагов 1 и 4 замерить кадр маркерами в порт 0xFE
|
||||||
|
(приём из v1 §8), чтобы маппинг страницы за тик не съел бюджет.
|
||||||
|
|
||||||
|
## 8. Ссылки
|
||||||
|
|
||||||
|
- `bin/sprinter-cc` — справка по `--w3`, `--bank`, `--memory`, `--memory-manual`.
|
||||||
|
- `runtime/crt0_banked.s`, `runtime/bank.s` — трамплины и захват резидентной
|
||||||
|
страницы W3.
|
||||||
|
- `libbgi/common/_bgi_begin.c` / `_bgi_end.c` — механика скобки W3 (R4).
|
||||||
|
- memory: `w3_resident_code`, `pop_banking_architecture`, `sdcc_banking`,
|
||||||
|
`bank_local_data_pattern`, `sprinter_memory_modes`, `memory_modes_implemented`,
|
||||||
|
`sprinter_emm_budget`, `mame_mcp_bridge`, `avoid_32bit_arith_z80`,
|
||||||
|
`libc_one_function_per_module`.
|
||||||
|
- `applications/PoP/docs/size_optimization_plan.md` — v1 (замер 2026-07-21,
|
||||||
|
раздел §8 про скорость отрисовки актуален и не дублируется здесь).
|
||||||
Binary file not shown.
@@ -6,8 +6,13 @@ EXAMPLE := roomtest
|
|||||||
# small: W1+W2 как единое 32КБ-пространство, DATA сразу за CODE (иначе
|
# small: W1+W2 как единое 32КБ-пространство, DATA сразу за CODE (иначе
|
||||||
# CODE ~23КБ переполняет W1 и лезет в фиксированный DATA@0x8000 в huge).
|
# CODE ~23КБ переполняет W1 и лезет в фиксированный DATA@0x8000 в huge).
|
||||||
MEMORY ?= small
|
MEMORY ?= small
|
||||||
EXTRA_FLAGS ?= --gfx 256 --w3 pop_trob.c pop_map.c --w3 pop_bg.c
|
# --w3 берёт ОДИН файл на флаг. В W3-резиденте держим ТОЛЬКО pop_bg —
|
||||||
EXTRA_SRCS := pop_kid.c pop_ctrl.c pop_level.c
|
# отрисовку тайлов: она большая и её зовёт лишь главный цикл. Всё
|
||||||
|
# остальное живёт в W1/W2, чтобы оставаться достижимым из будущих
|
||||||
|
# __banked-модулей (стражи): из банка резидентная страница W3 не видна —
|
||||||
|
# ни напрямую, ни транзитивно. См. docs/layout_plan_v2.md §2 (R2), §4.
|
||||||
|
EXTRA_FLAGS ?= --gfx 256 --w3 pop_bg.c
|
||||||
|
EXTRA_SRCS := pop_kid.c pop_ctrl.c pop_level.c pop_map.c pop_trob.c pop_redraw.c pop_geom.c
|
||||||
|
|
||||||
BG_DIR := $(CURDIR)/../poc/res/bg
|
BG_DIR := $(CURDIR)/../poc/res/bg
|
||||||
KID_DIR := $(CURDIR)/../poc/res/kid
|
KID_DIR := $(CURDIR)/../poc/res/kid
|
||||||
@@ -22,8 +27,11 @@ BG_DATA := $(BG_DIR)/pop_env0.atl $(BG_DIR)/pop_env1.atl $(BG_DIR)/pop_env2.
|
|||||||
# ЕДИНАЯ игровая (env+wall+kid).
|
# ЕДИНАЯ игровая (env+wall+kid).
|
||||||
KID_PAGES := $(foreach n,0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27,$(KID_DIR)/kid$(n).atl)
|
KID_PAGES := $(foreach n,0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27,$(KID_DIR)/kid$(n).atl)
|
||||||
KID_DATA := $(KID_PAGES) $(KID_DIR)/kid.pal $(KID_DIR)/sword.atl
|
KID_DATA := $(KID_PAGES) $(KID_DIR)/kid.pal $(KID_DIR)/sword.atl
|
||||||
|
# Таблицы анимации (кадры+seqtbl) — отдельный бинарь в EMM-странице, его
|
||||||
|
# делает pop_extract_kid_data.py (не упаковщик спрайтов) — своё правило ниже.
|
||||||
|
KID_BIN := $(KID_DIR)/kid_data.bin
|
||||||
|
|
||||||
EXTRA_DATA := $(BG_DATA) $(KID_DATA) $(LVL_DATA)
|
EXTRA_DATA := $(BG_DATA) $(KID_DATA) $(KID_BIN) $(LVL_DATA)
|
||||||
include $(PROJ_ROOT)/app.mk
|
include $(PROJ_ROOT)/app.mk
|
||||||
|
|
||||||
TC := $(PROJ_ROOT)/applications/PoP/toolchain
|
TC := $(PROJ_ROOT)/applications/PoP/toolchain
|
||||||
@@ -31,7 +39,7 @@ $(BG_DATA): $(TC)/pop_pack_bg.py $(TC)/render_room.py
|
|||||||
cd $(TC) && python3 pop_pack_bg.py
|
cd $(TC) && python3 pop_pack_bg.py
|
||||||
$(KID_DATA): $(TC)/pop_pack_kid.py $(TC)/pop_pack_bg.py
|
$(KID_DATA): $(TC)/pop_pack_kid.py $(TC)/pop_pack_bg.py
|
||||||
cd $(TC) && python3 pop_pack_kid.py
|
cd $(TC) && python3 pop_pack_kid.py
|
||||||
kid_data.h: $(TC)/pop_extract_kid_data.py
|
kid_data.h $(KID_BIN): $(TC)/pop_extract_kid_data.py
|
||||||
cd $(TC) && python3 pop_extract_kid_data.py
|
cd $(TC) && python3 pop_extract_kid_data.py
|
||||||
|
|
||||||
$(EXAMPLE).exe: pop_bg.c pop_bg.h pop_kid.c pop_kid.h pop_ctrl.c pop_ctrl.h pop_map.c pop_map.h pop_level.c pop_level.h pop_trob.c pop_trob.h kid_data.h $(BG_DATA) $(KID_DATA) $(LVL_DATA)
|
$(EXAMPLE).exe: pop_bg.c pop_bg.h pop_geom.c pop_geom.h pop_redraw.c pop_redraw.h pop_kid.c pop_kid.h pop_ctrl.c pop_ctrl.h pop_map.c pop_map.h pop_level.c pop_level.h pop_trob.c pop_trob.h kid_data.h $(BG_DATA) $(KID_DATA) $(KID_BIN) $(LVL_DATA)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -8,449 +8,16 @@
|
|||||||
|
|
||||||
#define SEQTBL_BASE 0x196Eu
|
#define SEQTBL_BASE 0x196Eu
|
||||||
|
|
||||||
/* {image, dx, dy, flags, sword}; chtab = sword>>6 (0=kid). */
|
/* {image, dx, dy, flags, sword}; chtab = sword>>6 (0=kid).
|
||||||
|
* САМА таблица кадров и seqtbl лежат в kid_data.bin (EMM-
|
||||||
|
* страница); здесь только тип и размеры. */
|
||||||
typedef struct { uint8_t image; int8_t dx, dy; uint8_t flags, sword; } kframe;
|
typedef struct { uint8_t image; int8_t dx, dy; uint8_t flags, sword; } kframe;
|
||||||
#define KID_NFRAMES 241
|
#define KID_NFRAMES 241
|
||||||
static const kframe kid_frames[KID_NFRAMES] = {
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{ 0, 1, 0,0xC4,0x00},
|
|
||||||
{ 1, 1, 0,0x44,0x00},
|
|
||||||
{ 2, 3, 0,0x47,0x00},
|
|
||||||
{ 3, 4, 0,0x48,0x00},
|
|
||||||
{ 4, 0, 0,0xE6,0x00},
|
|
||||||
{ 5, 0, 0,0x49,0x00},
|
|
||||||
{ 6, 0, 0,0x4A,0x00},
|
|
||||||
{ 7, 0, 0,0xC5,0x00},
|
|
||||||
{ 8, 0, 0,0x44,0x00},
|
|
||||||
{ 9, 0, 0,0x47,0x00},
|
|
||||||
{ 10, 0, 0,0x4B,0x00},
|
|
||||||
{ 11, 0, 0,0x43,0x00},
|
|
||||||
{ 12, 0, 0,0xC3,0x00},
|
|
||||||
{ 13, 0, 0,0x47,0x00},
|
|
||||||
{ 14, 0, 0,0x43,0x09},
|
|
||||||
{ 15, 0, 0,0xC3,0x00},
|
|
||||||
{ 16, 0, 0,0x44,0x00},
|
|
||||||
{ 17, 0, 0,0x46,0x00},
|
|
||||||
{ 18, 0, 0,0x48,0x00},
|
|
||||||
{ 19, 0, 0,0x89,0x00},
|
|
||||||
{ 20, 0, 0,0x0B,0x00},
|
|
||||||
{ 21, 0, 0,0x8B,0x00},
|
|
||||||
{ 22, 0, 0,0x11,0x00},
|
|
||||||
{ 23, 0, 0,0x07,0x00},
|
|
||||||
{ 24, 0, 0,0x05,0x00},
|
|
||||||
{ 25, 0, 0,0xC1,0x00},
|
|
||||||
{ 26, 0, 0,0xC6,0x00},
|
|
||||||
{ 27, 0, 0,0x43,0x00},
|
|
||||||
{ 28, 0, 0,0x48,0x00},
|
|
||||||
{ 29, 0, 0,0x42,0x00},
|
|
||||||
{ 30, 0, 0,0x42,0x00},
|
|
||||||
{ 31, 0, 0,0xC2,0x00},
|
|
||||||
{ 32, 0, 0,0xC2,0x00},
|
|
||||||
{ 33, 0, 0,0x43,0x00},
|
|
||||||
{ 34, 0, 0,0x48,0x00},
|
|
||||||
{ 35, 0, 0,0xCE,0x00},
|
|
||||||
{ 36, 0, 0,0xC1,0x00},
|
|
||||||
{ 37, 0, 0,0x45,0x00},
|
|
||||||
{ 38, 0, 0,0x8E,0x00},
|
|
||||||
{ 39, 0, 0,0x0B,0x00},
|
|
||||||
{ 40, 0, 0,0x8B,0x00},
|
|
||||||
{ 41, 0, 0,0x8A,0x00},
|
|
||||||
{ 42, 0, 0,0x01,0x00},
|
|
||||||
{ 43, 0, 0,0xC4,0x00},
|
|
||||||
{ 44, 0, 0,0xC3,0x00},
|
|
||||||
{ 45, 0, 0,0xC3,0x00},
|
|
||||||
{ 46, 0, 0,0xA5,0x00},
|
|
||||||
{ 47, 0, 0,0xA4,0x00},
|
|
||||||
{ 48, 0, 0,0x66,0x00},
|
|
||||||
{ 49, 4, 0,0x67,0x00},
|
|
||||||
{ 50, 3, 0,0x66,0x00},
|
|
||||||
{ 51, 1, 0,0x44,0x00},
|
|
||||||
{ 64, 0, 0,0xC2,0x00},
|
|
||||||
{ 65, 0, 0,0x41,0x00},
|
|
||||||
{ 66, 0, 0,0x42,0x00},
|
|
||||||
{ 67, 0, 0,0x00,0x00},
|
|
||||||
{ 68, 0, 0,0x00,0x00},
|
|
||||||
{ 69, 0, 0,0x80,0x00},
|
|
||||||
{ 70, 0, 0,0x00,0x00},
|
|
||||||
{ 71, 0, 0,0x80,0x00},
|
|
||||||
{ 72, 0, 0,0x00,0x00},
|
|
||||||
{ 73, 0, 0,0x80,0x00},
|
|
||||||
{ 74, 0, 0,0x00,0x00},
|
|
||||||
{ 75, 0, 0,0x00,0x00},
|
|
||||||
{ 76, 0, 0,0x80,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{ 80, -2, 0,0x41,0x00},
|
|
||||||
{ 81, -2, 0,0x41,0x00},
|
|
||||||
{ 82, -1, 0,0xC2,0x00},
|
|
||||||
{ 83, -2, 0,0x42,0x00},
|
|
||||||
{ 84, -2, 0,0x41,0x00},
|
|
||||||
{ 85, -2, 0,0x41,0x00},
|
|
||||||
{ 86, -2, 0,0x41,0x00},
|
|
||||||
{ 87, -1, 0,0x07,0x00},
|
|
||||||
{ 88, -1, 0,0x05,0x00},
|
|
||||||
{ 89, 2, 0,0x07,0x00},
|
|
||||||
{ 90, 2, 0,0x07,0x00},
|
|
||||||
{ 91, 2, -3,0x00,0x00},
|
|
||||||
{ 92, 2, -10,0x00,0x00},
|
|
||||||
{ 93, 2, -11,0x80,0x00},
|
|
||||||
{ 94, 3, -2,0x43,0x00},
|
|
||||||
{ 95, 3, 0,0xC3,0x00},
|
|
||||||
{ 96, 3, 0,0xC3,0x00},
|
|
||||||
{ 97, 3, 0,0x63,0x00},
|
|
||||||
{ 98, 4, 0,0xE3,0x00},
|
|
||||||
{ 28, 0, 0,0x00,0x00},
|
|
||||||
{ 99, 7, -14,0x80,0x00},
|
|
||||||
{100, 7, -12,0x80,0x00},
|
|
||||||
{101, 4, -12,0x00,0x00},
|
|
||||||
{102, 3, -10,0x80,0x00},
|
|
||||||
{103, 2, -10,0x80,0x00},
|
|
||||||
{104, 1, -10,0x80,0x00},
|
|
||||||
{105, 0, -11,0x00,0x00},
|
|
||||||
{106, -1, -12,0x00,0x00},
|
|
||||||
{107, -1, -14,0x00,0x00},
|
|
||||||
{108, -1, -14,0x00,0x00},
|
|
||||||
{109, -1, -15,0x80,0x00},
|
|
||||||
{110, -1, -15,0x80,0x00},
|
|
||||||
{111, 0, -15,0x00,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{112, 0, 0,0xC6,0x00},
|
|
||||||
{113, 0, 0,0x46,0x00},
|
|
||||||
{114, 0, 0,0xC5,0x00},
|
|
||||||
{115, 0, 0,0x45,0x00},
|
|
||||||
{116, 0, 0,0xC2,0x00},
|
|
||||||
{117, 0, 0,0xC4,0x00},
|
|
||||||
{118, 0, 0,0xC5,0x00},
|
|
||||||
{119, 0, 0,0x46,0x00},
|
|
||||||
{120, 0, 0,0x47,0x00},
|
|
||||||
{121, 0, 0,0x47,0x00},
|
|
||||||
{122, 0, 0,0x49,0x00},
|
|
||||||
{123, 0, 0,0xC8,0x00},
|
|
||||||
{124, 0, 0,0xC9,0x00},
|
|
||||||
{125, 0, 0,0x49,0x00},
|
|
||||||
{126, 0, 0,0x45,0x00},
|
|
||||||
{127, 2, 0,0x45,0x00},
|
|
||||||
{128, 2, 0,0xC5,0x00},
|
|
||||||
{129, 0, 0,0xC3,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{133, 0, 0,0x43,0x00},
|
|
||||||
{134, 0, 0,0xC4,0x00},
|
|
||||||
{135, 0, 0,0xC5,0x00},
|
|
||||||
{136, 0, 0,0x48,0x00},
|
|
||||||
{137, 0, 0,0x6C,0x00},
|
|
||||||
{138, 0, 0,0xEF,0x00},
|
|
||||||
{139, 0, 0,0x63,0x00},
|
|
||||||
{140, 0, 0,0xC3,0x00},
|
|
||||||
{141, 0, 0,0x43,0x00},
|
|
||||||
{142, 0, 0,0x43,0x00},
|
|
||||||
{143, 0, 0,0x44,0x00},
|
|
||||||
{144, 0, 0,0x44,0x00},
|
|
||||||
{172, 0, 1,0xC1,0x00},
|
|
||||||
{173, 0, 1,0xC7,0x00},
|
|
||||||
{145, 0, -12,0x01,0x00},
|
|
||||||
{146, 0, -21,0x00,0x00},
|
|
||||||
{147, 1, -26,0x80,0x00},
|
|
||||||
{148, 4, -32,0x80,0x00},
|
|
||||||
{149, 6, -36,0x81,0x00},
|
|
||||||
{150, 7, -41,0x82,0x00},
|
|
||||||
{151, 2, 17,0x42,0x00},
|
|
||||||
{152, 4, 9,0xC4,0x00},
|
|
||||||
{153, 4, 5,0xC9,0x00},
|
|
||||||
{154, 4, 4,0xC8,0x00},
|
|
||||||
{155, 5, 0,0x69,0x00},
|
|
||||||
{156, 5, 0,0xE9,0x00},
|
|
||||||
{157, 5, 0,0xE8,0x00},
|
|
||||||
{158, 5, 0,0x69,0x00},
|
|
||||||
{159, 5, 0,0x69,0x00},
|
|
||||||
{184, 0, 2,0x80,0x10},
|
|
||||||
{174, 0, 2,0x80,0x1A},
|
|
||||||
{175, 3, 2,0x00,0x12},
|
|
||||||
{176, 7, 2,0xC4,0x16},
|
|
||||||
{177, 10, 2,0x00,0x15},
|
|
||||||
{178, 7, 2,0x80,0x17},
|
|
||||||
{179, 4, 2,0x80,0x19},
|
|
||||||
{180, 0, 2,0xCE,0x18},
|
|
||||||
{181, 0, 2,0xCD,0x0F},
|
|
||||||
{182, 3, 2,0x00,0x14},
|
|
||||||
{183, 3, 2,0x00,0x1F},
|
|
||||||
{184, 0, 2,0x80,0x10},
|
|
||||||
{185, 0, 2,0x80,0x11},
|
|
||||||
{186, 0, 2,0x00,0x20},
|
|
||||||
{187, 0, 2,0x80,0x21},
|
|
||||||
{188, 2, 2,0xC3,0x22},
|
|
||||||
{ 14, 0, 0,0x43,0x00},
|
|
||||||
{189, 7, 2,0x80,0x13},
|
|
||||||
{190, 1, 2,0x80,0x0E},
|
|
||||||
{191, 0, 2,0x80,0x1B},
|
|
||||||
{181, 0, 2,0xCD,0x0F},
|
|
||||||
{181, 0, 2,0xCD,0x0F},
|
|
||||||
{112, 0, 0,0xC6,0x2B},
|
|
||||||
{113, 0, 0,0x46,0x2C},
|
|
||||||
{114, 0, 0,0xC5,0x2D},
|
|
||||||
{115, 0, 0,0x45,0x2E},
|
|
||||||
{114, 0, 0,0xC5,0x00},
|
|
||||||
{ 78, 0, 3,0x8A,0x00},
|
|
||||||
{ 77, 4, 3,0x87,0x00},
|
|
||||||
{211, 0, 1,0x44,0x00},
|
|
||||||
{212, 0, 1,0x44,0x00},
|
|
||||||
{213, 0, 1,0x44,0x00},
|
|
||||||
{214, 0, 1,0x47,0x00},
|
|
||||||
{215, 0, 7,0x4B,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{ 79, 4, 7,0x49,0x00},
|
|
||||||
{130, 0, 0,0x44,0x00},
|
|
||||||
{131, 0, 0,0x44,0x00},
|
|
||||||
{132, 0, 2,0x44,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{192, 0, 0,0x00,0x00},
|
|
||||||
{193, 0, 1,0x00,0x00},
|
|
||||||
{194, 0, 0,0x80,0x00},
|
|
||||||
{195, 0, 0,0x00,0x00},
|
|
||||||
{196, -1, 0,0x00,0x00},
|
|
||||||
{197, -1, 0,0x00,0x00},
|
|
||||||
{198, -1, 0,0x00,0x00},
|
|
||||||
{199, -4, 0,0x00,0x00},
|
|
||||||
{200, -4, 0,0x80,0x00},
|
|
||||||
{201, -4, 0,0x00,0x00},
|
|
||||||
{202, -4, 0,0x00,0x00},
|
|
||||||
{203, -4, 0,0x00,0x00},
|
|
||||||
{204, -4, 0,0x00,0x00},
|
|
||||||
{205, -5, 0,0x00,0x00},
|
|
||||||
{206, -5, 0,0x00,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{207, 0, 1,0x46,0x00},
|
|
||||||
{208, 0, 1,0xC6,0x00},
|
|
||||||
{209, 0, 1,0xC8,0x00},
|
|
||||||
{210, 0, 1,0x4A,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{255, 0, 0,0x00,0x00},
|
|
||||||
{ 52, 0, 0,0x80,0x00},
|
|
||||||
{ 53, 0, 0,0x00,0x00},
|
|
||||||
{ 54, 0, 0,0x00,0x00},
|
|
||||||
{ 55, 0, 0,0x00,0x00},
|
|
||||||
{ 56, 0, 0,0x80,0x00},
|
|
||||||
{ 57, 0, 0,0x00,0x00},
|
|
||||||
{ 58, 0, 0,0x00,0x00},
|
|
||||||
{ 59, 0, 0,0x00,0x00},
|
|
||||||
{ 60, 0, 0,0x80,0x00},
|
|
||||||
{ 61, 0, 0,0x00,0x00},
|
|
||||||
{ 62, 0, 0,0x80,0x00},
|
|
||||||
{ 63, 0, 0,0x00,0x00},
|
|
||||||
{160, 1, 1,0xC3,0x23},
|
|
||||||
{161, 0, 1,0x49,0x24},
|
|
||||||
{162, 0, 1,0xC3,0x25},
|
|
||||||
{163, 0, 1,0x49,0x26},
|
|
||||||
{164, 0, 1,0xC3,0x27},
|
|
||||||
{165, 1, 1,0x49,0x28},
|
|
||||||
{166, 1, 1,0x43,0x29},
|
|
||||||
{167, 1, 1,0xC9,0x2A},
|
|
||||||
{168, 4, 1,0xC6,0x00},
|
|
||||||
{169, 3, 1,0xCA,0x00},
|
|
||||||
{170, 1, 1,0x43,0x00},
|
|
||||||
{171, 1, 1,0xC8,0x00},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define KID_SEQTBL_LEN 2310
|
#define KID_SEQTBL_LEN 2310
|
||||||
static const uint8_t kid_seqtbl[KID_SEQTBL_LEN] = {
|
|
||||||
0xF9,0x01,0xFF,0x81,0x19,0xF9,0x01,0x01,0x02,0x03,0x04,0xFB,
|
/* Раскладка kid_data.bin: кадры (KID_NFRAMES*5), затем seqtbl. */
|
||||||
0x08,0x05,0xFB,0x03,0x06,0xFB,0x03,0x07,0xFB,0x05,0x08,0xFB,
|
#define KID_BIN_FRAMES_OFF 0
|
||||||
0x01,0xF2,0x01,0x09,0xFB,0x02,0x0A,0xFB,0x04,0x0B,0xFB,0x05,
|
#define KID_BIN_SEQTBL_OFF 1205
|
||||||
0x0C,0xFB,0x02,0xF2,0x01,0x0D,0xFB,0x03,0x0E,0xFB,0x04,0xFF,
|
|
||||||
0x81,0x19,0xF9,0x00,0x0F,0xFF,0xA0,0x19,0xF9,0x01,0xA6,0xFF,
|
|
||||||
0xA8,0x19,0xF9,0x05,0xFB,0x0A,0xB1,0xB1,0xFB,0xF9,0xFA,0xFE,
|
|
||||||
0xB2,0xFB,0x05,0xFA,0x02,0xA6,0xFB,0xFF,0xFF,0xD2,0x19,0xFF,
|
|
||||||
0xD2,0x19,0xF9,0x01,0xFB,0x02,0xCF,0xD0,0xFB,0x02,0xD1,0xFB,
|
|
||||||
0x02,0xD2,0xFB,0x03,0xF9,0x01,0xF2,0x00,0x9E,0xAA,0xAB,0xFF,
|
|
||||||
0xD8,0x19,0xF9,0x05,0xF8,0xFF,0x00,0xAC,0xFB,0xFF,0xFA,0x01,
|
|
||||||
0xAD,0xFB,0xFF,0xAE,0xFB,0xFF,0xFA,0x02,0xFB,0xFE,0xFA,0x01,
|
|
||||||
0xFB,0xFB,0xFA,0xFC,0xFF,0x4D,0x1A,0xF9,0x01,0xF8,0x01,0x00,
|
|
||||||
0x9B,0xFB,0x02,0xA5,0xFB,0xFE,0xFF,0xD2,0x19,0xF9,0x01,0xF8,
|
|
||||||
0xFF,0x00,0x9B,0x9C,0x9D,0x9E,0xFF,0x2E,0x1A,0xF9,0x01,0xF8,
|
|
||||||
0x01,0x00,0xFB,0x02,0xA3,0xFB,0x04,0xA4,0xA5,0xFF,0xD2,0x19,
|
|
||||||
0xF9,0x01,0xF8,0x01,0x00,0xFB,0x06,0xA4,0xA5,0xFF,0xD2,0x19,
|
|
||||||
0xF9,0x01,0xF8,0xFF,0x00,0xFB,0xFD,0xA0,0xFB,0xFE,0x9D,0xFF,
|
|
||||||
0xD2,0x19,0xF9,0x01,0xF8,0xFF,0x00,0xA8,0xF9,0x01,0x97,0xF9,
|
|
||||||
0x01,0x98,0x99,0x9A,0xF9,0x05,0x9B,0xF9,0x01,0x9C,0x9D,0xFF,
|
|
||||||
0xD2,0x19,0xF9,0x01,0xA7,0xFF,0x4A,0x1A,0xA2,0xFF,0x45,0x1A,
|
|
||||||
0xA9,0x96,0xFF,0xD2,0x19,0x9F,0xA0,0xFF,0x5F,0x1A,0xF9,0x01,
|
|
||||||
0xF4,0xFF,0xD2,0x19,0xF9,0x05,0xFB,0xF8,0xFF,0xD2,0x19,0xF9,
|
|
||||||
0x05,0xA0,0x9D,0xFF,0xD2,0x19,0xF9,0x07,0xFB,0xF8,0xFF,0x39,
|
|
||||||
0x1B,0xF9,0x05,0xFE,0xFB,0x05,0xFF,0x2E,0x1A,0xF9,0x05,0xFE,
|
|
||||||
0xFB,0x12,0xFF,0xA6,0x19,0xF9,0x01,0x10,0x11,0xFB,0x02,0x12,
|
|
||||||
0xFB,0x02,0x13,0xFB,0x02,0x14,0xFB,0x02,0x15,0xFB,0x02,0x16,
|
|
||||||
0xFB,0x07,0x17,0xFB,0x09,0x18,0xFB,0x05,0xFA,0xFA,0x19,0xFB,
|
|
||||||
0x01,0xFA,0x06,0x1A,0xFB,0x04,0xF4,0xF2,0x01,0x1B,0xFB,0xFD,
|
|
||||||
0x1C,0xFB,0x05,0x1D,0xF2,0x01,0x1E,0x1F,0x20,0x21,0xFB,0x01,
|
|
||||||
0xFF,0xA0,0x19,0xF9,0x01,0xF2,0x01,0x22,0xFB,0x05,0x23,0xFB,
|
|
||||||
0x06,0x24,0xFB,0x03,0x25,0xFB,0x05,0xF2,0x01,0x26,0xFB,0x07,
|
|
||||||
0x27,0xFB,0x0C,0xFA,0xFD,0x28,0xFB,0x08,0xFA,0xF7,0x29,0xFB,
|
|
||||||
0x08,0xFA,0xFE,0x2A,0xFB,0x04,0xFA,0x0B,0x2B,0xFB,0x04,0xFA,
|
|
||||||
0x03,0x2C,0xFB,0x05,0xF4,0xF2,0x01,0xFF,0x81,0x19,0xF9,0x01,
|
|
||||||
0xFB,0x01,0x6B,0xFB,0x02,0xFB,0x02,0x6C,0xFB,0x02,0x6D,0xFB,
|
|
||||||
0x02,0x6D,0xFB,0x02,0x6D,0xFF,0x16,0x1B,0x00,0xF9,0x01,0xFB,
|
|
||||||
0x01,0x6E,0x6F,0xFB,0x02,0x70,0xFB,0x02,0x6C,0xFB,0x02,0x6D,
|
|
||||||
0xFF,0x29,0x1B,0xF9,0x07,0xFE,0xFB,0x06,0x2D,0xFB,0x01,0x2E,
|
|
||||||
0xFF,0xC4,0x19,0xF9,0x07,0xFE,0xFB,0x06,0x2D,0xFB,0x01,0x2E,
|
|
||||||
0xFB,0x02,0x2F,0xFB,0xFF,0x30,0xFB,0x01,0x31,0xFB,0xFE,0x32,
|
|
||||||
0x33,0x34,0xFF,0xA0,0x19,0xF9,0x01,0xFB,0xFF,0xFF,0x75,0x19,
|
|
||||||
0xF9,0x01,0xFB,0x01,0x35,0xFB,0x01,0xF2,0x01,0x36,0xFB,0x08,
|
|
||||||
0x37,0xF2,0x01,0x38,0xFB,0x07,0x39,0xFB,0x03,0x3A,0xFB,0x01,
|
|
||||||
0x3B,0x3C,0xFB,0x02,0x3D,0xFB,0xFF,0x3E,0x3F,0x40,0xFB,0xFF,
|
|
||||||
0x41,0xFB,0xF2,0xFE,0xFF,0x95,0x19,0xF9,0x03,0xFA,0xFF,0x66,
|
|
||||||
0xFB,0xFE,0xFA,0x06,0x67,0xFB,0xFE,0xFA,0x09,0x68,0xFB,0xFF,
|
|
||||||
0xFA,0x0C,0x69,0xFB,0xFD,0xF8,0x00,0x0F,0xFF,0x49,0x1D,0xF9,
|
|
||||||
0x03,0xFA,0xFF,0xFB,0xFE,0x66,0xFB,0xFD,0xFA,0x06,0x67,0xFB,
|
|
||||||
0xFD,0xFA,0x09,0x68,0xFB,0xFE,0xFA,0x0C,0x69,0xFB,0xFD,0xF8,
|
|
||||||
0x00,0x0F,0xFF,0x49,0x1D,0xF9,0x03,0xFB,0x01,0xFA,0xFF,0x66,
|
|
||||||
0xFB,0x02,0xFA,0x06,0x67,0xFB,0xFF,0xFA,0x09,0x68,0xFA,0x0C,
|
|
||||||
0x69,0xFB,0xFE,0xF8,0x01,0x0F,0xFF,0x49,0x1D,0xF9,0x03,0xFB,
|
|
||||||
0x01,0xFA,0x03,0xF7,0x06,0x1C,0x66,0xFB,0x02,0xFA,0x06,0x67,
|
|
||||||
0xFB,0xFF,0xFA,0x09,0x68,0xFA,0x0C,0x69,0xFB,0xFE,0xF8,0x01,
|
|
||||||
0x0F,0xFF,0x49,0x1D,0xFB,0xFF,0xFA,0xFD,0xFF,0xE4,0x1B,0xFB,
|
|
||||||
0x01,0xFF,0xDB,0x1B,0x66,0xFB,0x02,0xFA,0x03,0x67,0xFB,0xFF,
|
|
||||||
0xFA,0x04,0x68,0xFA,0x05,0x69,0xFB,0xFE,0xF8,0x01,0x06,0xFF,
|
|
||||||
0x49,0x1D,0xF9,0x03,0xFB,0x01,0xFA,0x03,0x66,0xFB,0x02,0xFA,
|
|
||||||
0x06,0x67,0xFB,0x01,0xFA,0x09,0x68,0xFB,0x02,0xFA,0x0C,0x69,
|
|
||||||
0xF8,0x02,0x0F,0xFF,0x49,0x1D,0xF9,0x03,0xFB,0x01,0xFA,0x03,
|
|
||||||
0x66,0xFB,0x03,0xFA,0x06,0x67,0xFB,0x02,0xFA,0x09,0x68,0xFB,
|
|
||||||
0x03,0xFA,0x0C,0x69,0xF8,0x03,0x0F,0xFF,0x49,0x1D,0xF9,0x01,
|
|
||||||
0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0xF9,
|
|
||||||
0x02,0x4E,0x4F,0x50,0xFF,0xA1,0x1C,0xF9,0x01,0x43,0x44,0x45,
|
|
||||||
0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0xF9,0x02,0xFB,0x01,
|
|
||||||
0x4E,0xFB,0x02,0x4F,0xFB,0x01,0x50,0xFF,0xA1,0x1C,0xF9,0x01,
|
|
||||||
0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0xFB,0xFF,
|
|
||||||
0x4D,0xF9,0x02,0xFB,0xFE,0x4E,0xFB,0xFF,0x4F,0xFB,0xFF,0x50,
|
|
||||||
0xFF,0xA1,0x1C,0xF9,0x02,0x5B,0x5A,0x59,0x58,0x57,0x57,0x57,
|
|
||||||
0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63,
|
|
||||||
0x61,0x60,0x5F,0x5E,0x5D,0x5C,0x5B,0x5A,0x59,0x58,0x57,0x58,
|
|
||||||
0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x5F,0x5E,0x5D,0x5C,
|
|
||||||
0xFF,0x25,0x1D,0xF9,0x06,0x5C,0x5D,0x5D,0x5C,0x5C,0x5B,0xFF,
|
|
||||||
0xD8,0x1C,0x87,0x88,0x89,0x89,0x8A,0x8A,0x8A,0x8A,0x89,0x88,
|
|
||||||
0x87,0xFB,0xF9,0xFF,0x25,0x1D,0xF9,0x01,0x94,0x91,0x90,0x8F,
|
|
||||||
0x8E,0x8D,0xFB,0xFB,0xFA,0x3F,0xFC,0xF9,0x03,0x8C,0x8A,0x88,
|
|
||||||
0x5B,0xF9,0x02,0xFF,0xA4,0x1C,0xF9,0x01,0x87,0x88,0x89,0x8A,
|
|
||||||
0x8B,0x8C,0xFB,0x05,0xFA,0xC1,0xFD,0x8D,0x8E,0x8F,0x90,0x91,
|
|
||||||
0x92,0x93,0x94,0xF9,0x05,0x95,0xF9,0x01,0x76,0x77,0xFB,0x01,
|
|
||||||
0xFF,0xA0,0x19,0x51,0x52,0xF9,0x05,0x53,0xF9,0x01,0xF4,0xF2,
|
|
||||||
0x00,0x54,0x55,0xFB,0x03,0xFF,0xA0,0x19,0xF9,0x03,0x51,0xFA,
|
|
||||||
0x06,0x51,0xFA,0x09,0x51,0xFA,0x0C,0xFB,0x02,0xF8,0x00,0x0C,
|
|
||||||
0xFF,0x49,0x1D,0xF9,0x04,0x6A,0xFF,0x4B,0x1D,0xF9,0x01,0x35,
|
|
||||||
0xFB,0x02,0xF2,0x01,0x36,0xFB,0x07,0x37,0xF2,0x01,0x38,0xFB,
|
|
||||||
0x02,0x31,0xFB,0xFE,0x32,0x33,0x34,0xFF,0xA0,0x19,0xF9,0x01,
|
|
||||||
0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,
|
|
||||||
0xF9,0x00,0xF5,0x4F,0xFF,0x25,0x1D,0xF9,0x01,0x43,0x44,0x45,
|
|
||||||
0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0xFA,0xFC,
|
|
||||||
0x4F,0xFA,0xFE,0x4F,0x4F,0xFA,0x02,0x4F,0xFA,0x04,0xFF,0x25,
|
|
||||||
0x1D,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0xFA,
|
|
||||||
0xFF,0x4D,0xFA,0xFD,0x4E,0xFA,0xFC,0x4F,0xFA,0xF6,0x4F,0xFA,
|
|
||||||
0xF7,0x4F,0xFA,0xF8,0x4F,0xFA,0xF9,0x4F,0xFA,0xFA,0x4F,0xFA,
|
|
||||||
0xFB,0x4F,0xFA,0xFC,0x4F,0xFA,0xFD,0x4F,0xFA,0xFE,0x4F,0xFA,
|
|
||||||
0xFE,0x4F,0xFA,0xFF,0x4F,0xFA,0xFF,0x4F,0xFA,0xFF,0x4F,0x4F,
|
|
||||||
0x4F,0x4F,0xFA,0x01,0x4F,0xFA,0x01,0x4F,0xFA,0x02,0x4F,0xFA,
|
|
||||||
0x02,0x4F,0xFA,0x03,0x4F,0xFA,0x04,0x4F,0xFA,0x05,0x4F,0xFA,
|
|
||||||
0x06,0x4F,0xF8,0x00,0x06,0xFF,0x49,0x1D,0xF9,0x03,0x50,0xFF,
|
|
||||||
0xA1,0x1C,0xF9,0x05,0xFB,0xFC,0x32,0x33,0x34,0xFF,0xA0,0x19,
|
|
||||||
0xF9,0x05,0xFB,0x01,0xFA,0x03,0xF7,0x25,0x1E,0x66,0xFB,0x02,
|
|
||||||
0xFA,0x06,0x67,0xFB,0xFF,0xFA,0x09,0x68,0xFA,0x0C,0x69,0xFB,
|
|
||||||
0xFE,0xF8,0x00,0x0F,0xFF,0x49,0x1D,0x66,0xFB,0x02,0xFA,0x03,
|
|
||||||
0x67,0xFB,0xFF,0xFA,0x04,0x68,0xFA,0x05,0x69,0xFB,0xFE,0xF8,
|
|
||||||
0x00,0x06,0xFF,0x49,0x1D,0xF9,0x05,0xFB,0xFF,0xFA,0xFC,0x66,
|
|
||||||
0xFB,0xFF,0xFA,0x03,0xFB,0xFD,0xFA,0x01,0xF4,0xFB,0x01,0xF2,
|
|
||||||
0x01,0x6B,0xFB,0x02,0x6C,0xF2,0x01,0x6D,0xFF,0xB3,0x1F,0x79,
|
|
||||||
0xFB,0x01,0x7A,0x7B,0xFB,0x02,0x7C,0xFB,0x04,0x7D,0xFB,0x03,
|
|
||||||
0x7E,0xFB,0xFC,0x56,0xF2,0x01,0xF4,0xFB,0xFC,0x74,0xFB,0xFE,
|
|
||||||
0x75,0x76,0x77,0xFF,0xA0,0x19,0xFB,0xFB,0xFF,0xA0,0x19,0xF9,
|
|
||||||
0x01,0x79,0xFB,0x01,0x7A,0xFB,0x01,0x7B,0xFB,0x03,0x7C,0xFB,
|
|
||||||
0x04,0x7D,0xFB,0x03,0x7E,0xFB,0xFF,0xFB,0x03,0x7F,0x80,0x81,
|
|
||||||
0x82,0x83,0x84,0xFF,0xA0,0x19,0xF9,0x01,0x79,0xFB,0x01,0x7A,
|
|
||||||
0xFB,0x01,0x7B,0xFB,0x03,0x7C,0xFB,0x04,0x7D,0xFB,0x03,0x7E,
|
|
||||||
0xFB,0xFF,0xFB,0x02,0x7F,0x80,0x81,0x82,0x83,0x84,0xFF,0xA0,
|
|
||||||
0x19,0xF9,0x01,0x79,0xFB,0x01,0x7A,0xFB,0x01,0x7B,0xFB,0x03,
|
|
||||||
0x7C,0xFB,0x04,0x7D,0xFB,0x03,0x7E,0xFB,0xFF,0xFB,0x01,0x7F,
|
|
||||||
0x80,0x81,0x82,0x83,0x84,0xFF,0xA0,0x19,0xF9,0x01,0x79,0xFB,
|
|
||||||
0x01,0x7A,0xFB,0x01,0x7B,0xFB,0x03,0x7C,0xFB,0x04,0x7D,0xFB,
|
|
||||||
0x03,0x7E,0xFB,0xFF,0x7F,0x80,0x81,0x82,0x83,0x84,0xFF,0xA0,
|
|
||||||
0x19,0xF9,0x01,0x79,0xFB,0x01,0x7A,0xFB,0x01,0x7B,0xFB,0x03,
|
|
||||||
0x7C,0xFB,0x04,0x7D,0xFB,0x03,0x7E,0xFB,0xFE,0x80,0x81,0x82,
|
|
||||||
0x83,0x84,0xFF,0xA0,0x19,0xF9,0x01,0x79,0xFF,0xFC,0x1E,0xF9,
|
|
||||||
0x01,0x79,0xFB,0x01,0x7A,0xFB,0x01,0x7B,0xFB,0x03,0x7C,0xFB,
|
|
||||||
0x04,0x7D,0xFB,0xFF,0x7F,0x80,0x81,0x82,0x83,0x84,0xFF,0xA0,
|
|
||||||
0x19,0xF9,0x01,0x79,0xFB,0x01,0x7A,0xFB,0x01,0x7B,0xFB,0x03,
|
|
||||||
0x7C,0xFB,0x02,0x81,0x82,0x83,0x84,0xFF,0xA0,0x19,0xF9,0x01,
|
|
||||||
0x79,0xFB,0x01,0x7A,0xFB,0x01,0x7B,0xFB,0x02,0x7C,0xFB,0x02,
|
|
||||||
0x81,0x82,0x83,0x84,0xFF,0xA0,0x19,0xF9,0x01,0x79,0xFB,0x01,
|
|
||||||
0x7A,0xFB,0x01,0x7B,0xFB,0x02,0x7C,0xFB,0x01,0x81,0x82,0x83,
|
|
||||||
0x84,0xFF,0xA0,0x19,0xF9,0x01,0x79,0xFB,0x01,0x7A,0xFB,0x01,
|
|
||||||
0x7B,0xFB,0x02,0x83,0x84,0xFF,0xA0,0x19,0xF9,0x01,0x79,0xFB,
|
|
||||||
0x01,0x7A,0xFB,0x01,0x7B,0xFB,0x01,0x83,0x84,0xFF,0xA0,0x19,
|
|
||||||
0xF9,0x01,0x79,0xFB,0x01,0x7A,0xFB,0x01,0x84,0xFF,0xA0,0x19,
|
|
||||||
0xF9,0x01,0x79,0xFB,0x01,0x84,0xFF,0xA0,0x19,0xF9,0x01,0xFB,
|
|
||||||
0x01,0x6B,0xFB,0x02,0x6C,0x6D,0xFF,0xAF,0x1F,0xF9,0x05,0xFB,
|
|
||||||
0x01,0x6E,0x6F,0xFB,0x02,0x70,0x71,0xFB,0x01,0x72,0x73,0x74,
|
|
||||||
0xFB,0xFC,0x75,0x76,0x77,0xFF,0xA0,0x19,0xF9,0x01,0xF3,0x01,
|
|
||||||
0xE5,0xE5,0xE5,0xE5,0xE5,0xE5,0xE6,0xE7,0xE8,0xFF,0xDA,0x1F,
|
|
||||||
0xF9,0x01,0xFB,0xFB,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,
|
|
||||||
0x85,0x85,0x86,0x86,0x86,0x30,0xFB,0x01,0x31,0xFB,0xFE,0xF9,
|
|
||||||
0x05,0x32,0xF9,0x01,0x33,0x34,0xFF,0xA0,0x19,0xF9,0x01,0xFB,
|
|
||||||
0xFB,0xEA,0xEC,0xEE,0xF0,0x86,0xFB,0xFF,0xFF,0xA0,0x19,0xF9,
|
|
||||||
0x01,0xFB,0x04,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xF2,0x03,
|
|
||||||
0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCD,0xCD,0xF3,0x01,
|
|
||||||
0xCD,0xCD,0xC9,0xC6,0xFB,0xFC,0xFF,0xA0,0x19,0xF9,0x05,0xF4,
|
|
||||||
0xFB,0x01,0x6B,0xFB,0x02,0x6C,0xF9,0x01,0x6D,0xFF,0x36,0x20,
|
|
||||||
0xF9,0x01,0xFA,0xFE,0xFB,0x01,0x6B,0xFB,0x02,0x6C,0x6D,0xFB,
|
|
||||||
0x01,0x6E,0x6F,0xFB,0x02,0x70,0x71,0xFB,0x01,0xFA,0x01,0x72,
|
|
||||||
0xFA,0x01,0x73,0xFB,0xFE,0xFF,0x78,0x19,0xF9,0x05,0xF4,0xFA,
|
|
||||||
0xFE,0xFB,0x01,0xFB,0x02,0x6C,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,
|
|
||||||
0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,
|
|
||||||
0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0xFB,
|
|
||||||
0x01,0x6E,0x6E,0x6E,0x6F,0xFB,0x02,0x70,0x71,0xFB,0x01,0xFA,
|
|
||||||
0x01,0x72,0xFA,0x01,0x73,0x74,0xFB,0xFC,0x75,0x76,0x77,0xFF,
|
|
||||||
0xA0,0x19,0xF9,0x05,0xF4,0xFA,0xFE,0xFB,0x03,0xB9,0xF6,0xB9,
|
|
||||||
0xFF,0xA5,0x20,0xF9,0x05,0xFF,0xAE,0x20,0xF9,0x01,0xF6,0xB3,
|
|
||||||
0xB4,0xB5,0xB6,0xFB,0x01,0xB7,0xFB,0xFC,0xB9,0xFF,0xBA,0x20,
|
|
||||||
0xF9,0x01,0xF4,0xFB,0x04,0xB1,0xF6,0xB1,0xFF,0xC5,0x20,0xF9,
|
|
||||||
0x01,0xB2,0xF6,0xB2,0xFF,0xCD,0x20,0xFF,0x5A,0x20,0xF8,0x00,
|
|
||||||
0x00,0xF9,0x04,0xB9,0xFF,0xD9,0x20,0xF9,0x05,0xFB,0xFB,0xFA,
|
|
||||||
0xFF,0xF2,0x01,0xD9,0xDA,0xDB,0xFB,0x01,0xDC,0xFB,0xFC,0xFA,
|
|
||||||
0xFD,0xF2,0x01,0xDD,0xFB,0xFC,0xFA,0xFE,0xDE,0xFB,0xFE,0xFA,
|
|
||||||
0xFD,0xDF,0xFB,0xFD,0xFA,0xF8,0xF2,0x04,0xF2,0x01,0xE0,0xFB,
|
|
||||||
0xFF,0xFA,0xFF,0xE1,0xFB,0xFD,0xFA,0xFC,0xE2,0xFB,0xFF,0xFA,
|
|
||||||
0xFB,0xF2,0x01,0xE3,0xFB,0xFE,0xFA,0xFF,0xE4,0x00,0xF2,0x01,
|
|
||||||
0x00,0x00,0x00,0xF2,0x01,0x00,0x00,0x00,0xF2,0x01,0x00,0x00,
|
|
||||||
0x00,0xF2,0x01,0xF1,0x00,0xFF,0x2E,0x21,0x36,0xFF,0x32,0x21,
|
|
||||||
0x55,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x44,
|
|
||||||
0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x53,0x54,0x4C,0xFF,0x4B,
|
|
||||||
0x21,0xFB,0x01,0x30,0xFB,0x02,0x31,0xFB,0x06,0x32,0xFB,0x01,
|
|
||||||
0x33,0xFB,0xFF,0x34,0xFB,0x01,0x35,0xFB,0x01,0xFF,0x51,0x21,
|
|
||||||
0xFB,0x01,0x37,0x38,0xFF,0x32,0x21,0x4D,0x4E,0x4F,0x50,0x51,
|
|
||||||
0x52,0xFB,0x01,0x36,0x36,0x36,0x36,0x36,0x36,0x39,0x3A,0x3B,
|
|
||||||
0x3C,0x3D,0xFB,0x02,0x3E,0xFB,0xFF,0x3F,0xFB,0xFD,0x40,0x41,
|
|
||||||
0xFB,0xFF,0x42,0xFE,0xFB,0x10,0xFB,0x03,0xFF,0x54,0x21,0x0B,
|
|
||||||
0xFF,0x95,0x21,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFE,
|
|
||||||
0xFB,0x08,0x0B,0xFF,0x95,0x21,0xFE,0xFB,0x0B,0x0C,0xFB,0x01,
|
|
||||||
0x0D,0xFB,0x01,0x0E,0xFB,0x03,0x0F,0xFB,0x01,0x10,0x11,0xFF,
|
|
||||||
0xB8,0x21,0x13,0xFF,0xBC,0x21,0x14,0xFF,0xC0,0x21,0x15,0xFB,
|
|
||||||
0x01,0x16,0x17,0x18,0xFB,0x01,0x19,0xFB,0xFD,0x1A,0xFB,0xFE,
|
|
||||||
0x1B,0xFB,0xFC,0x1C,0xFB,0xFD,0x1D,0xFB,0xFE,0x1E,0xFB,0xFD,
|
|
||||||
0x1F,0xFB,0xFF,0x20,0x21,0xFF,0xE2,0x21,0x25,0xFF,0xE6,0x21,
|
|
||||||
0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0xFE,
|
|
||||||
0xFB,0x0C,0x0B,0xFF,0xF8,0x21,0x0B,0x0B,0xFE,0xFB,0x0D,0x2F,
|
|
||||||
0x2E,0x2D,0x2C,0x2B,0x2A,0x29,0x28,0x27,0x26,0x25,0x24,0x24,
|
|
||||||
0x24,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x23,
|
|
||||||
0x23,0x24,0x24,0x24,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,
|
|
||||||
0x22,0x22,0x23,0x23,0x24,0x24,0x24,0x23,0x23,0x23,0x22,0x22,
|
|
||||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x23,0x23,0x23,0x24,0xFF,
|
|
||||||
0x3C,0x22,0x01,0x12,0xFF,0x41,0x22,0xF9,0x01,0xBA,0xFB,0x05,
|
|
||||||
0xBA,0xFB,0x03,0xBB,0xFB,0x04,0xFF,0x47,0x22,0xBA,0xFF,0x53,
|
|
||||||
0x22,0xBC,0xFF,0x57,0x22,0xF9,0x00,0xBA,0xBA,0xBA,0xBC,0xBC,
|
|
||||||
0xBC,0xBC,0xBC,0xBC,0xBC,0xBC,0xFE,0xFB,0x08,0xFF,0x47,0x22,
|
|
||||||
0xBA,0xBA,0xBC,0xFF,0x70,0x22,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define KID_NSEQ 115
|
#define KID_NSEQ 115
|
||||||
static const uint16_t kid_seq_off[KID_NSEQ] = {
|
static const uint16_t kid_seq_off[KID_NSEQ] = {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "pop_bg.h"
|
#include "pop_bg.h"
|
||||||
|
#include "pop_geom.h"
|
||||||
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
|
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
|
||||||
#include "pop_kid.h" /* Kid.curr_col/curr_row — порядок оверлеев (см. ниже) */
|
#include "pop_kid.h" /* Kid.curr_col/curr_row — порядок оверлеев (см. ниже) */
|
||||||
|
|
||||||
@@ -311,11 +312,7 @@ static uint8_t wall_modifier(int row, int col)
|
|||||||
/* ---- PRNG (seg009.c:321, 32-бит LCG) — только на ВХОД в комнату ---- */
|
/* ---- PRNG (seg009.c:321, 32-бит LCG) — только на ВХОД в комнату ---- */
|
||||||
static unsigned long rnd_seed;
|
static unsigned long rnd_seed;
|
||||||
|
|
||||||
static uint16_t prandom(uint16_t maxv)
|
#define prandom(maxv) pop_prandom(&rnd_seed, (maxv))
|
||||||
{
|
|
||||||
rnd_seed = rnd_seed * 214013UL + 2531011UL;
|
|
||||||
return (uint16_t)((uint16_t)(rnd_seed >> 16) % (uint16_t)(maxv + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- Декали-марки стен (seg008.c:2041/2056) ------------------------ */
|
/* ---- Декали-марки стен (seg008.c:2041/2056) ------------------------ */
|
||||||
static void draw_left_mark(uint16_t dv, int arg2, int arg1, int row, int col)
|
static void draw_left_mark(uint16_t dv, int arg2, int arg1, int row, int col)
|
||||||
@@ -1125,10 +1122,7 @@ static int8_t col_from_x(int xpos) /* get_tile_div_mod: колонка (
|
|||||||
return (int8_t)xh;
|
return (int8_t)xh;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int8_t y_to_row(int y) /* y_to_row_mod4 (seg006, TILE_SIZEY=63) */
|
#define y_to_row(y) pop_y_to_row((int16_t)(y)) /* общий (pop_geom) */
|
||||||
{
|
|
||||||
return (int8_t)((y + 60) / 63 % 4 - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fore_only_tile(int row, int col)
|
static void fore_only_tile(int row, int col)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* pop_geom.c — общая геометрия + PRNG оригинала. См. pop_geom.h.
|
||||||
|
*/
|
||||||
|
#include "pop_geom.h"
|
||||||
|
|
||||||
|
/* data.h: шаг 14 (ширина тайла в координатах персонажа), [5] = col 0. */
|
||||||
|
const int16_t pop_x_bump[20] = {
|
||||||
|
-12, 2, 16, 30, 44, 58, 72, 86, 100, 114,
|
||||||
|
128, 142, 156, 170, 184, 198, 212, 226, 240, 254
|
||||||
|
};
|
||||||
|
const int16_t pop_y_land[5] = {-8, 55, 118, 181, 244};
|
||||||
|
|
||||||
|
int8_t pop_y_to_row(int16_t y)
|
||||||
|
{
|
||||||
|
return (int8_t)((y + 60) / TILE_SIZEY % 4 - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t pop_prandom(unsigned long *seed, uint16_t maxv)
|
||||||
|
{
|
||||||
|
unsigned long s = *seed * 214013UL + 2531011UL;
|
||||||
|
*seed = s;
|
||||||
|
return (uint16_t)((uint16_t)(s >> 16) % (uint16_t)(maxv + 1));
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* pop_geom.h — общая геометрия PoP и PRNG оригинала.
|
||||||
|
*
|
||||||
|
* Сюда сведено то, что раньше дублировалось по модулям (x_bump/y_land в
|
||||||
|
* pop_kid и pop_map, y_to_row в pop_bg и pop_map, 32-битный LCG в pop_bg и
|
||||||
|
* pop_trob). Кроме экономии это ФУНДАМЕНТ bank-safe API: модуль живёт в
|
||||||
|
* W1/W2 и не трогает графику, поэтому его может звать и главный цикл, и
|
||||||
|
* резидент W3, и будущий __banked-код стражей (docs/layout_plan_v2.md §4).
|
||||||
|
*/
|
||||||
|
#ifndef POP_GEOM_H
|
||||||
|
#define POP_GEOM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define FIRST_ONSCREEN_COLUMN 5 /* индекс col 0 комнаты в x_bump */
|
||||||
|
#define TILE_SIZEX 14 /* ширина тайла в координатах персонажа */
|
||||||
|
#define TILE_SIZEY 63 /* высота ряда */
|
||||||
|
|
||||||
|
/* x_bump (data.h): левая граница колонки в координатах персонажа; колонка
|
||||||
|
* комнаты col = x_bump[col + FIRST_ONSCREEN_COLUMN]. y_land: пол ряда
|
||||||
|
* (индекс row+1; [0] — ряд «над комнатой»). */
|
||||||
|
extern const int16_t pop_x_bump[20];
|
||||||
|
extern const int16_t pop_y_land[5];
|
||||||
|
|
||||||
|
/* y_to_row_mod4 (seg006): ряд по координате y с оборотом mod 4 (−1 = полоса
|
||||||
|
* над комнатой, 3 = под комнатой). */
|
||||||
|
int8_t pop_y_to_row(int16_t y);
|
||||||
|
|
||||||
|
/* prandom (seg009:321) — 32-битный LCG оригинала. Сид ВНЕШНИЙ: у стен
|
||||||
|
* (раскладка кладки) и у анимаций тайлов (фаза факелов) свои
|
||||||
|
* последовательности, смешивать их нельзя. */
|
||||||
|
uint16_t pop_prandom(unsigned long *seed, uint16_t maxv);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -2,12 +2,17 @@
|
|||||||
* pop_kid.c — движок Kid (Фаза K1): порт seg006.c play_seq/load_frame +
|
* pop_kid.c — движок Kid (Фаза K1): порт seg006.c play_seq/load_frame +
|
||||||
* seqtbl-интерпретатор. Данные — kid_data.h.
|
* seqtbl-интерпретатор. Данные — kid_data.h.
|
||||||
*/
|
*/
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sprinter.h>
|
||||||
|
#include <sprinter_mem.h>
|
||||||
#include <graphics.h>
|
#include <graphics.h>
|
||||||
#include <gfx.h>
|
#include <gfx.h>
|
||||||
#include <sprite.h>
|
#include <sprite.h>
|
||||||
#include "pop_kid.h"
|
#include "pop_kid.h"
|
||||||
#include "pop_bg.h" /* POP_YOFF — вертикальное центрирование */
|
#include "pop_bg.h" /* POP_YOFF — вертикальное центрирование */
|
||||||
#include "pop_map.h" /* pop_clip_char_top (clip_char) */
|
#include "pop_map.h" /* pop_clip_char_top (clip_char) */
|
||||||
|
#include "pop_geom.h"
|
||||||
#include "kid_data.h"
|
#include "kid_data.h"
|
||||||
|
|
||||||
kid_t Kid;
|
kid_t Kid;
|
||||||
@@ -16,14 +21,6 @@ kid_t Kid;
|
|||||||
* в play_seq, потребляется pop_check_knock (pop_map) — трясёт loose-полы. */
|
* в play_seq, потребляется pop_check_knock (pop_map) — трясёт loose-полы. */
|
||||||
int8_t knock;
|
int8_t knock;
|
||||||
|
|
||||||
/* Координатные таблицы (data.h). */
|
|
||||||
static const uint8_t x_bump[20] = {
|
|
||||||
(uint8_t)-12, 2, 16, 30, 44, 58, 72, 86, 100, 114,
|
|
||||||
128, 142, 156, 170, 184, 198, 212, 226, 240, 254
|
|
||||||
};
|
|
||||||
static const int16_t y_land[5] = {-8, 55, 118, 181, 244};
|
|
||||||
#define FIRST_ONSCREEN_COLUMN 5
|
|
||||||
#define TILE_SIZEX 14
|
|
||||||
|
|
||||||
/* ---- Атласы Kid (прямая адресация image>>3) ------------------------ */
|
/* ---- Атласы Kid (прямая адресация image>>3) ------------------------ */
|
||||||
#define KID_MAXPAGES 28
|
#define KID_MAXPAGES 28
|
||||||
@@ -75,8 +72,90 @@ void pop_kid_free(void)
|
|||||||
kid_npages = 0;
|
kid_npages = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- seqtbl-доступ (база SEQTBL_BASE) ------------------------------ */
|
/* ---- Данные анимации в EMM-странице (kid_data.bin) ------------------ *
|
||||||
#define SEQ(cs) kid_seqtbl[(uint16_t)((cs) - SEQTBL_BASE)]
|
* Таблица кадров (241*5 Б) и seqtbl (2310 Б) занимали 3.5 КБ в _CODE окна
|
||||||
|
* W1/W2 — самый дефицитный ресурс. Теперь они лежат в отдельной EMM-
|
||||||
|
* странице, которая маппится в W0 РОВНО на время play_seq (раз за тик), а
|
||||||
|
* весь остальной код читает cur_frame — 5-байтовую копию текущего кадра.
|
||||||
|
* Это ровно устройство оригинала: load_frame (seg006) заполняет cur_frame,
|
||||||
|
* и коллизия/отрисовка работают с ним, а не с таблицей.
|
||||||
|
* Страница адресуется как у pop_level: данные с 0x100, ниже — ISR-стаб. */
|
||||||
|
extern void _gfx_w0_isr(void);
|
||||||
|
|
||||||
|
#define KD_DATA_OFF 0x100u
|
||||||
|
/* Адрес кадра i в замапленной странице. Считаем В uint16_t и кастуем ОДИН
|
||||||
|
* раз: запись `(const uint8_t *)CONST + (uint16_t)i * 5u` SDCC 4.5 собирает
|
||||||
|
* НЕВЕРНО — умножение делает в 16 битах (add hl,hl / add hl,bc), а потом
|
||||||
|
* берёт только МЛАДШИЙ байт результата и подставляет старший байт константы
|
||||||
|
* (`ld c,l` / `inc b`). Для кадров i >= 52 (i*5 >= 256) адрес уезжает на
|
||||||
|
* −256*k, и cur_frame наполняется чужой строкой таблицы: у бега/шага/подъёма
|
||||||
|
* пропадал бит FRAME_NEEDS_FLOOR, и Kid проваливался сквозь пол.
|
||||||
|
* Артефакт: .sprinter-cc-roomtest/pop_kid.asm, функция load_frame. */
|
||||||
|
static const uint8_t *kd_frame_ptr(uint8_t i)
|
||||||
|
{
|
||||||
|
uint16_t off = (uint16_t)i;
|
||||||
|
off += (uint16_t)(off << 2); /* i*5 = i + i*4, без умножения */
|
||||||
|
off += (uint16_t)(KD_DATA_OFF + KID_BIN_FRAMES_OFF);
|
||||||
|
return (const uint8_t *)off;
|
||||||
|
}
|
||||||
|
#define KD_SEQ(cs) (*((const uint8_t *)(KD_DATA_OFF + KID_BIN_SEQTBL_OFF) + \
|
||||||
|
(uint16_t)((cs) - SEQTBL_BASE)))
|
||||||
|
/* Байт seqtbl по адресу оригинала (база SEQTBL_BASE); ТОЛЬКО под замапленной
|
||||||
|
* страницей данных — то есть внутри play_seq. */
|
||||||
|
#define SEQ(cs) KD_SEQ(cs)
|
||||||
|
|
||||||
|
static uint8_t kdat_blk, kdat_page, kdat_ok;
|
||||||
|
|
||||||
|
/* Текущий кадр (порт глобала cur_frame, seg006): 5 байт вместо таблицы. */
|
||||||
|
static kframe cur_frame;
|
||||||
|
|
||||||
|
int pop_kid_data_load(const char *path)
|
||||||
|
{
|
||||||
|
uint8_t *pg = (uint8_t *)0xC000; /* страница мапится в W3 на время чтения */
|
||||||
|
uint8_t saved_w3, blk;
|
||||||
|
uint16_t stub;
|
||||||
|
int fd, n;
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd < 0) return -1;
|
||||||
|
blk = mem_alloc_pages(1);
|
||||||
|
if (!blk) { close(fd); return -1; }
|
||||||
|
kdat_blk = blk;
|
||||||
|
kdat_page = mem_get_page(blk, 0);
|
||||||
|
|
||||||
|
saved_w3 = _io_page_w3;
|
||||||
|
sprinter_page_w3(kdat_page);
|
||||||
|
n = read(fd, pg + KD_DATA_OFF, 16384 - KD_DATA_OFF);
|
||||||
|
if (n >= (int)(KID_BIN_SEQTBL_OFF + KID_SEQTBL_LEN)) {
|
||||||
|
stub = (uint16_t)&_gfx_w0_isr; /* ISR-стаб W0-страницы (как pop_level) */
|
||||||
|
pg[0x38] = 0xC3;
|
||||||
|
pg[0x39] = (uint8_t)(stub & 0xFF);
|
||||||
|
pg[0x3A] = (uint8_t)(stub >> 8);
|
||||||
|
pg[0x66] = 0xED; pg[0x67] = 0x45; /* RETN */
|
||||||
|
}
|
||||||
|
sprinter_page_w3(saved_w3);
|
||||||
|
close(fd);
|
||||||
|
if (n < (int)(KID_BIN_SEQTBL_OFF + KID_SEQTBL_LEN)) { mem_free_block(blk); return -1; }
|
||||||
|
kdat_ok = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_kid_data_free(void)
|
||||||
|
{
|
||||||
|
if (kdat_ok) { mem_free_block(kdat_blk); kdat_ok = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load_frame (seg006:0293): скопировать кадр Kid.frame из таблицы в
|
||||||
|
* cur_frame. Звать ТОЛЬКО когда страница данных замаплена в W0. */
|
||||||
|
static void load_frame(void)
|
||||||
|
{
|
||||||
|
const uint8_t *f = kd_frame_ptr(Kid.frame);
|
||||||
|
cur_frame.image = f[0];
|
||||||
|
cur_frame.dx = (int8_t)f[1];
|
||||||
|
cur_frame.dy = (int8_t)f[2];
|
||||||
|
cur_frame.flags = f[3];
|
||||||
|
cur_frame.sword = f[4];
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t char_dx_forward(int8_t dx)
|
static uint8_t char_dx_forward(int8_t dx)
|
||||||
{
|
{
|
||||||
@@ -84,17 +163,23 @@ static uint8_t char_dx_forward(int8_t dx)
|
|||||||
return (uint8_t)(Kid.x + dx);
|
return (uint8_t)(Kid.x + dx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Аксессоры к текущему кадру (для pop_map — без дублирования kid_frames). */
|
/* Аксессоры к текущему кадру (для pop_map): читают cur_frame, НЕ таблицу —
|
||||||
int8_t kid_cur_dx(void) { return kid_frames[Kid.frame].dx; }
|
* их дёргают несколько раз за кадр, маппинг страницы тут недопустим. */
|
||||||
uint8_t kid_cur_flags(void) { return kid_frames[Kid.frame].flags; }
|
int8_t kid_cur_dx(void) { return cur_frame.dx; }
|
||||||
|
uint8_t kid_cur_flags(void) { return cur_frame.flags; }
|
||||||
|
|
||||||
/* seqtbl_offset_char: сменить последовательность Kid (единая точка —
|
/* seqtbl_offset_char: сменить последовательность Kid (единая точка —
|
||||||
* pop_ctrl/pop_map зовут ЕЁ, а не дублируют kid_seq_off/kid_seqtbl). */
|
* pop_ctrl/pop_map зовут ЕЁ, а не дублируют kid_seq_off/kid_seqtbl). */
|
||||||
void kid_set_seq(uint8_t seq_id) { Kid.curr_seq = kid_seq_off[seq_id]; }
|
void kid_set_seq(uint8_t seq_id) { Kid.curr_seq = kid_seq_off[seq_id]; }
|
||||||
|
|
||||||
/* play_seq (seg006.c:570): крутит опкоды до КАДРА (байт < 0xF0). */
|
/* play_seq (seg006.c:570): крутит опкоды до КАДРА (байт < 0xF0).
|
||||||
|
* Страница данных маппится в W0 на ВЕСЬ разбор — один map/unmap за вызов
|
||||||
|
* (в тике, до отрисовки: конфликта с атласом в W0 нет). В конце —
|
||||||
|
* load_frame: пока страница ещё замаплена, копируем кадр в cur_frame. */
|
||||||
void play_seq(void)
|
void play_seq(void)
|
||||||
{
|
{
|
||||||
|
if (!kdat_ok) return;
|
||||||
|
gfx_w0_map(kdat_page);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint8_t cmd = SEQ(Kid.curr_seq);
|
uint8_t cmd = SEQ(Kid.curr_seq);
|
||||||
Kid.curr_seq++;
|
Kid.curr_seq++;
|
||||||
@@ -154,6 +239,8 @@ void play_seq(void)
|
|||||||
break;
|
break;
|
||||||
default: /* КАДР */
|
default: /* КАДР */
|
||||||
Kid.frame = cmd;
|
Kid.frame = cmd;
|
||||||
|
load_frame(); /* cur_frame := таблица[frame] (страница ещё в W0) */
|
||||||
|
gfx_w0_unmap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,8 +251,8 @@ void kid_init(uint8_t seq_id, int8_t col, int8_t row, int8_t dir)
|
|||||||
Kid.curr_col = col;
|
Kid.curr_col = col;
|
||||||
Kid.curr_row = row;
|
Kid.curr_row = row;
|
||||||
Kid.direction = dir;
|
Kid.direction = dir;
|
||||||
Kid.x = (uint8_t)(x_bump[col + FIRST_ONSCREEN_COLUMN] + TILE_SIZEX);
|
Kid.x = (uint8_t)(pop_x_bump[col + FIRST_ONSCREEN_COLUMN] + TILE_SIZEX);
|
||||||
Kid.y = (uint8_t)y_land[row + 1];
|
Kid.y = (uint8_t)pop_y_land[row + 1];
|
||||||
Kid.fall_x = Kid.fall_y = 0;
|
Kid.fall_x = Kid.fall_y = 0;
|
||||||
Kid.repeat = 0;
|
Kid.repeat = 0;
|
||||||
Kid.curr_seq = kid_seq_off[seq_id];
|
Kid.curr_seq = kid_seq_off[seq_id];
|
||||||
@@ -280,7 +367,7 @@ void kid_heal(void)
|
|||||||
|
|
||||||
void kid_draw(void)
|
void kid_draw(void)
|
||||||
{
|
{
|
||||||
kframe fr = kid_frames[Kid.frame];
|
kframe fr = cur_frame; /* load_frame уже положил кадр (play_seq) */
|
||||||
int fwd, obj_x, obj_y, top;
|
int fwd, obj_x, obj_y, top;
|
||||||
uint8_t page, idx;
|
uint8_t page, idx;
|
||||||
const uint8_t *img;
|
const uint8_t *img;
|
||||||
|
|||||||
@@ -34,6 +34,13 @@ extern int8_t knock;
|
|||||||
* 0 — OK, -1 — ошибка. */
|
* 0 — OK, -1 — ошибка. */
|
||||||
int pop_kid_load(uint8_t npages);
|
int pop_kid_load(uint8_t npages);
|
||||||
|
|
||||||
|
/* Данные анимации (таблица кадров + seqtbl) — отдельная EMM-страница
|
||||||
|
* (kid_data.bin): в _CODE окна W1/W2 они занимали 3.5 КБ. Грузить ДО
|
||||||
|
* первого kid_init/play_seq. 0 — OK, -1 — ошибка (без них Kid не оживёт).
|
||||||
|
* Страница маппится в W0 внутри play_seq, раз за тик. */
|
||||||
|
int pop_kid_data_load(const char *path);
|
||||||
|
void pop_kid_data_free(void);
|
||||||
|
|
||||||
/* Атлас chtab_0 «меч в руке» (sword.atl) — спрайт клинка поверх Kid в кадрах
|
/* Атлас chtab_0 «меч в руке» (sword.atl) — спрайт клинка поверх Kid в кадрах
|
||||||
* подъёма меча/убирания в ножны (add_sword_to_objtable, seg006:1798).
|
* подъёма меча/убирания в ножны (add_sword_to_objtable, seg006:1798).
|
||||||
* Грузить ДО initgraph, как и страницы Kid. 0 — OK, -1 — ошибка (тогда
|
* Грузить ДО initgraph, как и страницы Kid. 0 — OK, -1 — ошибка (тогда
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* FRAME_NEEDS_FLOOR (0x40), под персонажем не floor -> start_fall();
|
* FRAME_NEEDS_FLOOR (0x40), под персонажем не floor -> start_fall();
|
||||||
* стена -> in_wall();
|
* стена -> in_wall();
|
||||||
* freefall (action 4) -> do_fall(): fall_y-ускорение (в fall_accel/speed),
|
* freefall (action 4) -> do_fall(): fall_y-ускорение (в fall_accel/speed),
|
||||||
* достиг y_land[curr_row+1] -> land()/inc_curr_row.
|
* достиг pop_y_land[curr_row+1] -> land()/inc_curr_row.
|
||||||
*
|
*
|
||||||
* Координатная система PoP: экран.left = 58, тайл = 14 ед. (TILE_SIZEX);
|
* Координатная система PoP: экран.left = 58, тайл = 14 ед. (TILE_SIZEX);
|
||||||
* col = (xpos-58)/14 (округл. вниз), xl = остаток; get_tile_div_mod_m7 =
|
* col = (xpos-58)/14 (округл. вниз), xl = остаток; get_tile_div_mod_m7 =
|
||||||
@@ -19,7 +19,15 @@
|
|||||||
#include "pop_kid.h"
|
#include "pop_kid.h"
|
||||||
#include "pop_map.h"
|
#include "pop_map.h"
|
||||||
#include "pop_ctrl.h" /* pop_ctrl_shift_held() — для check_grab */
|
#include "pop_ctrl.h" /* pop_ctrl_shift_held() — для check_grab */
|
||||||
#include "pop_bg.h" /* pop_loose_shake_draw/bake_empty — перерисовка */
|
#include "pop_geom.h" /* общая геометрия (x_bump/y_land/y_to_row) */
|
||||||
|
#include "pop_redraw.h" /* пометки перерисовки (порт set_redraw_*) */
|
||||||
|
/* pop_bg нужен ТОЛЬКО падающему куску (mob): spawn/tick/pos — это движущийся
|
||||||
|
* ОБЪЕКТ, а не перерисовка тайла (в оригинале он и живёт отдельно: mobs +
|
||||||
|
* draw_moving). Из-за него pop_loose_tick — единственная функция модуля,
|
||||||
|
* которую нельзя звать из __banked-кода; вся коллизия/физика/предметы, то
|
||||||
|
* есть то, что понадобится стражам, чиста от графики. Разделение mob на
|
||||||
|
* логику и отрисовку — задел следующей фазы. */
|
||||||
|
#include "pop_bg.h"
|
||||||
#include "pop_trob.h" /* room_modif + trob-список (пики/ворота) */
|
#include "pop_trob.h" /* room_modif + trob-список (пики/ворота) */
|
||||||
|
|
||||||
/* ---- Тайлы / действия / seq id (подмножество PoP) ------------------ */
|
/* ---- Тайлы / действия / seq id (подмножество PoP) ------------------ */
|
||||||
@@ -81,23 +89,17 @@
|
|||||||
|
|
||||||
#define FRAME_NEEDS_FLOOR 0x40
|
#define FRAME_NEEDS_FLOOR 0x40
|
||||||
#define FRAME_WEIGHT_X 0x1F
|
#define FRAME_WEIGHT_X 0x1F
|
||||||
#define TILE_SIZEX 14
|
|
||||||
#define TILE_RIGHTX 13
|
#define TILE_RIGHTX 13
|
||||||
#define SCREENSPACE_X 58
|
#define SCREENSPACE_X 58
|
||||||
#define FALL_ACCEL 3
|
#define FALL_ACCEL 3
|
||||||
#define FALL_MAX 33
|
#define FALL_MAX 33
|
||||||
|
|
||||||
#define TILE_MIDX 7
|
#define TILE_MIDX 7
|
||||||
#define FIRST_ONSCREEN_COLUMN 5
|
|
||||||
#define FRAME_THIN 0x20
|
#define FRAME_THIN 0x20
|
||||||
|
|
||||||
static const int16_t y_land[5] = {-8, 55, 118, 181, 244};
|
|
||||||
static const int8_t dir_front[2] = {-1, 1}; /* [dir+1]: dir=-1->-1, 0->+1 */
|
static const int8_t dir_front[2] = {-1, 1}; /* [dir+1]: dir=-1->-1, 0->+1 */
|
||||||
static const int8_t dir_behind[2] = {1, -1}; /* [dir+1]: назад по направлению */
|
static const int8_t dir_behind[2] = {1, -1}; /* [dir+1]: назад по направлению */
|
||||||
static const int16_t x_bump[20] = {
|
|
||||||
-12, 2, 16, 30, 44, 58, 72, 86, 100, 114,
|
|
||||||
128, 142, 156, 170, 184, 198, 212, 226, 240, 254
|
|
||||||
};
|
|
||||||
/* wall_type(tile): gate/doortop=1, mirror=2, chomper=3, wall=4, иначе 0. */
|
/* wall_type(tile): gate/doortop=1, mirror=2, chomper=3, wall=4, иначе 0. */
|
||||||
static const int8_t wall_dl[6] = {0, 10, 0, -1, 0, 0}; /* wall_dist_from_left */
|
static const int8_t wall_dl[6] = {0, 10, 0, -1, 0, 0}; /* wall_dist_from_left */
|
||||||
static const int8_t wall_dr[6] = {0, 0, 10, 13, 0, 0}; /* wall_dist_from_right */
|
static const int8_t wall_dr[6] = {0, 0, 10, 13, 0, 0}; /* wall_dist_from_right */
|
||||||
@@ -142,11 +144,9 @@ static uint8_t g_lcol[6], g_rcol[6];
|
|||||||
* отдельное — pop_ceil_modif[col] с той же семантикой (0 покой, 0x80.. —
|
* отдельное — pop_ceil_modif[col] с той же семантикой (0 покой, 0x80.. —
|
||||||
* тряска, 1..11 — отсчёт до падения). */
|
* тряска, 1..11 — отсчёт до падения). */
|
||||||
uint8_t pop_ceil_modif[10]; /* публично: читает pop_bg при отрисовке */
|
uint8_t pop_ceil_modif[10]; /* публично: читает pop_bg при отрисовке */
|
||||||
static uint8_t ceil_rest[10]; /* «перерисовать ПОКОЙ» (2 = обе страницы) */
|
|
||||||
static uint8_t ceil_bake[10]; /* «запечь колодец» на второй странице */
|
|
||||||
static uint8_t land_bake, land_bake_pos; /* щебень от приземления — вторая страница */
|
|
||||||
static uint8_t *g_above; /* ряд 2 комнаты сверху (fg), мутабельный */
|
static uint8_t *g_above; /* ряд 2 комнаты сверху (fg), мутабельный */
|
||||||
uint8_t pop_ceil_fell; /* 0 = нет; иначе col+1 провалившейся плиты-потолка */
|
uint8_t pop_ceil_fell; /* 0 = нет; иначе col+1 провалившейся плиты-потолка */
|
||||||
|
|
||||||
uint8_t pop_debris_at; /* 0 = нет; иначе tilepos+1 нового щебня в ЭТОЙ комнате */
|
uint8_t pop_debris_at; /* 0 = нет; иначе tilepos+1 нового щебня в ЭТОЙ комнате */
|
||||||
|
|
||||||
void pop_map_set_above(uint8_t *above_row2_fg) { g_above = above_row2_fg; }
|
void pop_map_set_above(uint8_t *above_row2_fg) { g_above = above_row2_fg; }
|
||||||
@@ -367,7 +367,7 @@ static int dist_from_wall_forward(uint8_t tiletype, int8_t tcol)
|
|||||||
uint8_t type = wall_type(tiletype);
|
uint8_t type = wall_type(tiletype);
|
||||||
int coll_left, cx;
|
int coll_left, cx;
|
||||||
if (type == 0) return 127;
|
if (type == 0) return 127;
|
||||||
coll_left = x_bump[tcol + FIRST_ONSCREEN_COLUMN] + TILE_MIDX;
|
coll_left = pop_x_bump[tcol + FIRST_ONSCREEN_COLUMN] + TILE_MIDX;
|
||||||
cx = char_front_coll();
|
cx = char_front_coll();
|
||||||
if (Kid.direction < 0) /* лицом влево */
|
if (Kid.direction < 0) /* лицом влево */
|
||||||
return cx - (coll_left + TILE_RIGHTX - wall_dr[type]);
|
return cx - (coll_left + TILE_RIGHTX - wall_dr[type]);
|
||||||
@@ -423,7 +423,7 @@ static uint8_t fell_on_spikes(void)
|
|||||||
static void land(void)
|
static void land(void)
|
||||||
{
|
{
|
||||||
uint8_t seq;
|
uint8_t seq;
|
||||||
Kid.y = (uint8_t)y_land[Kid.curr_row + 1];
|
Kid.y = (uint8_t)pop_y_land[Kid.curr_row + 1];
|
||||||
if (fell_on_spikes()) return; /* упал на вредные пики — смерть */
|
if (fell_on_spikes()) return; /* упал на вредные пики — смерть */
|
||||||
/* к краю пола — чуть назад (как оригинал) */
|
/* к краю пола — чуть назад (как оригинал) */
|
||||||
if (!tile_is_floor(get_tile_infrontof_char()) && distance_to_edge_weight() < 3)
|
if (!tile_is_floor(get_tile_infrontof_char()) && distance_to_edge_weight() < 3)
|
||||||
@@ -518,7 +518,7 @@ static void check_grab(void)
|
|||||||
uint8_t old_x;
|
uint8_t old_x;
|
||||||
if (!pop_ctrl_shift_held()) return; /* Shift не зажат */
|
if (!pop_ctrl_shift_held()) return; /* Shift не зажат */
|
||||||
if ((uint8_t)Kid.fall_y >= 32) return; /* падает слишком быстро */
|
if ((uint8_t)Kid.fall_y >= 32) return; /* падает слишком быстро */
|
||||||
if ((uint16_t)y_land[Kid.curr_row + 1] > (uint16_t)(Kid.y + 25)) return;
|
if ((uint16_t)pop_y_land[Kid.curr_row + 1] > (uint16_t)(Kid.y + 25)) return;
|
||||||
old_x = Kid.x;
|
old_x = Kid.x;
|
||||||
Kid.x = (uint8_t)char_dx_forward(-8);
|
Kid.x = (uint8_t)char_dx_forward(-8);
|
||||||
determine_col();
|
determine_col();
|
||||||
@@ -527,7 +527,7 @@ static void check_grab(void)
|
|||||||
determine_col();
|
determine_col();
|
||||||
} else {
|
} else {
|
||||||
Kid.x = (uint8_t)char_dx_forward((int8_t)distance_to_edge_weight());
|
Kid.x = (uint8_t)char_dx_forward((int8_t)distance_to_edge_weight());
|
||||||
Kid.y = (uint8_t)y_land[Kid.curr_row + 1];
|
Kid.y = (uint8_t)pop_y_land[Kid.curr_row + 1];
|
||||||
Kid.fall_y = 0;
|
Kid.fall_y = 0;
|
||||||
kid_set_seq(SEQ_15_GRAB_LEDGE_MIDAIR);
|
kid_set_seq(SEQ_15_GRAB_LEDGE_MIDAIR);
|
||||||
play_seq();
|
play_seq();
|
||||||
@@ -539,8 +539,8 @@ static void check_grab(void)
|
|||||||
static void do_fall(void)
|
static void do_fall(void)
|
||||||
{
|
{
|
||||||
uint8_t nrow = (uint8_t)(Kid.curr_row + 1);
|
uint8_t nrow = (uint8_t)(Kid.curr_row + 1);
|
||||||
if (nrow > 4) nrow = 4; /* защита y_land[] от выхода */
|
if (nrow > 4) nrow = 4; /* защита pop_y_land[] от выхода */
|
||||||
if ((uint16_t)y_land[nrow] > (uint16_t)Kid.y) {
|
if ((uint16_t)pop_y_land[nrow] > (uint16_t)Kid.y) {
|
||||||
check_grab(); /* ещё летит — попытка зацепа */
|
check_grab(); /* ещё летит — попытка зацепа */
|
||||||
} else {
|
} else {
|
||||||
if (get_tile_at_char() == TILE_WALL)
|
if (get_tile_at_char() == TILE_WALL)
|
||||||
@@ -900,11 +900,11 @@ static void bumped_floor(void)
|
|||||||
uint8_t frame;
|
uint8_t frame;
|
||||||
/* Оригинал сравнивает БЕЗЗНАКОВО: если персонаж НИЖЕ уровня пола,
|
/* Оригинал сравнивает БЕЗЗНАКОВО: если персонаж НИЖЕ уровня пола,
|
||||||
* разность заворачивается в большое число и тоже даёт «падать». */
|
* разность заворачивается в большое число и тоже даёт «падать». */
|
||||||
if ((uint16_t)(y_land[Kid.curr_row + 1] - (int16_t)Kid.y) >= 15) {
|
if ((uint16_t)(pop_y_land[Kid.curr_row + 1] - (int16_t)Kid.y) >= 15) {
|
||||||
bumped_fall(); /* высоко над полом — в воздухе */
|
bumped_fall(); /* высоко над полом — в воздухе */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Kid.y = (uint8_t)y_land[Kid.curr_row + 1]; /* ПРИЖАТЬ к полу */
|
Kid.y = (uint8_t)pop_y_land[Kid.curr_row + 1]; /* ПРИЖАТЬ к полу */
|
||||||
if (Kid.fall_y >= 22) { /* влетел быстро — только отжать */
|
if (Kid.fall_y >= 22) { /* влетел быстро — только отжать */
|
||||||
Kid.x = (uint8_t)char_dx_forward(-5);
|
Kid.x = (uint8_t)char_dx_forward(-5);
|
||||||
return;
|
return;
|
||||||
@@ -942,7 +942,7 @@ static void check_bumped(void)
|
|||||||
* hang->hang_fall->seq_11 (правильное приземление). */
|
* hang->hang_fall->seq_11 (правильное приземление). */
|
||||||
if (Kid.frame >= 87 && Kid.frame < 100) return;
|
if (Kid.frame >= 87 && Kid.frame < 100) return;
|
||||||
/* Вне рядов комнаты (падение мимо пола): get_tile даёт WALL, а
|
/* Вне рядов комнаты (падение мимо пола): get_tile даёт WALL, а
|
||||||
* dist_from_wall_forward/x_bump[] — мусор с большим отриц. сдвигом →
|
* dist_from_wall_forward/pop_x_bump[] — мусор с большим отриц. сдвигом →
|
||||||
* underflow X и уход в стену. fell_out ловит do_fall. */
|
* underflow X и уход в стену. fell_out ловит do_fall. */
|
||||||
if (Kid.curr_row < 0 || Kid.curr_row > 2) return;
|
if (Kid.curr_row < 0 || Kid.curr_row > 2) return;
|
||||||
/* seg004 check_collisions: на кадрах разворота коллизии НЕ считаются
|
/* seg004 check_collisions: на кадрах разворота коллизии НЕ считаются
|
||||||
@@ -973,7 +973,7 @@ static void check_bumped(void)
|
|||||||
{
|
{
|
||||||
uint8_t f = 0, prev, need;
|
uint8_t f = 0, prev, need;
|
||||||
if (wt) {
|
if (wt) {
|
||||||
int coll_left = x_bump[tcol + FIRST_ONSCREEN_COLUMN] + TILE_MIDX;
|
int coll_left = pop_x_bump[tcol + FIRST_ONSCREEN_COLUMN] + TILE_MIDX;
|
||||||
int lw = wall_dl[wt] + coll_left; /* get_left_wall_xpos */
|
int lw = wall_dl[wt] + coll_left; /* get_left_wall_xpos */
|
||||||
int rw = coll_left - wall_dr[wt] + TILE_RIGHTX; /* get_right_wall_xpos */
|
int rw = coll_left - wall_dr[wt] + TILE_RIGHTX; /* get_right_wall_xpos */
|
||||||
int e = char_x_forward_edge(), wh = ((int)kid_fp_width() + 1) >> 1;
|
int e = char_x_forward_edge(), wh = ((int)kid_fp_width() + 1) >> 1;
|
||||||
@@ -1027,8 +1027,6 @@ static void check_bumped(void)
|
|||||||
* отсчёт до падения (на тайле стоят/пробили). Порт animate_loose/
|
* отсчёт до падения (на тайле стоят/пробили). Порт animate_loose/
|
||||||
* make_loose_fall/check_press. Перерисовка — в pop_bg (shake/bake). */
|
* make_loose_fall/check_press. Перерисовка — в pop_bg (shake/bake). */
|
||||||
uint8_t pop_loose_modif[30]; /* публично: читает pop_bg при отрисовке */
|
uint8_t pop_loose_modif[30]; /* публично: читает pop_bg при отрисовке */
|
||||||
static uint8_t loose_bake[30]; /* счётчик «запечь пусто» (2 = обе страницы) */
|
|
||||||
static uint8_t loose_rest[30]; /* счётчик «перерисовать ПОКОЙ» после тряски (2 = обе стр.) */
|
|
||||||
|
|
||||||
/* Плита-ПОТОЛОК: состояние/сигналы — см. объявления перед get_tile. */
|
/* Плита-ПОТОЛОК: состояние/сигналы — см. объявления перед get_tile. */
|
||||||
|
|
||||||
@@ -1131,18 +1129,13 @@ void pop_loose_reset(void)
|
|||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 30; i++) {
|
for (i = 0; i < 30; i++) {
|
||||||
pop_loose_modif[i] = 0;
|
pop_loose_modif[i] = 0;
|
||||||
loose_bake[i] = 0;
|
|
||||||
loose_rest[i] = 0;
|
|
||||||
}
|
}
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
pop_ceil_modif[i] = 0;
|
pop_ceil_modif[i] = 0;
|
||||||
ceil_rest[i] = 0;
|
|
||||||
ceil_bake[i] = 0;
|
|
||||||
}
|
}
|
||||||
pop_ceil_fell = 0;
|
pop_ceil_fell = 0;
|
||||||
pop_debris_at = 0;
|
pop_debris_at = 0;
|
||||||
pop_loose_landed = 0;
|
pop_loose_landed = 0;
|
||||||
land_bake = 0;
|
|
||||||
pop_loose_mob_reset();
|
pop_loose_mob_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1159,7 +1152,7 @@ static void fell_on_your_head(void)
|
|||||||
uint8_t frame = Kid.frame, action = Kid.action;
|
uint8_t frame = Kid.frame, action = Kid.action;
|
||||||
if ((frame < 5 || frame >= 15) &&
|
if ((frame < 5 || frame >= 15) &&
|
||||||
(action < ACT_HANGCLIMB || action == ACT_TURN)) {
|
(action < ACT_HANGCLIMB || action == ACT_TURN)) {
|
||||||
Kid.y = (uint8_t)y_land[Kid.curr_row + 1];
|
Kid.y = (uint8_t)pop_y_land[Kid.curr_row + 1];
|
||||||
pop_kid_hurt = 1; /* hitp_delta<0 → draw_hurt_splash */
|
pop_kid_hurt = 1; /* hitp_delta<0 → draw_hurt_splash */
|
||||||
if (take_hp(1)) {
|
if (take_hp(1)) {
|
||||||
kid_set_seq(SEQ_22_CRUSHED);
|
kid_set_seq(SEQ_22_CRUSHED);
|
||||||
@@ -1201,24 +1194,17 @@ void pop_loose_tick(void)
|
|||||||
* Инкремент+сравнение считают row/col без деления. */
|
* Инкремент+сравнение считают row/col без деления. */
|
||||||
uint8_t row = 0, col = 0;
|
uint8_t row = 0, col = 0;
|
||||||
for (pos = 0; pos < 30; pos++) {
|
for (pos = 0; pos < 30; pos++) {
|
||||||
if (loose_bake[pos]) { /* упал: запечь пусто (2 кадра=2 стр.) */
|
if (pop_loose_modif[pos] != 0) {
|
||||||
pop_loose_bake_empty(row, col);
|
|
||||||
loose_bake[pos]--;
|
|
||||||
} else if (loose_rest[pos]) { /* тряска кончилась: перерисовать ПОКОЙ */
|
|
||||||
/* modif уже 0 → shake_draw рисует базовый кадр (покой) обоих тайлов
|
|
||||||
* (col и col+1: правая грань loose живёт в 2,7). 2 кадра = обе
|
|
||||||
* страницы дабл-буфера — иначе на одной остаётся застывший
|
|
||||||
* дрожащий кадр правой грани → мерцание («бесконечная тряска»). */
|
|
||||||
pop_loose_shake_draw(row, col);
|
|
||||||
loose_rest[pos]--;
|
|
||||||
} else if (pop_loose_modif[pos] != 0) {
|
|
||||||
uint8_t m = ++pop_loose_modif[pos];
|
uint8_t m = ++pop_loose_modif[pos];
|
||||||
if (m & 0x80) { /* тряска (do_knock) */
|
if (m & 0x80) { /* тряска (do_knock) */
|
||||||
if (m >= 0x84) { /* конец тряски: сброс + перерисовать покой */
|
if (m >= 0x84) { /* конец тряски: сброс + покой */
|
||||||
pop_loose_modif[pos] = 0;
|
pop_loose_modif[pos] = 0;
|
||||||
loose_rest[pos] = 2; /* покой на ОБЕИХ страницах */
|
/* modif уже 0 → кадр покоя обоих тайлов (col и col+1:
|
||||||
|
* правая грань loose живёт в соседе). ОБЕ страницы —
|
||||||
|
* иначе на одной застывает дрожащий кадр → мерцание. */
|
||||||
|
pop_set_redraw(pos, POP_RD_LOOSE, 2);
|
||||||
} else {
|
} else {
|
||||||
pop_loose_shake_draw(row, col); /* дрожащий кадр */
|
pop_set_redraw(pos, POP_RD_LOOSE, 1); /* дрожащий кадр */
|
||||||
}
|
}
|
||||||
} else if (m >= 11) { /* loose_floor_delay — падение */
|
} else if (m >= 11) { /* loose_floor_delay — падение */
|
||||||
/* remove_loose (seg007:0EB8): тайл → EMPTY (не debris!).
|
/* remove_loose (seg007:0EB8): тайл → EMPTY (не debris!).
|
||||||
@@ -1228,12 +1214,11 @@ void pop_loose_tick(void)
|
|||||||
* (стена-вниз от тайла снизу + чёрный фон). */
|
* (стена-вниз от тайла снизу + чёрный фон). */
|
||||||
g_fg[pos] = TILE_EMPTY;
|
g_fg[pos] = TILE_EMPTY;
|
||||||
pop_loose_modif[pos] = 0;
|
pop_loose_modif[pos] = 0;
|
||||||
pop_loose_bake_empty(row, col); /* запечь пусто на ТЕКУЩЕЙ странице сразу */
|
pop_set_redraw(pos, POP_RD_LOOSE_GONE, 2); /* запечь пусто, обе стр. */
|
||||||
loose_bake[pos] = 1; /* + вторая страница следующим кадром */
|
pop_loose_mob_spawn(row, col); /* отрыв падающего куска */
|
||||||
pop_loose_mob_spawn(row, col); /* отрыв падающего куска (L4) */
|
pop_loose_fell = (uint8_t)(pos + 1); /* сигнал приложению */
|
||||||
pop_loose_fell = (uint8_t)(pos + 1); /* сигнал приложению: кусок улетел */
|
|
||||||
} else { /* отсчёт 1..10 — дрожащий кадр */
|
} else { /* отсчёт 1..10 — дрожащий кадр */
|
||||||
pop_loose_shake_draw(row, col);
|
pop_set_redraw(pos, POP_RD_LOOSE, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (++col == 10) { col = 0; row++; } /* row/col без деления */
|
if (++col == 10) { col = 0; row++; } /* row/col без деления */
|
||||||
@@ -1242,27 +1227,21 @@ void pop_loose_tick(void)
|
|||||||
* рисуются в полосе у потолка, а провалившаяся плита становится EMPTY в
|
* рисуются в полосе у потолка, а провалившаяся плита становится EMPTY в
|
||||||
* НАШЕЙ копии ряда (g_above) — сверху открывается колодец. */
|
* НАШЕЙ копии ряда (g_above) — сверху открывается колодец. */
|
||||||
for (col = 0; col < 10; col++) {
|
for (col = 0; col < 10; col++) {
|
||||||
if (ceil_rest[col]) {
|
if (pop_ceil_modif[col] != 0) {
|
||||||
pop_ceil_shake_draw(col); /* modif уже 0 → кадр покоя */
|
|
||||||
ceil_rest[col]--;
|
|
||||||
} else if (pop_ceil_modif[col] != 0) {
|
|
||||||
uint8_t m = ++pop_ceil_modif[col];
|
uint8_t m = ++pop_ceil_modif[col];
|
||||||
if (m & 0x80) { /* тряска от сотрясения (do_knock) */
|
if (m & 0x80) { /* тряска от сотрясения (do_knock) */
|
||||||
if (m >= 0x84) { pop_ceil_modif[col] = 0; ceil_rest[col] = 2; }
|
if (m >= 0x84) { pop_ceil_modif[col] = 0;
|
||||||
else pop_ceil_shake_draw(col);
|
pop_set_redraw_above(col, POP_RDA_CEIL, 2); }
|
||||||
|
else pop_set_redraw_above(col, POP_RDA_CEIL, 1);
|
||||||
} else if (m >= 11) { /* loose_floor_delay — плита рушится */
|
} else if (m >= 11) { /* loose_floor_delay — плита рушится */
|
||||||
pop_ceil_modif[col] = 0;
|
pop_ceil_modif[col] = 0;
|
||||||
if (g_above) g_above[col] = TILE_EMPTY; /* remove_loose */
|
if (g_above) g_above[col] = TILE_EMPTY; /* remove_loose */
|
||||||
pop_ceil_bake_empty(col); /* колодец наверх на ТЕКУЩЕЙ странице */
|
pop_set_redraw_above(col, POP_RDA_CEIL_GONE, 2); /* колодец, обе стр. */
|
||||||
ceil_bake[col] = 1; /* + вторая страница следующим кадром */
|
pop_loose_mob_spawn(-1, col); /* кусок отрывается от потолка */
|
||||||
pop_loose_mob_spawn(-1, col); /* кусок отрывается от потолка */
|
|
||||||
pop_ceil_fell = (uint8_t)(col + 1); /* сигнал приложению */
|
pop_ceil_fell = (uint8_t)(col + 1); /* сигнал приложению */
|
||||||
} else {
|
} else {
|
||||||
pop_ceil_shake_draw(col); /* отсчёт 1..10 — дрожащий кадр */
|
pop_set_redraw_above(col, POP_RDA_CEIL, 1); /* отсчёт 1..10 */
|
||||||
}
|
}
|
||||||
} else if (ceil_bake[col]) {
|
|
||||||
pop_ceil_bake_empty(col);
|
|
||||||
ceil_bake[col]--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pop_loose_mob_tick(); /* продвинуть+нарисовать падающий кусок (после тайлов) */
|
pop_loose_mob_tick(); /* продвинуть+нарисовать падающий кусок (после тайлов) */
|
||||||
@@ -1270,34 +1249,22 @@ void pop_loose_tick(void)
|
|||||||
/* Отложенная допечка ПРОШЛОГО приземления на вторую страницу — ПЕРЕД
|
/* Отложенная допечка ПРОШЛОГО приземления на вторую страницу — ПЕРЕД
|
||||||
* разбором нового: иначе при двух плитах, севших подряд, land_bake
|
* разбором нового: иначе при двух плитах, севших подряд, land_bake
|
||||||
* затирался новым и на одной странице оставался старый пол. */
|
* затирался новым и на одной странице оставался старый пол. */
|
||||||
if (land_bake && pop_loose_landed) {
|
|
||||||
uint8_t r = 0, c = land_bake_pos;
|
|
||||||
while (c >= 10) { c -= 10; r++; }
|
|
||||||
pop_floor_bake(r, c);
|
|
||||||
land_bake = 0;
|
|
||||||
}
|
|
||||||
if (pop_loose_landed) { /* loose_land (seg007:11E8): на месте куска — щебень */
|
if (pop_loose_landed) { /* loose_land (seg007:11E8): на месте куска — щебень */
|
||||||
uint8_t pos = (uint8_t)(pop_loose_landed - 1);
|
uint8_t pos = (uint8_t)(pop_loose_landed - 1);
|
||||||
uint8_t r = 0, c = pos;
|
uint8_t r = 0, c = pos;
|
||||||
pop_loose_landed = 0;
|
pop_loose_landed = 0;
|
||||||
while (c >= 10) { c -= 10; r++; }
|
while (c >= 10) { c -= 10; r++; }
|
||||||
g_fg[pos] = TILE_DEBRIS;
|
g_fg[pos] = TILE_DEBRIS;
|
||||||
/* Перерисовка ПО ПЛОЩАДИ ПОЛА (не bake_empty: та стирает и верх стены
|
/* Перерисовка ПО ПЛОЩАДИ ПОЛА (не LOOSE_GONE: та стирает и верх стены
|
||||||
* ряда ниже — оставался чёрный прямоугольник под тайлом). */
|
* ряда ниже — оставался чёрный прямоугольник под тайлом). Обе
|
||||||
pop_floor_bake(r, c);
|
* страницы дабл-буфера. */
|
||||||
land_bake_pos = pos; land_bake = 1; /* вторая страница дабл-буфера */
|
pop_set_redraw(pos, POP_RD_FLOOR, 2);
|
||||||
do_knock(r); /* удар плиты трясёт loose этого ряда */
|
do_knock(r); /* удар плиты трясёт loose этого ряда */
|
||||||
pop_debris_at = (uint8_t)(pos + 1); /* сигнал приложению (персистентность) */
|
pop_debris_at = (uint8_t)(pos + 1); /* сигнал приложению (персистентность) */
|
||||||
} else if (land_bake) {
|
|
||||||
uint8_t r = 0, c = land_bake_pos;
|
|
||||||
while (c >= 10) { c -= 10; r++; }
|
|
||||||
pop_floor_bake(r, c);
|
|
||||||
land_bake = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* y_to_row_mod4 (seg006): ряд по y с оборотом mod4 (TILE_SIZEY=63). */
|
|
||||||
static int8_t y_to_row(int16_t y) { return (int8_t)(((y + 60) / 63) % 4 - 1); }
|
|
||||||
|
|
||||||
/* ---- clip_char (seg006:1749), первый блок: обрезка спрайта СВЕРХУ ----- *
|
/* ---- clip_char (seg006:1749), первый блок: обрезка спрайта СВЕРХУ ----- *
|
||||||
* Оригинал перед add_objtable кладёт в objtable прямоугольник клипа; блиттер
|
* Оригинал перед add_objtable кладёт в objtable прямоугольник клипа; блиттер
|
||||||
@@ -1326,7 +1293,7 @@ int pop_clip_char_top(int obj_x, int obj_y, uint16_t w, uint16_t h)
|
|||||||
xr = xl + wh; /* char_x_right */
|
xr = xl + wh; /* char_x_right */
|
||||||
top_y = obj_y - (int)h + 1; /* char_top_y */
|
top_y = obj_y - (int)h + 1; /* char_top_y */
|
||||||
if (top_y >= 192) top_y = 0; /* весь спрайт ниже комнаты */
|
if (top_y >= 192) top_y = 0; /* весь спрайт ниже комнаты */
|
||||||
trow = y_to_row((int16_t)top_y); /* char_top_row */
|
trow = pop_y_to_row((int16_t)top_y); /* char_top_row */
|
||||||
cL = get_tile_div_mod(xl); if (cL < 0) cL = 0;
|
cL = get_tile_div_mod(xl); if (cL < 0) cL = 0;
|
||||||
cR = get_tile_div_mod(xr); if (cR > 9) cR = 9;
|
cR = get_tile_div_mod(xr); if (cR > 9) cR = 9;
|
||||||
|
|
||||||
@@ -1364,13 +1331,13 @@ static void check_leave_below(void)
|
|||||||
Kid.action != ACT_MIDAIR &&
|
Kid.action != ACT_MIDAIR &&
|
||||||
(int8_t)Kid.y < 10 && (int8_t)Kid.y > -16) {
|
(int8_t)Kid.y < 10 && (int8_t)Kid.y > -16) {
|
||||||
Kid.y = (uint8_t)(Kid.y + 189);
|
Kid.y = (uint8_t)(Kid.y + 189);
|
||||||
Kid.curr_row = y_to_row((int16_t)Kid.y);
|
Kid.curr_row = pop_y_to_row((int16_t)Kid.y);
|
||||||
pop_leave_dir = 3;
|
pop_leave_dir = 3;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Kid.y >= 211) {
|
if (Kid.y >= 211) {
|
||||||
Kid.y = (uint8_t)(Kid.y - 189);
|
Kid.y = (uint8_t)(Kid.y - 189);
|
||||||
Kid.curr_row = y_to_row((int16_t)Kid.y);
|
Kid.curr_row = pop_y_to_row((int16_t)Kid.y);
|
||||||
pop_fell_out = 1;
|
pop_fell_out = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1456,8 +1423,8 @@ static int is_spike_harmful(uint8_t tilepos)
|
|||||||
static void spiked(uint8_t tilepos)
|
static void spiked(uint8_t tilepos)
|
||||||
{
|
{
|
||||||
pop_trob_modif(g_room)[tilepos] = 0xFF;
|
pop_trob_modif(g_room)[tilepos] = 0xFF;
|
||||||
Kid.y = (uint8_t)y_land[Kid.curr_row + 1];
|
Kid.y = (uint8_t)pop_y_land[Kid.curr_row + 1];
|
||||||
Kid.x = (uint8_t)(x_bump[Kid.curr_col + FIRST_ONSCREEN_COLUMN] + 10);
|
Kid.x = (uint8_t)(pop_x_bump[Kid.curr_col + FIRST_ONSCREEN_COLUMN] + 10);
|
||||||
Kid.x = (uint8_t)char_dx_forward(8);
|
Kid.x = (uint8_t)char_dx_forward(8);
|
||||||
Kid.fall_y = 0;
|
Kid.fall_y = 0;
|
||||||
take_hp(100); /* (TODO: sound_48_spiked) */
|
take_hp(100); /* (TODO: sound_48_spiked) */
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* pop_redraw.c — пометки перерисовки тайлов и их разбор. См. pop_redraw.h.
|
||||||
|
*
|
||||||
|
* Живёт в W1/W2 (НЕ в резиденте W3): пометки ставит логика, которая должна
|
||||||
|
* оставаться достижимой из будущих __banked-модулей. Сам разбор зовёт
|
||||||
|
* pop_bg (резидент W3) — это законно, потому что разбор дёргает только
|
||||||
|
* главный цикл.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "pop_redraw.h"
|
||||||
|
#include "pop_bg.h"
|
||||||
|
|
||||||
|
#define NTILES 30
|
||||||
|
#define NCOLS 10
|
||||||
|
|
||||||
|
static uint8_t rd_kind[NTILES], rd_cnt[NTILES];
|
||||||
|
static uint8_t rda_kind[NCOLS], rda_cnt[NCOLS];
|
||||||
|
/* Сколько всего непустых пометок: без него проход по 40 ячейкам крутился бы
|
||||||
|
* КАЖДЫЙ кадр впустую (замер 2026-07-27 на прежнем rest-цикле: ~12 % кадра). */
|
||||||
|
static uint8_t rd_pending;
|
||||||
|
|
||||||
|
void pop_redraw_reset(void)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < NTILES; i++) { rd_kind[i] = 0; rd_cnt[i] = 0; }
|
||||||
|
for (i = 0; i < NCOLS; i++) { rda_kind[i] = 0; rda_cnt[i] = 0; }
|
||||||
|
rd_pending = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages)
|
||||||
|
{
|
||||||
|
if (tilepos >= NTILES) return;
|
||||||
|
if (!rd_cnt[tilepos]) rd_pending++;
|
||||||
|
rd_kind[tilepos] = kind;
|
||||||
|
if (pages > rd_cnt[tilepos]) rd_cnt[tilepos] = pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_set_redraw_above(uint8_t col, uint8_t kind, uint8_t pages)
|
||||||
|
{
|
||||||
|
if (col >= NCOLS) return;
|
||||||
|
if (!rda_cnt[col]) rd_pending++;
|
||||||
|
rda_kind[col] = kind;
|
||||||
|
if (pages > rda_cnt[col]) rda_cnt[col] = pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* redraw_needed (seg008:0178): пройти пометки и нарисовать. row/col ведём
|
||||||
|
* бегущими счётчиками, а не через i/10 и i%10 — у Z80 нет деления, и SDCC
|
||||||
|
* выносит __divuchar/__moduchar в вершину цикла как общее подвыражение
|
||||||
|
* аргументов (30*2 делений за кадр даже когда рисовать нечего). */
|
||||||
|
void pop_redraw_needed(void)
|
||||||
|
{
|
||||||
|
uint8_t i, row = 0, col = 0, left = 0;
|
||||||
|
if (!rd_pending) return;
|
||||||
|
for (i = 0; i < NTILES; i++) {
|
||||||
|
if (rd_cnt[i]) {
|
||||||
|
switch (rd_kind[i]) {
|
||||||
|
case POP_RD_SPIKE: pop_spike_redraw(row, col); break;
|
||||||
|
case POP_RD_LOOSE: pop_loose_shake_draw(row, col); break;
|
||||||
|
case POP_RD_LOOSE_GONE: pop_loose_bake_empty(row, col); break;
|
||||||
|
case POP_RD_FLOOR: pop_floor_bake(row, col); break;
|
||||||
|
case POP_RD_LEVELDOOR: pop_leveldoor_redraw(row, col); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
if (--rd_cnt[i]) left++;
|
||||||
|
else rd_kind[i] = 0;
|
||||||
|
}
|
||||||
|
if (++col == 10) { col = 0; row++; }
|
||||||
|
}
|
||||||
|
for (i = 0; i < NCOLS; i++) {
|
||||||
|
if (rda_cnt[i]) {
|
||||||
|
if (rda_kind[i] == POP_RDA_CEIL) pop_ceil_shake_draw(i);
|
||||||
|
else pop_ceil_bake_empty(i);
|
||||||
|
if (--rda_cnt[i]) left++;
|
||||||
|
else rda_kind[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rd_pending = left;
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* pop_redraw.h — пометки «перерисовать тайл» и их разбор.
|
||||||
|
*
|
||||||
|
* Порт архитектуры оригинала: логика анимации НИЧЕГО не рисует, она ставит
|
||||||
|
* флаг (`set_redraw_full`/`set_wipe`/`redraw_20h`/`redraw_21h`, seg007), а
|
||||||
|
* отрисовка идёт отдельным проходом (`redraw_needed`, seg008:0178). У нас
|
||||||
|
* так же: pop_map/pop_trob зовут pop_set_redraw*, а pop_redraw_needed()
|
||||||
|
* (главный цикл) разбирает пометки и дёргает pop_bg.
|
||||||
|
*
|
||||||
|
* ЗАЧЕМ (кроме сходства с SDLPoP): из __banked-кода резидентная страница W3
|
||||||
|
* недостижима — ни напрямую, ни транзитивно (docs/layout_plan_v2.md §2 R2).
|
||||||
|
* Пока pop_map звал pop_bg, его нельзя было использовать из банка стражей.
|
||||||
|
* Пометки живут в W1/W2 и зовутся откуда угодно.
|
||||||
|
*
|
||||||
|
* ОТЛИЧИЕ ОТ ОРИГИНАЛА: у нас не один экран с dirty-rect, а две страницы
|
||||||
|
* дабл-буфера со своей ОЗУ-копией фона, поэтому счётчик пометки — это ЧИСЛО
|
||||||
|
* СТРАНИЦ (обычно 2), а вид перерисовки хранится явно: heal+рисовать поверх
|
||||||
|
* (транзиент) или запечь новый фон. В оригинале вид кодируется тем, в какой
|
||||||
|
* из таблиц redraw_frames_* стоит флаг.
|
||||||
|
*/
|
||||||
|
#ifndef POP_REDRAW_H
|
||||||
|
#define POP_REDRAW_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Виды перерисовки тайла (row*10+col). */
|
||||||
|
#define POP_RD_SPIKE 1 /* пики: heal + оба тайла (redraw_21h) */
|
||||||
|
#define POP_RD_LOOSE 2 /* loose: дрожащий кадр / кадр покоя */
|
||||||
|
#define POP_RD_LOOSE_GONE 3 /* loose провалился: запечь пусто */
|
||||||
|
#define POP_RD_FLOOR 4 /* пол изменился: кнопка/щебень/поднятый меч */
|
||||||
|
#define POP_RD_LEVELDOOR 5 /* створка двери уровня (ПРАВАЯ половина) */
|
||||||
|
|
||||||
|
/* Виды перерисовки полосы у потолка (по колонке). */
|
||||||
|
#define POP_RDA_CEIL 1 /* плита-потолок: дрожащий кадр / покой */
|
||||||
|
#define POP_RDA_CEIL_GONE 2 /* плита-потолок провалилась: колодец */
|
||||||
|
|
||||||
|
/* Пометить тайл/колонку: kind — вид, pages — на скольких страницах
|
||||||
|
* дабл-буфера перерисовать (1 = только текущая, 2 = обе). Повторная
|
||||||
|
* пометка перекрывает вид и берёт максимум счётчика. */
|
||||||
|
void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages);
|
||||||
|
void pop_set_redraw_above(uint8_t col, uint8_t kind, uint8_t pages);
|
||||||
|
|
||||||
|
/* Разобрать пометки: нарисовать всё помеченное на ТЕКУЩЕЙ (back) странице и
|
||||||
|
* уменьшить счётчики. Звать из главного цикла в слое ФОНА — до kid_draw. */
|
||||||
|
void pop_redraw_needed(void);
|
||||||
|
|
||||||
|
/* Сбросить все пометки (смена комнаты/уровня). */
|
||||||
|
void pop_redraw_reset(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -5,7 +5,14 @@
|
|||||||
*/
|
*/
|
||||||
#include "pop_trob.h"
|
#include "pop_trob.h"
|
||||||
#include "pop_level.h"
|
#include "pop_level.h"
|
||||||
#include "pop_bg.h" /* pop_spike_redraw */
|
#include "pop_geom.h"
|
||||||
|
#include "pop_redraw.h" /* пометки перерисовки тайлов (вместо прямых вызовов) */
|
||||||
|
/* pop_bg нужен ТОЛЬКО для пламени факела и пузырька зелья: это не тайловая
|
||||||
|
* перерисовка, а покадровый оверлей поверх фона (в оригинале — свои
|
||||||
|
* add_backtable/add_foretable внутри draw_tile). Всё остальное идёт через
|
||||||
|
* пометки, поэтому pop_process_trobs — единственная функция модуля, которую
|
||||||
|
* нельзя звать из __banked-кода. */
|
||||||
|
#include "pop_bg.h"
|
||||||
|
|
||||||
/* Коды тайлов (fg & 0x1F), которые анимируются. */
|
/* Коды тайлов (fg & 0x1F), которые анимируются. */
|
||||||
#define TILE_SPIKE 0x02
|
#define TILE_SPIKE 0x02
|
||||||
@@ -30,11 +37,6 @@ static trob_t trobs[TROBS_MAX];
|
|||||||
static uint8_t trobs_count;
|
static uint8_t trobs_count;
|
||||||
static uint8_t trob_code[TROBS_MAX]; /* префетч кодов тайлов на кадр (1 map W0) */
|
static uint8_t trob_code[TROBS_MAX]; /* префетч кодов тайлов на кадр (1 map W0) */
|
||||||
|
|
||||||
/* Отложенная перерисовка «покоя» законченных пик/кнопок текущей комнаты
|
|
||||||
* (2 кадра = обе страницы дабл-буфера, как loose_rest). */
|
|
||||||
static uint8_t spike_rest[POP_ROOMTILES];
|
|
||||||
static uint8_t button_rest[POP_ROOMTILES];
|
|
||||||
|
|
||||||
/* Последняя НАРИСОВАННАЯ draw-сигнатура тайла (spike: modifier; button:
|
/* Последняя НАРИСОВАННАЯ draw-сигнатура тайла (spike: modifier; button:
|
||||||
* признак «нажата» = таймер связи >1). Редрой пики/кнопки — ТОЛЬКО при её
|
* признак «нажата» = таймер связи >1). Редрой пики/кнопки — ТОЛЬКО при её
|
||||||
* изменении (порт redraw_11h-on-change из SDLPoP). Без этого кнопка под
|
* изменении (порт redraw_11h-on-change из SDLPoP). Без этого кнопка под
|
||||||
@@ -43,36 +45,19 @@ static uint8_t button_rest[POP_ROOMTILES];
|
|||||||
* расхождение было именно в безусловном редрое). */
|
* расхождение было именно в безусловном редрое). */
|
||||||
static uint8_t trob_drawn[POP_ROOMTILES];
|
static uint8_t trob_drawn[POP_ROOMTILES];
|
||||||
|
|
||||||
/* Сколько тайлов ждут отложенного редроя (spike_rest/button_rest). Без
|
|
||||||
* него цикл по 30 тайлам крутился КАЖДЫЙ кадр впустую: замер в MAME
|
|
||||||
* (2026-07-27) — служебная часть pop_process_trobs ~50 000 тактов при
|
|
||||||
* кадре 430 080, то есть ~12 % кадра на пустой проход. */
|
|
||||||
static uint8_t rest_pending;
|
|
||||||
|
|
||||||
/* Дверь уровня: отложенный редрой ВТОРОЙ страницы дабл-буфера. Створка
|
|
||||||
* анимируется покадрово в back-страницу, поэтому последний кадр анимации
|
|
||||||
* попадает только на одну из двух страниц — вторая застревает на шаг раньше
|
|
||||||
* и дверь «дрожит» через кадр. ldoor_pos = tilepos ПРАВОЙ половины. */
|
|
||||||
static uint8_t ldoor_rest, ldoor_pos;
|
|
||||||
|
|
||||||
/* prandom (seg009.c:321, 32-бит LCG) — нужен для стартовой фазы факела и
|
/* prandom (seg009.c:321, 32-бит LCG) — нужен для стартовой фазы факела и
|
||||||
* выбора следующего кадра пламени. */
|
* выбора следующего кадра пламени. */
|
||||||
static unsigned long trob_seed;
|
static unsigned long trob_seed;
|
||||||
|
|
||||||
static uint16_t trob_prandom(uint16_t maxv)
|
#define trob_prandom(maxv) pop_prandom(&trob_seed, (maxv))
|
||||||
{
|
|
||||||
trob_seed = trob_seed * 214013UL + 2531011UL;
|
|
||||||
return (uint16_t)((uint16_t)(trob_seed >> 16) % (uint16_t)(maxv + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void pop_trob_reset(void)
|
void pop_trob_reset(void)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < POP_NROOMS; i++) room_seen[i] = 0;
|
for (i = 0; i < POP_NROOMS; i++) room_seen[i] = 0;
|
||||||
for (i = 0; i < POP_ROOMTILES; i++) { spike_rest[i] = 0; button_rest[i] = 0; trob_drawn[i] = 0; }
|
for (i = 0; i < POP_ROOMTILES; i++) trob_drawn[i] = 0;
|
||||||
rest_pending = 0;
|
pop_redraw_reset();
|
||||||
ldoor_rest = 0;
|
|
||||||
trobs_count = 0;
|
trobs_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,9 +101,8 @@ void pop_add_trob(uint8_t room, uint8_t tilepos, int8_t type)
|
|||||||
void pop_trob_room_changed(void)
|
void pop_trob_room_changed(void)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < POP_ROOMTILES; i++) { spike_rest[i] = 0; button_rest[i] = 0; trob_drawn[i] = 0; }
|
for (i = 0; i < POP_ROOMTILES; i++) trob_drawn[i] = 0;
|
||||||
rest_pending = 0;
|
pop_redraw_reset();
|
||||||
ldoor_rest = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* anim_tile_modif (seg000:0B12) — при входе в комнату завести анимации её
|
/* anim_tile_modif (seg000:0B12) — при входе в комнату завести анимации её
|
||||||
@@ -373,26 +357,6 @@ void pop_process_trobs(uint8_t cur_room)
|
|||||||
* выносит оба деления (__divuchar/__moduchar) в вершину цикла как общее
|
* выносит оба деления (__divuchar/__moduchar) в вершину цикла как общее
|
||||||
* подвыражение аргументов redraw — 30*2=60 делений/кадр даже когда нет
|
* подвыражение аргументов redraw — 30*2=60 делений/кадр даже когда нет
|
||||||
* активных пик/кнопок (тот же случай, что был в pop_loose_tick). */
|
* активных пик/кнопок (тот же случай, что был в pop_loose_tick). */
|
||||||
if (rest_pending) {
|
|
||||||
uint8_t row = 0, col = 0, left = 0;
|
|
||||||
for (i = 0; i < POP_ROOMTILES; i++) {
|
|
||||||
if (spike_rest[i]) {
|
|
||||||
pop_spike_redraw(row, col);
|
|
||||||
if (--spike_rest[i]) left++;
|
|
||||||
}
|
|
||||||
if (button_rest[i]) {
|
|
||||||
pop_button_redraw(row, col);
|
|
||||||
if (--button_rest[i]) left++;
|
|
||||||
}
|
|
||||||
if (++col == 10) { col = 0; row++; }
|
|
||||||
}
|
|
||||||
rest_pending = left;
|
|
||||||
}
|
|
||||||
if (ldoor_rest) { /* доложить финальный кадр створки на 2-ю страницу */
|
|
||||||
pop_leveldoor_redraw(ldoor_pos / 10, ldoor_pos % 10);
|
|
||||||
ldoor_rest--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trobs_count == 0) return;
|
if (trobs_count == 0) return;
|
||||||
|
|
||||||
/* Префетч кодов тайлов всех trob'ов за ОДИН map/unmap окна 0, а не
|
/* Префетч кодов тайлов всех trob'ов за ОДИН map/unmap окна 0, а не
|
||||||
@@ -477,24 +441,20 @@ void pop_process_trobs(uint8_t cur_room)
|
|||||||
* неизменной сигнатурой, и стёртое уже не возвращается: рядом с
|
* неизменной сигнатурой, и стёртое уже не возвращается: рядом с
|
||||||
* Кидом остриё пропадало, а нижний кусок мерцал (стёрт на одной
|
* Кидом остриё пропадало, а нижний кусок мерцал (стёрт на одной
|
||||||
* странице дабл-буфера из двух). */
|
* странице дабл-буфера из двух). */
|
||||||
uint8_t trow = tp / 10, tcol = tp % 10;
|
/* Последний кадр (пика убралась, trob умирает) — пометить ОБЕ
|
||||||
pop_spike_redraw(trow, tcol);
|
* страницы: живой trob метит каждый кадр по одной. */
|
||||||
/* Последний кадр (пика убралась, trob умирает) — на ВТОРУЮ страницу
|
pop_set_redraw(tp, POP_RD_SPIKE, (uint8_t)(type < 0 ? 2 : 1));
|
||||||
* его уже никто не положит: ставим отложенный редрой. */
|
|
||||||
if (type < 0) { spike_rest[tp] = 1; rest_pending++; }
|
|
||||||
}
|
}
|
||||||
if (room == cur_room && code == TILE_LEVELDOOR) {
|
if (room == cur_room && code == TILE_LEVELDOOR) {
|
||||||
/* Створка едет каждый кадр — перерисовываем ПРАВУЮ половину (там
|
/* Створка едет каждый кадр — перерисовываем ПРАВУЮ половину (там
|
||||||
* её рисует draw_tile_anim_right) С ЗАПЕЧКОЙ в ОЗУ-копию: иначе
|
* её рисует draw_tile_anim_right) С ЗАПЕЧКОЙ в ОЗУ-копию: иначе
|
||||||
* kid_heal вернул бы из фона закрытую створку. Куски двери
|
* kid_heal вернул бы из фона закрытую створку. Куски двери
|
||||||
* непрозрачны, поэтому wipe не нужен. */
|
* непрозрачны, поэтому wipe не нужен. */
|
||||||
uint8_t trow = tp / 10, tcol = tp % 10;
|
/* Створку рисует ПРАВАЯ половина двери; последний кадр анимации
|
||||||
if (tcol + 1 < 10) {
|
* помечаем на обе страницы, иначе дверь дрожит через кадр. */
|
||||||
pop_leveldoor_redraw(trow, tcol + 1);
|
if (tp % 10 + 1 < 10)
|
||||||
/* Анимация кончилась — этот кадр лёг только на ОДНУ страницу;
|
pop_set_redraw((uint8_t)(tp + 1), POP_RD_LEVELDOOR,
|
||||||
* повторить его на второй, иначе дверь дрожит через кадр. */
|
(uint8_t)(type < 0 ? 2 : 1));
|
||||||
if (type < 0) { ldoor_pos = (uint8_t)(tp + 1); ldoor_rest = 1; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (room == cur_room && code == TILE_SWORD) {
|
if (room == cur_room && code == TILE_SWORD) {
|
||||||
/* МЕЧ — редрой только на смене видимого кадра (блеск = modif==1):
|
/* МЕЧ — редрой только на смене видимого кадра (блеск = modif==1):
|
||||||
@@ -503,9 +463,7 @@ void pop_process_trobs(uint8_t cur_room)
|
|||||||
* следующим кадром через rest-цикл. */
|
* следующим кадром через rest-цикл. */
|
||||||
uint8_t sig = (uint8_t)(mod[tp] == 1);
|
uint8_t sig = (uint8_t)(mod[tp] == 1);
|
||||||
if (sig != trob_drawn[tp]) {
|
if (sig != trob_drawn[tp]) {
|
||||||
uint8_t trow = tp / 10, tcol = tp % 10;
|
pop_set_redraw(tp, POP_RD_FLOOR, 2); /* обе страницы */
|
||||||
pop_button_redraw(trow, tcol);
|
|
||||||
button_rest[tp] = 1; rest_pending++;
|
|
||||||
trob_drawn[tp] = sig;
|
trob_drawn[tp] = sig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -517,9 +475,7 @@ void pop_process_trobs(uint8_t cur_room)
|
|||||||
* считаем только в момент редроя (редко), а не каждый кадр. */
|
* считаем только в момент редроя (редко), а не каждый кадр. */
|
||||||
uint8_t sig = (uint8_t)(get_doorlink_timer(mod[tp]) > 1);
|
uint8_t sig = (uint8_t)(get_doorlink_timer(mod[tp]) > 1);
|
||||||
if (sig != trob_drawn[tp]) {
|
if (sig != trob_drawn[tp]) {
|
||||||
uint8_t trow = tp / 10, tcol = tp % 10;
|
pop_set_redraw(tp, POP_RD_FLOOR, 2); /* обе страницы */
|
||||||
pop_button_redraw(trow, tcol);
|
|
||||||
button_rest[tp] = 1; rest_pending++;
|
|
||||||
trob_drawn[tp] = sig;
|
trob_drawn[tp] = sig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "pop_map.h"
|
#include "pop_map.h"
|
||||||
#include "pop_level.h"
|
#include "pop_level.h"
|
||||||
#include "pop_trob.h"
|
#include "pop_trob.h"
|
||||||
|
#include "pop_redraw.h"
|
||||||
|
|
||||||
__sfr __at (0xFE) io_border;
|
__sfr __at (0xFE) io_border;
|
||||||
|
|
||||||
@@ -202,6 +203,10 @@ int main(void)
|
|||||||
puts("pop_bg_load failed");
|
puts("pop_bg_load failed");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (pop_kid_data_load("kid_data.bin") != 0) { /* кадры+seqtbl в EMM-странице */
|
||||||
|
printf("kid_data.bin load failed\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
pop_sword_load(); /* меч в руке (без него кадры 229+ без клинка) */
|
pop_sword_load(); /* меч в руке (без него кадры 229+ без клинка) */
|
||||||
if (pop_kid_load(28) != 0) { /* ВСЕ страницы: бег+стоп+разворот+присед+прыжок */
|
if (pop_kid_load(28) != 0) { /* ВСЕ страницы: бег+стоп+разворот+присед+прыжок */
|
||||||
puts("kid atlas load failed");
|
puts("kid atlas load failed");
|
||||||
@@ -339,8 +344,10 @@ int main(void)
|
|||||||
pop_loose_tick(); /* loose-полы: анимация + перерисовка (СЛОЙ ФОНА */
|
pop_loose_tick(); /* loose-полы: анимация + перерисовка (СЛОЙ ФОНА */
|
||||||
/* — ДО Kid, чтобы Kid всегда был поверх плиты) */
|
/* — ДО Kid, чтобы Kid всегда был поверх плиты) */
|
||||||
io_border = 6; /* голубой */
|
io_border = 6; /* голубой */
|
||||||
pop_process_trobs(cur_room); /* пики/ворота: продвинуть + перерисовать (тоже */
|
pop_process_trobs(cur_room); /* пики/ворота/дверь: продвинуть СОСТОЯНИЕ (порт */
|
||||||
/* слой фона — ДО Kid) */
|
/* process_trobs — рисования внутри нет) */
|
||||||
|
pop_redraw_needed(); /* и разобрать пометки перерисовки тайлов (порт */
|
||||||
|
/* redraw_needed, seg008:0178) — СЛОЙ ФОНА, до Kid */
|
||||||
io_border = 4; /* синий */
|
io_border = 4; /* синий */
|
||||||
{ /* ворота соседа слева (room8) видны в col0 — */
|
{ /* ворота соседа слева (room8) видны в col0 — */
|
||||||
uint8_t lft = pop_room_link(cur_room, 0); /* редрой шва ТОЛЬКО при изменении openness */
|
uint8_t lft = pop_room_link(cur_room, 0); /* редрой шва ТОЛЬКО при изменении openness */
|
||||||
@@ -484,6 +491,7 @@ int main(void)
|
|||||||
closegraph();
|
closegraph();
|
||||||
pop_bg_free();
|
pop_bg_free();
|
||||||
pop_kid_free();
|
pop_kid_free();
|
||||||
|
pop_kid_data_free();
|
||||||
pop_level_free();
|
pop_level_free();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import os
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
SRC = "/Users/alex/Projects/DIY/Z80/Sprinter/C-Compiler/applications/PoP/SDLPoP/src"
|
SRC = "/Users/alex/Projects/DIY/Z80/Sprinter/C-Compiler/applications/PoP/SDLPoP/src"
|
||||||
|
OUT_BIN_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||||
|
"..", "poc", "res", "kid")
|
||||||
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||||
"..", "roomtest", "kid_data.h")
|
"..", "roomtest", "kid_data.h")
|
||||||
SEQTBL_BASE = 0x196E
|
SEQTBL_BASE = 0x196E
|
||||||
@@ -74,22 +76,21 @@ def main():
|
|||||||
f.write("#ifndef KID_DATA_H\n#define KID_DATA_H\n#include <stdint.h>\n\n")
|
f.write("#ifndef KID_DATA_H\n#define KID_DATA_H\n#include <stdint.h>\n\n")
|
||||||
f.write("#define SEQTBL_BASE 0x%04Xu\n\n" % SEQTBL_BASE)
|
f.write("#define SEQTBL_BASE 0x%04Xu\n\n" % SEQTBL_BASE)
|
||||||
|
|
||||||
# frame table
|
# frame table и seqtbl В .h НЕ ПОПАДАЮТ — они уезжают в kid_data.bin
|
||||||
f.write("/* {image, dx, dy, flags, sword}; chtab = sword>>6 (0=kid). */\n")
|
# (EMM-страница): 3.5 КБ в _CODE окна W1/W2 нам дороже, чем один
|
||||||
|
# gfx_w0_map за тик. См. applications/PoP/docs/layout_plan_v2.md §5.1.
|
||||||
|
f.write("/* {image, dx, dy, flags, sword}; chtab = sword>>6 (0=kid).\n"
|
||||||
|
" * САМА таблица кадров и seqtbl лежат в kid_data.bin (EMM-\n"
|
||||||
|
" * страница); здесь только тип и размеры. */\n")
|
||||||
f.write("typedef struct { uint8_t image; int8_t dx, dy; "
|
f.write("typedef struct { uint8_t image; int8_t dx, dy; "
|
||||||
"uint8_t flags, sword; } kframe;\n")
|
"uint8_t flags, sword; } kframe;\n")
|
||||||
f.write("#define KID_NFRAMES %d\n" % len(frames))
|
f.write("#define KID_NFRAMES %d\n" % len(frames))
|
||||||
f.write("static const kframe kid_frames[KID_NFRAMES] = {\n")
|
f.write("#define KID_SEQTBL_LEN %d\n\n" % len(seqtbl))
|
||||||
for (img, dx, dy, fl, sw) in frames:
|
|
||||||
dxs = dx - 256 if dx > 127 else dx
|
|
||||||
dys = dy - 256 if dy > 127 else dy
|
|
||||||
f.write(" {%3d,%4d,%4d,0x%02X,0x%02X},\n" % (img, dxs, dys, fl, sw))
|
|
||||||
f.write("};\n\n")
|
|
||||||
|
|
||||||
# seqtbl bytes
|
# раскладка kid_data.bin (смещения ОТ НАЧАЛА ДАННЫХ страницы)
|
||||||
f.write("#define KID_SEQTBL_LEN %d\n" % len(seqtbl))
|
f.write("/* Раскладка kid_data.bin: кадры (KID_NFRAMES*5), затем seqtbl. */\n")
|
||||||
f.write("static const uint8_t kid_seqtbl[KID_SEQTBL_LEN] = {\n")
|
f.write("#define KID_BIN_FRAMES_OFF 0\n")
|
||||||
f.write(emit_c(seqtbl) + "\n};\n\n")
|
f.write("#define KID_BIN_SEQTBL_OFF %d\n\n" % (len(frames) * 5))
|
||||||
|
|
||||||
# seq offsets
|
# seq offsets
|
||||||
f.write("#define KID_NSEQ %d\n" % len(offs))
|
f.write("#define KID_NSEQ %d\n" % len(offs))
|
||||||
@@ -97,6 +98,15 @@ def main():
|
|||||||
f.write(emit_c(offs, 8, "0x%04X") + "\n};\n\n")
|
f.write(emit_c(offs, 8, "0x%04X") + "\n};\n\n")
|
||||||
f.write("#endif\n")
|
f.write("#endif\n")
|
||||||
|
|
||||||
|
# kid_data.bin: кадры (по 5 байт) + seqtbl подряд
|
||||||
|
os.makedirs(OUT_BIN_DIR, exist_ok=True)
|
||||||
|
binpath = os.path.join(OUT_BIN_DIR, "kid_data.bin")
|
||||||
|
with open(binpath, "wb") as b:
|
||||||
|
for (img, dx, dy, fl, sw) in frames:
|
||||||
|
b.write(bytes((img & 0xFF, dx & 0xFF, dy & 0xFF, fl & 0xFF, sw & 0xFF)))
|
||||||
|
b.write(bytes(seqtbl))
|
||||||
|
print(f"kid_data.bin: {len(frames)*5 + len(seqtbl)} Б -> {binpath}")
|
||||||
|
|
||||||
print(f"kid_data.h: {len(frames)} кадров, seqtbl {len(seqtbl)} Б, "
|
print(f"kid_data.h: {len(frames)} кадров, seqtbl {len(seqtbl)} Б, "
|
||||||
f"{len(offs)} seq-оффсетов -> {OUT}")
|
f"{len(offs)} seq-оффсетов -> {OUT}")
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,893 @@
|
|||||||
|
# Функции BIOS v2.12
|
||||||
|
|
||||||
|
### Вызов функций BIOS
|
||||||
|
|
||||||
|
Вызов функций BIOS осуществляется из ассемблерного кода.
|
||||||
|
|
||||||
|
Номер функции задается в регистре C процессора. В остальные регистры,
|
||||||
|
при необходимости, загружаются входные параметры функции. После исполнения
|
||||||
|
функции происходит возврат в программу, из которой произошел вызов функции.
|
||||||
|
Установленный флаг CF (CF=1) означает, что работа функции произошла с
|
||||||
|
ошибкой. В некоторых регистрах передаются выходные параметры.
|
||||||
|
|
||||||
|
Ниже приведены таблицы входных и выходных параметров для каждой функции:
|
||||||
|
|
||||||
|
- Функции работы с памятью
|
||||||
|
- Функции управления 'железом'
|
||||||
|
- Функции управления окнами и режимами экрана
|
||||||
|
- Функции вывода текста на экран
|
||||||
|
- Графические функции
|
||||||
|
- Функции работы с жесткими дисками и дисководами
|
||||||
|
|
||||||
|
При работе функций BIOS необходимо что бы стек находился в области
|
||||||
|
8000h..0BFFFh, так как часть функций использует переключение страниц
|
||||||
|
PAGE1 и PAGE3.
|
||||||
|
|
||||||
|
Вызов функций BIOS возможен в различных конфигурациях компьютера Sprinter.
|
||||||
|
|
||||||
|
Конфигурация Spectrum: вызов функций BIOS осуществляется через 3D13h.
|
||||||
|
При этом работают и все функции TR-DOS.
|
||||||
|
|
||||||
|
Конфигурации Sprinter: вызов функций BIOS осуществляется через RST 18h
|
||||||
|
при подключенном системном ПЗУ.
|
||||||
|
|
||||||
|
Для постоянного подключения системного ПЗУ можно воспользоваться
|
||||||
|
такой последовательностью команд:
|
||||||
|
|
||||||
|
```asm
|
||||||
|
LD A,0
|
||||||
|
OUT (07Ch),A
|
||||||
|
```
|
||||||
|
|
||||||
|
После ее исполнения в 0-м окне Z80 будет включено ПЗУ BIOSа и программа
|
||||||
|
может вызывать функции BIOSа через RST 18h.
|
||||||
|
|
||||||
|
Отключение ПЗУ BIOSа из нулевого окна Z80 производится следующей
|
||||||
|
последовательностью команд:
|
||||||
|
|
||||||
|
```asm
|
||||||
|
LD A,0
|
||||||
|
OUT (03Ch),A
|
||||||
|
```
|
||||||
|
|
||||||
|
При необходимости, функции BIOSа могут быть вызваны программой, находящейся
|
||||||
|
в ОЗУ непосредственно в нулевом окне Z80. Для этого надо установить в
|
||||||
|
адресе 0008h следующий код:
|
||||||
|
|
||||||
|
```asm
|
||||||
|
ADDRESS_0008h:
|
||||||
|
PUSH AF
|
||||||
|
LD A,0
|
||||||
|
OUT (7Ch),A
|
||||||
|
POP AF
|
||||||
|
RET
|
||||||
|
```
|
||||||
|
|
||||||
|
После этого BIOS можно вызывать командой RST 8. (Функции TR-DOS, так
|
||||||
|
же как и в случае RST 18 остаются недоступны.) Вызывая программы таким
|
||||||
|
образом, через RST 8, следует помнить что адреса 3FFFh..0000h после входа
|
||||||
|
в BIOS будут содержать код ПЗУ, поэтому, если фунция использует данные в
|
||||||
|
ОЗУ, они должны находиться в других адресах.
|
||||||
|
|
||||||
|
Оптимизация программы для RST 8 недопустима, так как в ПЗУ, для
|
||||||
|
обратного переключения, стоит такая же программа, только порт 3Ch для
|
||||||
|
отключения ПЗУ BIOSа.
|
||||||
|
|
||||||
|
Вызов функций BIOS в exe-файлах, вызываемых с помощью операционной
|
||||||
|
системы Estex, производится командой RST 8. Необходимая программа в адресе
|
||||||
|
0008h уже имеется в блоке кода ОС Estex.
|
||||||
|
|
||||||
|
|
||||||
|
### Функции работы с памятью
|
||||||
|
|
||||||
|
**0C0h (192) EMM_FN0 Определение объемов ОЗУ**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C0h
|
||||||
|
Значение регистров на выходе:
|
||||||
|
HL - общий объем ОЗУ в страницах по 16k
|
||||||
|
BC - объем свободного ОЗУ в страницах по 16k
|
||||||
|
|
||||||
|
**0C1h (193) EMM_FN1 Инициализация распределения памяти**
|
||||||
|
Стирается вся информация о выделенных ранее блоках ОЗУ.
|
||||||
|
Блоки с системной информацией и первые 256K ОЗУ объявляются занятыми.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C1h
|
||||||
|
Значение регистров на выходе:
|
||||||
|
нет
|
||||||
|
|
||||||
|
**0C2h (194) EMM_FN2 Выделение блока ОЗУ**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C2h
|
||||||
|
B - число запрашиваемых страниц
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение - A - идентификатор блока
|
||||||
|
CF=1 - ошибка - A=1 - не хватает памяти
|
||||||
|
|
||||||
|
**0C3h (195) EMM_FN3 Освободить блок ОЗУ**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C3h
|
||||||
|
A - идентификатор блока
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неправильный идентификатор
|
||||||
|
идентификатор не всегда отслеживается правильно
|
||||||
|
|
||||||
|
**0C4h (196) EMM_FN4 Получить физический номер страницы из блока памяти**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C4h
|
||||||
|
A - идентификатор блока
|
||||||
|
B - логическая номер страницы в блоке
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - A - логический номер страницы
|
||||||
|
CF=1 - ошибка:
|
||||||
|
A=0 - блок не существует
|
||||||
|
A=255 - запрашиваемый номер страницы слишком велик
|
||||||
|
|
||||||
|
**0C5h (197) EMM_FN5 Получить список физических страниц блока**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C5h
|
||||||
|
A - идентификатор блока
|
||||||
|
HL - буфер 256 байт для размещения списка страниц
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение:
|
||||||
|
B - число страниц в блоке
|
||||||
|
HL - тот же адрес буфера, в буфере список физических
|
||||||
|
страниц по порядку, заканчивающийся байтом 0FFh
|
||||||
|
CF=1 - неверный идентификатор блока; старая информация в буфере
|
||||||
|
может быть затерта
|
||||||
|
|
||||||
|
**0C6h (198) EMM_FN6 Получение адресов портов окон**
|
||||||
|
|
||||||
|
Примечание по использованию функции получения адресов портов окон (0C6h):
|
||||||
|
>Cледует хотя бы один раз вызвать эти функции и сравнить адреса
|
||||||
|
>портов с теми, что используются в программе и, если они не совпадают,
|
||||||
|
>выдать соответствующее предупреждение. В данный момент эти порты
|
||||||
|
>таковы: PAGE0=82h, PAGE1=0A2h, PAGE2=0C2h, PAGE3=0E2h
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C6h
|
||||||
|
A - номер окна процессора - 0,1,2 или 3
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
C - 8-битный адрес порта окна
|
||||||
|
B - физический номер подключенной в окно страницы
|
||||||
|
CF=1 - ошибка - неверный номер окна
|
||||||
|
|
||||||
|
**0C7h (199) EMM_FN7 Получить номер следующей страницы блока**
|
||||||
|
|
||||||
|
Примечание по использованию функции EMM_FN7 (0C7h):
|
||||||
|
> Информация о распределении памяти хранится в виде RAM Allocation Table,
|
||||||
|
> похожей на дисковый FAT. Поэтому нахождение физического номера
|
||||||
|
> следующей страницы по предыдущему физическому номеру происходит
|
||||||
|
> значительно быстрее, чем поиск по увеличенному на единицу логическому
|
||||||
|
> номеру.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C7h
|
||||||
|
A - физическая страница
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
A - следуюшая физическая страница блока
|
||||||
|
A=0FFh - индицирует конец блока
|
||||||
|
CF=1 - ошибка - страница не принадлежит никакому блоку.
|
||||||
|
фактически, это означает, что она свободна.
|
||||||
|
|
||||||
|
**09Eh (158) EMM_FN8 Слияние блоков**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
A - идентификатор блока 1
|
||||||
|
B - идентификатор блока 2
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
A - идентификатор объединенного блока
|
||||||
|
CF=1 - ошибка - неверный идентификатор блока
|
||||||
|
|
||||||
|
**09Dh (157) EMM_FN9 Разделение блока**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=09Dh
|
||||||
|
A - идентификатор блока
|
||||||
|
B - новая длина блока
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
A - идентификатор блока результата
|
||||||
|
B - идентификатор блока остатка
|
||||||
|
CF=1 - ошибка - неверный идентификатор блока
|
||||||
|
|
||||||
|
### Функции управления 'железом'
|
||||||
|
|
||||||
|
**0EFh (239) FN_VERSION Выдача информации о версии BIOSа и железа.**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0EFh
|
||||||
|
HL - буфер, куда будет помещена ASCII строка с несколькими
|
||||||
|
полями, номером версии BIOS и названием модели
|
||||||
|
компьютера. Конец строки отмечен двойным нулем.
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
HL - тот же буфер с записанной строкой.
|
||||||
|
DE - версия BIOSа
|
||||||
|
BC - версия железа подробности ниже
|
||||||
|
A - количество полей в буфере (в данный момент - 2)
|
||||||
|
Первое поле - версия BIOS.
|
||||||
|
Второе - название модели компьютера.
|
||||||
|
CF=1 - ошибка - Очень старая версия,
|
||||||
|
не имеющая данной функции
|
||||||
|
|
||||||
|
**0F2h (242) FN_SICF=0 Установка синхронизации, очистка страницы режима экрана**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0F2h
|
||||||
|
A - режим синхронизации
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неверный номер режима синхронизации
|
||||||
|
|
||||||
|
### Функции работы с CMOS данными и Turbo режимом
|
||||||
|
|
||||||
|
Комментарий к функциям CMOS (0F5h-0F7h):
|
||||||
|
> Функции CMOS_RD, CMOS_WR, CMOS_TEST работают всегда. Если в машине нет
|
||||||
|
> микросхемы CMOS, то эмулируется ее память. Наличие микросхемы
|
||||||
|
> определяется функцией CMOS_TEST.
|
||||||
|
|
||||||
|
**0F5h (245) CMOS_TEST Проверить наличие CMOS**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0F5h
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - часы есть
|
||||||
|
CF=1 - часов нет
|
||||||
|
|
||||||
|
**0F6h (246) CMOS_RD Читать из регистра CMOS**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0F6h
|
||||||
|
D - номер регистра CMOS
|
||||||
|
Значение регистров на выходе:
|
||||||
|
A - считанные данные
|
||||||
|
CF=0 - часы есть
|
||||||
|
CF=1 - часов нет
|
||||||
|
|
||||||
|
**0F7h (247) CMOS_WR Писать в регистр CMOS**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0F7h
|
||||||
|
D - номер регистра CMOS
|
||||||
|
A - записываемые данные
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - часы есть
|
||||||
|
CF=1 - часов нет
|
||||||
|
|
||||||
|
**08Fh (143) FN_TURBO Функция управления турбо режимом.**
|
||||||
|
|
||||||
|
Комментарий к функции FN_TURBO (08Fh):
|
||||||
|
Переключение режима турбо может не произойти, если прошивка не
|
||||||
|
поддерживает это переключение. При этом ошибки не происходит. Так
|
||||||
|
же, переключение режима TURBO блокируется кнопкой "Turbo" в
|
||||||
|
режиме Turbo-OFF
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Fh
|
||||||
|
A - режим турбо: 2 - off, 3 - on
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неверный режим турбо
|
||||||
|
|
||||||
|
### Функции управления окнами и режимами экрана
|
||||||
|
|
||||||
|
**0B0h (176) WIN_OPEN Функция открытия окна.**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B0h
|
||||||
|
IX - описатель окна
|
||||||
|
E - флаги окна:
|
||||||
|
бит 0 указывает какую страницу режима включать после
|
||||||
|
исполнения функции;
|
||||||
|
бит 4 указывает на какой странице режима открывать окно
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение:
|
||||||
|
A - идентификатор окна
|
||||||
|
CF=1 - ошибка слишком много окон
|
||||||
|
|
||||||
|
**0B1h (177) WIN_CLOSE закрытие окна**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B1h
|
||||||
|
A - идентификатор окна
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - успешное завершение
|
||||||
|
CF=1 - ошибка - неверный идентификатор
|
||||||
|
Окно с номером 0 никогда не закрывается и попытка
|
||||||
|
закрытия приводит к ошибке
|
||||||
|
|
||||||
|
**0B2h (178) WIN_COPY_WIN Копирование данных текстового окна в память (запоминание окна)**
|
||||||
|
|
||||||
|
При работе этой функции через RST 18h или RST 8, обязателен запрет
|
||||||
|
прерываний, так как функция пользуется стеком для ускорения своей работы.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B2h
|
||||||
|
A - идентификатор глобального окна
|
||||||
|
H - размер окна в символах по вертикали
|
||||||
|
L - размер окна в символах по горизонтали
|
||||||
|
D - вертикальное положение окна в глобальном окне
|
||||||
|
E - горизонтальное положение окна в глобальном окне
|
||||||
|
IX - адрес буфера для запоминания данных
|
||||||
|
адрес буфера указывается для окна 0C000h если адрес
|
||||||
|
указан с 8000h, номер страницы буфера не действителен
|
||||||
|
ниже 8000h адрес указывать нельзя
|
||||||
|
A' - страница буфера для данных окна эта страница должна
|
||||||
|
принадлежать программе
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка - неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B3h (179) WIN_RESTORE_WIN Копирование из памяти в текстовое окно (восстановление окна)**
|
||||||
|
|
||||||
|
При работе этой функции через RST 18h или RST 8, обязателен запрет
|
||||||
|
прерываний, так как функция пользуется стеком для ускорения своей работы.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B2h
|
||||||
|
A - идентификатор глобального окна
|
||||||
|
H - размер окна в символах по вертикали
|
||||||
|
L - размер окна в символах по горизонтали
|
||||||
|
D - вертикальное положение окна в глобальном окне
|
||||||
|
E - горизонтальное положение окна в глобальном окне
|
||||||
|
IX - адрес буфера для запоминания данных
|
||||||
|
адрес буфера указывается для окна 0C000h если адрес
|
||||||
|
указан с 8000h, номер страницы буфера не действителен
|
||||||
|
ниже 8000h адрес указывать нельзя
|
||||||
|
A' - страница буфера для данных окна эта страница должна
|
||||||
|
принадлежать программе
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка - неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B4h (180) WIN_GET_SYM Взять символ с экрана**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B4h
|
||||||
|
A - идентификатор окна
|
||||||
|
DE - положение символа в окне:
|
||||||
|
D - вертикаль, E - горизонталь
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
L - символ, H - атрибут,
|
||||||
|
B - знакогенератор
|
||||||
|
CF=1 - ошибка неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B5h (181) WIN_PUT_SYM Положить символ на экран**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B5h
|
||||||
|
A - идентификатор окна
|
||||||
|
DE - положение символа в окне:
|
||||||
|
D - вертикаль, E - горизонталь
|
||||||
|
L - символ, H - атрибут символа
|
||||||
|
B - знакогенератор
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B6h (182) WIN_SET_ZG установка знакогенератора**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B6h
|
||||||
|
A - системный номер знакогенератора
|
||||||
|
DE - указатель на 2Kb блок данных знакогенератора
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка (старая версия, нет функции)
|
||||||
|
|
||||||
|
**0B7h (183) WIN_MOVE_WIN Перемещение окна**
|
||||||
|
|
||||||
|
При работе этой функции через RST 18h или RST 8, обязателен запрет
|
||||||
|
прерываний, так как функция пользуется стеком для ускорения своей работы.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B7h
|
||||||
|
A - идентификатор глобального окна
|
||||||
|
H - размер локального окна по вертикали в символах
|
||||||
|
L - размер локального окна по горизонтали в символах
|
||||||
|
D - положение локального окна по вертикали в символах
|
||||||
|
E - положение локального окна по горизонтали в символах
|
||||||
|
IX - новое положение локального окна (подобно DE)
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка - неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B8h (184) WIN_GET_ZG Получение знакогенератора**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B8h
|
||||||
|
DE - адрес, куда будет загружено 2kb знакогенератора
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка (старая версия, нет функции)
|
||||||
|
|
||||||
|
### Функции вывода текста на экран
|
||||||
|
|
||||||
|
**081h (129) LP_PRINT_ALL Печать символов с атрибутом**
|
||||||
|
|
||||||
|
На экран выводится строка из B одинаковых символов
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=081h
|
||||||
|
A - символ
|
||||||
|
E - атрибут
|
||||||
|
B - число выводимых символов
|
||||||
|
регистры HL,IX - сохраняются
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**082h (131) LP_PRINT_SYM Вывод символов на экран без атрибута**
|
||||||
|
|
||||||
|
На экран выводится строка из B одинаковых символов атрибут
|
||||||
|
остается тот, который был на экране
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=082h
|
||||||
|
A - символ
|
||||||
|
B - число выводимых символов
|
||||||
|
регистры HL,IX - сохраняются
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**083h (131) LP_PRINT_ATR печать атрибутов**
|
||||||
|
|
||||||
|
На экран выводится строка из B одинаковых атрибутов.
|
||||||
|
Символы не меняются.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=083h
|
||||||
|
E - атрибут
|
||||||
|
B - число выводимых символов
|
||||||
|
регистры HL,IX - сохраняются
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**084h (132) LP_SET_PLACE Установка текущего знакоместа в окне**
|
||||||
|
|
||||||
|
Позиция печати устанавливается в соответстии с регистром DE
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=084h
|
||||||
|
E - положение символа по горизонтали
|
||||||
|
D - номер символа по вертикали
|
||||||
|
Превышение границ приводит не к ошибке, а к переустановке
|
||||||
|
с начала, за вычетом полного размера окна
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**085h (133) LP_PRINT_LN Вывод строки символов на экран с текущего знакоместа**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=085h
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
E - атрибут, с которым будет выведена строка
|
||||||
|
B - длина выводимой строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**086h (134) LP_PRINT_LN2 Вывод строки символов на экран без атрибутов**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=086h
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
B - длина выводимой строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**087h (135) LP_PRINT_LN3 Вывод строки символов до разделителя**
|
||||||
|
|
||||||
|
После разделителя выводятся пробелы, что бы вывести B символов
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=087h
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
E - атрибут, с которым будет выведена строка
|
||||||
|
B - длина выводимой строки
|
||||||
|
D - символ-разделитель, указывающий конец строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**088h (136) LP_PRINT_LN4 Вывод строки символов до разделителя, без атрибутов**
|
||||||
|
|
||||||
|
символы из выводятся на экран, пока не встретится символ равный D,
|
||||||
|
далее печатаются пробелы, как дополнение строки до B символов.
|
||||||
|
Атрибуты не изменяются.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=088h
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
B - длина выводимой строки
|
||||||
|
D - символ-разделитель, указывающий конец строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**089h (137) LP_CLS_WIN Очистка экрана**
|
||||||
|
|
||||||
|
Выполнение производится выводом пробелов с заданным атрибутом
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=089h
|
||||||
|
DE - положение локального окна
|
||||||
|
H - размер в символах локального окна по вертикали
|
||||||
|
L - размер в символах локального окна по горизонтали
|
||||||
|
B - атрибут очистки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Ah (138) LP_SCROLL_UD Скроллинг части глобального окна вверх/вниз**
|
||||||
|
|
||||||
|
Скроллируются полные строки глобального окна
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Ah
|
||||||
|
B - тип скроллинга: 1 - вверх; 2 - вниз
|
||||||
|
D - начальная строка скроллинга
|
||||||
|
E - число скроллируемых строк
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Bh (139) LP_PRINT_LN5 Вывод строки символов на экран до разделителя**
|
||||||
|
|
||||||
|
После разделителя вывод останавливается
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
E - атрибут, с которым будет выведена строка
|
||||||
|
B - максимальная длина выводимой строки
|
||||||
|
D - символ-разделитель, указывающий конец строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Ch (140) LP_PRINT_LN6 Вывод строки символов на экран до разделителя без атрибутов**
|
||||||
|
|
||||||
|
После разделителя вывод останавливается.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Ch
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
B - максимальная длина выводимой строки
|
||||||
|
D - символ-разделитель, указывающий конец строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Dh (141) LP_CLS_WIN2 Очистка экрана с указанием символа заполнения**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Dh
|
||||||
|
DE - положение локального окна
|
||||||
|
H - размер в символах локального окна по вертикали
|
||||||
|
L - размер в символах локального окна по горизонтали
|
||||||
|
B - атрибут очистки
|
||||||
|
A - символ очистки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Eh (142) LP_GET_PLACE Получить текущее положение вывода на экран**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Eh
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
DE - координаты, в которых будет напечатан
|
||||||
|
следующий символ:
|
||||||
|
D - вертикаль, E - горизонталь
|
||||||
|
|
||||||
|
### Графические функции
|
||||||
|
|
||||||
|
**0A1h (161) PIC_POINT Установить точку**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0A1h
|
||||||
|
DE - координата по вертикали (пиксели)
|
||||||
|
HL - координата по горизонтали (пиксели)
|
||||||
|
Координаты считаются от верхнего левого угла экрана
|
||||||
|
A - идентификатор окна
|
||||||
|
B - цвет точки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неверный идентификатор окна
|
||||||
|
|
||||||
|
**0A4h (164) PIC_SET_PAL Установка палитры**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0A4h
|
||||||
|
HL - данные палитры
|
||||||
|
E - номер начального цвета
|
||||||
|
D - количество устанавливаемых цветов
|
||||||
|
B - маска при установке палитры.
|
||||||
|
Для нормального режима должнa быть 0FFh
|
||||||
|
A - номер палитры 0..15; от 8 до 15 - резервные
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**0A6h (166) SET_PAL_INIT Установка внутренней палитры**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0A6h
|
||||||
|
A - страница палитры
|
||||||
|
B - номер палитры:
|
||||||
|
B=2 - установка спектрумовской палитры
|
||||||
|
B=1 - установка графической плаитры
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неверный номер палитры
|
||||||
|
|
||||||
|
### Функции работы с жесткими дисками и дисководами
|
||||||
|
|
||||||
|
**50h,52h,53h (80,82,83) Зарезервированы**
|
||||||
|
|
||||||
|
Значение регистров на входе и на выходе:
|
||||||
|
нет
|
||||||
|
|
||||||
|
**51h (81) DRV_RESET Сброс контроллера и настройка на диск**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=51h
|
||||||
|
A - номер и тип устройства
|
||||||
|
бит 7..4 - тип устройства:
|
||||||
|
#0x - FDD
|
||||||
|
#6x - RAM-DISK
|
||||||
|
#8x - HDD
|
||||||
|
#Cx - CD-ROM
|
||||||
|
бит 3..0 - номер устройства
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка, нет диска или нет устройства
|
||||||
|
|
||||||
|
**54h (84) DRV_VERIFY Проверка секторов**
|
||||||
|
|
||||||
|
Проверка внутренняя на совпадение ECC
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=54h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
HL:IX - номер сектора (IX - младшая часть номера сектора)
|
||||||
|
B - количество проверяемых секторов
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - проверка с ошибкой
|
||||||
|
|
||||||
|
**55h (85) DRV_READ Чтение с устройства**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=55h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
HL:IX - номер сектора (IX - младшая часть номера сектора)
|
||||||
|
B - количество секторов
|
||||||
|
DE - адрес буфера для данных
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка чтения
|
||||||
|
HL:IX - номер сектора + кол-во прочитанных секторов
|
||||||
|
DE - адрес буфера для данных + (кол-во прочитанных секторов * размер сектора)
|
||||||
|
|
||||||
|
**56h (86) DRV_WRITE Запись на устройства**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=56h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
HL:IX - номер сектора (IX - младшая часть номера сектора)
|
||||||
|
B - количество секторов
|
||||||
|
DE - адрес буфера данных для записи
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка записи
|
||||||
|
HL:IX - номер сектора + кол-во прочитанных секторов
|
||||||
|
DE - адрес буфера для данных + (кол-во прочитанных секторов * размер сектора)
|
||||||
|
|
||||||
|
**57h (87) DRV_DETECT Определение параметров устройства**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=57h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
A - bit7=0 диск 720Кb
|
||||||
|
bit7=1 диск 1.44Mb
|
||||||
|
CF=1 - нет устройства или нет носителя
|
||||||
|
|
||||||
|
**58h (88) DRV_GET_PAR Получить параметры носителя**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=58h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
L - число секторов
|
||||||
|
H - число головок
|
||||||
|
DE - количество цилиндров
|
||||||
|
если HL=DE=0FFFFh - устройства нет
|
||||||
|
IX - размер сектора в байтах
|
||||||
|
B - доп. параметры для дискет:
|
||||||
|
бит7 - тип 1.44Mb/720Kb
|
||||||
|
CF=1 - нет устройства
|
||||||
|
|
||||||
|
**59h (89) DRV_SET_PAR Установить параметры носителя**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
L - число секторов
|
||||||
|
H - число головок
|
||||||
|
DE - количество цилиндров
|
||||||
|
IX - размер сектора в байтах
|
||||||
|
B - доп. параметры для дискет
|
||||||
|
бит7 - тип 1.44Mb/720Kb
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
|
||||||
|
**5Ah (90) EXT_VERSION Номер версии дисковой спецификации.**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=5Ah
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
D - версия
|
||||||
|
E - модификация
|
||||||
|
CF=1 - ошибка
|
||||||
|
|
||||||
|
**5Fh (95) DRV_LIST Список дисковых устройств**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=5Fh
|
||||||
|
IX - буфер для списка устройств
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
|
||||||
|
В буфере список дисков в формате:
|
||||||
|
|
||||||
|
IX+0 - размер заполненого буфера
|
||||||
|
IX+1 - кол-во устройств FDD
|
||||||
|
IX+2 - кол-во устройств HDD
|
||||||
|
IX+3 - кол-во устройств CD DRIVE
|
||||||
|
IX+4 - #00 - конец списка, иначе кол-во устройств нового типа
|
||||||
|
|
||||||
|
|
||||||
|
### Примечания и комментарии.
|
||||||
|
|
||||||
|
##### *Примечание по использованию функции получения адресов портов окон (0C6h).*
|
||||||
|
Cледует хотя бы один раз вызвать эти функции и сравнить адреса портов с
|
||||||
|
теми, что используются в программе и, если они не совпадают, выдать
|
||||||
|
соответствующее предупреждение. В данный момент эти порты таковы:
|
||||||
|
PAGE0=82h, PAGE1=0A2h, PAGE2=0C2h, PAGE3=0E2h
|
||||||
|
|
||||||
|
##### *Примечание по использованию функции EMM_FN7 (0C7h).*
|
||||||
|
Информация о распределении памяти хранится в виде RAM Allocation Table,
|
||||||
|
похожей на дисковый FAT. Поэтому нахождение физического номера следующей
|
||||||
|
страницы по предыдущему физическому номеру происходит значительно быстрее,
|
||||||
|
чем поиск по увеличенному на единицу логическому номеру.
|
||||||
|
|
||||||
|
##### *Комментарий к функции FN_VERSION (0EFh).*
|
||||||
|
Значения регистра BC на выходе и соответствующая ему конфигурация
|
||||||
|
BC=FFFF - Не определено
|
||||||
|
BC=FFFE - Конфигурация Spectrum, режим Sprinter ZX
|
||||||
|
BC=FFFD - Конфигурация Sprinter
|
||||||
|
BC=FFFC - Зарезервировано
|
||||||
|
BC=FFFB - Зарезервировано
|
||||||
|
BC=FFFA - Зарезервировано
|
||||||
|
BC=FFF9 - Зарезервировано
|
||||||
|
Иные значения BC - новые прошивки.
|
||||||
|
|
||||||
|
##### *Комментарий к функциям CMOS (0F5h-0F7h)*
|
||||||
|
Функции CMOS_RD, CMOS_WR, CMOS_TEST работают всегда. Если в машине нет
|
||||||
|
микросхемы CMOS, то эмулируется ее память. Наличие микросхемы
|
||||||
|
определяется функцией CMOS_TEST.
|
||||||
|
|
||||||
|
##### *Комментарий к функции FN_TURBO (08Fh)*
|
||||||
|
Переключение режима турбо может не произойти, если прошивка не
|
||||||
|
поддерживает это переключение. При этом ошибки не происходит. Так же,
|
||||||
|
переключение режима TURBO блокируется кнопкой "Turbo" в режиме Turbo-OFF
|
||||||
|
|
||||||
|
##### *Комментарий к функциям печати текста.*
|
||||||
|
Эти функции работают с текущим окном, которым всегда является последнее
|
||||||
|
открытое окно. К графическому экрану функции печати текста не применимы.
|
||||||
|
|
||||||
|
##### *Описатель окна.*
|
||||||
|
Для открытия окон используется 32-хбайтовый описатель окна (дескриптор),
|
||||||
|
адрес которого указывается в регистре IX.
|
||||||
|
|
||||||
|
IX - 32-хбайтовый описатель окна
|
||||||
|
(IX+0) - горизонтальный размер окна в знакоместах
|
||||||
|
(IX+1) - вертикальный размер в знакоместах
|
||||||
|
(IX+2) - положение окна по горизонтали на экране в знакоместах
|
||||||
|
(IX+3) - положение окна по вертикали на экране в знакоместах
|
||||||
|
(IX+4) - режим знакоместа
|
||||||
|
bit4=1 - text_mode bit4=0 - graf_mode
|
||||||
|
bit5=0 - 16, bit5=1 - 8 точек в знакоместе
|
||||||
|
graf_mode bit3..0 - не существенны
|
||||||
|
bit7..6 - номер палитры
|
||||||
|
text_mode bit7..6,3..0 - номер знакогенератора
|
||||||
|
исключение: bit7..6=B"11" - бордер
|
||||||
|
(IX+5) - дополнительный режим знакоместа
|
||||||
|
bit0=1 - указывает на включение спектрумовской
|
||||||
|
адресации экрана
|
||||||
|
(IX+6) - положение по X в поле графики (по знакоместам)
|
||||||
|
(IX+7) - положение по Y в поле графики (по знакоместам)
|
||||||
|
разъяснения о положении в поле графики - ниже
|
||||||
|
(IX+8..31) - зарезервировано (переменные окна)
|
||||||
|
в этих байтах должны быть нули
|
||||||
|
|
||||||
|
При открытии окна описатель копируется в системную страницу ОЗУ и
|
||||||
|
программа может не сохранять его. Что бы описатель окна не потерялся,
|
||||||
|
программа получает идентификатор окна. Он же идентификатор глобального
|
||||||
|
окна. В функциях запоминания, восстановления, перемещения, а так же
|
||||||
|
функциях стирания, скроллинга и т.п. идентификатор окна определяет
|
||||||
|
область экрана, относительно которой производится работа с локальными
|
||||||
|
окнами. Подразумеваются локальные окна в смысле "окно в окне".
|
||||||
|
Идентификатор окна определяет глобальное окно, отнoсительно которого
|
||||||
|
адресуются локальные. В части функций глобальное окно определяется по
|
||||||
|
умолчанию, как последнее, с которым производились действия с явным
|
||||||
|
указанием идентификатора.
|
||||||
|
|
||||||
|
В данный момент BIOS хранит только один описатель окна - последний,
|
||||||
|
с которым была произведена функция открытия. Идентификатор окна
|
||||||
|
выставляется в 0. В дальнейшем планитруется разработка функций со
|
||||||
|
множеством окон, потому, во избежание неприятностей в будущем, при
|
||||||
|
работе с окнами, программисту следует запоминать идентификатор окна
|
||||||
|
и пользоваться этим значением при работе с ним.
|
||||||
|
|
||||||
|
Типы стандартных окон:
|
||||||
|
0 - окно 32x24 в формате ZX Spectrum
|
||||||
|
1 - текстовое окно 64x24
|
||||||
|
2 - текстовое окно 40x32
|
||||||
|
3 - текстовое окно 80x32
|
||||||
|
4 - окно в формате ZX Spectrum, HL - положение окна на экране в знакоместах
|
||||||
|
5 - текстовое окно 64x24, HL - положение окна на экране в знакоместах
|
||||||
|
6 - текстовое окно 40x32, HL - положение окна на экране в знакоместах
|
||||||
|
7 - текстовое окно 80x32, HL - положение окна на экране в знакоместах
|
||||||
|
8 - графическое окно 0, HL - положение окна на экране
|
||||||
|
9 - графическое окно 1, HL - положение окна на экране
|
||||||
|
|
||||||
|
Данные палитры должны представлять собой список приблизительно такого вида:
|
||||||
|
|
||||||
|
DB blue1,green1,red1,0
|
||||||
|
DB blue2,green2,red2,0
|
||||||
|
.....................
|
||||||
|
DB blueN,greenN,redN,0
|
||||||
|
|
||||||
|
N - количество цветов. Значеное равное 0 соответствует 256-ти цветам.
|
||||||
|
При записи в видео-ОЗУ все данные предварительно проходят функцию AND
|
||||||
|
со значением регистра маски - B.
|
||||||
|
|
||||||
|
Страницы палитры 0..3 соответствуют графическим режимам. Для вывода в
|
||||||
|
соответствующей палитре нужно задать соответствующее значение bit7..6 в
|
||||||
|
байте режима знакоместа
|
||||||
|
|
||||||
|
Страницы 4..7 соответствуют текстовому режиму и спектрумовскому режиму.
|
||||||
|
В странице 4 задается цвет PAPER для каждого атрибута. В странице 5
|
||||||
|
задается цвет INK для каждого атрибута. В странице 6 задается цвет PAPER,
|
||||||
|
которым он будет моргать в режиме FLASH В странице 7 задается цвет INK,
|
||||||
|
которым он будет моргать в режиме FLASH. Таким образом, для каждого из
|
||||||
|
256-ти атрибутов задается четыре цвета если цвета 4,5 совпадают с
|
||||||
|
цветами 6,7 то режим FLASH оказывается отключенным. Для его включения
|
||||||
|
в спектрумовском режиме надо поменять местами цвета 6 и 7. Если надо
|
||||||
|
включить FLASH в режим IBM-CGA, следует установить цвета 6 и 7
|
||||||
|
одинаковыми и равными цвету 4. По сути режим FLASH всегда включен, и
|
||||||
|
на экране постоянно меняются цвета PAPER с 4-го на 6-й, а цвета INK с
|
||||||
|
5 на 7-й. Если эти пары цветов для атрибута знакоместа устанавливаются
|
||||||
|
одинаковыми, то FLASH в этом месте не виден.
|
||||||
|
|
||||||
|
##### *Комментарий к функциям работы с устройствами хранения информации.*
|
||||||
|
|
||||||
|
В этих функциях в регистре A обычно задается номер и тип устройства:
|
||||||
|
бит 0..3 - номер устройства
|
||||||
|
бит 4..7 - тип устройства:
|
||||||
|
0 - дисковод
|
||||||
|
6 - ram-disk
|
||||||
|
8 - HDD
|
||||||
|
C - CD-ROM
|
||||||
|
|
||||||
|
остальные номера не используются
|
||||||
|
|
||||||
|
А так же задаются: старшая часть номера сектора в регисте HL,
|
||||||
|
младшая часть номера сектора в регистре IX.
|
||||||
|
|
||||||
@@ -0,0 +1,901 @@
|
|||||||
|
# Функции BIOS v3.00
|
||||||
|
|
||||||
|
### Вызов функций BIOS
|
||||||
|
|
||||||
|
**Вызов функций BIOS осуществляется из ассемблерного кода.**
|
||||||
|
|
||||||
|
Номер функции задается в регистре C процессора. В остальные
|
||||||
|
регистры, при необходимости, загружаются входные параметры функции.
|
||||||
|
После исполнения функции происходит возврат в программу, из которой
|
||||||
|
произошел вызов функции. Установленный флаг CF (CF=1) означает, что
|
||||||
|
работа функции произошла с ошибкой. В некоторых регистрах передаются
|
||||||
|
выходные параметры.
|
||||||
|
|
||||||
|
Ниже приведены таблицы входных и выходных параметров для каждой функции:
|
||||||
|
|
||||||
|
- Функции работы с памятью
|
||||||
|
- Функции управления 'железом'
|
||||||
|
- Функции управления окнами и режимами экрана
|
||||||
|
- Функции вывода текста на экран
|
||||||
|
- Графические функции
|
||||||
|
- Функции работы с жесткими дисками и дисководами
|
||||||
|
|
||||||
|
При работе функций BIOS необходимо что бы стек находился в области
|
||||||
|
8000h..0BFFFh, так как часть функций использует переключение страниц
|
||||||
|
PAGE1 и PAGE3.
|
||||||
|
|
||||||
|
Вызов функций BIOS возможен в различных конфигурациях компьютера
|
||||||
|
Sprinter.
|
||||||
|
|
||||||
|
**Конфигурация Spectrum:** вызов функций BIOS осуществляется через
|
||||||
|
3D13h. При этом работают и все функции TR-DOS.
|
||||||
|
|
||||||
|
**Конфигурации Sprinter:** вызов функций BIOS осуществляется через RST
|
||||||
|
18h при подключенном системном ПЗУ.
|
||||||
|
|
||||||
|
Для постоянного подключения системного ПЗУ можно воспользоваться такой
|
||||||
|
последовательностью команд:
|
||||||
|
|
||||||
|
```asm
|
||||||
|
LD A,0
|
||||||
|
OUT (07Ch),A
|
||||||
|
```
|
||||||
|
|
||||||
|
После ее исполнения в 0-м окне Z80 будет включено ПЗУ BIOSа и программа
|
||||||
|
может вызывать функции BIOSа через RST 18h.
|
||||||
|
|
||||||
|
Отключение ПЗУ BIOSа из нулевого окна Z80 производится следующей
|
||||||
|
последовательностью команд:
|
||||||
|
|
||||||
|
```asm
|
||||||
|
LD A,0
|
||||||
|
OUT (03Ch),A
|
||||||
|
```
|
||||||
|
|
||||||
|
При необходимости, функции BIOSа могут быть вызваны программой,
|
||||||
|
находящейся в ОЗУ непосредственно в нулевом окне Z80. Для этого надо
|
||||||
|
установить в адресе 0008h следующий код:
|
||||||
|
|
||||||
|
```asm
|
||||||
|
ADDRESS_0008h:
|
||||||
|
PUSH AF
|
||||||
|
LD A,0
|
||||||
|
OUT (7Ch),A
|
||||||
|
POP AF
|
||||||
|
RET
|
||||||
|
```
|
||||||
|
|
||||||
|
После этого BIOS можно вызывать командой RST 8. (Функции TR-DOS, так
|
||||||
|
же как и в случае RST 18 остаются недоступны.) Вызывая программы таким
|
||||||
|
образом, через RST 8, следует помнить что адреса 3FFFh..0000h после
|
||||||
|
входа в BIOS будут содержать код ПЗУ, поэтому, если фунция использует
|
||||||
|
данные в ОЗУ, они должны находиться в других адресах.
|
||||||
|
|
||||||
|
Оптимизация программы для RST 8 недопустима, так как в ПЗУ, для
|
||||||
|
обратного переключения, стоит такая же программа, только порт 3Ch для
|
||||||
|
отключения ПЗУ BIOSа.
|
||||||
|
|
||||||
|
Вызов функций BIOS в exe-файлах, вызываемых с помощью операционной
|
||||||
|
системы Estex, производится командой RST 8. Необходимая программа в
|
||||||
|
адресе 0008h уже имеется в блоке кода ОС Estex.
|
||||||
|
|
||||||
|
### Функции работы с памятью
|
||||||
|
|
||||||
|
|
||||||
|
**0C0h (192) EMM_FN0 Определение объемов ОЗУ**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C0h
|
||||||
|
Значение регистров на выходе:
|
||||||
|
HL - общий объем ОЗУ в страницах по 16k
|
||||||
|
BC - объем свободного ОЗУ в страницах по 16k
|
||||||
|
|
||||||
|
**0C1h (193) EMM_FN1 Инициализация распределения памяти**
|
||||||
|
Стирается вся информация о выделенных ранее блоках ОЗУ.
|
||||||
|
Блоки с системной информацией и первые 256K ОЗУ объявляются занятыми.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C1h
|
||||||
|
Значение регистров на выходе:
|
||||||
|
нет
|
||||||
|
|
||||||
|
**0C2h (194) EMM_FN2 Выделение блока ОЗУ**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C2h
|
||||||
|
B - число запрашиваемых страниц
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение - A - идентификатор блока
|
||||||
|
CF=1 - ошибка - A=1 - не хватает памяти
|
||||||
|
|
||||||
|
**0C3h (195) EMM_FN3 Освободить блок ОЗУ**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C3h
|
||||||
|
A - идентификатор блока
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неправильный идентификатор
|
||||||
|
идентификатор не всегда отслеживается правильно
|
||||||
|
|
||||||
|
|
||||||
|
**0C4h (196) EMM_FN4 Получить физический номер страницы из блока памяти**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C4h
|
||||||
|
A - идентификатор блока
|
||||||
|
B - логическая номер страницы в блоке
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - A - логический номер страницы
|
||||||
|
CF=1 - ошибка:
|
||||||
|
A=0 - блок не существует
|
||||||
|
A=255 - запрашиваемый номер страницы слишком велик
|
||||||
|
|
||||||
|
**0C5h (197) EMM_FN5 Получить список физических страниц блока**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C5h
|
||||||
|
A - идентификатор блока
|
||||||
|
HL - буфер 256 байт для размещения списка страниц
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение:
|
||||||
|
B - число страниц в блоке
|
||||||
|
HL - тот же адрес буфера, в буфере список физических
|
||||||
|
страниц по порядку, заканчивающийся байтом 0FFh
|
||||||
|
CF=1 - неверный идентификатор блока; старая информация в буфере
|
||||||
|
может быть затерта
|
||||||
|
|
||||||
|
**0C6h (198) EMM_FN6 Получение адресов портов окон**
|
||||||
|
|
||||||
|
Примечание по использованию функции получения адресов портов окон (0C6h):
|
||||||
|
>Cледует хотя бы один раз вызвать эти функции и сравнить адреса
|
||||||
|
>портов с теми, что используются в программе и, если они не совпадают,
|
||||||
|
>выдать соответствующее предупреждение. В данный момент эти порты
|
||||||
|
>таковы: PAGE0=82h, PAGE1=0A2h, PAGE2=0C2h, PAGE3=0E2h
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C6h
|
||||||
|
A - номер окна процессора - 0,1,2 или 3
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
C - 8-битный адрес порта окна
|
||||||
|
B - физический номер подключенной в окно страницы
|
||||||
|
CF=1 - ошибка - неверный номер окна
|
||||||
|
|
||||||
|
**0C7h (199) EMM_FN7 Получить номер следующей страницы блока**
|
||||||
|
|
||||||
|
Примечание по использованию функции EMM_FN7 (0C7h):
|
||||||
|
> Информация о распределении памяти хранится в виде RAM Allocation Table,
|
||||||
|
> похожей на дисковый FAT. Поэтому нахождение физического номера
|
||||||
|
> следующей страницы по предыдущему физическому номеру происходит
|
||||||
|
> значительно быстрее, чем поиск по увеличенному на единицу логическому
|
||||||
|
> номеру.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0C7h
|
||||||
|
A - физическая страница
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
A - следуюшая физическая страница блока
|
||||||
|
A=0FFh - индицирует конец блока
|
||||||
|
CF=1 - ошибка - страница не принадлежит никакому блоку.
|
||||||
|
фактически, это означает, что она свободна.
|
||||||
|
|
||||||
|
**09Eh (158) EMM_FN8 Слияние блоков**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
A - идентификатор блока 1
|
||||||
|
B - идентификатор блока 2
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
A - идентификатор объединенного блока
|
||||||
|
CF=1 - ошибка - неверный идентификатор блока
|
||||||
|
|
||||||
|
**09Dh (157) EMM_FN9 Разделение блока**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=09Dh
|
||||||
|
A - идентификатор блока
|
||||||
|
B - новая длина блока
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
A - идентификатор блока результата
|
||||||
|
B - идентификатор блока остатка
|
||||||
|
CF=1 - ошибка - неверный идентификатор блока
|
||||||
|
|
||||||
|
### Функции управления 'железом'
|
||||||
|
|
||||||
|
**0EFh (239) FN_VERSION Выдача информации о версии BIOSа и железа.**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0EFh
|
||||||
|
HL - буфер, куда будет помещена ASCII строка с несколькими
|
||||||
|
полями, номером версии BIOS и названием модели
|
||||||
|
компьютера. Конец строки отмечен двойным нулем.
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
HL - тот же буфер с записанной строкой.
|
||||||
|
DE - версия BIOSа
|
||||||
|
BC - версия железа подробности ниже
|
||||||
|
A - количество полей в буфере (в данный момент - 2)
|
||||||
|
Первое поле - версия BIOS.
|
||||||
|
Второе - название модели компьютера.
|
||||||
|
CF=1 - ошибка - Очень старая версия,
|
||||||
|
не имеющая данной функции
|
||||||
|
|
||||||
|
**0F2h (242) FN_SICF=0 Установка синхронизации, очистка страницы режима экрана**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0F2h
|
||||||
|
A - режим синхронизации
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неверный номер режима синхронизации
|
||||||
|
|
||||||
|
### Функции работы с CMOS данными и Turbo режимом
|
||||||
|
|
||||||
|
Комментарий к функциям CMOS (0F5h-0F7h):
|
||||||
|
> Функции CMOS_RD, CMOS_WR, CMOS_TEST работают всегда. Если в машине нет
|
||||||
|
> микросхемы CMOS, то эмулируется ее память. Наличие микросхемы
|
||||||
|
> определяется функцией CMOS_TEST.
|
||||||
|
|
||||||
|
**0F5h (245) CMOS_TEST Проверить наличие CMOS**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0F5h
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - часы есть
|
||||||
|
CF=1 - часов нет
|
||||||
|
|
||||||
|
**0F6h (246) CMOS_RD Читать из регистра CMOS**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0F6h
|
||||||
|
D - номер регистра CMOS
|
||||||
|
Значение регистров на выходе:
|
||||||
|
A - считанные данные
|
||||||
|
CF=0 - часы есть
|
||||||
|
CF=1 - часов нет
|
||||||
|
|
||||||
|
**0F7h (247) CMOS_WR Писать в регистр CMOS**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0F7h
|
||||||
|
D - номер регистра CMOS
|
||||||
|
A - записываемые данные
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - часы есть
|
||||||
|
CF=1 - часов нет
|
||||||
|
|
||||||
|
**08Fh (143) FN_TURBO Функция управления турбо режимом.**
|
||||||
|
|
||||||
|
Комментарий к функции FN_TURBO (08Fh):
|
||||||
|
Переключение режима турбо может не произойти, если прошивка не
|
||||||
|
поддерживает это переключение. При этом ошибки не происходит. Так
|
||||||
|
же, переключение режима TURBO блокируется кнопкой "Turbo" в
|
||||||
|
режиме Turbo-OFF
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Fh
|
||||||
|
A - режим турбо: 2 - off, 3 - on
|
||||||
|
A - режим FDD: 12h - 720Kb, 13h - 1.44Mb
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неверный режим турбо
|
||||||
|
|
||||||
|
### Функции управления окнами и режимами экрана
|
||||||
|
|
||||||
|
**0B0h (176) WIN_OPEN Функция открытия окна.**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B0h
|
||||||
|
IX - описатель окна
|
||||||
|
E - флаги окна:
|
||||||
|
бит 0 указывает какую страницу режима включать после
|
||||||
|
исполнения функции;
|
||||||
|
бит 4 указывает на какой странице режима открывать окно
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение:
|
||||||
|
A - идентификатор окна
|
||||||
|
CF=1 - ошибка слишком много окон
|
||||||
|
|
||||||
|
**0B1h (177) WIN_CLOSE закрытие окна**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B1h
|
||||||
|
A - идентификатор окна
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - успешное завершение
|
||||||
|
CF=1 - ошибка - неверный идентификатор
|
||||||
|
Окно с номером 0 никогда не закрывается и попытка
|
||||||
|
закрытия приводит к ошибке
|
||||||
|
|
||||||
|
**0B2h (178) WIN_COPY_WIN Копирование данных текстового окна в память (запоминание окна)**
|
||||||
|
|
||||||
|
При работе этой функции через RST 18h или RST 8, обязателен запрет
|
||||||
|
прерываний, так как функция пользуется стеком для ускорения своей работы.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B2h
|
||||||
|
A - идентификатор глобального окна
|
||||||
|
H - размер окна в символах по вертикали
|
||||||
|
L - размер окна в символах по горизонтали
|
||||||
|
D - вертикальное положение окна в глобальном окне
|
||||||
|
E - горизонтальное положение окна в глобальном окне
|
||||||
|
IX - адрес буфера для запоминания данных
|
||||||
|
адрес буфера указывается для окна 0C000h если адрес
|
||||||
|
указан с 8000h, номер страницы буфера не действителен
|
||||||
|
ниже 8000h адрес указывать нельзя
|
||||||
|
A' - страница буфера для данных окна эта страница должна
|
||||||
|
принадлежать программе
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка - неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B3h (179) WIN_RESTORE_WIN Копирование из памяти в текстовое окно (восстановление окна)**
|
||||||
|
|
||||||
|
При работе этой функции через RST 18h или RST 8, обязателен запрет
|
||||||
|
прерываний, так как функция пользуется стеком для ускорения своей работы.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B2h
|
||||||
|
A - идентификатор глобального окна
|
||||||
|
H - размер окна в символах по вертикали
|
||||||
|
L - размер окна в символах по горизонтали
|
||||||
|
D - вертикальное положение окна в глобальном окне
|
||||||
|
E - горизонтальное положение окна в глобальном окне
|
||||||
|
IX - адрес буфера для запоминания данных
|
||||||
|
адрес буфера указывается для окна 0C000h если адрес
|
||||||
|
указан с 8000h, номер страницы буфера не действителен
|
||||||
|
ниже 8000h адрес указывать нельзя
|
||||||
|
A' - страница буфера для данных окна эта страница должна
|
||||||
|
принадлежать программе
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка - неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B4h (180) WIN_GET_SYM Взять символ с экрана**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B4h
|
||||||
|
A - идентификатор окна
|
||||||
|
DE - положение символа в окне:
|
||||||
|
D - вертикаль, E - горизонталь
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
L - символ, H - атрибут,
|
||||||
|
B - знакогенератор
|
||||||
|
CF=1 - ошибка неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B5h (181) WIN_PUT_SYM Положить символ на экран**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B5h
|
||||||
|
A - идентификатор окна
|
||||||
|
DE - положение символа в окне:
|
||||||
|
D - вертикаль, E - горизонталь
|
||||||
|
L - символ, H - атрибут символа
|
||||||
|
B - знакогенератор
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B6h (182) WIN_SET_ZG установка знакогенератора**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B6h
|
||||||
|
A - системный номер знакогенератора
|
||||||
|
DE - указатель на 2Kb блок данных знакогенератора
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка (старая версия, нет функции)
|
||||||
|
|
||||||
|
**0B7h (183) WIN_MOVE_WIN Перемещение окна**
|
||||||
|
|
||||||
|
При работе этой функции через RST 18h или RST 8, обязателен запрет
|
||||||
|
прерываний, так как функция пользуется стеком для ускорения своей работы.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B7h
|
||||||
|
A - идентификатор глобального окна
|
||||||
|
H - размер локального окна по вертикали в символах
|
||||||
|
L - размер локального окна по горизонтали в символах
|
||||||
|
D - положение локального окна по вертикали в символах
|
||||||
|
E - положение локального окна по горизонтали в символах
|
||||||
|
IX - новое положение локального окна (подобно DE)
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка - неверный идентификатор окна
|
||||||
|
|
||||||
|
**0B8h (184) WIN_GET_ZG Получение знакогенератора**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0B8h
|
||||||
|
DE - адрес, куда будет загружено 2kb знакогенератора
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка (старая версия, нет функции)
|
||||||
|
|
||||||
|
### Функции вывода текста на экран
|
||||||
|
|
||||||
|
**081h (129) LP_PRINT_ALL Печать символов с атрибутом**
|
||||||
|
|
||||||
|
На экран выводится строка из B одинаковых символов
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=081h
|
||||||
|
A - символ
|
||||||
|
E - атрибут
|
||||||
|
B - число выводимых символов
|
||||||
|
регистры HL,IX - сохраняются
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**082h (131) LP_PRINT_SYM Вывод символов на экран без атрибута**
|
||||||
|
|
||||||
|
На экран выводится строка из B одинаковых символов атрибут
|
||||||
|
остается тот, который был на экране
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=082h
|
||||||
|
A - символ
|
||||||
|
B - число выводимых символов
|
||||||
|
регистры HL,IX - сохраняются
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**083h (131) LP_PRINT_ATR печать атрибутов**
|
||||||
|
|
||||||
|
На экран выводится строка из B одинаковых атрибутов.
|
||||||
|
Символы не меняются.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=083h
|
||||||
|
E - атрибут
|
||||||
|
B - число выводимых символов
|
||||||
|
регистры HL,IX - сохраняются
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**084h (132) LP_SET_PLACE Установка текущего знакоместа в окне**
|
||||||
|
|
||||||
|
Позиция печати устанавливается в соответстии с регистром DE
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=084h
|
||||||
|
E - положение символа по горизонтали
|
||||||
|
D - номер символа по вертикали
|
||||||
|
Превышение границ приводит не к ошибке, а к переустановке
|
||||||
|
с начала, за вычетом полного размера окна
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**085h (133) LP_PRINT_LN Вывод строки символов на экран с текущего знакоместа**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=085h
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
E - атрибут, с которым будет выведена строка
|
||||||
|
B - длина выводимой строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**086h (134) LP_PRINT_LN2 Вывод строки символов на экран без атрибутов**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=086h
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
B - длина выводимой строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**087h (135) LP_PRINT_LN3 Вывод строки символов до разделителя**
|
||||||
|
|
||||||
|
После разделителя выводятся пробелы, что бы вывести B символов
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=087h
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
E - атрибут, с которым будет выведена строка
|
||||||
|
B - длина выводимой строки
|
||||||
|
D - символ-разделитель, указывающий конец строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**088h (136) LP_PRINT_LN4 Вывод строки символов до разделителя, без атрибутов**
|
||||||
|
|
||||||
|
символы из выводятся на экран, пока не встретится символ равный D,
|
||||||
|
далее печатаются пробелы, как дополнение строки до B символов.
|
||||||
|
Атрибуты не изменяются.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=088h
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
B - длина выводимой строки
|
||||||
|
D - символ-разделитель, указывающий конец строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**089h (137) LP_CLS_WIN Очистка экрана**
|
||||||
|
|
||||||
|
Выполнение производится выводом пробелов с заданным атрибутом
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=089h
|
||||||
|
DE - положение локального окна
|
||||||
|
H - размер в символах локального окна по вертикали
|
||||||
|
L - размер в символах локального окна по горизонтали
|
||||||
|
B - атрибут очистки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Ah (138) LP_SCROLL_UD Скроллинг части глобального окна вверх/вниз**
|
||||||
|
|
||||||
|
Скроллируются полные строки глобального окна
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Ah
|
||||||
|
B - тип скроллинга: 1 - вверх; 2 - вниз
|
||||||
|
D - начальная строка скроллинга
|
||||||
|
E - число скроллируемых строк
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Bh (139) LP_PRINT_LN5 Вывод строки символов на экран до разделителя**
|
||||||
|
|
||||||
|
После разделителя вывод останавливается
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
E - атрибут, с которым будет выведена строка
|
||||||
|
B - максимальная длина выводимой строки
|
||||||
|
D - символ-разделитель, указывающий конец строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Ch (140) LP_PRINT_LN6 Вывод строки символов на экран до разделителя без атрибутов**
|
||||||
|
|
||||||
|
После разделителя вывод останавливается.
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Ch
|
||||||
|
HL - адрес строки должен быть между 04000h и 0BFFFh
|
||||||
|
B - максимальная длина выводимой строки
|
||||||
|
D - символ-разделитель, указывающий конец строки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Dh (141) LP_CLS_WIN2 Очистка экрана с указанием символа заполнения**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Dh
|
||||||
|
DE - положение локального окна
|
||||||
|
H - размер в символах локального окна по вертикали
|
||||||
|
L - размер в символах локального окна по горизонтали
|
||||||
|
B - атрибут очистки
|
||||||
|
A - символ очистки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**08Eh (142) LP_GET_PLACE Получить текущее положение вывода на экран**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=08Eh
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
DE - координаты, в которых будет напечатан
|
||||||
|
следующий символ:
|
||||||
|
D - вертикаль, E - горизонталь
|
||||||
|
|
||||||
|
### Графические функции
|
||||||
|
|
||||||
|
**0A1h (161) PIC_POINT Установить точку**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0A1h
|
||||||
|
DE - координата по вертикали (пиксели)
|
||||||
|
HL - координата по горизонтали (пиксели)
|
||||||
|
Координаты считаются от верхнего левого угла экрана
|
||||||
|
A - идентификатор окна
|
||||||
|
B - цвет точки
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неверный идентификатор окна
|
||||||
|
|
||||||
|
**0A4h (164) PIC_SET_PAL Установка палитры**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0A4h
|
||||||
|
HL - данные палитры
|
||||||
|
E - номер начального цвета
|
||||||
|
D - количество устанавливаемых цветов
|
||||||
|
B - маска при установке палитры.
|
||||||
|
Для нормального режима должнa быть 0FFh
|
||||||
|
A -
|
||||||
|
0..3 биты - значения 0..7 - номер палитры
|
||||||
|
- значения 8..15 - зарезервированы
|
||||||
|
4..6 биты - зарезервированы (установить в 0)
|
||||||
|
7 бит -
|
||||||
|
- значение 0 - установить
|
||||||
|
- значение 1 - загрузить палитру в память
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - всегда
|
||||||
|
|
||||||
|
**0A6h (166) SET_PAL_INIT Установка внутренней палитры**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=0A6h
|
||||||
|
A - страница палитры
|
||||||
|
B - номер палитры:
|
||||||
|
B=3 - установка текстовой палитры CGA
|
||||||
|
B=2 - установка спектрумовской палитры
|
||||||
|
B=1 - установка графической плаитры
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - неверный номер палитры
|
||||||
|
|
||||||
|
### Функции работы с жесткими дисками и дисководами
|
||||||
|
|
||||||
|
**50h,52h,53h (80,82,83) Зарезервированы**
|
||||||
|
|
||||||
|
Значение регистров на входе и на выходе:
|
||||||
|
нет
|
||||||
|
|
||||||
|
**51h (81) DRV_RESET Сброс контроллера и настройка на диск**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=51h
|
||||||
|
A - номер и тип устройства
|
||||||
|
бит 7..4 - тип устройства:
|
||||||
|
#0x - FDD
|
||||||
|
#6x - RAM-DISK
|
||||||
|
#8x - HDD
|
||||||
|
#Cx - CD-ROM
|
||||||
|
бит 3..0 - номер устройства
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка, нет диска или нет устройства
|
||||||
|
|
||||||
|
**54h (84) DRV_VERIFY Проверка секторов**
|
||||||
|
|
||||||
|
Проверка внутренняя на совпадение ECC
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=54h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
HL:IX - номер сектора (IX - младшая часть номера сектора)
|
||||||
|
B - количество проверяемых секторов
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - проверка с ошибкой
|
||||||
|
|
||||||
|
**55h (85) DRV_READ Чтение с устройства**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=55h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
HL:IX - номер сектора (IX - младшая часть номера сектора)
|
||||||
|
B - количество секторов
|
||||||
|
DE - адрес буфера для данных
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка чтения
|
||||||
|
HL:IX - номер сектора + кол-во прочитанных секторов
|
||||||
|
DE - адрес буфера для данных + (кол-во прочитанных секторов * размер сектора)
|
||||||
|
|
||||||
|
**56h (86) DRV_WRITE Запись на устройства**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=56h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
HL:IX - номер сектора (IX - младшая часть номера сектора)
|
||||||
|
B - количество секторов
|
||||||
|
DE - адрес буфера данных для записи
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
CF=1 - ошибка записи
|
||||||
|
HL:IX - номер сектора + кол-во прочитанных секторов
|
||||||
|
DE - адрес буфера для данных + (кол-во прочитанных секторов * размер сектора)
|
||||||
|
|
||||||
|
**57h (87) DRV_DETECT Определение параметров устройства**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=57h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
A - bit7=0 диск 720Кb
|
||||||
|
bit7=1 диск 1.44Mb
|
||||||
|
CF=1 - нет устройства или нет носителя
|
||||||
|
|
||||||
|
**58h (88) DRV_GET_PAR Получить параметры носителя**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=58h
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
L - число секторов
|
||||||
|
H - число головок
|
||||||
|
DE - количество цилиндров
|
||||||
|
если HL=DE=0FFFFh - устройства нет
|
||||||
|
IX - размер сектора в байтах
|
||||||
|
B - доп. параметры для дискет:
|
||||||
|
бит7 - тип 1.44Mb/720Kb
|
||||||
|
CF=1 - нет устройства
|
||||||
|
|
||||||
|
**59h (89) DRV_SET_PAR Установить параметры носителя**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
A - номер и тип устройства (см. выше)
|
||||||
|
L - число секторов
|
||||||
|
H - число головок
|
||||||
|
DE - количество цилиндров
|
||||||
|
IX - размер сектора в байтах
|
||||||
|
B - доп. параметры для дискет
|
||||||
|
бит7 - тип 1.44Mb/720Kb
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
|
||||||
|
**5Ah (90) EXT_VERSION Номер версии дисковой спецификации.**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=5Ah
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
D - версия
|
||||||
|
E - модификация
|
||||||
|
CF=1 - ошибка
|
||||||
|
|
||||||
|
**5Fh (95) DRV_LIST Список дисковых устройств**
|
||||||
|
|
||||||
|
Значение регистров на входе:
|
||||||
|
C=5Fh
|
||||||
|
IX - буфер для списка устройств
|
||||||
|
Значение регистров на выходе:
|
||||||
|
CF=0 - нормальное завершение
|
||||||
|
|
||||||
|
В буфере список дисков в формате:
|
||||||
|
|
||||||
|
IX+0 - размер заполненого буфера
|
||||||
|
IX+1 - кол-во устройств FDD
|
||||||
|
IX+2 - кол-во устройств HDD
|
||||||
|
IX+3 - кол-во устройств CD DRIVE
|
||||||
|
IX+4 - #00 - конец списка, иначе кол-во устройств нового типа
|
||||||
|
|
||||||
|
|
||||||
|
### Примечания и комментарии.
|
||||||
|
|
||||||
|
##### *Примечание по использованию функции получения адресов портов окон (0C6h).*
|
||||||
|
Cледует хотя бы один раз вызвать эти функции и сравнить адреса портов с
|
||||||
|
теми, что используются в программе и, если они не совпадают, выдать
|
||||||
|
соответствующее предупреждение. В данный момент эти порты таковы:
|
||||||
|
PAGE0=82h, PAGE1=0A2h, PAGE2=0C2h, PAGE3=0E2h
|
||||||
|
|
||||||
|
##### *Примечание по использованию функции EMM_FN7 (0C7h).*
|
||||||
|
Информация о распределении памяти хранится в виде RAM Allocation Table,
|
||||||
|
похожей на дисковый FAT. Поэтому нахождение физического номера следующей
|
||||||
|
страницы по предыдущему физическому номеру происходит значительно быстрее,
|
||||||
|
чем поиск по увеличенному на единицу логическому номеру.
|
||||||
|
|
||||||
|
##### *Комментарий к функции FN_VERSION (0EFh).*
|
||||||
|
Значения регистра BC на выходе и соответствующая ему конфигурация
|
||||||
|
BC=FFFF - Не определено
|
||||||
|
BC=FFFE - Конфигурация Spectrum, режим Sprinter ZX
|
||||||
|
BC=FFFD - Конфигурация Sprinter
|
||||||
|
BC=FFFC - Зарезервировано
|
||||||
|
BC=FFFB - Зарезервировано
|
||||||
|
BC=FFFA - Зарезервировано
|
||||||
|
BC=FFF9 - Зарезервировано
|
||||||
|
Иные значения BC - новые прошивки.
|
||||||
|
|
||||||
|
##### *Комментарий к функциям CMOS (0F5h-0F7h)*
|
||||||
|
Функции CMOS_RD, CMOS_WR, CMOS_TEST работают всегда. Если в машине нет
|
||||||
|
микросхемы CMOS, то эмулируется ее память. Наличие микросхемы
|
||||||
|
определяется функцией CMOS_TEST.
|
||||||
|
|
||||||
|
##### *Комментарий к функции FN_TURBO (08Fh)*
|
||||||
|
Переключение режима турбо может не произойти, если прошивка не
|
||||||
|
поддерживает это переключение. При этом ошибки не происходит. Так же,
|
||||||
|
переключение режима TURBO блокируется кнопкой "Turbo" в режиме Turbo-OFF
|
||||||
|
|
||||||
|
##### *Комментарий к функциям печати текста.*
|
||||||
|
Эти функции работают с текущим окном, которым всегда является последнее
|
||||||
|
открытое окно. К графическому экрану функции печати текста не применимы.
|
||||||
|
|
||||||
|
##### *Описатель окна.*
|
||||||
|
Для открытия окон используется 32-хбайтовый описатель окна (дескриптор),
|
||||||
|
адрес которого указывается в регистре IX.
|
||||||
|
|
||||||
|
IX - 32-хбайтовый описатель окна
|
||||||
|
(IX+0) - горизонтальный размер окна в знакоместах
|
||||||
|
(IX+1) - вертикальный размер в знакоместах
|
||||||
|
(IX+2) - положение окна по горизонтали на экране в знакоместах
|
||||||
|
(IX+3) - положение окна по вертикали на экране в знакоместах
|
||||||
|
(IX+4) - режим знакоместа
|
||||||
|
bit4=1 - text_mode bit4=0 - graf_mode
|
||||||
|
bit5=0 - 16, bit5=1 - 8 точек в знакоместе
|
||||||
|
graf_mode bit3..0 - не существенны
|
||||||
|
bit7..6 - номер палитры
|
||||||
|
text_mode bit7..6,3..0 - номер знакогенератора
|
||||||
|
исключение: bit7..6=B"11" - бордер
|
||||||
|
(IX+5) - дополнительный режим знакоместа
|
||||||
|
bit0=1 - указывает на включение спектрумовской
|
||||||
|
адресации экрана
|
||||||
|
(IX+6) - положение по X в поле графики (по знакоместам)
|
||||||
|
(IX+7) - положение по Y в поле графики (по знакоместам)
|
||||||
|
разъяснения о положении в поле графики - ниже
|
||||||
|
(IX+8..31) - зарезервировано (переменные окна)
|
||||||
|
в этих байтах должны быть нули
|
||||||
|
|
||||||
|
При открытии окна описатель копируется в системную страницу ОЗУ и
|
||||||
|
программа может не сохранять его. Что бы описатель окна не потерялся,
|
||||||
|
программа получает идентификатор окна. Он же идентификатор глобального
|
||||||
|
окна. В функциях запоминания, восстановления, перемещения, а так же
|
||||||
|
функциях стирания, скроллинга и т.п. идентификатор окна определяет
|
||||||
|
область экрана, относительно которой производится работа с локальными
|
||||||
|
окнами. Подразумеваются локальные окна в смысле "окно в окне".
|
||||||
|
Идентификатор окна определяет глобальное окно, отнoсительно которого
|
||||||
|
адресуются локальные. В части функций глобальное окно определяется по
|
||||||
|
умолчанию, как последнее, с которым производились действия с явным
|
||||||
|
указанием идентификатора.
|
||||||
|
|
||||||
|
В данный момент BIOS хранит только один описатель окна - последний,
|
||||||
|
с которым была произведена функция открытия. Идентификатор окна
|
||||||
|
выставляется в 0. В дальнейшем планитруется разработка функций со
|
||||||
|
множеством окон, потому, во избежание неприятностей в будущем, при
|
||||||
|
работе с окнами, программисту следует запоминать идентификатор окна
|
||||||
|
и пользоваться этим значением при работе с ним.
|
||||||
|
|
||||||
|
Типы стандартных окон:
|
||||||
|
0 - окно 32x24 в формате ZX Spectrum
|
||||||
|
1 - текстовое окно 64x24
|
||||||
|
2 - текстовое окно 40x32
|
||||||
|
3 - текстовое окно 80x32
|
||||||
|
4 - окно в формате ZX Spectrum, HL - положение окна на экране в знакоместах
|
||||||
|
5 - текстовое окно 64x24, HL - положение окна на экране в знакоместах
|
||||||
|
6 - текстовое окно 40x32, HL - положение окна на экране в знакоместах
|
||||||
|
7 - текстовое окно 80x32, HL - положение окна на экране в знакоместах
|
||||||
|
8 - графическое окно 0, HL - положение окна на экране
|
||||||
|
9 - графическое окно 1, HL - положение окна на экране
|
||||||
|
|
||||||
|
Данные палитры должны представлять собой список приблизительно такого вида:
|
||||||
|
|
||||||
|
DB blue1,green1,red1,0
|
||||||
|
DB blue2,green2,red2,0
|
||||||
|
.....................
|
||||||
|
DB blueN,greenN,redN,0
|
||||||
|
|
||||||
|
N - количество цветов. Значеное равное 0 соответствует 256-ти цветам.
|
||||||
|
При записи в видео-ОЗУ все данные предварительно проходят функцию AND
|
||||||
|
со значением регистра маски - B.
|
||||||
|
|
||||||
|
Страницы палитры 0..3 соответствуют графическим режимам. Для вывода в
|
||||||
|
соответствующей палитре нужно задать соответствующее значение bit7..6 в
|
||||||
|
байте режима знакоместа
|
||||||
|
|
||||||
|
Страницы 4..7 соответствуют текстовому режиму и спектрумовскому режиму.
|
||||||
|
В странице 4 задается цвет PAPER для каждого атрибута. В странице 5
|
||||||
|
задается цвет INK для каждого атрибута. В странице 6 задается цвет PAPER,
|
||||||
|
которым он будет моргать в режиме FLASH В странице 7 задается цвет INK,
|
||||||
|
которым он будет моргать в режиме FLASH. Таким образом, для каждого из
|
||||||
|
256-ти атрибутов задается четыре цвета если цвета 4,5 совпадают с
|
||||||
|
цветами 6,7 то режим FLASH оказывается отключенным. Для его включения
|
||||||
|
в спектрумовском режиме надо поменять местами цвета 6 и 7. Если надо
|
||||||
|
включить FLASH в режим IBM-CGA, следует установить цвета 6 и 7
|
||||||
|
одинаковыми и равными цвету 4. По сути режим FLASH всегда включен, и
|
||||||
|
на экране постоянно меняются цвета PAPER с 4-го на 6-й, а цвета INK с
|
||||||
|
5 на 7-й. Если эти пары цветов для атрибута знакоместа устанавливаются
|
||||||
|
одинаковыми, то FLASH в этом месте не виден.
|
||||||
|
|
||||||
|
##### *Комментарий к функциям работы с устройствами хранения информации.*
|
||||||
|
|
||||||
|
В этих функциях в регистре A обычно задается номер и тип устройства:
|
||||||
|
|
||||||
|
бит 0..3 - номер устройства
|
||||||
|
бит 4..7 - тип устройства:
|
||||||
|
0 - дисковод
|
||||||
|
6 - ram-disk
|
||||||
|
8 - HDD
|
||||||
|
C - CD-ROM
|
||||||
|
|
||||||
|
остальные номера не используются
|
||||||
Binary file not shown.
@@ -0,0 +1,155 @@
|
|||||||
|
Estex: Disk SubSystem (DSS) Programming Guide
|
||||||
|
|
||||||
|
Table of Contents
|
||||||
|
1. Introducing
|
||||||
|
2. Identification of system functions
|
||||||
|
3. Disk devices functions
|
||||||
|
|
||||||
|
|
||||||
|
1. Introducing
|
||||||
|
|
||||||
|
This document contains the list of functions and concepts of
|
||||||
|
interaction with a disk subsystem.
|
||||||
|
DSS is a collection of very useful functions that reside in
|
||||||
|
DSS itself, ready for use by any your programs. These functions
|
||||||
|
are stored in library SYSTEM.DOS and allow management of files,
|
||||||
|
memory allocation, loading and execution of the programs.
|
||||||
|
|
||||||
|
File specification
|
||||||
|
|
||||||
|
The file specification is a string, containing a names of disk,
|
||||||
|
directories separated by a symbol "\" and name of file. The names
|
||||||
|
of disk drive and directories can be discard.
|
||||||
|
|
||||||
|
for example:
|
||||||
|
C:\TEXT\DOC\text.doc
|
||||||
|
A:file.txt
|
||||||
|
\TEXT\info.txt
|
||||||
|
|
||||||
|
The DSS used chars with colon suffix as names of disk devices
|
||||||
|
(A:, B:, C: etc.) The name of disk can be written down before
|
||||||
|
filename for specified disk there it placed.
|
||||||
|
For example: command
|
||||||
|
DIR C:DATFILE
|
||||||
|
searches for DATFILE in the current directory of disk C:.
|
||||||
|
When disk name not specified DSS used current disk. At start
|
||||||
|
DSS, the current disk is a disk whence was loaded DSS.
|
||||||
|
The filenames consist of two parts. The first part contain 8
|
||||||
|
chars of file name. The second part is not necessary and contain
|
||||||
|
3 chars of file type (also known as extentsion). At the writing
|
||||||
|
of filename, both parts are separated by char point.
|
||||||
|
For example: the names "NAME" and "NAME." is specified same file.
|
||||||
|
In the name don't allows symbols with codes less 32 and chars
|
||||||
|
. " / \ [ ] : | < > + = ; ,
|
||||||
|
As the subdirectories files too, their names are formed by
|
||||||
|
same way. The name of root directory always "\". And each
|
||||||
|
subdirectories contain two items with names "." and "..". The
|
||||||
|
name "." specified a current directory and name ".." specified
|
||||||
|
name of parent(uplevel) directory.
|
||||||
|
Some console commands and DSS functions allow to use global
|
||||||
|
symbols ? and * which can be used for filename templates.
|
||||||
|
The symbol ? means that any one char of filename. The
|
||||||
|
symbol * means that it char can be replaced by any symbols.
|
||||||
|
For example:
|
||||||
|
*.txt - means, all files with type "txt"
|
||||||
|
a??.* - means, files which contain three or less symbols and
|
||||||
|
first symbol is "a"
|
||||||
|
dc*.exe - means, files with type "exe" and began "dc"
|
||||||
|
|
||||||
|
File attributes
|
||||||
|
|
||||||
|
The each bit of byte attributes specified various attribute.
|
||||||
|
And it can be changed by DSS function.
|
||||||
|
|
||||||
|
bit 0 - Read only
|
||||||
|
bit 1 - Hidden
|
||||||
|
bit 2 - System
|
||||||
|
bit 3 - Volume label
|
||||||
|
bit 4 - Directory
|
||||||
|
bit 5 - Archive
|
||||||
|
bit 6 - Reserved
|
||||||
|
bit 7 - Reserved
|
||||||
|
|
||||||
|
Attribute "read only". When value is 1, file can be read,
|
||||||
|
but can't be written or deleted.
|
||||||
|
Attribute "hidden". When value is 1, DSS can't manipulate
|
||||||
|
with this file.
|
||||||
|
Attribute "system". Specified system file.
|
||||||
|
Attribute "volume label". In old version of MSDOS used for
|
||||||
|
specified volume laben, now it can be used for long filenames.
|
||||||
|
And must be 0 for compatibles.
|
||||||
|
Attribute "directory". When value is 1, means that this
|
||||||
|
file is directory.
|
||||||
|
Attribute "archive". This bite sets in 1 when DSS writing
|
||||||
|
in this file. It can be used in backup utilities for detect
|
||||||
|
changed files.
|
||||||
|
|
||||||
|
File handle
|
||||||
|
When any file are opened, DSS build File Control Block in
|
||||||
|
DSS working areas.
|
||||||
|
The Handle (and assigned file) identified by number which
|
||||||
|
returned DSS to program after file opening and used it in all
|
||||||
|
further DSS calls. In other words, when file is opening, the
|
||||||
|
program informs DSS his name and has taken back file handle.
|
||||||
|
Which used in further file operations.
|
||||||
|
All necessary information for working with file are placed
|
||||||
|
in DSS working areas.
|
||||||
|
|
||||||
|
|
||||||
|
2. Identification of system functions
|
||||||
|
|
||||||
|
00h (00) VERSION (Version of DSS)
|
||||||
|
input:
|
||||||
|
C - 00h
|
||||||
|
output:
|
||||||
|
D - version number
|
||||||
|
E - modification
|
||||||
|
The function return version number of DSS.
|
||||||
|
|
||||||
|
|
||||||
|
3. Disk devices functions
|
||||||
|
|
||||||
|
01h (01) CHDISK (Change current disk)
|
||||||
|
input:
|
||||||
|
A - disk number (0-A,1-B...)
|
||||||
|
C - 01h
|
||||||
|
output:
|
||||||
|
A - error code, if CF=1
|
||||||
|
A - number of disks, if CF=0
|
||||||
|
The function changes current disk device.
|
||||||
|
|
||||||
|
02h (02) CURDISK (Current disk number)
|
||||||
|
input:
|
||||||
|
C - 02h
|
||||||
|
output:
|
||||||
|
A - current disk number (0-A,1-B...)
|
||||||
|
The function returns number of current disk device.
|
||||||
|
|
||||||
|
03h (03) DSKINFO (Disk information)
|
||||||
|
input:
|
||||||
|
A - disk number (0-A,1-B...0FFh-current)
|
||||||
|
C - 03h
|
||||||
|
output:
|
||||||
|
A - error code, if CF=1
|
||||||
|
A - sectors per cluster, if CF=0
|
||||||
|
HL - clusters per disk
|
||||||
|
DE - free clusters
|
||||||
|
BC - bytes per sector
|
||||||
|
The function returns information about disk device
|
||||||
|
(capacity and free space).
|
||||||
|
for example:
|
||||||
|
LD C,03h ;Function DSKINFO
|
||||||
|
LD A,0FFh ;Information about current disk
|
||||||
|
RST 10h ;Execution of function
|
||||||
|
LD A,D ;There is a free
|
||||||
|
OR E ;space?
|
||||||
|
JR Z,NO_SPACE ;No, the disk is completely filled
|
||||||
|
|
||||||
|
09h (09) BOOTDSK (Number of boot disk)
|
||||||
|
input:
|
||||||
|
C - 09h
|
||||||
|
B = 0
|
||||||
|
output:
|
||||||
|
A - number of boot disk (0-A,1-B...)
|
||||||
|
The function returns number of boot disk device whence was loaded DSS.
|
||||||
|
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
Estex: Дисковая подсистема (DSS) – Обзор
|
||||||
|
|
||||||
|
1. Введение
|
||||||
|
2. Загрузка подсистемы
|
||||||
|
3. Системная консоль
|
||||||
|
4. Файловая система
|
||||||
|
|
||||||
|
1. Введение
|
||||||
|
Estex - операционная система компьютера Sprinter, включающая
|
||||||
|
в себя различные модули. Данный документ описывает модуль дисковой
|
||||||
|
подсистемы.
|
||||||
|
В DSS используется та же самая файловая система, как и в
|
||||||
|
MS-DOS FAT16 и полностью с ней совместима.
|
||||||
|
|
||||||
|
2. Загрузка подсистемы
|
||||||
|
После включения питания или сброса компьютера, BIOS считывает
|
||||||
|
первичный загрузчик с 1-го сектора загрузочного диска.
|
||||||
|
Если загрузка происходит с HDD или дискеты, то сначала загрузочный
|
||||||
|
сектор считывается в память и ему передается управление по загрузке
|
||||||
|
модуля дисковой подсистемы SYSTEM.DOS.
|
||||||
|
Затем выполняются следующие действия:
|
||||||
|
• инициализация дисковой подсистемы и вывод сообщения "Starting DOS..."
|
||||||
|
• загрузка системной консоли SYSTEM.EXE
|
||||||
|
• выполнение команд указанных в файле SYSTEM.BAT
|
||||||
|
Обычно файл SYSTEM.BAT содержит путь к программе файловой навигации
|
||||||
|
пользователя или другому часто используемому приложения.
|
||||||
|
Например "c:\fn\fn.exe".
|
||||||
|
|
||||||
|
Если во время загрузки вы хотите пропустить выполнение SYSTEM.BAT.
|
||||||
|
То вам следует нажать клавишу "SHIFT", как только появиться
|
||||||
|
сообщение "Starting DOS..." и удерживать пока не появится приглашение
|
||||||
|
консоли ("C:\>").
|
||||||
|
|
||||||
|
3. Системная консоль
|
||||||
|
В DSS многие задачи могут быть выполнены через интерфейс командной
|
||||||
|
строки называемой системной консолью. Основная задача консоли ввод
|
||||||
|
команд и их исполнение. Также она имеет ряд функций, которые выполняют
|
||||||
|
такие действия как управление файлами, перемещение по файловой структуре
|
||||||
|
каталогов, редактирование командной строки и переменных среды.
|
||||||
|
Системная консоль позволяет пользователю взаимодействовать с
|
||||||
|
операционной системой. Для DOS системная консоль это SYSTEM.EXE. Если вы
|
||||||
|
видите на экране приглашение командной строки (A:\> или C:\>), то это
|
||||||
|
означает что SYSTEM.EXE загружен и активизирован. Когда вы вводите
|
||||||
|
командную строку, командный процессор интерпретирует команду и выполняет
|
||||||
|
необходимые действия.
|
||||||
|
На сегодняшний день в консоли доступны следующие команды:
|
||||||
|
CD Displays the name of or changes the current directory.
|
||||||
|
CHDIR Displays the name of or changes the current directory.
|
||||||
|
CLS Clears the screen.
|
||||||
|
DATE Displays or sets the date.
|
||||||
|
DEL Deletes one or more files.
|
||||||
|
DIR Displays a list of files and subdirectories in a directory.
|
||||||
|
ECHO Displays messages, or turns command echoing on or off.
|
||||||
|
ERASE Deletes one or more files.
|
||||||
|
EXIT Quits the SYSTEM.EXE program (command interpreter).
|
||||||
|
HELP Provides Help information for console commands.
|
||||||
|
MD Creates a directory.
|
||||||
|
MKDIR Creates a directory.
|
||||||
|
PAUSE Suspends processing of a batch file and displays a message.
|
||||||
|
RD Removes a directory.
|
||||||
|
REM Records comments (remarks) in batch files or SYSTEM.BAT.
|
||||||
|
REN Renames a file or files.
|
||||||
|
RENAME Renames a file or files.
|
||||||
|
RMDIR Removes a directory.
|
||||||
|
TIME Displays or sets the system time.
|
||||||
|
VER Displays the System version.
|
||||||
|
|
||||||
|
4. Файловая система
|
||||||
|
Сейчас, в качестве файловой системы Estex использует FAT12 и FAT16.
|
||||||
|
С помощью файловой системы FAT (File Allocation Table) организуются
|
||||||
|
данные на винчестере и дискетах.
|
||||||
|
Для указания спецификации файла используется следующая форма:
|
||||||
|
|
||||||
|
[drive:][directory\]filename[.ext]
|
||||||
|
|
||||||
|
Файловая спецификация - это строка символов содержащая наименования
|
||||||
|
диска, директорий отделенных символом "\" и имя файла. Имена диска и
|
||||||
|
директории могут быть опущены, если требуемый файл расположен в текущей
|
||||||
|
директории.
|
||||||
|
|
||||||
|
Например:
|
||||||
|
|
||||||
|
C:\TEXT\DOC\text.doc
|
||||||
|
A:file.txt
|
||||||
|
\TEXT\info.txt
|
||||||
|
|
||||||
|
В DSS в качестве имен дисковых устройств используются буквы с
|
||||||
|
последующим символом двоеточия (A:, B:, C: и.т.д.) Имя диска может быть
|
||||||
|
набрано перед именем файла для указания диска, на котором он расположен.
|
||||||
|
|
||||||
|
Например:
|
||||||
|
команда
|
||||||
|
DIR C:TESTFILE
|
||||||
|
ищет TESTFILE в текущей директории диска C:.
|
||||||
|
Если имя диска не указанно используется текущий диск. После запуска DSS,
|
||||||
|
текущим диском является диск, с которого была загружена DSS.
|
||||||
|
|
||||||
|
Имена файлов состоят из двух частей. Первая часть может содержать
|
||||||
|
8 букв, цифр или следующие специальные символы:
|
||||||
|
$ % ' – _ @ { } ~ ` ! # ( ).
|
||||||
|
Вторая часть не является обязательной и содержит любую комбинацию из трех
|
||||||
|
букв, цифр или специальных символов с предшествующей точкой (.).
|
||||||
|
Например имена "NAME" и "NAME." указывают на одинаковый файл.
|
||||||
|
В имени файла не допускаются символы с кодом меньше 32, а также символы
|
||||||
|
. " / \ [ ] : | < > + = ; ,
|
||||||
|
Поскольку директории также являются файлами их имена образуются по
|
||||||
|
тем же правилам.
|
||||||
|
Имя корневой директории всегда "\". И каждая поддиректория содержит
|
||||||
|
два элемента с именами "." and "..". Имя "." указывает на текущую
|
||||||
|
директорию, а имя ".." указывает на родительную (на уровень выше)
|
||||||
|
директорию.
|
||||||
|
Некоторые команды и функции DSS позволяют использовать глобальные
|
||||||
|
символы * и ? которые могут использоваться для задания шаблона имени
|
||||||
|
файла.
|
||||||
|
Символ ? означает любой один символ в имени файла.
|
||||||
|
Символ * означает, что он может быть заменен на любое количество
|
||||||
|
любых символов.
|
||||||
|
|
||||||
|
for example:
|
||||||
|
*.txt - означает, все файлы с типом "txt"
|
||||||
|
a??.* - означает, файлы содержащие три и менее символов и первый символ "a"
|
||||||
|
dc*.exe - означает, файлы с типом "exe" и начинающиеся на "dc"
|
||||||
|
|
||||||
|
В именах файлов не делается различий между заглавными и прописными
|
||||||
|
символами.
|
||||||
|
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
|||||||
|
Акселератор компьютера Sprinter.
|
||||||
|
|
||||||
|
Акселератор предназначен для ускорения операций по пересылке блоков данных в ОЗУ и видео-ОЗУ.
|
||||||
|
|
||||||
|
Акселератор позволяет:
|
||||||
|
|
||||||
|
- быстро заполнять горизонтальную или вертикальную линию длиной до 256 точек одним цветом (в режиме 640x256 - одинарную/двойную горизонтальную линию длиной до 512 точек)
|
||||||
|
- быстро копировать горизонтальную или вертикальную линию длиной до 256 точек (в режиме 640x256 - горизонтальную линию до 512 точек)
|
||||||
|
- проводить быстрые операции AND, OR, XOR с блоками памяти.
|
||||||
|
|
||||||
|
Акселератор не может работать с блоками данных ПЗУ и Быстрого-ОЗУ.
|
||||||
|
|
||||||
|
ОЗУ акселератора является частью внутреннего ОЗУ ППЛМ.
|
||||||
|
Операции по пересылке данных производятся путем записи блока данных в это
|
||||||
|
внутреннее ОЗУ, а затем копировании его в нужное место ОЗУ из ОЗУ акселератора.
|
||||||
|
Блок данных, записываемый в ОЗУ акселератора может иметь различную
|
||||||
|
длинну из диапазона 1..256 байт.
|
||||||
|
|
||||||
|
После одной записи копирование может производиться несколько раз и, таким
|
||||||
|
образом, можно производить заполнение экрана текстурами.
|
||||||
|
|
||||||
|
Для заполнения экрана одним цветом используется другой режим
|
||||||
|
акселератора. В нем вместо копируемого блока данных из внутреннего ОЗУ
|
||||||
|
производится запись данных с шины процессора, которые в этот момент не
|
||||||
|
изменяются.
|
||||||
|
|
||||||
|
Управление акселератором производится непосредственно из программы.
|
||||||
|
Для этого изпользуются команды процессора, которые, фактически, являются
|
||||||
|
операциями типа NOP.
|
||||||
|
|
||||||
|
LD B,B - выключить акселетарор.
|
||||||
|
LD D,D - включить акселератор в режим приема байта размера блока
|
||||||
|
далее следует команда типа LD A,dat, где dat и будет новым
|
||||||
|
размером блока. Если размер блока был установлен ранее,
|
||||||
|
его можно не устанавливать.
|
||||||
|
LD C,C - Операция Fill - заполнение одним байтом. Последующая
|
||||||
|
команда типа LD (HL),A приведет к заполнению указанного
|
||||||
|
ранее количества байт значением A
|
||||||
|
LD E,E - Операция Fill для графического экрана - заполнение
|
||||||
|
вертикальных линий.
|
||||||
|
LD H,H - rezerved
|
||||||
|
LD L,L - копирование блока. Последующая команда типа LD A,(HL)
|
||||||
|
приведет к заполнению ОЗУ акселератора данными из адреса (HL),
|
||||||
|
а команда типа LD (DE),A приведет к перезаписи данных из ОЗУ
|
||||||
|
акселератора в ОЗУ или видео-ОЗУ.
|
||||||
|
LD A,A - копирование блока для графического экрана подобна команде
|
||||||
|
LD L,L, но работает с вертикальными линиями экрана.
|
||||||
|
|
||||||
|
Пример использования акселератора:
|
||||||
|
|
||||||
|
; Считаем, что экранная страница уже открыта по адресу #C000
|
||||||
|
LD HL,#C040 ; адрес начала линии первого экрана
|
||||||
|
LD DE,#C180 ; адрес начала линии второго экрана
|
||||||
|
LD BC,#140 ; длина экрана по горизонтали
|
||||||
|
DI ; запретить прерывания для работы с акселератором
|
||||||
|
LD D,D ; включить акселератор на установку размера блока
|
||||||
|
LD A,0 ; установить размер блока - 256 байт
|
||||||
|
LD A,A ; установить акселератор на копирование
|
||||||
|
; вертикальных линий.
|
||||||
|
LDIR ; копировать
|
||||||
|
LD B,B ; выключить акселератор
|
||||||
|
EI ; включить прерывания
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Эта часть программы произведет копирование всего содержимого первого экрана на другой.
|
||||||
|
Время исполения составляет примерно 26 милисекунд.
|
||||||
|
|
||||||
|
Дополнительные функции акселератора (AND, OR, XOR) работают таким же образом.
|
||||||
|
Для выполнения логических функций используются команды XOR (HL); OR (HL); AND (HL).
|
||||||
|
|
||||||
|
Пример кодирования блока в 256 байт.
|
||||||
|
|
||||||
|
LD HL,ADRES_1
|
||||||
|
LD DE,XOR_DAT
|
||||||
|
DI
|
||||||
|
LD D,D
|
||||||
|
LD A,0 ; число байт, которые надо закодировать
|
||||||
|
LD L,L
|
||||||
|
LD A,(DE) ; взять блок данных в ОЗУ акселератора
|
||||||
|
XOR (HL) ; произвести операцию XOR с данными акселератора
|
||||||
|
LD (HL),A ; запомнить в ОЗУ результат операции
|
||||||
|
LD B,B
|
||||||
|
EI
|
||||||
|
|
||||||
|
|
||||||
|
Скорость работы акселератора ограничивается только физической
|
||||||
|
скоростью работы основного ОЗУ. Определить примерное время работы команды с
|
||||||
|
акселератором можно по такой формуле:
|
||||||
|
|
||||||
|
Время работы = время работы команды без акселератора + время работы
|
||||||
|
акселератора
|
||||||
|
|
||||||
|
Время работы акселератора = число пересылаемых байт /7 микросекунд
|
||||||
|
|
||||||
|
Во время работы акселератора необходимо отключать прерывания, так как в этот момент
|
||||||
|
изменяется система команд процессора и программа на прерывании не сможет работать корректно.
|
||||||
@@ -0,0 +1,635 @@
|
|||||||
|
ÜÜÜÜÜÜ
|
||||||
|
ÜÛ°°°°°°
|
||||||
|
Û°° Û°°
|
||||||
|
Û°°ÜÜÜÛ°°
|
||||||
|
Û°°°°°°°°
|
||||||
|
Û°° Û°°
|
||||||
|
Û°° Û°° àå¨â¥ªâãà ª®¬¯ìîâ¥à Sprinter.
|
||||||
|
ß°° ß°°
|
||||||
|
|
||||||
|
‚¢¥¤¥¨¥.
|
||||||
|
|
||||||
|
„ ®¥ ®¯¨á ¨¥ ¯à¥¤¯®« £ ¥â «¨ç¨¥ ®¯à¥¤¥«¥ëå § ¨© ç¨â ⥫ï,
|
||||||
|
¨¬¥® § ¨¥ àå¨â¥ªâãàë ª®¬¯ìîâ¥à ZX-Spectrum ¨ ¨å à §®¢¨¤®á⥩, ¢
|
||||||
|
ç áâ®á⨠Pentagon-128 ¨ Scorpion-256, â ª ¦¥ § ¨¥ ï§ëª BASIC ¨
|
||||||
|
¥ª®â®à®¥ § ª®¬á⢮ á ï§ëª®¬ áᥬ¡«¥à Z80.
|
||||||
|
‡¤¥áì ï ¡ã¤ã §ë¢ âì ª®ä¨£ãà æ¨¥© ¬ è¨ë - ª®ªà¥âãî ॠ«¨§ æ¨î
|
||||||
|
ª®ªà¥â®© áå¥¬ë ¢ ¯¥à¥¯à®£à ¬¬¨à㥬®© «®£¨ç¥áª®© ¬¨ªà®á奬¥ (��‹Œ).
|
||||||
|
�â® ®§ ç ¥â, çâ® ¬ è¨ ¨¬¥¥â ¬®¦¥á⢮ ª®ä¨£ãà æ¨©, ª ¦¤ ï ¨§ ª®â®àëå
|
||||||
|
¨¬¥¥â ᢮î á奬ã.
|
||||||
|
Ÿ â ª ¦¥ ¨á¯®«ì§ãî ¯®ï⨥ Š�˜-އ“. �â® ¥ Š�˜ ¢ ä®à¬ «ì®¬
|
||||||
|
á¬ëá«¥, ¡ëáâ஥ އ“, ¢ ª®â®à®¬ ¯à®æ¥áá®à ¬®¦¥â à ¡®â âì ¢ë᮪®©
|
||||||
|
ç áâ®â¥ ¡¥§ ®¦¨¤ ¨ï. Š�˜-¥¬ íâ® Ž‡“ §ë¢ ¥âáï ⮫쪮 ¯® âà ¤¨æ¨¨,
|
||||||
|
¯®¤®¡® Š�˜-ã Š�537�“10 ¢ ª®¬¯ìîâ¥à å Pentagon-128.
|
||||||
|
|
||||||
|
|
||||||
|
Šà ⪨¥ ¤ ë¥ ª®¬¯ìîâ¥à Sprinter.
|
||||||
|
|
||||||
|
�p®æ¥áá®p . . . . . . . . . . . Z84C15
|
||||||
|
’ ªâ®¢ ï ç áâ®â . . . . 21MHz/3.5MHz
|
||||||
|
އ“ . . . . . . . . . . . . . . 4096Kb
|
||||||
|
Š�˜ އ“ . . . . . . . . . . . . . 64Kb
|
||||||
|
�‡“ . . . . . . . . . . . . . . .128Kb
|
||||||
|
‚¨¤¥®-އ“ . . . . . . . . . 256Kb(512)
|
||||||
|
Š®âp®««¥p ¤¨áª®¢ . . . . . Šp1818‚ƒ93
|
||||||
|
�®¤¤¥p¦ª 1.44Mb ä®p¬ â . . 3.5"¤¨áª
|
||||||
|
Š®âp®««¥p ¢¨ç¥áâ¥p . . . . . IDE/AT
|
||||||
|
Š®âp®««¥p ª« ¢¨ âãpë . . . 101key/AT
|
||||||
|
Š®âp®««¥p ¬ëè¨ . . . . . . . MS-Mouse
|
||||||
|
„¢ á«®â . . . . . . . áâ ¤ pâ ISA-8
|
||||||
|
†¥«¥§ ï í¬ã«ïæ¨ï AY-3-8910 áâ¥à¥®-OUT
|
||||||
|
COVOX . . . . . . . . . 8bit x 4chanel
|
||||||
|
‚¨¤¥®-p¥¦¨¬ë: . . . Spectrum standart
|
||||||
|
GRAF 320x256x256,640x256x16, TXT 80x32
|
||||||
|
‚ë室 ¢¨¤¥® TV ¨«¨ CGA ¬®¨â®p, RGB
|
||||||
|
|
||||||
|
|
||||||
|
’¥å¨ç¥áª ï ॠ«¨§ æ¨ï.
|
||||||
|
|
||||||
|
Ÿ¤à®¬ ¬ è¨ë ïîâáï ¯à®æ¥áá®à Z84C15 ¨ ��‹Œ EPF10K10QC208.
|
||||||
|
Šà®¬¥ ¨å ¯« ⥠¯à¨áãâáâ¢ãîâ ¬¨ªà®á奬a �‡“, 72å-¯¨®¢ë© SIMM
|
||||||
|
4Mb, 256Kb ¢¨¤¥®-އ“, 64Kb Š�˜-އ“, á奬 ª®â஫«¥à ¤¨áª®¢®¤
|
||||||
|
�ˆ‘ Š�1818‚ƒ93, ¡ãä¥àë ¤«ï ¯®¤ª«îç¥¨ï ¤¦®©á⨪ , ¬ £¨â®ä® , ¯à¨â¥à ,
|
||||||
|
ª« ¢¨ âãàë, ¤¨áª®¢®¤®¢, ¢¨ç¥áâ¥à , ¬ëè¨, ¡ãä¥àë¥ ¬¨ªà®á奬ë è¨ë ISA-8
|
||||||
|
¨ ¥é¥ ®¤ ��‹Œ ä¨à¬ë ALTERA - EPM7032LC44. �â ��‹Œ ¥ ¬¥ï¥â ᢮¥©
|
||||||
|
ª®ä¨£ãà æ¨¨ ¨ ¯à¥¤ § ç¥ ¤«ï ®¡¥á¯¥ç¥¨ï á¨åந§ 樨 ¨ ç «ì®£®
|
||||||
|
§ ¯ã᪠ª®¬¯ìîâ¥à . � ¯« ⥠⠪ ¦¥ ¯à¥¤ãᬮâॠ¢®§¬®¦®áâì ¯®¤ª«î票ï
|
||||||
|
CMOS ç ᮢ ®á®¢¥ ¬¨ªà®á奬ë DALLAS. Šà®¬¥ ¯¥à¨ä¥à¨¨ ¨ ¡ãä¥à®¢ ¨¬¥îâáï
|
||||||
|
¬¨ªà®áå¥¬ë ¤¥è¨äà æ¨¨, ¢å®¤ë ª®â®àëå ¯®¤ª«îç îâáï ª ¯à®æ¥áá®àã ç¥à¥§ ��‹Œ.
|
||||||
|
�â® ¯®§¢®«ï¥â «¥£ª® ¬¥ïâì ¤à¥á æ¨î ãáâனá⢠¡¥§ ª ª®£® «¨¡® ¨§¬¥¥¨ï
|
||||||
|
à §¢®¤ª¨ ¯¥ç ⮩ ¯« âë.
|
||||||
|
|
||||||
|
|
||||||
|
‚®§¬®¦®á⨠àå¨â¥ªâãàë ¬ è¨ë.
|
||||||
|
|
||||||
|
‘奬 ª®¬¯ìîâ¥p ®á®¢ ¡®«ì让 ¯¥p¥¯p®£p ¬¬¨p㥬®© «®£¨ç¥áª®©
|
||||||
|
¬¨ªp®á奬¥. �®¤ª«î票¥ ¯¥à¨ä¥à¨©ëå ãáâனá⢠ç¥à¥§ ��‹Œ ¯®§¢®«ï¥â ¯®«ãç¨âì
|
||||||
|
¢ë᮪ãî £¨¡ª®áâì ¬ è¨ë ¯® ª®ä¨£ãà æ¨ï¬.
|
||||||
|
�p®£p ¬¬¨p®¢ ¨¥ ��‹Œ ®áãé¥á⢫ï¥âáï ¥¯®áp¥¤á⢥® ¢ ¬®¬¥â
|
||||||
|
¢ª«î票ï, â ª ¦¥ ¯p¨ ¯¥p¥§ £p㧪¥, çâ® ¯®§¢®«ï¥â ª p¤¨ «ì® ¬¥ïâì
|
||||||
|
á奬㠢 ��‹Œ ¥¯®áp¥¤á⢥® ¢® ¢p¥¬ï p ¡®âë. �â® á¨«ì® ¢ë¤¥«ï¥â
|
||||||
|
àå¨â¥ªâãàã ª®¬¯ìîâ¥à ¨§ àï¤ áãé¥áâ¢ãîé¨å ª®¬¯ìîâ¥à®¢ ¨ ¯®í⮬㠬®£¨¥
|
||||||
|
¯®ïâ¨ï, ¯à¨áã騥 ®¡ëçë¬ ¬ è¨ ¬, ¬¥ïîâ ᢮© á¬ëá«. ” ªâ¨ç¥áª¨ ª®¬¯ìîâ¥à
|
||||||
|
¨¬¥¥â ¨§¬¥ï¥¬ãî àå¨â¥ªâãàã, ¢ ª®â®à®© ¢®§¬®¦ë ¨§¬¥¥¨ï ¢® ¬®£¨å ç áâïå
|
||||||
|
á奬ë. ’ ª, ¯à¨¬¥à, ¥«ì§ï £®¢®à¨âì ® ª®ªà¥âëå ¤à¥á å ¯®à⮢
|
||||||
|
¯®¤ª«îç¥¨ï ¯¥à¨ä¥à¨¨, â ª ª ª ®¨ ¬®£ãâ ¡ëâì ¨§¬¥¥ë ¢ ®¤ã ᥪã¤ã
|
||||||
|
¯ã⥬ ¯¥à¥¯à®£à ¬¬¨à®¢ ¨ï ��‹Œ ¨ ¤ ëå ¢ އ“, ®â¢¥ç îé¨å § ª®ä¨£ãà æ¨î
|
||||||
|
¯®à⮢. Š®ªà¥âë¥ ¤à¥á ¯®ï¢«ïîâáï ⮫쪮 ¢ ª®ªà¥âëå ª®ä¨£ãà æ¨ïå,
|
||||||
|
¯à¨¬¥à, â ª®© ª ª ª®ä¨£ãà æ¨ï ZX-Spectrum.
|
||||||
|
�¥à¥¯à®£à ¬¬¨à㥬®áâì áå¥¬ë ¤ ¥â ¤®¢®«ì® ¡®«ìèãî ᢮¡®¤ã
|
||||||
|
ä â §¨¨ ¯à®£à ¬¬¨áâ ¯® ª®ä¨£ãà æ¨¨ ¬ è¨ë. ‡ ¤ã¬ë¢ ï ª®ªà¥âãî
|
||||||
|
à ¡®âã ¯à®£à ¬¬¨áâ ¬®¦¥â ®¯à¥¤¥«¨âì ¢ ª ª®© ª®ä¨£ãà æ¨¨ ¥¥ ¬®¦®
|
||||||
|
ᤥ« âì «ãçè¥, , ¢®§¬®¦®, ¨ ¯à¨¤ã¬ âì á¢®î ª®ä¨£ãà æ¨î, ª®â®àãî
|
||||||
|
§ ⥬ ¬®¦® ॠ«¨§®¢ âì ¢ ��‹Œ ¨ ¢ª«îç¨âì ¯¥à¥¤ § ¯ã᪮¬ í⮩ ¯à®£à ¬¬ë.
|
||||||
|
|
||||||
|
|
||||||
|
�«®ç ï á奬 ª®¬¯ìîâ¥à Sprinter.
|
||||||
|
|
||||||
|
ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄ>Sinc
|
||||||
|
³�à¨â¥à³ ³ 2 ISA SLOTS ³ ³ ÚÄÄÄÄÄÄÄ>R
|
||||||
|
ÃÄÄÄÄÄÄÄ´ ÀÄÄÄÂÄÂÄÂÄÂÄÂÄÄÄÄÄÄÄÂÄÂÄÂÄÂÄÂÄÄÙ ³ ³ ÚÄÄÄÄÄ>G
|
||||||
|
³ Œëèì ³ ÚÄÄÄÁÄÁÄÁÄÁÄÁÄÄÄÄÄÄÄÁÄÁÄÁÄÁÄÁÄÄ¿ ³ ³ ³ ÚÄÄÄ>B
|
||||||
|
ÀÄÂÄÂÄÂÄÙ ³ �ãä¥àë ¨ ¤¥è¨äà â®àë ³ ³ ÚÄÁÄÁÄÁÄ¿
|
||||||
|
³ ³ ³ ÀÄÄÄÂÄÄÄÄÄÄÄÄÄÄÂÄÂÄÄÂÄÂÄÄÄÄÂÄÂÄÙ ³ ³ –€� ³
|
||||||
|
³ ³ ³ ³INT ³ ³ ³ ³ ³ ³ ³ ³ ¡ãä¥à ³
|
||||||
|
ÚÄÄÁÄÁÄÁÂÄ¿ ³ ³ ³ ³ ³ ÚÁÄÁÄÄÄÄÄÄÁÄ¿ÀÄÄÂÄÂÄÄÙ ÚÄÄÄÄÄÄÄÄ¿
|
||||||
|
³ ‚ãâà ³ ÃÄÄÄijÄÄÄÄÄÄÄÄÄÄÙ ÀÄij ³ÄÄÄ´ EPF10K10 ÃÄÄÄÙ ÀÄÄÄÄÄÄ´ ¢¨¤¥® ³
|
||||||
|
³ ¯®àâë ³ ÃÄÄÄijÄÄÄÄÄÄÄÄÄÄDATAij ³ÄÄÄ´ ÃÄÄV_DATAÄÄÄÄ´ ³
|
||||||
|
ÃÄÄÄÄÄÄÄÙ ÃÄÄÄijÄÄÄ¿ ÚÄÄÄÄÄÄÄÄij ³ÄÄÄ´ ÃÄÄÄÄÄÄÄÄÄÄÄÄ´ އ“ ³
|
||||||
|
³ Ã<ÄÄÄÙ ³ ³ ³ ³ ³ ³ ³ ³
|
||||||
|
³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄ´ ÃÄÄÄÄÄÄÄÄÄÄÄÄ´ ³
|
||||||
|
³ Z84C15 ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄADRESSÄÄÄÄÄ´ ÃÄV_ADRESSÄÄÄ´ ³
|
||||||
|
³ ÃÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ÃÄÄÄÄÄÄÄÄÄÄÄÄ´ ³
|
||||||
|
³ ³ ³ ³ ³ ³ ³ ³ ³ ³
|
||||||
|
³ Ã<ÄÄij ³Ä³ ³ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>´ ÃÄÄWE,CSiÄÄÄ>´ ³
|
||||||
|
³ Ã<ÄÄij ³Ä³ ³ÄÄÄÄDIRÄÄÄÄÄÄÄ>´ ³ ÀÄÄÄÄÄÄÄÄÙ
|
||||||
|
³ Ã<ÄÄij ³Ä³ ³ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>´ ÃÄÄÄÄÄÄÄ> Audio OUTs
|
||||||
|
³ ³ ³ ³ ³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄ¿
|
||||||
|
³ ³ ÚÄÁÄÁÄÁÄÁÄÄÄÄÄÄÄ¿ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄ´ MAIN ³
|
||||||
|
³ ³ ³ �‡“ ¨ Š�˜-އ“ Ã<ÄADR'Ä´ ÃÄÄDATAÄÄÄÄÄÄ´ RAM ³
|
||||||
|
ÀÄÂÄÂÄÂÄÄÂÙ ³ CS Ã<ÄCSÄÄÄ´ ÃÄÄÄÄÄÄÄÄÄÄÄÄ´ ³
|
||||||
|
³ ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³ ³ SIMM ³
|
||||||
|
³ D ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄ´ ³
|
||||||
|
³ A ³ ³ ³ EPM7032 ÃÄÄÄÄÄÄÄ>´ ÃÄÄADRESSÄÄÄÄ´ ³
|
||||||
|
³ T ³ ÀÄÄ>´ Sinchro ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄ´ ³
|
||||||
|
³ A ³ ³ HDD_DIR Ã<ÄÄÄÄÄÄÄ´ ³ ³ ³
|
||||||
|
³ ³ ³ ³ ”€�— Ã<ÄÄÄÄÄÄÄ´ ÃÄRAS,CAS,WEÄ´ ³
|
||||||
|
³ ³ ³ ÀÄÂÄÂÄÂÄÂÄÂÄÄÄÄÙ ³ ³ ÀÄÄÄÄÄÄÄÄÙ
|
||||||
|
³ ³ ³ ³ ³ ³ ³ ³ ³ ³
|
||||||
|
ÚÄÁÄÁÄÁÄÄÄÄÄÄÄÄÁÄÁÄÁÄÁÄÁÄÄÄÄÄÄÄ¿ ³ ³
|
||||||
|
³ �¥à¨ä¥à¨©ë¥ ãáâனá⢠Ã<ÄÄÄÄ´ ³
|
||||||
|
³ FDD,HDD,KEMPSTON Ã<DIRÄ´ ³
|
||||||
|
³ Ã<ÄÄÄÄ´ ³
|
||||||
|
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³
|
||||||
|
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>´ ³
|
||||||
|
ÚÄÄÄÄÄÄÄÄ¿ ³ ÚÄÄÄÄÄÄÄÄ¿ ³ ³
|
||||||
|
³ TAPE Ã<ÄÄÙ ³KeyboardÃÄÄÄÄÄÄÄÄÄ>´ ³
|
||||||
|
³ in/out ³ ô ³ ³
|
||||||
|
ÀÄÄÄÄÄÄÄÄÙ ÀÁÁÁÁÁÁÁÁÙ ÀÄÄÄÄÄÄÄÄÄÄÄÙ
|
||||||
|
|
||||||
|
�¨á㮪 1.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
„«ï ¯à®áâ®âë ¥ª®â®àë¥ ¡ãä¥àë ¨ ¤¥è¨äà â®àë á奬¥ ¥ 㪠§ ë.
|
||||||
|
Š®«¨ç¥á⢮ �஢®¤®¢ ¢ è¨ å â ª ¦¥ ãá«®¢ë. — áâì ᨣ «®¢ ã¯à ¢«¥¨ï
|
||||||
|
ãáâனá⢠á ��‹Œ á¬ã«ì⨯«¨æ¨à®¢ ë á ¤à¥á ¬¨ SIMM- .
|
||||||
|
|
||||||
|
|
||||||
|
„ «ì¥©è¥¥ ®¯¨á ¨¥ àå¨â¥ªâãàë ï¥âáï ®¯¨á ¨¥¬ ª®ªà¥âëå
|
||||||
|
ª®ä¨£ãà æ¨© ¨ ç á⥩ ª®ä¨£ãà æ¨©. �® ¯¥à¥¤ í⨬ á«¥¤ã¥â ᪠§ âì ¥áª®«ìª®
|
||||||
|
á«®¢ ® ¯¥à¥ª«î票¨ á ¬¨å ª®ä¨£ãà æ¨©.
|
||||||
|
|
||||||
|
‡ £à㧪 ª®ä¨£ãà æ¨©.
|
||||||
|
|
||||||
|
‚ ¬®¬¥â ¢ª«îç¥¨ï ª®¬¯ìîâ¥à , â ª ¦¥ ¯®á«¥ ¦ â¨ï RESET ¢áï
|
||||||
|
¨ä®à¬ æ¨ï, 室¨¢è ïáï ¢ ��‹Œ ®â¢¥ç îé ï § ª®ªà¥âãî ª®ä¨£ãà æ¨î,
|
||||||
|
áâ¨à ¥âáï. ��‹Œ ¯¥à¥å®¤¨â ¢ ०¨¬ ®¦¨¤ ¨ï § £à㧪¨ ¡«®ª ¤ ëå á奬ë.
|
||||||
|
‚ íâ®â ¬®¬¥â ¯à®æ¥áá®à ¯®«®áâìî ®âª«îç¥ ®â ª ª®© «¨¡® ¯¥à¨ä¥à¨¨.
|
||||||
|
‚ ¥£® ¤à¥á®¥ ¯à®áâà á⢮ ¯ ¬ï⨠®ª §ë¢ ¥âáï ¢ª«îç¥ ®¤ áâà ¨æ �‡“ ¨
|
||||||
|
®¤ áâà ¨æ Ž‡“ Š�˜-¯ ¬ïâ¨. ‹î¡ ï § ¯¨áì ¢ ¤à¥á®¥ ¯à®áâà á⢮ ¯ ¬ïâ¨
|
||||||
|
¯à®æ¥áá®à ¢ íâ®â ¬®¬¥â ¯à¨¢®¤¨â ª § ¯¨á¨ ¤ ëå ¢ ��‹Œ ¨ ¯à®£à ¬¬ ¢
|
||||||
|
¯®¤ª«î祮© áâà ¨æ¥ �‡“ ¨¬¥¥â ⮫쪮 ®¤ã ¥¤¨á⢥ãî æ¥«ì - § £à㧨âì
|
||||||
|
¢ ��‹Œ ¤ ë¥ ª®ä¨£ãà æ¨¨. ‚ í⮩ ¦¥ áâà ¨æ¥ �‡“ 室ïâáï ¤ ë¥
|
||||||
|
ç «ì®© ª®ä¨£ãà æ¨¨. (‚ ¤ ë© ¬®¬¥â íâ® ª®ä¨£ãà æ¨ï Sprinter-1.)
|
||||||
|
�à®£à ¬¬ § £à㧪¨ ª®ä¨£ãà æ¨¨ ¯à®¢¥àï¥â ä« £ ¢ Š�˜-¯ ¬ï⨠¨, ¥á«¨ ®
|
||||||
|
ãáâ ®¢«¥, § £à㦠¥â ¢ ��‹Œ ¤ ë¥ ¨§ އ“, ¥á«¨ á¡à®è¥, â® ¤ ë¥ ¨§
|
||||||
|
�‡“. � í⮬ ®á®¢ ® ¯¥à¥ª®ä¨£ãà¨à®¢ ¨¥ áå¥¬ë ª®¬¯ìîâ¥à .
|
||||||
|
„«ï ¨§¬¥¥¨ï áå¥¬ë ¤® § £à㧨âì ¢ ¯®á«¥¤îî áâà ¨æã Š�˜-¯ ¬ïâ¨
|
||||||
|
¡«®ª ¤ ëå ª®ä¨£ãà æ¨¨ ᮠᬥ饨ï #100 ¨ ¢ëáâ ¢¨âì ä« £, ª®â®àë¬ ï¢«ï¥âáï
|
||||||
|
⥪á⮢ ï áâப "FLEX_10K_LOADING", § ¯¨á ï ¯® ᬥ饨î #80 ¢ í⮩ ¦¥
|
||||||
|
áâà ¨æ¥ Š�˜- . �®á«¥ í⮣® ¤® ¯à®¨§¢¥á⨠¯®«ë© á¡à®á, ª®â®àë©
|
||||||
|
®áãé¥á⢫ï¥âáï ¯à®£à ¬¬® § ¯¨áìî ¢ á¯¥æ¨ «ìãî áâà ¨æã ¯ ¬ï⨠RESET_PAGE.
|
||||||
|
�à®£à ¬¬ ¢ �‡“, § ¯ã᪠¥¬ ï ¯® á¡à®áã 室¨â ä« £ FLEX_10K_LOADING ¨
|
||||||
|
ç¨ ¥â § £à㧪㠤 ëå ¢ ��‹Œ. �ਠí⮬ ® ®¤®¢à¥¬¥® § â¨à ¥â ä« £,
|
||||||
|
çâ® ¯à¥¤®â¢à é ¥â ¯®¢â®àãî § £à㧪㠮¢®© ª®ä¨£ãà æ¨¨ ¯à¨ ¦ ⨨
|
||||||
|
ª®¯ªã RESET ¨ ¯®§¢®«ï¥â ¢¥àãâìáï ¯®á«¥ "àã箣®" á¡à®á ¢ ç «ìãî
|
||||||
|
ª®ä¨£ãà æ¨î. ‡ â¨à ¨¥ ä« £ â ª ¦¥ ¨§¡ ¢«ï¥â ®â ¬ã票© ¢ á«ãç ¥
|
||||||
|
¯®¤ª«îç¥¨ï ¥¯à ¢¨«ì®© ª®ä¨£ãà æ¨¨ ¢® ¢à¥¬ï íªá¯¥à¨¬¥â®¢ á ¯à®£à ¬¬ ¬¨.
|
||||||
|
� ¦ ⨥ RESET ¢á¥£¤ ¢¥à¥â á奬㠢 ç «ìãî ª®ä¨£ãà æ¨î.
|
||||||
|
|
||||||
|
�ਬ¥ç ¨¥:
|
||||||
|
‚ãâà¥ïï ¨ä®à¬ æ¨ï ¡«®ª ¤ ëå ��‹Œ ï¥âáï § ªàë⮩
|
||||||
|
¨ä®à¬ 樥© ä¨à¬ë ALTERA. Šà®¬¥ á ¬¨å ¬¨ªà®á奬 ��‹Œ ALTERA ¯®áâ ¢«ï¥â
|
||||||
|
¨ ¯à®£à ¬¬®¥ ®¡¥á¯¥ç¥¨¥ ¤«ï à §¢®¤ª¨ á奬 ¢ãâਠ��‹Œ. Š á®¦ «¥¨î, íâ
|
||||||
|
¯à®£à ¬¬ ¥ ¬®¦¥â à ¡®â âì ª®¬¯ìîâ¥à¥ ⨯ ZX-Spectrum ¨ ¢ ¡«¨¦ ©è¥¬
|
||||||
|
®¡®§à¨¬®¬ ¡ã¤ã饬 ¥ ¯à¥¤¢¨¤¨âáï ¥¥ ¢¥àá¨ï ¤«ï Sprinter- . �®í⮬ã
|
||||||
|
à §à ¡®âª ®¢ëå ª®ä¨£ãà æ¨© ¬®¦¥â ¯à®¨§¢®¤¨âáï ⮫쪮 ¯à¨ «¨ç¨¨
|
||||||
|
¤®áâ â®ç® ¬®é®© ¬ è¨ë (¢á¥ ¤¥« «®áì Pentium-166) ¨ ¯à®£à ¬¬ë à §¢®¤ª¨
|
||||||
|
á奬 ¢ ��‹Œ, æ¥ ª®â®àãî á®áâ ¢«ï¥â á®â¨ ¤®«« ஢ ‘˜€.
|
||||||
|
‚ á¢ï§¨ á í⨬, ¢ ¤ ë© ¬®¬¥â Sprinter ¨¬¥¥â ¥áª®«ìª® ª®ªà¥âëå
|
||||||
|
ª®ä¨£ãà æ¨©, ¤¢¥ ¨§ ª®â®àëå § ¯¨á ë ¢ �‡“, ®áâ «ìë¥ ¬®£ãâ ¡ëâì
|
||||||
|
¯®¤£à㦥ë á ¤¨áª¥âë ¨«¨ ¢¨ç¥áâ¥à . �®áâ®ï® ¢¥¤¥âáï ᮢ¥àè¥á⢮¢ ¨¥
|
||||||
|
ª®ªà¥âëå ª®ä¨£ãà æ¨© ¨ à §à ¡®âª ®¢ëå.
|
||||||
|
|
||||||
|
Ю䍣ãà æ¨ï Sprinter-1.
|
||||||
|
|
||||||
|
‚ª«îç ¥â ¢ á¥¡ï ª®ä¨£ãà æ¨î Spectrum-128/256, à á¯à¥¤¥«¥¨¥ ¯ ¬ïâ¨
|
||||||
|
¤® 4Mb, à áè¨à¥ë© íªà á ०¨¬ ¬¨ Spectrum, Text-80x32, Graf-320x256x256,
|
||||||
|
ª®â஫«¥à ¤¨áª®¢®¤ , ª®â஫«¥à IDE ¢¨ç¥áâ¥à , ª®â஫«¥à ª« ¢¨ âãàë AT,
|
||||||
|
¯®¤ª«î祮© ª ª ZX-Keyboard, 8-bit COVOX.
|
||||||
|
�â ª®ä¨£ãà æ¨ï ¬ ªá¨¬ «ì® ¯à¨¡«¨¦¥ ª ª®ä®£ãà æ¨¨ ZX-Spectrum
|
||||||
|
¨ ¯®§¢®«ï¥â à ¡®â âì ®¡ëçëå ᯥªâà㬮¢áª¨å ¯à®£à ¬¬ å ¨ ¯®á⥯¥®
|
||||||
|
¬¥ïâì ¨å ¯®¤ à áè¨à¥ë¥ ०¨¬ë íªà ¨ ¯ ¬ïâ¨, â ª ¦¥ ¤«ï à ¡®âë á
|
||||||
|
®¢ë¬¨ ãáâனá⢠¬¨.
|
||||||
|
|
||||||
|
Ю䍣ãà æ¨ï Sprinter-2.
|
||||||
|
|
||||||
|
‚ª«îç ¥â ¢ á¥¡ï ª®ä¨£ãà æ¨î Spectrum-128/256, à á¯à¥¤¥«¥¨¥ ¯ ¬ïâ¨
|
||||||
|
¤® 4Mb, à áè¨à¥ë© íªà á ०¨¬ ¬¨ Spectrum, Text-80x32, Graf-320x256x256,
|
||||||
|
ª®â஫«¥à ¤¨áª®¢®¤ , ª®â஫«¥à IDE ¢¨ç¥áâ¥à , ª®â஫«¥à ª« ¢¨ âãàë AT,
|
||||||
|
¯®¤ª«î祮© ª ª ZX-Keyboard, Accelerator.
|
||||||
|
Ю䍣ãà æ¨ï, ª ª ¨ Sprinter-1 ¯à¨¡«¨¦¥ ª ᯥªâà㬮¢áª®©, ®
|
||||||
|
¨¬¥¥â ¡®«¥¥ ¦¥á⪨¥ âॡ®¢ ¨ï ª ¯à®£à ¬¬ ¬ ¯® ᮢ¬¥á⨬®áâ¨. �®§¢®«ï¥â
|
||||||
|
¨á¯®«ì§®¢ âì ªá¥«¥à â®à ®¯¥à 権 á ®á®¢ë¬ ¨ ¢¨¤¥®-އ“. €ªá¥«¥à â®à
|
||||||
|
ã᪮àï¥â ®¯¥à 樨 ¯¥à¥á뫪¨ ¡«®ª®¢ ¤ ëå ¨ § ¯®«¥¨ï އ“ ®¤¨¬ ¡ ©â®¬
|
||||||
|
¤® 䨧¨ç¥áª®£® ¯à¥¤¥« ᪮à®á⨠®á®¢®£® އ“.
|
||||||
|
‚ ¯®á«¥¤¥© ¢¥àᨨ ª®ä¨£ãà æ¨ï Sprinter-2 ¥ ¨¬¥¥â Spectrum-®¢áª®©
|
||||||
|
ª« ¢¨ âãàë. ‚¬¥áâ® ¥¥ ¨§ ¯®àâ 0FEh áç¨âë¢ ¥âáï ᪠ª®¤ ¯à¨è¥¤è¨© á
|
||||||
|
AT-ª« ¢¨ âãàë.
|
||||||
|
|
||||||
|
Ю䍣ãà æ¨ï ZX-Spectrum-256/AY.
|
||||||
|
|
||||||
|
�â ª®ä¨£ãà æ¨ï ¬ ªá¨¬ «ì® ¯à¨¡«¨¦¥ ª ZX-Spectrum-128/256
|
||||||
|
¨ ¢ª«îç ¥â ¢ ᥡï á奬㠬ã§ëª «ì®£® á®¯à®æ¥áá®à AY-3-8910. ‚ í⮩
|
||||||
|
ª®ä¨£ãà æ¨¨ ®âáãâáâ¢ãîâ à áè¨à¥ë¥ ०¨¬ë íªà .
|
||||||
|
‚â®à ï ¢¥àá¨ï á奬ë AY ¢ª«îç ¥â ¢ ᥡï âਠ£¥¥à â®à £®«®á®¢,
|
||||||
|
£¥¥à â®à è㬠¨ ॣã«ïâ®àë ¬¯«¨âã¤ë. ƒ¥¥à â®à ®£¨¡ î饩 ®âáãâáâ¢ã¥â.
|
||||||
|
’ ª ¦¥ ®âáãâáâ¢ã¥â ¢®§¬®¦®áâì çâ¥¨ï ¨§ ¯®à⮢ ¤ ëå á®¯à®æ¥áá®à .
|
||||||
|
‚ âà¥â쥩 ¢¥àᨨ AY ¯à¥¤¯®« £ ¥âáï ¤ ë¥ ¥¤®áâ ⪨ ¨áª«îç¨âì.
|
||||||
|
|
||||||
|
Ю䍣ãà æ¨ï Sprinter-3.
|
||||||
|
|
||||||
|
Ю䍣ãà æ¨ï ®â¢ï§ ®â ª®ä¨£ãà æ¨¨ ZX-Spectrum. �®«®áâìî
|
||||||
|
®âª«îç ¥âáï �‡“ ¨ ¢á¥ ¤à¥á®¥ ¯à®áâà á⢮ à §¡¨â® ç¥âëॠ®ª ¯® 16k,
|
||||||
|
¢ ª ¦¤®¥ ¨§ ª®â®àëå ¯®¤ª«îç ¥âáï «î¡ ï ¨§ 256-⨠áâà ¨æ Ž‡“. Žâáãâáâ¢ã¥â
|
||||||
|
ᯥªâà㬮¢áª¨© íªà , £à ä¨ç¥áª¨© íªà â ª®© ¦¥, ª ª ¢ ª®ä¨£ãà æ¨ïå
|
||||||
|
Sprinter-1 ¨ Sprinter-2. ˆ¬¥¥â ¤®¯®«¨â¥«ìë¥ äãªæ¨¨ ªá¥«¥à â®à .
|
||||||
|
�®§¢®«ï¥â ¯à®¨§¢®¤¨âì ®¯¥à 樨 AND, OR ¨ XOR á ¡«®ª ¬¨ ¤ ëå. ˆ¬¥¥â 8-bit
|
||||||
|
COVOX.
|
||||||
|
‚ ¤ «ì¥©è¥¬ ¯à¥¤¯®« £ ¥âáï ¯®¤ª«î票¥ ¢ í⮩ ª®ä¨£ãà æ¨¨
|
||||||
|
á¯à¨â¥à®¢áª®© §¢ãª®¢®© ª àâë.
|
||||||
|
|
||||||
|
Ю䍣ãà æ¨ï Game-1.
|
||||||
|
|
||||||
|
�®å®¦ ª®ä¨£ãà æ¨î Sprinter-3. €ªá¥«¥à â®à ¥ ¨¬¥¥â «®£¨ç¥áª¨å
|
||||||
|
äãªæ¨©, ¤«ï ¢ë¢®¤ §¢ãª ¨¬¥¥â COVOX-Blaster - COVOX á ¡ãä¥àë¬ Ž‡“,
|
||||||
|
¯®§¢®«ïî騬 ¢ë¢®¤¨âì §¢ãª ¯®¡«®ç® ¨ ®á¢®¡®¦¤ âì ¯à®æ¥áá®à®¥ ¢à¥¬ï ¤«ï
|
||||||
|
¤à㣮© à ¡®âë. Ю䍣ãà æ¨ï ®à¨¥â¨à®¢ ¨á¯®«ì§®¢ ¨¥ ¢ ¨£à å ¤«ï
|
||||||
|
Sprinter- .
|
||||||
|
|
||||||
|
|
||||||
|
‘奬 à á¯à¥¤¥«¥¨ï ¯ ¬ïâ¨.
|
||||||
|
|
||||||
|
‘奬ë à á¯à¥¤¥«¥¨ï ¯ ¬ï⨠¢ ª®ä¨£ãà æ¨ïå Sprinter-1 ¨ Sprinter-2
|
||||||
|
®¤¨ ª®¢ë ¨ ¤®áâ â®ç® ¯à®§à çë. ” ªâ¨ç¥áª¨ ® ¯à¥¤áâ ¢«ï¥â ᮡ®© á奬ã
|
||||||
|
à á¯à¥¤¥«¥¨ï ¯ ¬ï⨠ª®¬¯ìîâ¥à Scorpion, á «®¦¥®© ¥¥
|
||||||
|
¤®¯®«¨â¥«ì®© á奬®©, ª®â®à ï ¯®§¢®«ï¥â ¯à®¨§¢®«ì® ãáâ ¢«¨¢ âì ¢á¥
|
||||||
|
áâà ¨æë ¯ ¬ïâ¨, ª ª �‡“, â ª ¨ އ“.
|
||||||
|
Š ¦¤ ï áâà ¨æ �‡“ ¨«¨ އ“ ¨¬¥¥â ᢮© ¯®àâ, ¢ ª®â®à®¬ 㪠§ë¢ ¥âáï
|
||||||
|
¤¥©á⢨⥫ìë© ®¬¥à áâà ¨æë ¨§ 256-⨠áâà ¨æ ¢á¥å 4Mb. ‘âà ¨æë,
|
||||||
|
¯à®¥æ¨àã¥¬ë¥ ¢ à §«¨çë¥ ®ª ¤à¥á®£® ¯à®áâà á⢠¯à®æ¥áá®à ¨¬¥îâ ᢮¨
|
||||||
|
ᮡáâ¢¥ë¥ ¯®àâë. ’.¥. ‘âà ¨æ , ¢ª«îç ¥¬ ï ¢ ¤à¥á #4000..#7FFF, ¨
|
||||||
|
áâà ¨æ ®¬¥à 5 ®¡ë箣® Spectrum-®¢áª®£® à á¯à¥¤¥«¥¨ï ¯ ¬ïâ¨, ¢ª«îç ¥¬ ï
|
||||||
|
¢ ¤à¥á #C000..#FFFF ¨¬¥îâ à §¤¥«ìë¥ ¯®àâë.
|
||||||
|
‚ᥣ® â ª¨å ¯®à⮢ áâà ¨æ ¯ ¬ï⨠- 32.
|
||||||
|
16 ¯®à⮢ ®â¢¥ç îâ § ®¬¥à áâà ¨æ Ž‡“, ¯®¤ª«îç ¥¬ë¥ ª ¤à¥á ¬
|
||||||
|
#C000..#FFFF. …é¥ âਠ¯®à⠮⢥ç îâ § ¯®¤ª«î票¥ áâà ¨æ Ž‡“ ª ¤à¥á ¬
|
||||||
|
#0000..#3FFF, #4000..#7FFF ¨ #8000..#BFFF. ‚®á¥¬ì ¯®à⮢ ¨á¯®«ì§ãîâáï ¤«ï
|
||||||
|
¯®¤ª«î票ï à §«¨çëå áâà ¨æ �‡“. ޤ¨ ¯®àâ - ¤«ï ¯®¤ª«î票ï áâà ¨æë
|
||||||
|
Š�˜- ¢¬¥áâ® �‡“. ˆ ®¤¨ ¯®àâ - íâ® ¯®àâ á¨á⥬®£® �‡“, ¯®¤ª«îç ¥¬®£®
|
||||||
|
¬¥áâ® �‡“ áà §ã ¯®á«¥ á¡à®á ¬ è¨ë ¯® ª« ¢¨è ¬ Ctrl+Alt+Del.
|
||||||
|
Žá⠢訥áï 3 ¯®àâ áâà ¨æ ¯ ¬ï⨠®áâ îâáï ¤ ë© ¬®¬¥â ¢ १¥à¢¥.
|
||||||
|
‘奬 à á¯à¥¤¥«¥¨ï ¯ ¬ï⨠¯®§¢®«ï¥â ¯®¤ª«îç¨âì ¢ ¤à¥á®¥ ¯à®áâà á⢮
|
||||||
|
¯à®æ¥áá®à ¥ ⮫쪮 އ“ ¨«¨ �‡“, ® ¨ ¯®àâë ¨ ¯ ¬ïâì ISA ª àâ, ¢áâ ¢«ï¥¬ëå
|
||||||
|
¢ á«®â.
|
||||||
|
�ਠ¯®¤ª«î票¨ ¢ ¤à¥á #C000..#FFFF ᪮௨®®¢áª¨å à áè¨à¥ëå
|
||||||
|
áâà ¨æ Ž‡“, ¨å ¬¥áâ® ¬®¦® ¯¥à¥ ¤à¥á®¢ âì á«®âë. „«ï í⮣® ¤® ¯à®áâ®
|
||||||
|
§ ¯¨á âì ¢ ¯®àâ ®¤®© ¨§ íâ¨å áâà ¨æ § 票¥, ᮮ⢥âáâ¢ãî饥 ISA-á«®âã,
|
||||||
|
ª ª®â®à®¬ã ¥®¡å®¤¨¬® ¯à®¨§¢¥á⨠®¡à 饨¥. �â® § 票¥ â ª ¦¥ 㪠§ë¢ ¥â
|
||||||
|
ª 祬㠢¥¤¥âáï ®¡à 饨¥, ª ¯®àâ ¬ ¨«¨ ¯ ¬ïâ¨.
|
||||||
|
|
||||||
|
|
||||||
|
‘奬 à á¯à¥¤¥«¥¨ï ¯ ¬ï⨠Sprinter- .
|
||||||
|
|
||||||
|
€¤à¥á®¥ ¯à®áâà á⢮ ‘âà ¨çë¥ ¯®àâë �‡“ ª®¬¯ìîâ¥à
|
||||||
|
¯à®æ¥áá®à ¯®¤ª«îç ¥¬ëå áâà ¨æ áâà ¨æë ¯® 16k
|
||||||
|
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
|
||||||
|
³ #0000..#3FFF ÃÄ>´ ¯®àâë ÃÄÄ>´ ROM_BASIC ÃÄÄ>ÂÄÄÂÄÄÂÄ>´ EXPANSION ³
|
||||||
|
³ ³ ³ #7FFD,³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ ³ ³ #1FFD ÃÄ¿ ³ ROM_TR-DOS ÃÄÄ>´ ³ ÃÄ>´ TR-DOS ³
|
||||||
|
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ÀÄÄÄÄÄÄÄÙ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ #4000..#7FFF ÃÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ ³ ³ ÃÄ>´ BASIC128 ³
|
||||||
|
³ ³ ³ ³ ÃÄ Ä Ä Ä Ä Ä Ä ´ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ ³ ³ ³ ³ ROM_SYSTEM ÃÄÄ>Ù ³ ÃÄ>´ BASIC48 ³
|
||||||
|
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ #8000..#BFFF ÃÄÄÄÄ¿ ³ À>´ RAM_0000 ÃÄÄÄ>¿ ³ ÃÄ>´ SYSTEM ROM ³
|
||||||
|
³ ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ ³ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ÃÄ>´ SYSTEM ROM2 ³
|
||||||
|
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ ÀÄÄ>´ RAM_4000 ÃÄÄÄ>´ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ #C000..#FFFF ÿ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³ ÃÄ>´ CONFIG 2 ³
|
||||||
|
³ ³³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ ³³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ÀÄ>´ CONFIG 1 ³
|
||||||
|
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ³ ÀÄÄÄÄÄÄÄÄ>´ RAM_8000 ÃÄÄÄ>´ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
|
||||||
|
³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³
|
||||||
|
³ ³ ³ އ“ ª®¬¯ìîâ¥à
|
||||||
|
³ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ áâà ¨æë ¯® 16k
|
||||||
|
³ ³ �®àâë ÃÄÄ>´ RAM_0 ÃÄÄÄ>´ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
|
||||||
|
³ ³ #7FFD,³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ÃÄÄÄ>ÂÄ>´ RAM_00 ³
|
||||||
|
À>´ #1FFD ÃÄÄ>´ ÃÄÄÄ>´ ³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ ³ ÃÄ Ä Ä Ä Ä Ä Ä ³ ³ ³ ÃÄ>´ RAM_01 ³
|
||||||
|
³ ÃÄÄ>´ RAM_7 ÃÄÄÄ>´ ÀÄ>´ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ ³ ³ ³
|
||||||
|
³ ÃÄÄ>´ RAM_8 ÃÄ>ÂijÄÄÄ>´ ÃÄ Ä Ä Ä Ä Ä Ä ´
|
||||||
|
³ ³ ÃÄ Ä Ä Ä Ä Ä Ä ´ ³ ³ ÀÄÄ´ RAM_7F ³
|
||||||
|
³ ÃÄÄ>´ ÃÄ>´ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ ÀÄÄÄ>ÂÄ>´ RAM_80 ³
|
||||||
|
³ ÃÄÄ>´ RAM_F ÃÄ>ÁÄ>¿ ³ ÃÄ Ä Ä Ä Ä Ä Ä ´
|
||||||
|
ÀÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³ ³ ³
|
||||||
|
‚¥è¨¥ ãáâனá⢠³ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ÃÄ>´ RAM_FE ³
|
||||||
|
�®àâë ÃÄÄÄÄ>´ ISA_1 Ã<ÄÄÄÄ´ ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
|
||||||
|
ª®¬¯ìîâ¥à ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ ÀÄ>´ RAM_FF ³
|
||||||
|
ÃÄÄÄÄ>´ ISA_2 Ã<ÄÄÄÄ´ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
|
||||||
|
³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³
|
||||||
|
ÃÄÄÄÄ>´ HDD Ã<ÄÄÄÄ´
|
||||||
|
³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³
|
||||||
|
ÃÄÄÄÄ>´ OVER DEVICES Ã<ÄÄÄÄÙ
|
||||||
|
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
|
||||||
|
|
||||||
|
�¨á㮪 2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
‚ ¤àã£¨å ª®ä¨£ãà æ¨ïå á奬 à á¯à¥¤¥«¥¨ï ¯ ¬ï⨠ã¯à®é ¥âáï ¤«ï
|
||||||
|
®á¢®¡®¦¤¥¨ï à¥áãàᮢ ��‹Œ. Œ®£ãâ ®âáãâá⢮¢ âì ¯®àâë #1FFD ¨ #7FFD, â ª
|
||||||
|
¦¥ ã¯à®é ¥âáï á奬 à ¡®âë á ãáâனá⢠¬¨, ®â®¡à ¦ ¥¬ë¬¨ ¯ ¬ïâì.
|
||||||
|
|
||||||
|
|
||||||
|
‘奬 à á¯à¥¤¥«¥¨ï ¯®à⮢.
|
||||||
|
|
||||||
|
Sprinter ¨¬¥¥â ¤¢¥ ®¡®á®¡«¥ë¥ £àã¯¯ë ¯®à⮢. �¥à¢ ï £à㯯 , íâ®
|
||||||
|
¢ãâ२¥ ¯®àâë ¯à®æ¥áá®à Z84C15, ¢â®à ï - ¢¥è¨¥ ¯®àâë. €¤à¥á æ¨ï
|
||||||
|
¯®à⮢ ¯¥à¢®© £àã¯¯ë ¥ ¬®¦¥â ¡ëâì ¨§¬¥¥ , â ª ª ª í⨠¯®àâë ®¤®¬
|
||||||
|
ªà¨áâ ««¥ á ¯à®æ¥áá®à®¬. ‚â®à ï £à㯯 ¯®£ª«îç ¥âáï ç¥à¥§ ��‹Œ ¨ ¨å ¤à¥á
|
||||||
|
¬®£ãâ ¨§¬¥ïâìáï ª ª 㣮¤®, á ¥¤¨áâ¢¥ë¬ ãá«®¢¨¥¬, ¥¯¥à¥á¥ç¥¨ï á
|
||||||
|
¤à¥á ¬¨ ¯¥à¢®© £à㯯ë.
|
||||||
|
Ž â®¬ ª ª¨¥ ¯®àâë ¨¬¥îâáï ªà¨áâ ««¥ Z84C15 ¬®¦® ¯à®ç¨â âì ¢
|
||||||
|
¤®ªã¬¥â 樨 ¯® íâ®¬ã ¯à®æ¥áá®àã ¨ §¤¥áì ï 㯮¬ïã ¥ª®â®àë¥ ¨§ ¨å. ޤ¨
|
||||||
|
¨§ ¯®á«¥¤®¢ ⥫ìëå ¯®à⮢ ¨á¯®«ì§ã¥âáï ¤«ï ¢¢®¤ ¤ ëå á ªâ¨¢®© ¬ëè¨.
|
||||||
|
ޤ¨ ¨§ ¯ à ««¥«ìëå ¨á¯®«ì§ã¥âáï ¤«ï ¢ë¢®¤ ¤ ëå, ¢â®à®© ¯ à ««¥«ìë©
|
||||||
|
¯®àâ § ¢¥¤¥ë ᨣ «ë ¯à¥àë¢ ¨© ¨ § ¯à®á®¢ ¯àאַ£® ¤®áâ㯠ᮠ᫮⮢ ISA.
|
||||||
|
� à ««¥«ìë© ¯®àâ ¯à®æ¥áá®à Z84C15 ãáâ஥ â ª¨¬ ®¡à §®¬, çâ® ¥¬
|
||||||
|
¢®§¬®¦ ®à£ ¨§ æ¨ï ¯à¥àë¢ ¨© ¯® ᨣ « ¬ ¯à¨å®¤ï騬 ç¥à¥§ ¯ à ««¥«ìë©
|
||||||
|
¯®àâ. ” ªâ¨ç¥áª¨ ¢â®à®© ¯ à ««¥«ìë© ¯®à⠨ᯮ«ì§ã¥âáï ª ª ª®â஫«¥à
|
||||||
|
¯à¥àë¢ ¨©.
|
||||||
|
‘奬 à á¯à¥¤¥«¥¨ï ¯®à⮢ ¢â®à®© £àã¯¯ë ¨¬¥¥â á¢®î ®á®¡¥®áâì.
|
||||||
|
ƒ« ¢®© ¨¤¥¥© ¡ë«® ¯®«ã票¥ ¢®§¬®¦®á⨠¡ëáà® ¨§¬¥ïâì ª®ä¨£ãà æ¨î ¯®à⮢
|
||||||
|
¡¥§ ¯¥à¥£à㧪¨ ��‹Œ. �â® ¤®á⨣ãâ® ¯ã⥬ ¯à¨¬¥¥¨ï ª àâë à á¯à¥¤¥«¥¨ï
|
||||||
|
¯®à⮢, à ᯮ« £ î饩áï á¯¥æ¨ «ì®© áâà ¨æ¥ Ž‡“.
|
||||||
|
�ਠ¯®ï¢«¥¨¨ 横« ®¡à é¥¨ï ª ¯®àâã á ç « ¯à®¨á室¨â ®¡à 饨¥
|
||||||
|
ª އ“ ª àâë ¯®à⮢. ‚ ª à⥠¯®à⮢ § ¯¨á ® ª ª®© ¨¬¥® ¯®àâ ¯®¤ª«îç¥ ª
|
||||||
|
¤ ®¬ã ¤à¥áã. „ «¥¥ ¯à®¨á室¨â ¢ãâà¥ïï ¤¥è¨äà æ¨ï ¯® ¡ ©âã ¨§ ª àâë
|
||||||
|
¯®à⮢ ¨ ®¡à 饨¥ ª ¢ë¡à ®¬ã ¯®àâã. ‚ ०¨¬¥ ¥âãà¡® íâ® ¯à®¨á室¨â ¡¥§
|
||||||
|
ª ª¨å «¨¡® § ¤¥à¦¥ª, ¢ ०¨¬¥ âãà¡® ¯à®æ¥áá®àã ¢ëáâ ¢«ï¥âáï ᨣ « WAIT ¢
|
||||||
|
§ ¢¨á¨¬®á⨠®â ¥®¡å®¤¨¬®© ¤«¨ë 横« ®¡à é¥¨ï ª ¯®àâã.
|
||||||
|
„«ï ¯®¤ª«îç¥¨ï ª ª ª®¬ã «¨¡® ¤à¥áã ¨«¨ ®âª«îç¥¨ï ®â ¥£® ª ª®£®
|
||||||
|
«¨¡® ¯®àâ ¤®áâ â®ç® ®âªàëâì ª àâã ¯®à⮢ ¨ ¢¯¨á âì ¢ 㦮¥ ¬¥áâ® ®¤¨
|
||||||
|
¡ ©â.
|
||||||
|
‚ áâà ¨æ¥ ª àâë ¯®à⮢ ᮤ¥à¦¨âáï ç¥âëॠª àâë, ª®â®àë¥ ¬®£ãâ
|
||||||
|
¯¥à¥ª«îç âìáï ç¥à¥§ á¨áâ¥¬ë© ¯®àâ. ’ ª¨¬ ®¡à §®¬ ¬®¦® ®áãé¥á⢨âì ¡ëáâ஥
|
||||||
|
¯¥à¥ª«î票¥ ª®ä¨£ãà æ¨¨ ¯®à⮢, çâ® ¬®¦¥â ¡ëâì ¯®«¥§® ¯à¨ à ¡®â¥
|
||||||
|
Spectrum-®¢áª¨å ¯à®£à ¬¬ ᮢ¬¥áâ® á® Sprinter-®¢áª¨¬ ¡¨®á®¬.
|
||||||
|
|
||||||
|
|
||||||
|
Š®ªà¥âë¥ ¤à¥á ¯®à⮢, ¨á¯®«ì§ã¥¬ë¥ ¢ Sprinter-¥.
|
||||||
|
|
||||||
|
‡¤¥áì ï ¯à¨¢¥¤ã ¤à¥á æ¨î ¯®à⮢ ¤«ï ª®ä¨£ãà æ¨© Sprinter-1 ¨
|
||||||
|
Sprinter-2. ‘à §ã ®â¬¥çã, çâ® í⨠¤à¥á «¥£ª® ¬®£ãâ ¡ëâì ¨§¬¥¥ë ¯à®á⮩
|
||||||
|
¯à®£à ¬¬®©, ¢ á«ãç ¥ ¯®ï¢«¥¨ï â ª®© ¥®¡å®¤¨¬®áâ¨.
|
||||||
|
|
||||||
|
|
||||||
|
‘â ¤ àâë¥ ¯®àâë.
|
||||||
|
|
||||||
|
#FE - RD_KBD - ¯®àâ ª« ¢¨ âãàë
|
||||||
|
#FE - WR_BRD - ¯®àâ ¡®à¤îà
|
||||||
|
#7FFD - ¯®àâ à áè¨à¥¨ï ZX-Spectrum 128k
|
||||||
|
#1FFD - ¯®àâ à áè¨à¥¨ï Scorpion ZS-256
|
||||||
|
#1F,#0F - RD_KEMPS - ¯®àâ ¤¦®©á⨪ . ‚ ª®ä¨£ãà æ¨¨ Sprinter-1 ¯®àâ
|
||||||
|
#1F ¯¯ à â® ¯¥à¥ ¤à¥áã¥âáï ¯®àâ #0F
|
||||||
|
#BFFD,#FFFD - AY-PORTS - ¯®àâë AY-á®¯à®æ¥áá®à (ZX-Spectrum-256/AY)
|
||||||
|
|
||||||
|
�¥ ᮢᥬ áâ ¤ àâë¥ ¯®àâë.
|
||||||
|
|
||||||
|
#FB,#4F - ¯®àâ COVOX- .
|
||||||
|
|
||||||
|
|
||||||
|
„®¯®«¨â¥«ìë¥ 8-¡¨âë¥ ¯®àâë Sprinter- .
|
||||||
|
|
||||||
|
#82 - PAGE0 - áâà ¨æ Ž‡“, ¯®¤ª«îç ¥¬ ï ¢¬¥áâ® �‡“ ç¥à¥§ ¯®àâ #1FFD
|
||||||
|
#A2 - PAGE1 - áâà ¨æ Ž‡“, ¯®¤ª«îç¥ ï ¯® ¤à¥áã #4000
|
||||||
|
#C2 - PAGE2 - áâà ¨æ Ž‡“, ¯®¤ª«îç¥ ï ¯® ¤à¥áã #8000
|
||||||
|
#E2 - PAGE2 - áâà ¨æ Ž‡“, ¯®¤ª«îç¥ ï ¯® ¤à¥áã #C000
|
||||||
|
‡¤¥áì ¤® ®â¬¥â¨âì ®á®¡®, ç¥à¥§ ¯®àâ #E2 ¬®¦® ¨§¬¥¨âì «î¡ãî ¨§
|
||||||
|
16-⨠áâà ¨æ ᪮௨®®¢áª®£® à á¯à¥¤¥«¥¨ï ¯ ¬ïâ¨.
|
||||||
|
#89 - PORT_Y - ¢¥à⨪ «ì ï ª®®à¤¨ â â®çª¨ £à ä¨ç¥áª®¬ íªà ¥
|
||||||
|
¨«¨ áâà ¨æ VIDEO-RAM ¤«ï ᯥªâà㬮¢áª®£® ०¨¬
|
||||||
|
#C9 - RGMOD - ¯®àâ ०¨¬ íªà . �¥à¥ª«îç ¥â áâà ¨æë ०¨¬ íªà .
|
||||||
|
#3C,#7C - SYS_PORT - á¨áâ¥¬ë© ¯®àâ âண âì ¥ ४®¬¥¤ã¥âáï
|
||||||
|
|
||||||
|
#10..#1F,#EE,#EF,#F0,#F1,#F4 - ¢ãâ२¥ ¯®àâë Z84C15
|
||||||
|
|
||||||
|
�®àâë áâà ¨æ Ž‡“ ®âªàëâë ª ª § ¯¨áì, â ª ¨ ç⥨¥. �â®
|
||||||
|
¯®§¢®«ï¥â «¥£ª® ¢ë¯®«ïâì ¯à®£à ¬¬ë, ¨á¯®«ì§ãî騥 ¯¥à¥ª«î票¥ áâà ¨æ,
|
||||||
|
§ ⥬ ¢®§¢à é âì í⨠áâà ¨æë § ¤. �à¨ à ¡®â¥ BIOS- ¢á¥ áâà ¨æë
|
||||||
|
á®åà ïîâáï.
|
||||||
|
|
||||||
|
|
||||||
|
„®¯®«¨â¥«ìë¥ 16-⨡¨âë¥ ¯®àâë Sprinter- .
|
||||||
|
|
||||||
|
#xx50..#xx55 - ¯®àâë HDD - ¨á¯®«ì§®¢ âì ¢¥è¨¬¨ ¯à®£à ¬¬ ¬¨ ¥
|
||||||
|
४®¬¥¤ã¥âáï. ”ãªæ¨¨ à ¡®âë á HDD § ¯¨á ë ¢ �‡“.
|
||||||
|
|
||||||
|
|
||||||
|
‘ªàëâë¥ ¯®àâë Sprinter- .
|
||||||
|
|
||||||
|
‘ªàëâ묨 ïîâáï ¯®àâë ª®â®àë¥ ¤®áâã¯ë ¢ ª®ªà¥âë© ¬®¬¥â
|
||||||
|
¢à¥¬¥¨, ® ¬®£ãâ áâ âì ¤®áâã¯ë¬¨ ¯®á«¥ ¯à®¢¥¤¥¨ï ¨§¬¥¥¨© ¢ ª à⥠¯®à⮢.
|
||||||
|
ˆå ¤à¥á ¥ 㪠§ë¢ îâáï, â ª ª ª ®¨ ¬®£ãâ ¡ëâì ¢ëáâ ¢«¥ë ¢ «î¡®¥ ¬¥áâ®.
|
||||||
|
|
||||||
|
�®àâ �‡“ BASIC48
|
||||||
|
�®àâ �‡“ BASIC128
|
||||||
|
�®àâ �‡“ TR-DOS
|
||||||
|
�®àâ �‡“ EXPANSION
|
||||||
|
�®àâ �‡“ SYSTEM
|
||||||
|
|
||||||
|
—¥à¥§ í⨠¯®àâë ¬®¦® ãáâ ®¢¨âì ®¢ë¥ ¯à®è¨¢ª¨ �‡“. „«ï í⮣® ¨å
|
||||||
|
¤®áâ â®ç® § ¯¨á âì ¢ އ“ á ®¬¥à ¬¨ áâà ¨æ ¬¥ìè¥ #80 ¨ § ¯¨á âì ¢
|
||||||
|
ᮮ⢥âáâ¢ãî騩 ¯®àâ ®¬¥à í⮩ áâà ¨æë. �ਠ⠪®¬ ¯®¤ª«î票¨ áâà ¨æë
|
||||||
|
�⨠áâà ¨æë ¡ã¤ãâ § é¨é¥ë ®â § ¯¨á¨.
|
||||||
|
— áâ¨ç® áªàëâ묨, â ª ¦¥ ïîâáï ¨ ¯®àâë #7FFD,#1FFD ¢ ®¡ë箬
|
||||||
|
á®áâ®ï¨¨ ®¨ ¤®áâã¯ë ⮫쪮 § ¯¨áì, ® § 票ï, § ¯¨áë¢ ¥¬ë¥ ¢ íâ¨
|
||||||
|
¯®àâë ¬®¦® ¯à®ç¨â âì, ®âªàë¢ á®®â¢¥âáâ¢ãî騥 ¯®àâë ç⥨¥.
|
||||||
|
‚ ¤àã£¨å ª®ä¨£ãà æ¨ïå ¬®¦¥â ®âáãâá⢮¢ âì ç áâì ¯®à⮢ ¨«¨
|
||||||
|
¯à¨áãâá⢮¢ âì ®¢ë¥ ¯®àâë.
|
||||||
|
|
||||||
|
|
||||||
|
Žà£ ¨§ æ¨ï ¢¨¤¥®¯ ¬ï⨠¨ ¢¨¤¥®à¥¦¨¬®¢.
|
||||||
|
|
||||||
|
‚¨¤¥®-އ“ Sprinter- á®áâ ¢«ï¥â 256 ª¨«®¡ ©â. ‚ ¤ «ì¥©è¥¬
|
||||||
|
¯à¥¤¯®« £ ¥âáï ¥£® à áè¨à¥¨¥ ¤® 512 ª¨«®¡ ©â, ¤«ï ¯®«ãç¥¨ï ¡®«¥¥
|
||||||
|
¢ë᮪¨å ०¨¬®¢ à §à¥è¥¨ï.
|
||||||
|
‚ ०¨¬¥ Spectrum-®¢áª®£® íªà ¢áï ®à£ ¨§ æ¨ï â ª ï ¦¥ ª ª ¢
|
||||||
|
áâ ¤ à⮬ ZX-Spectrum. ‚ ®áâ «ìëå ०¨¬ å ¢ª«îç ¥âáï Sprinter-®¢áª¨©
|
||||||
|
íªà , áâàãªâãà ª®â®à®£® ¢ª«îç ¥â ¢ á¥¡ï ‘¯¥ªâà㬮¢áª¨© íªà ª ª ç áâì
|
||||||
|
á奬ë.
|
||||||
|
|
||||||
|
“áâனá⢮ íªà .
|
||||||
|
|
||||||
|
‚¥áì íªà à §¡¨â ª¢ ¤à âë, à §¬¥à®¬ ¢ áâ ¤ à⮥
|
||||||
|
‘¯¥ªâà㬮¢áª®¥ § ª®¬¥áâ®. „«ï ª ¦¤®£® ª¢ ¤à â ãáâ ¢«¨¢ ¥âáï ᢮©
|
||||||
|
ᮡáâ¢¥ë© à¥¦¨¬ ¢ë¢®¤ , â ª ¦¥ ¤à¥á ¢¨¤¥®-އ“, ®âªã¤ ¯à®¨§¢®¤¨âáï
|
||||||
|
¢ë¢®¤ ¢ íâ®â ª¢ ¤à â.
|
||||||
|
‚ ª ¦¤®¬ § ª®¬¥á⥠¬®¦¥â ¡ëâì § ¤ ᢮© ᮡáâ¢¥ë© à¥¦¨¬ ¢ë¢®¤ .
|
||||||
|
‚ ¤ ë© ¬®¬¥â ¬®¦® ãáâ ¢«¨¢ âì â ª¨¥ ०¨¬ë:
|
||||||
|
ZX-40 - ®¡ëçë© á¯¥ªâà㬮¢áª¨© ०¨¬ á ®¤¨¬ ¡¨â¯« ®¬ ¨
|
||||||
|
®¤¨¬ âਡã⮬ § ª®¬¥áâ®.
|
||||||
|
ZX-80 - �¥¦¨¬, ¯®å®¦¨© ᯥªâà㬮¢áª¨© ¯® áâ஥¨î
|
||||||
|
ᨬ¢®«®¢, ® ¢ ª ¦¤®¬ § ª®¬¥á⥠®ª §ë¢ ¥âáï ¤¢ ᨬ¢®« , ᦠâë¥ ¯®
|
||||||
|
£®à¨§®â «¨.
|
||||||
|
G256-8 - ƒà ä¨ç¥áª¨© ०¨¬. Š¢ ¤à ⠯।áâ ¢«ï¥â ᮡ®© ¬ áᨢ 8x8
|
||||||
|
â®ç¥ª. ‚ ª ¦¤®© â®çª¥ § ¤ ¥âáï ®¤¨ ¨§ 256-⨠梥⮢, ¢ë¡¨à ¥¬ëå ¨§ ¯ «¨âàë
|
||||||
|
16 ¬¨««¨®®¢ 梥⮢. Š¢ ¤à âë ¬®£ãâ ¨¬¥âì à §ë¥ ¯ «¨âàë. ’ ª¨å ¯ «¨âà ¤«ï
|
||||||
|
०¨¬ G256-8 - ç¥âëà¥.
|
||||||
|
G16-16 - ƒà ä¨ç¥áª¨© ०¨¬. Š¢ ¤à ⠯।áâ ¢«ï¥â ᮡ®© ¬ áᨢ
|
||||||
|
16x8 â®ç¥ª. Š ¦¤ ï â®çª ¨¬¥¥â ®¤¨ ¨§ 16 梥⮢, ¢ë¡¨à ¥¬ëå ¨§ ¯ «¨âàë 16
|
||||||
|
¬¨««¨®®¢ 梥⮢. ’ ª ¦¥, ª ª ¨ G256-8 ¢ ª¢ ¤à ⥠¬®¦¥â ¡ëâì ãáâ ®¢«¥
|
||||||
|
®¤ ¨§ 4-å ¯ «¨âà. � «¨âàë £à ä¨ç¥áª¨å ०¨¬®¢ ¯¥à¥á¥ª îâáï ¤àã£ á ¤à㣮¬.
|
||||||
|
� «¨âà 16-â¨æ¢¥â®£® ०¨¬ íâ® ¯¥à¢ë¥ 16 梥⮢ ¨§ ¯ «¨âàë 256-â¨æ¢¥â®£®.
|
||||||
|
BORDER - ‚ ª¢ ¤à ⠢뢮¤¨âáï æ¢¥â ¡®à¤¥à .
|
||||||
|
BLANK - Š¢ ¤à â £ á¨âáï - áâ ®¢¨âáï ç¥àë¬.
|
||||||
|
|
||||||
|
Ž¡ê¥¬ ¤ ëå ०¨¬ ª¢ ¤à â á®áâ ¢«ï¥â 2 ¡ ©â ,
|
||||||
|
¯®í⮬㠨§¬¥¥¨¥ ०¨¬ ¢á¥£® íªà ᢮¤¨âáï ª ¯¥à¥§ ¯¨á¨ 2.5 ª¨«®¡ ©â
|
||||||
|
¤ ëå ¢ ¢¨¤¥®-އ“.
|
||||||
|
�®¤®¡ ï áâàãªâãà íªà ¯®§¢®«ï¥â «¥£ª® ¯à®¨§¢®¤¨âì áªà®««¨£¨
|
||||||
|
ª ª ¢á¥£®, â ª ¨ ç á⥩ íªà ¯® § ª®¬¥áâ ¬.
|
||||||
|
|
||||||
|
�¥¦¨¬ íªà ãáâ ¢«¨¢ ¥âáï ¯à¨ ¢ª«î票¨, â ª ¦¥ á ¯®¬®éìî
|
||||||
|
äãªæ¨© ¡¨®á . ”ãªæ¨¨ ¡¨®á ¯®§¢®«ïîâ ®âªàë¢ âì íªà ¥ £à ä¨ç¥áª¨¥ ¨
|
||||||
|
⥪áâ®¢ë¥ ®ª ¢ ã¦ëå ¬¥áâ å ¨ 㦮£® à §¬¥à .
|
||||||
|
|
||||||
|
‚ ¡¨®á¥ ¨¬¥îâáï äãªæ¨¨ ®âªàëâ¨ï £à ä¨ç¥áª®£® íªà ¢¥áì íªà
|
||||||
|
320x256 â®ç¥ª. �®á«¥ ®âªàëâ¨ï í⮣® ०¨¬ íªà ¯à¥¤áâ ¢«ï¥â ᮡ®©.
|
||||||
|
¡®à ¨§ 256-⨠«¨¨©, ¤«¨®© ¯® 320 ¡ ©â. ‘®á¥¤¨¥ â®çª¨ ¢ «¨¨¨ - íâ®
|
||||||
|
á®á¥¤¨¥ ¡ ©âë. �¥à¥ª«î票¥ «¨¨© ¯à®¨§¢®¤¨âáï ç¥à¥§ PORT_Y, ¢ ª®â®à®¬
|
||||||
|
ãáâ ¢«¨¢ ¥âáï ®¬¥à «¨¨¨, ¢ë¢®¤¨¬®© íªà . �®¬¥à «¨¨© áç¨â îâáï
|
||||||
|
ᢥàåã íªà , ç¨ ï á ã«¥¢®©.
|
||||||
|
„«ï ¢ë¢®¤ ¢ £à ä¨ç¥áª¨© íªà â ª ¦¥ âॡã¥âáï ®âªàëâì
|
||||||
|
ᮮ⢥âáâ¢ãîéãî áâà ¨æã ®á®¢®£® އ“. ‚ í⮩ áâà ¨æ¥ ¡ã¤¥â ᮤ¥à¦ âìáï
|
||||||
|
ª®¯¨ï ¢¨¤¥®¨§®¡à ¦¥¨ï.
|
||||||
|
‚¨¤¥®-އ“ ï¥âáï ⥥¢ë¬ އ“, ¯®í⮬㠨ä®à¬ æ¨ï, 室ïé ïáï ¢
|
||||||
|
®á®¢®¬ އ“, ¯®¤ ª®â®àë¬ å®¤¨âáï ¢¨¤¥®-އ“ ¥ ®¡ï§ â¥«ì® ¡ã¤¥â
|
||||||
|
ᮢ¯ ¤ âì á ¨ä®à¬ 樥©, 室ï饩áï ¢ í⮬ ¢¨¤¥®-އ“. ‡ ¯¨áì ¢¨¤¥®-¤ ëå
|
||||||
|
¬®¦¥â ¯à®¨§¢®¤¨âìáï ¨ ¡¥§ ¯¥à¥§ ¯¨á¨ ¤ ëå ¢ ®á¢®¬ އ“, çâ® ®ª §ë¢ ¥âáï
|
||||||
|
¯®«¥§ë¬ ¯à¨ à ¡®â¥, ¯à¨¬¥à, á® á¯à ©â ¬¨. „«ï à ¡®âë á® á¯à ©â ¬¨ â ª ¦¥
|
||||||
|
¯à¥¤ãᬮâॠ०¨¬ § ¯¨á¨ ¢ ¢¨¤¥®-އ“ á ¯à®§à çë¬ æ¢¥â®¬. ‚ í⮬ ०¨¬¥
|
||||||
|
¨ä®à¬ æ¨ï, ¯¥à¥¤ ¢ ¥¬ ï ¢ ¢¨¤¥®-އ“ ¯à®¢¥àï¥âáï «¨ç¨¥ ¡ ©â #FF. …᫨
|
||||||
|
íâ®â ¡ ©â ®¡ à㦨¢ ¥âáï, ⮠横« § ¯¨á¨ ¯à®¯ã᪠¥âáï ¨ íªà ¥ ¢ í⮬
|
||||||
|
¬¥á⥠®áâ ¥âáï ⥠¤ ë¥, ª ª¨¥ ¡ë«¨ à ¥¥. ’ ª¨¬ ®¡à §®¬ íªà ¥ ¬®¦®
|
||||||
|
¡ëáâà® ¯à®à¨á®¢ë¢ âì á¯à ©âë, ¯à¥¤áâ ¢«ïî騥 ¨§ á¥¡ï ¯àאַ㣮«ìë¥ ª à⨪¨
|
||||||
|
á "¯à®§à ç묨" 梥⠬¨.
|
||||||
|
|
||||||
|
�ਬ¥à ¯à®£à ¬¬ë ¢ë¢®¤ ¯àאַ㣮«ì®© ª à⨪¨ íªà :
|
||||||
|
|
||||||
|
PAGE3 EQU #E2
|
||||||
|
RGADR EQU #89
|
||||||
|
|
||||||
|
LD A,#50 ; áâà ¨æ £à ä¨ç¥áª®£® ¢¨¤¥®íªà
|
||||||
|
OUT (PAGE3),A ; ãáâ ®¢¨âì ¢ PAGE3
|
||||||
|
LD HL,Pucture ; ¤à¥á ª à⨪¨ (�àï¬ë¥ „ ë¥)
|
||||||
|
LD DE,#C040+HorPlace ; ¯®«®¦¥¨¥ ª à⨪¨ íªà ¥ ¯® £®à¨§®â «¨
|
||||||
|
LD A,VerPlace ; ¯®«®¦¥¨¥ ª à⨪¨ íªà ¥ ¯® ¢¥à⨪ «¨
|
||||||
|
OUT (RGADR),A
|
||||||
|
LD B,VerSize ; ¢ëá®â ª à⨪¨
|
||||||
|
LOOP: PUSH DE ; § ¯®¬¨âì ¯®«®¦¥¨¥ «¨¨¨
|
||||||
|
PUSH BC ; § ¯®¬¨âì áç¥â稪 ¢ëá®âë
|
||||||
|
LD BC,HorSize ; ¤«¨ ª à⨪¨
|
||||||
|
LDIR ; ª®¯¨à®¢ âì «¨¨î
|
||||||
|
POP BC
|
||||||
|
POP DE
|
||||||
|
INC A ; á«¥¤ãîé ï ª®®à¤¨ â ¯® Y
|
||||||
|
OUT (RGADR),A
|
||||||
|
DJNZ LOOP ; ¯®¢â®àïâì 㦮¥ ª®«¨ç¥á⢮ à §
|
||||||
|
|
||||||
|
“¯à ¢«¥¨¥ ०¨¬®¬ ¢ë¢®¤ íªà (¢ª«î票¥ ¢ë¢®¤ á ¯à®§à ç묨
|
||||||
|
梥⠬¨, ®âª«î票¥ ª®¯¨à®¢ ¨ï ¢ ®á®¢®¥ އ“) ®áãé¥á⢫ï¥âáï ç¥à¥§
|
||||||
|
¬« ¤è¨¥ ¡¨âë ¯®àâ áâà ¨æë £à ä¨ç¥áª®£® íªà .
|
||||||
|
|
||||||
|
|
||||||
|
€ªá¥«¥à â®à ®¯¥à 権 á Ž‡“.
|
||||||
|
|
||||||
|
€ªá¥«¥à â®à ®¯¥à 権 á Ž‡“ ¯à¥¤ § ç¥ ¤«ï ãáª®à¥¨ï ®¯¥à 権
|
||||||
|
¯® ¯¥à¥á뫪¥ ¤ ëå ¨«¨ ¯® § ¯®«¥¨î އ“ ®¤¨¬ ¡ ©â®¬. €ªá¥«¥à â®à
|
||||||
|
¯à¨áãâáâ¢ã¥â ¢ ç¨áâ® Sprinter-®¢áª¨å ª®ä¨£ãà æ¨ïå ¨ ¯®í⮬㠨ª ª ¥
|
||||||
|
¬¥è ¥â à ¡®â¥ ®¡ëçëå Spectrum-®¢áª¨å ¯à®£à ¬¬.
|
||||||
|
Žá®¢®© ªá¥«¥à â®à ï¥âáï ¡ëáâ஥ ¢ãâ॥¥ އ“ ¢ ��‹Œ.
|
||||||
|
ޝ¥à 樨 ¯® ¯¥à¥á뫪¥ ¤ ëå ¯à®¨§¢®¤ïâáï ¯ã⥬ § ¯¨á¨ ¡«®ª ¤ ëå ¢ íâ®
|
||||||
|
¢ãâ॥¥ އ“, § ⥬ ª®¯¨à®¢ ¨¨ ¥£® ¢ 㦮¥ ¬¥áâ® ¯ ¬ï⨠¨§ í⮣® އ“.
|
||||||
|
�®á«¥ ®¤®© § ¯¨á¨ ª®¯¨à®¢ ¨¥ ¬®¦¥â ¯à®¨§¢®¤¨âìáï ¥áª®«ìª® à § ¨ â ª¨¬
|
||||||
|
®¡à §®¬ ¬®¦® ¯à®¨§¢®¤¨âì § ¯®«¥¨¥ íªà ⥪áâãà ¬¨.
|
||||||
|
„«ï § ¯®«¥¨ï íªà ®¤¨¬ 梥⮬ ¨á¯®«ì§ã¥âáï ¤à㣮© ०¨¬
|
||||||
|
ªá¥«¥à â®à . ‚ ¥¬ ¢¬¥áâ® ª®¯¨à㥬®£® ¡«®ª ¤ ëå ¨§ ¢ãâ॥£® އ“
|
||||||
|
¯à®¨§¢®¤¨âáï § ¯¨áì ¤ ëå á è¨ë ¯à®æ¥áá®à , ª®â®àë¥ ¢ íâ®â ¬®¬¥â ¥
|
||||||
|
¨§¬¥ïîâáï.
|
||||||
|
�«®ª ¤ ëå, § ¯¨áë¢ ¥¬ë© ¢ އ“ ªá¥«¥à â®à ¬®¦¥â ¨¬¥âì à §«¨çãî
|
||||||
|
¤«¨ã ¨§ ¤¨ ¯ §® 1..256 ¡ ©â.
|
||||||
|
“¯à ¢«¥¨¥ ªá¥«¥à â®à®¬ ¯à®¨§¢®¤¨âáï ¥¯®á।á⢥® ¨§ ¯à®£à ¬¬ë.
|
||||||
|
„«ï í⮣® ¨§¯®«ì§ãîâáï ª®¬ ¤ë ¯à®æ¥áá®à , ª®â®àë¥ ä ªâ¨ç¥áª¨ ïîâáï
|
||||||
|
®¯¥à æ¨ï¬¨ ⨯ NOP.
|
||||||
|
�â® ª®¬ ¤ë LD A,A; LD B,B; LD C,C; LD D,D; LD E,E; LD H,H, LD L,L
|
||||||
|
� § 票¥ ª®¬ ¤ á«¥¤ãî饥:
|
||||||
|
LD B,B - ¢ëª«îç¨âì ªá¥«¥â à®à.
|
||||||
|
LD D,D - ¢ª«îç¨âì ªá¥«¥à â®à ¢ ०¨¬ ¯à¨¥¬ ¡ ©â à §¬¥à ¡«®ª
|
||||||
|
¤ «¥¥ á«¥¤ã¥â ª®¬ ¤ ⨯ LD A,dat, £¤¥ dat ¨ ¡ã¤¥â ®¢ë¬
|
||||||
|
à §¬¥à®¬ ¡«®ª . …᫨ à §¬¥à ¡«®ª ¡ë« ãáâ ®¢«¥ à ¥¥,
|
||||||
|
¥£® ¬®¦® ¥ ãáâ ¢«¨¢ âì.
|
||||||
|
LD C,C - ޝ¥à æ¨ï Fill - § ¯®«¥¨¥ ®¤¨¬ ¡ ©â®¬. �®á«¥¤ãîé ï
|
||||||
|
ª®¬ ¤ ⨯ LD (HL),A ¯à¨¢¥¤¥â ª § ¯®«¥¨î 㪠§ ®£®
|
||||||
|
à ¥¥ ª®«¨ç¥á⢠¡ ©â § 票¥¬ A
|
||||||
|
LD E,E - ޝ¥à æ¨ï Fill ¤«ï £à ä¨ç¥áª®£® íªà - § ¯®«¥¨¥
|
||||||
|
¢¥à⨪ «ìëå «¨¨©.
|
||||||
|
LD H,H - rezerved
|
||||||
|
LD L,L - ª®¯¨à®¢ ¨¥ ¡«®ª . �®á«¥¤ãîé ï ª®¬ ¤ ⨯ LD A,(HL)
|
||||||
|
¯à¨¢¥¤¥â ª § ¯®«¥¨î އ“ ªá¥«¥à â®à ¤ 묨 ¨§ ¤à¥á (HL),
|
||||||
|
ª®¬ ¤ ⨯ LD (DE),A ¯à¨¢¥¤¥â ª ¯¥à¥§ ¯¨á¨ ¤ ëå ¨§ އ“
|
||||||
|
ªá¥«¥à â®à ¢ ®á®¢®¥ ¨«¨ ¢¨¤¥®-އ“.
|
||||||
|
LD A,A - ª®¯¨à®¢ ¨¥ ¡«®ª ¤«ï £à ä¨ç¥áª®£® íªà ¯®¤®¡ ª®¬ ¤¥
|
||||||
|
LD L,L, ® à ¡®â ¥â á ¢¥à⨪ «ì묨 «¨¨ï¬¨ íªà .
|
||||||
|
|
||||||
|
�ਬ¥à ¨á¯®«ì§®¢ ¨ï ªá¥«¥à â®à :
|
||||||
|
|
||||||
|
; ‘ç¨â ¥¬, çâ® íªà ï áâà ¨æ 㦥 ®âªàëâ ¯® ¤à¥áã #C000
|
||||||
|
LD HL,#C040 ; ¤à¥á ç « «¨¨¨ ¯¥à¢®£® íªà
|
||||||
|
LD DE,#C180 ; ¤à¥á ç « «¨¨¨ ¢â®à®£® íªà
|
||||||
|
LD BC,#140 ; ¤«¨ íªà ¯® £®à¨§®â «¨
|
||||||
|
DI ; § ¯à¥â¨âì ¯à¥àë¢ ¨ï ¤«ï à ¡®âë á ªá¥«¥à â®à®¬
|
||||||
|
LD D,D ; ¢ª«îç¨âì ªá¥«¥à â®à ãáâ ®¢ªã à §¬¥à ¡«®ª
|
||||||
|
LD A,0 ; ãáâ ®¢¨âì à §¬¥à ¡«®ª - 256 ¡ ©â
|
||||||
|
LD A,A ; ãáâ ®¢¨âì ªá¥«¥à â®à ª®¯¨à®¢ ¨¥
|
||||||
|
; ¢¥à⨪ «ìëå «¨¨©.
|
||||||
|
LDIR ; ª®¯¨à®¢ âì !
|
||||||
|
LD B,B ; ¢ëª«îç¨âì ªá¥«¥à â®à
|
||||||
|
EI ; ¢ª«îç¨âì ¯à¥àë¢ ¨ï
|
||||||
|
|
||||||
|
�â®â ®â१®ª ¯à®£à ¬¬ë ¯à®¨§¢¥¤¥â ª®¯¨à®¢ ¨¥ ¢á¥£® íªà á ®¤®£®
|
||||||
|
íªà ¤à㣮©. ‚à¥¬ï ¥£® ¨á¯®«¥¨ï á®áâ ¢«ï¥â ¯à¨¬¥à® 1.2 ¨â .
|
||||||
|
|
||||||
|
„®¯®«¨â¥«ìë¥ äãªæ¨¨ ªá¥«¥à â®à ¯®ï¢«ïî騥áï ¢ ª®ä¨£ãà æ¨¨
|
||||||
|
Sprinter-3 à ¡®â îâ ¯®¤®¡ë¬ ¦¥ ®¡à §®¬. „«ï ¢ë¯®«¥¨ï «®£¨ç¥áª¨å äãªæ¨©
|
||||||
|
¨á¯®«ì§ãîâáï ª®¬ ¤ë XOR (HL); OR (HL); AND (HL).
|
||||||
|
|
||||||
|
�ਬ¥à ªá®àª¨ ¡«®ª ¢ 256 ¡ ©â.
|
||||||
|
|
||||||
|
LD HL,ADRES_1
|
||||||
|
LD DE,XOR_DAT
|
||||||
|
DI
|
||||||
|
LD D,D
|
||||||
|
LD A,0 ; ç¨á«® ¡ ©â, ª®â®àë¥ ¤® ¯à®ªá®à¨âì
|
||||||
|
LD L,L
|
||||||
|
LD A,(DE) ; ‚§ïâì ¡«®ª ¢ އ“ ªá¥«¥à â®à
|
||||||
|
XOR (HL) ; ¯à®¨§¢¥á⨠®¯¥à æ¨î XOR á ¤ 묨 ªá¥«¥à â®à
|
||||||
|
LD (HL),A ; § ¯®¬¨âì ¢ އ“ १ã«ìâ â ®¯¥à 樨
|
||||||
|
LD B,B
|
||||||
|
EI
|
||||||
|
|
||||||
|
‘ª®à®áâì à ¡®âë ªá¥«¥à â®à ®£à ¨ç¨¢ ¥âáï ⮫쪮 䨧¨ç¥áª®©
|
||||||
|
᪮à®áâìî à ¡®âë ®á®¢®£® އ“. Ž¯à¥¤¥«¨âì ¢à¥¬ï à ¡®âë ª®¬ ¤ë á
|
||||||
|
ªá¥«¥à â®à®¬ ¬®¦® ¯® â ª®© ¯à¨¬¥à®© ä®à¬ã«¥:
|
||||||
|
|
||||||
|
‚६ï à ¡®âë = ¢à¥¬ï à ¡®âë ª®¬ ¤ë ¡¥§ ªá¥«¥à â®à + ¢à¥¬ï
|
||||||
|
à ¡®âë ªá¥«¥à â®à
|
||||||
|
‚६ï à ¡®âë ªá¥«¥à â®à = ç¨á«® ¯¥à¥áë« ¥¬ëå ¡ ©â /7000000 (ᥪã¤)
|
||||||
|
|
||||||
|
Žâª«î票¥ ¯à¥àë¢ ¨© ¢® ¢à¥¬ï à ¡®âë ªá¥«¥à â®à ¥®¡å®¤¨¬®, â ª
|
||||||
|
ª ª ¢ íâ®â ¬®¬¥â ç áâ¨ç® ¬¥ï¥âáï á¨á⥬ ª®¬ ¤ ¯à®æ¥áá®à ¨ ¯à®£à ¬¬
|
||||||
|
¯à¥àë¢ ¨¨ ¥ ᬮ¦¥â à ¡®â âì ®à¬ «ì®.
|
||||||
|
|
||||||
|
|
||||||
|
‡ ª«î票¥.
|
||||||
|
|
||||||
|
� ¡®â ¤ Sprinter-®¬ ¯à®¤®«¦ ¥âáï. ‘®¢¥àè¥áâ¢ã¥âáï ¦¥«¥§® ¨
|
||||||
|
¡¨®á. �¨è¥âáï á®äâ, ¯®¤¤¥à¦¨¢ î騩 à áè¨à¥ë¥ ०¨¬ë à ¡®âë ª®¬¯ìîâ¥à .
|
||||||
|
|
||||||
|
�® ¢á¥¬ ª®¬¬¥àç¥áª¨¬ ¢®¯à®á ¬ á¢ï§ ë¬ á ¯à¨®¡à¥â¥¨¥¬ ª®¬¯ìîâ¥à
|
||||||
|
¬®¦® ®¡à é âìáï ¢ ä¨à¬ã "�¥â¥àá":
|
||||||
|
|
||||||
|
Adress: ‘ ªâ-�¥â¥à¡ãà£, ã«. ‚®ááâ ¨ï, ¤. 35, ®ä. 31.
|
||||||
|
Phone: (812)-327-35-31
|
||||||
|
E-mail: peters@atlant.ru
|
||||||
|
|
||||||
|
�® â¥å¨ç¥áª¨¬ ¢®¯à®á ¬ ®¡à é âìáï ª® ¬¥:
|
||||||
|
|
||||||
|
Fido: Ivan Mak (2:5030/529.24)
|
||||||
|
E-mail: ivan_mak@yahoo.com (¢à¥¬¥® § ªàëâ)
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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 |
|
||||||
Binary file not shown.
Binary file not shown.
@@ -46,10 +46,16 @@ void gfx_scroll_h(const gfx_rect_t *area, int16_t dx, gfx_rect_t *dirty) {
|
|||||||
* DI/EI-банды по 16 строк leaf делает сам (h: 0=256). Между бандами по
|
* DI/EI-банды по 16 строк leaf делает сам (h: 0=256). Между бандами по
|
||||||
* ширине CPU-адрес двигаем на 256 (Port_Y выбирает строку). */
|
* ширине CPU-адрес двигаем на 256 (Port_Y выбирает строку). */
|
||||||
while (w) {
|
while (w) {
|
||||||
uint8_t cw = (w > 256) ? 256 : (uint8_t)w; /* 0 => 256 */
|
// Закомментированный блок должен работать правильно но не работает
|
||||||
|
// почему-то при w > 256 второй проход мусорит
|
||||||
|
// TODO: разобраться
|
||||||
|
// uint8_t cw = (w > 256) ? 256 : (uint8_t)w; /* 0 => 256 */
|
||||||
|
// _bgi_scroll_rows_raw(src, dst, cw, h, (uint8_t)area->y);
|
||||||
|
// src += 256; dst += 256;
|
||||||
|
// w -= (w > 256) ? 256 : w;
|
||||||
|
uint8_t cw = (w > 255) ? 255 : (uint8_t)w; /* 0 => 256 */
|
||||||
_bgi_scroll_rows_raw(src, dst, cw, h, (uint8_t)area->y);
|
_bgi_scroll_rows_raw(src, dst, cw, h, (uint8_t)area->y);
|
||||||
src += 256; dst += 256;
|
src += cw; dst += cw; w -= cw;
|
||||||
w -= (w > 256) ? 256 : w;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_bgi_end();
|
_bgi_end();
|
||||||
|
|||||||
Reference in New Issue
Block a user