Skip to content

Add the LXA and ANE opcodes, count the harness exit write only with I/O visible - #342

Merged
highbyte merged 1 commit into
feature/cpu-cycle-enginefrom
feature/cpu-lxa-ane-opcodes
Sep 18, 2026
Merged

highbyte merged 1 commit into
feature/cpu-cycle-enginefrom
feature/cpu-lxa-ane-opcodes

Conversation

@highbyte

Copy link
Copy Markdown
Owner

What

Two changes, both found through VICE VIC-II test programs that did not reach their real end.

LXA and ANE

LXA ($AB, LAX #imm) and ANE ($8B, XAA #imm) were not implemented in any compatibility profile. The CPU ran such a byte as a one-byte instruction and then executed its operand as the next opcode, so a program using them derailed. flibug's FLI displayer (from Black Mail's FLI Graph editor) runs LXA #0; the operand $00 was executed as BRK and the program ended in BASIC's warm start.

Both are "unstable" opcodes: their result ORs a chip-specific value into A before the AND.

  • LXA #imm: A = X = (A | $EE) & imm
  • ANE #imm: A = (A | $EE) & X & imm

$EE is the common value, and it is settled by the SingleStepTests 6502 corpus already in the test fixtures: all 20 LXA and all 20 ANE vectors match $EE (6 and 15 of them match $FF). The two opcodes are removed from the corpus test's known deviations, so their results, flags and cycles are now asserted.

They are in the StableUnofficial profile, the C64's and VIC-20's default: running them with the common value is closer to any real chip than running them as the wrong instruction. The profile's help text in the Avalonia config dialog and the CPU library docs say so. OpCodeId.LXA_I and OpCodeId.ANE_I are added.

The other unstable opcodes (SHA, SHX, SHY, TAS) stay unimplemented: their result also depends on whether the video chip takes the bus in a particular cycle, and they are a separate piece of work.

The VICE harness's exit register

The harness took any write to $D7FF as the program's exit code, in all 32 memory configurations. The testbench register is in the I/O area, so a program that clears memory with I/O banked out (colorfetchbug/main does) was stopped by a write to RAM. The harness now hooks $D7FF only in configurations where I/O is visible, from a new C64.IsIOVisible, and runs the programs with the FullUnofficial profile, since they are written for the real chip.

Verification

  • VICE VIC-II test programs (274 runs, PAL and NTSC): 256 → 258 match. flibug/blackmail-ee and blackmail-fixed now match their references pixel for pixel (the -ee variant depends on the constant). colorfetchbug/main now runs to its exit and differs in 7 pixels where its reference, a VICE screenshot, lacks the idle byte hardware shows when a bad line starts mid-line. vspbug/vsp_bug now really exits $00 (it was stopped with $5A before). No other result changed.
  • VICE CIA test programs (104 runs): identical before and after.
  • CPU tests: the corpus now asserts LXA and ANE; profile tests cover where they are defined.
  • With the C64's default settings the flibug displayer now runs instead of dropping to READY..
  • Games (Commando, Giana Sisters; PAL, NTSC, snapshots) and fourteen demos at three frame counts render byte-identically before and after, with the new default profile.
  • Performance (MacBook Air M1, For Your Sprites Only): unchanged.

…/O visible

LXA ($AB, LAX #imm) and ANE ($8B, XAA #imm) were not implemented in any
compatibility profile, so the CPU ran them as one-byte instructions and
executed their operand as the next opcode. Both now compute (A | $EE) & ...:
the constant differs between chips, and $EE is the one every LXA and ANE
vector of the SingleStepTests 6502 corpus shows, so the corpus now asserts
them. They are in the StableUnofficial profile, the C64's default: a program
using them derails otherwise. VICE's flibug test programs, whose FLI
displayer runs LXA #0, now match their references.

The VICE test harness took a write to $D7FF as the program's exit code in
every memory configuration. The testbench register is in the I/O area, so a
program that clears memory with I/O banked out was stopped early; the harness
now counts the write only where I/O is visible (new C64.IsIOVisible) and runs
the programs with the FullUnofficial profile.
@sonarqubecloud

Copy link
Copy Markdown

@highbyte
highbyte merged commit b6df33d into feature/cpu-cycle-engine Sep 18, 2026
9 checks passed
@highbyte
highbyte deleted the feature/cpu-lxa-ane-opcodes branch September 18, 2026 13:12
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.

1 participant