SBTTL 'IRQ Handelers and I/O Routines (12_Dec_84)' PAGE ;====================================================================== ; ; Copyright 1984 ; Morrow Designs, Inc. ; San Leandro, Ca. ; ; ; Module Description: ;-------------------- ; This module contains the interrupt routines, the circular ; buffer handeling routines and the keyboard input and output routines. ; ;---------------------------------------------------------------------- ; Index (12_Nov_84) ;------------------ ; ; IRQVEC Maskable Interrupt Entry ; NMIVEC Non_Maskable Interrupt Entry ; ; SNDINS Insert a Character into the Send Buffer ; SNDREM Remove a Character from the Send Buffer ; ININS Insert a Character into the Input Buffer ; INREM Remove a Character from the Input Buffer ; KEYINS Insert a Character into the Key Buffer ; KEYREM Remove a Character from the Key Buffer ; ; GETKEY Get a Character from the Keyboard ; PUTKEY Put a Character to the Keyboard PAGE ;---------------------------------------------------------------------- ; Maskable Interrupt Entry Point (12_Dec_84) ;------------------------------------------- ; 1) Irq occurs when the keyboard wants to send a char to the processor ; 2) The FTCHKEY entry is only used by the PUTKEY routine. ; ;PUTKEY Entry Point FTCHKEY:PLA ;Alias an IRQ (so RTI returns properly) TAX INX TXA PHA ;increment the return address by one PHP ;push the status onto the stack ;Normal IRQ Entry Point IRQVEC: PHA ;Save the Registers TYA PHA TXA PHA JSR GETKEY ;Get the key from the keyboard LDY LOCKMD ;If (Keyboard ne Locked) BMI IRQSK1 JSR KEYINS ; Insert Character into the Key Buffer IRQSK1: PLA TAX ;Restore the Registers PLA TAY PLA RTI ;Return PAGE ;---------------------------------------------------------------------- ; Non_Maskable Interrupt Entry Point (12_Dec_84) ;----------------------------------------------- ; 1) This Routine handels interrupts from the UART (ie the host computer ; has sent a character). Control is transfer to this routine from the ; page zero vector (see the DATxx module and the PUTKEY routines). ; 2) The GETNMI entry is only used by the PUTKEY routine. ; 3) Notice that nulls are ignored unless we're in monitor mode. ; ;PUTKEY Entry Point GETNMI: PLA ;Alias an IRQ (so RTI returns properly) TAX INX TXA PHA ;increment the return address by one PHP ;push the status onto the stack ;Normal NMI Entry Point NMIVEC: SEI ;disable maskable interrupts PHA TYA ;(Save the Index Registers) PHA TXA PHA LDA S1DATA ;Get a Character from the Uart AND #%01111111 ;(Remove the Parity Bit) BNE NMISK1 ;If ( (Char ne 0) Or LDY MONITOR ; (Monitor eq Enabled) ) BEQ NMISK2 NMISK1: JSR ININS ; Insert Char into Input Buffer NMISK2: PLA ;Restore the Registers TAX PLA TAY PLA RTI ;Return PAGE ;---------------------------------------------------------------------- ; Insert a Character into the Send Buffer (30_Nov_84) ;---------------------------------------------------- ; SNDINS: LDY BRKHIT ;If (BrkHit eq True) BEQ SISK1 CMP #CTRLC ; If (Character to Store eq ^C) BEQ SISK2 ; return LDY #0 ; Else STY BRKHIT ; BRKHIT = FALSE SISK1: LDY OUTEP ;Y:= End Buffer Index INY ;Increment the End Buffer Index CPY OUTSP ;If (The Buffer HAS NOT Overrun) BEQ SISK2 STY OUTEP ; Save the End Buffer Offset STA SNDBUF,Y ; Store the Character SISK2: RTS ;Return ;---------------------------------------------------------------------- ; Remove a Character from the Send Buffer (30_Nov_84) ;---------------------------------------------------- ; SNDREM: LDX OUTSP ;X:= Start Buffer Index CPX OUTEP BNE SRSK1 ;If (The Buffer is Empty) LDA #$FF ; A:= 0FF (Buffer Empty Flag) RTS ; Return SRSK1: INX ;Else Increment the Start Buffer Index STX OUTSP ; Update the Start Buffer Index LDA SNDBUF,X ; A:= Next Character RTS ; Return PAGE ;---------------------------------------------------------------------- ; Insert a Character into the Input Buffer (28_Nov_84) ;----------------------------------------------------- ; ININS: TAX ;(save the character) LDY #0 ;Y_Index:= 0 LDA #$FF CMP (INEP),Y ;If (Buffer is NOT Full) BNE IISK2 TXA ; (restore character) STA (INEP),Y ; Put the Character in the Buffer INC INEP ; Increment the Storage Pointer BNE IISK1 INC INEP+1 LDA INEP+1 AND #7 ; (Last Location in Buffer is $7FF) ORA #HIGH INBUF ; (First Location in Buffer is $400) STA INEP+1 IISK1: RTS ; Return IISK2: STA BUFFULL ;Else Set the Buffer Full Flag RTS ; Return ;---------------------------------------------------------------------- ; Remove a Character from the Input Buffer (28_Nov_84) ;----------------------------------------------------- ; INREM: LDY #0 ;Y_Index:= 0 LDA (INSP),Y ;A:= Character from inbuf CMP #$FF ;If (There is a valid Character in the Buffer) BEQ IRSK2 TAX ; (save the character removed) LDA #$FF STA (INSP),Y ; mark the spot empty INC INSP BNE IRSK1 ; Adjust the Buffer Pointer INC INSP+1 LDA INSP+1 AND #7 ; (Last Location in Buffer is $7FF) ORA #HIGH INBUF ; (First Location in Buffer is $400) STA INSP+1 IRSK1: TXA ;(get char back) IRSK2: RTS ;Return PAGE ;---------------------------------------------------------------------- ; Insert a Character into the Key Buffer (26_Nov_84) ;--------------------------------------------------- ; KEYINS: TAY ;Y:= Character to Store LDX KEYSP ;X:= Key Start Index TXA ;A:= Key Start Index CLC ADC #1 ;Increment the Start Pointer AND #$1F ;(Truncate Pointer to 32 Locations) CMP KEYEP ;If (Incremented Start Pointer ne End Pointer) BEQ KISK1 STA KEYSP ; Update the Key Start Pointer STY KEYBUF,X ; Put character in the Keyboard Buffer KISK1: RTS ;Return ;---------------------------------------------------------------------- ; Remove a Character from the Key Buffer (21_Nov_84) ;--------------------------------------------------- ; KEYREM: LDX KEYEP ;X:= Key End Index LDY KEYBUF,X ;Y:= Character from Keyboard Buffer INX TXA ;A:= Key End Index + 1 AND #$1F ;(Truncate Index to 32 Locations) STA KEYEP ;Update the Key End Pointer TYA ;A:= Character read from the Buffer RTS ;Return PAGE ;---------------------------------------------------------------------- ; Get a Character from the Keyboard ;---------------------------------- ; 1) returns with character in A reg ; GETKEY: LDX #0 STX PARTIAL ; clear input assembly area LDX #3 JSR KDLY ; wait 30 micro seconds LDY #8 ; set to receive 8 data bits from kbrd GTKLP1: LDA #1 ORA BDREG ; must not change other bits in baud register STA BAUD ; send request data to KBRD LDX #21 JSR KDLY ; wait 210 microseconds LDA BAUD AND #%10000000 ; get kbrd data bit ORA PARTIAL ; add in other bits STA PARTIAL ; save the bit(s) we have so far LDA BDREG STA BAUD ; clear request data DEY BEQ GTKSK1 ; if 0, then we have 8 bits, so go LDA PARTIAL ; else, set up partial for getting next bit added to it LSR A STA PARTIAL ; and restore partial LDX #10 JSR KDLY ; wait 100 micro secs JMP GTKLP1 ; then, go get the next bit GTKSK1: LDX #10 JSR KDLY LDA PARTIAL ; get the character we rcv'd RTS PAGE ;---------------------------------------------------------------------- ; Put a Character to the Keyboard (12_Dec_84) ;-------------------------------------------- ; 1) This routine sends the character in A reg to the keyboard. ; 2) If the last character sent was a bell then a delay is inserted ; before sending the character to give the keyboard time to transmit ; a character. ; 3) Notice that the NMI vector in page zero is redirected during ; the contention check to a routine (in page zero) that increments ; the Y register and then returns; Consequently, after the contention ; check, if the Y register is non-zero then there is a character from ; the host that needs to be processed. ; ;Check for a Bell Delay PUTKEY: LDX BELSNT ;If (Last Character Sent was a Bell) BEQ PTKSK1 LDY #40 ; Y:= Number of 2560 us delays (.1 sec) PTKLP0: LDX #$FF ; Repeat X:= 2560 us Delay JSR KDLY ; Delay 2560 us DEY ; Decrement Delay Count BNE PTKLP0 ; Until (Number of 2560 us Delays eq 0) PTKSK1: LDX #0 ;Set Bell Flag to False (Zero) CMP #BEEP ;If (Current Character is a Bell) BNE PTKSK2 DEX ; Set Bell Flag to True (Non_Zero) PTKSK2: STX BELSNT ;Update the Bell Sent Flag SEI ;Disable Interrupts PHA ;(Save Char to Send) ;Quick Contention Check PTKLP1: LDX BAUD ;While (Keyboard is trying to Send) BPL PTKSK3 PTKLP2: JSR FTCHKEY ; handle KBRD request as an interrupt JMP PTKLP1 PTKSK3: LDX #4 ;Counter:= 10us delay PTKLP3: DEX ;Repeat Decrement the Counter BNE PTKLP3 ;Until (Counter eq 0) ;Request Attention LDA #$1 ;assert attention to KBRD ORA BDREG ;but without affecting other bits STA BAUD ;Full Contention Check LDY #0 ;Y:= Host Request Flag LDX #4 ;X:= Timer LDA #LOW NMICNT STA VCTNMI+1 ;Redirect the NMI Vector LDX #2 ;Counter:= 5us delay PTKLP4: DEX ;Repeat Decrement the Counter BNE PTKLP4 ;Until (Counter eq 0) LDX #4 LDA #LOW NMINRM STA VCTNMI+1 ;Restore the Normal NMI Vector LDX BAUD ;check if KBRD Ack asserted BPL PTKSK4 ;If ( keyboard Ack asserted) then LDA BDREG STA BAUD ; cancel request to keyboard, DEY ; If (There was an NMI) BNE PTKLP2 JSR GETNMI ; Get the Key from the Host JMP PTKLP2 ; GoTo get the char from the keyboard ;Begin Transfer PTKSK4: DEY ;If (there was an NMI) BNE PTKSK5 JSR GETNMI ; Get the Key from the Host PTKSK5: LDY #8 ;Y:= Bit Counter (set to send 8 data bits) ACK1: LDX BAUD ;Repeat wait for KBRD to request data BPL ACK1 PLA ; get char to send TAX ; save it LSR A ; shift it for next time through PHA ; put back on stack TXA ; get bit to send AND #1 ; only LSB is needed ORA BDREG ; be sure not to change rest of register STA BAUD ; output bit to KBRD PTKLP5: LDX BAUD ; wait for KBRD to ACK that it got bit BMI PTKLP5 DEY ; now, adjust number of bits left to send BNE ACK1 ;Until (all 8 bits sent) LDA BDREG ;go to quiescent state STA BAUD PLA ;restore stack CLI ;re-enable interrupts RTS ;Return END