ADDR B1 B2 B3 B4 F:\chicken\timer.asm PAGE 1 * timer.asm * Routines for using the timer system. #include "debug.asm" *#include "buffalo.asm" ; For SCI routines OUTSTRG0 and . OUTCRLF * Print debug message pointed to by X printmsg: jsr OUTSTRG0 E ^ Unknown identifier. jsr OUTCRLF E ^ Unknown identifier. C000 39 rts mycrlf: C001 36 psha C002 86 0D LDAA #CR JSR OUTPUT E ^ Unknown identifier. C004 86 0A LDAA #LF JSR OUTPUT E ^ Unknown identifier. C006 32 pula C007 39 RTS * Print current values of all registers. printregs: C008 36 psha ; Store all registers C009 07 tpa C00A B7 C0 E0 staa ccr C00D 32 pula C00E B7 C0 D8 staa accA C011 F7 C0 D9 stab accB C014 FD C0 DA std accD C017 FF C0 DC stx regIX C01A 18 FF C0 DE sty regIY C01E 3C pshx C01F 36 psha C020 CE C0 E1 ldx #aeq jsr outstrg E ^ Unknown identifier. C023 CE C0 D8 ldx #accA jsr out1bsp E ^ Unknown identifier. C026 CE C0 E4 ldx #beq jsr outstrg0 E ^ Unknown identifier. C029 CE C0 D9 ldx #accB jsr out1bsp E ^ Unknown identifier. C02C CE C0 E7 ldx #deq jsr outstrg0 E ^ Unknown identifier. C02F CE C0 DA ldx #accD jsr out2bsp E ^ Unknown identifier. C032 CE C0 EA ldx #xeq jsr outstrg0 E ^ Unknown identifier. C035 CE C0 DC ldx #regIX jsr out2bsp E ^ Unknown identifier. C038 CE C0 ED ldx #yeq ADDR B1 B2 B3 B4 F:\chicken\timer.asm PAGE 2 jsr outstrg0 E ^ Unknown identifier. C03B CE C0 DE ldx #regIY jsr out2bsp E ^ Unknown identifier. C03E CE C0 F0 ldx #ccreq jsr outstrg0 E ^ Unknown identifier. C041 CE C0 E0 ldx #ccr jsr out1bsp E ^ Unknown identifier. jsr outcrlf E ^ Unknown identifier. C044 B6 C0 E0 ldaa ccr C047 06 tap C048 32 pula C049 38 pulx C04A 39 rts * Print current value of A accumulator. C04B B7 C0 D8 printA: staa accA C04E 36 psha C04F 3C pshx C050 CE C0 D8 ldx #accA jsr out1bsp E ^ Unknown identifier. C053 38 pulx C054 32 pula C055 39 rts C056 F7 C0 D9 printB: stab accB C059 36 psha C05A 3C pshx C05B CE C0 D9 ldx #accB jsr out1bsp E ^ Unknown identifier. C05E 38 pulx C05F 32 pula C060 39 rts C061 FD C0 DA printD: std accD C064 36 psha C065 3C pshx C066 CE C0 DA ldx #accD jsr out2bsp E ^ Unknown identifier. C069 38 pulx C06A 32 pula C06B 39 rts C06C FF C0 DC printX: stx regIX C06F 36 psha C070 3C pshx C071 CE C0 DC ldx #regIX jsr out2bsp E ^ Unknown identifier. C074 38 pulx C075 32 pula C076 39 rts C077 18 FF C0 DE printY: sty regIY C07B 36 psha C07C 3C pshx C07D CE C0 DE ldx #regIY ADDR B1 B2 B3 B4 F:\chicken\timer.asm PAGE 3 jsr out2bsp E ^ Unknown identifier. C080 38 pulx C081 32 pula C082 39 rts printCCR: C083 36 psha C084 07 tpa C085 B7 C0 E0 staa ccr C088 3C pshx C089 CE C0 E0 ldx #ccr jsr out1bsp E ^ Unknown identifier. C08C 38 pulx C08D B6 C0 E0 ldaa ccr C090 06 tap C091 32 pula C092 39 rts accA: rmb 1 accB: rmb 1 accD: rmb 2 regIX: rmb 2 regIY: rmb 2 ccr: rmb 1 C09C 41 3D aeq: fcc "A=" C09E 04 fcb EOT C09F 42 3D beq: fcc "B=" C0A1 04 fcb EOT C0A2 44 3D deq: fcc "D=" C0A4 04 fcb EOT C0A5 58 3D xeq: fcc "X=" C0A7 04 fcb EOT C0A8 59 3D yeq: fcc "Y=" C0AA 04 fcb EOT C0AB 43 43 52 3D ccreq: fcc "CCR=" C0AF 04 fcb EOT * Wait for user to hit enter C0B0 36 pause: psha jsr inchar E ^ Unknown identifier. C0B1 32 pula C0B2 39 rts #include "debug.asm" *------------------------------------------------------------ . --------------------------------------- * Subroutine: setup_periodic_alarm * Purpose: * Arrange for an alarm to go off at regular intervals, . and call a specific subroutine every * time it does. Uses the HC11's built-in Timer Output . Compare facility. Supports up to 5 * independent alarms. User is responsible for doing . the CLI to enable interrupts (either * before or after calling this subroutine). * Inputs: * A = Alarm number, 0-4 * X = Pointer to subroutine to invoke (not an ISR). * Y = Alarm period in timer cycles, 0-65535. * Side effects: * Timer output compare TOC(A+1) is set up to call ADDR B1 B2 B3 B4 F:\chicken\timer.asm PAGE 4 . subroutine at X. * All registers are trashed. *------------------------------------------------------------ . --------------------------------------- * First, declare frame pointer offsets for local variables: lOffset: equ 0 ; For offsets . calculated from alarm numbers. lPseudo: equ lOffset+2 ; For pointer to . pseudo-vector address. lCCR: equ lPseudo+2 ; For preserving . caller's condition code register. lPeriod: equ lCCR+1 ; For preserving . caller's Y / period of alarm. lSub: equ lPeriod+2 ; For preserving . caller's X / pointer to user subroutine. lAlarm: equ lSub+2 ; For preserving . caller's A / alarm number. sLocals: equ lAlarm+1 ; Total space . occupied by local variables. * Error messages. C0B3 41 6C 61 72 alarm_too_big: fcc "Alarm number is too big." . C0B7 6D 20 6E 75 . C0BB 6D 36 65 72 . C0BF 20 69 73 20 . C0C3 74 6F 6F 64 . C0C7 62 69 67 2E C0CB 04 fcb EOT * The actual subroutine starts here. setup_periodic_alarm: * Save arguments, reserve space for local variables, and set . up frame pointer. C0CC 36 psha ; Stack variable lAlarm <- . alarm number A. C0CD 3C pshx ; Stack variable lSub <- . subroutine pointer X. C0CE 18 3C pshy ; Stack variable lPeriod <- . alarm period Y. C0D0 07 tpa ; Copy caller's predicate . bits (CCR) to A. C0D1 36 psha ; Stack variable lCCR <- . caller's predicates. C0D2 18 30 tsy ; Let Y point to top of stack . (lCCR). C0D4 18 8F xgdy ; Put frame pointer Y into D. C0D6 83 00 04 subd #lCCR ; Adjust it to make space for . additional locals above lCCR. (lOffset, lPseudo) C0D9 18 8F xgdy ; Put frame pointer back into . Y. C0DB 18 35 tys ; Move stack pointer above . locals frame, in case we want to call subroutines. printY E ^ Unknown instruction or directive. * Do some error checking on our input arguments. C0DD 18 A6 09 ldaa lAlarm,y ; A = Alarm number. C0E0 81 04 cmpa #4 ; Max possible alarm number. C0E2 23 48 bls spa4 ; If that or lower, we're OK. C0E4 CE C0 B3 spa4: ldx #alarm_too_big ; Select error message: Alarm . is too big. ADDR B1 B2 B3 B4 F:\chicken\timer.asm PAGE 5 jsr outstrg ; Print error message to SCI. E ^ Unknown identifier. C0E7 7E C1 AF jmp spa3 ; Exit from subroutine . without really doing anything. * Disable interrupts before we start changing anything. C0EA 0F sei ; Mask interrupts while we're . rearranging things. * First, we calculate the pseudo-vector address in Buffalo's . jumptable that we'll need to set. C0EB 18 A6 09 ldaa lAlarm,y ; A = Alarm number. ldab #JUMPSIZE ; B = Size of a jump . instruction. E ^ Unknown identifier. C0EE 3D mul ; D = Offset to the jumptable . entry we want C0EF 18 ED 00 std lOffset,y ; Store it in lOffset local . variable. ldd #PVTOC1 ; Point D at last TOC . jumptable pseudo-vector entry. E ^ Unknown identifier. C0F2 18 A3 00 subd lOffset,y ; Subtract the lOffset we . saved earlier. C0F5 18 ED 02 std lPseudo,y ; Store D in lPseudo local . variable. C0F8 BD C0 61 jsr printD * Next, find the address of the appropriate ISR. C0FB 18 E6 09 ldab lAlarm,y ; Load alarm number. C0FE 58 lslb ; Double to get a word . offset. C0FF 4F clra ; Clear MSB of D; effectively . transfers B->D. C100 18 ED 00 std lOffset,y ; Store in lOffset local . variable. C103 C3 C2 21 addd #TOC_ISRs ; Add base address of TOC ISR . table. C106 8F xgdx ; Transfer TOC ISR table . entry pointer to X. C107 18 EC 00 ldd 0,y ; Transfer TOC ISR pointer to . D. C10A BD C0 61 jsr printD * Now, store the ISR address in the pseudo-vector location. C10D CD EE 02 ldx lPseudo,y ; Load pseudo-vector pointer . we computed in previous section. C110 ED 00 std 0,x ; Store TOC ISR pointer at . pseudo-vector location. This sets up the vector. * Figure out where to store our subroutine pointer. C112 18 EC 00 ldd lOffset,y ; Load offset we computed . earlier. addd #sub1 ; Add base of subroutine . pointer table. E ^ Unknown identifier. C115 8F xgdx ; X now points to subroutine . pointer table entry. C116 BD C0 6C jsr printX * Store the subroutine pointer there. C119 18 EC 07 ldd lSub,y ; Load pointer to the actual . subroutine into D. C11C ED 00 std 0,x ; Store it in the subroutine . pointer table entry. ADDR B1 B2 B3 B4 F:\chicken\timer.asm PAGE 6 * Now, compute the appropriate mask bit to select OCa in the . TMSK1 and TFLG1 registers. ldab #OC1I ; Bit mask for OC1I register . bit. (Also is OC1F.) E ^ Unknown identifier. C11E 18 A6 09 ldaa lAlarm,y ; This is the alarm number 0- . 4 we pushed earlier. C121 27 59 spa0: beq spa1 ; If it's 0, the mask we have . now is the right one. C123 54 lsrb ; Shift the mask right one . position (go to next OC) C124 4A deca ; Subtract 1 from alarm . number. C125 20 FA bra spa0 ; Keep looping. C127 BD C0 56 spa1: jsr printB * The following code actually enables the interrupts on . Output Compare #a to occur. stab TFLG1 ; Storing "1" turns OFF bit . OCaF in TFLG1 (clears state of OCaF flag). E ^ Unknown identifier. orab TMSK1 ; This prevents the next line . from turning off other OCxI bits. E ^ Unknown identifier. stab TMSK1 ; Turns on bit OCaI in TMSK1 . (enables interrupt OCaI). E ^ Unknown identifier. * Finally, we set the initial OCa alarm time relative to the . present time. C12A 4F clra ; Clear MSB of D. C12B 18 E6 09 ldab lAlarm,y ; Load alarm number into B. C12E 58 aslb ; Double that to get a word . offset. addd TOC1 ; Add to base of TOC . registers to point to TOCa. E ^ Unknown identifier. C12F 8F xgdx ; Put the pointer into regIX. C130 BD C0 6C jsr printX ldd TCNT ; Load the present system . timer value. E ^ Unknown identifier. C133 BD C0 61 jsr printD C136 18 E3 05 addd lPeriod,y ; Add it to the alarm period . that we saved earlier. C139 BD C0 61 jsr printD C13C ED 00 std 0,x ; Store it in the appropriate . TOCa register. (This line actually sets the alarm trigger . time.) * Finally, if alarm 4 (OC5) was selected, we have to . configure pin PA3 as OC5 rather than IC4. C13E 18 A6 09 ldaa lAlarm,y ; Load A with the alarm . number. C141 81 04 cmpa #4 ; Was it alarm #4? . (Representing OC5.) C143 26 6A bne spa2 ; If not, then don't... ldx #PACTL ; Select PACTL . register. E ^ Unknown identifier. bclr 0,x I4O5 ; Clear the I4/O5 bit . (select OC5 rather than IC4 for pin PA3). E ^ Unknown identifier. spa2: ADDR B1 B2 B3 B4 F:\chicken\timer.asm PAGE 7 * Throw away all the locals, restore stack pointer and the I . bit. Don't bother restoring any other registers. C145 18 A6 04 spa3: ldaa lCCR,y ; Load caller's CCR (really . we just care about I). C148 06 tap ; Transfer it to the real . CCR. (This may re-enable interrupts, if they were enabled in . caller.) C149 18 8F xgdy ; Move frame pointer into D. C14B C3 00 0A addd #sLocals ; Bump it up past all the . locals. (Including pushed registers.) C14E 18 8F xgdy ; Transfer it back to Y. C150 18 35 tys ; And from there back to the . stack pointer. Now it's safe to return. C152 39 rts ; Return from setup_periodic_ . alarm subroutine. *------------------------------------------------------------ . ------------ * Interrupt Service Routines that may be set up by setup_ . periodic_alarm. *------------------------------------------------------------ . ------------ ISR_TOC1: ldd TOC1 ; Get current TOC1 alarm time. E ^ Unknown identifier. addd per1 ; Add the period for this periodic . timer. E ^ Unknown identifier. std TOC1 ; Store it as the new alarm time. E ^ Unknown identifier. ldx sub1 ; Load first subroutine address. E ^ Unknown identifier. C153 AD 00 jsr 0,x ; Jump to that subroutine. ldaa #OC1F ; Select OC1F flag (in TFLG1 . register). E ^ Unknown identifier. staa TFLG1 ; Write 1 to OC1F in TFLG1 to turn . off OC1F, which resets TOC1. E ^ Unknown identifier. C155 3B rti ; Return from ISR_TOC1. ISR_TOC2: ldd TOC2 ; Get current TOC2 alarm time. E ^ Unknown identifier. addd per2 ; Add the period for this periodic . timer. E ^ Unknown identifier. std TOC2 ; Store it as the new alarm time. E ^ Unknown identifier. ldx sub2 ; Load 2nd subroutine address. E ^ Unknown identifier. C156 AD 00 jsr 0,x ; Jump to that subroutine. ldaa #OC2F ; Select OC2F flag (in TFLG1 . register). E ^ Unknown identifier. staa TFLG1 ; Write 1 to OC2F in TFLG1 to turn . off OC2F, which resets TOC2. E ^ Unknown identifier. C158 3B rti ; Return from ISR_TOC2. ISR_TOC3: ldd TOC3 ; Get current TOC3 alarm time. E ^ Unknown identifier. addd per3 ; Add the period for this periodic ADDR B1 B2 B3 B4 F:\chicken\timer.asm PAGE 8 . timer. E ^ Unknown identifier. std TOC3 ; Store it as the new alarm time. E ^ Unknown identifier. ldx sub3 ; Load 3rd subroutine address. E ^ Unknown identifier. C159 AD 00 jsr 0,x ; Jump to that subroutine. ldaa #OC3F ; Select OC3F flag (in TFLG1 . register). E ^ Unknown identifier. staa TFLG1 ; Write 1 to OC3F in TFLG1 to turn . off OC3F, which resets TOC3. E ^ Unknown identifier. C15B 3B rti ; Return from ISR_TOC3. ISR_TOC4: ldd TOC4 ; Get current TOC4 alarm time. E ^ Unknown identifier. addd per4 ; Add the period for this periodic . timer. E ^ Unknown identifier. std TOC4 ; Store it as the new alarm time. E ^ Unknown identifier. ldx sub4 ; Load 4th subroutine address. E ^ Unknown identifier. C15C AD 00 jsr 0,x ; Jump to that subroutine. ldaa #OC4F ; Select OC4F flag (in TFLG1 . register). E ^ Unknown identifier. staa TFLG1 ; Write 1 to OC4F in TFLG1 to turn . off OC4F, which resets TOC4. E ^ Unknown identifier. C15E 3B rti ; Return from ISR_TOC3. ISR_TOC5: ldd TOC5 ; Get current TOC5 alarm time. E ^ Unknown identifier. addd per5 ; Add the period for this periodic . timer. E ^ Unknown identifier. std TOC5 ; Store it as the new alarm time. E ^ Unknown identifier. ldx sub5 ; Load 5th subroutine address. E ^ Unknown identifier. C15F AD 00 jsr 0,x ; Jump to that subroutine. ldaa #OC5F ; Select OC5F flag (in TFLG1 . register). E ^ Unknown identifier. staa TFLG1 ; Write 1 to OC5F in TFLG1 to turn . off OC5F, which resets TOC5. E ^ Unknown identifier. C161 3B rti ; Return from ISR_TOC5. *------------------------------------------------------ * Persistent variables needed by setup_periodic_alarm. *------------------------------------------------------ * Table of pointers to all of our ISRs for the TOC . interrupts. TOC_ISRs: C162 C1 53 fdb ISR_TOC1 C164 C1 56 fdb ISR_TOC2 C166 C1 59 fdb ISR_TOC3 C168 C1 5C fdb ISR_TOC4 C16A C1 5F fdb ISR_TOC5 ADDR B1 B2 B3 B4 F:\chicken\timer.asm PAGE 9 * Programmers: Be sure to locate the below variable data . region in RAM. * Data region for remembering the periods for the 5 possible . periodic alarms. per1: rmb WORDSIZE E ^ Unknown identifier. per2: rmb WORDSIZE E ^ Unknown identifier. per3: rmb WORDSIZE E ^ Unknown identifier. per4: rmb WORDSIZE E ^ Unknown identifier. per5: rmb WORDSIZE E ^ Unknown identifier. * Data region for remembering the addresses of the . subroutines to call upon alarm. sub1: rmb WORDSIZE E ^ Unknown identifier. sub2: rmb WORDSIZE E ^ Unknown identifier. sub3: rmb WORDSIZE E ^ Unknown identifier. sub4: rmb WORDSIZE E ^ Unknown identifier. sub5: rmb WORDSIZE E ^ Unknown identifier. Symbol Table ETB 0017 CR 000D ETX 0003 US 001F VT 000B EM 0019 ALARM_TOO_BIG C0B3 FF 000C SOH 0001 MYCRLF C001 BEL 0007 FS 001C BEQ C09F DLE 0010 XEQ C0A5 GS 001D SETUP_PERIODIC_ALARMC0CC SPACE 0020 CAN 0018 SLOCALS 000A LCCR 0004 CCR C09B LSUB 0007 PRINTREGS C008 PRINTCCR C083 STX 0002 SUB 001A LF 000A ISR_TOC1 C153 ISR_TOC2 C156 ISR_TOC3 C159 ISR_TOC4 C15C LOFFSET 0000 Symbol Table F:\chicken\timer.asm PAGE 10 ISR_TOC5 C15F YEQ C0A8 ACCA C093 ACCB C094 ACCD C095 PRINTMSG C000 PRINTA C04B PRINTB C056 PRINTD C061 TOC_ISRS C162 DC1 0011 PRINTX C06C DC2 0012 LPSEUDO 0002 PRINTY C077 DC3 0013 DC4 0014 CCREQ C0AB ENQ 0005 TAB 0009 SPA0 C121 SPA1 C127 SPA2 C145 SPA3 C145 SPA4 C0E4 EOT 0004 ACK 0006 SYN 0016 NAK 0015 DEL 007F DEQ C0A2 LPERIOD 0005 LALARM 0009 PAUSE C0B0 AEQ C09C RS 001E SI 000F ESC 001B SO 000E NUL 0000 REGIX C097 REGIY C099 BS 0008