Add OPL4 playback and analyzer support
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Build multiple ISR frequency / command budget variants for A/B testing.
|
||||
Each variant produces a separate tsconf_*.img disk image.
|
||||
|
||||
.DESCRIPTION
|
||||
Generates inc\variant_cfg.h for each variant, runs build.bat, copies
|
||||
the output image. Restores the original variant_cfg.h afterward.
|
||||
|
||||
NO source files are regex-patched — only variant_cfg.h is overwritten.
|
||||
|
||||
.NOTES
|
||||
C compilation is SLOW (~60 sec per variant). Do NOT interrupt (Ctrl-C).
|
||||
#>
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = Split-Path -Parent $MyInvocation.MyCommand.Path # src_sdcc
|
||||
$projRoot = Split-Path -Parent $root # project root
|
||||
$cfgFile = "$root\inc\variant_cfg.h"
|
||||
|
||||
# ── Frequency tiers ──────────────────────────────────────────────────
|
||||
# ISR_FREQ = 3 500 000 / Step; Entries = 71 680 / Step; TPF = Entries
|
||||
# Shift = log2(44100 / Freq) rounded down
|
||||
$freqTiers = @{
|
||||
'2734' = @{ Tag=''; Freq=2734; Step=1280; Entries=56; Shift=4; Mask='0x0F'; TPF=56; Budgets=@(8,16) }
|
||||
'1367' = @{ Tag='hf'; Freq=1367; Step=2560; Entries=28; Shift=5; Mask='0x1F'; TPF=28; Budgets=@(8,16,32) }
|
||||
'683' = @{ Tag='qf'; Freq=683; Step=5120; Entries=14; Shift=6; Mask='0x3F'; TPF=14; Budgets=@(16,32,64) }
|
||||
}
|
||||
|
||||
# ── Generate variants: 2+3+3 = 8 base × 2 NS = 16 total ─────────────
|
||||
$baseVariants = @()
|
||||
foreach ($ft in $freqTiers.Values | Sort-Object Freq -Descending) {
|
||||
foreach ($b in $ft.Budgets) {
|
||||
$suffix = if ($ft.Tag) { "_$($ft.Tag)" } else { '' }
|
||||
$name = "b${b}${suffix}"
|
||||
$baseVariants += @{
|
||||
Name = $name
|
||||
Budget = $b
|
||||
Entries = $ft.Entries
|
||||
Step = $ft.Step
|
||||
Freq = $ft.Freq
|
||||
Shift = $ft.Shift
|
||||
Mask = $ft.Mask
|
||||
TPF = $ft.TPF
|
||||
DataLoc = '0xB600'
|
||||
NS = $false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Auto-generate _ns (no short waits) clones
|
||||
$nsVariants = foreach ($bv in $baseVariants) {
|
||||
$nv = $bv.Clone()
|
||||
$nv.Name = $bv.Name + '_ns'
|
||||
$nv.NS = $true
|
||||
$nv
|
||||
}
|
||||
$variants = $baseVariants + $nsVariants
|
||||
|
||||
# ── Save original variant_cfg.h ─────────────────────────────────────
|
||||
$cfgBackup = Get-Content $cfgFile -Raw
|
||||
|
||||
function Restore-Cfg {
|
||||
Set-Content $script:cfgFile -Value $script:cfgBackup -NoNewline
|
||||
}
|
||||
|
||||
# ── Helper: generate variant_cfg.h ──────────────────────────────────
|
||||
function Write-VariantCfg($v) {
|
||||
$nsLine = if ($v.NS) { "#define VGM_NO_SHORT_WAITS" } else { "/* #define VGM_NO_SHORT_WAITS */" }
|
||||
$content = @"
|
||||
/* variant_cfg.h -- AUTO-GENERATED by build_variants.ps1
|
||||
* Variant: $($v.Name) Freq=$($v.Freq)Hz Budget=$($v.Budget) NS=$($v.NS)
|
||||
*/
|
||||
#ifndef VARIANT_CFG_H
|
||||
#define VARIANT_CFG_H
|
||||
|
||||
#define ISR_FREQ $($v.Freq)
|
||||
#define ISR_TICKS_PER_FRAME $($v.TPF)
|
||||
#define VGM_SAMPLE_SHIFT $($v.Shift)
|
||||
#define VGM_SAMPLE_MASK $($v.Mask)
|
||||
#define VGM_FILL_CMD_BUDGET $($v.Budget)
|
||||
|
||||
#define VARIANT_POS_ENTRIES $($v.Entries)
|
||||
#define VARIANT_POS_STEP $($v.Step)
|
||||
#define VARIANT_DATA_LOC $($v.DataLoc)
|
||||
|
||||
$nsLine
|
||||
|
||||
#endif /* VARIANT_CFG_H */
|
||||
"@
|
||||
Set-Content $script:cfgFile -Value $content -NoNewline
|
||||
}
|
||||
|
||||
# ── Output directory ─────────────────────────────────────────────────
|
||||
$outDir = "$projRoot\variants"
|
||||
if (-not (Test-Path $outDir)) { New-Item -ItemType Directory -Path $outDir | Out-Null }
|
||||
|
||||
# ── Build loop ──────────────────────────────────────────────────────
|
||||
$total = $variants.Count
|
||||
$idx = 0
|
||||
$results = @()
|
||||
|
||||
foreach ($v in $variants) {
|
||||
$idx++
|
||||
$name = $v.Name
|
||||
Write-Host "`n========== [$idx/$total] Building $name ==========" -ForegroundColor Cyan
|
||||
Write-Host " Budget=$($v.Budget) Freq=$($v.Freq)Hz Entries=$($v.Entries) Step=$($v.Step) Shift=$($v.Shift) TPF=$($v.TPF) NS=$($v.NS)"
|
||||
|
||||
# --- Generate variant_cfg.h ---
|
||||
Write-VariantCfg $v
|
||||
|
||||
# --- Clean .rel files to force recompile ---
|
||||
Remove-Item "$root\build\*.rel" -ErrorAction SilentlyContinue
|
||||
|
||||
# --- Run build ---
|
||||
Write-Host " Building... (this takes ~60 sec)" -ForegroundColor Yellow
|
||||
$buildOut = cmd /c "cd /d $root && build.bat 2>&1"
|
||||
$buildOk = $buildOut | Where-Object { $_ -match 'BUILD OK' }
|
||||
$buildFail = $buildOut | Where-Object { $_ -match 'FAIL|ERROR|overflow' }
|
||||
|
||||
if ($buildFail -or -not $buildOk) {
|
||||
Write-Host " *** BUILD FAILED for $name ***" -ForegroundColor Red
|
||||
$buildOut | Where-Object { $_ -match 'FAIL|error|warning|_CODE|_DATA|Last byte|overflow|variant_cfg' } |
|
||||
ForEach-Object { Write-Host " $_" }
|
||||
$results += [pscustomobject]@{ Name=$name; Status='FAIL'; Code=0; Free=0 }
|
||||
continue
|
||||
}
|
||||
|
||||
# --- Extract sizes from output ---
|
||||
$codeLine = $buildOut | Where-Object { $_ -match '_CODE' } | Select-Object -First 1
|
||||
$freeLine = $buildOut | Where-Object { $_ -match 'Free before' } | Select-Object -First 1
|
||||
$codeSize = if ($codeLine -match '(\d+)\s+bytes') { [int]$Matches[1] } else { 0 }
|
||||
$freeSize = if ($freeLine -match 'Free before C000:\s*(\d+)') { [int]$Matches[1] } else { 0 }
|
||||
|
||||
# --- Show map ---
|
||||
$buildOut | Where-Object { $_ -match 'variant_cfg:|Section|_CODE|_DATA|_GSINIT|_HOME|_INITIAL|Last byte|Code:|Written.*WMF' } |
|
||||
ForEach-Object { Write-Host " $_" }
|
||||
|
||||
# --- Copy output image ---
|
||||
$srcImg = "$projRoot\tsconf.img"
|
||||
$dstImg = "$outDir\tsconf_$name.img"
|
||||
if (Test-Path $srcImg) {
|
||||
Copy-Item $srcImg $dstImg -Force
|
||||
Write-Host " -> $dstImg" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " WARNING: tsconf.img not found" -ForegroundColor Yellow
|
||||
}
|
||||
# Also copy WMF
|
||||
$srcWmf = "$projRoot\DiskRef\WC\VGMPLAY.WMF"
|
||||
$dstWmf = "$outDir\VGMPLAY_$name.WMF"
|
||||
if (Test-Path $srcWmf) {
|
||||
Copy-Item $srcWmf $dstWmf -Force
|
||||
}
|
||||
|
||||
$results += [pscustomobject]@{ Name=$name; Status='OK'; Code=$codeSize; Free=$freeSize }
|
||||
}
|
||||
|
||||
# ── Restore original variant_cfg.h ──────────────────────────────────
|
||||
Write-Host "`n========== Restoring original variant_cfg.h ==========" -ForegroundColor Cyan
|
||||
Restore-Cfg
|
||||
# Rebuild baseline to leave workspace clean
|
||||
Remove-Item "$root\build\*.rel" -ErrorAction SilentlyContinue
|
||||
Write-Host " Rebuilding baseline..." -ForegroundColor Yellow
|
||||
$null = cmd /c "cd /d $root && build.bat 2>&1"
|
||||
Write-Host " Done." -ForegroundColor Green
|
||||
|
||||
# ── Summary ──────────────────────────────────────────────────────────
|
||||
Write-Host "`n========== VARIANT SUMMARY ==========" -ForegroundColor Cyan
|
||||
$fmt = "{0,-18} {1,6} {2,6} {3,6} {4,3} {5,5} {6,5}"
|
||||
Write-Host ($fmt -f 'Name','Budget','Freq','Code','NS','Free','St')
|
||||
Write-Host ($fmt -f '----','------','----','----','--','----','--')
|
||||
foreach ($r in $results) {
|
||||
$v = $variants | Where-Object { $_.Name -eq $r.Name }
|
||||
$nsTag = if ($v.NS) { 'yes' } else { ' - ' }
|
||||
$color = if ($r.Status -eq 'OK') { 'Green' } else { 'Red' }
|
||||
Write-Host ($fmt -f $r.Name, $v.Budget, $v.Freq, $r.Code, $nsTag, $r.Free, $r.Status) -ForegroundColor $color
|
||||
}
|
||||
Write-Host "`nImages in: $outDir"
|
||||
|
||||
# ── Generate README.txt ──────────────────────────────────────────────
|
||||
$readme = @"
|
||||
Variants of VGM player for A/B testing
|
||||
=======================================
|
||||
|
||||
Parameters stored in inc\variant_cfg.h (single config file).
|
||||
build_variants.ps1 regenerates variant_cfg.h for each variant.
|
||||
|
||||
Frequency tiers:
|
||||
qf - quarter freq (ISR 683 Hz, step 5120, 14 ticks/frame)
|
||||
(none) - base freq (ISR 2734 Hz, step 1280, 56 ticks/frame)
|
||||
hf - half freq (ISR 1367 Hz, step 2560, 28 ticks/frame)
|
||||
|
||||
Other tags:
|
||||
b<N> - command budget (max commands between forced pauses)
|
||||
ns - no short waits (0x70-0x7F pauses skipped)
|
||||
|
||||
"@
|
||||
|
||||
$readme += "{0,-30} {1,6} {2,8} {3,3} {4,6} {5,5} {6}`n" -f 'Image','Budget','Freq','NS','Code','Free','Status'
|
||||
$readme += "{0,-30} {1,6} {2,8} {3,3} {4,6} {5,5} {6}`n" -f '-----','------','----','--','----','----','------'
|
||||
foreach ($r in $results) {
|
||||
$v = $variants | Where-Object { $_.Name -eq $r.Name }
|
||||
$nsTag = if ($v.NS) { 'yes' } else { ' - ' }
|
||||
$freq = "$($v.Freq)Hz"
|
||||
$readme += "{0,-30} {1,6} {2,8} {3,3} {4,6} {5,5} {6}`n" -f "tsconf_$($r.Name).img", $v.Budget, $freq, $nsTag, $r.Code, $r.Free, $r.Status
|
||||
}
|
||||
|
||||
$readme += @"
|
||||
|
||||
What to test
|
||||
------------
|
||||
1. Higher budget helps (b32/b48/b64 vs b8/b16)
|
||||
-> Increase VGM_FILL_CMD_BUDGET.
|
||||
|
||||
2. Lower freq helps (hf or qf better than base)
|
||||
-> ISR overhead is the bottleneck, reduce frequency.
|
||||
|
||||
3. Higher freq helps (base better than hf/qf)
|
||||
-> More granular timing needed, keep higher ISR.
|
||||
|
||||
4. _ns variants better -> short waits 0x70-0x7F are the problem.
|
||||
|
||||
5. Nothing helps -> something else (OPL3 write delay, VGM parsing, etc.)
|
||||
"@
|
||||
|
||||
Set-Content "$outDir\README.txt" -Value $readme -NoNewline -Encoding UTF8
|
||||
Write-Host "`nREADME.txt written to $outDir" -ForegroundColor Green
|
||||
|
||||
Write-Host "`nLegend:" -ForegroundColor DarkGray
|
||||
Write-Host " qf = quarter freq (683 Hz)" -ForegroundColor DarkGray
|
||||
Write-Host " hf = half freq (1367 Hz)" -ForegroundColor DarkGray
|
||||
Write-Host " (no suffix) = base freq (2734 Hz)" -ForegroundColor DarkGray
|
||||
Write-Host " bN = budget N commands per ISR tick" -ForegroundColor DarkGray
|
||||
Write-Host " ns = no short waits (0x70-0x7F skipped)" -ForegroundColor DarkGray
|
||||
Reference in New Issue
Block a user