147cb185b1
MEM-COLD3, шаги 3-5. Кандидаты выбирались не по размеру, а по тому, КТО зовёт: если единственный вызывающий уже в банке, код едет к нему и трамплин не появляется вовсе. * pop_kdraw.c -> БАНК 4 (к pop_cdraw.c): клинок в руке (pop_sword_draw) и блит спрайта chtab_2 по id (pop_kid_img_blit). Оба звал ровно pop_cdraw, теперь вызовы прямые — контракт и условие корректности в _pop_kdraw.h. * pop_kboot.c -> БАНК 8: загрузка атласов Кида и страницы kid_data.bin (раз за игру). Дескриптор страницы — _pop_kid.h. * pop_guard_cold.c -> БАНК 8: страж идёт за Кидом + вход стража в комнату. Оба зовёт roomtest_cold.c из того же банка — снова без трамплина. * Из main в банк 8 уехали pop_boot (загрузка ресурсов, палитра, первый экран), pop_level_switch (смена уровня) и pop_shutdown. FIRST_LEVEL переехал в pop_tune.h — константа нужна обеим половинам цикла. _CODE 23005 -> 19861, куча 3525 -> 6669 Б. Банк 8 — 6.5 из 16 КБ. tests-host 6/6 (в наборы добавлены eng_pop_kboot и eng_pop_guard_cold).
90 lines
3.5 KiB
C
90 lines
3.5 KiB
C
/*
|
||
* pop_kboot.c — ЗАГРУЗКА ресурсов Кида: атласы chtab_2 (kid0..27.atl) и
|
||
* страница таблиц анимации (kid_data.bin). БАНК 8.
|
||
*
|
||
* Отрабатывает раз за игру (и на выходе — освобождение), поэтому места в
|
||
* резиденте W1 не занимает: контракт с интерпретатором — _pop_kid.h, там
|
||
* же дескриптор страницы данных.
|
||
*/
|
||
#include <fcntl.h>
|
||
#include <unistd.h>
|
||
#include <sprinter.h>
|
||
#include <sprinter_mem.h>
|
||
#include <sprite.h>
|
||
#include "pop_kid.h"
|
||
#include "_pop_kid.h"
|
||
#include "kid_data.h"
|
||
|
||
/* ISR-стаб W0-страницы (тот же приём, что atlas_load): при прерывании с
|
||
* замапленной в W0 страницей CPU прыгает на 0x0038 → там обязан быть JP на
|
||
* _gfx_w0_isr (восстановит окно). */
|
||
extern void _gfx_w0_isr(void);
|
||
|
||
#define KID_MAXPAGES 28
|
||
|
||
int pop_kid_load(uint8_t npages) __banked
|
||
{
|
||
static const char *const names[KID_MAXPAGES] = {
|
||
"KID\\kid0.atl","KID\\kid1.atl","KID\\kid2.atl","KID\\kid3.atl","KID\\kid4.atl","KID\\kid5.atl",
|
||
"KID\\kid6.atl","KID\\kid7.atl","KID\\kid8.atl","KID\\kid9.atl","KID\\kid10.atl","KID\\kid11.atl",
|
||
"KID\\kid12.atl","KID\\kid13.atl","KID\\kid14.atl","KID\\kid15.atl","KID\\kid16.atl","KID\\kid17.atl",
|
||
"KID\\kid18.atl","KID\\kid19.atl","KID\\kid20.atl","KID\\kid21.atl","KID\\kid22.atl","KID\\kid23.atl",
|
||
"KID\\kid24.atl","KID\\kid25.atl","KID\\kid26.atl","KID\\kid27.atl"
|
||
};
|
||
uint8_t i;
|
||
if (npages > KID_MAXPAGES) npages = KID_MAXPAGES;
|
||
for (i = 0; i < npages; i++)
|
||
if (atlas_load(&kidp[i], names[i]) != 0)
|
||
return -1;
|
||
kid_npages = npages;
|
||
return 0;
|
||
}
|
||
|
||
void pop_kid_free(void) __banked
|
||
{
|
||
uint8_t i;
|
||
for (i = 0; i < kid_npages; i++)
|
||
atlas_free(&kidp[i]);
|
||
kid_npages = 0;
|
||
}
|
||
|
||
/* Таблица кадров (241*5 Б) и seqtbl (2310 Б) занимали 3.5 КБ в _CODE окна
|
||
* W1/W2 — самый дефицитный ресурс. Теперь они лежат в отдельной EMM-
|
||
* странице, которая маппится в W0 РОВНО на время play_seq (раз за тик).
|
||
* Страница адресуется как у pop_level: данные с 0x100, ниже — ISR-стаб. */
|
||
int pop_kid_data_load(const char *path) __banked
|
||
{
|
||
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) __banked
|
||
{
|
||
if (kdat_ok) { mem_free_block(kdat_blk); kdat_ok = 0; }
|
||
}
|