From 5a98adb6ee13837bb8e4897c0d7f38155bb0fd48 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Tue, 10 Feb 2026 18:29:27 -0500 Subject: [PATCH] Add instruction tracing to step_fast and improve error messages step_fast() never recorded trace entries, so crash dumps always showed an empty trace. Now records PC + opcode info in the same deque as step(). Also includes exception type in player-facing error messages when the exception string is empty. --- src/mudlib/embedded_if_session.py | 3 ++- src/mudlib/zmachine/zcpu.py | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/mudlib/embedded_if_session.py b/src/mudlib/embedded_if_session.py index 490fcd7..139c947 100644 --- a/src/mudlib/embedded_if_session.py +++ b/src/mudlib/embedded_if_session.py @@ -165,7 +165,8 @@ class EmbeddedIFSession: except Exception as e: tb = traceback.format_exc() logger.error(f"Interpreter crashed:\n{tb}") - self._error = f"interpreter error: {e}" + msg = str(e) or type(e).__name__ + self._error = f"interpreter error: {msg}" finally: self._done = True self._keyboard._waiting.set() diff --git a/src/mudlib/zmachine/zcpu.py b/src/mudlib/zmachine/zcpu.py index 0053577..4778bb4 100644 --- a/src/mudlib/zmachine/zcpu.py +++ b/src/mudlib/zmachine/zcpu.py @@ -226,17 +226,27 @@ class ZCpu: return table def step_fast(self): - """Execute a single instruction without tracing. + """Execute a single instruction with lightweight tracing. Returns True if execution should continue. """ + current_pc = self._opdecoder.program_counter (opcode_class, opcode_number, operands) = self._opdecoder.get_next_instruction() entry = self._dispatch[opcode_class][opcode_number] if entry is None: - raise ZCpuIllegalInstruction + self._trace.append(f" {current_pc:06x} ILLEGAL") + self._dump_trace() + raise ZCpuIllegalInstruction( + f"illegal opcode class={opcode_class} num={opcode_number}" + f" at PC={current_pc:#x}" + ) implemented, func = entry if not implemented: return False + self._trace.append( + f" {current_pc:06x} {func.__name__}" + f"({', '.join(str(x) for x in operands)})" + ) try: func(self, *operands) except (ZCpuQuit, ZCpuRestart):