Pre-consume store byte in op_aread and op_read_char before blocking reads

Without this, MUD-level saves during read_line/read_char capture PC pointing
at the store byte, which gets misinterpreted as an opcode on restore.
This commit is contained in:
Jared Miller 2026-02-10 15:42:15 -05:00
parent ad47ee05bd
commit 1b3a3646d6
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
2 changed files with 14 additions and 5 deletions

View file

@ -52,8 +52,8 @@ class EmbeddedIFSession:
branch data (V3) or store byte (V5+). Process them so execution branch data (V3) or store byte (V5+). Process them so execution
resumes at the next instruction. resumes at the next instruction.
- MUD-level _do_save during sread/aread: PC points past the read - MUD-level _do_save during sread/aread: PC points past the read
instruction. No post-processing needed (phantom output suppressed instruction (store byte pre-consumed in op_aread/op_read_char).
in start()). No post-processing needed (phantom output suppressed in start()).
""" """
if not self.save_path.exists(): if not self.save_path.exists():
return False return False

View file

@ -808,7 +808,13 @@ class ZCpu:
text_buffer_addr = args[0] text_buffer_addr = args[0]
parse_buffer_addr = args[1] if len(args) > 1 else 0 parse_buffer_addr = args[1] if len(args) > 1 else 0
# Read input from keyboard # Consume store byte BEFORE blocking in read_line(). This ensures
# the PC is past the entire instruction when MUD-level saves capture
# state during read_line(). Without this, saves point PC at the store
# byte, which gets misinterpreted as an opcode on restore.
store_addr = self._opdecoder.get_store_address()
# Read input from keyboard (blocks until player types something)
text = self._ui.keyboard_input.read_line() text = self._ui.keyboard_input.read_line()
text = text.lower().strip("\n\r") text = text.lower().strip("\n\r")
@ -840,7 +846,7 @@ class ZCpu:
offset = pos + word_len offset = pos + word_len
# Store terminating character (13 = newline) # Store terminating character (13 = newline)
self._write_result(13) self._write_result(13, store_addr=store_addr)
def op_print_char(self, char): def op_print_char(self, char):
"""Output the given ZSCII character.""" """Output the given ZSCII character."""
@ -968,8 +974,11 @@ class ZCpu:
if time != 0 or input_routine != 0: if time != 0 or input_routine != 0:
raise ZCpuNotImplemented raise ZCpuNotImplemented
# Consume store byte BEFORE blocking in read_char() — same reason
# as op_aread: PC must be past the full instruction for MUD saves.
store_addr = self._opdecoder.get_store_address()
char = self._ui.keyboard_input.read_char() char = self._ui.keyboard_input.read_char()
self._write_result(char) self._write_result(char, store_addr=store_addr)
def op_scan_table(self, x, table, length, *args): def op_scan_table(self, x, table, length, *args):
"""Search a table for a value, branch if found, store address (V4+). """Search a table for a value, branch if found, store address (V4+).