diff --git a/src/mudlib/zmachine/zcpu.py b/src/mudlib/zmachine/zcpu.py index 36e3fd1..2be4445 100644 --- a/src/mudlib/zmachine/zcpu.py +++ b/src/mudlib/zmachine/zcpu.py @@ -168,31 +168,34 @@ class ZCpu: log(f"Jump to offset {branch_offset:+d}") self._opdecoder.program_counter += branch_offset - 2 + def step(self): + """Execute a single instruction. Returns True if execution should continue.""" + current_pc = self._opdecoder.program_counter + log(f"Reading next opcode at address {current_pc:x}") + (opcode_class, opcode_number, operands) = self._opdecoder.get_next_instruction() + implemented, func = self._get_handler(opcode_class, opcode_number) + log_disasm( + current_pc, + zopdecoder.OPCODE_STRINGS[opcode_class], + opcode_number, + func.__name__, + ", ".join([str(x) for x in operands]), + ) + if not implemented: + log(f"Unimplemented opcode {func.__name__}, halting execution") + return False + + # The returned function is unbound, so we must pass + # self to it ourselves. + func(self, *operands) + return True + def run(self): """The Magic Function that takes little bits and bytes, twirls them around, and brings the magic to your screen!""" log("Execution started") - while True: - current_pc = self._opdecoder.program_counter - log(f"Reading next opcode at address {current_pc:x}") - (opcode_class, opcode_number, operands) = ( - self._opdecoder.get_next_instruction() - ) - implemented, func = self._get_handler(opcode_class, opcode_number) - log_disasm( - current_pc, - zopdecoder.OPCODE_STRINGS[opcode_class], - opcode_number, - func.__name__, - ", ".join([str(x) for x in operands]), - ) - if not implemented: - log(f"Unimplemented opcode {func.__name__}, halting execution") - break - - # The returned function is unbound, so we must pass - # self to it ourselves. - func(self, *operands) + while self.step(): + pass ## ## Opcode implementation functions start here.