diff --git a/cdrom.jam b/cdrom.jam index 32ba440..1029e9c 100644 --- a/cdrom.jam +++ b/cdrom.jam @@ -35,8 +35,6 @@ const { } = import("xa"); const { spuPushCdSample } = import("spu"); -// TEMP FMV-debug: command/response trace. -pub extern fn printf(format: *const[] u8, ...) i32; // Disc struct redeclaration (same shape as disc.jam). const Disc = struct { @@ -365,11 +363,6 @@ pub const Cdrom = struct { const cmd: u32 = self.pendingCmd as u32; self.busy = 0; - var dbgf: []u8 = "[CDcmd] cmd=%02x pcnt=%u pendingLba=%u lba=%u state=%02x mode=%02x\n"; - printf(dbgf.ptr, cmd, - ((self.paramW as u32) - (self.paramR as u32)) & 0xFF, - self.pendingLba, self.lba, self.state as u32, self.mode as u32); - // psxe cdrom_handle_resp1 prechecks (cdrom.c:271-447), before // dispatch: (1) disc-required commands with no disc → INT5(11h,80h), // (3) wrong parameter count → INT5(03h,20h), unknown command → @@ -701,8 +694,6 @@ pub const Cdrom = struct { // Seek / Pause). pub fn executeResp2(self: mut Self, disc: *mut[] Disc) { const cmd: u32 = self.pendingCmd as u32; - var dbgf2: []u8 = "[CDr2 ] cmd=%02x pendingLba=%u lba=%u state=%02x\n"; - printf(dbgf2.ptr, cmd, self.pendingLba, self.lba, self.state as u32); if (cmd == CDL_INIT) { self.ifr = 2; self.pushResp(self.getStat()); @@ -888,15 +879,6 @@ pub const Cdrom = struct { self.dataRidx = rIdx; self.dataWidx = wEnd; - if (lba >= 4805 && lba <= 4820) { - // TEMP: what did discReadAt load? sub=submode(0x12), the data - // word the game's size=504 DMA reads first is at byte rIdx+32. - var pf: []u8 = "[CDrd] lba=%u sub=%02x dataAt%u=%02x%02x%02x%02x\n"; - printf(pf.ptr, lba, self.dataBuf[18] as u32, rIdx + 32, - self.dataBuf[rIdx + 32] as u32, self.dataBuf[rIdx + 33] as u32, - self.dataBuf[rIdx + 34] as u32, self.dataBuf[rIdx + 35] as u32); - } - if ((self.mode as u32 & MODE_XA_ADPCM) != 0) { self.tryDecodeXa(spu); } diff --git a/cpu.jam b/cpu.jam index feb773c..f3cebf7 100644 --- a/cpu.jam +++ b/cpu.jam @@ -42,17 +42,6 @@ pub extern fn free(ptr: *mut[] u8); pub extern fn memset(dst: *mut[] u8, c: i32, n: u64) *mut[] u8; pub extern fn putchar(c: i32) i32; pub extern fn fflush(stream: u64) i32; -// TEMP REG_TRACE: libc decls for the per-instruction psxe divergence trace. -pub extern fn getenv(name: *const[] u8) u64; -pub extern fn fopen(path: u64, mode: *const[] u8) u64; -pub extern fn fprintf(stream: u64, fmt: *const[] u8, ...) i32; -// TEMP REG_TRACE downsample/window (rebuild jam + psxe -DTRACE_* to change): -// emit one line every TRACE_STRIDE instructions, starting at TRACE_START. -// STRIDE=10000 downsamples the whole run to localize the diverging frame; -// then STRIDE=1 + START= detail-traces it. -const TRACE_START: u64 = 154843000; -const TRACE_STRIDE: u64 = 1; -const TRACE_END: u64 = 154850000; const Disc = struct { file: *mut[] u8, @@ -94,10 +83,6 @@ const Cpu = struct { savedPc: u32, hi: u32, lo: u32, - // TEMP REG_TRACE: per-instruction trace for psxe divergence diff. - traceFp: u64, - traceInit: u32, - traceN: u64, // Pending load: the R3000 has a one-slot load-delay queue — a // value read from memory becomes visible in the destination // register only after the *next* instruction commits. @@ -174,7 +159,6 @@ pub fn freshCpu() Cpu { var c: Cpu = Cpu { pc: 0xBFC00000, nextPc: 0xBFC00004, savedPc: 0, hi: 0, lo: 0, - traceFp: 0, traceInit: 0, traceN: 0, loadD: 0, loadV: 0, branch: 0, delaySlot: 0, branchTaken: 0, halted: 0, cycles: 0, @@ -576,23 +560,6 @@ pub fn iSw(c: mut Cpu, opc: u32, bus: Bus, regs: *mut[] u32, cop0: *mut[] u32) { raiseException(c, cop0, CAUSE_ADES); return; } - // TEMP FMV probe: PC that writes the MDEC command port (0x1F801820). - // psxe issues all MDEC cmds (tables + 88 decodes) from pc=0x800d2ecc; - // see if jam reaches that PC for the decode or only the tables. - if ((addr & 0x1FFFFFFF) == 0x1F801820 && (t & 0x80000000) == 0) { - var pf: []u8 = "[MDECstore] pc=%08x op=%u val=%08x ra=%08x\n"; - printf(pf.ptr, c.savedPc, (t >> 29) & 7, t, gprRead(regs, 31)); - // Dump the function body around the store so we can read the - // decode-loop gate (disassemble manually). Same code in psxe. - var df: []u8 = "[DIS] %08x: %08x\n"; - var a: u32 = 0x800d2bc0; // decode-loop region around the 0x800d2c70 F-call - var k: u32 = 0; - while (k < 110) { - printf(df.ptr, a, busRead32(bus, a)); - a = a + 4; - k = k + 1; - } - } busWrite32(bus, cop0, addr, t); } @@ -1251,44 +1218,7 @@ pub fn step(c: mut Cpu, bus: Bus, regs: *mut[] u32, cop0: *mut[] u32) { // psxe `return`s after the exception so the current cycle does NOT // dispatch the vector's first instruction — that happens on the // next cycle. We do the same here; without the return, every IRQ - // handler runs 1 instruction ahead of psxe (divergence verified - // via REG_TRACE diff against Harvest Moon at L=19258536). - - // TEMP REG_TRACE: emit one line per instruction matching psxe's - // REG_TRACE_FMT (saved_pc, opcode, r0..r31, hi, lo) so the two traces - // can be `cmp`d to find the first jam↔psxe divergence. Enabled by the - // PSX_REG_TRACE env var (a file path), same as psxe. Capped so the file - // stays bounded; periodic flush survives a SIGALRM kill. - if (c.traceInit == 0) { - c.traceInit = 1; - var evn: []u8 = "PSX_REG_TRACE"; - const ep: u64 = getenv(evn.ptr); - if (ep != 0) { - var wmode: []u8 = "w"; - c.traceFp = fopen(ep, wmode.ptr); - } - } - if (c.traceFp != 0) { - const ic: u64 = c.traceN; // instruction index - c.traceN = ic + 1; - if (ic >= TRACE_START && ic < TRACE_END && ((ic - TRACE_START) % TRACE_STRIDE) == 0) { - const topc: u32 = busRead32(bus, c.savedPc); - // Leading %llu = cumulative cycle count BEFORE this instruction - // (jam c.cycles ↔ psxe total_cycles). Lets `cmp` of field 1 - // pinpoint where the cycle models first disagree. - var tfmt: []u8 = "%llu %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n"; - fprintf(c.traceFp, tfmt.ptr, c.cycles, c.savedPc, topc, - regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7], - regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15], - regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23], - regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31], - c.hi, c.lo, - bus.timer.dbgTimerCounter(0), bus.timer.dbgTimerCounter(1), - bus.timer.dbgTimerCounter(2), bus.irq[0], bus.irq[1], - bus.cdrom.dbgDelay(), bus.cdrom.dbgInfo(), bus.cdrom.dbgLba()); - } - if ((ic & 0x3FFFFF) == 0) { fflush(c.traceFp); } - } + // handler runs 1 instruction ahead of psxe. // // Fetch-access cost (psxe cpu.c:302, last_cycles = bus access cycles): @@ -1324,10 +1254,6 @@ pub fn step(c: mut Cpu, bus: Bus, regs: *mut[] u32, cop0: *mut[] u32) { } const opc: u32 = busRead32(bus, c.pc); - if (opc == 0x0c034b99) { // TEMP: jal 0x800d2e64 (MDEC-cmd helper F) - var jf: []u8 = "[jalF] from=%08x ra=%08x\n"; - printf(jf.ptr, c.savedPc, gprRead(regs, 31)); - } c.pc = c.nextPc; c.nextPc = c.nextPc + 4; diff --git a/disc.jam b/disc.jam index dfe0912..8211e62 100644 --- a/disc.jam +++ b/disc.jam @@ -24,9 +24,9 @@ const { cueAlloc, cueFree, cueParse, cueRead, cueQuery, pub extern fn malloc(size: u64) *mut[] u8; pub extern fn free(ptr: *mut[] u8); pub extern fn memset(dst: *mut[] u8, c: i32, n: u64) *mut[] u8; -pub extern fn printf(format: *const[] u8, ...) i32; // File I/O exclusively via std.fs — no raw libc file ABI in this module. const { File, exists } = import("std/fs"); +const { print } = import("std/fmt"); const SECTOR_SIZE: u32 = 2352; const LEAD_IN_SECTORS: u32 = 150; @@ -88,16 +88,15 @@ pub fn discOpen(d: *mut[] Disc, path: []u8) i32 { d[0].cuePtr = c; d[0].isCue = 1; d[0].loaded = 1; - var fmt: []u8 = "Opened CUE: %.*s (%u tracks)\n"; - printf(fmt.ptr, path.len as i32, path.ptr, cueGetTrackCount(c)); + const tracks: u32 = cueGetTrackCount(c); + print("Opened CUE: {path} ({tracks} tracks)\n"); return 1; } match (File.open(path)) { Some(f) { d[0].file = f; d[0].loaded = 1; - var fmt: []u8 = "Opened disc image: %.*s\n"; - printf(fmt.ptr, path.len as i32, path.ptr); + print("Opened disc image: {path}\n"); return 1; } None { return 0; } diff --git a/main.jam b/main.jam index b004e6d..eb786b5 100644 --- a/main.jam +++ b/main.jam @@ -47,11 +47,11 @@ const { const { Vec } = import("std").collections; const { File, exists } = import("std/fs"); const { Args, args, next, exit } = import("std").process; +const { print } = import("std/fmt"); extern fn malloc(size: u64) *mut[] u8; extern fn free(ptr: *mut[] u8); extern fn memset(dst: *mut[] u8, c: i32, n: u64) *mut[] u8; -extern fn printf(format: *const[] u8, ...) i32; extern fn write(fd: i32, buf: *const[] u8, count: u64) i64; extern fn putchar(c: i32) i32; // File I/O (fopen/fread/fwrite/fclose/fseek/access) comes from std/fs @@ -137,9 +137,6 @@ const Cpu = struct { savedPc: u32, hi: u32, lo: u32, - traceFp: u64, - traceInit: u32, - traceN: u64, loadD: u32, loadV: u32, branch: u8, @@ -263,9 +260,7 @@ fn loadExe(path: []u8, bus: Bus, regs: *mut[] u32, c: mut Cpu) { gprWrite(regs, 30, sp); } - var fmt: []u8 = "Loaded EXE: PC=%08X SP=%08X GP=%08X size=%u dest=%08X\n"; - printf(fmt.ptr, c.pc, gprRead(regs, 29), gprRead(regs, 28), - fileSz, ramDest); + print("Loaded EXE: {fileSz} bytes\n"); } None { var msg: []u8 = "loadExe: cannot open file\n"; @@ -450,8 +445,7 @@ fn dumpVramPpm(path: []u8, vram: *mut[] u8) { y = y + 1; } f.close(); - var msg: []u8 = "Wrote VRAM dump: %.*s\n"; - printf(msg.ptr, path.len as i32, path.ptr); + print("Wrote VRAM dump: {path}\n"); } None { } } @@ -534,14 +528,12 @@ fn main() { exit(1); } if (!fileExists(biosPath)) { - var fmt: []u8 = "error: BIOS file not found: %.*s\n"; - printf(fmt.ptr, biosPath.len as i32, biosPath.ptr); + print("error: BIOS file not found: {biosPath}\n"); flushAll(); exit(1); } const got: u64 = loadBios(biosPath, bus); - var biosFmt: []u8 = "Loaded BIOS: %llu bytes from %.*s\n"; - printf(biosFmt.ptr, got, biosPath.len as i32, biosPath.ptr); + print("Loaded BIOS: {got} bytes from {biosPath}\n"); flushAll(); // EXE side-load. If `./demo.exe` exists we drop it into RAM and jump @@ -644,8 +636,7 @@ fn main() { var afmt: []u8 = "WARN: SDL audio device failed to open\n"; write(STDOUT, afmt.ptr, afmt.len); } else { - var aok: []u8 = "Audio device opened (id=%u, 44.1kHz S16 stereo, callback mode)\n"; - printf(aok.ptr, audioDev); + print("Audio device opened (id={audioDev}, 44.1kHz S16 stereo, callback mode)\n"); } var postMsg: []u8 = "SDL2 ready. Priming VRAM...\n"; write(STDOUT, postMsg.ptr, postMsg.len); @@ -747,21 +738,6 @@ fn main() { // FMV-debug probe: periodic GP0 family histogram. Once every // 300 frames (~5s at 60Hz) dump g[72..79] so we can see if/when // family 5 (CPU→VRAM, the FMV upload signature) starts firing. - if ((frames % 300) == 0) { - var gpuState: *mut[] u32 = bus.gpu.bufPtr(); - var fmt: []u8 = "[%u] GP0 families: misc=%u poly=%u line=%u rect=%u blit=%u cpu2vram=%u vram2cpu=%u drawset=%u\n"; - printf(fmt.ptr, frames, - gpuState[72], gpuState[73], gpuState[74], gpuState[75], - gpuState[76], gpuState[77], gpuState[78], gpuState[79]); - const cdinfo: u32 = bus.cdrom.dbgInfo(); - var cdfmt: []u8 = " cd: lba=%u state=%02x readOngoing=%u mode=%02x ifr=%02x dispmode=%06x 24bpp=%u\n"; - printf(cdfmt.ptr, bus.cdrom.dbgLba(), - cdinfo & 0xFF, (cdinfo >> 8) & 0xFF, - (cdinfo >> 16) & 0xFF, (cdinfo >> 24) & 0xFF, - gpuState[47], (gpuState[47] >> 4) & 1); - flushAll(); - } - // Bail after a long-but-finite session if no quit event comes — // protects users from a runaway window when there's no controller // input wired up yet. @@ -772,21 +748,6 @@ fn main() { // the equivalent in psx_mcd_destroy. mcdRamSave(bus.mcdRam, mcdPath); - // FMV-debug probe: dump GP0 command-family histogram. g[72..79] - // counts how many GP0 cmds of each family fired during the run. - // Family index = top 3 bits of the cmd byte: - // 0 = misc (nop/cache/fill) 4 = blit (vram2vram only here) - // 1 = polygon 5 = CPU→VRAM (image load) - // 2 = line 6 = VRAM→CPU - // 3 = rectangle 7 = drawing settings (E1..E6) - // For an FMV intro we expect family 5 (CPU→VRAM) > 0 if MDEC - // output is being uploaded. If it's 0 the bug is upstream - // (CD-ROM streaming / MDEC pipeline never feeds the GPU). - var gpuState: *mut[] u32 = bus.gpu.bufPtr(); - var fmt: []u8 = "GP0 families: misc=%u poly=%u line=%u rect=%u blit=%u cpu2vram=%u vram2cpu=%u drawset=%u\n"; - printf(fmt.ptr, gpuState[72], gpuState[73], gpuState[74], gpuState[75], - gpuState[76], gpuState[77], gpuState[78], gpuState[79]); - sdlAudioClose(audioDev); free(audioCtx); free(buttons as *mut[] u8); diff --git a/mdec.jam b/mdec.jam index 9bdb408..371266e 100644 --- a/mdec.jam +++ b/mdec.jam @@ -439,10 +439,6 @@ pub const Mdec = struct { self.inputFull = 0; self.busy = 1; const op: u32 = (val >> 29) & 7; - // TEMP FMV probe: log every MDEC command word. op=1 DECODE is the - // frame decode the FMV needs; op=2/3 are the quant/IDCT tables. - var pf: []u8 = "[MDECcmd] op=%u val=%08x words=%u\n"; - printf(pf.ptr, op, val, val & 0xFFFF); var newWords: u32 = 0; if (op == MDEC_CMD_NOP) { self.busy = 0;