************************************************* * * Toaster Operating System * Version 1.6e2 * * (c) 1996 Corin Anderson and Chris Setter * * CSE 477, Spring Quarter, 1996 * University of Washington * ************************************************* ******************************************************************** * Revision History * * 1.6e2 Fix applied to temperature sensor. At timer overflows, * there is noise on the A/D ports, probably caused by the PWM * signal that's driving the toaster's servo. This noise * manifests itself as a high frequency ring in the last two * bits of the temperature data. This is a major problem * the difference between light and dark toast settings are * less than 3 bits apart. The solution applied here is to * simply ignore the temperature sensor's reading during this * ringing period. The ringing lasts no longer than about * 12.5 ms, or about 25K e-cycles. This solution solves the * problem. * * 1.5e2 Modified to be used without the evaluation board. * Modifications include: * ** Globals are now at $0047 * ** Code is now at $F800 * ** RESET and IC1 interrupts are set with FDB * statement * ** Buffalo functions are replaced with NULLFCN * * 1.5 User Interface modified. No more command stuff. User * simply says "toast" and off things go. Toaster has longer * responses. * * Sensor code still being modified and tested. * * New voice chip vocabulary * * 1.4 Code added to read and respond accordingly to the bread * and temperature sensors. * * Also added code to prompt the user for toasting level. * * Never functional. Version bumped for new UI. * * 1.3 Reworked speech recognition code so the toaster won't try * to recognize its own voice (from the Say() routine). * * Added code to audibly prompt the user to train words. Also * added code to display the word on the terminal. Both of * these functions use arrays of the voice clips and words. * * New voice chip vocabulary * * 1.2 Interfaced TOS to Bread Platform servo motor. The servo * requires a pulse width modulated (PWM) control signal to * position the shaft angle. Thus, the output capture facility * is used. * * For the safety of the toaster and of the user, there is a * servo override button on the toaster. When this button is * pushed, the servo is swung up to its raise position. This * still doesn't unlock the bread platform from the motor, but * at least this will open the contacts to the heating coils * and free the user's bread. * * 1.1 Added code to disregard speech matches that have too high * of a score. With luck, this will eliminate false positives. * Unfortunately, this will also lead to false negatives. But * that's usually easier to cope with. * * 1.0 First release of functional TOS. Includes code for speech * recognition, voice response, and motion detection. Speech * recognition is limited to about 5 words trained at startup. * Voice responses are tailored for the specific command: make * toast. * * 0.1 First incarnation of TOS. Does not function properly. Has * incorrect handling of voice response chip (ISD1000A). Needs * substantial work to be functional. * ********************************************************************* ********************************************************************* * Constant definitions for Speech Recognition chip * Bus connections for Speech Recognition chip SBUS EQU $1003 S bus is C[6:4] KBUS EQU $1003 K bus is C[3:0] * Bus bit mask SMASK EQU %01110000 Middle 3 bits KMASK EQU %00001111 Lower 4 bits * States for speech recognition chip srNULL EQU %00000010 Null state srRDSTATUS EQU %00000010 Read status from K bus srRDOUTPUT EQU %00000011 Read output buffer from K bus srWRINPUT EQU %00000100 Write intput buffer on K bus * Status codes srRDYHI EQU %00000000 Ready for second (hi) nibble srRDYVOICE EQU %00000001 Ready for voice input srRDYCMD EQU %00000010 Ready to receive command srRDYLO EQU %00000011 Ready for first (lo) nibble * Command codes srCMDRECOG EQU %00000001 Recognize word srCMDTRAIN EQU %00000010 Train a pattern srCMDRESULT EQU %00000100 Read result and score srCMDRESET EQU %00000111 Clear all patterns from HM2007 * Result codes srTOOSLOW EQU $55 Voice was too long (too slow) srTOOFAST EQU $66 Voice was too short (too fast) srNOTFOUND EQU $77 Voice was not found ******************************************************************** * Constant definitions for general purpose * Port data direction registers (offset from $1000) REGBAS EQU $1000 DDRC EQU $07 Data direction for port C (0=Input, 1=Output) OC1M EQU $0C OC1 Action Mask register OC1D EQU $0D OC1 Action Data register TIC1 EQU $10 IC1 register (16 bits) TOC1 EQU $16 OC1 register (16 bits) TOC3 EQU $1A OC3 register (16 bits) TCTL1 EQU $20 OM2,OL2;OM3,OL3;OM4,OL4;OM5,OL5 TCTL2 EQU $21 -,-;EDG1B,EDG1A;EDG2B,EDG2A;EDG3B,EDG3A TMSK1 EQU $22 OC1I,OC2I,OC3I,OC4I,OC5I,IC1I,IC2I,IC3I TFLG1 EQU $23 OC1F,OC2F,OC3F,OC4F,OC5F,IC1F,IC2F,IC3F *PVIC1 EQU $00E8 EVB pseudo-vector for IC1 TMRREG EQU $0E Timer counter register (16 bits) * A/D controller and reading defines ADCTL EQU $30 ADR1 EQU $31 ADR2 EQU $32 ADR3 EQU $33 ADR4 EQU $34 Option EQU $39 **************************************************************************** * Voice clip indices * /* Voice response clips */ vLIKETOAST EQU %00000000 /* Would you like some toast? */ vTOAST EQU %00001100 /* toast */ vYES EQU %00010100 /* yes? */ vNO EQU %00011011 /* no */ vOKAY EQU %00100010 /* okay */ vHOWLIGHT EQU %00101001 /* how light? */ vLIGHT EQU %00110010 /* light */ vMEDIUM EQU %00111010 /* medium */ vDARK EQU %01000001 /* dark */ vUSING EQU %01001001 /* using setting *? vEND EQU %01010011 /* end */ vLOWERING EQU %01011011 /* lowering */ vRAISING EQU %01100011 /* raising */ vDONE EQU %01101011 /* done */ vSLOWER EQU %01110010 /* slower */ vFASTER EQU %01111010 /* faster */ vWHAT EQU %10000010 /* I'm sorry, what? */ vPLSSAY EQU %10001101 /* Please say -- */ vNOBREAD EQU %10010110 /* I should toast what? */ **************************************************************************** * Speech recognition indicies * /* Word Recognition indicies (bcd) */ wYES EQU $01 #define wYes '01' wNO EQU $02 #define wNo '02' wTOAST EQU $03 #define wToast '03' wLIGHT EQU $04 wMEDIUM EQU $05 wDARK EQU $06 wEND EQU $07 #define wEnd '07' wLASTWORD EQU $07 #define wLastWord '07' srMAXTRAIN EQU 3 #define srMaxTrain 3 srTHRESH EQU $80 #define srThresh 0x40 ********************************************************************************* * I/O port mapping for voice chip and motion detection VOCPORT EQU $1004 Port B isdENBAR EQU $1003 Port C port gPlayClip[0]; isdENMASK EQU %10000000 Bit 7 isdEOM EQU $1000 Port A port gEOM[0]; isdEOMMASK EQU %00000001 Bit 0 MOTPORT EQU $1000 Port A port gMotion[0]; MOTMASK EQU %00000010 Bit 1 ********************************************************************************* * Bread Platform pulse widths and control data OC3_OC1 EQU %00100000 OC1 controls A[5] OC3_CTL EQU %00100000 OC3 clears on compare PW_RAISE EQU $0D80 PW_LOWER EQU $0480 BREAD_DLY EQU 32 tLIGHT EQU $91 Treshold for light toast tMEDIUM EQU $93 Treshold for medium toast tDARK EQU $95 Treshold for dark toast ********************************************************************************* * Global Variables ORG $0048 * The only global variable. And it could even go away if I wanted to use * input capture. But I don't so it won't. 8) motLASTST RMB 1 Last known state of motion sensor srINITED RMB 1 1 == INIT_SR has been called, 0 otherwise TOASTLEVEL RMB 1 Toast level (threshold for temp IC) *********************************************************************** * Interrupt vectors, including RESET and IC1 ORG $FFFE RESET: jump to start of program FDB MAIN ORG $FFEE IC1 ISR FDB IC1ISR ORG $F800 * If we're not on the EVB, pass all the Buffalo functions to NULLFCN. NULLFCN RTS * BUFFALO I/O routines * Must be defined here because they must *follow* NULLFCN's definition * The $FFxx addresses are the addresses of the functions when used with the EVB OUTA EQU NULLFCN $FFB8 Output ASCII character in A OUT1BSP EQU NULLFCN $FFBE Output 1 byte in hex, followed by a space OUT1BYT EQU NULLFCN $FFBB Output 1 byte in hex OUTCRLF EQU NULLFCN $FFC4 Output carriage return and line feed OUTSTRG EQU NULLFCN $FFC7 Output string terminated by $04, incl. CR/LF OUTSTRG0 EQU NULLFCN $FFCA Output string terminated by $0F, excl. CR/LF *********************************************************************** * void main(void) * { * int w; MAIN LDS #$0047 JSR INIT Init(); LDAA #'M JSR OUTA JSR OUTCRLF * while(1) { MAINLOOP LDAA #'L * JSR OUTA * JSR OUTCRLF JSR WORDRECOG if (WordRecognized()) { BEQ ML1 JSR GETWORD w = GetWord(); PSHA TSX JSR OUT1BSP PULA SUBA #wTOAST if (w == wToast) BNE MAINLOOP JSR MAKETOAST MakeToast(); LDAA #'/ JSR OUTA LDAA #'P JSR OUTA BRA MAINLOOP * } ML1 JSR MOTDETECT else if (MotionDetected()) { BEQ MAINLOOP JSR RESPONDMOT RespondToMotion(); BRA MAINLOOP * } * } * } *********************************************************************** * void Init(void) * { INIT JSR INIT_VR InitVoiceResponse(); JSR INIT_SR InitSpeechRecognition(); JSR INIT_BREAD CLRA STAA motLASTST gLastMotState = 0; RTS * } **************************************************************************************** * void InitSpeechRecognition(void) * { INIT_SR LDAB #wLASTWORD int i=wLastWord; * int j; CLRA /* We're not fully initialized yet */ STAA srINITED JSR srCLEAR srClearPatterns(); * /* i == Accumulator B */ * /* j == Accumulator A */ * /* Train vocabulary */ ISR4 TBA while (i) { BEQ ISR1 LDAA #srMAXTRAIN j = srMaxTrain; ISR3 BEQ ISR2 while(j) { LDX #ISR_MSG1 puts("Please train word: "); PSHA JSR OUTSTRG ** TBA puts(words[i]); ** ADDA #'0 ** JSR OUTA LDX #srWORDS /* X <= &words[0].s */ PSHB DECB /* words is 0-based */ LSLB ABX /* X <= &words[0].s + 2*i */ LDX 0,X /* X <= words[i].s */ JSR OUTSTRG PULB LDAA #vPLSSAY JSR SAY LDX #vWORDS /* X <= &words[0].v */ ABX /* X == &words[i].v */ DEX /* words is 0-based */ LDAA 0,X /* A <= words[i].v */ JSR SAY TBA srTrainWord(i); JSR srTRAINWORD PULA j--; SUBA #1 BRA ISR3 } ISR2 SUBB #1 i--; BRA ISR4 } * /* Activate recognition circuit */ ISR1 LDAA #srRDSTATUS outs(srRdStatus); JSR OUTS ISR5 JSR INST while (inst() != srRdyCmd); SUBA #srRDYCMD BNE ISR5 LDAA #srWRINPUT outs(srWrInput); JSR OUTS LDAA #srCMDRECOG outk(srCmdRecog); JSR OUTK JSR INK ink(); LDAA #1 /* We're initialized now */ STAA srINITED RTS * } ************************************************************************************ * void InitVoiceResponse(void) * { INIT_VR LDX #$1000 BSET isdENBAR,X isdENMASK gISDEnableBar = 1; BSET DDRC,X isdENMASK /* Set pin as output */ BSET isdENBAR,X isdENMASK gISDEnableBar = 1; RTS * } ********************************************************************************* * bool WordRecognized(void) * { WORDRECOG LDAA #'W * JSR OUTA * JSR OUTCRLF LDAA #srRDSTATUS outs(srRdStatus); JSR OUTS JSR INST st = inst(); SUBA #srRDYCMD if (st == srRdyCmd) { BNE WR1 * JSR BEGINRECOG LDAA #1 return 1; RTS * } else WR1 CLRA return 0; RTS * } *************************************************************************** BEGINRECOG LDAA #'B * JSR OUTA * JSR OUTCRLF LDAA #srRDSTATUS outs(srRdStatus); JSR OUTS BR1 JSR INST while (inst() != srRdyCmd); SUBA #srRDYCMD BNE BR1 LDAA #srWRINPUT outs(srWrInput); JSR OUTS LDAA #srCMDRECOG outk(srCmdRecog); JSR OUTK JSR INK ink(); LDAA #20 BR2 NOP NOP SUBA #1 BNE BR2 LDAA #srRDSTATUS outs(srRdStatus); JSR OUTS JSR INST RTS ************************************************************************* * bcd GetWord(void) * { * bcd w; GETWORD LDAA #'G JSR OUTA * JSR OUTCRLF LDAA #srRDSTATUS outs(srRdStatus); JSR OUTS GW1 JSR INST while(inst() != srRdyCmd); SUBA #srRDYCMD BNE GW1 LDAA #srWRINPUT outs(srWrInput); JSR OUTS LDAA #srCMDRESULT outk(srCmdResult); JSR OUTK JSR INK ink(); * /* Read which word was read */ JSR READLOHI ReadLoHi(&w); PSHA TSX JSR OUT1BSP * /* Read score (required) and throw away */ JSR READLOHI ReadLoHi(NULL); PSHA TSX JSR OUT1BSP JSR BEGINRECOG PULB /* B <= score */ PULA /* A <= word */ SUBA #srTOOFAST BNE GW2 LDAA #vSLOWER JSR SAY BRA GETWORD GW2 ADDA #srTOOFAST SUBA #srTOOSLOW BNE GW3 LDAA #vFASTER JSR SAY BRA GETWORD GW3 ADDA #srTOOSLOW SUBA #srNOTFOUND BNE GW4 LDAA #vWHAT JSR SAY BRA GETWORD GW4 ADDA #srNOTFOUND /* A is word (again) */ PSHA TBA SUBA #srTHRESH BLO GW5 PULA LDAA #vWHAT JSR SAY BRA GETWORD GW5 LDAA #'/ JSR OUTA LDAA #'G JSR OUTA JSR OUTCRLF PULA RTS return w; * } ***************************************************************************** * void ReadLoHi(bcd *w) * { READLOHI LDAA #'R JSR OUTA LDAA #'L JSR OUTA LDAA #'H JSR OUTA JSR OUTCRLF LDAA #srRDSTATUS outs(srRdStatus); JSR OUTS RLH1 JSR INST while (inst() != srRdyLo); SUBA #srRDYLO BNE RLH1 LDAA #srRDOUTPUT outs(srRdOutput); JSR OUTS JSR INK w->lo = ink(); PSHA LDAA #%101 outs(101); JSR OUTS LDAA #%001 outs(001); JSR OUTS LDAA #%000 outs(000); JSR OUTS LDAA #srRDSTATUS outs(srRdStatus); JSR OUTS RLH2 JSR INST while(inst() != srRdyHi); SUBA #srRDYHI BNE RLH2 LDAA #srRDOUTPUT outs(srRdOutput); JSR OUTS JSR INK w->hi = ink(); LSLA LSLA LSLA LSLA PULB ABA PSHA LDAA #%101 outs(101); JSR OUTS LDAA #%001 outs(001); JSR OUTS LDAA #%000 outs(000); JSR OUTS LDAA #srRDSTATUS outs(srRdStatus); JSR OUTS JSR INST inst(); PULA RTS * } *********************************************************************************** * void srTrainWord(bcd index) * { srTRAINWORD PSHA /* Save index from register A */ LDAA #'T JSR OUTA LDAA #'W JSR OUTA TSX JSR OUT1BSP JSR OUTCRLF LDAA #srRDSTATUS outs(ReadStatus); JSR OUTS TW_1 JSR INST while(inst() != ReadyForCommand); SUBA #srRDYCMD BNE TW_1 LDAA #srWRINPUT outs(WriteInput); JSR OUTS LDAA #srCMDTRAIN outk(CmdTrain); JSR OUTK JSR INK LDAA #srRDSTATUS outs(ReadStatus); JSR OUTS TW_2 JSR INST while(inst() != ReadyForLo); PSHA SUBA #srRDYCMD BEQ TW_CONFZD PULA SUBA #srRDYLO BNE TW_2 LDAA #srWRINPUT outs(WriteInput); JSR OUTS PULA PSHA ANDA #$0F outk(loDigit); JSR OUTK JSR INK LDAA #srRDSTATUS outs(ReadStatus); JSR OUTS TW_3 JSR INST while(inst() != ReadyForHi); SUBA #srRDYHI BNE TW_3 LDAA #srWRINPUT outs(WriteInput); JSR OUTS PULA LSRA LSRA LSRA LSRA ANDA #$0F outk(hiDigit); JSR OUTK JSR INK LDAA #srRDSTATUS outs(ReadStatus); JSR OUTS TW_4 JSR INST inst(); SUBA #srRDYCMD while (inst() != ReadyCommand); /* Wait for word */ BNE TW_4 RTS TW_CONFZD PULA /* Restore the stack! */ LDX #CONFZD_MSG printf("Voice chip confused... trying again.\n"); JSR OUTSTRG PULA JMP srTRAINWORD * } ******************************************************************************** * void srClearPatterns(void) * { srCLEAR LDAA #srRDSTATUS outs(ReadStatus); JSR OUTS CLR_1 JSR INST while(inst() != ReadyForCommand); SUBA #srRDYCMD BNE CLR_1 LDAA #srWRINPUT JSR OUTS LDAA #srCMDRESET outk(CmdReset); JSR OUTK JSR INK ink(); LDAA #2000 CLR_2 NOP NOP SUBA #1 BNE CLR_2 LDAA #srRDSTATUS outs(ReadStatus); JSR OUTS JSR INST RTS * } **************************************************************************** * void MakeToast(void) * { * /* Check preconditions, like bread in toaster */ MAKETOAST LDAA #'M JSR OUTA LDAA #'T JSR OUTA JSR OUTCRLF JSR CHECKBREAD BNE MTOK LDAA #vNOBREAD JSR SAY RTS * /* Ask what toasting level */ MTOK LDAA #vHOWLIGHT JSR SAY MT0_1 JSR WORDRECOG BNE MT0_1 JSR GETWORD /* Light toast? */ SUBA #wLIGHT BNE MT0_2 LDAA #tLIGHT STAA TOASTLEVEL LDAB #vLIGHT BRA MTCONT MT0_2 ADDA #wLIGHT /* Dark toast? */ SUBA #wDARK BNE MT0_3 LDAA #tDARK STAA TOASTLEVEL LDAB #vDARK BRA MTCONT MT0_3 LDAA #tMEDIUM /* Medium toast (default) */ STAA TOASTLEVEL LDAB #vMEDIUM MTCONT PSHB LDAA #vUSING JSR SAY PULB TBA JSR SAY LDAA #vLOWERING Say(vLowering); JSR SAY JSR LOWER * while(1) { MT3 JSR CHECKTEMP if (TempThreshReached()) BNE MT4 break; JSR WORDRECOG if (!WordRecognized()) BEQ MT3 continue; JSR GETWORD if (GetWord() != wEnd) SUBA #wEND BNE MT3 continue; BRA MT4 break; * } MT4 LDAA #vRAISING Say(vRaising); JSR SAY JSR RAISE LDAA #vDONE Say(vDone); JSR SAY RTS * } **************************************************************************** * ***** CHRIS Read bread sensor here and put the number of slices loaded * ***** into accumulator A * For now, just lie and say that the toaster if fully loaded CHECKBREAD NOP * Set the ADCTL to read PE1 (left eye) LDX #REGBAS *** Eye 1 seems to be misbehaving. It is being software disabled for now. *** Misbehaving manifests itself by causing the microC to start executing *** instructions from anywhere within its memory, not nec. in PC order. **Eye1 LDAA #%10000001 ** STAA ADCTL,X ** JSR GetVal * ADR1 is one of 4 AD values we can use ** LDAA ADR1,X * I hope this constant works!!! ** SUBA #$80 ** BLS BreadIn1 ** CLRA ** BRA Eye2 **BreadIn1 LDAA #1 ** PSHA Eye2 LDAA #%10000010 STAA ADCTL,X JSR GetVal * ADR1 is one of 4 AD values we can use LDAA ADR1,X * I hope this constant works!!! SUBA #$80 BLS BreadIn2 CLRA ** PULA RTS BreadIn2 NOP ** PULA LDAA #1 RTS **************************************************************************** * ***** CHRIS Read the temperature IC. If the temperature is * above some threshold, return 1 in accumulator A. Else, return * 0 in A. For now, we'll lie and say that the temperature * has not been reached yet. CHECKTEMP NOP LDX #REGBAS * If counter is less than 25K, there's probably IC1 noise on the line. Don't * try to read the A/D port LDD TMRREG,X SUBD #25600 BLO CHKTEMP_END * Set the ADCTL to read PE7 LDX #REGBAS LDAA #%10000111 STAA ADCTL,X JSR GetVal * ADR1 is one of 4 AD values we can use LDAA ADR1,X STAA VOCPORT For debugging, output the value to the ISD's bus (port B) SUBA TOASTLEVEL BHS Hot CLRA RTS Hot LDAA #1 RTS CHKTEMP_END CLRA RTS *********************************************************** * Common ADC routine to wait until ADC is ready with value. GetVal NOP LDX #REGBAS WaitAD LDAA Option,X ANDA #%10000000 BEQ WaitAD ReadAD LDAA ADCTL,X ANDA #%10000000 BEQ ReadAD RTS **************************************************************************** * void Say(int vIndex) * { SAY STAA VOCPORT outva(vIndex); /* Output voice clip address */ LDAA #'S JSR OUTA JSR OUTCRLF LDX #$1000 gPlayClip = 0; BCLR isdENBAR,X isdENMASK LDAA #20 /* The low pulse must be long enough for the chip to catch it */ S0 NOP NOP SUBA #1 BNE S0 BSET isdENBAR,X isdENMASK gPlayClip = 1; BRSET isdEOM,X isdEOMMASK * while (!gEOM); BRCLR isdEOM,X isdEOMMASK * while (gEOM); /* low for 16 ms */ * /* If the toaster's voice triggered * the speech chip, reset the recognition */ LDAA #srRDSTATUS outs(srRdStatus); JSR OUTS JSR INST st = inst(); SUBA #srRDYCMD if (st != srRdyCmd) BNE S1 LDAA srINITED if (srInited) BEQ S1 JSR BEGINRECOG S1 RTS * } ********************************************************************************* * bool MotionDetected(void) * { MOTDETECT LDAA #'O * JSR OUTA * JSR OUTCRLF LDAA MOTPORT ANDA #MOTMASK BEQ MD1 if (gMotion) { LDAA motLASTST if (!gLastMotState) { BNE MD2 LDAA #1 gLastMotState = 1; STAA motLASTST RTS return 1; * } MD1 LDAA motLASTST } else if (gLastMotState) { BEQ MD2 CLRA STAA motLASTST gLastMotState = 0; * } * } MD2 CLRA RTS return 0; * } ********************************************************************************** * void RespondToMotion(void) * { RESPONDMOT LDAA #'R JSR OUTA LDAA #'M JSR OUTA JSR OUTCRLF LDAA #vLIKETOAST Say(vLikeToast); JSR SAY RM1 JSR WORDRECOG BNE RM1 JSR GETWORD /* Yes */ SUBA #wYES BNE RM2 JSR MAKETOAST RTS RM2 LDAA #vOKAY JSR SAY RTS * } ********************************************************************************* INIT_BREAD NOP * Set up IC1 to override microcontroller's grip on the servo * and raise the bread platform * These lines are needed to set up the IC1's ISR on the EVB * LDAA #$7E Jump (extended) opcode * STAA PVIC1 * LDX #IC1ISR * STX PVIC1+1 LDX #REGBAS * Set up OC3 (A[5]) to drop pulse at successful output compare BCLR TMSK1,X %11111000 BCLR TFLG1,X %11111000 Writing a 1 clears the bits LDAA #OC3_CTL STAA TCTL1,X LDD #PW_RAISE STD TOC3,X * Set up OC1 to raise pulse at timer overflow LDAA #OC3_OC1 OC1 affects OC3 STAA OC1M,X STAA OC1D,X OC1 writes a 1 to OC3 CLRA CLRB STD TOC1,X Successful compare at CLK == 0 BSET TMSK1,X %00000100 IC1 ISR BSET TFLG1,X %00000100 Clear IC1 flag (if any) LDAA #%00110000 Capture on any edge STAA TCTL2,X * Here's where we initialize the ADC. LDAA #%10000000 STAA Option,X CLI Enable interrupts ** JSR RAISE RTS ********************************************************************************* RAISE LDX #REGBAS ** LDAA #OC3_CTL Enable OC3 ** STAA TCTL1,X ** LDAA #OC3_OC1 Enable OC1 ** STAA OC1M,X LDD #PW_RAISE Raise bread platform STD TOC3+REGBAS ** JSR PAUSEBREAD ** CLRA ** STAA TCTL1,X Disable OC3 ** STAA OC1M,X Disable OC1 RTS ********************************************************************************* LOWER LDX #REGBAS ** LDAA #OC3_CTL Enable OC3 ** STAA TCTL1,X ** LDAA #OC3_OC1 Enable OC1 ** STAA OC1M,X LDD #PW_LOWER STD TOC3+REGBAS ** JSR PAUSEBREAD ** CLRA ** STAA TCTL1,X Disable OC3 ** STAA OC1M,X Disable OC1 RTS ********************************************************************************* IC1ISR LDX #REGBAS LDD #PW_RAISE STD TOC3,X BSET TFLG1,X %00000100 Clear IC1 flag RTI ********************************************************************************* PAUSEBREAD LDAA #BREAD_DLY PB1 PSHA JSR PAUSE32 PULA DECA BNE PB1 RTS **************************************************************************** INK LDX #$1000 Set direction bits to input BCLR DDRC,X #KMASK LDAA KBUS Read data from K bus ANDA #KMASK Discard non-K bus data RTS **************************************************************************** INST JSR INK Status register is on K bus ANDA #%00000011 Status bits are lower two RTS **************************************************************************** OUTK LDX #$1000 BSET DDRC,X #KMASK PSHA Save data to be written TSX LDAA KBUS Read current value ANDA #KMASK^$FF Save non-K bus part ORA 0,X Add K-bus part STAA KBUS Write data NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP PULA Clean up stack RTS **************************************************************************** OUTS LDX #$1000 BSET DDRC,X #SMASK LSLA 00000SSS -> 0000SSS0 LSLA 0000SSS0 -> 000SSS00 LSLA 000SSS00 -> 00SSS000 LSLA 00SSS000 -> 0SSS0000 PSHA Save data to be written TSX LDAA SBUS Read current value ANDA #SMASK^$FF Save non-S bus part ORA 0,X Add S-bus part STAA SBUS Write data NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP PULA Clean up stack RTS PAUSE NOP NOP SUBA #1 BNE PAUSE RTS PAUSE32 LDAA #$FFFF P32 DECA BNE P32 RTS vWORDS FCB vYES,vNO,vTOAST,vLIGHT,vMEDIUM,vDARK,vEND srWORDS FDB srStrYES,srStrNO,srStrTOAST,srStrLIGHT,srStrMEDIUM,srStrDARK,srStrEND static char* words[] = { srStrYES FCC 'yes' "yes", FCB $04 srStrNO FCC 'no' "no", FCB $04 srStrTOAST FCC 'toast' "toast", FCB $04 srStrLIGHT FCC 'light' "light", FCB $04 srStrMEDIUM FCC 'medium' "medium", FCB $04 srStrDARK FCC 'dark' "dark", FCB $04 srStrEND FCC 'end' "end" FCB $04 * }; ISR_MSG1 FCC 'Train word: ' FCB $04 CONFZD_MSG FCC 'Voice chip confused... returning to command loop.' FCB $04