Skip to content

Conversation

@fcoury
Copy link
Collaborator

@fcoury fcoury commented Nov 26, 2025

Summary

  • Upgraded project from Zig 0.13 to Zig 0.15.2 with full compatibility
  • Fixed multiple Z80 instruction implementation bugs (IX/IY handling, BIT operations, RST instructions)
  • Added comprehensive documentation (README, MIGRATION.md, CLAUDE.md)
  • Enhanced test infrastructure and benchmark comparison capabilities

Key Changes

Zig 0.15 Migration

  • Updated build system to use root_module pattern
  • Migrated to new unmanaged container APIs (ArrayList, etc.)
  • Updated I/O system to new writer/reader interfaces
  • Fixed all breaking changes from type system updates

Z80 Instruction Fixes

  • BIT instruction: Fixed flag handling for indexed operations (IX+d, IY+d)
  • IX/IY operations: Unified handling with proper cycle counting
  • Stack operations (PUSH): Corrected byte ordering (high byte first)
  • Logical operations (AND/OR/XOR): Added missing XY1 flag updates
  • Missing opcodes: Added RST 28H (0xEF), JP P,nn (0xF2), RST 30H (0xF7), JP M,nn (0xFA)

Documentation

  • README.md: Complete rewrite with installation, usage, and architecture overview
  • MIGRATION.md: Comprehensive Zig 0.13→0.15 migration guide with examples
  • CLAUDE.md: Project structure and development workflow documentation

Build System

  • Added support for custom library paths (~/.local)
  • Improved Z80 library integration

Test Plan

  • Build project with zig build
  • Run all integration tests: ./zig-out/bin/zig80-test run
  • Verify benchmark mode: ./zig-out/bin/zig80-test run --bench
  • Ensure no regressions with --stop flag
  • Validate CLI unit tests: zig test src/cli.zig

fcoury and others added 17 commits November 28, 2025 14:48
Migrate the entire codebase from Zig 0.13 to Zig 0.15.2, addressing
all breaking API changes:

- Build system: root_source_file → root_module with createModule()
- I/O: std.io.getStdOut() → std.fs.File.stdout() with explicit buffers
- Containers: ArrayList now unmanaged, pass allocator to all methods
- Type system: @typeinfo enums now snake_case (.optional, .@"struct")
- Calling convention: callconv(.C) → callconv(.c)
- File I/O: file.reader().readAllAlloc() → file.readToEndAlloc()
- JSON: std.json.stringify() → std.json.Stringify.valueAlloc()
- String: std.mem.split() → std.mem.splitSequence()
- Struct fields: field.default_value → field.defaultValue()

Also adds z80 library linking from ~/.local installation path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- 0xEF: RST 28H
- 0xF2: JP P, nn (jump if positive/sign flag not set)
- 0xF7: RST 30H
- 0xFA: JP M, nn (jump if minus/sign flag set)

All base opcodes (0x00-0xFF) are now implemented, removing the
unreachable else branch from the main opcode switch.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Changed 0xFD handler to use exec_ind() instead of IY_TABLE lookup.
This fixes prefix chaining (e.g., FD DD sequence) by falling back
to executeOpcode for unknown opcodes, allowing proper prefix
switching between IX and IY modes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Add indexedAddr() helper for signed displacement calculation
- Fix IXH/IXL register access (was using ir.* >> 8 instead of ir.*)
- Add 4-cycle overhead for DD/FD prefix instructions
- Implement exec_ddcb for DD CB / FD CB indexed bit operations
- Fix exec_ind else branch to not decrement PC/R for non-indexed ops
- Fix comment: 0xDD is IX, not IY

Test improvement: 280 -> 82 mismatches (1274/1356 tests passing)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Fix BIT instruction for indexed mode (F3/F5 from address high byte)
- Fix land/lxor/lor to set F3/F5 flags
- Fix indexed addressing cycle counts (AND/XOR/OR/CP (IX+d) now 19 cycles)
- Fix SBC A,n cycle count (7 cycles)
- Fix NEG cycle count (8 cycles)
- Fix push byte order (high byte first)
- Add EX (SP),IX/IY instruction
- Add LD SP,IX/IY instruction
- Add RETN instruction (including undocumented variants)
- Add RETI instruction
- Add LD I,A and LD R,A instructions
- Fix IM 0/1/2 switch syntax (use commas not bitwise OR)
- Add undocumented IM 0 variants (0x4E, 0x6E)

Reduces test mismatches from 82 to 3 (remaining are port I/O tests
that need test infrastructure updates)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- 99.6% test coverage (3 of ~750 tests failing)
- Document remaining port I/O test infrastructure work
- Add completed milestones for instruction set implementation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Port I/O Improvements:
- Update port I/O callbacks from u8 to u16 for proper 16-bit addressing
- Fix IN r,(C) instructions (ED 40/48/50/58/60/68/70/78) to use full BC register
- Fix OUT (C),r instructions (ED 41/49/51/59/61/69/71/79) to use full BC register
- Fix IN A,(n) to form port address from A (high byte) and n (low byte)
- Fix OUT (n),A to form port address from A (high byte) and n (low byte)
- Update INI/IND/OUTI/OUTD to use BC register for port addressing
- Add floating bus simulation in port read callback (returns high byte)

Flag Handling:
- Fix setInFlags() to set Sign flag instead of Subtract flag
- Add missing HalfCarry=false and XY1 updates in setInFlags()
- Preserve Carry flag in IN instructions (not modified)

Instruction Fixes:
- Fix ED 53 (LD (nn), DE) - correct double fetchWord bug and add missing cycles
- Fix LDI/LDD integer overflow in XY2 flag calculation

Test Infrastructure:
- Update test port callbacks to use u16 addresses
- Improve panic messages to show test name, opcode, and PC on cycle errors
- Update port I/O format strings to display 16-bit addresses (0x{X:0>4})

Development:
- Update shell.nix to use zig_0_15

All basic port I/O tests now pass with --both flag (0 output mismatches).
- Replace deprecated HTTP client API (open/send/wait) with std.http.Client.fetch
- Update std.mem.split to splitScalar and splitSequence
- Change callback calling convention from .C to .c
- Add ?u32 type support for optional integer flags and positional arguments
- Improve type checking for union/struct recursive parsing
- Uncomment and fix main executable configuration in build.zig
- Handle optional result from CLI parser in main.zig
- Fix H flag cleared in LDI/LDIR/LDD/LDDR instructions
- Fix N flag cleared in SLA instruction
- Reimplement DAA to match Z80 reference behavior
- Fix H flag to receive old carry in CCF instruction
- Add clarifying comment for SCF flag behavior
- Remove debug prints from CPM hook to reduce output noise
- Defer CPU state dumps until comparison fails for better performance
- Replace custom bit counting with @popcount builtin
- Simplify parity calculation using popCount
The HALT instruction handler was printing 'HALT\n' which could get concatenated
with the previous output from test programs (like 'Tests completeHALT').
Adding a newline before the HALT message ensures proper separation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants