This program is supposed to have 2 timers wich count at different rates
The main file:
Code: Select all
.NOLIST
#define EQU .equ
#define equ .equ
#define END .end
#define end .end
#define DB .db
#define db .db
#define DW .dw
#define dw .dw
#include "ti83plus.inc"
.LIST
#define correctoverflows
queue_size equ 20
.org 9D93h
.db $BB,$6D
call install
ld hl,text
bcall(_puts) ; Disables interrutps
ei
call eventloop
im 1
ret
text:
db " Mode 2!!", 0
evthand1_code:
ld hl, 0
inc hl
ld (evthand1_code + 1), hl
ld de, 0
ld (currow), de
B_CALL(_disphl)
ret
evthand2_code:
ld hl, 0
inc hl
ld (evthand2_code + 1), hl
ld de, 1
ld (currow), de
B_CALL(_disphl)
ret
;----[ DATA ]---------------------------------------------------------------
lst_timedevents:
db 2 ; Amount
db 1, 45 ; evthand1_nr, evthand1_timer
dw 0 ; evthand1_data
db 2, 60 ; evthand2_nr, evthand2_timer
dw 0 ; evthand2_data
lut_maxtimers:
db 0, 45, 60
lut_eventhandlers:
dw 0
dw evthand1_code
dw evthand2_code
eventpointer:
dw eventqueue
eventqueue:
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0
db 0, 0, 0 ; Zero-extension
db $FF ; If (eventpointer) ever points at this, the queue has been flooded
#include "evthand.inc"
.end
Code: Select all
.module eventhandler
_start
;----------------------------------------------------------------
; The main code wich executes events as they are triggered
;----------------------------------------------------------------
;Author Dries Guldolf
;Remarks To start your event based program just call eventloop
; Make sure that the isr is installed and that interrupts are enabled
shifteventqueue:
di ; If an interrupt triggers while we're modifying the eventqueue...
ld hl, eventqueue + 3 ; Shift the event queue 3 bytes
ld de, eventqueue ;
ld bc, queue_size * 3 ;
ldir ;
ld hl, (eventpointer) ; Decrement the eventpointer
dec hl ;
dec hl ;
dec hl ;
ld (eventpointer), hl ;
ei ; Enable interrupts
eventloop:
;
; Do stuff here (like checking if the clear button is pressed and return if it is)
;
ld a, (eventqueue) ; Fetch the event type
;
; Check for system events here (see $00 as a system event)
;
or a ;
jr nz, runeventcode ; If there was an event, execute it
halt ; Some power-saving stuff
jr eventloop ;
runeventcode:
ld h, 0 ; Get the address of the event handler code
ld l, a ;
add hl, hl ;
ld de, lut_eventhandlers ;
add hl, de ;
ld a, (hl) ;
inc hl ;
ld h, (hl) ;
ld l, a ;
ld de, shifteventqueue ; Push the return address
push de ;
ld de, (eventqueue + 1) ; Pointer to event data
jp (hl) ; Run event code
;----------------------------------------------------------------
; Adds an event to the eventqueue
;----------------------------------------------------------------
;Author Dries Guldolf
;Input A The event type
; DE pointer to the event data
;Output HL points at the next entry in the eventqueue
;Destroys AF, DE
;Result Your event is added to the eventqueue
;Remarks This routine can take care of an overflown eventqueue
; itself if you define correctoverflows (doesn't add
; the event) otherwise it will call a costum routine
; called bufferoverflow, you can quit the program by
; restoring SP or modify stuff and return (preserve B).
addevent:
ld hl, (eventpointer) ; Write the data to the eventqueue
ld (hl), a ;
inc hl ;
ld (hl), e ;
inc hl ;
ld (hl), d ;
inc hl ;
ld a, (hl) ; If the buffer has overflown we can correct it
inc a ; If (eventpointer) points to $FF there is an overflow
#ifdef floodprotection
jr nz, _nooverflow ; Clean the zero-extension if there was an overflow
ld hl, eventqueue + (queue_size * 3)
xor a ; This can be left out because it will only be executed if a=0
ld (hl), a ; Unrolled loop
inc hl ;
ld (hl), a ;
inc hl ;
ld (hl), a ;
dec hl ;
dec hl ; HL points again at the zero-ext, if another event triggers it's wiped again
_nooverflow:
#else
call z, bufferoverflow ; Jump to the overflow handler
#endif
ld (eventpointer), hl ; Write new pointer
ret ; Done
;----------------------------------------------------------------
; The interrupt service routine
;----------------------------------------------------------------
;Author Dries Guldolf
;Results Every timer of lst_timedevents is decremented and
; if a timer hit zero, the event is added to the queue
;Remarks To use this isr call install first and execute im 1
; at the end of your program.
interrupt_start
ex af, af' ;
exx ;
ld hl, lst_timedevents ;
ld b, (hl) ;
inc hl ; HL points to the beginning of the list
_loop:
ld a, (hl) ; Get the event type
inc hl ; HL points to the timer
dec (hl) ; Decrement the timer
jr z, _addevent ; If it hit zero then add the event
inc hl ; Otherwise go to next timed event
inc hl ;
inc hl ;
_continue:
djnz _loop ; Do this for all the timed events
ld a, %00001000 ; Aknowledge thingie
out (3), a ;
ld a, %00001010 ; Reenable hardware and quit the interrupt
out (3), a ;
exx ;
ex af, af' ;
ei ;
ret ;
_addevent:
; Reset the timer
push hl ; We need the address later
ld h, 0 ; Get the maxtimer for this event
ld l, a ;
ld de, lut_maxtimers ;
add hl, de ;
ld c, (hl) ;
pop hl ;
ld (hl), c ; And writeback
; Add it to the event queue
inc hl ; Fetch the data pointer
ld e, (hl) ;
inc hl ;
ld d, (hl) ;
inc hl ;
push hl ;
call addevent ; Add the event to the queue
pop hl ;
jr _continue ; Repeat for all timed events
interrupt_end
;----------------------------------------------------------------
; Installs an interrupt in SavesScreen
;----------------------------------------------------------------
;Author Dries Guldolf
;Results A 257 byte table filled with $88 is made
; The interrupt routine is copied to $8888
;Destroys All
install:
di ; Disable interrupts (don't want an interrupt before we're ready)
ld hl, $8700 ; Start of interrupt table
ld de, $8701 ; Start of interrupt table +1
ld bc, 256 ; 257 byte table
ld (hl), $88 ; Fill it with $88
ldir ;
; Now we have a 257 byte table starting at $8700 filled with $88
ld hl, interrupt_start ; Copy interrupt routine to $8888
ld de, $8888 ;
ld bc, interrupt_end - interrupt_start ;
ldir ;
ld a, $87 ; The interrupt relocation table is stored at $87xx
ld i, a ;
im 2 ; Activate the costum interrupt
ei ; Enable interrupts
ret
#if (interrupt_end - interrupt_start + $8888) > (savesscreen + 768)
.echo "\nFATAL ERROR!\nThe isr is too large ("
.echo interrupt_end - interrupt_start
.echo " bytes).\nThere's a maximum of "
.echo savesscreen + 768 - $8888
.echo " bytes!\nHow the hell did you caused this error???\n\n"
#else
.echo "\nEvent handler package by Dries Guldolf,\nTotal size: "
.echo _end - _start
.echo " bytes.\n\n"
#endif
; 180 bytes :)
_end
.module
- FIXED This code runs perfectly in TI-flash debugger but not on a real 84+ (shuts down, pull a batery, press on, ram reset ) - No idea whats happening, probabely some ti84+ unfriendly interrupt thingies...
- FIXED If you press the on key the memory gets corrupted writing +-$88A1 all over the place (starting at the end, slowely gets to my program, corrupts it, tidebugger: undefined instruction), suprisingly this is the address of the EI instruction when the interrupt finishes, must be a wrong mask, cant figure it out? Wikiti says %00011011?
- FIXED In shifteventqueue I tought that the first next 3 instrs were not neccesary, but the emu crashed if these aren't included?
Oh yeah: feel free to optimize
EDIT: opdated the code