better debug support

This commit is contained in:
ed
2026-07-11 22:44:32 -04:00
parent 8b0fb1d4e4
commit aca6e30e20
8 changed files with 261 additions and 174 deletions
+1
View File
@@ -24,6 +24,7 @@
"autorun": [
"monitor reset shellhalt",
"load hello_psyq.elf",
"source scripts/gdb/gdb_tape_atoms.gdb",
"tbreak main",
"continue"
]
+30
View File
@@ -0,0 +1,30 @@
-- gte_debug.lua — defensive version + prints error context.
local ok, err = pcall(function()
print("[debug] PCSX exists:", PCSX ~= nil)
print("[debug] PCSX.WebServer exists:", PCSX and PCSX.WebServer ~= nil)
print("[debug] PCSX.WebServer.Handlers exists:", PCSX and PCSX.WebServer and PCSX.WebServer.Handlers ~= nil)
if not PCSX.WebServer then
print("[debug] creating PCSX.WebServer...")
PCSX.WebServer = {}
end
if not PCSX.WebServer.Handlers then
print("[debug] creating PCSX.WebServer.Handlers...")
PCSX.WebServer.Handlers = {}
end
print("[debug] type of Handlers:", type(PCSX.WebServer.Handlers))
PCSX.WebServer.Handlers.gte = function(req)
local r = PCSX.getRegisters()
local out = { "pc=0x" .. string.format("%x", r.pc) }
for i = 0, 31 do
out[#out + 1] = string.format("D[%d]=0x%08x C[%d]=0x%08x",
i, r.CP2D.r[i], i, r.CP2C.r[i])
end
return table.concat(out, "\n")
end
print("[debug] handler registered")
end)
if not ok then
print("[debug] ERROR: " .. tostring(err))
end
+13 -2
View File
@@ -321,11 +321,12 @@ function ps1-meta { param(
[Parameter(Mandatory=$true)][string[]]$sources,
[Parameter(Mandatory=$true)][string]$metadata,
[string]$out_root = (join-path $path_build 'gen'),
[string[]]$passes = @('--all')
[string[]]$passes = @('--all'),
[string[]]$extra_args = @()
)
$script = join-path $path_scripts 'ps1_meta.lua'
write-host "ps1-meta $($sources.Count) source(s), passes=$($passes -join ',')" ` -ForegroundColor Magenta
$arg_list = @($passes) + @('--metadata', $metadata) + @('--out-root', $out_root)
$arg_list = @($passes) + @('--metadata', $metadata) + @('--out-root', $out_root) + @($extra_args)
foreach ($s in $sources) { $arg_list += @('--source', $s) }
& luajit $script @arg_list
if ($LASTEXITCODE -ne 0) {
@@ -383,6 +384,16 @@ function build-gte_hello {
)
link-modules $link_modules $elf $link_args
make-binary $elf $exe
# Post-link: emit ONLY build/gen/gdb_tape_atoms_runtime.gdb. The per-source
# *.atoms.sourcemap.txt was already generated by the pre-link --all call,
# so we skip --atoms-source-map here to avoid re-doing the work. The
# gdb-runtime emission requires --elf (for nm-based address lookup) so it
# MUST happen post-link. ON by default per user pref 2026-07-11.
ps1-meta -sources $atom_sources -metadata $path_atom_metadata `
-out_root (join-path $path_build 'gen') `
-passes @('--gdb-runtime') `
-extra_args @('--elf', $elf)
}
build-gte_hello
-95
View File
@@ -1,95 +0,0 @@
# scripts/launch_debug_session.ps1
#
# Wrapper around pcsx-redux.exe + gdb-multiarch that auto-launches the
# gdb_tape_atoms.gdb helper and (optionally) hot-reloads the .ps-exe.
#
# Generated by track gdb_tape_atom_debugging_20260711 — see
# C:\projects\Pikuma\ps1-ai\docs\gdb_tape_atom_debugging.md for the manual.
#
# usage:
# .\launch_debug_session.ps1 # bare gdb attach (assumes pcsx-redux is up)
# .\launch_debug_session.ps1 -AutoLoadAtoms # also source gdb_tape_atoms.gdb on startup
# .\launch_debug_session.ps1 -AutoResetEmu # hot-reload the .ps-exe before attaching
# .\launch_debug_session.ps1 -AutoStartEmu # launch pcsx-redux.exe if not running
#
# All three flags can be combined: -AutoStartEmu -AutoResetEmu -AutoLoadAtoms
[CmdletBinding()]
param(
[switch]$AutoLoadAtoms,
[switch]$AutoResetEmu,
[switch]$AutoStartEmu,
[string]$ExePath = (Join-Path $PSScriptRoot '..\build\hello_gte.ps-exe'),
[string]$ElfPath = (Join-Path $PSScriptRoot '..\build\hello_gte.elf')
)
$ErrorActionPreference = 'Stop'
# ── Pre-checks (E10: pcsx-redux on :3333, E11: gdb-multiarch in PATH) ──
function Test-Prerequisites {
# E11: gdb-multiarch must be in PATH.
if (-not (Get-Command gdb-multiarch -ErrorAction SilentlyContinue)) {
Write-Error "gdb-multiarch not found in PATH. Install via scoop or .\update_deps.ps1." -ErrorAction Stop
exit 1
}
# E10: pcsx-redux must be reachable on :3333 (or we auto-start).
$tcp = New-Object System.Net.Sockets.TcpClient
try {
$async = $tcp.BeginConnect('localhost', 3333, $null, $null)
$connected = $async.AsyncWaitHandle.WaitOne(2000, $false) -and -not $async.IsFaulted
} catch {
$connected = $false
}
$tcp.Close()
if (-not $connected) {
if ($AutoStartEmu) {
Write-Host "pcsx-redux not running; auto-starting..." -ForegroundColor Cyan
$pcsxExe = (Join-Path $PSScriptRoot '..\toolchain\pcsx-redux\vsprojects\x64\Release\pcsx-redux.exe')
if (-not (Test-Path $pcsxExe)) {
Write-Error "pcsx-redux.exe not found at $pcsxExe. Build it first, or pass -ExePath + start pcsx-redux manually." -ErrorAction Stop
exit 1
}
Start-Process -FilePath $pcsxExe -PassThru | Out-Null
Start-Sleep -Seconds 3
} else {
Write-Error "Cannot connect to pcsx-redux at localhost:3333. Start pcsx-redux first (or pass -AutoStartEmu)." -ErrorAction Stop
exit 1
}
}
}
# ── Optional: hot-reload .ps-exe via pcsx-redux's web server (port 8080) ──
function Invoke-HotReload {
$absolutePath = [System.IO.Path]::GetFullPath($ExePath)
$uri = 'http://localhost:8080/api/v1/load-exec'
$body = @{ filename = $absolutePath } | ConvertTo-Json
try {
Invoke-RestMethod -Uri $uri -Method Post -Body $body -ContentType 'application/json' | Out-Null
Write-Host "Hot-reloaded $absolutePath into pcsx-redux." -ForegroundColor Green
} catch {
Write-Warning "Could not hot-reload via pcsx-redux web server (port 8080): $_"
}
}
# ── Main ──
Test-Prerequisites
if ($AutoResetEmu) { Invoke-HotReload }
$gdbScript = Join-Path $PSScriptRoot 'gdb\gdb_tape_atoms.gdb'
$gdbArgs = @(
'-q'
'-ex', "file $ElfPath"
'-ex', 'target remote localhost:3333'
)
if ($AutoLoadAtoms) {
$gdbArgs += @('-ex', "source $gdbScript")
}
Write-Host "Launching gdb-multiarch (script: $gdbScript, elf: $ElfPath)..." -ForegroundColor Cyan
& gdb-multiarch @gdbArgs
+94
View File
@@ -0,0 +1,94 @@
# scripts/launch_pcsx_debug.ps1
#
# One-shot launcher for debug sessions: starts pcsx-redux with the .ps-exe
# loaded, the gdb stub enabled, AND the pcsx_debug_helper Lua plugin loaded
# so external CLI tools (gdb's `shell` command, etc.)
# can read GTE state via http://localhost:8080/api/v1/lua/gte
# (the gdb stub doesn't expose COP2 at all).
#
# usage:
# .\scripts\launch_pcsx_debug.ps1
# .\scripts\launch_pcsx_debug.ps1 -ExePath build\hello_gte.ps-exe
# .\scripts\launch_pcsx_debug.ps1 -HelperZip scripts\pcsx_debug_helper.zip
#
# After launch:
# - gdb: target remote localhost:3333
# - web: curl http://localhost:8080/api/v1/lua/gte
#
# Companion: scripts/debug_psyq.ps1 (bare launch — no .ps-exe, no helper).
[CmdletBinding()]
param(
[string]$PcsxPath = (Join-Path $PSScriptRoot '..\toolchain\pcsx-redux\vsprojects\x64\Release\pcsx-redux.exe'),
[string]$ExePath = (Join-Path $PSScriptRoot '..\build\hello_gte.ps-exe'),
[string]$HelperZip = (Join-Path $PSScriptRoot 'pcsx_debug_helper.zip'),
[int] $GdbPort = 3333,
[int] $WebPort = 8080
)
$ErrorActionPreference = 'Stop'
# ── Pre-checks ──
foreach ($p in @($PcsxPath, $ExePath, $HelperZip)) {
if (-not (Test-Path $p)) {
Write-Error "Missing: $p"
exit 1
}
}
# Kill any existing pcsx-redux so the archive file isn't locked.
Get-Process pcsx-redux -ErrorAction SilentlyContinue | Stop-Process -Force
Start-Sleep -Seconds 2
# ── Launch ──
$absExe = [System.IO.Path]::GetFullPath($ExePath)
$absZip = [System.IO.Path]::GetFullPath($HelperZip)
$args = @(
'-gdb', '-run'
'-loadexe', "`"$absExe`""
'-archive', "`"$absZip`""
)
Write-Host "Launching pcsx-redux..." -ForegroundColor Cyan
Write-Host " ps-exe : $absExe"
Write-Host " helper zip: $absZip"
Write-Host " gdb : localhost:$GdbPort"
Write-Host " web : localhost:$WebPort/api/v1/lua/gte"
Write-Host ""
Start-Process -FilePath $PcsxPath -ArgumentList $args | Out-Null
# ── Wait for both endpoints to come up ──
$deadline = (Get-Date).AddSeconds(15)
while ((Get-Date) -lt $deadline) {
$gdbUp = $false
$webUp = $false
try {
$tcp = New-Object System.Net.Sockets.TcpClient
$tcp.BeginConnect('localhost', $GdbPort, $null, $null) | Out-Null
Start-Sleep -Milliseconds 100
$gdbUp = $tcp.Connected
$tcp.Close()
} catch { $gdbUp = $false }
try {
$r = Invoke-WebRequest -Uri "http://localhost:$WebPort/" -UseBasicParsing -TimeoutSec 1 -ErrorAction SilentlyContinue
$webUp = $r.StatusCode -ne 0
} catch { $webUp = $false }
if ($gdbUp -and $webUp) { break }
Start-Sleep -Milliseconds 500
}
# ── Smoke-test the gte handler ──
try {
$r = Invoke-WebRequest -Uri "http://localhost:$WebPort/api/v1/lua/gte" -UseBasicParsing -TimeoutSec 5
$firstLine = ([System.Text.Encoding]::UTF8.GetString($r.Content) -split "`n")[0]
Write-Host "GTE handler OK: $firstLine" -ForegroundColor Green
} catch {
Write-Warning "GTE handler NOT responding: $_"
Write-Host "Check the pcsx-redux Lua Console for debug cli messages." -ForegroundColor Yellow
}
Write-Host ""
Write-Host "pcsx-redux running. PIDs:" -ForegroundColor Cyan
Get-Process pcsx-redux | Select-Object Id, ProcessName | Format-Table
+68 -77
View File
@@ -2,22 +2,23 @@
---
--- Reads the pre-scanned SourceScan payload (produced once upstream by `duffle.scan_source`)
--- for `MipsAtom_(name)` (kind="atom"), `MipsAtomComp_` / `MipsAtomComp_Proc_` (kind="comp_*"),
--- and `MipsCode code_<name>` (kind="raw_atom") declarations. Walks each atom's
--- pre-tokenized body (`{{tok=string, rel=integer}, ...}` from `duffle.tokenize_body`), counts
--- per-token word contributions via `ctx.shared.word_counts`, and emits one
--- `WORD N LINE L TEXT T` line per `.word` to `gen/<basename>.atoms.sourcemap.txt`.
--- and `MipsCode code_<name>` (kind="raw_atom") declarations.
--- Walks each atom's pre-tokenized body (`{{tok=string, rel=integer}, ...}` from `duffle.tokenize_body`),
--- counts per-token word contributions via `ctx.shared.word_counts`, and emits one
--- `WORD N LINE L TEXT T` line per `.word` to `<out_root>/<basename>.atoms.sourcemap.txt`.
---
--- **Two output forms** (per the workspace's per-emission-form pattern from
--- `guide_metaprogram_ssdl.md`):
--- 1. **Canonical text form** — `<source_dir>/gen/<basename>.atoms.sourcemap.txt`.
--- Always emitted. Format-version-tagged for forward-compat.
--- 2. **gdb-runtime form** — `<ctx.out_root>/gdb_tape_atoms_runtime.gdb` (pure
--- gdb command script; addresses pre-computed via `nm`; the 9 user commands
--- defined as `define ... end` blocks). Emitted ONLY when
--- `ctx.flags.gdb_runtime` is true AND `ctx.flags.elf_path` points to an
--- existing ELF. The gdb runtime form lets `gdb-multiarch --without-python`
--- users (the common case on Windows MinGW builds) load the source-map data
--- via `source <path>` — no Python/Tcl/Guile required.
--- 1. **Canonical text form** — `<out_root>/<basename>.atoms.sourcemap.txt`.
--- Always emitted. Format-version-tagged for forward-compat.
--- Lives in `<out_root>/` (build/gen) NOT `<source_dir>/gen/`. This file is a **build report**, not a compile artifact.
--- Matches the convention used by `annotation.lua` (`<out_root>/<basename>.errors.h`) + `static_analysis.lua` (`<out_root>/<basename>.static_analysis.txt`).
--- Compile artifacts (`*.macs.h`, `*.offsets.h`) stay in `<source_dir>/gen/`.
--- 2. **gdb-runtime form** — `<ctx.out_root>/gdb_tape_atoms_runtime.gdb`
--- (pure gdb command script; addresses pre-computed via `nm`; the 9 user commands defined as `define ... end` blocks).
--- Emitted ONLY when `ctx.flags.gdb_runtime` is true AND `ctx.flags.elf_path` points to an existing ELF.
--- The gdb runtime form lets `gdb-multiarch --without-python` users (the common case on Windows MinGW builds)
--- load the source-map data via `source <path>` — no Python/Tcl/Guile required.
---
--- **Output format** (canonical text form):
--- ```
@@ -33,16 +34,14 @@
--- ENDATOM
--- ```
---
--- Marker calls (`atom_label(...)`, `atom_offset(...)`) emit 0 `.word`s. They share the
--- same walking convention as `passes/offsets.lua :: scan_atom_body`: markers do NOT
--- advance the word-offset counter, but if a marker is bundled on the same token with a
--- trailing instruction (e.g. `atom_label(foo) load_half_u(...)`), the trailing
--- instruction's word count is added. This matches `offsets.lua :: count_marker_rest`.
--- Marker calls (`atom_label(...)`, `atom_offset(...)`) emit 0 `.word`s.
--- They share the same walking convention as `passes/offsets.lua :: scan_atom_body`:
--- markers do NOT advance the word-offset counter, but if a marker is bundled on the same token with a
--- trailing instruction (e.g. `atom_label(foo) load_half_u(...)`),
--- the trailing instruction's word count is added. This matches `offsets.lua :: count_marker_rest`.
---
--- **Conventions:** tabs (1/level), EmmyLua annotations, no regex,
--- Lua 5.3 compatible. See "lua.md" in the ps1-ai styleguides.
---
--- Provenance: generated 2026-07-11 by track gdb_tape_atom_debugging_20260711.
--- Lua 5.3 compatible.
-- ════════════════════════════════════════════════════════════════════════════
-- Module-scope requires + package.path setup
@@ -68,19 +67,6 @@ local FORMAT_VERSION = 1
local LABEL_MARKER = "atom_label"
local OFFSET_MARKER = "atom_offset"
-- gdb-runtime file header + atom-count default for C2 alias table (32 entries).
local C2_DATA_ALIASES = {
"v0.xy", "v0.z", "v1.xy", "v1.z", "v2.xy", "v2.z",
"rgb", "otz",
"ir0", "ir1", "ir2", "ir3",
"sxy0", "sxy1", "sxy2", "sxyp",
"sz0", "sz1", "sz2", "sz3",
"rgb_fifo", "mac0_in",
"?", "?", "?", "?",
"mac0", "mac1", "mac2", "mac3",
"mac4", "mac5", "mac6", "mac7",
}
-- ════════════════════════════════════════════════════════════════════════════
-- Type declarations
-- ════════════════════════════════════════════════════════════════════════════
@@ -106,9 +92,9 @@ local function is_marker_token(tok)
return leading == LABEL_MARKER or leading == OFFSET_MARKER
end
--- Count words contributed by the non-marker portion of `tok` (after the marker's
--- closing `)`). Mirrors offsets.lua:182 `count_marker_rest`. Returns 0 if there's
--- no trailing content after the marker call.
--- Count words contributed by the non-marker portion of `tok` (after the marker's closing `)`).
--- Mirrors offsets.lua:182 `count_marker_rest`.
--- Returns 0 if there's no trailing content after the marker call.
--- @param tok string
--- @param wc table
--- @return integer
@@ -120,9 +106,9 @@ local function count_marker_rest(tok, wc)
return count_token_words(rest, wc)
end
--- Compute per-word entries for an atom. Shared between the canonical text form
--- (per-source `.atoms.sourcemap.txt`) and the gdb-runtime form
--- (`gdb_tape_atoms_runtime.gdb`).
--- Compute per-word entries for an atom.
--- Shared between the canonical text form (per-source `.atoms.sourcemap.txt`)
--- and the gdb-runtime form (`gdb_tape_atoms_runtime.gdb`).
---
--- Returns a list of `{pos, line, text}` entries + the total word count.
--- Markers contribute 0 entries (the marker call emits 0 `.word`s).
@@ -245,8 +231,8 @@ local function gdb_escape(s)
return (s:gsub("\\", "\\\\"):gsub('"', '\\"'))
end
--- Build the list of atoms with addresses + word entries. Shared helper for the
--- gdb-runtime file emission.
--- Build the list of atoms with addresses + word entries.
--- Shared helper for the gdb-runtime file emission.
--- @param ctx PassCtx
--- @return table[] -- list of {idx, name, src_path, file_base, addr, size_bytes, words, entries}
local function build_atom_table(ctx)
@@ -302,15 +288,13 @@ local function build_atom_table(ctx)
return matched
end
--- Append the 9 gdb command definitions to `lines`. Pure gdb scripting
--- no Python, no Tcl, no Guile required. **Fully hardcoded per-atom** because
--- gdb doesn't do nested `$` substitution in var names — `$__atom_name_$__i`
--- inside a `while` loop is treated as one literal identifier, not a concat.
--- Append the 9 gdb command definitions to `lines`. Pure gdb scripting no Python, no Tcl, no Guile required.
--- **Fully hardcoded per-atom** because gdb doesn't do nested `$` substitution in var names
--- `$__atom_name_$__i` inside a `while` loop is treated as one literal identifier, not a concat.
---
--- Each command is a static sequence of `printf` / `tbreak` / `if ... end`
--- blocks. The Lua pass emits N atoms' worth of lines — no runtime iteration.
--- With 7 atoms + ~200 word entries, the runtime file is ~2000 lines, all
--- auto-generated, no human edit ever.
--- Each command is a static sequence of `printf` / `tbreak` / `if ... end` blocks.
--- The Lua pass emits N atoms' worth of lines — no runtime iteration.
--- With 7 atoms + ~200 word entries, the runtime file is ~2000 lines, all auto-generated, no human edit ever.
--- @param lines table -- output line buffer (mutated in place)
--- @param matched table -- list of atom records from `build_atom_table`
local function append_gdb_commands(lines, matched)
@@ -382,10 +366,11 @@ local function append_gdb_commands(lines, matched)
lines[#lines + 1] = " set $__pc = (unsigned int)$pc"
lines[#lines + 1] = " set $__matched = 0"
for _, a in ipairs(matched) do
local end_addr = a.addr + a.words * 4
-- Precompute end_addr (gdb 12.1's expression evaluator chokes on `addr + words*4`).
lines[#lines + 1] = string.format(
" if $__pc >= $__atom_addr_%d && $__pc < $__atom_addr_%d + $__atom_words_%d * 4",
a.idx, a.idx, a.idx)
" set $__end_%d = $__atom_addr_%d + $__atom_words_%d * 4", a.idx, a.idx, a.idx)
lines[#lines + 1] = string.format(
" if $__pc >= $__atom_addr_%d && $__pc < $__end_%d", a.idx, a.idx)
lines[#lines + 1] = string.format(
' printf "atom: code_%%s\\n", $__atom_name_%d', a.idx)
lines[#lines + 1] = ' printf "addr: 0x%08x\\n", $__pc'
@@ -425,14 +410,19 @@ local function append_gdb_commands(lines, matched)
-- ── stepi_inside_atom ──
-- Hardcoded one if-containment-check per atom (no loop).
-- Precompute end_addr in Lua so we don't ask gdb to evaluate `addr + words*4`
-- inside the if condition (gdb 12.1's expression evaluator chokes on the
-- `*` and emits a misleading 'function malloc' error in some gdb builds).
lines[#lines + 1] = "define stepi_inside_atom"
lines[#lines + 1] = " set $__in_atom = 0"
lines[#lines + 1] = " set $__did_step = 0"
lines[#lines + 1] = " set $__pc = (unsigned int)$pc"
for _, a in ipairs(matched) do
local end_addr = a.addr + a.words * 4
-- Precompute end_addr in the convenience var (single expression gdb handles).
lines[#lines + 1] = string.format(
" if $pc >= $__atom_addr_%d && $pc < $__atom_addr_%d + $__atom_words_%d * 4",
a.idx, a.idx, a.idx)
" set $__end_%d = $__atom_addr_%d + $__atom_words_%d * 4", a.idx, a.idx, a.idx)
lines[#lines + 1] = string.format(
" if $__pc >= $__atom_addr_%d && $__pc < $__end_%d", a.idx, a.idx)
lines[#lines + 1] = " set $__in_atom = 1"
lines[#lines + 1] = " stepi"
lines[#lines + 1] = " set $__did_step = 1"
@@ -448,30 +438,29 @@ local function append_gdb_commands(lines, matched)
lines[#lines + 1] = "end"
lines[#lines + 1] = ""
-- ── show_c2 (32 entries) ──
-- Hardcoded with `$c2_data[N]` (COP2 data regs). Requires target attached.
-- ── show_c2 ──
-- GTE data regs (COP2). pcsx-redux's gdb stub doesn't expose COP2 (only
-- 72 regs: 32 GPR + COP0 + FPR).
-- curl http://localhost:8080/api/v1/lua/gte
-- We keep the command definition as a stub that points the user at the plugin.
lines[#lines + 1] = "define show_c2"
for i = 0, 31 do
local alias = C2_DATA_ALIASES[i + 1] or "?"
lines[#lines + 1] = string.format(
' printf "C2[%%2d] 0x%%08x [%%s]\\n", %d, $c2_data[%d], "%s"',
i, i, alias)
end
lines[#lines + 1] = ' echo "[gdb_tape_atoms] show_c2: gdb stub does not expose COP2 in this build."'
lines[#lines + 1] = ' echo "[gdb_tape_atoms] Use scripts/pcsx_debug_helper.zip + curl http://localhost:8080/api/v1/lua/gte"'
lines[#lines + 1] = ' echo "[gdb_tape_atoms] (or pcsx-redux Debug > Registers window for a native view)"'
lines[#lines + 1] = "end"
lines[#lines + 1] = "document show_c2"
lines[#lines + 1] = " Pretty-print all 32 C2 data registers as hex + named alias. Requires target attached."
lines[#lines + 1] = " Stub. The gdb stub in this pcsx-redux build does not expose COP2 regs."
lines[#lines + 1] = " For GTE data + control state, use the pcsx_debug_helper Lua plugin or the"
lines[#lines + 1] = " pcsx-redux Debug > Registers window."
lines[#lines + 1] = "end"
lines[#lines + 1] = ""
-- ── show_c2ctl (32 entries) ──
-- ── show_c2ctl ──
lines[#lines + 1] = "define show_c2ctl"
for i = 0, 31 do
lines[#lines + 1] = string.format(
' printf "C2CTL[%%2d] 0x%%08x\\n", %d, $c2_control[%d]', i, i)
end
lines[#lines + 1] = ' echo "[gdb_tape_atoms] show_c2ctl: see show_c2 for the same workaround."'
lines[#lines + 1] = "end"
lines[#lines + 1] = "document show_c2ctl"
lines[#lines + 1] = " Pretty-print all 32 C2 control registers as hex. Requires target attached."
lines[#lines + 1] = " Stub. Same workaround as show_c2."
lines[#lines + 1] = "end"
lines[#lines + 1] = ""
@@ -488,9 +477,8 @@ local function append_gdb_commands(lines, matched)
end
--- Emit the gdb-runtime file (post-link). Pure gdb scripting — no Python.
--- Reads ELF addresses via `mipsel-none-elf-nm -S`, embeds them in
--- `<ctx.out_root>/gdb_tape_atoms_runtime.gdb` so gdb loads the data via
--- `set $var = ...` + `define ... end` blocks at source-time.
--- Reads ELF addresses via `mipsel-none-elf-nm -S`, embeds them in `<ctx.out_root>/gdb_tape_atoms_runtime.gdb`
--- so gdb loads the data via `set $var = ...` + `define ... end` blocks at source-time.
--- @param ctx PassCtx
local function emit_gdb_runtime(ctx)
if not (ctx.flags and ctx.flags.gdb_runtime) then return end
@@ -563,7 +551,7 @@ end
local M = {}
--- Pass entry: emit one `gen/<basename>.atoms.sourcemap.txt` per source file
--- Pass entry: emit one `<out_root>/<basename>.atoms.sourcemap.txt` per source file
--- that contains at least one `MipsAtom_(name)` / `MipsCode code_<name>` declaration.
--- Optionally also emit `<ctx.out_root>/gdb_tape_atoms_runtime.gdb` when
--- `ctx.flags.gdb_runtime` is true.
@@ -591,7 +579,10 @@ function M.run(ctx)
local n_raw_atoms = src.scan.raw_atoms and #src.scan.raw_atoms or 0
if n_atoms + n_raw_atoms > 0 then
local basename = duffle.basename_no_ext(src.path)
local out_path = src.dir .. "/gen/" .. basename .. ".atoms.sourcemap.txt"
-- Build report, NOT compile artifact: live in <out_root> alongside the other reports
-- (annotation.lua's *.errors.h, static_analysis.lua's *.static_analysis.txt, gdb_tape_atoms_runtime.gdb).
-- The per-source <source_dir>/gen/ is reserved for headers actually #included by C.
local out_path = ctx.out_root .. "/" .. basename .. ".atoms.sourcemap.txt"
local content = render_source_map(src, wc)
if not ctx.dry_run then
@@ -612,4 +603,4 @@ function M.run(ctx)
return { outputs = outputs, errors = errors, warnings = warnings }
end
return M
return M
Binary file not shown.
+55
View File
@@ -0,0 +1,55 @@
-- autoexec.lua - pcsx_debug_helper plugin entry point.
-- Packaged in scripts/pcsx_debug_helper.zip. Loaded by pcsx-redux via
-- the -archive CLI flag (see scripts/launch_pcsx_debug.ps1).
--
-- Registers two web handlers for external CLI tools:
-- /api/v1/lua/gte - full GTE state (32 data + 32 control regs + PC)
-- /api/v1/lua/gp - GP state summary (screenshot endpoint + VRAM endpoint refs)
--
-- The GTE handler reads COP2 regs via PCSX.getRegisters().CP2D/CP2C. The
-- pcsx-redux gdb stub doesn't expose COP2, so this is the only way for
-- external tools to see GTE state.
--
-- The GP handler is a thin pointer: pcsx-redux's Lua API exposes only PCSX.GPU.takeScreenShot()
-- (no GPUSTAT, no GP0/GP1 command log, no display state). For richer GP state, the existing web endpoints are the practical path:
-- /api/v1/state/still - PNG screenshot
-- /api/v1/gpu/vram/raw - VRAM raw bytes (1MB)
--
-- Companion: scripts/gdb/gdb_tape_atoms.gdb (covers GPRs + atom-aware stepping).
local function register_handlers()
if not PCSX.WebServer then PCSX.WebServer = {} end
if not PCSX.WebServer.Handlers then PCSX.WebServer.Handlers = {} end
-- ── GTE state ──
PCSX.WebServer.Handlers.gte = function(req)
local r = PCSX.getRegisters()
local out = { "pc=0x" .. string.format("%x", r.pc) }
for i = 0, 31 do
out[#out + 1] = string.format("D[%d]=0x%08x C[%d]=0x%08x",
i, r.CP2D.r[i], i, r.CP2C.r[i])
end
return table.concat(out, "\n")
end
-- ── GP state (pointer to existing endpoints) ──
-- pcsx-redux's Lua GPU API exposes only takeScreenShot(); no GPUSTAT / GP0 / GP1 command log / display state.
-- We point to the existing web endpoints that DO expose those (when the emulator is actually rendering. Paused-at-BP frames won't have a fresh frame).
PCSX.WebServer.Handlers.gp = function(req)
local out = {
"gpu_screenshot_png=http://localhost:8080/api/v1/state/still",
"vram_raw=http://localhost:8080/api/v1/gpu/vram/raw (1MB VRAM)",
"gpustat=NOT_AVAILABLE_VIA_LUA",
"gp_command_log=NOT_AVAILABLE_VIA_LUA (use pcsx-redux Debug > GPU Logger)",
"hint_run_emulator_unpaused_for_screenshot",
}
return table.concat(out, "\n")
end
end
local ok, err = pcall(register_handlers)
if ok then
print("[pcsx_debug_helper] handlers registered: gte, gp")
else
print("[pcsx_debug_helper] registration failed: " .. tostring(err))
end