Unify OPL4 loading and fix progress page corruption
This commit is contained in:
+139
-11
@@ -618,6 +618,99 @@ ivf_no:
|
||||
__endasm;
|
||||
}
|
||||
|
||||
/* 1 = после холодного загрузчика дочитать непрочитанный хвост файла в
|
||||
* освободившиеся после сжатия страницы (нужно только если файл целиком
|
||||
* не поместился в мегабуфер при первичной загрузке). */
|
||||
static uint8_t s_load_tail;
|
||||
|
||||
/* ── Прогресс-бар ────────────────────────────────────────────────────
|
||||
* Показывает ДОЛГИЕ фазы: заливку сэмплов в SRAM карты со сжатием
|
||||
* потока (рисует сам холодный загрузчик) и догрузку хвоста большого
|
||||
* файла (pb_tail_step ниже). Чтение с SD не отмечаем — оно заметно
|
||||
* быстрее, а лишние обращения к экрану в его цикле ни к чему.
|
||||
* Для .vgz бар целиком принадлежит inflate.asm, мы молчим.
|
||||
*
|
||||
* Доля закрашенного считается по Брезенхэму (только сложение/вычитание):
|
||||
* умножение и деление на Z80 тянут за собой библиотечные вызовы. */
|
||||
static uint8_t s_pb_acc; /* < tail_tot + stepv, в байт влезает */
|
||||
static uint16_t s_pb_cell;
|
||||
static uint8_t s_pb_stepv; /* прибавка за один шаг */
|
||||
static uint8_t s_pb_tail_tot; /* страниц в хвосте — шкала pb_tail_step */
|
||||
|
||||
/* Отдать бар холодному загрузчику: он рисует, пока основная память
|
||||
* плагина отключена. Пишем в его блок параметров по фиксированным
|
||||
* адресам #9802.. (страница 5, смещение #1800). Если дальше будет ещё
|
||||
* и догрузка хвоста — отдаём загрузчику половину, остальное ему. */
|
||||
static void pb_handoff(uint8_t with_tail)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)(0xD800 + 2);
|
||||
uint8_t w = ifl_pb_bw;
|
||||
|
||||
s_pb_cell = ifl_pb_attr_ofs & 0x3FFF;
|
||||
s_pb_acc = 0;
|
||||
|
||||
if (with_tail) {
|
||||
w >>= 1;
|
||||
s_pb_stepv = w; /* вторая половина — под хвост */
|
||||
s_pb_cell += w;
|
||||
}
|
||||
|
||||
if (s_is_vgz)
|
||||
w = 0; /* .vgz: бар за inflate.asm */
|
||||
|
||||
wc_mngc_pl(CMDBLK_PAGE);
|
||||
p[0] = ifl_pb_text_pg;
|
||||
p[1] = (uint8_t)(ifl_pb_attr_ofs & 0x3FFF);
|
||||
p[2] = (uint8_t)((ifl_pb_attr_ofs & 0x3FFF) >> 8);
|
||||
p[3] = ifl_pb_green;
|
||||
p[4] = w; /* прибавка за страницу (шкала — 64 страницы) */
|
||||
p[5] = w; /* сколько ячеек ещё не закрашено */
|
||||
p[6] = 0; /* аккумулятор: загрузчик может вызываться не раз */
|
||||
}
|
||||
|
||||
/* Один шаг догрузки хвоста — вызывается из ll4_tail_loop (уже на своей
|
||||
* странице, основная память снова видна). */
|
||||
void pb_tail_step(void)
|
||||
{
|
||||
uint8_t saved_pg;
|
||||
|
||||
if (s_is_vgz || !s_pb_tail_tot)
|
||||
return;
|
||||
|
||||
saved_pg = sfr_page3;
|
||||
sfr_page3 = ifl_pb_text_pg;
|
||||
|
||||
s_pb_acc += s_pb_stepv;
|
||||
while (s_pb_acc >= s_pb_tail_tot) {
|
||||
s_pb_acc -= s_pb_tail_tot;
|
||||
*(volatile uint8_t *)(0xC000 + s_pb_cell) = ifl_pb_green;
|
||||
s_pb_cell++;
|
||||
}
|
||||
|
||||
sfr_page3 = saved_pg;
|
||||
}
|
||||
|
||||
/* Один шаг из total; за все total шагов закрашивается ровно ifl_pb_bw ячеек. */
|
||||
static void pb_step(uint8_t total)
|
||||
{
|
||||
uint8_t saved_pg;
|
||||
|
||||
if (s_is_vgz)
|
||||
return;
|
||||
|
||||
saved_pg = sfr_page3;
|
||||
sfr_page3 = ifl_pb_text_pg;
|
||||
|
||||
s_pb_acc += ifl_pb_bw;
|
||||
while (s_pb_acc >= total) {
|
||||
s_pb_acc -= total;
|
||||
*(volatile uint8_t *)(0xC000 + s_pb_cell) = ifl_pb_green;
|
||||
s_pb_cell++;
|
||||
}
|
||||
|
||||
sfr_page3 = saved_pg;
|
||||
}
|
||||
|
||||
/* The unused tail of plugin-relative page 5 (not WC physical page #05)
|
||||
* contains the one-shot large OPL4 loader at logical address 9800h.
|
||||
* Offset 1800h is also above WC's 1000h..1447h screen scratch range. */
|
||||
@@ -651,6 +744,10 @@ ll4_irq_was_off:
|
||||
ld c, a ; final page count
|
||||
; D/E already hold page/address high byte
|
||||
|
||||
ld a, (_s_load_tail) ; файл целиком поместился → хвоста нет
|
||||
or a
|
||||
jr z, ll4_success
|
||||
|
||||
ll4_tail_loop:
|
||||
ld a, d
|
||||
cp a, #64
|
||||
@@ -681,6 +778,12 @@ ll4_tail_loop:
|
||||
or a
|
||||
jr nz, ll4_fail
|
||||
|
||||
push bc
|
||||
push de
|
||||
call _pb_tail_step ; страница хвоста дочитана — шаг бара
|
||||
pop de
|
||||
pop bc
|
||||
|
||||
inc d
|
||||
ld e, #0xc0
|
||||
jr ll4_tail_loop
|
||||
@@ -714,7 +817,9 @@ uint8_t load_vgm(void)
|
||||
s_pages = (uint8_t)((fsize + 16383UL) >> 14);
|
||||
if (!s_pages)
|
||||
s_pages = 1;
|
||||
s_pb_tail_tot = 0;
|
||||
if (s_pages > 64) {
|
||||
s_pb_tail_tot = (uint8_t)(s_pages - 64); /* шкала бара для хвоста */
|
||||
s_pages = 64;
|
||||
large_file = 1;
|
||||
}
|
||||
@@ -734,6 +839,7 @@ uint8_t load_vgm(void)
|
||||
/* WC_EOF нормален на последнем секторе */
|
||||
if (rc && rc != WC_EOF)
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
wc_mngcvpl(0); /* страница 0 для проверки заголовка */
|
||||
@@ -804,12 +910,33 @@ uint8_t load_vgm(void)
|
||||
dbg_trace2(0xA5, s_pages, 0);
|
||||
}
|
||||
|
||||
if (large_file) {
|
||||
s_pages = load_large_opl4();
|
||||
if (!s_pages)
|
||||
return 0;
|
||||
/* Холодный загрузчик (asm/opl4_loader.asm, страница 5) — единственный
|
||||
* путь заливки сэмплов OPL4 в SRAM карты. Запускаем его всегда, когда
|
||||
* поток начинается с блока 0x67, независимо от размера файла: он же
|
||||
* вырезает залитые блоки из потока и правит смещения в заголовке.
|
||||
* large_file → вдобавок дочитать хвост файла в освободившиеся страницы.
|
||||
* Файл без блоков (только встроенные GM-инструменты, либо вообще не
|
||||
* OPL4) загрузчику отдавать нельзя — он такое отвергает. */
|
||||
wc_mngcvpl(0);
|
||||
{
|
||||
const uint8_t *b = (const uint8_t *)0xC000;
|
||||
uint16_t ds = 0x40;
|
||||
if (*(const uint16_t *)(b + 0x08) >= 0x0150) {
|
||||
/* data offset относителен 0x34; старшие 16 бит всегда нулевые */
|
||||
uint16_t d = *(const uint16_t *)(b + 0x34);
|
||||
if (d)
|
||||
ds = 0x34 + d;
|
||||
}
|
||||
if (b[ds] != 0x67 && !large_file)
|
||||
return s_pages;
|
||||
}
|
||||
|
||||
pb_handoff(large_file);
|
||||
s_load_tail = large_file;
|
||||
s_pages = load_large_opl4();
|
||||
if (!s_pages)
|
||||
return 0;
|
||||
|
||||
return s_pages;
|
||||
}
|
||||
|
||||
@@ -1202,14 +1329,15 @@ void main(void)
|
||||
s_vgz_compressed_pages = 0;
|
||||
draw_pre_load_info();
|
||||
|
||||
/* Показать статус ДО начала загрузки — "Unpacking..." для .vgz
|
||||
* (распаковка), "Loading..." для файлов >= 1 МБ (синхронная заливка
|
||||
* сэмплов OPL4 в SRAM карты идёт байт за байтом с busy-wait и
|
||||
* занимает секунды; без надписи выглядит как зависание). Для .vgz
|
||||
* это последний WC API вызов перед inflate — дальше load_vgm
|
||||
* работает только портами. */
|
||||
/* Показать статус ДО начала загрузки: "Unpacking.." для .vgz,
|
||||
* "Loading.." для остальных. Мгновенной загрузки не бывает ни для
|
||||
* одного размера — чтение с SD плюс (для OPL4) побайтовая заливка
|
||||
* сэмплов в SRAM карты с busy-wait. Здесь же настраиваем прогресс-
|
||||
* бар: для .vgz его рисует inflate.asm, иначе — pb_step() ниже.
|
||||
* Для .vgz это последний WC API вызов перед inflate — дальше
|
||||
* load_vgm работает только портами. */
|
||||
s_is_vgz = is_vgz_filename();
|
||||
if (s_is_vgz || ((const uint8_t *)&wc_file_size)[2] >= 0x10) {
|
||||
{
|
||||
buf_clear(work_buf);
|
||||
buf_append_str(work_buf, s_is_vgz ? "Unpacking.." : "Loading..");
|
||||
print_line(&s_wnd, ROW_VGM_START, work_buf, WC_COLOR(WC_YELLOW, WC_BLACK));
|
||||
|
||||
Reference in New Issue
Block a user