Kerm, there's no way around the data vs. code issue. It's going to be inherently buggy, but if the program doesn't work anyway on the Nspire, what's it going to hurt to try it?
To determine if you're running on an Nspire, the only way to tell is by checking the OS version (which you said, and I really do not like), or look for the presence of ED ED on the boot page, which takes a second, but it works. I have some code somewhere that does that...
Here's the crappy group of functions I came up with a long time ago for Nspire-specific stuff:
Code:
LockKeypad:
;Locks the Nspire to the 84+SE keypad (wrong keypad error with Nspire one).
;Inputs: None
;Outputs: None
;Notes: This must be run from RAM.
; Destroys appData - appData+4
; Requires Flash unlocked.
ld a,03h
execInvalid:
push af
ld hl,3FF0h
ld de,appData
ld bc,5
ldir
xor a
ld de,7FF0h
ld b,0EDh
call WriteAByte
xor a
ld de,7FF1h
ld b,0EDh
call WriteAByte
pop bc
xor a
ld de,7FF2h
call WriteAByte
xor a
ld de,7FF3h
ld b,10h
call WriteAByte
xor a
ld de,7FF4h
ld b,0C9h
call WriteAByte
call 3FF0h
xor a
ld hl,appData
ld de,7FF0h
ld bc,5
WriteFlash:
;Writes BC bytes from HL to ADE
;Inputs: A is page
; HL is source
; DE is destination
; BC is number of bytes to write
;Outputs: ADE is next destination location
; HL is next source location
; BC=0
;Notes: This must run from RAM.
; Requires Flash unlocked.
push af
WriteFlashLoop:
pop af
push af
push bc
ld b,(hl)
call WriteAByte
pop bc
bit 7,d
jr z,noOverflow
res 7,d
set 6,d
pop af
inc a
push af
noOverflow:
inc hl
dec bc
ld a,b
or c
jr nz,WriteFlashLoop
pop af
ret
UnlockKeypad:
;Unlocks the Nspire from the 84+SE keypad (no more wrong keypad error).
;Inputs: None
;Outputs: None
;Notes: This must be run from RAM.
; Destroys appData - appData+4.
; Requires Flash unlocked.
ld a,04h
jr execInvalid
IsNspire:
;Determines if calculator is an Nspire.
;Inputs: None
;Outputs: Carry set if NOT Nspire
;Notes: This must run from RAM.
; Destroys all
scf
in a,(2)
bit 7,a
ret z
in a,(21h)
and 3
scf
ret z
in a,(6)
push af
ld a,7Fh
out (6),a
ld hl,4000h
ld bc,4000h
isNspireLoop:
ld e,(hl)
inc hl
dec bc
ld a,b
or c
scf
jr z,exitIsNspire
ld a,e
cp 0EDh
jr nz,isNspireLoop
ld e,(hl)
inc hl
dec bc
ld a,b
or c
scf
jr z,exitIsNspire
ld a,e
cp 0EFh
jr nz,isNspireLoop
exitIsNspire:
pop bc
ld a,b
out (6),a
ret
EraseFlash:
;Erases Flash sector (sets all to 0FFh)
;Inputs: A is Flash page within sector
;Outputs: A is start of next Flash sector
; All registers preserved
;Notes: This must run from RAM.
; Requires Flash unlocked.
push bc
and 0FCh
ld b,4
eraseLoop:
call EraseFlashPage
inc a
djnz eraseLoop
pop bc
ret
EraseFlashPage:
;Erases Flash page (sets all to 0FFh)
;Inputs: A is Flash page
;Outputs: All registers preserved
;Notes: This must run from RAM.
; Requires Flash unlocked.
push hl
push de
push af
ld bc,4000h
ld de,4000h
push af
loop: pop af
push af
push bc
ld b,0FFh
call WriteAByte
pop bc
inc de
dec bc
ld a,b
or c
jr nz,loop
pop af
pop af
pop de
pop hl
ret
WriteAByte:
;Writes byte B to A:DE
;Inputs: A is page
; DE is address
; B is byte to write
;Outputs: DE=DE+1
; All preserved
;Notes: This must run from RAM.
; Requires Flash unlocked.
push af
push bc
push hl
ld c,a
in a,(6)
push af
ld a,c
ld hl,(OP1)
push hl
push af
ld a,8
out (6),a
ld hl,OP1
ld (hl),b
.db 0EDh,0EFh
pop af
out (6),a
ldi
pop hl
ld (OP1),hl
pop af
out (6),a
pop hl
pop bc
pop af
ret
unlockFlash:
;Unlocks Flash protection.
;Inputs: None
;Outputs: Destroys all
ld a,1
ld (appInfo+2),a
bcall(50CBh)
ret