Created
June 17, 2017 00:41
-
-
Save mshroyer/1546f5ee47eeea3fb5172813ea221cda to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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