home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
pub
/
ucsdterak
/
kbdhandlr.text
< prev
next >
Wrap
Text File
|
2020-01-01
|
7KB
|
152 lines
; ----------------------------
; KBDHNDLR TTY Receive Handler
; ----------------------------
;
; Two routines are provided that maintain an interrupt-driven
; TTY-receive queue. Appropriate PASCAL declarations are:
;
; CONST KQSIZE = maximum number of queued characters
;
; TYPE QUEUE = RECORD (* These are order-dependent !!! *)
; QSIZE: INTEGER;
; INP: INTEGER;
; OUTP: INTEGER;
; MAXCHAR: INTEGER;
; DATA: PACKED ARRAY [0..RCVQSIZE] OF CHAR;
; END;
; VAR KQ: QUEUE; (* must be declared in outermost block *)
;
; PROCEDURE KBDINIT (VAR Q: QUEUE; SIZE:INTEGER); EXTERNAL;
; PROCEDURE KBDFINIT; EXTERNAL;
;
; KBDINIT (KQ,KQSIZE); (* initialize the queue handler *)
;
; WHILE TRUE DO
; WITH KQ DO
; IF INP <> OUTP THEN (* characters available *)
; BEGIN
; CH := DATA[OUTP];
; OUTP := OUTP+1; IF OUTP > QSIZE THEN OUTP := 0;
; ...
; END;
;
; KBDFINIT; (* terminate the queue handler *)
;
; The RECORD declaration for the queue must appear exactly as it
; does above except that you can of course use any names you like.
; Do NOT attempt to lump the first four integer variables together
; into a single group of the form list:INTEGER. In that case,
; the compiler allocates them in reverse order, so that your code
; and the interrupt handler will not agree about which words have
; what meaning.
;
; The queue handler runs continuously as an interrupt-driven task
; at high priority. As characters come in, it advances the queue
; INP pointer and keeps track of the maximum number of characters in
; the queue in the MAXCHAR variable. Queue overflow is indicated
; by MAXCHAR > QSIZE. You must terminate by calling KBDFINIT, or
; the TTY receive interrupts will be left enabled and you will end
; up crashing the system by executing garbage code when the next
; character is received. (KBDFINIT also repairs the interrupt
; vectors for breakpoints and the clock, so failing to call it will
; quite likely crash the system even in the absence of incoming
; TTY characters.)
;
; The manipulation of the clock and BPT interrupt vectors is borrowed
; from UCSD's old communications program. The purpose is to allow
; the clock handler to be interrupted by incoming TTY characters.
;
KDB .EQU 177562 ; Receive Data Buffer absolute address
KSR .EQU 177560 ; Receive Status Register absolute address
KINTV .EQU 60 ; Receiver Interrupt Vector address
CLKINTV .EQU 100 ; Clock interrupt vector address
BPTINTV .EQU 14 ; BPT interrupt vector address
QXCINTV .EQU 250 ; QX controller interrupt vector
;
.PROC KBDINIT,2 ; (VAR Q:QUEUE, SIZE:INTEGER)
;
.DEF KBDLOC ; holds vector address
.DEF KBDPR ; holds old priority
Q .EQU 4 ; stack offset for Q address
SIZE .EQU 2 ; stack offset for QSIZE value
;
MOV Q(SP),R0 ; obtain the Q record address
MOV R0,KQADRS ; remember Q address
MOV SIZE(SP),(R0)+ ; store size in QSIZE word
MOV #0,(R0)+ ; clear INP, OUTP, and MAXCHAR
MOV #0,(R0)+
MOV #0,(R0)
;
;
MOV @#KINTV,KBDLOC ; save old interrupt vector
MOV @#KINTV+2,KBDPR ; and old priority
MOV #KHNDLR,@#KINTV ; store interrupt handler address
MOV #200,@#KINTV+2 ; set interrupt priority 4 for TTY input
;MOV #100,@#KSR ; enable interrupts for TTY input
;
MOV (SP)+,R0 ; pop return address from stack
ADD #4,SP ; discard 2 parameters (4 bytes)
JMP @R0 ; and return to PASCAL interpreter
;
KQADRS .WORD 0 ; holds Q address for handler
KBDLOC .WORD 0 ; holds old interrupt vector
KBDPR .WORD 0 ; holds old interrupt priority
;
QSIZE .EQU 0 ; offset from Q
INP .EQU 2 ; likewise
OUTP .EQU 4
MAXCHAR .EQU 6
DATA .EQU 10
;
KHNDLR: MOV R0,-(SP) ; free registers R0, R1, R2 for use
MOV R1,-(SP)
MOV R2,-(SP)
MOV KQADRS,R2 ; fetch Q address saved by KBDINIT
MOV INP(R2),R0 ; fetch INP value
MOV R0,R1 ; make a working copy
ADD R2,R1 ; R1 = address (Q) + value (INP)
MOVB @#KDB,DATA(R1) ; DATA[INP] := input character
BICB #200,DATA(R1) ; clear bit 8 (parity)
BEQ EXIT ; ignore nulls (do not bump INP)
INC R0 ; INP := INP+1
CMP QSIZE(R2),R0
BPL NOWRAP ; if QSIZE >= INP then no wraparound
CLR R0 ; else INP := 0
NOWRAP MOV R0,INP(R2) ; restore INP
;
SUB OUTP(R2),R0
BMI INOUT
BEQ INOUT
BR OUTIN ; if INP > OUTP, # char = INP - OUTP
INOUT ADD QSIZE(R2),R0 ; otherwise, # char = QSIZE+1 + INP - OUTP
ADD #1,R0
OUTIN CMP MAXCHAR(R2),R0
BPL EXIT ; if MAXCHAR >= # char, exit
MOV R0,MAXCHAR(R2) ; otherwise, store new MAXCHAR
;
EXIT MOV (SP)+,R2 ; restore registers for caller
MOV (SP)+,R1
MOV (SP)+,R0
RTT ; return from interrupt
;
CLKHNDLR: COM CLKFLG ; do not reexecute BPT if BPT handler
BEQ CLKEXIT ; takes so long that clock ticks again
BPT ; let breakpoint transfer to old clock
CLKEXIT COM CLKFLG ; reset flag
RTI ; and exit
;
CLKFLG .WORD 0 ; flags reentry before BPT exit
;
.PROC KBDFINIT
.REF KBDLOC ; old interrupt vector saved by KBDINIT
.REF KBDPR ; old kbd priority saved by KBDINIT
;
MOV @#KBDPR,@#KINTV+2 ; restore interrupt priority
MOV @#KBDLOC,@#KINTV ; and interrupt vector
RTS PC ; and return
;
.END