Story: E01-S03
Status: observed in VICE x128 3.10 with a true-emulation 1541; not the final
compiler map
kcall)in: kc_target = KERNAL entry address; A/X/Y = routine arguments
out: A/X/Y and N/V/Z/C exactly as the routine returned them
I flag = the caller's I flag
CR, RCR, P0L/H, P1L/H = their values at the call
Sequence (src/platform/kernal-probe.s):
PHP/SEI, save A and the caller's P.CLI (the KERNAL runs in its own default mapping with IRQs enabled), then
JSR through an indirect jump to the routine.PHP/SEI, save A and the result P.The ordering in steps 3 and 6 matters: whenever CR selects bank 1, bottom common RAM must already be enabled, or the wrapper's own code disappears.
The wrapper code and its variables must be in bottom common RAM. Hardware stack
cost is the caller's return address plus one more (kc_jump), on top of the
routine's own usage. kc_target must not sit at $xxFF (6502 JMP ($xxFF)
bug); the source has a link-time .assert.
The probe also has kcall_inline, a compact call form (JSR kcall_inline
followed by .word target, 5 bytes per call site) that preserves A/X/Y. It was
needed to fit the probe inside the 8K common window.
| State | CR | RCR (low bits) | Meaning |
|---|---|---|---|
| 0 | $0E |
%0110 |
RAM bank 0 to $BFFF, system ROM high, I/O, 8K bottom common |
| 1 | $4E |
%0110 |
Same with RAM bank 1 |
RCR bits 6–7 (VIC bank) are carried over from the entry value.
All checks pass; both per-state result bytes are $FF.
| Bit | Check | State 0 | State 1 |
|---|---|---|---|
$01 |
Every CHROUT returns C=0 | pass | pass |
$02 |
OPEN 15,8,15 + CHKIN 15 return C=0 |
pass | pass |
$04 |
Status text starts with two digits and ends in CR | 00, OK,00,00 |
00, OK,00,00 |
$08 |
LDTND ($98) = 0 after CLRCHN/CLOSE on the success path |
pass | pass |
$10 |
CHKIN on absent device 30 returns C=1, A=5 |
pass | pass |
$20 |
LDTND = 0 after CLRCHN/CLOSE on the failure path |
pass | pass |
$40 |
CR/RCR/P0/P1 identical after every wrapper call | pass | pass |
$80 |
$4000 still shows this bank's marker after all calls |
pass | pass |
READST after the failed CHKIN returns $80 (device not present) from both
states, so ST also survives the round trip. Note that OPEN with no filename
sends nothing on the serial bus, so the device-not-present error surfaces at
CHKIN, not OPEN. Compiler disk code must check both.
The x128 screenshot (build/kernal-probe-vicii.png) shows one CHROUT line per
state, both drive-8 status lines, and NOVA128 KERNAL PROBE OK.
Changing the wrapper's flag merge from AND #$FB to AND #$FA (dropping the
routine's carry) makes both state results $EF and the verifier fails with
CHKIN carry was clear. The checks are therefore not vacuous.
docs/mmu-probe.md).scripts/build-kernal-probe.ps1 # PRG + fresh build/kernal-probe.d64
scripts/verify-kernal-probe.ps1 # true-drive autostart, remote checks, screenshot
The verifier polls kprobe_complete over the remote monitor because loading
through true drive emulation takes a variable number of seconds. The monitor
transcript is saved to build/kernal-probe-remote.txt.
Powered by TurnKey Linux.