Repository navigation
Fix DD/FD EX AF,AF' timing and the R count of CB instructions - #42
Merged
davidly merged 1 commit intoNov 11, 2026
Merged
Conversation
EX AF,AF' after a DD or FD prefix counted 4 T-states. It takes 8: the
prefix's fetch plus the instruction's own 4. z80_cycles held 4 for
opcode 08h and z80_emulate returned 0 so the main loop wouldn't count it
twice, but z80_execute_unprefixed adds the prefix's 4 to what
z80_emulate returns, so the prefixed form got 4 + 0. The table entry is
now 0, like the other opcodes z80_emulate times itself (DJNZ, JR, EXX,
ED), and z80_emulate returns its default 4. Unprefixed EX AF,AF' is
still 4.
With TRACK_Z80_R_REGISTER on, R counted one fetch for a CB-prefixed
instruction and three for DD CB d and FD CB d. A Z80 increments R twice
for both: for the CB prefix and its opcode, or for the DD/FD and CB
prefixes. The displacement and final opcode of the indexed forms aren't
M1 cycles. The CB handler now bumps R, and the DD/FD CB path no longer
bumps it a third time. Measured as LD R,A / instruction / LD A,R with
the switch on:
CB 00 +2 (was +1)
DD CB 05 06 +2 (was +3)
FD CB 05 46 +2 (was +3)
NOP (+1), ED 44 and DD 23 (+2) and DD DD 23 (+3) are as before. The
default build doesn't track R, so it is unchanged.
The loop that consumes repeated DD and FD prefixes never ended when
memory held nothing but prefixes. It now gives up after 65,536 of them
and reports the instruction as not implemented, as prefixed HALT does.
No test covers that limit.
cyclecheck.py gains cases for a prefix on instructions that ignore it
(EX AF,AF', NOP, LD BC,nn, JR, EXX, ED NEG), repeated and mixed
prefixes, INIR, INDR, OTIR and OTDR, and CPIR and CPDR that match on
the first byte. Without this change it fails the two EX AF,AF' cases;
with it everything passes. ZEXALL, ZEXDOC, the exercisers in ra.sh,
flagcheck.py and aluflagcheck.py still pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three fixes to the Z80 engine in
x80.cxx, found by stepping every Z80 encoding through ntvcm and a second copy of the engine and comparing the results.1.
DD/FDEX AF,AF'counted 4 T-states instead of 8z80_cyclesheld 4 for opcode08handz80_emulatereturned 0 so the main loop wouldn't count it twice.z80_execute_unprefixedadds the prefix's 4 to whatz80_emulatereturns, so the prefixed form got 4 + 0.The table entry is now 0, like the other opcodes
z80_emulatetimes itself (DJNZ,JR,EXX,ED), andz80_emulatereturns its default 4. UnprefixedEX AF,AF'is still 4.2. R counted the wrong number of fetches for
CBinstructionsOnly visible with
TRACK_Z80_R_REGISTERon; the default build is unchanged.A Z80 increments R twice for a
CBinstruction and twice forDD CB d/FD CB d(the displacement and final opcode aren't M1 cycles). Measured asLD R,A/ instruction /LD A,R:CB 00DD CB 05 06FD CB 05 46NOP(+1),ED 44andDD 23(+2) andDD DD 23(+3) are as before.3. The repeated-prefix loop never ended on memory holding only prefixes
The loop that consumes repeated
DD/FDprefixes now gives up after 65,536 of them and reports the instruction as not implemented, as prefixedHALTdoes. No test covers this limit.Tests
tests/cyclecheck.pygains cases for:EX AF,AF',NOP,LD BC,nn,JR,EXX,ED NEG);INIR,INDR,OTIRandOTDR;CPIRandCPDRthat match on the first byte.Without this change it fails the two
EX AF,AF'cases; with it everything passes.Run on macOS (clang,
-O3): ZEXALL and ZEXDOC (67 tests each, no errors), the exercisers intests/ra.sh,flagcheck.pyandaluflagcheck.pyall pass.zexsup/zexusupwere not run (nocpm_compilerscheckout), and I did not build with Watcom or MSVC.