Skip to content

Instantly share code, notes, and snippets.

@mshroyer
Created June 17, 2017 00:41
Show Gist options
  • Save mshroyer/1546f5ee47eeea3fb5172813ea221cda to your computer and use it in GitHub Desktop.
Save mshroyer/1546f5ee47eeea3fb5172813ea221cda to your computer and use it in GitHub Desktop.
#include "ti86asm.inc"
; ===========================
; Emblem 86 version 1.1 gamma
; ===========================
; Mark's new label
; This is an 86 assembly program that allows users to draw a custom emblem for
; their calculators (on-calc) and install it in a user-interrupt routine so that
; it will be constantly present in the upper-right corners of their screens.
; See the readme file for more information.
; By Mark Shroyer, 12.16.1999.
; [email protected] http://gael.port5.com/
.org _asm_exec_ram
false .equ $00 ; Macro defines for use in my program.
true .equ $01
graphmem .equ $FC00 ; The beginning of the screen memory.
_user_int_checksum .equ $D2FD ; Where user int checksum is stored.
_user_int_routine .equ $D2FE ; Where routine memory starts.
nop
jp Prog_Initiate
.dw 0
.dw FileID
FileID:
.db "Emblem 86 v1.1",Lgamma,0
; =====
; Volatile data:
; This data is intented to possibly change throughout program execution.
Data_IntEnabled:
; Specifies whether the user interrupt flag was set at the beginning of
; program execution so that the closing routine knows whether to re-enable it
; upon termination of the program. This value may also be reset if the user
; tells the program to enable or disable the user-int routine.
.db false
Data_MainMenu_02:
.db " 3. Enable user-int ",0
Data_Icon:
.db %10000000, %00000000, %00000000
.db %10000000, %01010010, %01100101
.db %11001010, %01110101, %01010110
.db %10101010, %01010111, %01100101
.db %11000100, %01010101, %01010101
.db %00011000, %00000000, %00000000
.db %00000000, %00110011, %00000000
.db %00000000, %11001100, %10000000
.db %00000000, %00000000, %00000000
.db %00000000, %10001100, %00000000
.db %00000000, %01001100, %00000000
.db %00000000, %00000000, %00000000
.db %00000001, %00000100, %00000000
.db %00000000, %10001000, %00000000
.db %00000000, %01110000, %00000000
.db %00000000, %00000000, %00000000
; =====
; Static data:
; This data is not supposed to change.
Data_MainMenu_Title:
.db 222," Emblem 86 v1.1",Lgamma," ",0
Data_MainMenu_01:
.db " 1. Veiw/change icon "
.db " 2. Install routine ",0
Data_MainMenu_03:
.db "Press MORE for info. ",0
Data_Toggle_Enable:
.db " 3. Enable user-int ",0
Data_Toggle_Disable:
.db " 3. Disable user-int ",0
Data_Default_Icon:
.db %10000000, %00000000, %00000000
.db %10000000, %01010010, %01100101
.db %11001010, %01110101, %01010110
.db %10101010, %01010111, %01100101
.db %11000100, %01010101, %01010101
.db %00011000, %00000000, %00000000
.db %00000000, %00110011, %00000000
.db %00000000, %11001100, %10000000
.db %00000000, %00000000, %00000000
.db %00000000, %10001100, %00000000
.db %00000000, %01001100, %00000000
.db %00000000, %00000000, %00000000
.db %00000001, %00000100, %00000000
.db %00000000, %10001000, %00000000
.db %00000000, %01110000, %00000000
.db %00000000, %00000000, %00000000
Data_Icon_Frame:
.db %00000011, %11111111, %11111111, %11111111, %11000000
.db %00000010, %00000000, %00000000, %00000000, %01000000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000010, %00000000, %00000000, %00000000, %01110000
.db %00000011, %11111111, %11111111, %11111111, %11110000
.db %00000000, %11111111, %11111111, %11111111, %11110000
.db %00000000, %11111111, %11111111, %11111111, %11110000
Data_Editor_01:
.db "1. Edit icon",0
Data_Editor_02:
.db "2. Clear icon",0
Data_Editor_03:
.db "3. Reload current",0
Data_Editor_04:
.db "4. Restore default",0
Data_Instructions_01:
.db "ENTER = Set pixel",0
Data_Instructions_02:
.db "DEL = Cear pixel",0
Data_About:
.db "Mark Shroyer "
.db "[email protected] "
.db " "
.db "12.16.1999 "
.db "v1.1",Lgamma," ",0
Data_DoneMsg:
.db "Done!",0
; =====
; Program routines:
; This is the program itself.
Prog_Initiate:
ei ; Make sure that interrupts are enabled...
res indicRun,(iy+indicflags) ; Rid of that nasty running indicator.
res appAutoScroll,(iy+appflags) ; Turn off auto-scrolling text
res appTextSave,(iy+appflags) ; Deactivate writing to the text shadow.
ld hl,Data_IntEnabled ; \
ld (hl),false ; \
bit 2,(iy+$23) ; \ Save the condition of the user-interrupt
jr z,Prog_Initiate_01 ; / flag and then clear it.
res 2,(iy+$23) ; /
ld (hl),true ; /
Prog_Initiate_01:
call _flushallmenus ; Clear the remnants of any menus that were up before
; the program was run (if they aren't cleared, the
; calculator will make text scroll vertically when it
; reaches a certain point, because it still thinks that
; menus are up and doesn't want to overwrite them.
call _homeup ; Return text cursor the the upper-left of the screen.
; -----
Prog_MainMenu:
call _clrScrn ; Clear the screen memory and the text shadow.
call Prog_PrepToggle
call Prog_MenuTopBar
call _newline ; Execute a carriage-return
ld hl,Data_MainMenu_01 ; \ Print the first line
call _puts ; / of the menu.
Prog_MainMenu_01:
ld a,0
ld (_curCol),a
ld a,4
ld (_curRow),a
ld hl,Data_MainMenu_02
call _puts
call _newline
ld hl,Data_MainMenu_03
call _puts
Prog_MainMenu_02:
call _getkey
cp k1
jp z,Prog_IconViewer
cp k2
jp z,Prog_Install_Routine
cp k3
jp z,Prog_ToggleInt
cp kNext
jp z,About
cp kExit
jp z,Prog_Terminate
jr Prog_MainMenu_02
; -----
About:
; Brings up the "About" screen, in all its glory....
call _clrScrn
call Prog_MenuTopBar
call _newline
ld hl,Data_About
call _puts
call _getkey
call _clrScrn
jp Prog_MainMenu
; -----
Prog_ToggleInt:
; Toggles the state of the Data_IntEnabled variable (which tells the termination
; routine whether to set the user-int flag or not when the program ends), then
; jumps to a certain point on the menu routine. This can be done because this
; menu routine is really the only thing that calls this function.
ld a,(Data_IntEnabled) ; \
cp true ; \
jr nz,Prog_ToggleInt_01 ; \
ld a,false ; \ Toggle the state of the data flag I put
ld (Data_IntEnabled),a ; > at Data_IntEnabled.
jr Prog_ToggleInt_02 ; /
Prog_ToggleInt_01: ; /
ld a,true ; /
ld (Data_IntEnabled),a ; /
Prog_ToggleInt_02: ; Prog_PrepToggle is called to change the state
call Prog_PrepToggle ; of the text that is displayed on the main menu
; to advertise this function. See Prog_PrepToggle
; itself for more details about this.
jp Prog_MainMenu_01 ; Jump back to just the right point on the menu routine...
; -----
Prog_PrepToggle:
; Using the data about the state of the user-int flag before program execution
; (currently stored at Data_IntEnabled), this routine switches around the text
; for line 3 of the main menu, so that always displays the appropriate command:
; either "Enable user-int" or "Disable user-int", respective to the current
; state of things.
ld a,(Data_IntEnabled)
cp true
jr nz,Prog_PrepToggle_01
ld hl,Data_Toggle_Disable
ld de,Data_MainMenu_02
ld bc,22
ldir
ret
Prog_PrepToggle_01:
ld hl,Data_Toggle_Enable
ld de,Data_MainMenu_02
ld bc,22
ldir
ret
; -----
Prog_MenuTopBar:
; Simple function, draws in the title line that you see on the main menu and a
; few other screens throughout the program.
call _homeup
set textInverse,(iy+textflags)
ld hl,Data_MainMenu_Title
call _puts
res textInverse,(iy+textflags)
ret
; -----
Prog_IconViewer:
; This is the routine that causes and monitors the menu that first comes up
; when one selects option 1 on the main menu.
call _clrScrn
call _homeup
call Prog_MenuTopBar
Prog_IconViewer_s:
call Prog_IconEdit_Refresh
ld hl,_penCol
ld (hl),5
ld hl,_penRow
ld (hl),15
ld hl,Data_Editor_01
call _vputs
ld hl,_penCol
ld (hl),5
ld hl,_penRow
ld (hl),23
ld hl,Data_Editor_02
call _vputs
ld hl,_penCol
ld (hl),5
ld hl,_penRow
ld (hl),31
ld hl,Data_Editor_03
call _vputs
ld hl,_penCol
ld (hl),5
ld hl,_penRow
ld (hl),39
ld hl,Data_Editor_04
call _vputs
Prog_IconViewer_01:
call _getkey
cp k1
jr nz,Prog_Icon_Viewer_02
Prog_IconViewer_01b:
call _clrScrn
call _homeup
call Prog_MenuTopBar
ld hl,_penCol
ld (hl),5
ld hl,_penRow
ld (hl),15
ld hl,Data_Instructions_01
call _vputs
ld hl,_penCol
ld (hl),5
ld hl,_penRow
ld (hl),23
ld hl,Data_Instructions_02
call _vputs
jp Prog_ChangeIcon
Prog_Icon_Viewer_02:
cp kEnter
jr z,Prog_IconViewer_01b ; Jump to the same place that k1 would have
; brought you.
cp k2
jp z,Prog_ClearIcon
cp k3
jp z,Prog_RestoreCurrent
cp k4
jp z,Prog_RestoreDefault
cp kExit
jp z,Prog_MainMenu
jr Prog_IconViewer_01
; -----
Prog_ClearIcon:
; Clears the entire icon.
ld hl,Data_Icon
ld (hl),0
ld de,Data_Icon+1
ld bc,47
ldir
jp Prog_IconViewer_s
; -----
Prog_RestoreDefault:
; Copies 48 bytes from Data_Default_Icon to Data_Icon, restoring the default
; sprite.
ld hl,Data_Default_Icon
ld de,Data_Icon
ld bc,48
ldir
jp Prog_IconViewer_s
; -----
Prog_RestoreCurrent:
; Copies 48 bytes from Icon (which is located in the user-interrupt routine)
; to Data_Icon, taking any installed icon into the program. The user interrupt
; routine does not need to be activated for this to work. If there is something
; besides one of these icons in that space in memory (or nothing at all), this
; will either result in a blank icon or a bunch of garbage, but no harm will be
; done.
ld hl,Icon
ld de,Data_Icon
ld bc,48
ldir
jp Prog_IconViewer_s
; -----
Prog_IconEdit_Refresh:
; Refreshes the image of the sprite Data_Icon and the sprite frame that it is
; overlayed on.
ld hl,Data_Icon_Frame
ld de,graphmem+282
ld b,22
Prog_IconEdit_Refresh_01:
push bc
ld bc,5
ldir
ex de,hl
push de
ld de,11
add hl,de
pop de
ex de,hl
pop bc
djnz Prog_IconEdit_Refresh_01
ld hl,Data_Icon
ld de,graphmem+315
ld b,16
Prog_IconEdit_Refresh_02:
push bc
ld bc,3
ldir
ex de,hl
push de
ld de,13
add hl,de
pop de
ex de,hl
pop bc
djnz Prog_IconEdit_Refresh_02
ret
; -----
Prog_IconEdit_ChangeBit:
; Sets or clears specific bit in Data_Icon. The bit to be modified is
; determined by treating the sprite Data_Icon as a matrix of points, counted
; from the top-left pixel (i.e. bit) using (_penCol) as the abscissa (x
; coordinate) and using (_penRow) as the ordinate (y coordinate). If bit 0 of
; asm_flag1 is set then the bit will be set; otherwise, the bit will be zeroed.
; This routine is based on the same principle as my Set_Pixel function.
ld hl,_penCol
ld b,(hl) ; Load the abscissa into b.
ld hl,_penRow
ld c,(hl) ; Load the ordinate into c.
push bc ; Push the word-register bc onto the stack.
ld hl,0 ; Clear hl so that h can be used as a counter variable.
Prog_IconEdit_ChangeBit_01:
ld a,b ; \ Jump to Prog_IconEdit_ChangeBit_02
cp 8 ; > if b, the abscissa, is less than 8.
jr c,Prog_IconEdit_ChangeBit_02 ; /
sub 8 ; \ Subtract 8 from b (whose value is currently stored in a), load
ld b,a ; > the new value back to b, and increment h.
inc h ; /
jr Prog_IconEdit_ChangeBit_01 ; Loop back to ..._01 to do it again until
; b == mod((abscissa),8) and h == (abscissa)-b.
; From here on in this routine, the following notations may be used:
; (x-whole) = The value of the greatest multiple of 8 less than or equal
; to the value of the abscissa.
; (x-remainder) = The value of mod((abscissa),8)
; (y-offset)/3 = One-third of the byte offset that needs to be added to the
; address of Data_Icon to locate the right byte row (this
; expression is equal to the ordinate).
; (y-offset) = Three times the ordinate.
; (offset) = The total offset from Data_Icon that will be used to locate
; the byte that the pixel in question is located in.
Prog_IconEdit_ChangeBit_02:
ld l,b ; h = (x-whole)
; l = (x-remainder)
; c = (y-offset)/3
ex de,hl ; d = (x-whole)
; e = (x-remainder)
; c = (y-offset)/3
ld hl,Data_Icon ; Initiate the value of (hl), so that the offset can be
; added to it to obtain the address of the byte the
; specific pixel is in.
ld b,0
ld a,c ; a = (y-offset)/3
ld c,d ; c = (x-whole)
add hl,bc ; Add (x-whole) to hl (increasing the offset).
ld c,e ; c = (x-remainder)
ld de,0 ; Zero de so that it can be used as an element in the addition.
ld e,a ; e = (y-offset)/3 (Note that this also sets de to the same value).
ld b,3 ; Load b (the counter variable for the djnz looping operation) with
; three, so that the following loop will be repeated three times:
Prog_IconEdit_ChangeBit_03:
add hl,de ; Add (y-offset)/3 to the running offset total (since this will
; be done three times, it will really be adding (y-offset) to
; the running total).
djnz Prog_IconEdit_ChangeBit_03 ; Decrement b and jump back to ..._03 so
; long as b is greater than 0.
ld a,c ; a = (x-remainder)
pop bc ; Restore bc from the stack.
cp 0 ; Compare (x-remainder) to zero.
jr nz,Prog_IconEdit_ChangeBit_04 ; If not equal, jump to ..._04.
bit 0,(iy+asm_flag1)
jr z,Prog_IconEdit_ChangeBit_03b
set 7,(hl) ; Set the bit (7) and exit routine of bit 0 of asm_flag1
; is set.
ret ; Done.
Prog_IconEdit_ChangeBit_03b:
res 7,(hl) ; Reset the bit (7) and exit the routine, done if bit 0
ret ; of asm_flag1 is not set.
Prog_IconEdit_ChangeBit_04: ; The same deal, this time testing for bit 6...
cp 1
jr nz,Prog_IconEdit_ChangeBit_05
bit 0,(iy+asm_flag1)
jr z,Prog_IconEdit_ChangeBit_04b
set 6,(hl)
ret
Prog_IconEdit_ChangeBit_04b:
res 6,(hl)
ret
Prog_IconEdit_ChangeBit_05:
cp 2
jr nz,Prog_IconEdit_ChangeBit_06
bit 0,(iy+asm_flag1)
jr z,Prog_IconEdit_ChangeBit_05b
set 5,(hl)
ret
Prog_IconEdit_ChangeBit_05b:
res 5,(hl)
ret
Prog_IconEdit_ChangeBit_06:
cp 3
jr nz,Prog_IconEdit_ChangeBit_07
bit 0,(iy+asm_flag1)
jr z,Prog_IconEdit_ChangeBit_06b
set 4,(hl)
ret
Prog_IconEdit_ChangeBit_06b:
res 4,(hl)
ret
Prog_IconEdit_ChangeBit_07:
cp 4
jr nz,Prog_IconEdit_ChangeBit_08
bit 0,(iy+asm_flag1)
jr z,Prog_IconEdit_ChangeBit_07b
set 3,(hl)
ret
Prog_IconEdit_ChangeBit_07b:
res 3,(hl)
ret
Prog_IconEdit_ChangeBit_08:
cp 5
jr nz,Prog_IconEdit_ChangeBit_09
bit 0,(iy+asm_flag1)
jr z,Prog_IconEdit_ChangeBit_08b
set 2,(hl)
ret
Prog_IconEdit_ChangeBit_08b:
res 2,(hl)
ret
Prog_IconEdit_ChangeBit_09:
cp 6
jr nz,Prog_IconEdit_ChangeBit_10
bit 0,(iy+asm_flag1)
jr z,Prog_IconEdit_ChangeBit_09b
set 1,(hl)
ret
Prog_IconEdit_ChangeBit_09b:
res 1,(hl)
ret
Prog_IconEdit_ChangeBit_10:
bit 0,(iy+asm_flag1)
jr z,Prog_IconEdit_ChangeBit_10b
set 0,(hl)
ret
Prog_IconEdit_ChangeBit_10b:
res 0,(hl)
ret
; -----
Prog_ChangeIcon:
; This is the input loop for the icon editing. It checks for the following
; keypresses:
; - up
; - down
; - left
; - right
; - enter
; - delete
; - exit
ld hl,_penCol ; \
ld (hl),0 ; \ Zero the coordinates of the cursor so that it starts in
ld hl,_penRow ; / the upper-left corner of the editing window.
ld (hl),0 ; /
Prog_ChangeIcon_01:
call Prog_IconEdit_Refresh ; Redraw the icon.
ld a,(_penCol) ; \
cp 24 ; |
jr c,Prog_ChangeIcon_02 ; |
ld a,23 ; |
ld (_penCol),a ; | Checks for clipping in the
Prog_ChangeIcon_02: ; | coordinate values stored in
ld a,(_penRow) ; > the variables _penCol and
cp 16 ; | _penRow for the coordinates
jr c,Prog_ChangeIcon_03 ; | of the edit box cursor.
ld a,15 ; |
ld (_penRow),a ; |
Prog_ChangeIcon_03: ; /
ld a,(_penCol) ; \ Add the appropriate offesets to
add a,88 ; \ the edit-box coordinates of the
ld b,a ; \ cursor and store those values
ld a,(_penRow) ; > in the b and c registers
add a,19 ; / so that the cursor can be drawn
ld c,a ; / at screen position ( b,c ) by
call Prog_DrawCursor ; / the Prog_DrawCursor routine.
call _getkey
cp kUp
jr nz,Prog_ChangeIcon_11
ld hl,_penRow
ld a,(hl)
cp 0
jr z,Prog_ChangeIcon_01
dec (hl)
jr Prog_ChangeIcon_01
Prog_ChangeIcon_11:
cp kDown
jr nz,Prog_ChangeIcon_12
ld hl,_penRow
inc (hl)
Prog_ChangeIcon_12:
cp kLeft
jr nz,Prog_ChangeIcon_13
ld hl,_penCol
ld a,(hl)
cp 0
jr z,Prog_ChangeIcon_01
dec (hl)
jr Prog_ChangeIcon_01
Prog_ChangeIcon_13:
cp kRight
jr nz,Prog_ChangeIcon_14
ld hl,_penCol
inc (hl)
Prog_ChangeIcon_14:
cp kEnter
jr nz,Prog_ChangeIcon_15
set 0,(iy+asm_flag1)
call Prog_IconEdit_ChangeBit
jr Prog_ChangeIcon_01
Prog_ChangeIcon_15:
cp kDel
jr nz,Prog_ChangeIcon_16
res 0,(iy+asm_flag1)
call Prog_IconEdit_ChangeBit
jr Prog_ChangeIcon_01
Prog_ChangeIcon_16:
cp kExit
jp z,Prog_IconViewer
jr Prog_ChangeIcon_01
; -----
Prog_DrawCursor:
; Draws the crosshair cursor on the screen at point ( b,c ). Does not check
; for clipping, but both the SetPixel routine that uses and the
; Prog_ChangeIcon routine that it is called by do.
dec b
call SetPixel
dec b
call SetPixel
ld a,b
add a,3
ld b,a
call SetPixel
inc b
call SetPixel
ld a,b
sub 2
ld b,a
dec c
call SetPixel
dec c
call SetPixel
ld a,c
add a,3
ld c,a
call SetPixel
inc c
jp SetPixel
; -----
SetPixel:
; Sets the pixel at screen coordinate ( b , c ). Checks for clipping. This
; routine considers the origin to be at the upper-left corner of the screen.
; Throughout this routine's comments, some of the following notation may be
; used:
; (x-whole) = The value of the greatest multiple of 8 less than or equal
; to the value of the abscissa.
; (x-remainder) = The value of mod((abscissa),8)
; (y-offset)/16 = One sixteenth of the byte offset that needs to be added to
; the address of Data_Icon to locate the correct byte row (this
; expression is equal to the ordinate).
; (y-offset) = Sixteen times the ordinate, the value of the memory offset
; created by the ordinate.
; (offset) = The total offset from Data_Icon that will be used to locate
; the byte that the pixel in question is located in.
ld a,b
cp 128
ret nc ; Return if x-coordinate is greater than or equal to 128.
ld a,c
cp 64
ret nc ; Return if y-coordinate is greater than or equal to 64.
push bc ; Push the word (bc) onto the stack so that it can be restored
; when this routine is finished.
ld hl,0 ; Zero hl so that h can be used as a counter variable.
SetPixel_01:
ld a,b ; \ If b is less than 8, jump to
cp 8 ; | SetPixel_02.
jr c,SetPixel_02 ; /
sub 8 ; \ Subtract 8 from the value of b (currently stored in a),
ld b,a ; | load the new value into b, and increment h, the counter
inc h ; / register.
jr SetPixel_01
SetPixel_02:
ld l,b ; h = (x-whole)
; l = (x-remainder)
; c = (y-offset)/16
ex de,hl ; d = (x-whole)
; e = (x-remainder)
; c = (y-offset)/16
ld hl,graphmem ; Initiate hl, which will contain the memory address of the
; byte this pixel is located in. From here, the offset can
; simply be added to hl to obtain the correct address.
ld b,0
ld a,c ; a = (y-offset)/16
ld c,d ; bc = (x-whole)
add hl,bc ; hl = graphmem+(x-whole)
ld c,e ; c = (x-remainder)
ld e,a ; e = (y-offset)/16
ld d,0 ; Allows de to be equal to e, by zeroing the most signifigant byte.
ld b,16 ; B will be used as the counter register in the following loop. The
; loop will, therefore, have 16 iterations.
SetPixel_03:
add hl,de ; Add (y-offset)/16 to the running total of the offset. Since,
; due to the loop, this will be done 16 times, this would be the
; same as adding (y-offset) to hl.
; HL = graphmem+(x-whole)+(y-offset) = Address of pixel's byte.
djnz SetPixel_03 ; Decrement b and loop back to SetPixel_03 if b is
; still greater than zero.
ld a,c ; a = (x-remainder)
pop bc ; Pop bc back off the stack, restoring the original values.
cp 0 ; If (x-remainder) is not 0,
jr nz,SetPixel_04 ; jump to SetPixel_04.
set 7,(hl) ; Set bit 7 (the first bit) of (hl).
ret ; Done.
SetPixel_04:
cp 1 ; If (x-remainder) is not 1,
jr nz,SetPixel_05 ; jump to SetPixel_05.
set 6,(hl) ; Set bit 6 (the second bit) of (hl).
ret ; Done.
SetPixel_05:
cp 2 ; If (x-remainder) is not 2,
jr nz,SetPixel_06 ; jump to SetPixel_06.
set 5,(hl) ; You get the picture...
ret
SetPixel_06:
cp 3
jr nz,SetPixel_07
set 4,(hl)
ret
SetPixel_07:
cp 4
jr nz,SetPixel_08
set 3,(hl)
ret
SetPixel_08:
cp 5
jr nz,SetPixel_09
set 2,(hl)
ret
SetPixel_09:
cp 6
jr nz,SetPixel_10
set 1,(hl)
ret
SetPixel_10:
set 0,(hl)
ret
; -----
Prog_Terminate:
; Closes the program.
ld a,(Data_IntEnabled) ; \ If the user-int flag wasn't set when
cp true ; > the program started, jump to
jr nz,Prog_Terminate_01 ; / Prog_Terminate_01.
set 2,(iy+$23) ; Set the user-int flag.
Prog_Terminate_01:
set indicRun,(iy+indicflags) ; Re-activate the "running" indicator.
set appAutoScroll,(iy+appflags) ; Turn text scrolling back on.
set appTextSave,(iy+appflags) ; Turn the text shadow back on.
call _homeup ; Return cursor to top-left of the screen.
jp _clrScrn ; Clear the screen memory and the text shadow.
; -----
Prog_Install_Routine:
ld hl,User_Int_Routine ; Load source address into hl.
ld de,_user_int_routine ; Load destination address into bc.
ld bc,IntEnd-IntStart ; Load length of source into bc.
ldir ; Copy the data.
ld hl,Data_Icon ; Copy the icon. Must be done before
ld de,Icon ; checksum calculation.
ld bc,48
ldir
ld a,(_user_int_routine) ; \
ld hl,_user_int_routine+($28*1)-1 ; \
add a,(hl) ; \
ld hl,_user_int_routine+($28*2)-1 ; \
add a,(hl) ; \
ld hl,_user_int_routine+($28*3)-1 ; \ Claculate and store checksum
add a,(hl) ; / of user interrupt routine.
ld hl,_user_int_routine+($28*4)-1 ; /
add a,(hl) ; /
ld hl,_user_int_routine+($28*5)-1 ; /
add a,(hl) ; /
ld (_user_int_checksum),a ; /
ld hl,Data_IntEnabled ; Set Data_IntEnabled, which specifies whether the
ld (hl),true ; user-int routine should be reactivated when the
; program terminates, on.
call _clrScrn
call _homeup
ld hl,Data_DoneMsg ; Load the "Done!" message and
call _puts ; paste it on the screen.
ld b,60 ; Load 60 into b, the counter register for the djnz loop:
Prog_Install_Routine_01:
halt ; Halt the processor and put it into low-power mode until an
; interrupt occurs. Since the next interrupt will almost certainly
; be caused by the quartz timer, which sets off a maintenance
; interrupt at 200 Hz (200 times a second), the program will pause
; 60 times, each time for 1/200 of a second.
djnz Prog_Install_Routine_01 ; Decrement b and loop back to ..._01 if
; b is greater than zero.
jp Prog_MainMenu ; Jump back t the main menu routine.
; =====
; Below is the user interrupt routine that this program installs. None of this
; code is run during program execution.
User_Int_Routine:
.org _user_int_routine ; set base address to _user_int_routine
IntStart:
ld hl, $FC00+13 ; HL points to display
ld de, Icon ; DE points to start of sprite
ld b, 16 ; B is counter: There are 16 rows to the sprite.
Loop:
ld a,(de) ; Get byte from sprite
ld (hl), a ; Display byte on screen
inc de
inc hl
ld a,(de) ; Get next byte (will be on same line).
ld (hl),a ; Display byte on screen.
inc de
inc hl
ld a,(de)
ld (hl),a
inc de
push bc
ld bc,14
add hl,bc
pop bc
djnz Loop ; Loop back if there is another row to be printed.
ret
.dw $0000 ; I insert a word here so that this program
; does not use the same memory for the sprite as
; another of my programs does, preventing the two
; from being incompatible... hard to explain, but
; it does have a purpose.
; (Feel free to remove those two bytes, then, if your calc's
; _that_ short on memory... :P)
Icon:
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
.db $00, $00, $00
IntEnd:
; =====
.end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment