
;  SHARED PART OF PERM FOR PSR COMPILER
;*******************
;* PERM0S VSN 12   *
;* 23.APR.80       *
;*******************

PON=2
POFF=3
DELETE=5;  EMT DELETE TASK
GETID=14; EMT 12. - GET ID
PONPOF=21;  EMT 17. - PON POFF

TTID=1
DKID=3
DIRID=4
LPID=14

LOADID=41; ACTUAL ID OF LOADER TASK  ***** MAY CHANGE **************

LNB=R5


; *************************************************************

;  FAULT VALUES FOR PROGRAM TERMINATION

FEOF      =    31;     FAULT 25, NO FILE OR END OF FILE
SYNFLT    =    32;     FAULT 26, SYNTAX FAULT ON I/O STRING
DSCFLT    =    33;     FAULT 27, DISC I/O FAIL (EG ILLEGAL BLOCK)
DSCFUL    =    34;     FAULT 28, DISC OR DIRECT  IS FULL UP

; ************************************************************

RDSYX=0; INDEX INTO STREAM DESCRIPOR
NEXYX=2; DITTO
GETBX=4; DITTO
SER=6
REPLY=7
UNIT=10
FSYS=11
NAME=12; BIA NAME(0:5)
BLOCK=20
OFFSET=22
NCHARX=22
PTX=24
MAXX=26
BUFFS=30

; INDEX TO STRAM DESCRIPTOR - FROM OFFSET
RDSY=-22
NEXY=-20; ; NEXTX-OFFSET
GETB=-16 ; GETBX-OFFSET
NCHAR=0; =NCHARX-OFFSET
PT=2;  =PTX-OFFSET
MAX=4;  =MAXX-OFFSET
; ******************************
; NOTE:  ON OUTPUT             *
;        PT IS MAPPED TO NCHAR *
;        PRSY IS MAPPED TO RDSY*
; ******************************

; LAYOUT OF READ/WRITE I/O SEGMENT  (SEG 7 ADDR=160000)

RDSPSR=160000
NXYPSR=160002
PRSPSR=160004
SINP  =160006
SOUT  =160010
PSTOP =160012
CLOSE =160014
SIGNAL=160016

; ADDRESS OF PERM VARIABLES
X     =160020
Y     =160022
INSTRM=160024
OUTSTR=160026
ID    =160030
CALLID=160031
STRPTS=160032; %INTEGERARRAY STRPTS(0:7)
TOP=160052
UNFYS=160054
GLA=160056
INTCHR=160060
STR0ID = 160061
SPARE=160062

; END OF PERM VARIABLES

ZERO=60
ONE=61
NINE=71
A=101
Z=132
SLASH=57
COMMA=54
DOT=56
OPENBR=50
CLSEBR=51

; ************************************************************

.=20000

; ************************************************************
        MOV   #-2, R0;    KILL TASK ADDRESS
        JMP   DOSTOP
        BR   ENTRY;      NORMAL ENTRY
        BR   SPENTR;     SYSTEM TASK ENTRY

SPON,SPOFF,PONOFF,MAPVRT,GETABS
SGETID,STIME,SLINKN,SMAPHW,TIMEP,DATEP


SETSTREAMS:; ROUTINE TO SET UP THE STREAM DESCRIPTORS
;  ON ENTRY:_ R0 -> BUFFER CONTANING THE FILE DESCRIPTORS (TERM IN LF)

ENTRY:
        MOV R0,R5;     PUT PARAM INTO R5
      EMT   GETID
      MOV   R0,@#ID
      MOV   #SINP, R0
      MOV   #SELECTINPUT, (R0)+
        MOV   #SELOUT, (R0)+
        MOV   #DOSTOP, (R0)+; %AND SET UP %STOP
        MOVB  R4, @#CALLID;  REMEMBER WHO CALLED
      SWAB   R4
      MOVB   R4, @#STR0ID
        MOV   R3, @#UNFYS
        MOV   #CLSE,  (R0)+
        MOV   #SIGNL1, (R0)+
        MOV   R1, @#GLA;   SAVE TOP OF GLA
        MOV #SPARE,R4; POINTER TO FREE SPACE IN I/O SEG
        CLR R3; R3=CURRENT STREAM*2
        MOV   R2, -(SP);                  LOADER FLAG
        BNE   LOADSP
         MOVB @#STR0ID,R2; R2 (ON ENTRY TO STUFF) IS P_SERVICE
        CLR R0; 0=CHAR TYPE, 2=FILE TYPE
        JSR PC,STUFF; SET ASIDE SPACE FOR TT INPUT
LOADSP:    CLR -(SP); SET ASIDE A LOCATION
        ADD #2,R3;  R3=1*2
SS1:    MOVB (R5)+,R0; GET NEXT CHAR
        CMPB #12,R0; NEWLINE?
        BNE SS4; NO, SO CONTINUE THE CHECK
        CMP #10,R3; HAS OUTPUT(0) BEEN SET UP?
        BGT SS2; NOT YET, SO SET UP

; DO INITIAL SELECTION OF STREAMS AND JUMP TO IMP PROGRAM
        TST   (SP)+;           DUMP 'INIT' POINTER
        MOV   (SP)+, R0;       PICK UP 'LOADER' FLAG
        BNE   OUTONLY;         IS LOADER, SO DONT DO SELECT INPUT
        CLR -(SP)
        JSR PC,@SINP; SELECT INPUT(0)
OUTONLY:  CLR -(SP)
        JSR PC,@SOUT; SELECT OUTPUT(0)
        CLR R1; ENSURE TOP OF STACK PT OK
        MOV   R4, @#TOP
        MOV   @#GLA, R1; PICK UP TOP OF GLA
SPENTR:
        MOV   2(R1), R1; PICK UP S#GO POINTER (ZERO IN OLD CASE)
        BEQ   OLDTPE;             OLD TYPE
        JSR   PC, @(R1)+;        AND ENTER LIKE EXTERNAL ROUTINE

OLDTPE: MOV #40020, PC; ENTER IMP PROGRAM

; **********

SS2:    DEC R5; SET UP OUTPUT(0), THEN GET IT TO READ NL AGAIN
SS3:    MOV #10,R3; OUTPUT(0)
      MOVB @#STR0ID,R2
        CLR R0; CHAR TYPE STREAM
        JSR PC,STUFF; SET UP OUTPUT(0)
        CLR   (SP); AND CLEAR 'INITIALISED' POINTER
        ADD   #2, R3;          AND DO OUTPUT(1)
        BR SS1; AND GET NEXT

SS4:    ; TRY NEXT CHECK
        CMPB #SLASH,R0
        BEQ SS3; DO OUTPUT STREAMS NOW
        CMPB #COMMA,R0; IS IT ','?
        BNE SS5; NO, SO DO NEXT CHECK
; YES, SO MOVEW TO NEXT
SS6:    ADD #2,R3; STEP R3 TO NEXT STREAM
        CLR (SP); SET 'DONE' MARKER
        BR SS1; AND GET NEXT CHAR

SS5:    ; NEXT CHECK
        CMPB #DOT,R0; IS IT '.'?
        BNE SS7; NO, SO LOOK FOR FILE NAME
        ; YES, SO MUST BE A DEVICE
        TST (SP); ALREADY SET UP?
        BEQ   SS5A; NO, SO LOOK FOR DEVICE
        MOVB   -(R1), R0; PICK UP LAST CHAR
        SUB   #ZERO, R0; CONVERT TO 0 OR 1
        BLT   FAILT; LESS THAN ZERO ???
        CMP   #4, R0; NO, SO CHECK FOR ONE TO FOUR
        BLT   FAILT; NEITHER, SO FAIL PROGRAM
        MOVB   R0, -2(R1); WRITE UNIT INTO UNIT BYTE


        MOVB   DISCT(R0), -4(R1);  FILL IN SERVICE NUMBER
        BR    SS1; GO FOR NEXT CHAR

DISCT: 001403;  .BYTE 3,3
        007010;   .BYTE 8.,14.
        000034;    .BYTE   28., 0

SS5A:   MOVB (R5)+,R1; GET NEXT TWO CHARS INTO A WORD
        SWAB R1
        BISB (R5)+,R1
        MOV #DEVTAB,R0; TABLE OF POSSIBLES
        CLR R2; INDEX
SS5B:   MOV (R0)+,(SP); INDICATE LOOKING (+HOLDS TEST DEVICE)
        BEQ FAILT; END OF TABLE, SO FAULT
        CMP (SP),R1; GOT IT?
        BEQ SS5C; YES, SO EXIT
        INC R2; INDEX
        BR SS5B; AND CHECK NEXT

SS5C: TST   R2
      BNE   SS5C1;                      NOT TT, SO LOOK UP
      MOVB   @#STR0ID, R2;              TT, SO USE AMENDED NO
      BR SS5C2;   AND CONTINUE
SS5C1:   MOVB DEVIDS(R2),R2; GET ITS SERVICE NUMBER
SS5C2:  CLR R0; CHAR TYPE
        JSR PC,STUFF; AND ALLOCATE SPACE
        BR SS1; TAKE THE COMMA

SS7:    ; CHECK FOR LEGAL FILE NAME
        CMP #ZERO,R0
        BGT FAIL
        CMP #NINE,R0
        BGE SS8; BETWEEN 0-9
        CMP #A,R0
        BGT FAIL
        CMP #Z,R0
        BLT FAIL

SS8:    TST (SP); FIRST TIME?
        BNE SS9; NO, SO DONT SET UP
        MOV R0,-(SP);  SAVE THE CHAR
        MOV #DKID,R2; GET ID OF DISC TASK
        MOV #2,R0; FILE TYPE
        JSR PC,STUFF; DECLARE THE SPACE
        ADD #610,R4; AALLOW FOR DISC BUFFER
        MOV R4,R1
        SUB #1016,R1; POINT AT BEGINNING OF 'NAME'
        MOV (SP)+,R0; RESTORE THE CHAR
        INC (SP); BEEN HERE BEFORE POINTER
SS9:    MOVB R0,(R1)+; PLANT CHAR
        BR SS1; GET THE NEXT

FAIL:   CMP   #OPENBR, R0; IS IT FILE SYS DEFF
        BNE   FAILT; NO, SO FAIL
        TST   (SP);  FILE SPEC?
        BEQ   FAILT; NO, SO FAIL
        MOVB   (R5)+, R1; GET NEXT CHAR
        SUB   #ZERO, R1;  MAKE IT NUMBER
        MOVB  (R5)+, R0; GET NEXT CHAR (2ND NUMBER OR ')')
        CMP   #CLSEBR, R0
        BEQ   FAIL2;  YES, SO EXIT
        ASL   R1
        ASL   R1
        ASL   R1
        ADD   R0, R1; ADD IN SECOND NUMBER
        SUB   #ZERO, R1;  -'0'
        MOVB  (R5)+, R0; GET THE ')'
        CMP   #CLSEBR, R0
        BNE   FAILT

FAIL2:  CMP   #77, R1; LEGAL?
        BLT   FAILT; NOPE
        MOV   STRPTS(R3), R0; GET PT TO STREAM
        MOVB  R1, FSYS(R0); AND PLANT IN FSYS
        JMP   SS1; AND GET NEXT

FAILT: MOV   #SYNFLT,R0
        JMP   DOSTOP


STUFF:
        MOV R4,STRPTS(R3); PLANT POINTER TO STREAM DEFINITION
        CLR (R4)+; FIRST TIME FLAG
        MOV R0,(R4)+; TYPE OF STREAM FLAG
        CLR (R4)+; GETB
        MOVB R2,(R4)+; SERVICE TASK
        MOVB @#ID,(R4)+; REPLY 
        MOV   @#UNFYS, (R4)+
        MOV #TYPE1,R1
        MOV #6,R0; COPY 6. WORDS
STLP:   MOV (R1)+,(R4)+
        DEC R0
        BNE STLP
        ADD   #172, (R4); SET MAX TO POINT AT END OF BUFFER
        ADD #172,R4; SPACE FOR BUFFER
        RTS PC; AND RETURN
; *******************************************************************
; READSYMBOL, NEXTSYMBOL, PRINTSYMBOL, SELECT INPUT, SELECT OUTPUT ETC
; ********************************************************************

NEXTSYMBOL:
        MOV @X,R1
        BGE NSOK; NEXTSYMBOL PRESENT
        MOV @#X,R0; NEXTSYMBOL NOT THERE, SO PICK UP STREAM POINTER
        JSR PC,@GETB(R0); GET A BUFFER
; CHAR IS INB R1
NSOK: RTS PC

READSYMBOL: ; STACK CONTAINS:- RA, ^S
RS1:    MOV @#X,R0; PICK UP STREAM BUFFER POINTER
        MOV (R0),R1; LOOK FOR NEXTSYMBOL
        BGE RS2; ITS THERE
        JSR PC,@GETB(R0); GET A BUFFER

RS2:    ; GOT CHAR IN R1
        INC PT(R0); STEP THE POINTER
        CMP PT(R0),MAX(R0); REACHED THE END?
        BNE RS3; NO, SO EXIT
        MOV #100000,(R0); MAKE NEXTSYMBOL NOT PRESENT
        BR RS4; AND HOP IT

RS3:   MOVB @PT(R0),(R0); PICK UP 'NEXTSYMBOL'
        BIC #177400,(R0); ENSURE ONLY 8 BITS

RS4:   MOV (SP)+,R0; PICK UP RETURN ADDRESS
        MOV R1,@(SP)+; PLANT CHAR THROUGH POINTER, AND POP THE ADDRESS
        MOV  R0,PC; RETURN TO CALLER

; ***************************************************************
; THE GET BUFFER ROUTINE USED IS DEPENDANT ON WHETHER CHAR OR FILE
; ***************************************************************

GETB1: ; CHARACTER GET BUFFER
        SUB #OFFSET,R0; POINT TO BEGINNING OF STREAM DESCRIPTOR
        MOV R4,-(SP); SAVE R4
        MOV R0,R4; REMEBER ADDR OF DESC
        MOV SER(R4),R0; PICK UP SERVICE/REPLY
        MOV R4,R2
        ADD #BUFFS,R2; POINT TO INPUT BUFFER
        CLR R1; READ REQUEST
        EMT   PONPOF
        ; ON RETURN R1 WILL INDICATE SUCCESS/FAILURE AND LENGTH
        TST R1
        BEQ EOF; END OF FILE
BUFFCOM:  MOV R4,R0; STREAM DESC
        ADD #BUFFS,R0; POINT TO FIRST CHAR
        MOV R0,PTX(R4); SET PT UP
        ADD R0,R1; ^END OF BUFFER
        MOV R1,MAXX(R4); PLANT IN MAX
        ADD #OFFSET,R4; POINT TO NORAMAL POSITION
        MOVB @PT(R4),(R4); PICK UP NEXTSYMBOL
        BIC #177400,(R4); AND ENSURE 8 BITS
        MOV (R4),R1; PUT BACK IN R1
        MOV R4,R0; RESTORE R0 TO POINT TO 'NEXTSY'
        MOV (SP)+,R4; RESTORE USERS R4
        RTS PC; AND RETURN

EOF:
        MOV   (SP)+, R4;      RESTORE R4
        TST   (SP)+;  TOSS RA AWAY
EOF2:   MOV   #100004, R1;    EOF CHAR
        JMP   RS4;  AND EXIT

EFAIL:   MOV   #FEOF, R0; PLANT EOF FAILED CODE
EFAIL2: JMP   DOSTOP; AND DO '%STOP'

DFAIL:   MOV   #DSCFLT, R0
         BR    EFAIL2

GETBF2: ; FILE GET BUFFER ROUTINE
        SUB #OFFSET,R0; POINT BACK TO BEGINNING
        MOV R4,-(SP); AND SAVE R4
        MOV R0,R4
        MOV BLOCK(R4), R3; PICK UP BLOCK NUMBER
        BEQ EOF; HIT END-OF-FILE
        CLR R1; DO A READ
        MOV R4,R2
        ADD #BUFFS,R2; POINT TO BUFFER
        MOV SER(R4),R0; SERVICE AND REPLY
        EMT   PONPOF;  ASK FOR BLOCK

        ; GOT BLOCK

        TST R1; SUCCESS/FAILURE FLAG
        BNE   DFAIL; DISC FAIL

        MOV BLOCK(R4), R3
        MOV   R4, R2
        ADD   #UNIT, R2;          CONSTRUCT PT TO FILE DESC
        MOV #1,R1; GET NEXT SERVICE

       SWAB   R0;                     GET SERVICE/REPLY AGAIN
        INC R0;                 USE DIRECTORY SERVICE (DISC+1)
        EMT PONPOF
        MOV R1,BLOCK(R4)
        MOV #1000,R1
        BR BUFFCOM; COMMON WITH GETBF1


; ******************************************************************
; SELECT INPUT
; ******************************************************************
SELECTINPUT:
; STACK CONTAINS RA AND PARAM

        MOV 2(SP),R0; PICK UP PARAM
        MOV R0,@#INSTRM
        ASL R0
        MOV STRPTS(R0),R0; GET POINTER TO DESCRIPTOR
        MOV R0,@#X; AND SET UP THE POINTER
        BEQ INNULL; NULL STREAM
        ADD #OFFSET,@#X; INTO 'OFFSET' POSITION

SIAGN:  MOV (R0),@#RDSPSR; SET UP ROUTINE CALL RDSYX(R0)
        BEQ NOTSETUP; FIRST TIME THROUGH JUMP OUT
        MOV NEXYX(R0),@#NXYPSR; SET UP NEXTSYMBOL ENTRY POINT
SIRET:  MOV (SP)+,R3; GET RA
        TST (SP)+; POP PARAM
        MOV R3,PC; AND RETURN

NOTSETUP:
        MOV R1,-(SP); SAVE R1??????
        TST NEXYX(R0); ON FIRST ENTRY, NEXY CONTAINS TYPE:-
        ; TYPE = 0 - CHAR STREAM
        ; TYPE = 2 - FILE STREAM
        BEQ INCHAR
        BR INFILE


INNULL: MOV #EOF2,@#RDSPSR
        MOV #NULLNS,@#NXYPSR   ; WAS NULLRS - NOT DEFINED?
        BR SIRET; AND RETURN

NULLNS:
        MOV #100004,R1
        RTS PC

INCHAR: ; SET UP STREAM FOR CHARACTER HANDLING
        MOV #READSYMBOL,(R0); ,RDSYX(R0)
        MOV #NEXTSYMBOL,NEXYX(R0)
        MOV #GETB1,GETBX(R0)
INCH2:  MOV #100000,OFFSET(R0); SET NEXTSYMBOL NOT PRESENT
        MOV (SP)+,R1; RESTORE R1
        BR SIAGN; AND SET IT UP

INFILE: ; SET UP STREAM FOR FILE HANDLING
        MOV R4,-(SP); SAVE R4
        MOV R0,R4; STREAM DESC ->R4
        MOV R4,R2
        ADD #SER,R2; POINT R2 AT SERVICE/REPLY
        MOV (R2)+,R0; SERVICE/REPLY
        INC R0; BUT USE DIRECTORY HANDLER
        ; R2 POINTS TO NAME DESCRIPTOR (+UNIT ETC)
        CLR R1; SERVICE=EXAMINE
        EMT PONPOF
        MOV R1,BLOCK(R4); PLANT BLOCK NUMBER
        BEQ   INEOF;  NO FILE
INE2:   MOV R4,R0; PICK UP STREAM POINTER AGAIN
        MOV #READSYMBOL,(R4)+
        MOV #NEXTSYMBOL,(R4)+
        MOV #GETBF2,(R4)
        MOV (SP)+,R4; RESTORE USERS R4
        BR INCH2; FINISH SETTING UP

INEOF:  CMPB   @#ID, #LOADID
        BEQ   INE2; ITS THE LOADER, SO LET IT THROUGH
        JMP   EFAIL; OTHERWISE, FAIL IT

; **********************************************************************
;                  OUTPUT ROUTINES
; **********************************************************************

PRINTSYMBOL:;  STACK CONTAINS RA, CHAR
; CHARACTER VERSION!
        MOV @#Y,R0
        MOV 2(SP),R1; PICK UP THE CHAR
        CMP R1,#100000; PROMPT CHAR?
        BEQ DOPUT1; YES, SO OUTPUT BUFFER
        MOVB R1,@0(R0); PLANT INDIRECT THROUGH POINTER
        INC (R0); AND STEP POINTER
        CMPB   #12,R1; IS IT NL?
        BEQ DOPUT1; YES, SO OUTPUT BUFFER
        CMP MAX(R0),(R0); HAVE WE REACHED THE END OF THE BUFFER?
        BEQ DOPUT1; YES, SO OUTPUT BUFFER
        
NULLPS: ; NULL PRINTSYMBOL - JUST RETURN
PRET: MOV (SP)+,(SP); SHUFFLE PARAM DOWN
        RTS PC; AND RETURN

DOPUT1:  MOV   #PRET,-(SP);  DO A PSEUDO JSR PC,DOPUT; RTS PC
DOPUT:; BUFFER OUTPUT ROUTINE FOR CHARACTER I/O
        MOV R4,-(SP); SAVE USERS R4
        MOV   R3, -(SP)
        MOV   R2, -(SP)
        MOV R0,R4; AND GET POINTER
        MOV (R0), R3; R3 CONTAINS POINTER TO END
        SUB #OFFSET,R4; POINT BACK TO BEGINNING
        MOV SER(R4),R0; GET SERVICE NUMBER
        MOV R4,R2; CONSTRUCT POINTER TO BUFFER
        ADD #BUFFS,R2; BY ADDING BUFFER OFFSET
        SUB R2, R3; AND SUBTACT FROM END TO GIVE LENGTH
        MOV #1, R1; 1=WRITE
        EMT   PONPOF;  SEND IT
        ADD #BUFFS,R4; POINTS TO BUFFER
        MOV R4,-6(R4); AND POINT 'POINTER' TO IT
PBR:    MOV   (SP)+, R2
        MOV   (SP)+, R3
        MOV   (SP)+, R4
        RTS   PC; AND RETURN

; *********************************************************************
;        FILE HANDLING PRINTSYMBOL AND PUT BUFFER
; *********************************************************************

DISCPS:; STACK CONTAINS RA, CHAR
; DISC VERSION
        MOV @#Y,R0; GET STREAM DESCRIPTOR
        MOV 2(SP),R1; CHAR
        MOVB R1,@0(R0); AND PLANT THROUGH POINTER
        INC (R0)
        CMP MAX(R0),(R0); END OF BUFFER?
        BNE PRET; NO, SO COMMON EXIT

; DISC PUT BUFFER
; WRITES OUT THE CURRENT BLOCK, THEN GETS ANOTHER BLOCK AND INITS IT

        MOV   #PRET, -(SP); DO A PSEUDO JSR PC,DPUT; RTS PC
DPUT:   MOV   R4, -(SP); SAVE USERS R4
        MOV   R3, -(SP)
        MOV   R2, -(SP)
        MOV   R0,R4
        SUB #OFFSET,R4; POINT AT BEGINNING
        MOV BLOCK(R4), R3
        MOV R4,R2
        ADD #BUFFS,R2; CONSTRUCT BUFFER POINTER IN R2
        MOV #1, R1; WRITE OPERATION
        MOV SER(R4),R0; SERVICE NUMBER
        EMT   PONPOF
        TST R1; SUCCESS/FAIL FLAG
        BEQ DPS1; OK
FAILX: JMP DFAIL; DISC FAILED

DPS1:
; NOW FIND THE NEXT BLOCK
        MOV #4, R1; OPERATION=APPEND
        MOV BLOCK(R4),R3; LAST BLOCK NO
        MOV SER(R4),R0; SERVICE NO OF DISC
        INC R0; CHANGED TO DIRECTORY
        MOV   R4, R2
        ADD   #UNIT, R2;            CONSTRUCT PT TO FILE DESC
        EMT   PONPOF
        JSR PC,DPSET; SET BUFFER UP ETC
        BR    PBR

DPSET: ; SET UP BLOCK
        MOV R1,BLOCK(R4); REMEMBER NEXT BLOCK
        BNE   DPS2; OK
        CLR   RDSYX(R4);  ENSURE IT WONT TRY AGAIN
        MOV   #DSCFUL, R0; SET R0 = 28
        JMP   DOSTOP;  AND STOP TASKS
DPS2:
        MOV #400,R0; SET 400 WORDS
        MOV   R4, R3
        ADD #OFFSET, R3
        MOV R3,R2
        ADD #6,R2; POINT AT BEGINNING OF BUFFER
        MOV R2,(R3); LEAVE PT SET UP
CLLP:     MOV #2004,(R2)+; PLANT EOF IN BUFFER
        DEC R0
        BNE CLLP; AND LOOP TILL DONE

        MOV   R2, MAX(R3); AND SET UP MAX
        RTS   PC

; ******************************************************************
;  SELECT OUTPUT
; ******************************************************************

SELOUT:    ; SELECT OUTPUT, STACK CONTAINS R.A. AND STREAM NO
        MOV 2(SP),R0; GET STREAM NO
        ADD #4,R0; INTO OUTPUT RANGE
        MOV R0,@#OUTSTR; INTO STREAM NO
        ASL R0; WORD INDEX
        MOV STRPTS(R0),R0; AND PICK UP DESCRIPTOR
        BEQ OTNULL; THE NULL STREAM
        MOV R0,R1; CONSTRUCT POINTER TO OFFSET IN R1
        ADD #OFFSET,R1
        MOV R1,@#Y; AND REMEMBER IN OUT POINTER

SOAGN:  MOV (R0),@#PRSPSR; AND PLANT IN PRINTSYMBOL POINTER
        BNE PRET; ALREADY SET UP, SO RETURN

; SO FIRST TIME THROUGH
        TST NEXYX(R0); STREAM TYPE
        BNE OTFILE; FILE TYPE

; CHAR TYPE
        MOV #PRINTS,(R0); SET UP PRINTSYMBOL ROUTINE POINTER
        MOV R0,(R1); CONSTRUCT POINTER TO START OF BUFFER IN 'PT'
        ADD #BUFFS,(R1)
        BR SOAGN; AND DUMP THE ADDRESS

; OUTPUT FILE TYPE
OTFILE:
        MOV R4,-(SP); SAVE USER R4
        MOV R0,R4; AND REMEMBER STREAM POINTER
        MOV #DISCPS,(R0); DUMP FILE PRINTSYMBOL
        BIS   #200, NAME(R0);   MAKE IT 'TEMP'
        MOV R0,R2; POINT TO SER/REPLY
        ADD #SER,R2
        MOV (R2)+,R0; R2 NOW POINTS TO FILE NAME ETC
        INC R0; USE DIRECTORY SERVICE
        MOV #2,R1; DESTROY FILE
        EMT   PONPOF
        SWAB R0; GET DIR SERVICE AGAIN
        MOV #3,R1; CREATE FILE
        EMT   PONPOF
        ;R1 CONTAINS FIRST BLOCK NO
        JSR PC,DPSET; SET UP BLOCK, POINTERS ETC
        MOV R4,R0; RESTORE FILE DESC INTO R0
        MOV (SP)+,R4; AND USERS R4
        BR SOAGN; AND FINALISE SETTIN G UP

; NULL STREAM
OTNULL:
        MOV #NULLPS,@#PRSPSR
        JMP PRET; AND RETURN

; ***************************************************************
;                   CLOSE
; ***************************************************************
; RA, PARAM ON STACK
; PARAM=0 => INPUT
; PARAM=4 => OUTPUT
; CLOSES CURRENT STREAM AND SELECTS ZERO

CLSE:    TST   R0
        BNE   CLOUT; CLOSE OUTPUT
        ; OTHERWISE INPUT
        MOV   @#X, R1; GET CURRENT DESCRIPTOR
        BEQ   CLRET; NULL STREAM
        CLR   RDSY(R1)
        CLR   R0; ASSUME CHAR STREAM
        CMP   GETB(R1), #GETBF2; IS IT?
        BNE   CLSI1; YES, SO JUMP
        MOV   #2, R0
CLSI1:  MOV   R0, NEXY(R1);  STUFF TYPE
CLRET:   CLR   -(SP);  SELECT INPUT(0)
        JSR   PC, SELECTINPUT
        RTS   PC;  AND RETURN TO USER

CLOUT:    ; CLOSE OUTPUT
        MOV   @#Y, R0
        MOV   RDSY(R0), R1; IS IT INITIALISED?
        BEQ   CLORET; NO, SO LEAVE ALONE
        CLR   RDSY(R0)
        CMP   #DISCPS, R1; IS IT A DISC STREAM?
        BEQ CLO2; YES, SO BRANCH
        JSR   PC, DOPUT; DO A CHARACTER PUT BUFFER
        BR   CLORET;  AND RETURN
CLO2:
        OFF2=OFFSET-SER

        MOV   R4, -(SP);           SAVE R4
        MOV   R0, R4
        SUB   #OFF2, R4
        MOV   (R4), R0; GET SER NUMBER
        MOV   R4, R2; CONSTRUCT POINTER
        ADD   #22, R2;  BUFFS-SER
        MOV   12(R4), R3; BLOCK NUMBER
        MOV   #1, R1; WRITE
        EMT   PONPOF
        TST   R1
        BEQ   CLO3; OK
        JMP   DFAIL; OTHERWISE FAILED
CLO3:   MOV   (R4)+,R0
        INC   R0
        MOV   R4, R2
        MOV   #6, R1; RENAME TEMP
        EMT   PONPOF
        MOV   (SP)+, R4;         RESTORE R4

CLORET:  CLR   -(SP);  SELECT OUTPUT(0)
        JSR   PC, SELOUT
        RTS   PC


; **********************************************************
;                   STOP
; **********************************************************

DOSTOP:
        MOV    R0, -(SP); SAVE STOP CODE
        ;  CLOSE ALL THE OUTPUT STREAMS!
        MOV   #6, R5
        STRPT1=STRPTS+10;  DO OUTPUT STREAMS ONLY
DOST0:  MOV   STRPT1(R5), @#Y; SET UP STREAM
        BEQ   DOST00;  NULL STREAM
        ADD   #OFFSET, @#Y
        MOV   #4, R0;  INDICATE OUTPUT STREAM
        JSR   PC, CLSE;  AND CLOSE IT
DOST00: SUB   #2,R5; NEXT STREAM DOWN
        BNE   DOST0; NOT FINISHED


        MOV   @#ID, R0; GET CALLER (AND ID)
        SWAB   R0; AND GET READY TO SEND IT
        MOV   #2, R1;   SERVICE = STOPPING
        MOV   (SP)+, R3;  AND STOP CODE
        EMT   PON
        CLR R0
        EMT   DELETE; AND DELETE THE TASK


DEVTAB:
; THIS TABLE WILL HAVE TO BE CONSTRUCTED IN WORDS FROM EMAS
        52124;  .ASCII /TT/
        46120;   .ASCII /PL/
        52062;   .ASCII /2T/
        52063;   .ASCII /3T/ (LETTERS ARE REVERSED)
        0    ;  TABLE TERMINATOR

DEVIDS:
; DITTO TO LAST
        6001;  .BYTE TTID, LPID
        12423;   .BYTE T2ID, T3ID  (19. AND 21.)
        0

TYPE1:
; RDSY, NEXY, GETB, SER, REPLY - NOT PLANTED BY THIS
;        0;  UNIT/FSYS
        20040; SP, SP - NAME IS 6 CHARS
        20040
        20040
        0; BLOCK NO
        0; NEXTSYMBOL
        0; PT
        ; MAX NOT ALLOWED FOR


MONITOR=160012

EVENT=2
EVINF=4
ELIST=6
PROG=12

SIGNL1:  MOV (SP), R0
      MOV   R4, -(SP)
      MOV   R5, -(SP)
SIG0:  SUB   PROG(R4), R0
      CLR   R2;     CALCULATE TEXTUAL LEVEL
      MOV   LNB, R3
      TST   (R3)+
      CMP   LNB, (R4)
      BEQ   SIG2
SIG1:  INC   R2
      CMP   LNB, (R3)+
      BNE   SIG1
SIG2:  MOV   ELIST(R4), R1;   EVENT LIST
      BEQ   SIG5
SIG3:  ADD   PROG(R4), R1
      CMP   R0, (R1)
      BLOS  SIG4;  TOO EARLY
      CMP   R0, 2(R1)
      BHI   SIG4;  TOO LATE
      CMP   R2, 6(R1)
     
      BNE   SIG4;    WRONG LEVEL
      BIT   4(R1), 6(SP)
      BEQ   SIG5;   EVENT NOT TRAPPED
      MOV   6(SP), EVENT(R4)
      MOV   10(SP), EVINF(R4)
      JMP   12(R1);   RE-ENTER PROGRAM

SIG4: MOV   10(R1), R1
      BNE   SIG3
SIG5: TST   R2;    OUTERMOST LEVEL?
      BEQ   SIG6; YES, GIVE UP
      MOV   (LNB), LNB; PSEUDO RETURN
      MOV   (LNB)+, R0;  RETURN ADDRESS
      BIT   -2(R0), #1; EXTERNAL?
      BEQ   SIG0
      MOV   (R3), R4; YES, RECOVER GLA
      BR   SIG0

SIG6: MOV   (SP)+, LNB;  RESTORE CONTENT
      MOV   (SP)+, R4
MOV   (SP)+, R2;   FAILURE ADDRESS
      MOV   (SP)+, R1;   EVENT
      MOV   (SP)+, R0;  EXTRA INFO
      MOV   @#MONITOR, PC;  CALL MONITOR



SPON:   MOV   2(SP), R3
        MOV   (R3)+, R0
        MOV   (R3)+, R1
        MOV   (R3)+, R2
        MOV   (R3), R3
        EMT   2;           EMT PON
SPONR:  MOV   (SP)+, (SP)
        RTS   PC

SPOFF:  MOV   @2(SP), R0
        EMT   3
        MOV   R0, -(SP)
        MOV   4(SP), R0
        MOV   (SP)+, (R0)+
        MOV   R1, (R0)+
        MOV   R2, (R0)+
        MOV   R3, (R0)
        BR SPONR

PONOFF: MOV   R4, -(SP)
        MOV   4(SP), R4
        MOV   (R4)+, R0
        MOV   (R4)+, R1
        MOV   (R4)+, R2
        MOV   (R4), R3
        EMT   PONPOF;          EMT PONPOFF
        SUB   #6, R4
        MOV   R0, (R4)+
        MOV   R1, (R4)+
        MOV   R2, (R4)+
        MOV   R3, (R4)
        MOV   (SP)+, R4
        BR   SPONR

MAPVRT: MOV   (SP)+, R3;   RA
        MOV   (SP)+, R2
        MOV   (SP)+, R1
        MOV   (SP)+, R0
        EMT   12;          EMT MAP VIRTUAL (10)
        MOV   R3, PC
GETABS:        ; %INTEGER VAD, LEN, ID
      MOV   (SP)+, R3; RA
      MOV   (SP)+, R0;  ID
      MOV   (SP)+, R2; LEN (=0 => DROP)
      MOV   (SP), R1; VAD
      ;072127;        ASH R1, -13.  - RIGHT
      ; 177763
        ROL   R1
        ROL   R1
        ROL   R1
        ROL   R1
      BIC   #177770, R1; CLEAR TOP BITS
      EMT   13; MAP ABS
      ;  R0 = PAR, R1 = PDR
      CLRB   R1
      ASR   R1
      ASR   R1;   LEN IN WORDS
      ADD   #100, R1
      ADD   (SP)+, R2;  R2=LEN+VAD
      BIC   #160000, R2; AS  INDEX IN SEGMENT
      CMP   R2, R1
      BGT   GETABX; OUT OF SEGMENT
      MOV   R0, R1; RESULT (PAGES)
      MOV   R3, PC; AND RETURN
GETABX: CLR   R1; FAILED
      MOV   R3, PC; AND RETURN
SGETID: EMT   GETID
      MOV   R0, R1
      RTS   PC

STIME:         ; %INTEGER TICKS
      MOV   (SP)+, R3
      MOV   (SP)+, R0; TICKS
      EMT   10;   EMT 8.
      MOV   R3, PC

SLINKN:        ;  %INTEGER SER
      MOV   (SP)+, R3
      MOV   (SP)+, R0; SER
      EMT   15; EMT 13.
      MOV   R3, PC

SMAPHW:        ;  %INTEGER SEGS
      MOV   (SP)+, R3
      MOV   (SP)+, R0; SEGS
      EMT   17;  EMT 15.
      MOV   R3, PC
TIMEP:        ; TICKS FROM IPL (OR SET UP)

DATEP:         ; DATE  (IN THREE WORDS)
.END
