Difference between revisions of "Z80:Miscellaneous Routines"
KermMartian (talk | contribs) (Created page with "A list of small routines that can help you. Feel free to add your own. = Battery Status = Directly polls the hardware for battery status. Thanks to Steve Riekeberg. ;N...") |
KermMartian (talk | contribs) |
||
Line 89: | Line 89: | ||
= Direct Input = | = Direct Input = | ||
− | Used for direct input. See [[Z80:Direct | + | Used for direct input. See [[Z80:Direct-input-output|here]] to learn more about direct input. Thanks to Steve Riekeberg. |
Line 154: | Line 154: | ||
out (10h),a ;Turn the LCD back on | out (10h),a ;Turn the LCD back on | ||
res onKey,(iy+keyFlags) | res onKey,(iy+keyFlags) | ||
+ | |||
+ | = Find Next App = | ||
+ | This routine is useful if you want to manually search through the installed apps on a calculator. | ||
+ | |||
+ | FindNextApp: | ||
+ | ;Inputs: | ||
+ | ; B is the base page of the app. | ||
+ | ;Outputs: | ||
+ | ; c flag set if the field was found | ||
+ | ; nc means the app header subfield was not found | ||
+ | ; B is the number of pages of the app | ||
+ | ; A is the page of the next app | ||
+ | ; H is the input page number | ||
+ | ; L is the page number of the currently swapped in page in bank 1 | ||
+ | ; | ||
+ | ;Comments: | ||
+ | ; This code must run in RAM | ||
+ | in a,(6) | ||
+ | ld c,a | ||
+ | push bc ;b is the app page, c is the current page | ||
+ | ld a,b | ||
+ | out (6),a | ||
+ | call FindNumPages | ||
+ | pop hl ;h is the app page, l is the current page | ||
+ | ld b,a | ||
+ | ld a,l | ||
+ | out (6),a | ||
+ | ld a,h | ||
+ | ret nc | ||
+ | sub b | ||
+ | scf | ||
+ | ret | ||
+ | FindNumPages: | ||
+ | ;Outputs: | ||
+ | ; c flag set if the field was found | ||
+ | ; nc means the app header subfield was not found | ||
+ | ; A is the number of app pages | ||
+ | ; B is 0 | ||
+ | ; (HL) is the number of app pages | ||
+ | ld hl,4000h | ||
+ | ld bc,128 | ||
+ | ld a,c | ||
+ | or a | ||
+ | FNPLoop: | ||
+ | cpir | ||
+ | ret po | ||
+ | ret nz | ||
+ | inc a | ||
+ | cp (hl) | ||
+ | jr z,$+6 | ||
+ | dec a | ||
+ | jp FNPLoop | ||
+ | inc l | ||
+ | ld a,(hl) | ||
+ | scf | ||
+ | ret | ||
+ | |||
+ | = IncHLMem1 = | ||
+ | When reading through data in MemBank1, this routine is particularly useful as it adjusts the flash pages accordingly, as well as the pointer HL. If HL does not point to data in MemBank1 (4000h~7FFFh) then HL will simply be incremented, which is useful if the data might be in RAM or flash. | ||
+ | |||
+ | IncHLMem1: | ||
+ | inc l ; 4 4*16384 65536 | ||
+ | ret nz ;11| 5 64*5+16320*11 179840 | ||
+ | inc h ; 4 4*64 256 | ||
+ | ret po ;11| 5 11*63+5 698 | ||
+ | ld h,a | ||
+ | in a,(6) ; 11 11 11 | ||
+ | inc a ; 4 4 4 | ||
+ | out (6),a ; 11 11 11 | ||
+ | ld a,h | ||
+ | ld h,40h ; 7 7 7 | ||
+ | ret ; 10 10 | ||
+ | |||
+ | It destroys no registers and is very efficient. However, if you are really in need of speed, such as with a ReadArc routine, you can try something like this (conditionally calling the routine): | ||
+ | |||
+ | inc l | ||
+ | call z,IncMem1Ptr | ||
+ | <<rest of code>> | ||
+ | |||
+ | IncMem1ptr | ||
+ | inc h ; 4 4*64 256 | ||
+ | ret po ;11| 5 11*63+5 698 | ||
+ | ld h,a | ||
+ | in a,(6) ; 11 11 11 | ||
+ | inc a ; 4 4 4 | ||
+ | out (6),a ; 11 11 11 | ||
+ | ld a,h | ||
+ | ld h,40h ; 7 7 7 | ||
+ | ret ; 10 10 | ||
+ | |||
+ | = SortA = | ||
+ | This code is not as efficient as it could be, but it works. it sorts a bunch of bytes to be in ascending order: | ||
+ | |||
+ | SortA: | ||
+ | ;Inputs: | ||
+ | ; BC is the size | ||
+ | ; HL is where the data is located | ||
+ | ;Takes at least n iterations, at most n(n+1)/2 | ||
+ | ld d,h | ||
+ | ld e,l | ||
+ | SortALoop: | ||
+ | push bc | ||
+ | push de | ||
+ | ld a,(hl) | ||
+ | call SwapBytes | ||
+ | SortLoop1: | ||
+ | jp po,NextSort | ||
+ | cp (hl) | ||
+ | cpi | ||
+ | jr c,SortLoop1 | ||
+ | dec hl | ||
+ | call z,SwapBytes | ||
+ | jr c,SortLoop1 | ||
+ | EndSwap: | ||
+ | pop de | ||
+ | jr SortALoop+1 | ||
+ | NextSort: | ||
+ | pop hl | ||
+ | pop bc | ||
+ | dec hl | ||
+ | add hl,bc | ||
+ | or a | ||
+ | sbc hl,de | ||
+ | ret c | ||
+ | ret z | ||
+ | ld b,h | ||
+ | ld c,l | ||
+ | inc bc | ||
+ | ex de,hl | ||
+ | jp SortA+1 | ||
+ | SwapBytes: | ||
+ | inc bc | ||
+ | push af | ||
+ | ld a,(de) | ||
+ | ldi | ||
+ | dec hl | ||
+ | ld (hl),a | ||
+ | inc hl | ||
+ | pop af | ||
+ | scf | ||
+ | ret | ||
+ | |||
+ | = Set15MHz = | ||
+ | This routine will set the calculator to 15MHz mode if possible: | ||
+ | |||
+ | Set15MHz: | ||
+ | ;Ouputs: | ||
+ | ; Sets the calculator to 15MHz if possible | ||
+ | ; z flag set if the calc is at 6MHz, nz if at 15MHz | ||
+ | in a,(2) | ||
+ | rlca | ||
+ | and 1 | ||
+ | out (20h),a | ||
+ | ret | ||
+ | |||
+ | = Set6MHz = | ||
+ | This is pretty tiny (3 bytes) so it isn't worth making it a subroutine. In other words, just use it inline: | ||
+ | |||
+ | xor a | ||
+ | out (20h),a | ||
Revision as of 05:53, 5 February 2016
A list of small routines that can help you. Feel free to add your own.
Contents
Battery Status
Directly polls the hardware for battery status. Thanks to Steve Riekeberg.
;Name: BatteryStatus ;Description: Returns if the batteries are good, or low and need changing. ;Inputs: None ;Outputs: Non-Zero = Good Batteries Zero = Batteries Low ;Destroys: A GetBatteryStatus: in a, (2) and 01h ret
Boundary Check
Checks if coordinates is inside a designated box. Thanks to Adm. Wiggin.
; Your box coords (will not work with 0, keep x1 < x2, and y1 < y2 [duh]) #define x1 10 #define y1 10 #define x2 20 #define y2 30 check: ; a = x ; b = y ; returns c flag set if good ; returns c flag reset if no good (nc) ; destorys af (quite obvious if one knows any z80 at all) cp x1 jr c,nogood cp x2+1 jr nc,nogood ld a,b cp y1 jr c,nogood cp y2+1 jr nc,nogood ;if it gets here, it's in the box! Yay! Hooray! Peoples rejoice! ; as a side effect of the last operation, the carry flag is already set. ret nogood: or a;to reset the carry flag ret
Center Text
Displays a string centered on the screen (small font). Thanks to WikiGuru.
;input:hl points to string ;output: string displayed centered on screen ;destroyed: all registers ;other remarks: (penrow) must be set before calling this sub-routine ; first byte of string must be the length of the string centertxt: bcall(_SStringLength) ld a,96 ;width of screen sub b ;subtract width of string rra ;divide by 2 to be centered ld (pencol),a ld b,(hl) inc hl bcall(_VPutSN) ret ;to call: ... ld hl,0 ld (penrow),hl ld hl,txtTest call centertxt ... txtTest: .db 11,"Sample Text"
Direct Input
Used for direct input. See here to learn more about direct input. Thanks to Steve Riekeberg.
;Name: DirectInput ;Inputs: A = Key Group ;Outputs: A = Key Code; Zero If None ;Destroys: A, B DirectInput: ld b,a ld a,$ff ;Reset the keypad out (1),a ld a,b out (1),a in a,(1) ret
Hotspot
Checks if h>b, l>c, h<d, and l<e. Thanks to kermmartian and DarkerLine.
;----------Hot spot detection----------- ;inputs: b,c (first x and y cor) ; d,e (last x and y cor) ; h,l (current x,y) ;output: "c" flag [either true (set) or false (reset)] hdetect: ld a,h cp b ccf ret nc cp d ret nc ld a,l cp c ccf ret nc cp e ret
On/Off Calc
Turns the calculator "off" and waits for user to press on. Note: Pulling batteries out will result in Ram Clear. Thanks to Taricorp.
;no inputs ld a,02h out (10h),a ;Turn off LCD ld a,08h out (3),a call LCD_Delay ld a,36h out (4),a ld a,01h out (3),a halt ;It halts until ON is pressed ld a,0Bh out (3),a ld a,03h out (10h),a ;Turn the LCD back on res onKey,(iy+keyFlags)
Find Next App
This routine is useful if you want to manually search through the installed apps on a calculator.
FindNextApp: ;Inputs: ; B is the base page of the app. ;Outputs: ; c flag set if the field was found ; nc means the app header subfield was not found ; B is the number of pages of the app ; A is the page of the next app ; H is the input page number ; L is the page number of the currently swapped in page in bank 1 ; ;Comments: ; This code must run in RAM in a,(6) ld c,a push bc ;b is the app page, c is the current page ld a,b out (6),a call FindNumPages pop hl ;h is the app page, l is the current page ld b,a ld a,l out (6),a ld a,h ret nc sub b scf ret FindNumPages: ;Outputs: ; c flag set if the field was found ; nc means the app header subfield was not found ; A is the number of app pages ; B is 0 ; (HL) is the number of app pages ld hl,4000h ld bc,128 ld a,c or a FNPLoop: cpir ret po ret nz inc a cp (hl) jr z,$+6 dec a jp FNPLoop inc l ld a,(hl) scf ret
IncHLMem1
When reading through data in MemBank1, this routine is particularly useful as it adjusts the flash pages accordingly, as well as the pointer HL. If HL does not point to data in MemBank1 (4000h~7FFFh) then HL will simply be incremented, which is useful if the data might be in RAM or flash.
IncHLMem1: inc l ; 4 4*16384 65536 ret nz ;11| 5 64*5+16320*11 179840 inc h ; 4 4*64 256 ret po ;11| 5 11*63+5 698 ld h,a in a,(6) ; 11 11 11 inc a ; 4 4 4 out (6),a ; 11 11 11 ld a,h ld h,40h ; 7 7 7 ret ; 10 10
It destroys no registers and is very efficient. However, if you are really in need of speed, such as with a ReadArc routine, you can try something like this (conditionally calling the routine):
inc l call z,IncMem1Ptr <<rest of code>> IncMem1ptr inc h ; 4 4*64 256 ret po ;11| 5 11*63+5 698 ld h,a in a,(6) ; 11 11 11 inc a ; 4 4 4 out (6),a ; 11 11 11 ld a,h ld h,40h ; 7 7 7 ret ; 10 10
SortA
This code is not as efficient as it could be, but it works. it sorts a bunch of bytes to be in ascending order:
SortA: ;Inputs: ; BC is the size ; HL is where the data is located ;Takes at least n iterations, at most n(n+1)/2 ld d,h ld e,l SortALoop: push bc push de ld a,(hl) call SwapBytes SortLoop1: jp po,NextSort cp (hl) cpi jr c,SortLoop1 dec hl call z,SwapBytes jr c,SortLoop1 EndSwap: pop de jr SortALoop+1 NextSort: pop hl pop bc dec hl add hl,bc or a sbc hl,de ret c ret z ld b,h ld c,l inc bc ex de,hl jp SortA+1 SwapBytes: inc bc push af ld a,(de) ldi dec hl ld (hl),a inc hl pop af scf ret
Set15MHz
This routine will set the calculator to 15MHz mode if possible:
Set15MHz: ;Ouputs: ; Sets the calculator to 15MHz if possible ; z flag set if the calc is at 6MHz, nz if at 15MHz in a,(2) rlca and 1 out (20h),a ret
Set6MHz
This is pretty tiny (3 bytes) so it isn't worth making it a subroutine. In other words, just use it inline:
xor a out (20h),a