diff --git a/src/mudlib/embedded_if_session.py b/src/mudlib/embedded_if_session.py index 79aa40e..763de68 100644 --- a/src/mudlib/embedded_if_session.py +++ b/src/mudlib/embedded_if_session.py @@ -53,6 +53,17 @@ class EmbeddedIFSession: save_data = self.save_path.read_bytes() parser = QuetzalParser(self._zmachine) parser.load_from_bytes(save_data) + # In V1-3, the saved PC points to branch data after the save + # instruction. Process the branch as "save succeeded" so the + # PC advances past it. Detect by checking for save opcode (0xB5) + # immediately before the restored PC. + pc = self._zmachine._opdecoder.program_counter + if ( + self._zmachine._mem.version <= 3 + and pc > 0 + and self._zmachine._mem[pc - 1] == 0xB5 + ): + self._zmachine._cpu._branch(True) return True except Exception as e: logger.debug(f"Restore failed: {e}") diff --git a/src/mudlib/zmachine/zcpu.py b/src/mudlib/zmachine/zcpu.py index c6bbb09..4241189 100644 --- a/src/mudlib/zmachine/zcpu.py +++ b/src/mudlib/zmachine/zcpu.py @@ -236,8 +236,7 @@ class ZCpu: except (ZCpuQuit, ZCpuRestart): # Normal control flow - don't dump trace raise - except ZCpuError: - # All other ZCpu errors - dump trace for debugging + except Exception: self._dump_trace() raise return True diff --git a/src/mudlib/zmachine/zstackmanager.py b/src/mudlib/zmachine/zstackmanager.py index e874484..7960d77 100644 --- a/src/mudlib/zmachine/zstackmanager.py +++ b/src/mudlib/zmachine/zstackmanager.py @@ -153,6 +153,11 @@ class ZStackManager: "Remove and return value from the top of the data stack." current_routine = self._call_stack[-1] + if not current_routine.stack: + frame_idx = len(self._call_stack) - 1 + ra = getattr(current_routine, "return_addr", "N/A") + pc = getattr(current_routine, "program_counter", 0) + raise ZStackPopError(f"frame {frame_idx}, return_addr={ra}, pc=0x{pc:06x}") return current_routine.stack.pop() def get_stack_frame_index(self):