; CLONE - A COMMAND LANGUAGE FOR ON-LINE EXECUTION ; LAST EDIT: 19-NOV-81 ; ; THE CLONE COMMAND LANGUAGE WAS DESIGNED BY DAVE PLUMMER AND ; ANDREW TODD-POKROPEK AT UNIVERSITY COLLEGE HOSPITAL, LONDON. ; IT WAS THE SUBJECT OF THE PAPER: MODULARITY AND COMMAND LANGUAGES ; IN MEDICAL COMPUTING, PRESENTED AT THE FIFTH INTERNATIONAL ; CONFERENCE ON INFORMATION PROCESSING IN MEDICAL IMAGING, HELD ; AT NASHVILLE IN JUNE 1977. ; ; THIS IMPLEMENTATION FOR THE PDP11 UNDER RSX11M V3.2 IS BY ; DAVE PLUMMER. IT WAS INITIALY DEVELOPED WHILST WORKING FOR THE C.E.A. ; AT ORSAY FRANCE AND FURTHER EXTENDED AT U.C.L.A. ; ; THIS SOFTWARE IS AVAILABLE TO ALL NON PROFIT MAKING ORGANISATIONS ; ON REQUEST AND ON THE UNDERSTANDING THAT IT WILL NOT BE USED FOR ; FINANTIAL GAIN OR TRANSMITTED TO ANOTHER PARTY WITHOUT THE WRITTEN ; CONSENT OF THE AUTHOR. ; ; DAVE PLUMMER ; ; DIVISION OF NUCLEAR MEDICINE ; U.C.L.A. CENTER FOR THE HEALTH SCIENCES ; LOS ANGELES ; CA. 90024 U.S.A. ; ; .NLIST ; REMOVE THE FOLLOWING DEFINITION TO SUPPRESS INITIAL COMMENTS ; BLURB=0 ; .IF DF BLURB .PAGE .LIST .ENDC .TITLE CLONE ; ; FIRST EDIT 8-AUG-78 ; IDENT$ V003 ; ; ; ; ; ; THIS MODULE CONTAINS THE ENTRY POINT AND ALL ; ROUTINES WHICH MANIPULATE SYSTEM STRUCTURES. ; IN ADDITION TO THE BASIC COMMAND AND DATA REQUEST ; CALLS. ; ; .PSECT CLONE ; ; THE EXECUTIVE CONTROLS TWO PRINCIPAL STRUCTURES, THE PROCESS ; LIST AND THE STREAM LIST. THE PROCESS LISTHEAD IS A FIXED ; LOCATION AT 'PROCLH' EACH PROCESS LIST ITEM CONTAINS A STREAM ; LISTHEAD. ; PROCESS LIST OFFSETS ARE DEFINED AS FOLLOWS: PL.FWD==4 ;PROCESS LIST FORWARD POINTER PL.BWD==6 ;PROCESS LIST BACKWARD POINTER PL.SLH==10 ;2 WORD STREAM LIST HEAD PL.TI==14 ;PROCESS TI (DEVICE NAME AND UNIT) PL.UCB==20 ;PROCESS TI: UCB ADDRESS PL.UIC==22 ;PROCESS UIC (GROUP,USER) PL.LUN==24 ;LUN ASSIGNED TO PROCESS PL.QST==26 ;2 WORD QIO STATUS BLOCK FOR INPUT PL.DBF==32 ;INPUT BUFFER POINTER PL.FLG==34 ;PROCESS FLAGS WORD PL.CBF==36 ;ASYNCRONOUS COMMAND INPUT BUFFER POINTER PL.RBF==40 ;UNFAMILIAR REGION BUFFER POINTER ; PL.SIZ==17. ;SIZE OF A PROCESS LIST ITEM IN WORDS. ; ; PROCESS FLAG BIT DEFINITIONS ARE: PF.WTI==1 ;WAITING FOR INPUT PF.WTO==2 ;WAITING FOR OUTPUT PF.EXT==4 ;PROCESS QUEUED TO EXIT PF.TRA==10 ;EXECUTION TRACE ENABLED PF.LOG==20 ;TRANSACTION LOG ENABLED ; ; ; ; ; ; ; AN ACTIVE PROCESS IS COMPOSED OF ONE OR MORE STREAMS. ; STREAMS EXECUTE IN STREAM LIST PRIORITY ORDER AND ; SYNCRONISE WITH EACH OTHER AT TRANSACTIONS. ; THE STREAM LIST CONTAINS THE FOLLOWING VALUES: SL.FWD==4 ;STREAM LIST FORWARD POINTER SL.BKW==6 ;AND REVERSE POINTER SL.CLH==10 ;2 WORD LISTHEAD FOR CONTROL DESCRIPTORS SL.TSK==10 ; OR NAME OF A TASK STREAM SL.REG==14 ;ID OF TASK STREAMS CURRENT REGION. ALWAYS ; NON-ZERO FOR A TASK STREAM, ZERO FOR A CLONE STREAM SL.STA==16 ;STREAMS TRANSACTION STATUS. SL.RQD==20 ;REQUEST DESCRIPTOR POINTER SL.BST==22 ;STREAMS SAVED STATE DURING BREAKIN COMMAND SL.BRQ==24 ;SAVED REQUEST DESCRIPTOR DURING BREAKIN SL.EFN==24 ; OR LOCAL EFN FOR TASK STREAM SL.FLG==26 ;STREAM FLAGS SL.RLH==30 ;STREAMS RECORD LIST HEAD (TWO WORDS) SL.STB==34 ;STREAMS SYMBOL TABLE LIST HEAD (THREE WORDS) SL.STK==42 ;STREAMS STACK ITEM POINTER SL.USP==44 ;STREAMS SAVED USER STACK POINTER SL.ESB==46 ;ADDRESS OF EXIT STATUS BLOCK ITEM SL.LEV==50 ;PARSER LEXICAL LEVEL ;THE FOLLOWING LOCATIONS SAVE DATA FOR DORMANT STREAMS SL.EXS==52 ;EXECUTION STATUS OF A DORMANT STREAM SL.SFP==54 ;STACK FRAME POINTER OF A DORMANT STREAM ;END OF CONTEXT SAVE LOCATIONS SL.LMT==56 ;LOCAL MACRO SYMBOL TABLE LISTHEAD. 3 WORDS SL.SIZ==26. ;LENGTH OF A STREAM LIST ITEM IN WORDS ; ; STREAM FLAGS ARE FG.BRK==1 ;BREAKIN IN PROGRESS FG.STP==2 ;STEP MODE FG.MCR==4 ;REPLY TO MCR MODE FG.SRQ==10 ;SPECIAL REQUEST IN PROGRESS FG.TXT==20 ;PRINT ALL REPLIES ; ; .MCALL ALUN$S,ENAR$S,DSAR$S,EXIT$S,CLEF$S,EXIF$S,STSE$S ; ; ; ; ; DEFINE SOME USEFUL CONSTANTS ; CTRLZ=32 CR=15 LF=12 TAB=11 SPACH=40 EOF=-1 EOS=0 ; ; ; EVENT FLAG WE USE FOR SYNCRONISATION CL1EFN==32. ; ; APR USED FOR MAPPING TASK STREAMS REGIONS ; THIS MAY OVERLAY THE EXECUTIVE MAPPING SO ; WE MUST EXPLICITLY CALL UNMAP BEFORE ANY ; EXECUTIVE REFERANCE. MAPAPR==4 ; ; ; REDEFINE CERTAIN ERROR CODES IN THE ROOT SO OVERLAYS CAN USE THEM E.UND==6 E.BFA==31 ; ; .IIF NDF BLURB .LIST .PAGE ; ; ; ; ENTRY POINT AND INITIALIZATION ; CLONE: CALL INITSP ;INIT SPACE ADMINISTRATION CALL INICOM ;INIT COMMUNICATIONS MODULE CALL INIFIL ;INIT FILE SYSTEM ; ; AND GO TO MAIN EXEC LOOP .PAGE ; RUN - SCHEDULE THE CLONE INTERPRETER BETWEEN THE STREAMS ; THIS IS THE MAIN CONTROL LOOP. HOWEVER CERTAIN PROCESSES ; EXECUTE ASYNCRONOUSLY IN AST FORM. AS THESE MAY ACCESS ; EXECUTIVE DATA STRUCTURES AST RECOGNITION MUST BE ; DISABLED WHILST EXECUTING THE EXECUTIVE CODE. ; RUN: CLR ACTIVE ;INIT SOMETHING TO DO FLAG CLR STREAM ;NO STREAM CURRENT DSAR$S ;DISABLE ASTS ; ; START PROCESS LIST SCAN MOV PROCLH,R0 ;GET THE PROCESS LISTHEAD BNE 1$ JMP 82$ ; ; CONTINUE PROCESS LIST SCAN 1$: CMP R0,#PROCLH ;END OF PROCESS LIST ? BNE 19$ ;SKIP IF NOT JMP 90$ ;ELSE TERMINATE SCAN 19$: MOV R0,PROC ;SAVE CURRENT PROCESS TST PL.LUN(R0) ;IS THIS A NEW PROCESS BNE 2$ CALL PRCINI ;IF SO INITIALISE IT BCC 2$ JMP 80$ ;IGNORE PROCESS IF WE FAIL 2$: CALL SETTI ;SWITCH OUR TI: TO THAT OF PROCESS MOV R0,R1 ;POINT TO STREAM LISTHEAD ADD #PL.SLH,R1 MOV R1,STRMLH ;AND SAVE IT TST PL.CBF(R0) ;ANY COMMANDS QUEUED ? BEQ 5$ ;SKIP IF NOT ; IF A COMMAND IS QUEUED BUT NO CLONE STREAM IS ACTIVE ; WE CREATE A NEW STREAM. OTHERWISE THE COMMAND IS A BREAKIN. ; IF THE STREAM IS SUSPENDED AND THE BREAKIN LINE IS NULL ; THE COMMAND IS INTERPRETED AS A RESUME. MOV (R1),R1 ;GET FIRST STREAM BEQ 3$ ;IF NONE CREATE NEW TST SL.REG(R1) ;IS IT A TASK STREAM ? BNE 3$ ;IF SO CREATE NEW MOV R1,STREAM CMP SL.STA(R1),#TS.SPD ;IS STREAM SUSPENDED ? BNE 6$ ;SKIP IF NOT MOV PL.CBF(R0),R2 ;GET THE COMMAND BUFFER TSTB 10(R2) ;IS BUFFER NULL ? BNE 6$ ;GO BREAKIN IF NOT MOV #TS.RUN,SL.STA(R1) ;RESTORE STREAM TO RUN CLR PL.CBF(R0) MOV R2,R0 ;FREE COMMAND BUFFER CALL FREESP MOV PROC,R0 BR 5$ ;GO CONTINUE 6$: CALL BRKIN ;ELSE BREAKIN CURRENT STREAM BCC 4$ ;GO INSERT COMMAND LINE BR 5$ ;BREAKIN NOT ACCEPTABLE YET. ; CREATE A NEW STREAM AND MAKE IT CURRENT 3$: CALL NEWSTR ;CREATE A NEW STREAM BCS 7$ ;ERROR CREATING STREAM MOV R1,STREAM ;AND SAVE ITS POINTER ; 4$: CALL NEWCTL ;ALLOCATE A CONTROL DESCRIPTOR BCC 8$ MOV #TS.EXT,SL.STA(R1);FLAG STREAM EXITED BR 7$ 8$: MOV PL.CBF(R0),R2 ;GET QUEUED BUFFER CLR PL.CBF(R0) ;AND CLEAR POINTER CALL PUTLIN ;INSERT IN DESCRIPTOR MOV #TS.RUN,SL.STA(R1);CHANGE TO RUN STATE BR 10$ ;AND GO PROCESS STREAM ; 7$: MOV PL.CBF(R0),R0 ;GET COMMAND BUFFER CALL FREESP ;DEALLOCATE MOV PROC,R0 ;RESTORE PROCESS POINTER CLR PL.CBF(R0) ;NULL BUFFER POINTER BR 10$ ;GO TRY TO RUN PROCESS ; 5$: TST PL.RBF(R0) ;IS A TASK WAITING TO CONNECT ? BEQ 10$ ;IF NOT JUST RUN THE FIRST STREAM MOV PL.RBF(R0),R2 ;GET THE CONNECT PACKET CLR PL.RBF(R0) CALL TSKNKT ;GO CONECT TASK STREAM ; ; NOW JUST SCAN THE STREAM LIST FOR SOMETHING TO DO 10$: MOV @STRMLH,R1 BEQ 80$ ;NULL LIST ; START OF STREAM LIST SCAN 11$: CMP R1,STRMLH ;END OF STREAM LIST ? BEQ 80$ MOV R1,STREAM ;SAVE STREAM POINTER CALL TRNSCT ;TRANSACTION POSSIBLE ? BCS 80$ ;IF C SET BREAK FROM STREAM LIST SCAN 20$: MOV SL.FWD(R1),R1 ;ELSE ON TO NEXT STREAM BR 11$ ; ; AFTER TERMINATING A SCAN OF THE STREAM LIST ; IF PROCESS HAS TERMINATED: KILL IT THEN GO TO NEXT 80$: MOV PL.FWD(R0),-(SP);NEXT PROCESS TST PL.SLH(R0) ;PROCESS STILL ACTIVE ? BNE 81$ ;YES CALL CL1BYE ;PRINT DISCONNECT MESSAGE MOV PL.LUN(R0),R2 ;FREE PROCESS LUN CALL ENDLUN MOV #PROCLH,R3 ;GET LISTHEAD MOV R0,R2 ;AND PROCESS ITEM CALL UNLINK ;UNLINK FORM PROCESS LIST CALL FREESP ;AND DE-ALLOCATE SPACE 81$: MOV (SP)+,R0 ;AND RESTORE SUCCESSOR TST PROCLH ;ANY PROCESSES STILL ACTIVE ? BEQ 82$ ;IF NOT SHOULD WE EXIT ? JMP 1$ ;ELSE CONTINUE SCAN ; ; HERE IF NO PROCESSES REMAIN ACTIVE WE EXIT HAVING CHECKED ; THAT NOTHING IS QUEUED TO US. 82$: ENAR$S ;ENABLE ASTS EXIF$S #CL1EFN ;EXIT IF NOTHING HAPPENING BR 91$ ;CLEAR FLAG AND CONTINUE ; ; AFTER THE LAST PROCESS WE LOOK TO SEE IF ANYTHING ; IS HAPPENING. IF NOT WE GO TO SLEEP. OTHERWISE ; GO BACK TO THE BEGINNING. 90$: ENAR$S ;RE-ENABLE ASTS TST ACTIVE ;ANYTHING HAPPENING ? BNE 92$ ;IF SO KEEP RUNNING 91$: CLEF$S #CL1EFN ;CLEAR AND TEST FLAG CMP $DSW,#IS.SET ;WAS FLAG SET BEQ 92$ ;GO RUN AGAIN IF SO STSE$S #CL1EFN ;STOP TILL SOMETHING HAPPENS BR 91$ ; 92$: JMP RUN ;GO PROCESS EVENT ; ; ; THE FOLLOWING LOCATIONS ARE THE PRINCIPAL ENTRYPOINTS ; TO THE CLONE DATABASE. THEY MAY BE SAFELY ACCESSED ; BY USER ROUTINES TO OBTAIN STREAM AND PROCESS PARAMETERS. PROC:: .WORD 0 ;THE CURRENTLY ACTIVE PROCESS STREAM::.WORD 0 ;THE CURRENTLY ACTIVE STREAM MACSTB::.WORD 0 ;THE TABEL OF AVAILABLE 'MACROS' ; ; THESE LOCATIONS DEFINE THE STREAMS CONTEXT WHILST IT IS ; ACTIVE. WHILST A STREAM IS DORMANT THEY ARE SAVED IN THE ; STREAM LIST ITEM. THUS DURING EXECUTION ON THE SYSTEM STACK ; THESE LOCATIONS ARE NOT VALID. ; EXEC:: .WORD 0 ;EXECUTION STATUS. SAVED IN SL.EXS BLOCKP::.WORD 0 ;STACKFRAME POINTER. SAVED IN SL.SFP ; ; ; THE FOLLOWING LOCATIONS ARE LOCAL TO THE CLONE EXECUTIVE ; PROCLH::.WORD 0,0 ;THE ROOT OF ALL STRUCTURES STRMLH: .WORD 0 ;ADDRESS OF CURRENT STREAM LISTHEAD SYSSP: .WORD 0 ;SAVE LOCATION FOR SYSTEM STACK POINTER ;DURING USER MODE. ACTIVE: .WORD 0 ;SOMETHING ACTIVE FLAG ; ; ; ; ; USER - SWITCH TO USER STACK ; INPUT: R0=CURRENT PROCESS ITEM ; R1=CURRENT STREAM ITEM ; OUTPUT: R6=USER STACK POINTER ; STREAM CONTEXT WORDS ARE SET ; R1 DESTROYED ; ; USER:: MOV SL.EXS(R1),EXEC ;SET CURRENT EXECUTION STATUS MOV SL.SFP(R1),BLOCKP ;AND CURRENT STACK FRAME POINTER MOV SL.USP(R1),R1 ;GET NEW SP MOV (SP)+,-(R1) ;MOVE RETURN ADDRESS TO USER STACK MOV SP,SYSSP ;SAVE SYSTEM SP MOV R1,SP ;CHANGE STACKS RETURN ;AND RETURN ON USER STACK ; ; SYSTEM - SWITCH TO SYSTEM STACK ; ; OUTPUT: R0=CURRENT PROCESS ITEM ; R1=CURRENT STREAM ; R6=SYSTEM SP ; USER CONTEXT IS SAVED IN STREAM ITEM. ; SYSTEM::MOV STREAM,R1 ;GET THE CURRENT STREAM MOV EXEC,SL.EXS(R1) ;SAVE EXECUTION STATUS MOV BLOCKP,SL.SFP(R1) ;SAVE CURRENT STACK FRAME POINTER MOV SYSSP,R0 ;GET SYSTEM SP MOV (SP)+,-(R0) ;COPY RETURN ADDRESS TO SYSTEM STACK MOV SP,SL.USP(R1) ;SAVE USER SP MOV R0,SP ;CHANGE STACKS MOV PROC,R0 RETURN ;AND RETURN ON SYSTEM STACK ; ; PAUSE - TRAP FROM USER CODE TO EXEC ; INPUT: R2=NEW TRANSACTION STATE TO ENTER ; ; OUTPUT: A RETURN IS EXECUTED ON THE SYSTEM STACK ; USER SP IS SAVED ; ALL OTHER USER REGISTERS ARE DESTROYED ; RETURN OCCURES WHEN THE STREAM IS RE-SCHEDULED BY CLONE ; ; PAUSE:: CALL SYSTEM ;ENTER SYSTEM STATE MOV R2,SL.STA(R1) ;SET TRANSACTION STATE CLC ;IDENTIFY RETURN AS NORMAL RETURN ;BACK TO SYSTEM RETURN ADDRESS ; .PAGE ; TRNSCT - PERFORM A TRANSACTION IF POSSIBLE ; ; INPUT: ; R0=PROCESS LIST ITEM ; R1=STREAM LIST ITEM ; ; ; ACTION: ; AN EXECUTABLE STREAM IS RUN ; A STREAM IN ONE OF THE TRANSACTION STATES IS FREED IF ; THE TRANSACTION HAS COMPLETED. ; A STREAM WHICH HAS EXITED IS DE-ALLOCATED ; ; OUTPUT: ; THE STATE OF THE C BIT INDICATES ACTION TO BE TAKEN ON ; RETURN FROM TRNSCT. ; C=1 INDICATES THAT THE CURRENT STREAM IS ACTIVE OR ; BLOCKED BY A HIGHER STREAM IN THE SAME PROCESS. UNDER ; THESE CIRCUMSTANCES NO ATTEMPT SHOULD BE MADE TO RUN ; A LOWER STREAM. ; C=0 INDICATES THAT THE CURRENT STREAM IS WAITING FOR ; SOME ACTION FROM A LOWER STREAM AND THAT LOWER STREAMS ; SHOULD THUS BE CONCIDERED FOR EXECUTION. ; ; TRNSCT: MOV SL.STA(R1),R2 ;GET STREAM STATUS BMI 1$ CMP R2,#TRTBLN ;CHECK STATUS VALID BGT 1$ JMP @TRSTBL(R2) ;DISPATCH TO TRANSACTION PROCESSOR ; 1$: TRAP ;CRASH ; ; ; TRSTBL: TBLDF$ TSRUN,TS.RUN,ST ;STREAM IS EXECUTABLE TBLDF$ TSWCM,TS.WCM ;STREAM IS WAITING FOR A COMMAND LINE TBLDF$ TSWRQ,TS.WRQ ;STREAM IS WAITING FOR DATA INPUT ;SL.RQD POINTS TO A REQUEST DESCRIPTOR TBLDF$ TSBRK,TS.TSK ;TASK STREAM EXECUTING TBLDF$ TSRDY,TS.RDY ;TASK STREAM HAS A REPLY READY TBLDF$ TSNXT,TS.RPY ;WAITING FOR REPLY TO BE ACCEPTED ;SL.RQD CONTAINS REPLY ITEM POINTER TBLDF$ TSNXT,TS.EOJ ;WAITING FOR JOB TO TERMINATE TBLDF$ TSNXT,TS.GET ;WAITING FOR GET TO COMPLETE TBLDF$ TSBRK,TS.OUT ;WAITING FOR OUTPUT TO COMPLETE ;NOT USED IN CURRENT IMPLEMENTATION TBLDF$ TSNXT,TS.SPD ;SUSPENDED TBLDF$ TSEXT,TS.EXT ;STREAM HAS EXITED TBLDF$ TSBRK,TS.MCR ;STREAM WAITING FOR MCR TO PROCESS COMMAND TBLDF$ TSNXT,TS.PAS ;STREAM IS LETTING N REQUESTS PASS UNPROCESSED ;SL.RQD CONTAINS N ; TRTBLN=.-TRSTBL ;END OF TABLE ; ; ; TSWCM - WAITING FOR COMMAND INPUT ; TSWCM: BIT #PF.WTI,PL.FLG(R0);TERMINAL INPUT IN PROGRESS ? BEQ 1$ ;IF NOT REQUEST HAS COMPLETED JMP TSBRK ;ELSE BREAK ; 1$: MOV PL.DBF(R0),R2 ;ELSE GET BUFFER CLR PL.DBF(R0) ;RESET POINTER CALL PUTLIN ;INSERT IN INPUT DESCRIPTOR MOV #TS.RUN,SL.STA(R1);PUT STREAM IN RUN JMP TSRUN ;GO RUN STREAM ; ; ; TSWRQ - WAITING FOR DATA INPUT REQUEST ; TSWRQ: BIT #PF.WTI,PL.FLG(R0) ;DO WE HAVE TERMINAL INPUT IN PROGRESS BNE 10$ ;IF SO JUST BREAK TST PL.DBF(R0) ;IS THERE A BUFFER ALLOCATED BNE 2$ ;IF SO WE HAVE DATA TO LOOK AT ; ; HERE WE HAVE TO INITIATE AN INPUT REQUEST. THIS IS PROBABLY A NEW REQUEST ; HOWEVER A BREAKIN OR @ MAY HAVE STOLEN OUR FIRST REQUEST. TST SL.REG(R1) ;ARE WE A TASK STREAM BNE 1$ ;SKIP IF SO TST SL.EXS(R1) ;CHECK SAVED EXECUTION STATUS BEQ 1$ ;SKIP IF WE ARE STILL RUNNING MOV #TS.RUN,SL.STA(R1) ;MAKE STREAM RUNNABLE JMP TSRUN ;AND GO RUN IT ; 1$: CALL REQDAT ;DO THE INPUT REQUEST BCS 10$ ;RETURN IF WE GET NOTHING BR TSRDON ;ELSE GO COMPLETE REQUEST ; ; HERE A TERMINAL INPUT REQUEST HAS COMPLETED. WE HAVE TO CHECK FOR THINGS ; WHICH ARE NOT REPLIES TO OUR STREAM. ; CHECK FOR '@' TO CREATE A NEW STREAM 2$: MOV PL.DBF(R0),R3 ;GET THE BUFFER ADDRESS MOV R3,R2 ADD #10,R2 ;AND SKIP HEADER CMPB (R2)+,#'@ ;INDIRECT FILE ? BNE TSRDAT ;IF NOT REPLY DATA TSTB (R2) ;ANYTHING ELSE ON LINE ? BNE 3$ CLRB -(R2) ;IF NOT PATCH OUT '@' 3$: MOV STREAM,-(SP) ;SAVE CURRENT STREAM MOV R3,-(SP) ;SAVE BUFFER POINTER CLR PL.DBF(R0) ;RESET INPUT DATA BUFFER POINTER CALL NEWSTR ;CREATE THE NEW STREAM BCS 11$ ;SKIP IF CREATE FAILS MOV @PL.SLH(R0),STREAM;POINT TO NEW STREAM CALL NEWCTL ;CREATE NEW CONTROL DESCRIPTOR BCS 12$ ;SKIP IF THAT FAILS MOV (SP)+,R2 ;RESTORE BUFFER ITEM CALL PUTLIN ;QUEUE COMMAND TO NEW STREAM 9$: MOV (SP)+,STREAM ;RESTORE CURRENT STREAM MOV STREAM,R1 MOV PROC,R0 INC ACTIVE ;SO WE PICK UP THE BUFFER 10$: JMP TSBRK ;AND QUIT C SET ; 11$: MOV (SP)+,R0 ;DE-ALLOCATE BUFFER CALL FREESP BR 9$ ;AND CONTINUE ; 12$: MOV STREAM,R1 MOV #TS.EXT,SL.STA(R1) BR 11$ ; ; HERE A TERMINAL INPUT REQUEST HAS COMPLETED WITH DATA FOR OUR STREAM TSRDAT: BIT #FG.SRQ,SL.FLG(R1) ;SPECIAL REQUEST ? BNE 3$ ;IF SO SKIP PASS PROCESSING MOV @STRMLH,R1 ;GET TOP STREAM CALL PASSIT ;CHECK FOR STREAMS IN TS.PAS ; 3$: MOV STREAM,R1 ;RESTORE CURRENT STREAM MOV SL.RQD(R1),R2 ;GET REQUEST DESCRIPTOR MOV PL.DBF(R0),R3 ;GET INPUT DATA BUFFER CLR PL.DBF(R0) ;CLEAR BUFFER POINTER CLR 4(R3) ;CLEAR OWNER WORD MOV #M.STR,6(R3) ;SET STRING MODE MOV R3,RD.BUF(R2) ;SET ITEM IN DESCRIPTOR ; TSRDON: BIC #FG.SRQ,SL.FLG(R1) ;CLEAR SPECIAL REQUEST FLAG TST SL.REG(R1) ;IS THIS A TASK STREAM ? BNE 1$ ;IF SO SKIP MOV #TS.RUN,SL.STA(R1) BR TSRUN ;GO RUN STREAM ; 1$: CALL RPYTSK ;REPLY TO TASK INC ACTIVE ;KEEP THINGS MOVING BR TSBRK ;GO BREAK FROM SCAN ; ; TSRDY: MOV #TS.TSK,SL.STA(R1);PUT TASK STREAM IN RUN CMP SL.FWD(R1),STRMLH ;END OF STREAM LIST ? BNE 1$ ;IF NOT KEEP GOING CMP @STRMLH,R1 ;TOP OF LIST ? BNE 1$ ;IF NOT KEEP GOING CALL DISCON ;ELSE DISCONNECT STREAM FROM TASK CALL SEND ;REPLY TO TASK BR TSEXT ;AND GO TO STREAM EXIT CODE ; 1$: CALL SEND ;CONTINUE TASK INC ACTIVE BR TSBRK ;AND BREAK FROM SCAN ; ; TSEXT: MOV SL.BKW(R1),R2 ;GET STREAM ABOVE CMP R2,STRMLH ;ARE WE THE TOP ? BEQ STREX ;IF SO JUST QUIT ; CMP SL.STA(R2),#TS.EOJ;IS THE GUY ABOVE WAITING FOR US ? BNE 1$ ;SKIP IF NOT MOV #TS.RUN,SL.STA(R2);ELSE FREE HIM UP BR STREX ;AND GO EXIT OURSELVES ; 1$: CMP SL.STA(R2),#TS.RPY;HAS HE A REPLY QUEUED ? BNE 2$ ;SKIP IF NOT MOV SL.RQD(R2),R0 ;GET REPLY ITEM CALL VOIDSP ;AND DELETE IT CLR SL.RQD(R2) ;AND CLEAR POINTER BR 10$ ;AND GO FREE HIM ; 2$: CMP SL.STA(R2),#TS.PAS ;IS HE IN PASS ? BNE 3$ ;IF NOT NOTHING TO DO CLR SL.RQD(R2) ;ZERO PASS COUNT BR 10$ ; 3$: CMP SL.STA(R2),#TS.GET ;IS HE TRYING TO GET SOMETHING ? BEQ 10$ ;IF SO FREE HIM ; 4$: CMP SL.STA(R2),#TS.SPD;IS HE SUSPENDED BNE 11$ ;IF NOT JUST SKIP ; 10$: MOV #TS.RUN,SL.STA(R2) ;RESUME THE STREAM ABOVE INC ACTIVE 11$: MOV PROC,R0 ;RESTORE PROCESS BR TSBRK ;GO BREAK FROM LIST SCAN ; STREX: CALL ENDSTR ;REMOVE THE STREAM INC ACTIVE ;KEEP THINGS MOVING BR TSBRK ;AND BREAK FROM SCAN ; ; ; ; ; IF STREAM IS RUNNABLE GO RUN IT TSRUN: INC ACTIVE TST SL.REG(R1) ;IS IT A TASK STREAM ? BEQ 1$ ;SKIP IF NOT CALL RUNTSK ;CALL TASK STREAM INTERPRETER BR TSBRK ;AND BREAK FROM SCAN ; 1$: CALL RUNSTR ;ELSE CLONE INTERPRETER DSAR$S ;SUPPRESS ASTS ; RETURN WITH C SET TO INDICATE BREAK FROM ; SCAN OF STREAM LIST. ; TSBRK: SEC ;BREAK FROM SCAN STATUS RETURN ; ; RETURN WITH C CLEAR TO INDICATE CONTINUE WITH ; DOWNWARD STREAM LIST SCAN. TSNXT: CLC RETURN ; ; ; RUNSTR - CAUSES THE CURRENT STREAM TO EXECUTE ; IF STREAM HAS NEVER EXECUTED IT IS INITIATED. ; STACK USAGE NEEDS SOME EXPLANATION. ; A STREAM IS CALLED INITIALY BY A JSR PC ; ON THE USER STACK. WHEN A STREAM FINALY COMPLETES IT ; PERFORMES A RETURN TO THE NEXT INSTRUCTION. ; DURING STREAM EXECUTION PAUSE MAY BE CALLED ; TO TRAP TO THE CLONE EXECUTIVE. THIS IS ACHEVED BY ; LEAVING PAUSES RETURN ADDRESS ON THE USER STACK AND ; RETURNING ON THE SYSTEM STACK. THE ADDRESS ON THE SYSTEM ; STACK WILL ALWAYS BE THE RETURN ADDRESS OF RUNSTR. ; A RETURN ON THE USER STACK IS ALL THAT IS REQUIRED ; IN ORDER TO RESUME A CURRENTLY EXECUTING STREAM ; ; RUNSTR: ENAR$S TST SL.STK(R1) ;IS THIS A NEW STREAM ? BEQ 1$ ;IF SO INIT STACK CALL USER ;ELSE SWITCH TO USER STACK RETURN ;AND RETURN TO USER CODE ; ; SET UP STACK FOR A NEW STREAM 1$: MOV #USTKSZ,R1 ;ALLOCATE STACK ITEM CALL GETSPA BCS 2$ ;ALLOCATION FAIL MOV STREAM,R1 MOV R0,SL.STK(R1) ;SAVE BASE OF STACK ADD #USTKSZ*2,R0 ;POINT TO TOP OF STACK MOV R0,SL.USP(R1) ;INIT STACK POINTER CLR SL.EXS(R1) ;INIT EXECUTION STATUS CLR SL.LEV(R1) ;INIT LEXICAL LEVEL CLR SL.SFP(R1) ;INIT STACK FRAME POINTER MOV PROC,R0 ;GET THE PROCESS POINTER CALL USER ;SWITCH TO USER STACK CALL BEGIN ;CREATE A STACK FRAME CLR R1 ;NULL CONTEXT FOR VALEXP CALL VALEXP ;AND CALL PARSER CALL RPLY ;REPLY ANY RESULT CALL END ;AND CLEAR STACK FRAME CALL SYSTEM ;BACK TO SYSTEM STACK MOV SL.STK(R1),R0 ;RELEASE STACK CALL FREESP 2$: MOV PROC,R0 MOV STREAM,R1 MOV #TS.EXT,SL.STA(R1) ;MARK STREAM EXITING RETURN ; ; ; ; PRCINI - INITIATE A PROCESS ; R0=PROCESS ITEM TO INIT ; PRCINI: CALL GETLUN ;ALLOCATE A LUN BCC 1$ ;WE GOT ONE RETURN ;INITIALIZATION FAILED 1$: MOV R2,PL.LUN(R0) ;AND SET IN PROCESS LIST MOV PL.TI(R0),R3 ;GET TERMINAL NAME MOVB PL.TI+2(R0),R4 ;AND UNIT ALUN$S R2,R3,R4 ;ASSIGN LUN CALL TIINFO ;GET PROCESS UCB AND UIC CLR PL.SLH(R0) ;ZERO STREAM LISTHEAD CLR PL.DBF(R0) ;AND DATA BUFFER CALL CL1HEL ;PRINT HELLO MESSAGE CALL FIND ;CREATE MACRO DIRECTORY MOV R2,MACSTB ;AND SAVE IT CLC RETURN ; ; ; ; ; ; ; NEWSTR - CREATES A NEW CLONE STREAM ITEM ; AN ITEM IS CREATED, INITIALISED AND LINKED TO ; THE STREAM LIST. NEWSTR: MOV R0,-(SP) CALL GETSTR ;ALLOCATE AND ZERO STREAM ITEM BCS 1$ ;SKIP IF ALLOCATION ERROR MOV PROC,R0 ;AND RESTORE R0 MOV R0,R3 ;GET LISTHEAD ADD #PL.SLH,R3 MOV R1,R2 CALL LINKB ;LINK AT BEGINNING OF LIST MOV #TS.RUN,SL.STA(R1) 1$: MOV (SP)+,R0 RETURN ; ; ; ENDSTR - CONVERSLY DE-ALLOCATES A STREAMS RECOURCES ENDSTR: MOV R0,-(SP) MOV R1,-(SP) TST SL.REG(R1) ;IS THIS A TASK STREAM ? BNE 10$ ;SKIP IF SO 1$: TST SL.CLH(R1) ;ANYTHING IN CONTROL DESCRIPTOR LIST BEQ 2$ ;SKIP IF NOT CALL ENDCTL ;ELSE DE-ALLOCATE BR 1$ ;AND CHECK AGAIN ; DEALLOCATE THE LOCAL MACRO TABLE 2$: MOV R1,R2 ;POINT TO LISTHEAD ADD #SL.LMT,R2 3$: TST (R2) BEQ 10$ MOV @4(R2),R0 ;GET VALUE ITEM CALL FREESP ;DEALLOCATE IT CALL REMNAM ;REMOVE ENTRY FROM TABLE BR 2$ ;AND TRY FOR MORE ; DEALLOCATE ANY RECORDED ITEMS 10$: MOV SL.RLH(R1),R0 ;DE-ALLOCATE RECORD LIST CALL VOIDSP ; ; NOW UNLINK AND DEALLOCATE THE STREAM ITEM ITSELF MOV STRMLH,R3 ;GET LISTHEAD MOV (SP),R2 ;AND ITEM TO UNLINK CALL UNLINK ;UNLINK STREAM ITEM MOV (SP),R0 CALL FREESP ;AND DE-ALLOCATE MOV (SP)+,R1 MOV (SP)+,R0 RETURN ; ; ; TSKNKT - CREATE A TASK STREAM AND CONECT TASK ; INPUT: R2=CONNECT QUEUE ITEM. BEING: ; NAME (2 WORDS) ; REGION ID ; ; OUTPUT: R0 PROCESS ITEM POINTER ; R1 NEW STREAM ITEM POINTER ; ; OTHER REGISTERS MODIFIED: R2,R3,R4 ; TSKNKT: CALL GETSTR ;ALLOCATE STREAM ITEM BCS 1$ ;SKIP IF ALLOCATION FAILS MOV 4(R2),SL.TSK(R1);STORE TASK NAME MOV 6(R2),SL.TSK+2(R1) MOV 10(R2),SL.REG(R1);SAVE REGION ID 1$: MOV R2,R0 ;COPY CONNECT ITEM POINTER CALL FREESP ;DE-ALLOCATE THE CONNECT ITEM MOV STRMLH,R3 ;GET STREAM LISTHEAD MOV R1,R2 ;COPY NEW STREAM ITEM POINTER BEQ 2$ ;AND SKIP IF THERE IS NONE CALL LINKB ;LINK INTO STREAM LIST MOV #TS.RUN,SL.STA(R1);QUEUE TASK FOR EXECUTION 2$: MOV PROC,R0 ;RETURN PROC TO R0 RETURN ;NOTHING ELSE TO DO ; ; ; GETSTR - ALLOCATE A STREAM ITEM AND INITIALISE IT ; OUTPUT: R1=STREAM ITEM ADDRESS ; RETURN IS WITH C SET IF ALLOCATION FAILS ; ALL OTHER REGISTERS PRESERVED ; GETSTR::MOV R0,-(SP) MOV #SL.SIZ,R1 CALL GETSPA MOV R0,R1 MOV (SP)+,R0 RETURN .PAGE ; THE FOLLOWING ROUTINES ARE CONCERNED WITH THE CONTROL OF COMMAND ; LINE INPUT, BOTH FROM THE TERMINAL AND FROM FILES. ; ; ; ; A CONTROL DESCRIPTOR IS ASSOCIATED WITH EACH SOURCE ; OF COMMAND INPUT. E.G. EACH FILE OR CONSOLE. ; THE CONTROL DESCRIPTOR CONTAINS SUFFICIENT INFORMATION ; TO RE-ESTABLISH A POSITION IN THE FILE AFTER ; A CONTEXT SWITCH OR TRANSFER OF INTERPRETED CODE. ; ; NEWCTL - ALLOCATES A NEW CONTROL DESCRIPTOR ; ; OUTPUT: R2=DESCRIPTOR ITEM POINTER ; ITEM IS INITIALISED AND LINKED AT HEAD ; OF DESCRIPTOR LIST. ; ; REGISTERS MODIFIED: R2,R4 ; ; CONTROL DESCRIPTOR ITEMS HAVE THE FOLLOWING FORMAT: CD.FWD==4 ;FORWARD DESCRIPTOR LIST POINTER CD.BWD==6 ;BACKWARD DESCRIPTOR LIST POINTER CD.FDB==10 ;FILE DESCRIPTOR POINTER ;ZERO IF ASSOCIATED FILE IS CLOSED CD.DEV==12 ;DEVICE NAME AND BINARY UNIT FOR DISK FILES (2 WORDS) CD.FID==16 ;THREE WORDS ENABLING THE FILE TO ;BE RE-OPENED BY ID. IF CD.FID IS ZERO THE ;INPUT IS FROM THE CONSOLE. ; FOR FILE INPUT THE NEXT TWO WORDS ARE THE ; VIRTUAL BLOCK AND BYTE OFFSET IN THE FILE TO THE ; CURRENT RECORD. CD.PNT==24 ;VIRTUAL BLOCK POINTER ;BYTE OFFSET IN BLOCK ; FOR CONSOLE INPUT THEY ARE THE BUFFER LISTHEAD CD.BLH==24 ; CD.CMA==30 ;ACTUAL MEMORY ADDRESS OF CURRENT LINE ;FOR CONSOLE BUFFERS THIS IS THE ADDRESS OF ;THE BUFFER ITEM. CD.CHP==32 ;CHARACTER POINTER OFFSET ;BIT 15 INDICATES THAT POINTER IS AT EOL. CD.LIN==34 ;LINE NUMBER CD.LSM==36 ;LAST SYMBOL READ CD.LTP==40 ;AND ITS TYPE CD.FLG==42 ;COMMAND DESCRIPTOR FLAGS WORD CF.LIT==1 ;LITERAL (INDIRECT FILE) INPUT CF.SUB==2 ;SUBSTITUTION ENABLED CD.ARG==44 ;SUBROUTINE ARGUMENT BLOCK POINTER CD.SIZ==20. ;DESCRIPTOR LIST ITEM LENGTH IN WORDS ; NEWCTL::MOV R0,-(SP) MOV R1,-(SP) MOV R3,-(SP) MOV #CD.SIZ,R1 ;ITEM SIZE REQUIRED CALL GETSPA MOV R0,R2 ;THATS DESCRIPTOR POINTER BCS 1$ ;SKIP IF ALLOCATION FAILED MOV STREAM,R1 ;GET CURRENT STREAM MOV R1,R3 ADD #SL.CLH,R3 ;POINT TO LISTHEAD CALL LINKB ;LINK AT BEGINNING 1$: MOV (SP)+,R3 MOV (SP)+,R1 MOV (SP)+,R0 RETURN ; ; ; ENDCTL - DE-ALLOCATE CURRENT CONTROL DESCRIPTOR ; ; INPUT: SL.CLH =ADDRESS OF DESCRIPTOR TO DE-ALLOCATE ; OUTPUT: ASSOCIATED BUFFERS ARE DE-ALLOCATED ; DESCRIPTOR IS UNLINKED FROM LIST AND DE-ALLOCATED. ; ; REGISTERS MODIFIED: NONE ; ; ENDCTL::MOV R0,-(SP) MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) MOV R4,-(SP) MOV STREAM,R2 MOV SL.CLH(R2),R2 ;GET THE CURRENT CONTROL DESCRIPTOR BEQ 30$ ;RETURN IF NULL TST CD.FID(R2) ;FILE INPUT ? BNE 10$ ;SKIP IF SO ; ; DE-ALLOCATE COMMAND BUFFER CHAIN MOV CD.BLH(R2),R0 ;BUFFER LIST HEAD BEQ 20$ ;IS NULL 1$: MOV 4(R0),R1 ;SAVE SUCCESSOR CALL FREESP ;DE-ALLOCATE BUFFER MOV R1,R0 BEQ 20$ ;BREAK IF END BR 1$ ;ELSE KEEP GOING 10$: CALL CLOSE ;CLOSE OPEN FILE ; 20$: MOV CD.ARG(R2),R3 ;GET ARGUMENT BLOCK POINTER CALL ENDARG ;DEALLOCATE ARGUMENT BLOCK MOV STREAM,R3 ;FORM CONTROL LISTHEAD ADD #SL.CLH,R3 CALL UNLINK ;UNLINK DESCRIPTOR MOV R2,R0 CALL FREESP ;DE-ALLOCATE DESCRIPTOR CALL GETLIN ;GET BACK THE OLD COMMAND LINE 30$: MOV (SP)+,R4 MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RETURN ; ; ; ; PUTLIN - INSERT A BUFFER IN A CONSOLE INPUT DESCRIPTOR ; ; INPUT: R2=ADDRESS OF BUFFER ITEM ; OUTPUT: NON-BLANK BUFFERS ARE LINKED TO DESCRIPTOR LIST ; NULL BUFFERS ARE DE-ALLOCATED IMMEDIATLY ; ; THE CONSOLE BUFFER LIST IS A LINKED LIST OF VARIABLE LENGTH ITEMS ; CONTAINING COMMAND BUFFERS INPUT FROM THE CONSOLE. ; THE LISTHEAD IS AT CD.BLH IN THE COMMAND DESCRIPTOR. ; CB.FWD=4 ;POINTER TO SUCCEDING CONSOLE BUFFER ITEM ;THIS IS ZERO AT THE END OF THE LIST CB.BKW=6 ;REVERSE POINTER IN BUFFER LIST CB.BUF=10 ;START OF COMMAND TEXT. ; ; REGISTERS R3,R4 DESROYED ; PUTLIN: TST R2 ;DO WE HAVE A BUFFER ? BEQ 20$ ;RETURN IF NOT MOV R0,-(SP) MOV R1,-(SP) MOV STREAM,R1 TSTB CB.BUF(R2) ;IS BUFFER NULL ? BEQ 1$ ;IF SO JUST THROW IT AWAY MOV SL.CLH(R1),R3 ;GET CONTROL DESCRIPTOR ADD #CD.BLH,R3 ;GET COMMAND BUFFER LISTHEAD CALL LINKE ;LINK IN BUFFER AT END OF LIST CLR CB.FWD(R2) ;AND FLAG END OF LIST BR 2$ ; 1$: MOV R2,R0 ;DE-ALLOCATE EMPTY BUFFER CALL FREESP 2$: MOV (SP)+,R1 MOV (SP)+,R0 20$: RETURN ; ; ; NEXLIN - RETURN NEXT COMMAND INPUT LINE ; ; OUTPUT: A NEW COMMAND LINE IS AVAILABLE ; REGISTERS R3,R4,R5 DESTROYED ; ; IF INPUT IS FROM THE CONSOLE AND NO MORE ; COMMAND BUFFERS ARE QUEUED A PROMPT IS ISSUED AND ; A SWITCH TO SYSTEM STATE OCCURES. ; NEXLIN::MOV R0,-(SP) MOV R1,-(SP) MOV R2,-(SP) 1$: MOV STREAM,R1 ;PICK UP CURRENT STREAM POINTER MOV SL.CLH(R1),R2 ;GET CURRENT DESCRIPTOR TST CD.FID(R2) ;CONSOLE STREAM? BEQ 2$ ;SKIP IF SO CALL NEXT ;ELSE READ FROM FILE BR 10$ ;AND QUIT 2$: MOV CD.CMA(R2),R0 ;GET CURRENT BUFFER BNE 3$ ;SKIP IF THERE IS ONE MOV CD.BLH(R2),R0 ;ELSE GET START OF BUFFER LIST BEQ 4$ ;IF NULL GO READ BR 5$ ;ELSE NO PROBLEM 3$: MOV CB.FWD(R0),R0 ;GET SUCCESSOR BUFFER BNE 5$ ;SKIP IF THERE IS ONE 4$: CALL REQCMD ;GO REQUEST COMMAND INPUT BR 1$ ;GO SEE IF WE GOT SOMETHING ; 5$: MOV R0,CD.CMA(R2) ;SAVE THE CURRENT BUFFER 10$: CLR CD.CHP(R2) ;RESET CHAR POINTER INC CD.LIN(R2) ;SET LINE NUMBER MOV PROC,R0 BIT #PF.TRA,PL.FLG(R0);TRACING ENABLED ? BEQ 11$ ;SKIP IF NOT TST EXEC ;IS LINE TO BE EXECUTED ? BNE 11$ ;SKIP IF NOT CALL TRACE ;ELSE PRINT LINE 11$: MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RETURN ;AND EXIT ; ; REQCMD - CAUSE CURRENT STREAM TO ENTER WAIT FOR COMMAND STATE ; REQCMD: MOV #CPRMT+4,R0 ;GET PROMPT STRING MOV STREAM,R1 ;GET STREAM ITEM MOV SL.LEV(R1),R1 ;AND GET LEXICAL LEVEL BIC #177770,R1 ;LIMIT THE NUMBER OF INDENTS 1$: DEC R1 BLE 2$ MOVB #TAB,(R0)+ BR 1$ ; 2$: CLRB (R0)+ MOV #CPRMT,R2 CALL QIO ;ISSUE INPUT REQUEST PAUSE$ #TS.WCM ;SPECIFY NEW STATE RETURN ;NOW WEVE GOT SOMETHING ; CPRMT: .ASCII /CL1> / .EVEN ; ; ; THE FOLLOWING THREE ROUTINES ENABLE THE INTERPRETER ; TO LOCATE ITS CHARACTER POSITION IN THE CURRENT COMMAND ; INPUT. ; ; GETPNT - GET CURRENT CHARACTER POINTER ; ; OUTPUT: R0=ADDRESS OF NEXT CHARACTER TO READ ; ; REGISTERS R3,R4,R5 DESTROYED ; ;- ; GETPNT::MOV R1,-(SP) MOV R2,-(SP) 1$: MOV STREAM,R1 ;GET THE CURRENT STREAM MOV SL.CLH(R1),R2 ;GET COMMAND DESCRIPTOR TST CD.FID(R2) ;FILE INPUT ? BEQ 2$ ;SKIP IF NOT TST CD.FDB(R2) ;IS FILE OPEN ? BNE 2$ ;IF SO ITS STILL EASY CALL POINT ;ELSE OPEN FILE AND POINT TO RECORD 2$: TST CD.CMA(R2) ;DO WE HAVE A CURRENT LINE ? BEQ 3$ ;IF NOT GO READ ONE TST CD.CHP(R2) ;ARE WE AT END OF LINE (BIT 15 SET) BPL 10$ ;IF NOT THERES NO PROBLEM 3$: CALL NEXLIN ;ELSE READ ANOTHER LINE ; ; NOW THAT THE LINE IS RESIDENT, SET UP THE CHARACTER POINTER 10$: MOV CD.CMA(R2),R0 ;GET BUFFER ADDRESS TST CD.FID(R2) ;IS THIS A FILE INPUT BNE 11$ ;IF SO NO PROBS ADD #10,R0 ;ELSE SKIP HEADER 11$: ADD CD.CHP(R2),R0 ;OFFSET TO CURRENT CHAR MOV (SP)+,R2 MOV (SP)+,R1 RETURN ; ; ; PUTPNT - UPDATE POINTER IN CURRENT BUFFER ; ; INPUT: R0=POINTER TO CURRENT SYMBOL ; R1=SYMBOL LENGTH (-1) FOR PUTBACK MODE ; ; OUTPUT: CHARACTER POINTER IS ADVANCED OVER SYMBOL. ; IF R0 POINTS TO AN END-OF-LINE CHAR (NULL BYTE) ; OF AN END-OF-FILE CHAR (-1) THE POINTER IS NOT ; UPDATED, BUT THE END-OF-LINE FLAG (BIT 15 OF CD.CHP) ; IS SET. ; ; PUTPNT IS ALSO CALLED WITH R1=-1 TO RESET THE CHARACTER ; POINTER IN A 'PUTBACK' OPERATION. IN THIS MODE THE POINTER ; IS SET TO THE ADDRESS INDICATED IN R0 AND THE EOL FLAG ; IS CLEARED. ; ; ALL REGISTERS PRESERVED ; PUTPNT::MOV R0,-(SP) MOV R2,-(SP) MOV STREAM,R2 ;GET CURRENT STREAM MOV SL.CLH(R2),R2 ;AND INPUT DESCRIPTOR ; TST R1 ;CHECK FOR A 'PUTBACK' BPL 1$ ;SKIP IF NOT BIC #100000,CD.CHP(R2) ;CLEAR EOL FLAG BR 4$ ; 1$: TSTB (R0) ;END OF LINE ? BEQ 2$ ;IF SO SET FLAG CMPB (R0),#-1 ;END OF FILE ? BNE 3$ ;IF NOT JUST UPDATE THE POINTER 2$: BIS #100000,CD.CHP(R2);SET END OF LINE FLAG BR 4$ ; 3$: ADD R1,R0 ;SKIP OVER ITEM 4$: SUB CD.CMA(R2),R0 ;FORM BUFFER OFFSET TST CD.FID(R2) ;CONSOLE INPUT BNE 5$ ;NO PROBS IF NOT SUB #10,R0 ;ELSE ALLOW FOR HEADER 5$: MOVB R0,CD.CHP(R2) ;SAVE OFFSET MOV (SP)+,R2 MOV (SP)+,R0 RETURN ; ; GETLIN - SET UP CD.CMA FIELD OF DESCRIPTOR ; MUST BE CALLED WHENEVER A TRANSFER OF CONTROL OCCURES. ; ; REGISTERS DESTROYED: NONE ; ; GETLIN::MOV R2,-(SP) MOV STREAM,R2 ;GET CURRENT STREAM MOV SL.CLH(R2),R2 ;GET CURRENT DESCRIPTOR BEQ 20$ ;SKIP IF NULL TST CD.FID(R2) ;CONSOLE OR FILE ? BEQ 20$ ;SKIP IF CONSOLE INPUT 10$: CALL POINT ;ELSE UPDATE FILE 20$: MOV (SP)+,R2 RETURN ; ; ; ; ; ; THE NEXT TWO ROUTINES PERMIT THE POINTER IN AN INPUT ; DESCRIPTOR TO BE SAVED AND RESTORED. ; ; SAVPNT - SAVE INPUT POINTER ; INPUT: SL.CTL- CURRENT CONTROL DESCRIPTOR POINTER ; OUTPUT: R0 - POINTER TO COPY OF CURRENT DESCRIPTOR ; SAVPNT::MOV R1,-(SP) MOV STREAM,R1 MOV SL.CLH(R1),R1 MOV R1,R0 CALL CPYITM CLR CD.FDB(R0) ;NO CURRENT FDB MOV (SP)+,R1 RETURN ; ; RSTPNT - RESTORE AN INPUT POINTER ; INPUT: R0=POINTER TO RESTORE ; OUTPUT: CURRENT CONTROL DESCRIPTOR IS UPDATED ; TO DUPLICATE INPUT. ; THIS EFFECTS A JUMP WITHIN A MACRO FILE. ; ; REGISTERS MODIFIED: NONE ; RSTPNT::MOV R1,-(SP) MOV STREAM,R1 MOV SL.CLH(R1),R1 TST CD.FID(R0) ;FILE INPUT ? BEQ 1$ ;SKIP IF NOT MOV CD.PNT(R0),CD.PNT(R1) MOV CD.PNT+2(R0),CD.PNT+2(R1) BR 2$ 1$: MOV CD.CMA(R0),CD.CMA(R1);CURRENT LINE POINTER 2$: MOV CD.CHP(R0),CD.CHP(R1);CHARACTER OFFSET MOV CD.LIN(R0),CD.LIN(R1);LINE NUMBER MOV CD.LSM(R0),CD.LSM(R1);PUT-BACK SYMBOL MOV CD.LTP(R0),CD.LTP(R1);PUT-BACK TYPE MOV CD.FLG(R0),CD.FLG(R1);FLAGS WORD CALL GETLIN ;PAGE LINE IN MOV (SP)+,R1 RETURN .PAGE ; BRKIN - INITIATE A BREAKIN COMMAND ; BREAKIN COMMANDS EXECUTE AT THE SAME STACK LEVEL AS THE ; CURRENT ENVIRONMENT. ONCE BREAKIN MODE IS ENTERED IT ; REMAINS ACTIVE UNTIL A RESUME COMMAND IS ISSUED. ; BRKIN OPERATES IN EXACTLY THE SAME MANNER AS RUNSTR ; EXCEPT THAT STREAM INITIALISATION IS NOT REQUIRED. ; IF A BREAKIN COMMAND IS ATTEMPTED WHILST ANOTHER IS ALREADY ; IN PROGRESS, THE CURRENT COMMND IS STOPPED AND RETURN OCCURES ; WITH C SET. WHEN BREAKIN STATUS HAS CLEARED THE NEW BREAKIN ; WILL EXECUTE. ; ; OUTPUT: C CLEAR - BREAKIN ACCEPTED ; C SET - BREAKIN REJECTED ; BRKIN: BIT #FG.BRK,SL.FLG(R1) ;BREAKIN ALREADY IN PROGRESS ? BNE 1$ ;IF SO KILL IT FIRST TST SL.EXS(R1) ;IS STREAM EXECUTING BEQ BRK ;IF SO JUST EXECUTE THE BREAKIN BR 2$ ;ELSE HOLD OFF FOR THE MOMENT ; ; HERE WE PREVENT THE BREAKIN OF A BREAKIN BY TERMINATING THE CURRENTLY ; ACTIVE ROUTINE. FOR TERMINAL INPUT WE FORCE A CONTROL-Z INTO THE ; INPUT BUFFER. IF THE STREAM HAS A REPLY QUEUED WE MUST DE-ALLOCATE ; THE REPLY ITEM AND CHANGE THE STATUS TO RUN. 1$: MOV R0,-(SP) MOV R1,-(SP) MOV #EX.RBI,SL.EXS(R1) ;GIVE BREAKIN ROUTINE RESUME STATUS CMP SL.STA(R1),#TS.RPY ;TEST FOR REPLY QUEUED BNE 3$ ;SKIP IF NONE MOV #TS.RUN,SL.STA(R1) ;MAKE STREAM RUNNABLE MOV SL.RQD(R1),R0 ;GET REPLY ITEM CALL VOIDSP 3$: MOV SL.CLH(R1),R2 ;GET CONTROL DESCRIPTOR TST CD.FID(R2) ;FILE INPUT ? BNE 4$ ;SKIP IF SO MOV #5,R1 ;ALLOCATE A BUFFER ITEM CALL GETSPA ;TO RECEIVE AN EOF BCS 5$ ;SKIP ON ALLOCATION FAIL MOV #CTRLZ,10(R0) ;STORE THE EOF 5$: MOV R0,R2 ;COPY ITEM ADDRESS CALL PUTLIN 4$: MOV (SP)+,R1 MOV (SP)+,R0 2$: SEC RETURN ; BRK: MOV SL.STA(R1),SL.BST(R1);SAVE TRANSACTION STATE MOV SL.RQD(R1),SL.BRQ(R1);SAVE REQUEST DESCRIPTOR BIS #FG.BRK,SL.FLG(R1);SET BREAKIN STATUS CALL USER ;SWITCH TO USER STACK ; 2$: MOV STREAM,R1 ;RESTORE CURRENT STREAM MOV #TS.RUN,SL.STA(R1);AND MAKE STREAM RUNNABLE CLR SL.RQD(R1) CLR R1 ;INIT CONTEXT CALL VALEXP ;START THE PARSER ; VALEXP IMMEDIATLY RETURNS TO OUR OWN RETURN ADDRESS ; WE ONLY ARRIVE AT THE NEXT INSTRUCTION WHEN THE ; BREAKIN SEQUENCE IS COMPLETE. CALL RPLY ;REPLY ANY RESULT MOV STREAM,R1 TST EXEC ;STREAM STILL EXECUTABLE BEQ 2$ ;IF SO GET MORE BREAKIN COMMANDS CMP EXEC,#EX.ERR ;ERROR IN BREAKIN ? BNE 3$ MOV #EX.RUN,EXEC ;IF SO RESET STATUS BR 2$ ;AND CONTINUE BREAKIN 3$: CMP EXEC,#EX.RBI ;RESUME FROM BREAKIN BNE 4$ ;IF NOT LEAVE NEW STATUS MOV #EX.RUN,EXEC ;ELSE PUT BACK TO RUN 4$: MOV SL.BST(R1),SL.STA(R1); RESTORE PREVIOUS STATUS MOV SL.BRQ(R1),SL.RQD(R1) CLR SL.BST(R1) ;CLEAR BREAKIN STATUS CLR SL.BRQ(R1) BIC #FG.BRK,SL.FLG(R1);CLEAR BREAKIN FLAG CALL SYSTEM ;SWITCH TO SYSTEM STACK CALL ENDCTL ;DE-ALLOCATE DESCRIPTOR CLC RETURN ;AND CONTINUE ; ; ; .PAGE ; THE FOLLOWING ROUTINES ARE CALLED BY THE STREAM INTERPRETERS TO ; INITIATE TRANSACTIONS. FOR CLONE STREAMS THEY WILL GENERALY CAUSE ; THE STREAM TO ENTER A TRANSACTION STATE AND SUSPEND FOR TASK STREAMS ; THE ACTION IS SIMILAR BUT NO CONTEXT SWITCH IS REQUIRED. ; ; ; ; ; RQST - REQUEST INPUT ; RQSTSP - REQUEST INPUT IN SPECIAL MODE ; ; INPUT: R0=REQUEST TYPE ; 0 TEST REQUEST ; M.STR STRING INPUT REQUEST ; R1=NAME STRING ADDRESS ; R2=PROMPT STRING ; OUTPUT: R0=ITEM ADDRESS (WHEN CALLED BY A CLONE STREAM) ; NONE WHEN CALLED BY A TASK STREAM ; ; OTHER REGISTERS DESTROYED: R3,R4,R5 ; RQST:: MOV R0,-(SP) MOV R1,-(SP) MOV R2,-(SP) BR REQ ; RQSTSP::MOV R0,-(SP) MOV R1,-(SP) MOV R2,-(SP) MOV STREAM,R1 BIS #FG.SRQ,SL.FLG(R1) ;SET SPECIAL REQUEST FLAG REQ: MOV #RD.SIZ,R1 ;CREATE REQUEST DESCRIPTOR CALL GETSPA BCS 1$ ;SKIP ON ALLOCATION FAIL MOV R0,R2 MOV (SP),RD.PRM(R2) ;SAVE PROMPT POINTER MOV 2(SP),RD.NAM(R2);SAVE NAME POINTER MOV 4(SP),RD.TYP(R2) ;INIT INPUT MODE CLR RD.BUF(R2) ;CLEAR BUFFER POINTER MOV STREAM,R1 ;RESTORE STREAM POINTER MOV R2,SL.RQD(R1) ;SET REQUEST DESCRIPTOR MOV #TS.WRQ,SL.STA(R1); SET WAIT STATUS IN CASE ITS A TASK STREAM TST SL.REG(R1) ;ARE WE A TASK STREAM ? BNE 1$ ;IF SO JUST RETURN PAUSE$ #TS.WRQ ;GO DO THE REQUEST MOV STREAM,R1 ;GET BACK THE STREAM POINTER MOV SL.RQD(R1),R0 ;AND THE REQUEST DESCRIPTOR CLR SL.RQD(R1) ;CLEAR DESCRIPTOR POINTER MOV RD.BUF(R0),4(SP);GET RESULT CALL FREESP ;DE-ALLOCATE DESCRIPTOR ; ; 1$: MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 ;RETURN RESULT IF WE ARE IN CLONE MODE RETURN ; ; ; ; RPLY - REPLY A VALUE TO THE STREAM BELOW ; INPUT: R0=VALUE ITEM TO REPLY ; RETURN OCCURES ONCE REPLY HAS BEEN ACCEPTED. ; IF NO LOWER STREAM EXISTS THE VALUE IS PRINTED. ; IN MCR MODE VALUES ARE REPLIED TO MCR. ; REGISTERS R1,R2 PRESERVED R0,R3,R5,R5 DESTROYED ; ; RPLY:: TST R0 ;ANYTHING TO REPLY ? BEQ 10$ ;SKIP IF NOT TST EXEC BNE 10$ MOV R1,-(SP) MOV R2,-(SP) MOV #M.STR,R1 ;CONVERT TO STRING CALL CONVRT BCS 2$ ;SKIP IF UNDEFINED MOV STREAM,R1 ;GET STREAM POINTER BIT #FG.TXT,SL.FLG(R1) ;TEXT MODE ? BNE 1$ ;GO PRINT IF SO BIT #FG.MCR,SL.FLG(R1) ;MCR MODE ? BNE 5$ ;SKIP IF SO MOV SL.FWD(R1),R2 ;GET STREAM BELOW CMP R2,STRMLH ;ARE WE THE BOTTOM ? BEQ 1$ ;IF SO GO PRINT CMP SL.STA(R2),#TS.EXT;JOB BELOW FINISHED ? BEQ 2$ ;IF SO IGNORE REPLY ; ; REPLIES GENERATED BY A BREAKIN ARE TREATED AS THOUGH THEY CAME FROM ; A HIGHER STREAM AND THUS MUST DECREMENT THE PASS COUNT. BIT #FG.BRK,SL.FLG(R1) ;IS STREAM IN BREAKIN MODE ? BEQ 3$ ;IF NOT SKIP CMP SL.BST(R1),#TS.PAS ;IS BROKEN INTO STREAM IN PASS ? BNE 3$ ;SKIP IF NOT DEC SL.BRQ(R1) ;ELSE COUNT THIS REPLY BGT 3$ CLR SL.BRQ(R1) ;RESET PASS COUNT MOV #TS.RUN,SL.BST(R1) ;AND MAKE STREAM RUNNABLE 3$: MOV R0,SL.RQD(R1) ;QUEUE REPLY ITEM PAUSE$ #TS.RPY ;WAIT FOR REPLY TO BE ACCEPTED BR 9$ ;AND RETURN ; 1$: MOV R0,R2 ;IF NO TASK - PRINT REPLY ADD #10,R2 CALL OUT 2$: CALL VOIDSP ;RELEASE ITEM BR 9$ ;AND RETURN ; 5$: MOV R0,R2 ADD #10,R2 CALL LOGMCR ;LOG THE REPLY DSAR$S ;INHIBIT ASTS UNTIL WEVE CHANGED STATUS CALL QMCR ;QUEUE THE REPLY TO MCR CALL VOIDSP ;RELEASE ITEM TST EXEC ;CHECK NO ERRORS BNE 9$ PAUSE$ #TS.MCR ;ENTER MCR WAIT STATE ; 9$: MOV (SP)+,R2 MOV (SP)+,R1 10$: RETURN ; ; ; ; ;+ ; REQDAT - PERFORM A DATA INPUT REQUEST ; ; THIS ROUTINE ATTEMPTS TO SATISFY AN INPUT REQUEST WITH A REPLY FROM A ; HIGHER STREAM, OR WITH A DIRECT LOOKUP IN A HIGHER STREAM'S SYMBOL TABLE. ; IF BOTH THESE ATTEMPTS FAIL A TERMINAL INPUT REQUEST IS ISSUED. ; ; CALLED ON CLONE SYSTEM STACK FOR A STREAM IN TS.WRQ WHICH HAS NO INPUT ; ACTIVE OR COMPLETED. ; ; INPUT: SL.RQD = REQUEST DESCRIPTOR POINTER ; DESCRIPTOR OFFSETS ARE: RD.NAM==4 ;ADDRESS OF NAME STRING RD.PRM==6 ;ADDRESS OF PROMPT STRING RD.BUF==10 ;LOCATION TO RECEIVE DATA BUFFER POINTER RD.TYP==12 ;TYPE OF INPUT REQUEST ; 0 TEST IF DATA IS AVAILABLE (FLAG IN RD.BUF) ; M.STR STRING INPUT REQUEST ; M.NUM NUMERIC INPUT REQUEST ; M.BOO LOGICAL INPUT REQUEST ; AT PRESENT NON-ZERO IS STRING REQUEST. RD.SIZ==6 ;LENGTH OF DESCRIPTOR IN WORDS ; ; OUTPUT: C=0 DATA IS AVAILABLE ; RD.BUF POINTS TO DATA ITEM ; C=1 A TERMINAL INPUT REQUEST HAS BEEN STARTED. ; R2 REQUEST DESCRIPTOR ADDRESS ; ; REGISTERS DESTROYED: R3,R4,R5 ; ; ; THE STREAM LIST IS SCANNED IN AN UPWARD DIRECTION. IF LOOKUP IS ENABLED ; EACH STREAM'S SYMBOL TABLE IS SCANNED FOR A VARIABLE OF THE SPECIFIED NAME ; WHICH, IF FOUND, PROVIDES THE RESULT OF THE INPUT REQUEST. IF LOOKUP IS ; NOT ENABLED OR NO MATCHING NAME IS FOUND, BUT A STREAM HAS A REPLY QUEUED ; THIS IS USED TO SATISFY THE REQUEST. FINALY IS BOTH THESE MECHANISMS FAIL ; A TERMINAL INPUT REQUEST IS INITIATED. ; ; IF THE REQUEST TYPE IS 'TEST', RD.BUF IN THE REQUEST DESCRIPTOR ; IS SET 1/0 TO INDICATE DATA AVAILABLE/NOT-AVAILABLE RESPECTIVLY ; ; IF FG.SRQ IS SET THE REQUEST IS DIRECTED TO THE CONSOLE WITHOUT ; SCANNING FOR REPLIES OR PERFORMING ANY LOOKUP. ; ; REQDAT::MOV R0,-(SP) MOV R1,-(SP) MOV STREAM,R1 MOV SL.RQD(R1),R2 ;GET REQUEST DESCRIPTOR MOV R2,-(SP) ;SAVE IT ON TOP OF THE STACK TST SL.REG(R1) ;IS THIS A TASK STREAM BEQ 3$ ;SKIP IF NOT CALL MAP ;ELSE MAP OVER COMMON REGION MOV STREAM,R1 ;AND RESTORE THE STREAM POINTER 3$: BIT #FG.SRQ,SL.FLG(R1) ;SPECIAL REQUEST ? BNE 20$ ;SKIP SCAN IF SO ; ; START THE UPWARD STREAM LIST SCAN CLR R3 ;SAVE FIRST STREAM IN TS.RPY 1$: MOV SL.BKW(R1),R1 ;GO TO NEXT STREAM UP CMP R1,STRMLH ;IS THIS THE LISTHEAD BEQ 4$ ;IF SO BREAK FROM SEARCH CMP SL.STA(R1),#TS.RPY ; ANYTHING TO REPLY ? BNE 2$ ;SKIP IF NOT TST R3 ;ALREADY GOT ONE ? BNE 2$ MOV R1,R3 ;SAVE STREAM WITH REPLY QUEUED 2$: MOV (SP),R2 ;RESTORE REQUEST DESCRIPTOR MOV RD.NAM(R2),R0 ;GET NAME ADDRESS BEQ 1$ ;LOOP IF NULL TSTB (R0) ;IS NAME NULL ? BEQ 1$ ;IF SO SKIP LOOKUP MOV R1,-(SP) ;SAVE STREAM MOV SL.STB+4(R1),R2 ;GET SYMBOL TABLE POINTER MOV #6,R1 ;MAX STRING LENGTH CALL LOOKUP ;LOOKUP NAME IN TABLE MOV (SP)+,R1 ;RESTORE STREAM BCS 1$ ;SKIP IF LOOKUP FAILED MOV (R2),R0 ;ELSE GET RESULT POINTER CALL DEREF ;FOLLOW ANY INDIRECTIONS BNE 10$ ;AND GO REPLY WITH RESULT BR 1$ ; ; HERE AS WE COULDNT FIND OUR VARIABLE IN A SYMBOL TABLE ; WE SEE IF WE FOUND ANY STREAMS WITH A REPLY QUEUED 4$: MOV R3,R1 ;ANY STREAMS WITH REPLYS QUEUED ? BEQ 20$ ;IF NOT WE HAVE TO ASK FOR INPUT MOV (SP),R2 ;RESTORE REQUEST DESCRIPTOR TST RD.TYP(R2) ;IS THIS ONLY A TEST REQUEST BEQ 10$ ;IF SO DONT TOUCH THE STREAM MOV SL.RQD(R1),R0 ;GET REPLY ITEM CLR SL.RQD(R1) ;CLEAR POINTER MOV #TS.RUN,SL.STA(R1) ;FREE STREAM FOR EXECUTION ; ; ; HERE WEVE FOUND A STREAM WHICH CAN SATISFY THE REQUEST ; R0=VALUE ITEM ; R1=STREAM POINTER ; 10$: MOV (SP),R2 ;RESTORE REQUEST DESCRIPTOR TST RD.TYP(R2) ;IS THIS A TEST REQUEST ? BNE 12$ ;SKIP IF NOT MOV #1,R0 ;SET DATA AVAILABLE FLAG BR 16$ ; ; IF ANY STREAMS ARE IN TS.PAS BETWEEN THE SOURCE OF THE REPLY ; AND ITS RECIPIANT WE MUST DECREMENT THEIR PASS COUNTS 12$: MOV SL.FWD(R1),R1 ;GET THE NEXT STREAM BELOW CALL PASSIT ;AND SEARCH FOR STREAMS IN TS.PAS ; ; SET DATA ITEM POINTER IN REQUEST DESCRIPTOR AT RD.BUF MOV #M.STR,R1 ;CONVERT TO STRING CALL CONVRT MOV (SP),R2 ;GET REQUEST DESCRIPTOR CALL LOGRPY ;LOG REPLY IF REQUIRED MOV STREAM,R1 TST SL.REG(R1) ;IS REQUEST FROM A TASK STREAM ? BNE 16$ ;IF SO DATA WILL BE COPIED TST 4(R0) ;IS THIS A TEMPORARY ITEM ? BEQ 16$ ;IF SO NO NEED TO DUPLICATE CALL CPYITM ;ELSE CREATE A COPY CLR 4(R0) ;CLEAR OWNER WORD BR 16$ ;GO RETURN RESULT ; 17$: CLR R0 ;UNSATISFIED TEST REQUEST 16$: MOV (SP),R2 ;GET REQUEST DESCRIPTOR MOV R0,RD.BUF(R2) ;SET ITEM POINTER CLC ;FLAG DATA AVAILABLE BR 30$ ;AND RETURN ; ; HERE WE HAVE TO START AN INPUT REQUEST 20$: MOV (SP),R2 ;GET BACK DESCRIPTOR TST RD.TYP(R2) ;IS THIS A TEST REQUEST ? BEQ 17$ ;IF SO RETURN NOTHING AVAILABLE FLAG CALL REQUIN ;GO START INPUT SEC ;FLAG NO DATA AVAILABLE ; 30$: MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RETURN ;OPERATION COMPLETE ; ; ; REQUIN - REQUEST CONSOLE INPUT ; INPUT: R2=REQUEST DESCRIPTOR ; REQUIN: MOV R2,-(SP) MOV RD.NAM(R2),R2 ;GET NAME ADDRESS BEQ 1$ TSTB (R2) ;IS NAME NULL ? BEQ 1$ ;SKIP IF SO CALL OUT ;AND PRINT NAME 1$: MOV (SP),R2 MOV RD.PRM(R2),R2 ;NOW GET PROMPT CALL QIO ;AND START THE READ MOV (SP)+,R2 RETURN ; ; ; ; PASSIT - DECREMENT PASS COUNTS FOR ANY STREAMS PASSED BY A REPLY ; ; INPUT: R1 HIGHEST STREAM TO CONSIDER ; STREAM STREAM WHICH IS RECEIVING THE REPLY ; ; OUTPUT: R1=STREAM ; PASSIT: CMP R1,STREAM ;ARE WE DOWN TO THE RECEIVING STREAM BEQ 2$ CMP SL.STA(R1),#TS.PAS ;PASS STATUS ? BNE 1$ ;IF NOT SKIP THIS STREAM DEC SL.RQD(R1) ;ONE LESS REPLY BGT 1$ MOV #TS.RUN,SL.STA(R1) ;MAKE STREAM RUNNABLE CLR SL.RQD(R1) ;CLEAR REQUEST DESCRIPTOR 1$: MOV SL.FWD(R1),R1 ;DOWN TO NEXT STREAM BR PASSIT ;AND PROCESS THIS ONE ; 2$: RETURN ;STOP AT CURRENT STREAM ; ; ; ; ; ; RECORD - RECORD A VALUE IN CURRENT STREAM ; INPUT: R0=VALUE POINTER ; R1=NAME POINTER (NOT YET IMPLEMENTED) ; RECORD::TST R0 ;ANYTHING THERE BEQ 1$ CALL LOGREC MOV R0,-(SP) MOV STREAM,R1 MOV SL.RLH(R1),R0 ;GET RECORD LIST CALL VOIDSP ;RELEASE PREVIOUS VALUE IF ANY MOV (SP)+,SL.RLH(R1);AND SAVE NEW ONE MOV SL.BKW(R1),R1 ;GET STREAM ABOVE CMP R1,STRMLH ;IF THERE IS ONE BEQ 1$ CMP SL.STA(R1),#TS.GET ;WAITING FOR GET ? BNE 1$ MOV #TS.RUN,SL.STA(R1);IF SO PUT HIM BACK IN RUN 1$: RETURN .PAGE ; LOCAL SERVICE ROUTINES ; ; ; ; CL1HEL - PRINT HELLO MESSAGE ; CL1HEL: MOV #HELMES,R2 CALL OUT RETURN ; CL1BYE: MOV #BYEMES,R2 CALL OUT RETURN ; ; HELMES: .ASCII /CLONE / VER$ .ASCII / CONNECTED/<0> ; BYEMES: .ASCII /CLONE DISCONNECTED/<0> .EVEN ; ; ; ; ; DISAST - DISABLE/ENABLE AST RECOGNITION CO-ROUTINES ; ; THE ROUTINE(S) ACT AS COROUTINES TO DISABLE ; AND RE-ENABLE AST RECOGNITION DURING LIST OPERATIONS ; ; THE C CONDITION CODE IS PRESERVED THROUGH A RETURN WHICH ; RE-ENABLES ASTS. ; DISAST::DSAR$S ;INHIBIT ASTS BCS 1$ ;THEY ALREADY WERE MOV (SP),-(SP) ;PUSH UP RETURN ADDRESS MOV #ENAST,2(SP) ;SET RETURN THROUGH ENABLE 1$: RETURN ; ENAST: MOV #0,-(SP) ;LOCATION TO SAVE C BIT BCC 1$ DEC (SP) ;FLAG C SET 1$: ENAR$S ;RE-ENABLE ASTS ROL (SP)+ ;POP C FLAG BACK INTO CARRY RETURN ; ; ; ABORT - THIS ROUTINE IS CALLED WHEN SOMETHING SCREWS UP TOTALY ; IT ATTEMPTS TO PRINT USEFUL STATUS INFORMATION AND EXITS. ; ; ABORT:: MOV #ABOMES,R2 CALL OUT CALL TRACE CALL CPOINT EXIT$S ; ABOMES: .ASCIZ /CLONE -- ABORTED/ .EVEN .END CLONE