Code: Select all
.P65C02
TestCPU:
LDA #0
STA $84
STA $85
LDA #$1D ; 'N' EOR 'S'
STA $83
LDA #$6B ; 'N' EOR 'S' EOR '8'
STA $1D
LDA #$4E ; 'N'
RMB4 $83 ; magic $47 opcode
EOR $83
; accumulator now contains ASCII:
; N - NMOS 6502
; S - 65SC02
; C - 65C02 or 65CE02
; 8 - 68C816 or 65C802
; output routine for BBC Micro
JSR $FFEE ; OSWRCH
JSR $FFE7 ; OSNEWL
RTS
I thought it might be instructive to explain how this code works. As the comments hint, the key is in the "magic" $47 opcode, which behaves differently on all four families. Other opcodes with a similar class of behaviour could have been used, but $47 has some nice properties that make it work particularly well here.
The first 8 instructions, immediately preceding the "magic opcode", set up some zero-page locations with "magic data". These are needed to cause some of the CPUs to behave in useful ways once given the $47 opcode. Address $83 was chosen because it is available to user programs on the BBC Micro, and is a 1-byte NOP on the 65SC02. Any other 1-byte NOP opcode could be substituted for this address, as long as the zeroes stored at $84 and $85 are also moved to follow it. Address $1D is important for a different reason and should not casually be moved; on the BBC Micro it harmlessly clobbers BASIC's DATA pointer. It can be moved out of zero-page if the data stored at $84 is changed to match, but $83 must contain $1D.
An NMOS 6502 interprets $47 $83 as a concatenation of LSR $83 and EOR $83, in that effective order. Since that instruction is immediately followed by another EOR $83, the accumulator is left unchanged from its initial value of ASCII 'N'.
A 65SC02 interprets both $47 and $83 as 1-byte NOPs. The following EOR $83 changes the accumulator to ASCII 'S' using the magic value $1D stored there earlier.
A 65C02 interprets $47 $83 as RMB4 $83 (as written in the listing), which clears bit 4 of that memory location. The subsequent EOR now produces ASCII 'C' in the accumulator; it's a useful coincidence that 'S' and 'C' differ by only one bit. The rare 65CE02 is backwards compatible with the 65C02, and will be identified as one by this routine.
A 65816 (or 65802) interprets $47 $83 as EOR [$83], indirecting through the 3-byte long pointer we set up there earlier. The magic value stored there combines with the $1D magic value to convert 'N' into '8' in ASCII.
I'm sure some of you are now thinking of the "Story of Mel"…