Files
Sprinter-SDCC/docs/fast_ram.md
T
snark13 1b78dda125 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>
2026-06-26 23:19:00 +03:00

12 KiB
Raw Permalink Blame History

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 — мусор, важен сам факт обращения):

        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:

        ; выбрать физическую страницу 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 временно выключается, после — восстанавливается прежнее состояние:

_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 вокруг всех точек входа в систему.