PGM RDRIV
REL
**********************************************************
* *
* Device driver for single character input devices ie. *
* Console keyboard, paper tape reader etc. *
* *
**********************************************************
*
* States and interrupt vectors
*
MPICMSK EQU #C2
COKRDY EQU 2
ERRVEC EQU #3FC * ERROR TRAP VECTOR
BRKERR EQU #30
PARERR EQU 8
*
* Device control block symbols
*
* 0 ; device driver ptr (BCPL)
* 0 ; link to code (=0)
* 0
D.ID EQU 6 * id
D.WKQ EQU 8 * work queue
D.START EQU 10 * start routine - for QPKT
D.STOP EQU 14 * stop routine - for DQPKT
D.CALL EQU 18 * subroutine jump to
D.INT EQU 20 * interrupt routine offset address
D.I EQU D.CALL+6 * offset for interrupt rtn
D.VEC EQU 24 * interrupt vector number
D.CSW EQU 26 * control and status word
D.IOW EQU 28 i/o address
*
* Packet symbols
*
P.ID EQU 2 * task or device id
P.TYPE EQU 4 * type or action
P.RES1 EQU 6 * first result
P.RES2 EQU 8 * second result
P.A1 EQU 10 * argument 1
*
* The rootnode
*
CRNTSK EQU #506
DEVMVP EQU #51A * MOVPKT for device drivers (MC addr)
DEVINT EQU #51E * INTENT for device drivers (MC addr)
DEVRET EQU #522 * INTRET for device drivers (MC addr)
DW RINITI * initialisation rtn
DW RUNINI * uninitialisation rtn
* Device initialisation routine. It is entered with the
* address of the DCB in BX. BX and DI must be preserved.
* assume console USART has been set up by the monitor
RINIT MOV D.START(BX),!RSTART
MOV D.STOP(BX),!RSTOP
MOV D.START+2(BX),CS
MOV D.STOP+2(BX),CS
PUSH SI
MOV SI,!RINT make offset for CALL in DCB
MOV D.INT(BX),SI
MOV D.INT+2(BX),CS correct code seg in DCB
MOV SI,D.VEC(BX) get interrupt vector number
ADD SI,!40
SHL SI
SHL SI
MOV (SI),BX plug interrupt vector with
ADD (SI),!D.CALL address
MOV 2(SI),!0 interrupt CS = 0
POP SI
RETS
* Device uninitialisation routine. It is entered with
* the address of the DCB in BX, which must be preserved.
RUNIN PUSH AX
MOV AX,ERRVEC
PUSH BX
MOV BX,D.VEC(BX) get address to plug
ADD BX,!40
SHL BX
SHL BX
MOV (BX),AX plug it
MOV AX,ERRVEC+2
MOV 2(BX),AX
POP BX
POP AX
RETS
* Device start routine. This is entered whenever a pkt
* is sent to the device and its work queue is empty. It
* is entered with the address of the DCB in BX, and the
* BCPL address of the packet in SI. It returns non-zero.
RSTART MOV DX,D.IOW(BX) get address of i/o register
IN ignore chars in buffer
IN
* work out which PIC bit should be unmasked
MOV CX,D.VEC(BX)
MOV DL,!1
SHL DL,CL
NOT DL 0 bit now in correct position
IN MPICMSK get current mask
AND AL,DL
OUT MPICMSK enable interrupt
NOT DL return non-zero
RETS
* Device stop routine. This is entered if the head pkt
* is dequeued from the device. It is entered with the
* DCB in BX, which must
* be preserved.
RSTOP PUSH CX
MOV DL,!1
MOV CX,D.VEC(BX) get interrupt number
SHL DL,CL
IN MPICMSK
OR AL,DL
OUT MPICMSK
POP CX
RETS
* This code is entered by the subroutine jump in the DCB
* which in turn was entered via the interrupt vector. The last
* word pushed onto the m/c stack therefore is the address of the
* DCB + D.I
RINT PUSH BX
PUSH AX
PUSH CX
PUSH DX
PUSH SI
MOV BX,SP get stack pointer
MOV BX,10(BX) get IP (points into DCB)
MOV DX,D.CSW-D.I(BX) status register address
MOV SI,D.WKQ-D.I(BX) get pkt
MOV AX,CRNTSK
SHL AX
SHL SI MC pkt address
JE RINTOUT
XOR CX,CX prepare pkt RES2
IN get device status
TEST AL,!COKRDY character received?
JNE RINT2 ok USART agrees
NOT CX error
RINT2 MOV P.RES2(SI),CX set RES2
TEST AL,!BRKERR break hit?
JE RINT2A probably not
MOV P.RES2(SI),!1
MOV DX,D.IOW-D.I(BX)
IN clear bum char
MOV AL,!#37
MOV DX,D.CSW-D.I(BX)
OUT clear error
XOR AX,AX put 0 in pkt
B RINT2B
*
RINT2A TEST AL,!PARERR parity error
JE RINT2AB no
MOV DX,D.IOW-D.I(BX)
IN
MOV AL,!#37
MOV DX,D.CSW-D.I(BX)
OUT clear error
MOV AX,CRNTSK
SHL AX
B RINTOUT
*
RINT2AB MOV DX,D.IOW-D.I(BX) get address of i/o register
IN fetch character
XOR AH,AH clear top byte of word
RINT2B MOV P.RES1(SI),AX store char. in pkt
MOV DX,(SI) deq pkt
MOV D.WKQ-D.I(BX),DX
OR DX,DX
JNE RINT3
MOV CX,D.VEC-D.I(BX) last dequeued so stop device
MOV DL,!1
SHL DL,CL
IN MPICMSK
OR AL,DL
OUT MPICMSK
*
RINT3 MOV CX,D.ID-D.I(BX) id of sender
MOV BX,CRNTSK setting args for MOVPKT
SHL BX
CIS DEVMVP
RINTOUT JIS DEVINT exit via INTENT
*
EVEN
DSEG
RINITI DW RINIT
DW 0
RUNINI DW RUNIN
DW 0
END