home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
ucsdterak
/
rcvhandlr.text
< prev
next >
Wrap
Text File
|
1984-04-10
|
7KB
|
157 lines
; ----------------------------
; RCVHNDLR TTY Receive Handler
; ----------------------------
;
; Two routines are provided that maintain an interrupt-driven
; TTY-receive queue. Appropriate PASCAL declarations are:
;
; CONST RCVQSIZE = 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 RCVQ: QUEUE; (* must be declared in outermost block *)
;
; PROCEDURE RCVINIT (VAR Q: QUEUE; SIZE:INTEGER); EXTERNAL;
; PROCEDURE RCVFINIT; EXTERNAL;
;
; RCVINIT (RCVQ,RCVQSIZE); (* initialize the queue handler *)
;
; WHILE TRUE DO
; WITH RCVQ DO
; IF INP <> OUTP THEN (* characters available *)
; BEGIN
; CH := DATA[OUTP];
; OUTP := OUTP+1; IF OUTP > QSIZE THEN OUTP := 0;
; ...
; END;
;
; RCVFINIT; (* 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 RCVFINIT, 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. (RCVFINIT 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.
;
RDB .EQU 177522 ; Receive Data Buffer absolute address
RSR .EQU 177520 ; Receive Status Register absolute address
RCVINTV .EQU 120 ; 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 RCVINIT,2 ; (VAR Q:QUEUE, SIZE:INTEGER)
;
.DEF BPTLOC ; used to save BPT interrupt handler adrs
.DEF BPTPR ; used to save BPT handler 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,RCVQADRS ; 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 @#BPTINTV,BPTLOC ; save old BPT handler address
MOV @#BPTINTV+2,BPTPR ; and old BPT handler priority
MOV @#CLKINTV,@#BPTINTV ; make BPT vector point to old clock
MOV #0,@#BPTINTV+2 ; and let it run at low priority
MOV #CLKHNDLR,@#CLKINTV ; and replace clock handler with ours
MOV #0,@#QXCINTV+2 ; make floppy interruptable
;
MOV #RCVHNDLR,@#RCVINTV ; store interrupt handler address
MOV #200,@#RCVINTV+2 ; set interrupt priority 4 for TTY input
MOV #100,@#RSR ; 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
;
RCVQADRS .WORD 0 ; holds Q address for handler
BPTLOC .WORD 0 ; saves old BPT handler location
BPTPR .WORD 0 ; saves old BPT handler priority
;
QSIZE .EQU 0 ; offset from Q
INP .EQU 2 ; likewise
OUTP .EQU 4
MAXCHAR .EQU 6
DATA .EQU 10
;
RCVHNDLR: MOV R0,-(SP) ; free registers R0, R1, R2 for use
MOV R1,-(SP)
MOV R2,-(SP)
MOV RCVQADRS,R2 ; fetch Q address saved by RCVINIT
MOV INP(R2),R0 ; fetch INP value
MOV R0,R1 ; make a working copy
ADD R2,R1 ; R1 = address (Q) + value (INP)
MOVB @#RDB,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 RCVFINIT
.REF BPTLOC ; old BPT handler loc, saved by RCVINIT
.REF BPTPR ; old BPT handler priority, likewise
;
MOV #0,@#RSR ; disable receive interrupt
MOV @#BPTINTV,@#CLKINTV ; repair clock interrupt vector
MOV @#BPTPR,@#BPTINTV+2 ; reestablish BPT handler priority
MOV @#BPTLOC,@#BPTINTV ; repair BPT handler address
MOV #340,@#QXCINTV+2 ; repair QX controller vector
RTS PC ; and return
;
.END