+ cmp #5
+ beq @LoadXAndReturn
+
+; It is either a 4510 (C65) or a 45GS02 (MEGA65)
+
+ ; 45GS02 supports 32-bit ZP indirect, so use that to check CPU type
+ ; without requiring a functioning MEGA65 hypervisor.
+ ; We setup a read of $200FF, then store a different value in $00FF
+ ; and then re-read $200FF to see if it is unchanged.
+
+ ; Save the 32-bit ZP pointer and data byte
+ ldx #4
+@L10: lda $fb,x
+ sta @GetCPUTemp,x
+ dex
+ bpl @L10
+
+ ; Setup 32-bit pointer to $000200FF
+ lda #$ff
+ sta $fb
+ lda #$00
+ sta $fc
+ sta $fe
+ lda #$02
+ sta $fd
+
+ ; Prefixing LDA ($nn),Z with a NOP uses 32-bit ZP pointer on 45GS02,
+ ; but normal 16-bit ZP pointer on 4510
+ ; (We assume Z=$00, which will be the normal case)
+ nop ; prefix to tell next instruction to be 32-bit ZP
+ .byte $b2,$fb ; LDA ($nn),Z
+ eor #$ff ; change the value
+ sta $ff ; store in $FF
+ ; now try again to load it: If the same, then 45GS02, as $200FF is unchanged
+ nop ; prefix to tell next instruction to be 32-bit ZP
+ .byte $b2,$fb ; LDA ($nn),Z
+ cmp $ff ; does the loaded value match what is in $FF?
+ beq @Is4510 ; matches, so must be a 4510 = C65
+ bne @Is45GS02 ; $200FF and $FF have different values, so must be a MEGA65 45GS02
+@Is4510:
+ jsr @RestoreGetCPUTemp
+ lda #3 ; CPU_4510 constant
+ ldx #0 ; load high byte of word
+ rts
+
+@Is45GS02:
+ jsr @RestoreGetCPUTemp
+ lda #8 ; CPU_45GS02 constant
+ ldx #0 ; load high byte of word
+ rts
+
+@RestoreGetCPUTemp:
+ ; Save the 32-bit ZP pointer and data byte
+ ldx #4
+@L11: lda @GetCPUTemp,x
+ sta $fb,x
+ dex
+ bpl @L11
+ rts
+
+ ; Temporary storage for the ZP locations we modify above
+@GetCPUTemp: .byte 0,0,0,0,0
+
+