TITLE RTIMER - 'Timer Subroutines for MULRPT' ENTRY SETTMR,TICK .Z80 ; Routines use a single CTC channel to implement a multi- ; channel timer capability. The SETTMR subroutine is called ; to set a timer. Each "tick" of the CTC interrupt calls ; the TICK subroutine, which counts down the timers. When ; a timer expires its associated subroutine is called. INCLUDE RCONFIG.LIB ; Timer data structure definition CNT EQU 0 ;Timer count, 2 bytes ARG EQU 2 ;Service sub. calling arg, 2 bytes SVC EQU 4 ;Address of service subroutine TDSLEN EQU 6 ;Size of data structure SUBTTL 'SETTMR - Timer Initialization Subroutine' PAGE ; SETTMR - Set a timer channel. ; ; *** WARNING: Enter with interrupts disabled -- or else! ; ; Entry parameters: ; A = Channel number. ; BC = Timer value in ticks. ; DE = Argument to be passed to the service ; subroutine in DE when called. ; HL = Address of service subroutine. ; Return parameters: ; Registers AF, BC, DE, HL trashed. SETTMR: PUSH HL ;Save during calculations PUSH BC ; Calculate data structure address for this channel LD L,A ;Make 16 bit channel number LD H,0 ADD HL,HL ;Channel * 2 LD C,L ;Copy to BC LD B,H ADD HL,HL ;Channel * 4 ADD HL,BC ;Channel * 6 (offset) LD BC,TIMDS ;Get data structure base ADD HL,BC ;Point to data structure ; Fill data structure. POP BC ;Get time count LD (HL),C ;Store it INC HL LD (HL),B INC HL LD (HL),E ;Store calling arg INC HL LD (HL),D INC HL POP DE ;Get service address LD (HL),E ;Store it INC HL LD (HL),D RET SUBTTL 'TICK - CTC Interrupt Handler' PAGE ; TICK - CTC interrupt service. Counts down each timer ; channel if active (i.e. count is non-zero). When count ; reaches zero, calls service subroutine. TICK: PUSH AF ;Save interrupted context PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY ; Loop executes once for each timer channel. LD A,NUMCH ;Number of timers (and channels) LD HL,TIMDS ;Base of data structures TLOOP: LD (COUNT),A ;Set loop count LD C,L ;Copy data structure pointer... LD B,H ;...to BC for safekeeping LD E,(HL) ;Get time count INC HL LD D,(HL) LD A,D ;Test for zero count (inactive) OR E JR Z,NXTTMR ;Inactive, skip to next channel DEC DE ;Count down one LD (HL),D ;Update time count DEC HL LD (HL),E LD A,D ;Is it zero now? OR E JR NZ,NXTTMR ;No, don't service it INC HL ;Point to calling arg INC HL LD E,(HL) ;Get calling arg INC HL LD D,(HL) INC HL LD A,(HL) ;Get service address INC HL LD H,(HL) LD L,A PUSH BC ;Save data pointer CALL VECTOR ;Call the service sub. POP BC ;Restore data pointer NXTTMR: LD HL,TDSLEN ;Offset to next data ADD HL,BC LD A,(COUNT) ;Get loop count DEC A JR NZ,TLOOP ;Continue POP IY ;Restore interrupted context POP IX POP HL POP DE POP BC POP AF EI RETI ;Back to mainline VECTOR: JP (HL) ;Vector to subroutine DSEG COUNT: DEFS 1 ;Loop counter TIMDS: DEFS TDSLEN*NUMCH ;Note: this area is zeroed by ;the main program at reset SUBTTL 'Symbol Table' END