ba3aca07bf
ЗАМЕР, из которого всё выросло (MAME, 2026-08-25): `open` стоит 51,4 мс, а чтение 16 КБ из уже открытого файла — 32,6 мс. То есть 61 % времени загрузки уходит на ОТКРЫТИЕ, а не на данные, и чистая скорость чтения — 491 КБ/с, а не 260. На диске игры 343 файла; одна только стартовая пачка (kid+shadow+bg+sound+guard, ~142 файла) — это 7,3 секунды чистого open. * toolchain/pop_pack_arc.py + pop_arc.c/h (банк 8) — формат PBA1: заголовок 512 Б, магия, count, записи по 4 байта (offset в СЕКТОРАХ — архив бывает больше 64 КБ; size в байтах — ресурс всегда <= 16 КБ, он обязан лезть в EMM-страницу). Таблицу держит вызывающий на своём стеке: в W2 её класть нельзя, а стека в точке загрузки израсходовано 75 байт из 1279 (замер там же). * libc: bank_read_page — чтение из УЖЕ ОТКРЫТОГО файла в EMM-страницу. bank_load_file переписана через неё, поэтому дублирования работы с W3 не осталось и резидент почти не вырос. * Набор эффектов: 10 файлов -> SND\snd.arc, один open вместо десяти. * Музыка: трек лежит ОДНИМ файлом и читается порциями по странице — нарезка на куски больше не нужна. Этот же путь понадобится финалу `won` (1,2 МБ), который в память целиком не влезает. * Менеджер звука приведён к оригиналу: играющая музыка участвует в таблицах приоритета наравне с эффектами (seg000:1672 + data.h:433). Почти вся музыка НЕперебиваема, поэтому поверх неё эффект не стартует — ровно как в SDLPoP; раньше эффект её перебивал. * ALLOCS 3000 -> 6000 (решение пользователя): сборка +20 с, резидент -161 байт. Куча 87 -> 248 Б. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
36 lines
1.8 KiB
C
36 lines
1.8 KiB
C
/*
|
||
* bank_read_page — прочитать из УЖЕ ОТКРЫТОГО файла прямо в EMM-страницу.
|
||
*
|
||
* Зачем отдельно от bank_load_file: та открывает и закрывает файл на каждый
|
||
* вызов, а `open` на Sprinter стоит дорого — замер в MAME (PoP, 2026-08-25):
|
||
* open 51,4 мс против 32,6 мс на чтение 16 КБ, то есть 61 % времени уходит
|
||
* на открытие. Кто читает из одного файла несколько кусков (архив ресурсов,
|
||
* поток музыки), обязан держать fd открытым — тогда эта цена платится раз.
|
||
*
|
||
* ESTEX принимает файловый буфер только в W1..W3; используем W3, сохраняя и
|
||
* восстанавливая раскладку. Функция резидентна, поэтому её безопасно
|
||
* вызывать из банкового кода huge: пока W3 занят целевой страницей, никакой
|
||
* памяти вызывающего мы не читаем. Позицию в файле вызывающий ставит сам
|
||
* (lseek) — здесь только перенос.
|
||
*
|
||
* Возврат: фактически прочитанный размер либо -1 + errno.
|
||
*/
|
||
#include <unistd.h>
|
||
#include <errno.h>
|
||
#include <sprinter.h>
|
||
#include <sprinter_mem.h>
|
||
|
||
int bank_read_page(int fd, uint8_t phys_page, uint16_t off, uint16_t size)
|
||
{
|
||
uint8_t saved;
|
||
int n;
|
||
if (off > 0x3FFFu || size > (uint16_t)(0x4000u - off)) {
|
||
errno = EINVAL; return -1;
|
||
}
|
||
saved = _io_page_w3;
|
||
sprinter_page_w3(phys_page);
|
||
n = read(fd, (void *)(0xC000u + off), size);
|
||
sprinter_page_w3(saved);
|
||
return n;
|
||
}
|