PoP roomtest (план v2, шаг 1): таблицы анимации Kid -> EMM-страница
kid_frames (241*5) и kid_seqtbl (2310) занимали 3.5 КБ в _CODE окна W1/W2 — самого дефицитного ресурса. Теперь они лежат в kid_data.bin (отдельная EMM-страница), которая маппится в W0 ровно на время play_seq — один map/unmap за тик, в фазе тика, без конфликта с атласом в W0. Ключ к переносу — порт load_frame/cur_frame (seg006): оригинал раз за тик копирует кадр в структуру, и вся коллизия/отрисовка читает ЕЁ, а не таблицу. У нас так же: kid_cur_dx/kid_cur_flags (их дёргают несколько раз за кадр из pop_map) и kid_draw читают cur_frame — 5 байт в _DATA. kid_seq_off (230 Б) оставлен резидентным: его читает kid_set_seq из pop_ctrl/pop_map, вне страницы. pop_extract_kid_data.py теперь пишет и kid_data.bin, и урезанный kid_data.h (тип kframe, размеры, смещения в бинаре, kid_seq_off). Замер: _CODE 24881 -> 21634 (-3247 Б), куча W2 2076 -> 5315 Б, W3 без изменений. Проверено в MAME скриптом: стойка -> бег (кадр 8) -> стоп, перемещение и коллизия у кромки работают, спрайт рисуется. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
* pop_kid.c — движок Kid (Фаза K1): порт seg006.c play_seq/load_frame +
|
||||
* seqtbl-интерпретатор. Данные — kid_data.h.
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sprinter.h>
|
||||
#include <sprinter_mem.h>
|
||||
#include <graphics.h>
|
||||
#include <gfx.h>
|
||||
#include <sprite.h>
|
||||
@@ -75,8 +79,76 @@ void pop_kid_free(void)
|
||||
kid_npages = 0;
|
||||
}
|
||||
|
||||
/* ---- seqtbl-доступ (база SEQTBL_BASE) ------------------------------ */
|
||||
#define SEQ(cs) kid_seqtbl[(uint16_t)((cs) - SEQTBL_BASE)]
|
||||
/* ---- Данные анимации в EMM-странице (kid_data.bin) ------------------ *
|
||||
* Таблица кадров (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
|
||||
#define KD_FRAMES(i) ((const uint8_t *)(KD_DATA_OFF + KID_BIN_FRAMES_OFF) + (uint16_t)(i) * 5u)
|
||||
#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_FRAMES(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)
|
||||
{
|
||||
@@ -84,17 +156,23 @@ static uint8_t char_dx_forward(int8_t dx)
|
||||
return (uint8_t)(Kid.x + dx);
|
||||
}
|
||||
|
||||
/* Аксессоры к текущему кадру (для pop_map — без дублирования kid_frames). */
|
||||
int8_t kid_cur_dx(void) { return kid_frames[Kid.frame].dx; }
|
||||
uint8_t kid_cur_flags(void) { return kid_frames[Kid.frame].flags; }
|
||||
/* Аксессоры к текущему кадру (для pop_map): читают cur_frame, НЕ таблицу —
|
||||
* их дёргают несколько раз за кадр, маппинг страницы тут недопустим. */
|
||||
int8_t kid_cur_dx(void) { return cur_frame.dx; }
|
||||
uint8_t kid_cur_flags(void) { return cur_frame.flags; }
|
||||
|
||||
/* seqtbl_offset_char: сменить последовательность Kid (единая точка —
|
||||
* 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]; }
|
||||
|
||||
/* play_seq (seg006.c:570): крутит опкоды до КАДРА (байт < 0xF0). */
|
||||
/* play_seq (seg006.c:570): крутит опкоды до КАДРА (байт < 0xF0).
|
||||
* Страница данных маппится в W0 на ВЕСЬ разбор — один map/unmap за вызов
|
||||
* (в тике, до отрисовки: конфликта с атласом в W0 нет). В конце —
|
||||
* load_frame: пока страница ещё замаплена, копируем кадр в cur_frame. */
|
||||
void play_seq(void)
|
||||
{
|
||||
if (!kdat_ok) return;
|
||||
gfx_w0_map(kdat_page);
|
||||
for (;;) {
|
||||
uint8_t cmd = SEQ(Kid.curr_seq);
|
||||
Kid.curr_seq++;
|
||||
@@ -154,6 +232,8 @@ void play_seq(void)
|
||||
break;
|
||||
default: /* КАДР */
|
||||
Kid.frame = cmd;
|
||||
load_frame(); /* cur_frame := таблица[frame] (страница ещё в W0) */
|
||||
gfx_w0_unmap();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -280,7 +360,7 @@ void kid_heal(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;
|
||||
uint8_t page, idx;
|
||||
const uint8_t *img;
|
||||
|
||||
Reference in New Issue
Block a user