@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