Unify OPL4 loading and fix progress page corruption
This commit is contained in:
Binary file not shown.
BIN
Binary file not shown.
@@ -15,6 +15,20 @@ OPL_WAVE_DAT EQU #7F
|
|||||||
PORT_SYSCONF EQU #20AF ; System Config (turbo bits [1:0]), see isr.s
|
PORT_SYSCONF EQU #20AF ; System Config (turbo bits [1:0]), see isr.s
|
||||||
TURBO_14MHZ EQU #02
|
TURBO_14MHZ EQU #02
|
||||||
|
|
||||||
|
; ── Блок параметров прогресс-бара ───────────────────────────────────
|
||||||
|
; Основная память плагина (Win2) на время работы загрузчика отключена —
|
||||||
|
; здесь стоит страница 5, — поэтому ifl_pb_* прочитать неоткуда. main.c
|
||||||
|
; кладёт нужное сюда ДО вызова, замапив страницу 5 в Win3 (адреса ниже
|
||||||
|
; фиксированы намеренно: #9802..#9806, их знает load_large_opl4()).
|
||||||
|
; Точка входа остаётся #9800, поэтому первым стоит перепрыг блока.
|
||||||
|
JR opl4_large_entry ; #9800
|
||||||
|
pb_text_pg: DB 0 ; #9802 физ. страница текстового экрана
|
||||||
|
pb_ptr: DW 0 ; #9803 текущая ячейка атрибутов (окно-отн.)
|
||||||
|
pb_green: DB 0 ; #9805 цвет закрашенной части
|
||||||
|
pb_step: DB 0 ; #9806 прибавка к аккумулятору за страницу
|
||||||
|
pb_left: DB 0 ; #9807 сколько ячеек ещё можно закрасить
|
||||||
|
pb_acc: DB 0 ; #9808 аккумулятор Брезенхэма (шкала — 64)
|
||||||
|
|
||||||
; Return: A bit 0..6 = compacted 16K page count (0 = reject),
|
; Return: A bit 0..6 = compacted 16K page count (0 = reject),
|
||||||
; A bit 7 = ROM-image flag,
|
; A bit 7 = ROM-image flag,
|
||||||
; H = first VPL page for the unread tail,
|
; H = first VPL page for the unread tail,
|
||||||
@@ -502,6 +516,17 @@ compact_and_patch:
|
|||||||
ld a,(dst_page)
|
ld a,(dst_page)
|
||||||
inc a
|
inc a
|
||||||
ld (dst_page),a
|
ld (dst_page),a
|
||||||
|
; Дальше копировать нечего, как только приёмник добрал до
|
||||||
|
; result_pages — это весь сжатый поток вместе с GD3. Без этой
|
||||||
|
; проверки цикл всегда шёл до 64-й страницы и для небольшого
|
||||||
|
; файла перемалывал сотни килобайт мусора за концом данных.
|
||||||
|
; (Для большого файла не срабатывает: там исходные страницы
|
||||||
|
; кончатся раньше, хвост дочитывается уже после возврата.)
|
||||||
|
push hl
|
||||||
|
ld hl,result_pages
|
||||||
|
cp (hl)
|
||||||
|
pop hl
|
||||||
|
jr nc,.copy_done
|
||||||
add a,#20
|
add a,#20
|
||||||
ld bc,PORT_W0
|
ld bc,PORT_W0
|
||||||
out (c),a
|
out (c),a
|
||||||
@@ -514,6 +539,10 @@ compact_and_patch:
|
|||||||
ld (copy_src_page),a
|
ld (copy_src_page),a
|
||||||
cp 64
|
cp 64
|
||||||
jr z,.copy_done
|
jr z,.copy_done
|
||||||
|
push de
|
||||||
|
call pb_tick ; фаза сжатия: продолжаем ту же шкалу
|
||||||
|
pop de
|
||||||
|
ld a,(copy_src_page)
|
||||||
add a,#20
|
add a,#20
|
||||||
ld bc,PORT_W3
|
ld bc,PORT_W3
|
||||||
out (c),a
|
out (c),a
|
||||||
@@ -596,7 +625,7 @@ next_src_page:
|
|||||||
call map_vpl
|
call map_vpl
|
||||||
ld hl,#C000
|
ld hl,#C000
|
||||||
ld (src_ptr),hl
|
ld (src_ptr),hl
|
||||||
ret
|
jp pb_tick ; фаза заливки: одна страница -> шаг бара
|
||||||
|
|
||||||
len_is_zero:
|
len_is_zero:
|
||||||
ld hl,block_len
|
ld hl,block_len
|
||||||
@@ -639,6 +668,58 @@ sub_len_bc:
|
|||||||
ld (block_len+2),hl
|
ld (block_len+2),hl
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
; ── Прогресс-бар ────────────────────────────────────────────────────
|
||||||
|
; Обе фазы загрузчика идут по страницам мегабуфера монотонно 0 -> 64:
|
||||||
|
; заливка двигает src_page от 0 до конца блоков, копирование продолжает
|
||||||
|
; с того же места до 64. Поэтому шкала фиксированная (64), и хватает
|
||||||
|
; одного счётчика Брезенхэма без умножения и деления.
|
||||||
|
; Вызывается из next_src_page и из цикла копирования; регистры не портит.
|
||||||
|
pb_tick:
|
||||||
|
push af
|
||||||
|
push bc
|
||||||
|
push hl
|
||||||
|
ld a,(pb_step)
|
||||||
|
ld hl,pb_acc
|
||||||
|
add a,(hl)
|
||||||
|
ld (hl),a
|
||||||
|
.spill: cp 64
|
||||||
|
jr c,.done
|
||||||
|
sub 64
|
||||||
|
ld (pb_acc),a
|
||||||
|
ld a,(pb_left)
|
||||||
|
or a
|
||||||
|
jr z,.done ; бар уже закрашен до конца
|
||||||
|
call pb_paint
|
||||||
|
ld a,(pb_acc)
|
||||||
|
jr .spill
|
||||||
|
.done: pop hl
|
||||||
|
pop bc
|
||||||
|
pop af
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Закрасить одну ячейку. Текстовый экран временно подставляем в Win0.
|
||||||
|
; PORT_W0 — write-only на реальном TSConf (и не обязан возвращать ранее
|
||||||
|
; записанное значение в эмуляторе), поэтому восстанавливать страницу через
|
||||||
|
; IN нельзя. Номер приёмника нам и так известен: #20 + dst_page. Во время
|
||||||
|
; заливки dst_page=0 и Win0 не используется, а во время копирования это
|
||||||
|
; всегда текущая страница назначения.
|
||||||
|
pb_paint:
|
||||||
|
ld bc,PORT_W0
|
||||||
|
ld a,(pb_text_pg)
|
||||||
|
out (c),a
|
||||||
|
ld hl,(pb_ptr)
|
||||||
|
ld a,(pb_green)
|
||||||
|
ld (hl),a ; Win0 начинается с #0000 — смещение и есть адрес
|
||||||
|
inc hl
|
||||||
|
ld (pb_ptr),hl
|
||||||
|
ld hl,pb_left
|
||||||
|
dec (hl)
|
||||||
|
ld a,(dst_page)
|
||||||
|
add a,#20
|
||||||
|
ld bc,PORT_W0
|
||||||
|
out (c),a
|
||||||
|
ret
|
||||||
|
|
||||||
chip_wait:
|
chip_wait:
|
||||||
in a,(OPL_STAT)
|
in a,(OPL_STAT)
|
||||||
rrca
|
rrca
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
/* Плотная раскладка: полная версия spectrum.s + загрузчик OPL4.
|
/* Плотная раскладка: полная версия spectrum.s + загрузчик OPL4.
|
||||||
* Проверяется build.bat: _CODE должен закончиться раньше _DATA,
|
* Проверяется build.bat: _CODE должен закончиться раньше _DATA,
|
||||||
* а последняя секция — раньше 0xC000. */
|
* а последняя секция — раньше 0xC000. */
|
||||||
#define VARIANT_DATA_LOC 0xB8DF
|
#define VARIANT_DATA_LOC 0xB8B8
|
||||||
|
|
||||||
/* ── Спектроанализатор: скорости затухания (в TV-кадрах) ────────── */
|
/* ── Спектроанализатор: скорости затухания (в TV-кадрах) ────────── */
|
||||||
/* Меньше = быстрее затухание. 1 = каждый кадр (~20 мс). */
|
/* Меньше = быстрее затухание. 1 = каждый кадр (~20 мс). */
|
||||||
|
|||||||
+20
-322
@@ -128,17 +128,11 @@ static uint16_t fb_scaled; /* temp: масштабированная часто
|
|||||||
static uint8_t fb_reg; /* temp: AY рег. (0xA0) / YMF278B port (0xD0) /
|
static uint8_t fb_reg; /* temp: AY рег. (0xA0) / YMF278B port (0xD0) /
|
||||||
* тип data-block (0x67) — ветки взаимоисключающие */
|
* тип data-block (0x67) — ветки взаимоисключающие */
|
||||||
|
|
||||||
/* ── Патч заголовков wave-таблицы после загрузки блока 0x84 (ROM Image) ──
|
/* Взводится холодным загрузчиком (через vgm_opl4_preloaded_rom), когда он
|
||||||
* См. wave_upload_block(): референсный NedoOS-драйвер (vgm/opl4.asm,
|
* перенёс в SRAM блок типа 0x84 (ROM Image) и пропатчил бит RAM-адресации
|
||||||
* opl4loadromdatablock) после заливки ROM-блока, чей адрес попадает в
|
* в 128 заголовках wave-таблицы. Тогда исходные номера волн из VGM надо
|
||||||
* первые 64КБ RAM-региона (где живёт таблица заголовков сэмплов, 128
|
* отображать в диапазон SRAM-заголовков 384-511 (см. обработчик 0xD0). */
|
||||||
* записей по 12 байт), принудительно взводит бит RAM-адресации (#20) в
|
static uint8_t opl4_rom_loaded;
|
||||||
* первом байте КАЖДОЙ записи — иначе встроенные в заголовки адреса
|
|
||||||
* сэмплов остаются ROM-относительными, и чип читает не тот PCM-семпл. */
|
|
||||||
static uint8_t hdr_recs; /* оставшиеся записи таблицы (0-128); 0=не патчим */
|
|
||||||
static uint8_t hdr_sub; /* позиция внутри 12-байтной записи (0-11) */
|
|
||||||
static uint8_t opl4_rom_loaded; /* 0x84 ROM image перенесён в SRAM; номера
|
|
||||||
* волн надо отображать в диапазон 384-511 */
|
|
||||||
|
|
||||||
/* VGM_FILL_CMD_BUDGET определён в variant_cfg.h (через isr.h) */
|
/* VGM_FILL_CMD_BUDGET определён в variant_cfg.h (через isr.h) */
|
||||||
|
|
||||||
@@ -827,307 +821,16 @@ static void asm_read_2bytes(void) __naked
|
|||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ─────────────────────────────────────────────────────────────────────
|
/* Заливка PCM-сэмплов в SRAM карты живёт целиком в холодном загрузчике
|
||||||
* OPL4 (ZXM-MoonSound) — прямая (не через cmd-buffer) запись в wave-порты
|
* (asm/opl4_loader.asm на оверлейной странице 5): он вызывается из
|
||||||
* #7E (выбор регистра) / #7F (данные), плюс переключение turbo-режима.
|
* load_vgm() ДО старта воспроизведения, заливает блоки 0x67 типа
|
||||||
* Используются ТОЛЬКО в wave_upload_block() — разовая синхронная заливка
|
* 0x84/0x87 и вырезает их из потока. Поэтому сюда, в основной бюджет
|
||||||
* PCM-сэмплов при загрузке трека, до старта ISR-плейбека (не hot-path).
|
* 0x8000-0xBFFF, эти 376 байт больше не входят, а обработчик 0x67 ниже
|
||||||
* ───────────────────────────────────────────────────────────────────── */
|
* просто пропускает блок: к началу воспроизведения его уже нет.
|
||||||
/* out (n),a — короткая форма (2 байта). Старший байт адреса (A15-A8)
|
|
||||||
* при этом равен A (значению-аргументу), но плата его не видит: линия
|
|
||||||
* CA[7..0] у CPLD DD2 — единственный адресный вход декодера портов
|
|
||||||
* #7E/#7F/#C4-#C7 (8 бит), верхняя половина шины к нему не подключена
|
|
||||||
* (см. схему ZXM-MoonSound, dd2.tdf) — как и в родном moon_driver.asm.
|
|
||||||
*
|
*
|
||||||
* Перед каждой записью — опрос busy-флага (бит0 порта #C4 — тот же
|
* ВАЖНО: загрузчик снимает только непрерывную серию блоков в САМОМ
|
||||||
* порт, что и FM Bank1 addr-select, но на чтение отдаёт статус чипа).
|
* начале потока. Блок сэмплов в середине трека будет пропущен, а не
|
||||||
* Без этого ожидания запись может быть потеряна чипом (особенно в
|
* залит (проверено: ни в одном файле Moonsound_pack такого нет). */
|
||||||
* режиме прямого доступа к памяти) — подтверждено рабочим NedoOS-
|
|
||||||
* драйвером (common/moonsound.asm: opl4_wait), а не только datasheet. */
|
|
||||||
static void chip_wait(void) __naked {
|
|
||||||
__asm
|
|
||||||
push af
|
|
||||||
cw_loop:
|
|
||||||
in a, (0xC4)
|
|
||||||
rrca
|
|
||||||
jr c, cw_loop
|
|
||||||
pop af
|
|
||||||
ret
|
|
||||||
__endasm;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wave_out_reg(uint8_t reg) __naked {
|
|
||||||
__asm
|
|
||||||
call _chip_wait
|
|
||||||
out (0x7E), a
|
|
||||||
ret
|
|
||||||
__endasm;
|
|
||||||
(void)reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wave_out_dat(uint8_t val) __naked {
|
|
||||||
__asm
|
|
||||||
call _chip_wait
|
|
||||||
out (0x7F), a
|
|
||||||
ret
|
|
||||||
__endasm;
|
|
||||||
(void)val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Быстрая заливка fb_w байт из текущей VPL-страницы. В отличие от
|
|
||||||
* asm_read_byte()+wave_out_dat() указатели и счётчик держатся в регистрах;
|
|
||||||
* обязательный busy-wait перед каждым байтом сохранён. Вызывающий код не
|
|
||||||
* даёт циклу пересечь границу страницы. */
|
|
||||||
static void wave_upload_fast(void) __naked {
|
|
||||||
__asm
|
|
||||||
ld hl, (_fb_rp)
|
|
||||||
ld bc, (_fb_w)
|
|
||||||
wuf_loop:
|
|
||||||
in a, (0xC4)
|
|
||||||
rrca
|
|
||||||
jr c, wuf_loop
|
|
||||||
ld a, (hl)
|
|
||||||
out (0x7F), a
|
|
||||||
inc hl
|
|
||||||
dec bc
|
|
||||||
ld a, b
|
|
||||||
or a, c
|
|
||||||
jr nz, wuf_loop
|
|
||||||
ld (_fb_rp), hl
|
|
||||||
ret
|
|
||||||
__endasm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─────────────────────────────────────────────────────────────────────
|
|
||||||
* wave_upload_block — залить payload VGM data-block 0x67 типа 0x84
|
|
||||||
* (YMF278B ROM Image) / 0x87 (RAM Image) в SRAM карты ZXM-MoonSound.
|
|
||||||
*
|
|
||||||
* Вызывается из обработчика 0x67 в vgm_fill_buffer() ДО начала реальной
|
|
||||||
* ISR-подачи звука (все такие блоки в реальных файлах идут одним пакетом
|
|
||||||
* в самом начале потока) — поэтому синхронная блокирующая заливка здесь
|
|
||||||
* безопасна: играть ещё нечему.
|
|
||||||
*
|
|
||||||
* Формат payload (VGM spec, "ROM/RAM Image" data block, offset от начала
|
|
||||||
* data-payload, т.е. после opcode+0x66+type+4-байт общего размера):
|
|
||||||
* [0..3] ROM/RAM Size (информационное, не используется)
|
|
||||||
* [4..7] Start Address — смещение внутри SRAM карты (0-based)
|
|
||||||
* [8..] сами байты сэмпла/инструмент-заголовков
|
|
||||||
*
|
|
||||||
* Адресация чипа YMF278B: 2МБ встроенный ROM (General MIDI) + 1МБ SRAM,
|
|
||||||
* физически идущие в чипе одним адресным пространством — SRAM начинается
|
|
||||||
* сразу по границе 0x200000 (аппаратный CS чипа по адресному биту A21,
|
|
||||||
* см. datasheet, от платы не зависит). wavetblhdr=4 (4×0x80000=0x200000)
|
|
||||||
* выставлен так, чтобы номер сэмпла (wave) 384 указывал ровно на начало
|
|
||||||
* этой SRAM — тем самым абсолютный адрес = 0x200000 + Start Address.
|
|
||||||
*
|
|
||||||
* len = полный размер data-block (4-байтовое поле "size" из потока),
|
|
||||||
* включает 8-байтовый под-заголовок выше.
|
|
||||||
* ───────────────────────────────────────────────────────────────────── */
|
|
||||||
static void wave_upload_block(void) __naked
|
|
||||||
{
|
|
||||||
__asm
|
|
||||||
; ROM/RAM Size (4 bytes) is informational only.
|
|
||||||
call _asm_read_2bytes
|
|
||||||
call _asm_read_2bytes
|
|
||||||
|
|
||||||
; NEW2: FM bank 1, register 05h = 03h. Wave registers ignore writes
|
|
||||||
; until this bit is enabled, and the command ISR has not started yet.
|
|
||||||
call _chip_wait
|
|
||||||
ld a, #0x05
|
|
||||||
out (0xC6), a
|
|
||||||
call _chip_wait
|
|
||||||
ld a, #0x03
|
|
||||||
out (0xC7), a
|
|
||||||
|
|
||||||
; VGM start address is little-endian; YMF278B wants high/mid/low.
|
|
||||||
call _asm_read_byte
|
|
||||||
ld (_fb_b2), a
|
|
||||||
call _asm_read_byte
|
|
||||||
ld (_fb_b1), a
|
|
||||||
call _asm_read_byte
|
|
||||||
ld (_fb_ch), a
|
|
||||||
call _asm_read_byte ; unused top byte of the 32-bit address
|
|
||||||
|
|
||||||
; Patch 128 twelve-byte headers only for a ROM image beginning at 0.
|
|
||||||
xor a
|
|
||||||
ld (_hdr_recs), a
|
|
||||||
ld (_hdr_sub), a
|
|
||||||
ld a, (_fb_reg)
|
|
||||||
cp a, #0x84
|
|
||||||
jr nz, wub_header_ready
|
|
||||||
ld a, (_fb_ch)
|
|
||||||
ld hl, #_fb_b1
|
|
||||||
or a, (hl)
|
|
||||||
inc hl
|
|
||||||
or a, (hl)
|
|
||||||
jr nz, wub_header_ready
|
|
||||||
ld a, #0x80
|
|
||||||
ld (_hdr_recs), a
|
|
||||||
wub_header_ready:
|
|
||||||
|
|
||||||
; Memory address = 200000h + start address. Register order matters.
|
|
||||||
ld a, #0x03
|
|
||||||
call _wave_out_reg
|
|
||||||
ld a, (_fb_ch)
|
|
||||||
add a, #0x20
|
|
||||||
call _wave_out_dat
|
|
||||||
ld a, #0x04
|
|
||||||
call _wave_out_reg
|
|
||||||
ld a, (_fb_b1)
|
|
||||||
call _wave_out_dat
|
|
||||||
ld a, #0x05
|
|
||||||
call _wave_out_reg
|
|
||||||
ld a, (_fb_b2)
|
|
||||||
call _wave_out_dat
|
|
||||||
|
|
||||||
; 11h = memory access mode, WT header base 200000h; 06h = data port.
|
|
||||||
ld a, #0x02
|
|
||||||
call _wave_out_reg
|
|
||||||
ld a, #0x11
|
|
||||||
call _wave_out_dat
|
|
||||||
ld a, #0x06
|
|
||||||
call _wave_out_reg
|
|
||||||
|
|
||||||
; fb_t32 contains the whole block payload, including its 8-byte header.
|
|
||||||
ld hl, (_fb_t32)
|
|
||||||
ld de, #0x0008
|
|
||||||
or a
|
|
||||||
sbc hl, de
|
|
||||||
ld (_fb_t32), hl
|
|
||||||
jr nc, wub_len_ready
|
|
||||||
ld hl, (_fb_t32 + 2)
|
|
||||||
dec hl
|
|
||||||
ld (_fb_t32 + 2), hl
|
|
||||||
wub_len_ready:
|
|
||||||
|
|
||||||
ld a, (_hdr_recs)
|
|
||||||
or a
|
|
||||||
jr z, wub_fast_test
|
|
||||||
ld a, #0x01
|
|
||||||
ld (_opl4_rom_loaded), a
|
|
||||||
|
|
||||||
; Patch address bit 21 in byte 0 of each of the first 128 headers.
|
|
||||||
wub_patch_test:
|
|
||||||
ld a, (_hdr_recs)
|
|
||||||
or a
|
|
||||||
jr z, wub_fast_test
|
|
||||||
ld hl, #_fb_t32
|
|
||||||
ld a, (hl)
|
|
||||||
inc hl
|
|
||||||
or a, (hl)
|
|
||||||
inc hl
|
|
||||||
or a, (hl)
|
|
||||||
inc hl
|
|
||||||
or a, (hl)
|
|
||||||
jp z, wub_finish
|
|
||||||
|
|
||||||
call _asm_read_byte
|
|
||||||
ld e, a
|
|
||||||
ld a, (_hdr_sub)
|
|
||||||
or a
|
|
||||||
jr nz, wub_patch_count
|
|
||||||
ld a, e
|
|
||||||
or a, #0x20
|
|
||||||
ld e, a
|
|
||||||
wub_patch_count:
|
|
||||||
ld a, (_hdr_sub)
|
|
||||||
inc a
|
|
||||||
cp a, #0x0C
|
|
||||||
jr nz, wub_store_sub
|
|
||||||
xor a
|
|
||||||
ld (_hdr_sub), a
|
|
||||||
ld hl, #_hdr_recs
|
|
||||||
dec (hl)
|
|
||||||
jr wub_patch_write
|
|
||||||
wub_store_sub:
|
|
||||||
ld (_hdr_sub), a
|
|
||||||
wub_patch_write:
|
|
||||||
ld a, e
|
|
||||||
call _wave_out_dat
|
|
||||||
|
|
||||||
; --fb_t32. The high word changes only when the low word wraps.
|
|
||||||
ld hl, (_fb_t32)
|
|
||||||
dec hl
|
|
||||||
ld (_fb_t32), hl
|
|
||||||
ld a, h
|
|
||||||
and a, l
|
|
||||||
inc a
|
|
||||||
jr nz, wub_patch_test
|
|
||||||
ld hl, (_fb_t32 + 2)
|
|
||||||
dec hl
|
|
||||||
ld (_fb_t32 + 2), hl
|
|
||||||
jr wub_patch_test
|
|
||||||
|
|
||||||
; Upload the rest in chunks that never cross a mapped 16K page.
|
|
||||||
wub_fast_test:
|
|
||||||
ld hl, #_fb_t32
|
|
||||||
ld a, (hl)
|
|
||||||
inc hl
|
|
||||||
or a, (hl)
|
|
||||||
inc hl
|
|
||||||
or a, (hl)
|
|
||||||
inc hl
|
|
||||||
or a, (hl)
|
|
||||||
jr z, wub_finish
|
|
||||||
|
|
||||||
; fb_w = 0 - fb_rp: number of bytes through FFFFh inclusive.
|
|
||||||
ld hl, (_fb_rp)
|
|
||||||
xor a
|
|
||||||
sub a, l
|
|
||||||
ld e, a
|
|
||||||
ld a, #0x00
|
|
||||||
sbc a, h
|
|
||||||
ld d, a
|
|
||||||
ld (_fb_w), de
|
|
||||||
|
|
||||||
; If the remaining 32-bit length is smaller, use its low word.
|
|
||||||
ld hl, (_fb_t32 + 2)
|
|
||||||
ld a, h
|
|
||||||
or a, l
|
|
||||||
jr nz, wub_fast_upload
|
|
||||||
ld hl, (_fb_t32)
|
|
||||||
or a
|
|
||||||
sbc hl, de
|
|
||||||
jr nc, wub_fast_upload
|
|
||||||
ld hl, (_fb_t32)
|
|
||||||
ld (_fb_w), hl
|
|
||||||
wub_fast_upload:
|
|
||||||
call _wave_upload_fast
|
|
||||||
|
|
||||||
; fb_t32 -= fb_w, propagating carry into the high word.
|
|
||||||
ld hl, (_fb_t32)
|
|
||||||
ld de, (_fb_w)
|
|
||||||
or a
|
|
||||||
sbc hl, de
|
|
||||||
ld (_fb_t32), hl
|
|
||||||
jr nc, wub_after_subtract
|
|
||||||
ld hl, (_fb_t32 + 2)
|
|
||||||
dec hl
|
|
||||||
ld (_fb_t32 + 2), hl
|
|
||||||
wub_after_subtract:
|
|
||||||
|
|
||||||
; wave_upload_fast leaves fb_rp at zero exactly on a page boundary.
|
|
||||||
ld hl, (_fb_rp)
|
|
||||||
ld a, h
|
|
||||||
or a, l
|
|
||||||
jr nz, wub_fast_test
|
|
||||||
ld hl, #_fb_cpg
|
|
||||||
inc (hl)
|
|
||||||
ld a, (hl)
|
|
||||||
call _wc_mngcvpl
|
|
||||||
ld hl, #0xC000
|
|
||||||
ld (_fb_rp), hl
|
|
||||||
jr wub_fast_test
|
|
||||||
|
|
||||||
wub_finish:
|
|
||||||
ld a, #0x02
|
|
||||||
call _wave_out_reg
|
|
||||||
ld a, #0x10 ; sound generation, WT base 200000h
|
|
||||||
call _wave_out_dat
|
|
||||||
ret
|
|
||||||
__endasm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─────────────────────────────────────────────────────────────────────
|
/* ─────────────────────────────────────────────────────────────────────
|
||||||
* asm_emit_skip_spec — запись CMD_SKIP_TICKS + spec_mask в cmd buffer
|
* asm_emit_skip_spec — запись CMD_SKIP_TICKS + spec_mask в cmd buffer
|
||||||
*
|
*
|
||||||
@@ -1920,17 +1623,12 @@ ym2_fm_passthru:;
|
|||||||
asm_read_2bytes();
|
asm_read_2bytes();
|
||||||
fb_t32 |= ((uint32_t)fb_b1 << 16) | ((uint32_t)fb_b2 << 24);
|
fb_t32 |= ((uint32_t)fb_b1 << 16) | ((uint32_t)fb_b2 << 24);
|
||||||
|
|
||||||
if (fb_reg == 0x84 || fb_reg == 0x87) {
|
/* сохранить → vgm_skip → восстановить */
|
||||||
/* YMF278B ROM/RAM Image — залить payload в SRAM карты */
|
vgm_read_ptr = (uint16_t)fb_rp;
|
||||||
wave_upload_block();
|
vgm_cur_page = fb_cpg;
|
||||||
} else {
|
vgm_skip(fb_t32);
|
||||||
/* сохранить → vgm_skip → восстановить */
|
fb_rp = (uint8_t *)vgm_read_ptr;
|
||||||
vgm_read_ptr = (uint16_t)fb_rp;
|
fb_cpg = vgm_cur_page;
|
||||||
vgm_cur_page = fb_cpg;
|
|
||||||
vgm_skip(fb_t32);
|
|
||||||
fb_rp = (uint8_t *)vgm_read_ptr;
|
|
||||||
fb_cpg = vgm_cur_page;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+139
-11
@@ -618,6 +618,99 @@ ivf_no:
|
|||||||
__endasm;
|
__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)
|
/* The unused tail of plugin-relative page 5 (not WC physical page #05)
|
||||||
* contains the one-shot large OPL4 loader at logical address 9800h.
|
* contains the one-shot large OPL4 loader at logical address 9800h.
|
||||||
* Offset 1800h is also above WC's 1000h..1447h screen scratch range. */
|
* 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
|
ld c, a ; final page count
|
||||||
; D/E already hold page/address high byte
|
; D/E already hold page/address high byte
|
||||||
|
|
||||||
|
ld a, (_s_load_tail) ; файл целиком поместился → хвоста нет
|
||||||
|
or a
|
||||||
|
jr z, ll4_success
|
||||||
|
|
||||||
ll4_tail_loop:
|
ll4_tail_loop:
|
||||||
ld a, d
|
ld a, d
|
||||||
cp a, #64
|
cp a, #64
|
||||||
@@ -681,6 +778,12 @@ ll4_tail_loop:
|
|||||||
or a
|
or a
|
||||||
jr nz, ll4_fail
|
jr nz, ll4_fail
|
||||||
|
|
||||||
|
push bc
|
||||||
|
push de
|
||||||
|
call _pb_tail_step ; страница хвоста дочитана — шаг бара
|
||||||
|
pop de
|
||||||
|
pop bc
|
||||||
|
|
||||||
inc d
|
inc d
|
||||||
ld e, #0xc0
|
ld e, #0xc0
|
||||||
jr ll4_tail_loop
|
jr ll4_tail_loop
|
||||||
@@ -714,7 +817,9 @@ uint8_t load_vgm(void)
|
|||||||
s_pages = (uint8_t)((fsize + 16383UL) >> 14);
|
s_pages = (uint8_t)((fsize + 16383UL) >> 14);
|
||||||
if (!s_pages)
|
if (!s_pages)
|
||||||
s_pages = 1;
|
s_pages = 1;
|
||||||
|
s_pb_tail_tot = 0;
|
||||||
if (s_pages > 64) {
|
if (s_pages > 64) {
|
||||||
|
s_pb_tail_tot = (uint8_t)(s_pages - 64); /* шкала бара для хвоста */
|
||||||
s_pages = 64;
|
s_pages = 64;
|
||||||
large_file = 1;
|
large_file = 1;
|
||||||
}
|
}
|
||||||
@@ -734,6 +839,7 @@ uint8_t load_vgm(void)
|
|||||||
/* WC_EOF нормален на последнем секторе */
|
/* WC_EOF нормален на последнем секторе */
|
||||||
if (rc && rc != WC_EOF)
|
if (rc && rc != WC_EOF)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wc_mngcvpl(0); /* страница 0 для проверки заголовка */
|
wc_mngcvpl(0); /* страница 0 для проверки заголовка */
|
||||||
@@ -804,12 +910,33 @@ uint8_t load_vgm(void)
|
|||||||
dbg_trace2(0xA5, s_pages, 0);
|
dbg_trace2(0xA5, s_pages, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (large_file) {
|
/* Холодный загрузчик (asm/opl4_loader.asm, страница 5) — единственный
|
||||||
s_pages = load_large_opl4();
|
* путь заливки сэмплов OPL4 в SRAM карты. Запускаем его всегда, когда
|
||||||
if (!s_pages)
|
* поток начинается с блока 0x67, независимо от размера файла: он же
|
||||||
return 0;
|
* вырезает залитые блоки из потока и правит смещения в заголовке.
|
||||||
|
* 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;
|
return s_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1202,14 +1329,15 @@ void main(void)
|
|||||||
s_vgz_compressed_pages = 0;
|
s_vgz_compressed_pages = 0;
|
||||||
draw_pre_load_info();
|
draw_pre_load_info();
|
||||||
|
|
||||||
/* Показать статус ДО начала загрузки — "Unpacking..." для .vgz
|
/* Показать статус ДО начала загрузки: "Unpacking.." для .vgz,
|
||||||
* (распаковка), "Loading..." для файлов >= 1 МБ (синхронная заливка
|
* "Loading.." для остальных. Мгновенной загрузки не бывает ни для
|
||||||
* сэмплов OPL4 в SRAM карты идёт байт за байтом с busy-wait и
|
* одного размера — чтение с SD плюс (для OPL4) побайтовая заливка
|
||||||
* занимает секунды; без надписи выглядит как зависание). Для .vgz
|
* сэмплов в SRAM карты с busy-wait. Здесь же настраиваем прогресс-
|
||||||
* это последний WC API вызов перед inflate — дальше load_vgm
|
* бар: для .vgz его рисует inflate.asm, иначе — pb_step() ниже.
|
||||||
* работает только портами. */
|
* Для .vgz это последний WC API вызов перед inflate — дальше
|
||||||
|
* load_vgm работает только портами. */
|
||||||
s_is_vgz = is_vgz_filename();
|
s_is_vgz = is_vgz_filename();
|
||||||
if (s_is_vgz || ((const uint8_t *)&wc_file_size)[2] >= 0x10) {
|
{
|
||||||
buf_clear(work_buf);
|
buf_clear(work_buf);
|
||||||
buf_append_str(work_buf, s_is_vgz ? "Unpacking.." : "Loading..");
|
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));
|
print_line(&s_wnd, ROW_VGM_START, work_buf, WC_COLOR(WC_YELLOW, WC_BLACK));
|
||||||
|
|||||||
Reference in New Issue
Block a user