;;; -*- 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