.TITLE YRDRV .IDENT /12.2XC/ ; RECEIVER DL11 DRIVER ; RECEIVE HALF ONLY (1ST CSR/DATA REG OF PAIR) ; ; MODIFIED BY: ; ; R. E. CALDWELL 30-OCT-79 ; ; RC024 -- REMOVE UNNEEDED CONDITIONALIZATION. ; ; DL11 ASYNCHRONOUS COMMUNICATIONS DRIVER ; ; INPUT TERMINATION ON HEX FF (377 OCTAL) CHARACTER. ALSO ON ; BYTE COUNT... ; ; MACRO LIBRARY CALLS ; LD$YR=0 ; REMOVE IF YR: NOT LOADABLE .IIF NDF,$XDT,NRM$YD=0 .MCALL HWDDF$,PKTDF$ HWDDF$ ;DEFINE HARDWARE REGISTERS PKTDF$ ;DEFINE I/O PACKET OFFSETS .MCALL UCBDF$,CUCDF$ UCBDF$ ; DEFINE UCB OFFSETS CUCDF$ ;COMMUNICATIONS UCB LABELS ; ; CONFIGURATION DEPENDENT PARAMETERS ; ; ; EQUATED SYMBOLS ; ; ; RXCSR BIT ASSIGNMENTS ; DTSTCH= 100000 ;DATA SET CHANGE RING= 40000 ;RING LINE ASSERTED CTS= 20000 ;CLEAR TO SEND CRRIER= 10000 ;CARRIER STATE RECACT= 4000 ;RECEIVER ACTIVE RXDONE= 200 ;RECEIVER DONE RCVENB= 100 ;RECEIVER INTERRUPT ENABLE DSINTE= 40 ;DATA SET CHANGE INTERRUPT ENABLE RTS= 4 ;REQUEST TO SEND TRMRDY= 2 ;DATA TERMINAL READY ; ; RXDBUF BIT ASSIGNMENTS ; RXERR= 100000 ;RECEIVER ERROR "OR" BIT OVRNER= 40000 ;RECEIVER OVERRUN ERROR IF SET FRMERR= 20000 ;RECEIVER FRAMING ERROR ; ; TXCSR BIT ASSIGNMENTS ; TXRDY= 200 ;TRANSMITTER DONE BIT TXINTE= 100 ;TRANSMITTER INTERRUPT ENABLE BIT BREAK= 1 ;CLAMP OUTPUT TO SPACE ; ; LOCAL DATA ; ; ; UNIT IMPURE DATA TABLE (INDEXED BY UNIT, POINTS TO UCB) ; D$$E11=1 CNTBL: ;REF LABEL UNITBL: ;UCB ADDRESSES .REPT D$$E11 .WORD 0 ;ENSURE SET TO ZERO .ENDM .IF GT D$$E11-1 TEMP: ;REF LABEL UNIT: .BLKW 1 ;TEMPORARY STORAGE FOR UNIT NUMBER .ENDC .ENABL LSB ; ; DRIVER DISPATCH TABLE ; $YRTBL::.WORD DLINIT ;DEVICE INITIALIZATION .WORD DLCANC ;DEVICE I/O CANCELLATION .WORD DLTMO ;TIMEOUT ENTRY POINT .WORD DLPWRF ;POWER FAIL ROUTINE ;+ ;**- DLINIT - DL-11 SYNCHRONOUS COMMUNICATION CONTROLLER I/O INITIATOR ; ; DLINIT IS ENTERED WHEN AN I/O REQUEST IS QUEUED ON THE DEVICE, ; AND AT THE END OF EACH QIO REQUEST WHICH OBEYS THE ; NORMAL RSX-11M INPUT/OUTPUT LOGIC FLOW. IF THE DEVICE IS ; AVAILABLE AND A REQUEST IS IN THE QUEUE FOR THAT UNIT, ; THE REQUEST IS INITIATED. ; IF NO REQUEST EXISTS FOR THAT UNIT OR IF IT IS ; BUSY, AN EXIT IS TAKEN TO THE CALLER. NOTE THAT BECAUSE OF ; THE NATURE OF THE DL-11, EACH UNIT IS A CONTROLLER ITSELF, ; HAS ITS OWN SCB, AND THEREFORE ITS OWN QUEUE. ; EACH TIME DLINIT IS CALLED, IT IS CALLED TO SERVICE ONLY ; THE UNIT SPECIFIED IN THE CALL. NOTE ALSO THAT ONLY ; 8-BIT, NO PARITY DATA IS SUPPORTED. ; ; INPUTS: ; ; R4 = STATUS CONTROL BLOCK ADDRESS ; R5 = ADDRESS OF THE UCB TO BE INITIATED. ; ; OUTPUTS: ; ; IF A REQUEST IS SUCCESSFULLY DEQUEUED, THE ; DEVICE IS INITIATED APPROPRIATELY. ;- DLINIT: .IF DF,NRM$YD NOP .IFF BPT ;DEBUG XDT CALL .ENDC CALL $GTPKT ;GET AN I/O PACKET TO PROCESS BCS 140$ ;NO REQUEST OR UNIT BUSY ; ; SAVE UCB ADDRESS MOV R5,UNITBL ; NOTE MUST USE UNITBL(R3) IF MULTI-UNIT DRIVER ; (CHECK IF R3 IS BYTE OR WORD OFFSET ALSO...) ; ; THE FOLLOWING ARGUMENTS ARE RETURNED BY $GTPKT: ; ; R1 = ADDRESS OF THE I/O REQUEST PACKET. ; R2 = PHYSICAL UNIT NUMBER OF THE REQUEST UCB. ; R3 = CONTROLLER INDEX ; R4 = ADDRESS OF THE STATUS CONTROL BLOCK. ; R5 = ADDRESS OF THE UCB SPECIFIED IN THE ; DLINIT CALL. ; ; DL11 I/O REQUEST PACKET FORMAT ; ; WORD CONTENT ; ; 0 I/O QUEUE THREAD WORD ; 1 REQUEST PRIORITY, EVENT FLAG NUMBER ; 2 ADDRESS OF THE TCB OF THE REQUESTER TASK ; 3 POINTER TO SECOND LUN WORD IN TASK HEADER ; 4 CONTENTS OF FIRST LUN WORD (UCB) ; 5 I/O FUNCTION CODE ; 6 VIRTUAL ADDRESS OF I/O STATUS BLOCK ; 7 RELOCATION BIAS OF I/O STATUS BLOCK ; 10 I/O STATUS BLOCK ADDRESS (REAL OR DISPLACEMENT +140000) ; 11 VIRTUAL ADDRESS OF AST SERVICE ROUTINE ; 12 RELOCATION BIAS OF I/O BUFFER ; 13 BUFFER ADDRESS FOR TRANSFER ; 14 TOTAL BYTE COUNT TO TRANSFER ; 15 BYTE COUNT FOR SECOND PART OF TRANSMISSION OR 0 ; 16 NOT USED ; 17 NOT USED ; 20 NOT USED ; MOV S.CSR(R4),R2 ;GET RECEIVER CSR ADDRESS ADD #I.FCN+1,R1 ;POINT TO I/O FUNCTION CODE CMPB #IO.RVB/256.,(R1);READ VIRTUAL? BEQ 20$ ; IF SO TREAT LIKE READ LOGICAL CMPB #IO.WVB/256.,(R1);WRITE VIRT? BEQ 24$ ;IF SO GO HANDLE CMPB #IO.INL/256.,(R1) ;CHECK IF TRANSFER FUNCTION BLOS 40$ ;BRANCH ON CONTROL FUNCTION CMPB #IO.RLB/256.,(R1) ;READ LOGICAL? BEQ 20$ ;YES, SERVICE READ REQUEST ; ; FALL THROUGH ON TRANSMIT (WRITE LOGICAL) ; 24$: BR DLSUCC ;TRANSMIT...RETURN ALL WELL ;(REALLY NOTHING TO DO...) ; ; RECEIVE FUNCTION INITIATION ; 20$: ;REFERENCE LABEL 30$: ;REF LABEL ; SET UP TIMEOUT MOVB S.ITM(R4),S.CTM(R4) ;INIT TIMER... MOV R5,R0 ;SET UP TRANSFER VECTOR ADD #U.RBUF,R0 ;RECEIVE TRANSFER INFORMATION HERE MOV U.BUF(R5),(R0)+ ;TRANSFER BIAS MOV U.BUF+2(R5),(R0)+ ;AND VIRTUAL ADDRESS MOV U.CNT(R5),(R0) ;AND COUNT TSTB 2(R2) ; CLEAR RECEIVE BUFFER STATUS MOV #1,DLFLG ;FLAG THAT WE ARE USING USER BUFFER ; AND THAT THERE MAY BE TYPE-AHEAD THERE BIS #RCVENB,(R2) ; ENABLE RECEIVER BR 140$ ;RETURN - INTERRUPT CODE PROPAGATES RECEIVE ; ; CONTROL FUNCTION INITIATION (INITIATE OR TERMINATE CONTROLLER, ; OR CHANGE OPERATING MODE) ; 40$: BNE 70$ ;IF NOT EQUAL, MODE CHANGE REQUEST ;WMG015 CLR (R2) ;CLEAR RXCSR ; ; DO START FUNCTION INITIATION ; MOV R5,UNITBL(R3) ;INITIALIZE UCB ADDRESS IN UNIT TABLE BR 120$ ;RETURN SUCCESSFUL ; ; SERVICE DEVICE MODE CHANGE REQUEST ; 70$: ; DLSUCC: ;REFERENCE LABEL 120$: MOV #IS.SUC&377,R0 ;RETURN SUCCESSFUL STATUS DLFIN: ;REFERENCE LABEL 130$: CLRB S.STS(R4) ;CLEAR CONTROLLER STATUS BICB #US.BSY,U.STS(R5) ;CLEAR UNIT STATUS MOV R0,-(SP) ;SAVE STATUS WORD 1 MOV S.PKT(R4),R1 ;GET I/O PKT ADDRESS MOV R1,-(SP) ;SAVE PKT ADDRESS TO STASH IN R3 FOR $IOFIN ; HERE TRY AND COMPUTE THE REAL COUNT READ... ; DO SO BY SUBTRACTING U.RCNT FIELD FROM R1 TO GET ; NUMBER OF BYTES ACTUALLY SENT... MOV I.PRM+4(R1),R1 ;AND REQUESTED BYTE COUNT SUB U.RCNT(R5),R1 ;SUBTRACT BYTES NOT TRANSFERRED (IF ANY) MOV R1,-(SP) ;SAVE ON STACK FOR A CALL TO DLINIT... CALL DLINIT ;ATTEMPT TO INITIATE SOMETHING ; WITH A HARD CODED TERMINATOR POSSIBLE, GOTTA RETURN WHAT WE ; ACTUALLY READ... MOV (SP)+,R1 ;GET BYTES TRANSFERRED AS STATUS WORD MOV (SP)+,R3 ;GET I/O PKT ADDRESS TO FINISH ON... MOV (SP)+,R0 ;RESTORE STATUS WORD 1 CALLR $IOFIN ;TERMINATE LAST PACKET 140$: RETURN ; ; POWER FAIL SERVICE ; DLPWRF: ;REFERENCE LABEL CLRB S.CTM(R4) ;DISABLE TIMEOUTS BIC #RCVENB,@S.CSR(R4) ;;;DISABLE RECEIVER CLR DLFLG CLR DLBFI ;;; RESET POINTERS CLR DLBFO MOV #IE.DNR$377,R0 ;NOT RDY BR 130$ ;FINISH I/O ; ; I/O CANCELLATION ; DLCANC: ;;;REFERENCE LABEL CMP R1,I.TCB(R0) ;;;CANCEL FOR THIS TASK? BNE 140$ ;;;JUST RETURN IF NOT CMPB #IO.WLB/256.,I.FCN+1(R0) ;;;WAS FUNCTION TRANSMIT? BEQ 140$ ;;;JUST LET FINISH IF YES TST U.RCNT(R5) ;;;RECEIVE FINISHED? BLE 140$ ;;;BR IF YES ;;; LEAVE INTERRUPT DISABLE HERE BIC #RCVENB,@S.CSR(R4) ;;;DISABLE RECEIVER CLR DLFLG CLR DLBFI ;;; RESET POINTERS CLR DLBFO MOV #IE.ABO&377,R0 ;;;PUT ERROR CODE IN R0 CLR U.RCNT(R5) ;;;MARK COUNT SATISFIED BR 150$ ;;;FINISH OFF I/O ; ; TIMEOUT SERVICE ROUTINE ; ; INPUTS: ; ; R0 = DEVICE TIMEOUT STATUS 'IE.DNR' ; R3 = CONTROLLER INDEX ; R4 = ADDRESS OF SCB ; R5 = ADDRESS OF UCB ; DLTMO: ;;;TIMEOUT ENTRY POINT ; MOV S.CSR(R4),R3 ;;;GET RECEIVER CSR ;;; FORCE RECEIVER NOT TO HAVE ANY MORE INTERRUPTS... BIC #RCVENB,@S.CSR(R4) ;;;DISABLE RECEIVER CLR DLFLG CLR DLBFI ;;; RESET POINTERS CLR DLBFO 150$: ;;;REFERENCE LABEL MTPS #0 ;;;ALLOW INTERRUPTS MOV U.SCB(R5),R4 JMP DLFIN ;;;WAIT FOR SOFTWARE TIMEOUT TO FINISH .DSABL LSB ; ; **- $YRINT - DL-11 INPUT INTERRUPT SERVICE ; $YRINT:: ;;;REFERENCE LABEL INTSV$ YR,PR5,D$$E11 ;;;GENERATE INTERRUPT SAVE CODE CALL DLSET ;;;SET CSR IN R4, UCB IN R5 MOV (R4),-(SP) ;;;SAVE CSR, TEST DATA SET CHANGE 10$: MOV 2(R4),R4 ;;;CAPTURE BUFFER REGISTER IN R4 ;;; THE ABOVE GRABS THIS CHAR QUICKLY. NOW SEE IF WE HAVE TO ;;; HANDLE TYPE-AHEAD (DLFLG=1). 20$: TSTB (SP)+ ;;;RECEIVER DONE? BPL 70$ ;;;IF NOT, DISMISS INTERRUPT CMP DLFLG,#1 ;;; SEE IF MODE IS TYPEAHEAD, USER START OR ;;; USER CONTINUE BGE 31$ ;;; IF GE THERE'S A USER BUFFER THERE ;;; DLFLG=0. TYPE-AHEAD MODE. ;;; STORE CHAR IN DLBUF MOV R0,-(SP) ;;; NEED A REG MOV DLINP,R0 ;;; GET COUNTER MOV PC,-(SP) ;;; GET ABS ADDRESS OF DLBUF ADD #,(SP) ;;; ON STACK ADD R0,(SP) MOVB R4,@(SP)+ ;;; STORE BYTE INC R0 BIC #177000,R0 ;;; BUMP INPUT MODULO 512 BYTES MOV R0,DLINP ;;; THEN SAVE AS NEXT INPUT LOCATION MOV (SP)+,R0 ;;; PUT REG BACK JMP 70$ ;;; THEN EXIT THIS INTERRUPT 31$: BGT 36$ ;;; IF DLFLG=2 NORMAL USER PROCESSING OCCURS MOV #2,DLFLG ;;; DLFLG WAS 1. SET IT TO 2 TO FLAG WE GOT ;;; HERE ALREADY. ; ;;; HERE WE JUST STARTED A USER I/O AND HAVE TYPE-AHEAD POTENTIALLY ;;; PRESENT. WE WANT TO FLUSH THE TYPE-AHEAD TO THE USER'S BUFFER ;;; AND SO FLAG IT, AND THEN PLACE THE CURRENT BYTE INTO THERE TOO ;;; AFTER IT. THIS SHOULD GIVE US THE DESIRED TYPE-AHEAD EFFECT, ;;; THOUGH IT REQUIRES THAT AT LEAST ONE CHARACTER ARRIVE AFTER ;;; THE I/O START, SO WE CAN'T MISS AN ENTIRE I/O, JUST THE FIRST ;;; FEW CHARACTERS OF IT. MOV R0,-(SP) MOV R1,-(SP) ;;;NEED SOME REGS MOV R2,-(SP) .IF DF,M$$MGE MOV @#KISAR6,-(SP) ;;;SAVE CURRENT MAPPING MOV U.RBUF(R5),@#KISAR6 ;;;MAP TO USER BUFFER .ENDC MOV PC,R1 ;;;POINT WITH R1 AT... ADD #,R1 ;;; DLBUF (PIC) 32$: MOV DLOUT,R0 ;;; GET OUTPUT POINTER 34$: CMP R0,DLINP ;;; SEE IF WE HAVE ALL CHARS BEQ 33$ ;;;IF EQ YES MOV R1,R2 ;;; USE R2 AS ACCUMULATOR ADD R0,R2 ;;; POINT AT DESIRED BYTE MOVB @R2,@U.RBUF+2(R5) ;;; STORE BYTE FOR USER DEC U.RCNT(R5) ;;;SEE IF COUNT SATISFIED BLE 37$ ;;;YES, IF EQUAL INC U.RBUF+2(R5) ;;;BUMP BYTE ADDRESS .IF DF,M$$MGE BIT #20000,U.RBUF+2(R5) ;;;OVERFLOWED 4K BOUNDARY? BEQ 38$ ;;;NO, IF ZERO BIC #20000,U.RBUF+2(R5) ;;;CLEAR OVERFLOW BIT ADD #200,U.RBUF(R5) ;;;BUMP BIAS ADD #200,@#KISAR6 ;;; IN UCB AND APR 6 .ENDC 38$: INC R0 BIC #177000,R0 ;;;BUMP OUT POINTER MOD 512 MOV R0,DLOUT ;;; COPY TO MEMORY FOR NEXT I/O BR 34$ ;;; GO TRY ANOTHER COPY 33$: ;;; NOW GRAB LAST BYTE 37$: ;;; THE RESULT OF THIS IS TO GIVE US AN I/O TYPEAHEAD THAT FILLS IN ;;; TYPED AHEAD DATA FIRST WHEN THE FIRST INTERRUPT THAT WE DO GET ;;; COMES IN. .IF DF,M$$MGE MOV (SP)+,@#KISAR6 ;;;RESTORE CURRENT MAPPING .ENDC MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 36$: TST U.RCNT(R5) ;;;COUNT ALREADY SATISFIED? BLE 70$ ;;;IF SO, DISMISS INTERRUPT 60$: ;;;REFERENCE LABEL .IF DF M$$MGE MOV @#KISAR6,-(SP) ;;;SAVE CURRENT MAPPING MOV U.RBUF(R5),@#KISAR6 ;;;MAP TO USER BUFFER MOVB R4,@U.RBUF+2(R5) ;;;STORE BYTE IN USER BUFFER MOV (SP)+,@#KISAR6 ;;;RESTORE CURRENT MAPPING .IFF MOVB R4,@U.RBUF+2(R5) ;;;STORE BYTE IN USER BUFFER .IFTF DEC U.RCNT(R5) ;;;SEE IF COUNT SATISFIED BLE 80$ ;;;YES, IF EQUAL INC U.RBUF+2(R5) ;;;BUMP BYTE ADDRESS .IFT BIT #20000,U.RBUF+2(R5) ;;;OVERFLOWED 4K BOUNDARY? BEQ 73$ ;;;NO, IF ZERO BIC #20000,U.RBUF+2(R5) ;;;CLEAR OVERFLOW BIT ADD #200,U.RBUF(R5) ;;;BUMP BIAS .ENDC 73$: ;;; CHECK FOR TERMINATOR CHARACTER AND END RIGHT NOW IF WE GOT IT. ;;; HARDCODED TERMINATOR IS 377 OCTAL CMPB R4,(PC)+ ;;; COMPARE TO BYTE IN NEXT WORD YRTRM==. .WORD 177777 ;;; BYTE OF FF HEX (DUPLICATED FOR ;;; THE HECK OF IT...) IN GLOBAL. ; BEQ 80$ ;;; IF EQ THEN FINISH RIGHT NOW... BNE 70$ ;;; IF EQ THEN WE HAVE A FINISH ON TERMINATOR INC U.RCNT(R5) ;;;SO BACK UP COUNT TO EXCLUDE THE X'FF' FROM ;;; THE COUNT. BR 80$ ;;; THEN TERMINATE 70$: ;;;REFERENCE LABEL RETURN ;;;EXIT INTERRUPT ; ; REQUEST SATISFIED ; 80$: ;;;REFERENCE LABEL MOV U.SCB(R5),R4 ;;;GET SCB ADDRESS ; BIC #RCVENB,@S.CSR(R4) ;;;DISABLE RECEIVER CLR DLFLG ;;; SAY WE USE TYPE AHEAD BUFFER ; NOTE A NON-GENERAL FEATURE HERE: ; WE READ TYPE-AHEAD BUFFER ONCE WE GET A REAL INTERRUPT ; SO FIRST INTERRUPT HAS A BIT OF EXTRA OVERHEAD. ; USUALLY WILL BE ONLY 2-3 CHARS SO DON'T WORRY ABOUT IT ; TOO MUCH THOUGH. CALL $FORK ;;;GO TO FORK LEVEL JMP DLSUCC ;FINISH I/O SUCESSFUL ; ; ; DLSET - SET UP REGISTER R4 WITH CSR ADDRESS, R5 WITH ; UCB ADDRESS. UNIT NUMBER IN LOW ORDER 4 BITS OF UNIT. ; DLSET: ;;;REFERENCE LABEL TST R5 ;;;CHECK FOR UCB ADDRESS BEQ 10$ ;;;IF NO UCB, TROUBLE MOV U.SCB(R5),R4 ;;;FIRST GET SCB ADDRESS MOVB S.ITM(R4),S.CTM(R4) ;;;RESET TIMEOUT. MOV S.CSR(R4),R4 ;;;NOW DEVICE CSR ADDRESS RETURN ;;;AND NOW RETURN 10$: TST (SP)+ ;;;CLEAR STACK OF RETURN ADDRESS DLSXT: JMP $INTXT ;;;DISMISS INTERRUPT DLFLG: .WORD 0 ;;; FLAG THAT I/O IS STARTED IF NONZERO DLINP: DLBFI: .WORD 0 ;;; ADDRESS FILLED IN BUFFER DLOUT: DLBFO: .WORD 0 ;;; ADDRESS EMPTIED IN BUFFER DLBUF: DLBFR: .BLKB 512. ;;; RING BUFFER FOR BIIIIG TYPE AHEAD ;;; NOTE DLBFR IS A POWER OF 2 LONG SO WE CAN DO CIRCULAR ;;; OPS ON IT. .WORD 0,0 ;SAFETY .END