;;; -*- TI-Asm -*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Unity - assembly program loader for the TI-81
;;;
;;; Copyright (c) 2010 Benjamin Moody
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation, either version 3 of
;;; the License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program. If not, see
;;; .
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.nolist
.include
.list
.export INIT_EXEC_PROG, PATCH_JERROR, PATCH_READ_KEY_GROUP, USER_INT_CALL, KERNEL_SIZE
.org progMem - $2000
check_exec:
;; Check if currently waiting to execute an assembly block
ld hl,(curPC)
ld bc,exec_sig_str ; note: this (4-byte) string is
; located at D3FC, so the end of the
; string is on a 256-byte boundary
check_exec_loop:
ld a,(bc)
cp (hl)
ret nz
inc hl
inc c
jr nz,check_exec_loop
INIT_EXEC_PROG:
;; called by stage1 loader
;; HL = start of packed data to execute
;; C = 0
ex de,hl ; DE = start of packed data
;; Read starting address (initial checksum = 0)
ld hl,7 ; HL = 00000000 000000111; we will
; shift in 14 bits from 3 initial data
; bytes
read_org_get_input:
call get_5_bits
ret c
ret nz
read_org_loop:
add a,a
jr z,read_org_get_input
adc hl,hl
jr nc,read_org_loop
ld (program_start),hl
load_next_line:
;; HL = next address to place program data
;; DE = address of next packed data byte
ld b,10
ld (hl),1
load_line_get_input:
;; HL = output ptr, DE = input ptr
;; C = accumulated checksum, B = # bytes to next checksum
call get_5_bits
jr c,load_program_finished
jr nz,throw_error
;; data byte OK; A = ddddd100
load_line_loop:
add a,a
jr z,load_line_get_input
rl (hl)
jr nc,load_line_loop
inc hl
ld (hl),1
djnz load_line_loop
;; verify check bits
dec hl
ld a,(hl)
cp l
jr z,load_next_line
;; check bits invalid
throw_error:
ld a,$D3
PATCH_JERROR:
;; stage2 loader should locate the JError routine and replace
;; this with a jump, if possible
cpl
rst $0020
ret
load_program_finished:
;; verify final checksum
ld a,c
and $F8
jr nz,throw_error
;; Program is valid! Let's execute it!
ei
program_start .equ $ + 1
call dummy
;; Simulate pressing Enter, so that the Pause command will
;; exit and program execution will continue.
rst $0038 ; if a key is pressed, this will set
; PSC/LGSC so the key will not be
; recognized again soon
ld a,skEnter
ld (kbdScanCode),a
ld (kbdDebncCnt),a ; if no key is pressed, this will
; prevent kbdScanCode from being
; zeroed out for the next ~80 ms
ret
get_5_bits:
;; Get next encoded character from input
;; C = accumulated checksum
;; DE = input ptr
;; return with carry set if at end of line or end of program
;; return with A = 0 and zero clear if an invalid token found
;; otherwise, return A = value * 8 + 4
;; check that DE < (endPC)
push hl
ld hl,(endPC)
scf
sbc hl,de
pop hl
ret c
ld a,(de)
add a,$100 - tEnter ; sets carry flag if equal to tEnter
ret z
add a,tEnter - tA
cp 27
jr c,get_5_bits_ok
;; check for special chars
push bc
push hl
ld hl,special_chars
ld bc,5
cpir ; does *not* affect carry flag - carry
; flag is still clear due to the
; comparison above
ld a,c
pop hl
pop bc
ret nz
add a,27
get_5_bits_ok:
ld (curPC),de
inc de
xor c
rlca
rlca
rlca
ld c,a
and $F8
or $04
cp a
dummy: ret
nop
nop
nop
nop
nop
.if $ != $D3D3
.error "code misaligned"
.endif
int_start:
push af
push bc
push de
push hl
;; Check for Y= + GRAPH (emergency shutdown)
ld a,$BF
PATCH_READ_KEY_GROUP:
;; stage2 loader should replace this with a call to the
;; normal keypad scan routine if possible (there doesn't
;; seem to be any harm in using port 1 this way, but
;; there's probably a reason TI always includes a delay
;; between the output and input.)
out (1),a
in a,(1)
xor $EE
jr nz,no_force_poweroff
set shift2nd,(iy + shiftFlags)
no_force_poweroff:
USER_INT_CALL:
;; Space for user interrupt routine
ld hl,dummy
;; only try to execute an assembly program if APD counter
;; is active (i.e., GetKey is running), indicating that
;; the calculator is in a (mostly)-stable state
bit apdRunning,(iy + apdFlags)
call nz,check_exec
pop hl
pop de
pop bc
pop af
jp $0038
nop
special_chars:
.db tQuest - tA ; BC = 4
.db tComma - tA ; BC = 3
.db tSpace - tA ; BC = 2
.db tPi - tA ; BC = 1
.db tQuote - tA ; BC = 0
exec_sig_str:
.db tPause, tEnter, tAdd, tAdd
KERNEL_SIZE .equ $ - (progMem - $2000)
.if $ != $D400
.error "code misaligned"
.endif