.TITLE MOSIO - MOS I/O HANDLING ROUTINES .INSRT ../moscnf-1.sml .INSRT ../mosmac.sml .INSRT ../mostbl.sml .INSRT ../tmplt/mosdev-1.sml .LIST ME $CNFIG ;DEFINE SYSTEM CONFIGURATION .PAGE $DFIOR .PAGE $DFIST .PAGE $DFPCT .PAGE $DFDCT $DFDEV ;DEFINE SYSTEM DEVICE NUMBERS .NLIST ME .LIST MEB .ENABL ISD .GLOBL DSCHD ;SYSTEM SCHEDULER ENTRY POINT .GLOBL $IOCMP ;I/O COMPLETION ENTRY POINT .GLOBL $IOCMR ;I/O COMPLETION ENTRY/RETURN .GLOBL $IOSIG ;I/O COMPLETE SIGNAL ROUTINE .GLOBL $DCTVT ;DEVICE CONTROL TABLE VECTOR TABLE .GLOBL $APCT ;ADDRESS OF ACTIVE PCT .GLOBL $APID ;ACTIVE PROCESS' PID .GLOBL $APFLG ;ADDR OF ACTIVE PROCESS' CAP FLAGS .GLOBL SCHDFLG ;SCHEDULER FLAG .GLOBL $SIO ;ASYNCHRONOUS START I/O .GLOBL $SIN ;SYNCHRONOUS STRING INPUT .GLOBL $SOUT ;SYNCHRONOUS STRING OUTPUT .GLOBL $BIN ;SYNCHRONOUS BYTE INPUT .GLOBL $BOUT ;SYNCHRONOUS BYTE OUTPUT .GLOBL $SPRIO ;SET PRIMARY I/O DEVICES .GLOBL $STI ;SIMULATE TERMINAL INPUT .GLOBL $ENQ,$DEQ,$QDEL .GLOBL $CVPCT ;PID => PCT ADDR CONVERSION .GLOBL .SNKUP,.SNKOT ;SPECIAL DATA SINK OUTPUT DEVICE .IF NE, KF.SCD .GLOBL TYPE, TYPEN ;NEEDED FOR LOGGIN .ENDC .GLOBL $ERR4 ;BAD DCT ADDRESS ERROR HALT .GLOBL $MIOTP,$MIOBT ;MOSIO CODE SPACE TOP/BOTTOM .PAGE .CSECT MOS $MIOTP: .SBTTL $SIO - START I/O TRANSFER ; CALLED WITH: R0 - ADDRESS OF I/O REQUEST BLOCK (IORB) $SIO: $PUSH R2 MOVB $APID,IRPID(R0) ;SET CALLER'S PID CLR IRSTA(R0) ;RESET TRANSFER STATUS CLR IRBX(R0) ; AND BYTES TRANSFERRED 6$: MOV IRDEV(R0),R2 ;GET DEVICE NUMBER BPL 1$ ;IF NOT NEGATIVE, SKIP CMP R2,#-2 ;-1 OR -2 BLT 5$ ;IF NOT, ERROR NEG R2 ;CHANGE TO 1 OR 2 BIC #1,R2 ;CHANGE -1 -> 0, -2 -> 2 ADD $APCT,R2 ;ADD IN PCT ADDRESS .IF NE, PCTPRI+2-PCTPRO .ERROR ;PCTPRI, PCTPRO NOT CONTIGUOUS .ENDC MOV PCTPRI(R2),R2 ;GET PRIMARY I/O DEVICE NUMBER BEQ 7$ ;IF ZERO, THEN SUSPEND PROCESS AS DET 1$: BEQ ERR4 ;BAD DCT ERROR CMP R2,$DCTVT ;INDEX TOO LARGE? BHI ERR4 ;IF SO, BAD DCT NDX ERROR ASL R2 ;CONVERT TO WORD NDX MOV $DCTVT(R2),R2 ;GET ADDRESS OF THE DCT BEQ ERR4 ;IF NOT DEFINED, ERROR BIT #DF.OFL,DCTFLG(R2) ;DEVICE INITIALIZED? BEQ 2$ ;IF SO, SKIP JSR PC,DCTINI ;INITIALIZE DCT BIT #DF.OFL,DCTFLG(R2) ;INITIALIZED NOW? BNE 4$ ;IF NOT, GIVE OFF-LINE ERROR 2$: $ENQ ;ENQUEUE NEW REQUEST CMP R0,(R2) ;NEW REQUEST AT HEAD OF QUEUE? BNE 3$ ;IF NOT, TRANSFER IN PRGRESS, EXIT MOV IRUVA(R0),DCTUVA(R2) ;SET BUFFER ADDR IN DCT MOV IRBR(R0),DCTBR(R2) ; BUFFER LENGTH, JSR PC,@DCTDVA(R2) ;ELSE, CALL TRANSFER START ROUTINE 3$: $POP R2 $RTT ;AND RETURN 4$: BIS #PS.FZN,@$APFLG ;FREEZE OURSELVES JSR PC,DSCHD ;RUN THE SCHEDULER BR 4$ ;AND MAKE IT STICK 7$: MOV @$APFLG,-(SP) ;REMEMBER IF WAITING FOR SYNC I/O BIC #PS.IO,@$APFLG BIS #PS.DET,@$APFLG ;MARK OURSELVES AS DETACHED JSR PC,DSCHD ;RUN THE SCHEDULER MOV (SP)+,@$APFLG ;RESTORE WAIT FLAGS BR 6$ ;AND SEE IF WE HAVE BEEN ATTACHED 5$: $POP R0 ;RECOVER IORB ADDRESS ERR4: BUGHLT ;BAD DCT ADDRESS ERROR HALT $ERR4: NOP DCTINI: $PUSH @#4 ;SAVE TRAP CATCHER $PUSH R1 MOV SP,DCTUVA(R2) ;TEMP SAVE STACK PTR IN DCT MOV #NOXDEV,@#4 ;AND CATCH NON-EXISTANT DEVICE ERRORS MOV DCTIVA(R2),R1 ;GET INTERRUPT VECTOR ADDRESS BEQ 1$ ;IF NONE, SKIP MOV R2,(R1) ;SET POINTER TO DCT ADD #DCTIHX,(R1)+ ; AND TRANSFER TO DCT PREAMBLE MOV #340,(R1)+ ;DON'T ALLOW OTHER INTERRUPTS 1$: JSR PC,@DCTINA(R2) ;CALL DEVICE INITIALIZER ROUTINE DCTINX: $POP R1 $POP @#4 RTS PC ;AND RETURN NOXDEV: MOV DCTUVA(R2),SP ;RECOVER STACK POINTER BIS #DF.OFL,DCTFLG(R2) ;INDICATE HARDWARE OFF-LINE BR DCTINX ;AND EXIT .PAGE .SBTTL $SIN/$SOUT - SYNCHRONOUS STRING I/O ; CALLED WITH: R0 - ADDRESS OF STRING BUFFER ; R1 - LENGTH OF BUFFER ; ; RETURNS WITH: R0 - ADDRESS OF STRING ; R1 - ACTUAL LENGTH OF STRING $SOUT: $PUSH R0 MOV $APCT,R0 ;GET ACTIVE PCT $PUSH #DV.PRO ;INDICATE SYNCH OUTPUT BR SYNCIO ;AND DO SYNCHRONOUS I/O $SIN: $PUSH R0 MOV $APCT,R0 ;GET ACTIVE PCT $PUSH #DV.PRI ;GET INPUT DEVICE SYNCIO: ADD #PCTIBR,R0 ; AND ADVANCE TO SYNCH IORB MOVB #377,IROPC(R0) ;INDICATE SYNCHRONOUS I/O REQUEST $POP IRDEV(R0) ;GET DEVICE NUMBER MOV R1,IRBR(R0) ;INDICATE LENGTH OF BUFFER MOV (SP),IRUVA(R0) ; AND ITS ADDRESS BIS #PS.IO,@$APFLG ;MARK AS IN I/O WAIT STATE $SIO R0 ;INITIATE THE I/O JSR PC,DSCHD ;AND RUN SCHEDULER MOV IRBX(R0),R1 ;I/O COMPLETE-GET BYTES TRANSFERED CMP #77777,IRSTA(R0) ;CHECK STATUS & SET CARRY IF ERROR $POP R0 $RTTCC .PAGE .SBTTL $BIN/$BOUT - SYNCHRONOUS BYTE INPUT/OUTPUT ; CALLED WITH: R0 - CHARACTER TO SEND ; ; RETURNS WITH: R0 - CHARACTER $BIN: $PUSH R1 $PUSH R0 ;PUT CHARACTER ON STACK MOV SP,R0 ;POINT TO CHARACTER ON STACK MOV #1,R1 ;LENGTH OF 1 $SIN R0,R1 ;AND DO STRING I/O $POP R0,R1 $RTTCC $BOUT: $PUSH R1 $PUSH R0 ;PUT CHARACTER ON STACK MOV SP,R0 ;POINT TO CHARACTER ON STACK MOV #1,R1 ;LENGTH OF 1 $SOUT R0,R1 $POP R0,R1 $RTTCC .PAGE .SBTTL $STI - SIMULATE TERMINAL INPUT ; CALLED WITH: R0 - DEVICE NUMBER ; R1 - (LO) DATA BYTE $STI: $PUSH R0 BEQ ERR4 ;BAD DCT ERROR CMP R0,$DCTVT ;INDEX TOO LARGE? BHI ERR4 ;IF SO, BAD DCT NDX ERROR ASL R0 ;CONVERT TO WORD NDX MOV $DCTVT(R0),R0 ;GET ADDRESS OF THE DCT BEQ ERR4 ;IF NOT DEFINED, ERROR BIT #DF.OFL,DCTFLG(R0) ;DCT INITIALIZED? BNE 2$ ;IF NOT, FLUSH CHAR TST (R0) ;CHECK FOR ACTIVE IORB BEQ 1$ ;IF NONE, ENQUEUE IN RING BUFFER MOVB R1,@DCTUVA(R0) ;TRANSFER THE BYTE $PUSH R1 MOV (R0),R1 ;GET IORB MOV #1,IRBX(R1) ;AND SET BYTE COUNT $POP R1 JMP $IOCMP ;AND INDICATE I/O COMPLETE 1$: CMP DCTRC(R0),#DCTTLN-DCTRNG ;SPACE LEFT IN BUFFER? BHIS 2$ ;IF NOT, SKIP MOVB R1,@DCTTL(R0) ;PLOP IN BYTE INC DCTRC(R0) ;BUMP COUNTER INC DCTTL(R0) ; AND TAIL POINTER CMP DCTTL(R0),DCTEND(R0) ;REACHED END OF BUFFER BLO 2$ ;IF NOT, SKIP MOV DCTFNT(R0),DCTTL(R0) ;ELSE, RESET POINTER 2$: $POP R0 $RTT ;RETURN .PAGE .SBTTL $IOCMP - I/O COMPLETION ENTRY POINT ; ENTERED WITH: R0 - ADDRESS OF DCT ; (SP) - OLD R0 ; $IOCMP: CALL $IOCMR $POP R0 ;RESTORE THE OLD R0 $RTT ;CALLED VIA JUMP, RETURN FROM INTRPT .PAGE .SBTTL $IOCMR - DO ACTUAL I/O COMPLETION ; CALLED VIA JSR, MAY BE USED BY DEVICE ROUTINES THAT WISH TO REGAIN CONTROL ; ; ENTERED WITH: R0 - ADDRESS OF DCT ; $IOCMR: $PUSH R0,R1,R2 MOV R0,R2 ;GET DCT ADDRESS MOV (R2),R1 ;GET ACTIVE IORB ADDRESS BEQ 1$ ;IF SPURIOUS INTERRUPT, IGNORE CMP (R1),R1 ;CIRCULAR ENTRY IN IORB LIST? BNE 2$ ;NO, OK BUGHLT 2$: JSR PC,$IOSIG ;SIGNAL IO COMPLETION $DEQ ;REMOVE CURRENT IORB FROM HEAD OF Q MOV (R2),R0 ;GET NEXT IORB TO SERVICE BEQ 1$ ;IF NONE, SKIP MOV IRUVA(R0),DCTUVA(R2) ;SET BUFFER ADDR IN DCT MOV IRBR(R0),DCTBR(R2) ;BUFFER LENGTH, JSR PC,@DCTDVA(R2) ;START TRANSFER GOING 1$: $POP R2,R1,R0 ;RESTORE REGS RTS PC ;DONE .PAGE .SBTTL $IOSIG - SIGNAL I/O COMPLETION ; ; CALLED WITH: R2 - ADDR OF DCT ; R1 - ADDR OF IORB ; ; RETURNS WITH: R0 - CLOBBERED ; $IOSIG: MOV IROPC(R1),R0 ;GET PID/OPC CMPB R0,#377 ;SYNCHRONOUS I/O? BEQ 1$ ;IF SO, DON'T SIGNAL BIS #I.DONE,IRSTA(R1) ;SET TRANSFER DONE BIT SWAB R0 ;AND PUT PID IN LO BYTE $SGNLI R0,R0,R1 ;SIGNAL I/O COMPLETE RTS PC 1$: SWAB R0 ;GET PID IN LOW BYTE .IF NE, KF.SCD $PUSH R0 ;GOING TO MASH BIC #-400,R0 ;ONLY WANT PROCID CALL TYPEN ;AND TYPE IT MOV #SIOC,R0 ;AND A MESSAGE CALL TYPE $POP R0 ;GO BACK TO BUSINESS .ENDC $CVPCT ;GET PCT ADDRESS BIC #PS.IO,PCTFLG(R0) ;LET IT PROCEED, I/O IS FINISHED INC SCHDFLG ;AND MAKE A NOTE OF ACTIVITY RTS PC .IF NE, KF.SCD .CSECT MOSDAT SIOC: .ASCIZ / Io/<12> .EVEN .CSECT MOS .ENDC .PAGE .SBTTL $SPRIO - SET PRIMARY I/O DEVICE DESIGNATORS ; ; CALLED WITH: R0 - (LO) PID ; R1 - PRIMARY INPUT DEVICE (-1 MEANS NO CHANGE) ; R2 - PRIMARY OUTPUT DEVICE (-1 MEANS NO CHANGE) ; ; RETURNS WITH: R1 - CURRENT PRIMARY INPUT DEVICE ; R2 - CURRENT PRIMARY OUTPUT DEVICE ; $SPRIO: $PUSH R0 $CVPCT ;GET PCT ADDRESS TST R1 ;DEVICE SPECIFIED? BMI 1$ ;IF NOT, SKIP MOV R1,PCTPRI(R0) ;SET PRIMARY INPUT DEVICE 1$: MOV PCTPRI(R0),R1 ;AND RETURN CURRENT VALUE TST R2 BMI 2$ MOV R2,PCTPRO(R0) ;SET PRIMARY OUTPUT DEVICE 2$: MOV PCTPRO(R0),R2 ;AND RETURN PRESENT VALUE BIC #PS.DET,PCTFLG(R0) ;CLEAR DETACHED FLAG $POP R0 $RTT .PAGE .SBTTL .SNKUP & .SNKOT - SPECIAL SINK DEVICE .SNKUP: BIC #DF.OFL,DCTFLG(R2) ;INDICATE INITIALIZED RTS PC .SNKOT: $PUSH R0,R1 MOV IRBR(R0),IRBX(R0) ;INDICATE ALL TRANSFERRED MOV R0,R1 ;GET IORB ADDRESS MOV R2,R0 ;AND DCT ADDRESS JSR PC,$IOSIG ;SIGNAL IMMEDIATE I/O COMPLETEION $POP R1,R0 RTS PC $MIOBT: ;BOTTOM OF CODE SPACE .END