Commit graph

277 commits

Author SHA1 Message Date
0c6eadb0da
Implement QuetzalWriter._generate_ifhd_chunk()
The IFhd chunk contains 13 bytes of metadata identifying the story
and current execution state:
- Release number (2 bytes) from header
- Serial number (6 bytes) from header
- Checksum (2 bytes) from header
- Program counter (3 bytes) from CPU state

This allows save files to be validated against the story file.
2026-02-10 09:47:24 -05:00
8097bbcf55
Document save/restore as open gap in hybrid interpreter
op_save is a stub that always fails. QuetzalWriter chunks are stubs.
Added as open question 7, next step item, and corrected the inaccurate
claim that save/restore works.
2026-02-09 23:13:47 -05:00
ec4e53b2d4
Fix backspace echo for terminals that send chr(127)
The input detection handled both chr(8) and chr(127) but the echo
logic only checked chr(8). Most modern terminals send chr(127) for
backspace, so the cursor never moved back visually.
2026-02-09 23:11:43 -05:00
1b08c36b85
Update investigation and journey docs with session 3 findings 2026-02-09 23:06:43 -05:00
bbd70e8577
Truncate words to dictionary resolution before lookup 2026-02-09 23:04:56 -05:00
6e62ca203b
Fix return value storage in finish_routine 2026-02-09 23:04:54 -05:00
fa31f39a65
Fix signed comparison in op_jl 2026-02-09 23:04:52 -05:00
f8f5ac7ad0
Add z-machine garbled output investigation doc and debug script 2026-02-09 22:54:32 -05:00
127ca5f56e
Fix BitField slice and off-by-one bugs in zobjectparser.py
Property parsing had 4 classes of bug, all producing wrong addresses
for object property data:

1. Off-by-one in shortname skip: addr += 2*len missed the length byte
   itself, causing property table scan to start 1 byte too early.
   Affected get_prop_addr_len and get_next_property.

2. V3 property number slices bf[4:0] extracted 4 bits not 5.
   Property numbers 16-31 were read as 0-15.

3. V3 property size slices bf[7:5] extracted 2 bits not 3.
   Properties larger than 4 bytes got wrong sizes.

4. V5 property number/size slices bf[5:0] extracted 5 bits not 6.

Also fixed get_property_length reading size from the wrong byte in
V5 two-byte headers (was reading first byte which has property
number, instead of second byte which has size).

Root cause for all slice bugs: BitField uses Python [start:stop)
semantics but code was written as [high:low] inclusive notation.
Same class of bug as the write_global fix in commit e5329d6.
2026-02-09 22:54:32 -05:00
5ffbe660fb
Flush stdout after character echo in readline 2026-02-09 22:03:06 -05:00
2ce82e7d87
Add unit tests for op_test, op_verify, and op_get_child
Adds comprehensive test coverage for three newly implemented Z-machine opcodes:

- op_test: Tests bitmap flag checking with all flags set, some missing, zero
  flags, and identical values
- op_verify: Tests checksum verification with matching and mismatched checksums
- op_get_child: Tests getting first child of object with and without children

Also extends MockMemory with generate_checksum() and MockObjectParser with
get_child() to support the new tests.
2026-02-09 21:52:08 -05:00
2cf303dd67
Add --debug flag to Zork 1 smoke test 2026-02-09 21:47:39 -05:00
48727c4690
Log warning for undefined ZSCII characters 2026-02-09 21:47:20 -05:00
8ba1701c9f
Dump instruction trace for all error exceptions, not just illegal opcode
Wrap opcode execution with try-except to catch all ZCpuError subclasses except
ZCpuQuit and ZCpuRestart, which are normal control flow. This ensures we get
trace dumps for divide by zero, not implemented, and other errors.
2026-02-09 21:47:13 -05:00
0f5fada29e
Remove duplicate routine_address == 0 check from op_call
The _call() method already handles this case, so the check in op_call is redundant.
2026-02-09 21:46:59 -05:00
e6b63622fa
Document Zork 1 milestone in if-journey
The hybrid interpreter can now run Zork 1, marking the first working
implementation of the embedded interpreter path. This enables levels 2-5
(inspectable/moldable/shared worlds) rather than just the opaque terminal
approach of level 1.
2026-02-09 21:46:53 -05:00
9a0bacd581
Document write_word permission model in zmemory 2026-02-09 21:46:52 -05:00
1bcb83961a
Guard against word-not-found in sread tokenization
If text.find(word_str, offset) returns -1, use the offset as a fallback.
2026-02-09 21:46:45 -05:00
28a097997c
Add explanatory comment to ZStackBottom sentinel 2026-02-09 21:46:40 -05:00
eeb65e0cc2
Remove debug print statements from zcpu opcode dispatch
The exception that follows provides the context, so these prints are redundant.
2026-02-09 21:46:34 -05:00
e5329d6788
Fix 7-bit truncation bug in write_global corrupting game state 2026-02-09 21:45:54 -05:00
311a67e80a
Fix bugs found running Zork 1 through hybrid interpreter
Spec fixes: implement op_test (bitwise AND branch), add missing branch
to op_get_child, handle call-to-address-0 as no-op in op_call/_call.
I/O fixes: correct keyboard API (keyboard_input.read_line), non-TTY
fallbacks in trivialzui, stdout flush for immediate output. Graceful
handling of unmapped ZSCII characters. Add instruction trace buffer
for debugging.
2026-02-09 21:36:30 -05:00
8d749fbb7e
Add missing newline to A2 alphabet table for V3
The V3 A2 table needs newline (ZSCII 13) at code 7, matching viola's
implementation. The previous fix only removed the erroneous '<' but
didn't add the newline, leaving the table at 24 chars instead of 25.
2026-02-09 21:17:04 -05:00
9116777603
Fix A2 alphabet table with extra character shifting symbols
DEFAULT_A2 had 26 chars instead of 25 due to an erroneous '<'. This
shifted all symbol mappings, causing periods to render as exclamation
marks and other garbled punctuation in Zork 1 output.
2026-02-09 21:11:12 -05:00
e1c6a92368
Fix Python 3 integer division in zmachine modules
Python 2 `/` did integer division, Python 3 returns float. Changed to
`//` in zobjectparser (attribute byte offset) and zmemory (address
bounds checks). Zork 1 hit this on the first test_attr opcode.
2026-02-09 21:07:16 -05:00
8eb2371ce1
Add stack and local_vars to ZStackBottom sentinel
ZStackBottom lacked attributes that normal stack operations need when
returning from a subroutine to the top level. Zork 1 hit this on the
first subroutine return during startup.
2026-02-09 21:05:27 -05:00
61765fa6ba
Allow game writes to header region in dynamic memory
write_word() was routing all header writes through game_set_header()
which enforced overly strict per-byte permissions. Zork 1 legitimately
writes to header address 2 on startup. Now uses the same dynamic/static
boundary check that viola does, matching the reference implementation.
2026-02-09 21:03:10 -05:00
e0e2e84dc2
Add smoke test script for running Zork 1 through hybrid interpreter
Loads zork1.z3, creates ZMachine with TrivialZUI, and runs
interactively with graceful error handling for unimplemented opcodes.
2026-02-09 20:59:07 -05:00
d218929f02
Add step() method to ZCpu for async MUD integration
Extracts the run loop body into step() which executes one instruction
and returns True/False for continue/halt. run() now delegates to step().
2026-02-09 20:59:03 -05:00
fb8cbf7219
Implement op_verify and wire ZLexer into sread for Zork 1
op_verify now performs actual checksum validation against the header
instead of raising NotImplemented. ZLexer is injected into ZCpu and
sread tokenizes input into the parse buffer per the V3 spec.
2026-02-09 20:57:15 -05:00
205e2716dd
Update if-journey.rst with hybrid interpreter progress 2026-02-09 20:44:22 -05:00
72dd047b7b
Port 5 complex opcodes to hybrid z-machine interpreter
Implement op_sread (text input), op_save/restore (file I/O stubs),
op_restart (exception-based reset), op_input_stream and op_sound_effect
(no-op stubs). Add ZCpuRestart exception. All implementations follow TDD
with comprehensive unit tests.
2026-02-09 20:44:22 -05:00
c76ee337d3
Port 4 medium opcodes to hybrid z-machine interpreter
Implements op_print_addr, op_print_num, op_ret, and op_show_status following
TDD approach with tests first. Each opcode now properly decodes/prints text,
handles signed numbers, returns from routines, or acts as a no-op as appropriate.
2026-02-09 20:44:22 -05:00
1b9d84f41a
Port 10 object tree opcodes to hybrid z-machine interpreter
Implemented 10 opcodes for object tree manipulation: get_sibling,
test_attr, set_attr, clear_attr, jin, remove_obj, print_obj,
get_prop_addr, get_next_prop, and get_prop_len.

Added 6 supporting methods to ZObjectParser: set_attribute,
clear_attribute, remove_object, get_property_data_address,
get_next_property, and get_property_length.

Fixed bug in insert_object where sibling chain walk never advanced
the prev pointer, potentially causing infinite loops.

Added 16 unit tests with MockObjectParser to verify CPU opcode
behavior. All tests passing.
2026-02-09 20:44:21 -05:00
5ea030a0ac
Re-copy fixed repos/zvm source into src/mudlib/zmachine
Copies the cleaned-up zvm source (ruff-compliant, ty-clean) back into
the zmachine module. Adds __init__.py with proper exports and updates
.gitignore for debug.log/disasm.log.
2026-02-09 20:44:21 -05:00
dcc952d4c5
Port 12 trivial opcodes to hybrid z-machine interpreter 2026-02-09 20:44:21 -05:00
677ddac89f
Add z-machine opcode tracing script 2026-02-09 18:51:52 -05:00
47ef606e7f
Update documents with new IF system 2026-02-09 17:59:47 -05:00
108091bfae
Add blank line before IF mode prompt to match dfrotz 2026-02-09 17:55:14 -05:00
f8e9ae0acc
Add spacing between IF session exit messages 2026-02-09 17:55:14 -05:00
54cd0f6656
Strip dfrotz prompt even without preceding newline 2026-02-09 17:55:14 -05:00
05c9a48bb3
Strip dfrotz prompt even with trailing whitespace 2026-02-09 17:28:28 -05:00
b90e61c4fc
Add tests for save overwrite auto-confirm and failure detection 2026-02-09 17:11:59 -05:00
8dc2d4b934
Auto-confirm overwrite and clean up save feedback 2026-02-09 17:10:30 -05:00
de58209fd0
Add test for chunked IF response reading 2026-02-09 17:07:43 -05:00
da176a1363
Use get_running_loop() instead of deprecated get_event_loop() 2026-02-09 17:07:27 -05:00
e8f16ca18a
Speed up IF reads with chunked I/O and short idle timeout 2026-02-09 17:05:27 -05:00
43fce6a4ed
Fix line length issues in IF session tests 2026-02-09 16:45:36 -05:00
76488139c8
Add error handling for process communication failures in IF save/restore 2026-02-09 16:45:12 -05:00
bb1f9bbbd8
Prevent double-save when quitting IF sessions 2026-02-09 16:44:13 -05:00