mdview2: статус-бар в отдельный модуль, упростить alloc_set_storage

- mdview2_status.c: вынести статус-бар/меню/спиннер из ядра
- mdview2.c: убрать retry-цикл в alloc_set_storage (fail-fast вместо
  ложной устойчивости — при нехватке EMM под индекс контент тоже не влезет)
- mdview2.h: дополнить экспортами статус-модуля
- mdview2_md.c / mdview2_raw.c: зачистка после расщепления
- mdview/mdview.c: переименовать scroll_* → md_scroll_* (симметрия)
- docs/fast_ram.md, docs/turboc.txt: добавить справочные доки
- examples/mdview2/README.MD, READMEBG.MD: обновить описание

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 23:19:00 +03:00
parent 05916a3cc6
commit 1b78dda125
12 changed files with 1802 additions and 443 deletions
+195
View File
@@ -0,0 +1,195 @@
# Fast RAM (Быстрое ОЗУ / «КЭШ-ОЗУ») на Sprinter
Сводка по результатам изучения документации платформы. Источники:
- `docs/converted/Architecture.txt` — официальное «Описание архитектуры» (раздел
«Распределение основной памяти»).
- `docs/converted/ARHITECT.txt` — ранняя редакция того же документа (про загрузку
конфигураций ППЛМ).
- `docs/converted/IvanMak.txt` / `docs/converted/Parinov.txt` / `docs/converted/Forum.txt`
и `docs/part2/forum.txt` — форумные ответы Дениса Паринова (Sprinter Team) и
руководство Ивана Мака (раздел «7 КЭШ-ОЗУ»).
- `docs/part2/accelerator_doc.txt` — ограничение акселератора.
- `docs/samples/sprinterIntLib.asm` — практический пример temporary-off / restore.
> **Терминология.** В документации одно и то же ОЗУ называется тремя именами:
> **Fast RAM**, **Быстрое ОЗУ** и **«КЭШ-ОЗУ»**. Это *не* кэш в формальном смысле
> (нет автоматического заполнения/вытеснения) — это отдельный массив статической
> памяти, в котором процессор работает на полной частоте **без тактов ожидания**.
> Имя «КЭШ» — историческое, по аналогии с кэшем на КР537РУ10 в Pentagon-128.
---
## 1. Что это и зачем
* **Объём:** 64 КБ статической памяти (SRAM), отдельной от основного DRAM-SIMM
(4 МБ) и от видео-ОЗУ (256 КБ).
* **Скорость:** процессор обращается к Fast RAM на полной тактовой частоте
(21 МГц) **без wait-state'ов**. Основное ОЗУ (DRAM) требует тактов ожидания,
поэтому код и данные в Fast RAM исполняются/читаются заметно быстрее.
* **Назначение:** разместить «горячий» код или данные (внутренние циклы,
таблицы, буферы), которые критичны по скорости.
* **Системная роль:** Fast RAM также используется механизмом
переконфигурирования ППЛМ — именно в неё BIOS грузит данные новой
конфигурации и флаг `ACEX_30K_LOADING` (старое имя `FLEX_10K_LOADING`) перед
программным сбросом. Поэтому к Fast RAM нельзя относиться как к «своей» памяти,
которая всегда сохраняется (см. §5).
---
## 2. Карта физических страниц
Память делится на 16 КБ-блоки с однобайтовым физическим номером:
| Тип памяти | Физические номера страниц |
|---------------|---------------------------|
| Основное ОЗУ | `#00..#4F`, видео-область `#50..#5F`, ... |
| ПЗУ (ROM) | `#E0..#EF` |
| **Fast RAM** | `#F0..#FF` |
> Хотя диапазон номеров Fast RAM — `#F0..#FF` (16 значений), **реально
> используются только биты 1 и 2** номера страницы. То есть адресуются 4
> страницы × 16 КБ = **64 КБ**: `#F0`, `#F2`, `#F4`, `#F6`.
---
## 3. Как включать Fast RAM
Есть **два способа** подключить Fast RAM в адресное пространство Z80.
### Способ A. Pentagon-style через порт `#FB` / `#7B` (в окно 0)
Включается «как кэш в Pentagon»: подключает 16 КБ Fast RAM в **окно 0**
(`#0000..#3FFF`) вместо ПЗУ. Переключение — *побочный эффект чтения порта*
(значение в `A` после `IN` — мусор, важен сам факт обращения):
```asm
DI
IN A,(#FB) ; включить Fast-RAM — 16 КБ в окно 0 (#0000..#3FFF)
; ... ваш код / работа с Fast RAM ...
IN A,(#7B) ; выключить Fast-RAM (вернуть ПЗУ в окно 0)
EI
```
* `IN A,(#FB)`**включить**.
* `IN A,(#7B)`**выключить**.
> **Конфликт портов.** Порт `#FB` (и `#4F`) — это также порт COVOX/Blaster-а.
> Вывод (`OUT`) в `#FB` управляет звуком, а *чтение* (`IN`) — переключает
> Fast RAM. Не путать направления обращения.
### Способ B. Как ПЗУ — через PAGE0 (`#82`) + порт `#1FFD`
Fast RAM-страница (`#F0..#FF`) выбирается в PAGE0 и подключается на место ПЗУ
в окно 0 через спец-порт `#1FFD`:
```asm
; выбрать физическую страницу Fast RAM в PAGE0
LD A, #F0 ; номер страницы Fast RAM
OUT (#82), A ; PAGE0 = страница в окно 0
LD A,1 ; 1 → ОЗУ (выбранная страница) в #0000..#3FFF
LD BC,#1FFD
OUT (C),A
; ...
LD A,0 ; 0 → вернуть ПЗУ в #0000..#3FFF
LD BC,#1FFD
OUT (C),A
```
* Порты PAGE: `PAGE0=#82`, `PAGE1=#A2`, `PAGE2=#C2`, `PAGE3=#E2`.
**Чтение** порта PAGE возвращает текущий номер страницы.
* Эти адреса портов формально могут отличаться в других конфигурациях ППЛМ —
правильнее запрашивать их у BIOS и сверять (см. `docs/part2/bios_doc.txt`,
~строка 1033).
---
## 4. Преимущества
1. **Скорость без wait-state.** Главное и единственное предназначение — код и
данные исполняются на полной частоте 21 МГц без тактов ожидания, в отличие от
основного DRAM.
2. **Идеально для горячих участков.** Внутренние циклы, lookup-таблицы,
временные буферы рендера — то, к чему обращаются интенсивно и многократно.
3. **Отдельный массив.** Не отнимает страницы основного 4 МБ ОЗУ и не пересекается
с видео-областью.
---
## 5. Ограничения и подводные камни ⚠️
Это **самая важная часть** — Fast RAM небезопасна в обращении и легко даёт
«молча не работает».
1. **Акселератор НЕ работает с Fast RAM.**
Акселератор поддерживает пересылку блоков только для основного ОЗУ и
видео-ОЗУ. Пересылку **ROM и FastRAM он не поддерживает**. То есть нельзя
использовать accel-Fill/Copy для заполнения или копирования в/из Fast RAM —
только обычные `LD`-циклы процессора.
2. **Содержимое не сохраняется между процессами.**
Fast RAM может быть использована другими программами. При запуске любого
процесса через DSS (а также самим механизмом переконфигурирования ППЛМ)
**содержимое Fast RAM может быть затёрто**. Нельзя рассчитывать на
персистентность данных между вызовами системы.
3. **Перед вызовами DSS и BIOS Fast RAM надо ОТКЛЮЧАТЬ.**
Системные функции рассчитывают на стандартную карту памяти (ПЗУ в окне 0).
Вызывать `RST 10h` (ESTEX/DSS) или `RST 8` (BIOS) при включённой Fast RAM в
окне 0 — нельзя.
4. **Прерывания.**
Fast RAM (способ A) подключается в окно 0, перекрывая ПЗУ и системный вектор.
Если используются прерывания, программа **обязана установить свой обработчик
по адресу `#0038`**. На практике работу с Fast RAM ведут с `DI`, а на время
ожидания кадра/`halt` Fast RAM временно выключают и восстанавливают (см. §6).
5. **Окно 0 занято под DSS.**
В нашем C-toolchain'е окно 0 (`#0000..#3FFF`) — это ESTEX/DSS система
(см. `release_docs/ru/platform_reference.md`). Подключение Fast RAM в окно 0
вытесняет именно её, что усиливает требование п.3.
6. **Конфликт `#FB` с COVOX.** См. §3, способ A.
---
## 6. Канонический паттерн temporary-off / restore
Из реального резидента (`docs/samples/sprinterIntLib.asm`): перед `ei: halt`
(ожидание кадрового прерывания) Fast RAM временно выключается, после —
восстанавливается прежнее состояние:
```asm
_intWaitVsyncSys
call memCacheOffTemporary ; временно выключаем Fast RAM
ei
halt
jp memCacheRestoryState ; восстанавливаем прежнее состояние подключения
```
Идея паттерна: библиотека хранит флаг «было ли Fast RAM включено», умеет
безопасно его снять на время системных операций (прерывания, DSS/BIOS) и вернуть
обратно. При интеграции в C-toolchain эту логику следует обернуть так же:
сохранять состояние, отключать вокруг любого `RST`/`halt`, восстанавливать.
---
## 7. Выводы для нашего C-toolchain (SDCC + target-слой)
* **Из коробки сейчас не используется.** В `runtime/`, `lib/`, `libc/` обращений
к Fast RAM нет (порт `#FB`/`#7B` нигде не задействован под эту задачу).
* **Где могло бы пригодиться:** разместить «горячую» функцию или таблицу в
Fast RAM для ускорения. Но 64 КБ перекрывают окно 0, конфликтуют с DSS и не
переживают системные вызовы — это узкоспециализированный, ручной режим, не
кандидат на общий механизм линковки.
* **Реалистичный сценарий:** короткий самодостаточный inner-loop без вызовов
системы, с `DI`, со своим вектором `#0038`, скопированный в Fast RAM обычным
`LD`-циклом (не акселератором), исполняемый из окна 0, с гарантированным
восстановлением карты памяти перед любым `RST`.
* **Несовместимость с акселератором** означает, что для графики/блочных операций
Fast RAM бесполезна — там выигрывает accel по основному/видео-ОЗУ.
Если будем добавлять поддержку — делать это отдельным opt-in механизмом
(по аналогии с banked-режимами), с обязательной обёрткой off/restore вокруг всех
точек входа в систему.