;;; -*- TI-Asm -*- ;;; ;;; Mimas - Assembly language IDE for the TI-83 Plus ;;; ;;; 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 . ;; CompareStrings: ;; ;; Compare two zero-terminated strings, ignoring case. (abc is ;; considered equal to ABC.) ;; ;; To be precise: NUL < '_' < ' ' < '!' < ... < '@' = '`' < 'A' = 'a' ;; < ... < 'Z' = 'z' < '[' = '{' < '\' = '|' < ']' = '}' < '~' = '^'. ;; ;; Input: ;; - HL = address of first string ;; - DE = address of second string ;; ;; Output: ;; - Zero flag set (and carry flag reset) if two strings are equal ;; - Carry flag set if string at HL is alphabetically earlier than the ;; string at DE ;; - If strings are not equal, HL and DE are set to the respective ;; addresses of the first byte that differs. ;; ;; Destroys: ;; - AF, BC, DE, HL ; P1_CompareStrings_Loop: ; inc de ; inc hl ; or a ; ret z ; P1_CompareStrings: ; ld a,(de) ; cp (hl) ; jr z,P1_CompareStrings_Loop ; call P1_CompareStrings_Norm ; ld b,a ; ld a,(hl) ; call P1_CompareStrings_Norm ; cp b ; jr z,P1_CompareStrings_Loop ; ret P1_CompareStrings_Norm: or a ret z sub '_' - 1 ret c cp 1 ret z sub 20h ret ;; BSearch2: ;; ;; Search a sorted array of 2-byte entries. ;; ;; The callback function is called with the given value in DE, and the ;; address of an array element in HL. It must return with the zero ;; flag set if HL "equals" DE, or with the carry flag set if HL is ;; "less than" DE. The callback function must preserve DE if it cares ;; about the value, but it need not preserve HL, BC, or AF. ;; ;; Input: ;; - HL = address of first element ;; - BC = number of elements ;; - DE = search key ;; - IX = comparison function ;; ;; Output: ;; - If an exact match was found, zero flag set and HL is the address ;; of the matching array element ;; - If an exact match was not found, zero flag clear and HL is the ;; address of the first array element that is "greater" than DE. ;; (If there are none, then HL will equal the sum of the input HL ;; and BC.) ;; ;; Destroys: ;; - AF, BC P1_BSearch2_UpperHalf: pop hl pop af pop bc ;; top half has size ceil(BC / 2) - 1 = floor((BC - 1) / 2) inc hl inc hl dec bc P1_BSearch2_Continue: srl b rr c P1_BSearch2: ld a,b or c jr z,P1_BSearch_Failed push bc push hl ;; add 2 * floor(BC / 2) res 0,c add hl,bc push hl call P1_Call_IX jr z,P1_BSearch2_Success jr c,P1_BSearch2_UpperHalf pop af pop hl pop bc ;; bottom half has size floor(BC / 2) jr P1_BSearch2_Continue P1_BSearch2_Success: pop hl pop bc pop bc ret P1_BSearch_Failed: inc a ret ;; BSearchS: ;; ;; Search a sorted list of variable-length entries, such as ;; zero-terminated strings or compressed symbol strings. ;; ;; The callback function is called with the given value in DE, and an ;; arbitrary address in the list (which might either be at the start ;; or the middle of an entry) in HL. It must do one of the following: ;; ;; - Set HL to the address of the start of the given entry, and return ;; with the zero flag set, indicating that the given entry "equals" ;; DE; ;; - Set HL to the address of the start of the given entry, and return ;; with zero and carry flags reset, indicating that the given entry ;; is "greater" than DE; or ;; - Set HL to the address of the start of the *next* entry, and ;; return with zero flag reset and carry flag set, indicating that ;; the given entry is "less" than DE. ;; ;; The callback function must preserve DE if it cares about the value, ;; but it need not preserve BC or AF. ;; ;; Note that the list usually needs to have a sentinel value placed ;; before the first byte, and occasionally also after the last byte, ;; so that the callback function will be able to identify the start ;; and end of the first and last string in the list, respectively. ;; ;; Input: ;; - HL = address of start of list ;; - BC = address of byte following end of list ;; - DE = search key ;; - IX = seek-and-compare function ;; ;; Output: ;; - If an exact match was found, zero flag set and HL is the address ;; of the matching array element ;; - If an exact match was not found, zero flag clear and HL is the ;; address of the first array element that is "greater" than DE. ;; (If there are none, HL equals the input BC.) ;; ;; Destroys: ;; - AF, BC P1_BSearchS_UpperHalf: pop bc pop af P1_BSearchS: xor a sbc hl,bc add hl,bc jr z,P1_BSearch_Failed jr nc,P1_BSearchS_Error push hl push bc add hl,bc rr h rr l call P1_Call_IX jr z,P1_BSearchS_Success jr c,P1_BSearchS_UpperHalf ld b,h ld c,l pop af pop hl jr P1_BSearchS P1_BSearchS_Success: pop bc pop bc ret P1_BSearchS_Error: ;; If we ever get here, it means that either the array was not ;; properly terminated, or there is a bug in the callback ;; function. BCALL _ErrSignChange ;; UNREACHABLE ;; Call_IX: ;; ;; Call IX. ;; ;; Input: ;; - IX = address to be called P1_Call_IX: jp (ix) ;; SFont_Len_A: ;; ;; Get the width of a small font character. ;; ;; Input: ;; - A = character ;; ;; Output: ;; - A = B = character width ;; ;; Destroys: ;; - F P1_SFont_Len_A: push hl ld l,a ld h,0 add hl,hl add hl,hl add hl,hl push de BCALL _SFont_Len pop de ld a,b pop hl ret ;; CenterString: ;; ;; Given a zero-terminated string, determine the pixel column to place ;; it so that it will be centered on the screen. ;; ;; Input: ;; - HL = address of string ;; ;; Output: ;; - A = (penCol) = starting pixel column ;; ;; Destroys: ;; - AF, BC P1_CenterString: push hl xor a P1_CenterString_Loop: ld c,a ld a,(hl) inc hl or a jr z,P1_CenterString_Done call P1_SFont_Len_A add a,c jr P1_CenterString_Loop P1_CenterString_Done: pop hl ld a,SCREEN_WIDTH + 1 sub c rra ld (penCol),a ret ;; KeyToChar: ;; ;; Convert a keypress value into the corresponding ASCII character, if ;; any. ;; ;; Input: ;; - A = primary keycode ;; - (keyExtend) = extended keycode ;; - haveDBKey, (iy + DBKeyFlags) = 1 if key comes from external ;; keyboard ;; ;; Output: ;; - Zero flag set if key corresponds to a single-character token ;; - A = character value ;; ;; Destroys: ;; - AF, DE, HL P1_KeyToChar: cp EchoStart ret c ld e,a ;; replace '?' with '_' (but only if typed at calculator ;; keypad, not if using TI-Keyboard) bit haveDBKey,(iy + DBKeyFlags) jr nz,P1_KeyToChar_Normal cp kQuest ld a,Lunderscore ret z P1_KeyToChar_Normal: ;; replace '*' with a cross symbol ld a,e cp kMul ld a,Lcross ret z ld d,0 ld a,e cp kExtendEcho3 jr c,P1_KeyToChar_1Byte ld d,e ld a,(keyExtend) ld e,a P1_KeyToChar_1Byte: BCALL _KeyToString ld a,(hl) dec a ret nz inc hl ld a,(hl) ret ;; GetKeyCursor: ;; ;; Get a keypress, displaying a blinking small-font cursor while we ;; wait. ;; ;; Input: ;; - (penCol) = X coordinate of cursor plus 1 ;; - (penRow) = Y coordinate of cursor ;; ;; Output: ;; - A = keycode ;; ;; Destroys: ;; - F, BC, DE, HL ;; - curRow, curCol P1_GetKeyCursor: ;; We don't use the built-in small font cursor, since it (a) ;; is ugly, and (b) gives no indication of the shift state. ld hl,0F00h ld (curRow),hl in a,(6) ld hl,P1_SmallCursorHook BCALL _SetCursorHook BCALL _CursorOn call P1_GetKey BCALL _CursorOff BCALL _ClrCursorHook BCALL _RestoreTR ret P1_SmallCursorHook: db 83h cp 24h jr z,P1_SmallCursorHook_Erase BCALL _IsEditFull ld d,LcurFull jr z,P1_SmallCursorHook_Indic ld a,(flags + shiftFlags) bit shift2nd,a ld d,LcurO2 jr nz,P1_SmallCursorHook_Indic bit shiftAlpha,a jr z,P1_SmallCursorHook_NoShift inc d and 1 << shiftLwrAlph jr z,P1_SmallCursorHook_Indic inc d P1_SmallCursorHook_Indic: BCALL _SaveTR ld a,d BCALL _PutMap jr P1_SmallCursorHook_Finish P1_SmallCursorHook_NoShift: BCALL _RestoreTR P1_SmallCursorHook_Finish: set textInverse,(iy + textFlags) P1_SmallCursorHook_Erase: ld hl,penCol dec (hl) push ix BCALL _VPutBlank pop ix res textInverse,(iy + textFlags) cp a ret ;; GetKey: ;; ;; Get a keypress using the system's key handler. ;; ;; Output: ;; - A = keycode ;; ;; Destroys: ;; - F, DE, HL P1_GetKey: res onInterrupt,(iy+onFlags) BCALL _GetKey ret