Skip to content

Take the freeze slot number in the byte order the code actually uses - #944

Open
mlund wants to merge 1 commit into
MEGA65:developmentfrom
mlund:fix/syspart-slot-number-byte-order
Open

Take the freeze slot number in the byte order the code actually uses#944
mlund wants to merge 1 commit into
MEGA65:developmentfrom
mlund:fix/syspart-slot-number-byte-order

Conversation

@mlund

@mlund mlund commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

syspart_locate_freezeslot says X holds the low byte of the slot number and Y the high byte. It does the opposite and pushes X then Y, and pops with plx before ply, so plx gets what phy pushed. The multiply reads the low byte from Y.

freeze_to_slot in freeze.asm already does it correctly, asking for "Slot in XXYY".

Callers have followed the code, not the comment: the cc65 freeze menu carries ;; XXX - We had to swap the X/Y byte order around for this to work: Why???. This changes the comment and bounds check only as swapping the pops would break every caller that works today.

Measured on an R3 with 1888 slots, and under Xemu with 2045: a slot passed the documented way lands 256 slots on. Slot 1 gave base + $40000 where the slot size is $400.

Other fixes:

  • Bounds check never rejected anything. After comparing the high byte it fell through into the low byte comparison whichever way the first test went, so the high byte's answer was thrown away. An out-of-range slot was accepted and returned a sector past the end of the slot area. Under Xemu, slot 2145 of 2045 was accepted before this change and is refused after; slots 0 and 1 are unchanged.

  • Both error paths returned without pulling the slot number the routine had pushed, so rts took the caller's return address off the stack instead. Nothing triggered it, because the check accepted everything. Fixing the check hung the machine until this was fixed too.

  • syspart_unfreeze_from_slot_trap deliberately restores only X. The dispatch clobbers X with tax, while Y reaches the handler from the caller untouched. TrapToHypervisor in gs4510.vhdl copies registers to the shadow set and assigns only reg_sp, reg_sph and the flags — never reg_y.

Tested by assembling HICKUP and running it under Xemu with -hickup, reading the sector back from $D681 for slots 0, 1 and one past the end.

syspart_locate_freezeslot documents X as the low byte, but it pushes X
then Y and pops plx before ply, so the multiply reads the low byte from
Y.  freeze_to_slot already asks for "Slot in XXYY", and callers follow
the code rather than the comment, so correct the comment and the bounds
check rather than the pops.

That check rejected nothing: it fell through to the low byte whichever
way the high byte compared.  Fixing it exposed error paths that returned
without pulling the pushed slot number.

Also say why syspart_unfreeze_from_slot_trap restores only X: the trap
dispatch clobbers it with tax, while Y reaches the handler untouched.

Under Xemu: slot 2145 of 2045 was accepted, now refused; 0 and 1 unchanged.
@mlund
mlund force-pushed the fix/syspart-slot-number-byte-order branch from 9b7bcaa to 4e58c24 Compare August 20, 2026 08:35
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