- One-shot cold loader (asm/opl4_loader.asm, overlaid into plugin page 5) uploads embedded PCM sample blocks into ZXM-MoonSound SRAM and compacts the VGM stream in place, letting files over the normal 64-page megabuffer budget play back through the existing pipeline. - instant_abort() was filling only one of the two ISR command buffers with the shutdown chain; the chain (SILENCE_OPL + WAVE_OFF/TL + CMD_ISR_DONE) doesn't fit in one buffer, so after the first CMD_END_BUF the ISR swapped into stale data and never reached CMD_ISR_DONE, hanging at the end of long tracks instead of advancing to the next one. Now fills both buffers while frozen and syncs update_buffer()'s own ready-tracking state. - Switch to 14MHz before the SRAM upload (previously ran at whatever speed WC's file I/O left active) and show "Loading..." for .vgz and files >= 1MB, since the busy-waited upload takes several seconds. - Confirmed on real hardware: long OPL4 tracks (previously stuck looping at the end) now finish and advance normally, ESC exits cleanly.
183 lines
8.1 KiB
Batchfile
183 lines
8.1 KiB
Batchfile
@echo off
|
||
chcp 65001 >nul
|
||
REM ===========================================================================
|
||
REM build.bat — Сборка VGM Player Plugin (SDCC/Z80)
|
||
REM
|
||
REM Инструменты:
|
||
REM sdcc — компилятор C (sdcccall(1), mz80, без frame pointer)
|
||
REM sdas — ассемблер SDCC (ASM файлы)
|
||
REM sdld / sdcc --link-cmd-file — линковщик
|
||
REM node — JS-скрипты (gen_pos_table, ihx2wmf)
|
||
REM
|
||
REM Структура вывода: build/ (временные .rel) → vgmplay.wmf
|
||
REM ===========================================================================
|
||
|
||
setlocal
|
||
|
||
cd /d "%~dp0"
|
||
|
||
REM --- Папка для временных файлов ---
|
||
if not exist build mkdir build
|
||
|
||
REM --- Флаги SDCC ---
|
||
REM -mz80 : целевая архитектура Z80
|
||
REM --sdcccall 1 : соглашение вызова sdcccall(1) (регистровая передача)
|
||
REM --no-std-crt0 : не линковать стандартный crt0 (наш в asm/crt0.s)
|
||
REM --opt-code-size : оптимизация по размеру (важно для 8-бит)
|
||
REM --no-peep-asm : не трогать __naked asm-блоки
|
||
set CFLAGS=-mz80 --sdcccall 1 --no-std-crt0 --opt-code-size -I inc --disable-warning 85
|
||
|
||
REM --- Флаги ассемблера (sdas) ---
|
||
set ASFLAGS=-plosff
|
||
|
||
REM --- Читаем параметры варианта из variant_cfg.h ---
|
||
for /f "tokens=3" %%a in ('findstr /C:"#define VARIANT_POS_ENTRIES" inc\variant_cfg.h') do set POS_ENTRIES=%%a
|
||
for /f "tokens=3" %%a in ('findstr /C:"#define VARIANT_POS_STEP" inc\variant_cfg.h') do set POS_STEP=%%a
|
||
for /f "tokens=3" %%a in ('findstr /C:"#define VARIANT_DATA_LOC" inc\variant_cfg.h') do set DATA_LOC=%%a
|
||
echo variant_cfg: entries=%POS_ENTRIES% step=%POS_STEP% data-loc=%DATA_LOC%
|
||
|
||
echo [1/8] Генерация pos_table.s...
|
||
node scripts\gen_pos_table.js --entries %POS_ENTRIES% --step %POS_STEP%
|
||
if errorlevel 1 ( echo FAIL gen_pos_table && goto :err )
|
||
|
||
echo [2/8] Генерация freq_tables.bin...
|
||
node scripts\gen_freq_tables.js --page-base 1 --binary build\freq_tables.bin --cheader inc\freq_lut_map.h
|
||
if errorlevel 1 ( echo FAIL gen_freq_tables && goto :err )
|
||
|
||
echo [3/9] Сборка inflate.asm (sjasmplus)...
|
||
..\tools\sjasm\sjasmplus.exe asm\inflate.asm >nul 2>&1
|
||
if errorlevel 1 ( echo FAIL inflate.asm && goto :err )
|
||
REM inflate.asm имеет SAVEBIN "build/inflate.bin" внутри
|
||
REM Паддинг inflate.bin до 16KB (чтобы cmdblocks.bin начинался на границе страницы)
|
||
powershell -NoProfile -Command "$f=[IO.File]::ReadAllBytes('build\inflate.bin'); if($f.Length -lt 16384){$pad=New-Object byte[] (16384-$f.Length); [IO.File]::WriteAllBytes('build\inflate.bin',$f+$pad); Write-Host (' inflate.bin padded: '+$f.Length+' -> 16384')}"
|
||
if errorlevel 1 ( echo FAIL pad inflate && goto :err )
|
||
|
||
echo [3a/9] Сборка cold OPL4 loader...
|
||
..\tools\sjasm\sjasmplus.exe asm\opl4_loader.asm >nul 2>&1
|
||
if errorlevel 1 ( echo FAIL opl4_loader.asm && goto :err )
|
||
|
||
echo [3b/9] Сборка cmdblocks.asm (sjasmplus)...
|
||
..\tools\sjasm\sjasmplus.exe asm\cmdblocks.asm >nul 2>&1
|
||
if errorlevel 1 ( echo FAIL cmdblocks.asm && goto :err )
|
||
node scripts\overlay_bin.js build\cmdblocks.bin build\opl4_loader.bin 0x1800
|
||
if errorlevel 1 ( echo FAIL overlay OPL4 loader && goto :err )
|
||
REM cmdblocks.asm имеет SAVEBIN "build/cmdblocks.bin" внутри
|
||
|
||
echo [4/9] Компиляция C файлов...
|
||
sdcc %CFLAGS% -c main.c -o build\main.rel >nul
|
||
if errorlevel 1 ( echo FAIL main.c && goto :err )
|
||
|
||
sdcc %CFLAGS% -c lib\vgm.c -o build\vgm.rel >nul
|
||
if errorlevel 1 ( echo FAIL vgm.c && goto :err )
|
||
|
||
sdcc %CFLAGS% -c lib\keys.c -o build\keys.rel >nul
|
||
if errorlevel 1 ( echo FAIL keys.c && goto :err )
|
||
|
||
REM txtlib is now hand-written assembly (asm\txtlib.s), assembled below
|
||
|
||
echo [5/9] Сборка ASM файлов...
|
||
sdasz80 %ASFLAGS% build\crt0.rel asm\crt0.s >nul
|
||
if errorlevel 1 ( echo FAIL crt0.s && goto :err )
|
||
|
||
sdasz80 %ASFLAGS% build\isr.rel asm\isr.s >nul
|
||
if errorlevel 1 ( echo FAIL isr.s && goto :err )
|
||
|
||
sdasz80 %ASFLAGS% build\pos_table.rel asm\pos_table.s >nul
|
||
if errorlevel 1 ( echo FAIL pos_table.s && goto :err )
|
||
|
||
call lib\wc_api\build_lib.bat >nul
|
||
if errorlevel 1 ( echo FAIL wc_api.lib && goto :err )
|
||
|
||
sdasz80 %ASFLAGS% build\txtlib.rel asm\txtlib.s >nul
|
||
if errorlevel 1 ( echo FAIL txtlib.s && goto :err )
|
||
|
||
sdasz80 %ASFLAGS% build\inflate_call.rel asm\inflate_call.s >nul
|
||
if errorlevel 1 ( echo FAIL inflate_call.s && goto :err )
|
||
|
||
sdasz80 %ASFLAGS% build\spectrum.rel asm\spectrum.s >nul
|
||
if errorlevel 1 ( echo FAIL spectrum.s && goto :err )
|
||
|
||
sdasz80 %ASFLAGS% build\cold_return.rel asm\cold_return.s >nul
|
||
if errorlevel 1 ( echo FAIL cold_return.s && goto :err )
|
||
|
||
echo [6/9] Линковка...
|
||
REM Порядок важен: crt0 первым (entry point), затем модули
|
||
REM Layout: CODE #8000–#B8CF, DATA #B8D0–#BFFF
|
||
REM Все секции (DATA + GSINIT + HOME + INITIALIZER) должны
|
||
REM уместиться до #BFFF (Win2). Если CODE вырастет →
|
||
REM понизить --data-loc или оптимизировать код.
|
||
sdcc -mz80 --no-std-crt0 --out-fmt-ihx --code-loc 0x8000 --data-loc %DATA_LOC% ^
|
||
build\crt0.rel ^
|
||
build\main.rel ^
|
||
build\vgm.rel ^
|
||
build\keys.rel ^
|
||
build\isr.rel ^
|
||
build\pos_table.rel ^
|
||
build\wc_api.lib ^
|
||
build\txtlib.rel ^
|
||
build\inflate_call.rel ^
|
||
build\spectrum.rel ^
|
||
build\cold_return.rel ^
|
||
-o build\vgmplay.ihx >nul
|
||
if errorlevel 1 ( echo FAIL link && goto :err )
|
||
|
||
REM --- Вывод карты памяти секций из map-файла ---
|
||
powershell -NoProfile -Command ^
|
||
"$m=Get-Content build\vgmplay.map -Raw;" ^
|
||
"function gs($p){if($m -match '([0-9a-f]{8})\s+'+$p){return $Matches[1]}return '00000000'};" ^
|
||
"$secs=@('CODE','DATA','GSINIT','GSFINAL','INITIALIZED','HOME','INITIALIZER');" ^
|
||
"Write-Host '';" ^
|
||
"Write-Host ' Section Start End Size';" ^
|
||
"Write-Host ' -------------- -------- -------- ----------';" ^
|
||
"$lastEnd=0;$codeEnd=0;$dataStart=0;" ^
|
||
"foreach($s in $secs){" ^
|
||
" $st=[Convert]::ToInt32((gs ('s__'+$s)),16);" ^
|
||
" $ln=[Convert]::ToInt32((gs ('l__'+$s)),16);" ^
|
||
" if($ln -eq 0){continue};" ^
|
||
" $en=$st+$ln-1;" ^
|
||
" if($en -gt $lastEnd){$lastEnd=$en};" ^
|
||
" if($s -eq 'CODE'){$codeEnd=$en};" ^
|
||
" if($s -eq 'DATA'){$dataStart=$st};" ^
|
||
" Write-Host (' _'+$s.PadRight(14)+' 0x'+$st.ToString('X4')+' 0x'+$en.ToString('X4')+' '+$ln.ToString().PadLeft(5)+' bytes')" ^
|
||
"};" ^
|
||
"$free=0xBFFF-$lastEnd;" ^
|
||
"Write-Host ' -------------- -------- -------- ----------';" ^
|
||
"Write-Host (' Last byte: 0x'+$lastEnd.ToString('X4')+' Free before C000: '+$free+' bytes');" ^
|
||
"if($codeEnd -ge $dataStart -and $dataStart -gt 0){Write-Host (' *** ERROR: _CODE (end 0x'+$codeEnd.ToString('X4')+') overlaps _DATA (start 0x'+$dataStart.ToString('X4')+')! ***') -ForegroundColor Red; exit 1};" ^
|
||
"if($lastEnd -ge 0xC000){Write-Host ' *** ERROR: sections overflow past 0xBFFF! ***' -ForegroundColor Red; exit 1}"
|
||
if errorlevel 1 goto :err
|
||
|
||
echo [7/9] Генерация WMF (multi-page)...
|
||
REM Склеить freq_tables.bin + inflate page + cmdblocks.bin
|
||
copy /b build\freq_tables.bin+build\inflate.bin+build\cmdblocks.bin build\extra_combined.bin >nul
|
||
if errorlevel 1 ( echo FAIL combine extra && goto :err )
|
||
node scripts\ihx2wmf.js build\vgmplay.ihx ..\DiskRef\WC\VGMPLAY.WMF --extra build\extra_combined.bin
|
||
if errorlevel 1 ( echo FAIL ihx2wmf && goto :err )
|
||
copy /Y ..\DiskRef\WC\VGMPLAY.WMF ..\VGMPLAY.WMF >nul
|
||
|
||
echo [8/9] Проверка размеров binary...
|
||
powershell -NoProfile -Command "Get-ChildItem build\*.bin | Select-Object Name, Length | Format-Table -AutoSize"
|
||
|
||
echo [9/9] Сборка образа диска...
|
||
if not exist "..\tools\robimg.exe" (
|
||
echo SKIP: tools\robimg.exe не найден
|
||
goto :ok
|
||
)
|
||
del /Q ..\tsconf.img 2>nul
|
||
..\tools\robimg.exe -p="..\tsconf.img" -s=280000 -C="..\DiskRef" >nul 2>&1
|
||
if errorlevel 1 ( echo FAIL robimg && goto :err )
|
||
echo tsconf.img готов
|
||
|
||
:ok
|
||
echo.
|
||
echo === BUILD OK ===
|
||
goto :end
|
||
|
||
:err
|
||
echo.
|
||
echo === BUILD FAILED ===
|
||
exit /b 1
|
||
|
||
:end
|
||
endlocal
|