SBTTL 'IRQ Handelers and I/O Routines (28_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 (17_Nov_84) ;------------------ ; ; IRQVEC Maskable Interrupt Entry ; NMIVEC Non_Maskable Interrupt Entry ; ; GETKEY Get a Character from the Keyboard ; PUTKEY Put a Character to the Keyboard ; ; KEYINS Insert a Character into the Key Buffer ; KEYREM Remove a Character from the Key Buffer ; 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 PAGE ;---------------------------------------------------------------------- ; Maskable Interrupt Entry Point (17_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 (28_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 ;---------------------------------------------------------------------- ; 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 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 ;---------------------------------------------------------------------- ; 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 (18_Dec_84) ;----------------------------------------------------- ; ININS: LDX INCNT ;If (Lo_Byte of Bytes Remaining eq 0) BNE INISK1 DEC INCNT+1 ; Adjust Hi_Byte of Bytes Remaining BPL INISK1 ; If (Hi_Byte of Bytes Remaining lt 0) INC INCNT+1 ; Restore Hi_Byte of Bytes Rem. LDA #$FF ; A:= Buffer Full Flag STA BUFFULL ; Set the Buffer Full Flag RTS ; Return INISK1: DEC INCNT ;Adj Lo_Byte Bytes of Remaining CPX #INSLIM ;If ( (Lo_Byte of Bytes Remaining eq Limit) And BNE INISK2 LDX INCNT+1 ; (Hi_Byte of Bytes Remaining eq 0) ) BNE INISK2 TAX LDA UARTCMD AND #%11111101 ; Clear DTR STA UARTCMD STA S1STAT TXA INISK2: LDX #0 ;X_Index:= 0 STA (INEP,X) ;Put the Character in the Buffer INC INEP ;Increment the Storage Pointer BNE INISK3 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 INISK3: RTS ; Return PAGE ;---------------------------------------------------------------------- ; Remove a Character from the Input Buffer (18_Dec_84) ;----------------------------------------------------- ; INREM: LDX INCNT ;If ( (Lo_Byte of Bytes Remaining eq 0FF) And BNE INRSK1 LDX INCNT+1 ; (Hi_Byte of Bytes Remaining eq Limit) ) CPX #(HIGH INLEN) BNE INRSK1 LDA #$FF ; A:= Buffer Empty Flag RTS ; Return INRSK1: INC INCNT ;Adjust the Bytes Remaining Counter BNE INRSK2 INC INCNT+1 INRSK2: LDX INCNT ;If ( (Lo_Byte of Bytes Remaining eq Limit) And CPX #REMLIM BNE INRSK3 LDX INCNT+1 ; (Hi_Byte of Bytes Remaining eq 0) BNE INRSK3 LDA UARTCMD ORA #2 ; Set DTR STA UARTCMD STA S1STAT INRSK3: LDX #0 ;X_Index:= 0 LDA (INSP,X) ;A:= Character from Buffer INC INSP ;Increment the Buffer Pointer BNE INRSK4 ;If (Lo_Byte Buffer Pointer eq 0) PHA INC INSP+1 ; Adjust Hi_Byte of the Buffer Pointer LDA INSP+1 AND #7 ; (Last Location in Buffer is $7FF) ORA #HIGH INBUF ; (First Location in Buffer is $400) STA INSP+1 PLA ; (get char back) INRSK4: STX BUFFULL ;Clear Buffer Full RTS ;Return END