From dce3adbc4cae486e2f3c080b995669d6db5ef58f Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Tue, 27 Oct 2026 17:04:06 -0400 Subject: Switch 2: window image sizes, queue semaphores, built-in fonts, memory budget - gsv 1510 CalculateRequirements: block-linear size/alignment for window images. - nvhost-gpu: Switch 2 channel event 7 is a real (unsignalled) event. - Puller mirrors NVN2 queue semaphore releases into the page the CPU and GPU wait on (the first two-page nx2:gpu region); EDEN_NX2_METHOD_TRACE logs methods. - pl:u 2000/2010 GetBuiltInFontSharedMemory/GetBuiltInFontData serve plain TTF copies of the shared fonts. - Switch 2 processes count the alias region in their max memory, so the game's nninitStartup heap (total - 6.3 GiB) has room for its sound heap. - gdbrsp.py: interrupt, threads, selthread, hits, continue_async, sleep. --- tools/nx2/gdbrsp.py | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'tools') diff --git a/tools/nx2/gdbrsp.py b/tools/nx2/gdbrsp.py index 9b3b2d8b37..f0acd2aebd 100644 --- a/tools/nx2/gdbrsp.py +++ b/tools/nx2/gdbrsp.py @@ -131,6 +131,10 @@ def main(): break elif op == "continue": print("stop:", rsp.cmd("c")) + elif op == "continue_async": + # Resume without waiting for a stop reply (pair with interrupt). + pkt = b"c" + rsp.s.sendall(b"$" + pkt + b"#" + f"{sum(pkt) & 0xff:02x}".encode()) elif op == "x0": r = rsp.regs() regs = r @@ -156,6 +160,85 @@ def main(): if nfp <= fp: break fp = nfp + elif op == "interrupt": + # Stop a running target (Ctrl-C) and print the stop reply. + rsp.s.sendall(b"") + print("interrupt:", rsp._read_packet()) + elif op == "threads": + # threads [frames]: every thread's pc, lr and frame-pointer chain. + ids = [] + r = rsp.cmd("qfThreadInfo") + while r.startswith("m"): + ids += [t for t in r[1:].split(",") if t] + r = rsp.cmd("qsThreadInfo") + depth = int(parts[1]) if len(parts) > 1 else 16 + for t in ids: + rsp.cmd(f"Hg{t}") + r = rsp.regs() + chain = [] + fp = r.get("x29", 0) + for _ in range(depth): + d = rsp.mem(fp, 16) + if len(d) < 16: + break + nfp, ret = struct.unpack(" : select the first thread whose pc, lr or frame chain falls in + # [lo, hi); later regs/mem ops then read that thread. + lo, hi = int(parts[1], 16), int(parts[2], 16) + ids = [] + r = rsp.cmd("qfThreadInfo") + while r.startswith("m"): + ids += [t for t in r[1:].split(",") if t] + r = rsp.cmd("qsThreadInfo") + for t in ids: + rsp.cmd(f"Hg{t}") + r = rsp.regs() + cands = [r.get("pc", 0), r.get("x30", 0) & 0xFFFFFFFFFFFF] + fp = r.get("x29", 0) + for _ in range(8): + d = rsp.mem(fp, 16) + if len(d) < 16: + break + nfp, ret = struct.unpack(" [memreg]: stop at addr n times, printing x0/x1/lr (and 16 bytes at + # memreg) each time; steps off the breakpoint before resuming. + addr, n = int(parts[1], 16), int(parts[2]) + memreg = parts[3] if len(parts) > 3 else None + for i in range(n): + rsp.cmd(f"Z0,{addr:x},4") + rsp.cmd("c") + r = rsp.regs() + regs = r + extra = "" + if memreg and memreg in r: + extra = " mem=" + rsp.mem(r[memreg], 16).hex() + print(f" hit {i} pc={r.get('pc', 0):#x} x0={r.get('x0', 0):#x} x1={r.get('x1', 0):#x} " + f"x19={r.get('x19', 0):#x} x20={r.get('x20', 0):#x}" + extra) + if r.get("pc") != addr: + break + rsp.cmd(f"z0,{addr:x},4") + rsp.cmd("s") + elif op == "sleep": + import time + time.sleep(float(parts[1])) elif op == "quit": break rsp.s.close() -- cgit v1.2.3