TITLE CPNSER - SECOND PROCESSOR CONTROL V1317 SUBTTL M. CHURCH - LNS/MIT P. HURLEY - DEC/JMF/TW/CDO/GMU 01 JUL 80 SEARCH F,S $RELOC $HIGH ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED ; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978,1979,1982 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS. XP VCP1SR,1317 ;VERSION NUMBER FOR LOADER STORAGE MAP CPNSER::ENTRY CPNSER ;LOAD IF SPECIFIED BY COMMON ;ROUTINE TO SETUP THE SUBQUEUE SCHEDULING SCAN TABLE FOR CPU1 ; CALLED ONCE EVERY SCDINT TICKS BY SCHED1 SCDSS1::ILDB T1,SSPNT1## ;GET NEXT PRIMARY SUBQUEUE MOVEI T4,SSSCN1## ;ADDRESS OF SCHEDULING SCAN TABLE PJRST SCDSST## ;LET SCHED1 DO THE WORK ;SUBROUTINE TO INSURE THAT A JOB IS ON CPU0 ;CALLING SEQUENCE: ; PUSHJ P,ONCPU0 ;ALWAYS RETURNS CPOPJ ON CPU0 ONCPU0::PUSH P,T1 ;SAVE CALLERS T1 PUSH P,T2 ;SAVE ANOTHER MOVE T2,.CPJOB## ;GET CURRENT JOB MOVSI T1,(SP.ROP) ;RUN ONLY ON POLICY CPU IORM T1,JBTSPS##(T2) ;LIGHT FOR BECOM0 FIXUPS MOVE T1,BOOTCP## ;GET CURRENT POLICY CPU PUSHJ P,ONCPUN ;GET ON CORRECT CPU, NOT RUNNABLE ANYWHERE ELSE JRST TTPOPJ## ;RETURN WHEN ON CPUN ;ROUTINE TO GET ON CPU OWNING A TERMINAL ;U POINTS TO LDB ONCPUL::LDB T1,LDPCPU## ;GET THE NUMBER OF THE OWNING CPU PJRST ONCPUN ;GET ON THAT CPU ;ROUTINE TO GET ON CPUN BUT FAIL IF CPU IS NOT RUNNING ;CALLED FROM UUO'S LIKE PERF. AND DTE. ; T1 = CPU NUMBER ; PUSHJ P,ONCPUS ; HERE IF CPU IS NOT RUNNING ( OR GOING AWAY ) ; HERE WHEN ON CPUN ONCPUS::PUSH P,T1 ;SAVE CPU NUMBER LSH T1,.CPSOF## ;OFFSET FROM CPU0 CDB SKIPL .C0RUN##(T1) ;CPU MARKED TO GO AWAY SKIPLE .C0OK##(T1) ;OR ALREADY DEAD JRST TPOPJ## ;YES, FAIL RETURN POP P,T1 ;RESTORE CPU NUMBER AOS (P) ;GIVE GOOD RETURN ;FALL INTO ONCPUN ;CALLED TO REQUEUE CURRENT JOB TO CPUN (UUO LEVEL CALL ONLY) ;T1=NUMBER OF DESIRED CPU ONCPUN::PUSHJ P,SETCPN ;MAKE RUNNABLE ONLY ON THE RIGHT CPU CAMN T1,.CPCPN## ;ARE WE ON THE RIGHT CPU? POPJ P, ;YES, RETURN PUSH P,.UPMP+.UPMUP ;SAVE UUO PC MOVEM 17,.JDAT+JOBD17## ;SAVE ACS MOVEI 17,.JDAT+JOBDAC## BLT 17,.JDAT+JOBD16## MOVE J,.CPJOB## ;SET SO WILL RESCHEDULE TO RIGHT CPU MOVE T1,[XC.UOU##,,ONCPU1] MOVEM T1,.CPPC## JRST CLKSPD## ;RESCHED TO RIGHT CPU ;HERE ON CPU N ONCPU1: POP P,.UPMP+.UPMUP ;RESTORE UUO PC POPJ P, ;AND CONTINUE, ON CORRECT CPU SUBTTL MULTIPROCESSING I/O CONTROL ;SUBROUTINE TO CHECK IF ON THE RIGHT CPU FOR IO ;RETURNS DEYCPF-BYTE IN T1 ;RETURNS T4 NEGATIVE IF NOT DUAL-PORTED ;PRESERVES T2,T3 CHKCP:: CHKCPI::LDB T1,DEYCPF## ;GET NUMBER OF 1ST CPU OWNING DEVICE HLRO T4,DEVCPU(F) ;DUAL PORTED DEVICE TRNE T4,DEPCPS ; ON 2 CPUS? LDB T4,DEYCPS## ;YES, GET 2ND CPU WHICH OWNS DEVICE CAIN T1,7 ;DEVICE ON GENERIC BOOT CPU MOVE T1,BOOTCP## ;YES, GET CPU NUMBER CAME T1,.CPCPN## ;ARE WE ON THE RIGHT CPU? CAMN T4,.CPCPN## AOS (P) ;YES, SKIP RETURN POPJ P, ;TELL CALLER IF WE ARE OK SETCPN::PUSHJ P,SAVE1## ;SAVE P1 PUSH P,J ;SAVE J MOVE J,.CPJOB## MOVEI P1,SP.CP0 ;RIGHTMOST BIT IS CPU0 (=1) LSH P1,(T1) ;POSITION BIT FOR RIGHT CPU TRC P1,SP.CPA ;NOT RUNNABLE FOR ALL OTHER CPUS DPB P1,MPYNRN## ;NOT RUNNABLE ON ALL BUT CPU N JRST JPOPJ## ;RETURN ;ROUTINES TO KEEP THE NUMBER OF BUFFERS SWEPT FOR, AND THOSE WE CAN DO, CORRECT IFN FTKL10,< ;SUBROUTINE TO SAVE THE VITAL INFORMATION ABOUT BUFFERS IN THE DDB ;CALLED BY THE FILLER, CHECKED BY THE EMPTIER STONBF::LDB T1,PJOBN## ;JOB NUMBER MOVE T1,JBTST3##(T1) ;CPU JOB LAST RAN ON LDB T2,[POINT 1,S,^L] ;IF A SWEEP IS IN PROGRESS TRNE S,IOACT ; IT MIGHT BE PAST USERS BUFFER. SINCE CONSO APR,LP.CSB+LP.CSD ; WE DON"T SWEEP AGAIN IF IOACT IS ON, SETZ T2, ; REQUIRE 1 MORE SWEEP FOR OUTPUT ADD T2,.CPCSN##-.CPCDB##(T1) ;SWEEP SERIAL NUMBER SYSPIF MOVEM T2,DEVCSN(F) ;SAVE IN DDB MOVE T2,.CPCPN##-.CPCDB##(T1) ;CPU JOB LAST RAN ON DPB T2,DEYCPU## ;SAVE IN DDB JRST ONPOPJ ;SUBROUTINE TO CHECK THAT WE CAN HAVE THE BUFFERS ;UPDATES LH(DEVNBF) TO REFLECT ALL THE BUFFERS WHICH HAVE BEEN SWEPT FOR ;PRESERVES T2 CKNBF:: PUSHJ P,CHKCP ;IF WE ARE ON THE CPU WHICH OWNS THE DEVICE JRST CHKNB JUMPL T4,ADDNBF ;OK IF NOT ON 2 CPUS TLNN S,IO JRST CHKNB LDB T1,DEYPCL## ;CPU WHICH STARTED IO CAIN T1,7 ;7 IS A SUBSTITUTE FOR 0 MOVEI T1,0 TRNE S,IOACT CAMN T1,.CPCPN## JRST ADDNBF ; THEN ALL BUFFERS ARE USABLE ;PRESERVES T3,T2 CHKNB:: SYSPIF LDB T1,DEYCPU## ;CPU JOB STARTED IO ON LDB T4,PJOBN## ;IF NOT WHERE JOB NOW IS, MOVE T4,JBTST3##(T4) CAME T1,.CPCPN##-.CPCDB##(T4) JRST ADDNB1 ; WE HAVE SWEPT, SO ADD TO LH LSH T1,.CPSOF## MOVE T1,.C0CSN##(T1) ;CURRENT SWEEP SERIAL NUMBER ON THAT CPU CAMG T1,DEVCSN(F) ;IF THEY ARE THE SAME JRST ONPOPJ ; THAT CPU HASN'T SWEPT, CAN'T HAVE EXTRA BUFFERS JRST ADDNB1 ;SUBROUTINE TO UPDATE THE LH(DEVNBF) AND CLEAR THE RH ;PRESERVES T2,T3 ADDNBF: SYSPIF ADDNB1: HRRZ T1,DEVNBF(F) ;NUMBER OF BUFFERS TO UPDATE BY JUMPE T1,ONPOPJ ;GO IF NOTHING TO ADD MOVN T4,T1 ;SET TO CLEAR RH HRLI T4,-1(T1) ;OVERFLOW FROM RH WILL GET THE LAST ONE ADDM T4,DEVNBF(F) ;UPDATE DEVNBF JRST ONPOPJ ;AND RETURN >;END FTKL10 ;SUBROUTINE TO GET JOB ON RIGHT CPU FOR FILE OPERATION ;CALL WITH F = DDB ;PRESERVES T1,T4(I KNOW..) SETCPF::PUSHJ P,SAVT## ;SAVE CALLERS LDB T1,DEYPCL## ;IF QUEUED PROTOCOL JUMPN T1,CPOPJ## ; IT CAN RUN ON ANY CPU SETCF1::PUSHJ P,CHKCPI CAIA MOVE T1,.CPCPN## PUSHJ P,ONCPUS ;GET ON CORRECT CPU CAIA ;CPU NOT RUNNING POPJ P, ;RETURN WHEN ON CPUN MOVSI T1,DVOFLN ;NO, GET OFFLINE BIT IORM T1,DEVCHR(F) ;LIGHT IN DDB PUSHJ P,CPUOFS ;GET OFFSET TO CPU'S CDB MOVSI T2,100000 ;CPU DETACHED BIT TDNN T2,.C0RUN##(T1) ;IS THIS CPU DETACHED JRST [PUSHJ P,HNGSTP## ;COMPLAIN TO USER AND OPERATOR JRST SETCF1] ;AND TRY ALL OVER AGAIN PUSHJ P,RTNEVM## ;RETURN EVM IFN FTPI,< MOVEI T4,'IDC' ;"IO TO DETACHED CPU" CODE PUSHJ P,PSIJBI## ;SEE IF USER WANTS THE TRAP JRST [TRO S,IOIMPM!IODERR!IODTER!IOBKTL ;YES, GET ERROR BITS PUSHJ P,CLRACT## ;FOR ANY CORRECTION THE USER MAY WANT JRST ERRGOU##] ;TAKE OFF WITH THE TRAP > ;END FTPI JRST CPUZAP ;USER DOESN'T WANT TRAP, ZAP HIM ;SUBROUTINE TO RING THE DOORBELL SETQPB::PUSHJ P,CPUOFS ;GET RIGHT CPU MOVE T1,.C0QPC##(T1) ;DOORBELL BITS FOR ALL OTHER CPUS IORM T1,DOORBL## ;RING RING POPJ P, ;ROUTINE TO RETURN THE OFFSET FROM CPU0 CDB TO THE CURRENT CPU CDB CPUOFS::LDB T1,DEYCPF## ;CPU OWNING THE DEVICE LSH T1,.CPSOF## ;MULTIPLY BY LENGTH OF CDB (OLY WORKS FOR POWER OF TWO) POPJ P, ;RETURN ;CODE CALLED FROM USRXIT TO SEE IF MUST RESCHEDULE UXITMP::SKIPGE .CPRUN## ;CAN THIS CPU RUN JOBS PJRST DPXST ;NO, MUST RESCHEDULE MOVEI T1,SP.CR0 ;BIT FOR CAN RUN ON CPU0 LSH T1,@.CPCPN## ;POSITION FOR CPU PROCESSING UUO TDNE T1,JBTSPS##(J) ;CAN JOB CONTINUE TO RUN HERE AOS (P) ;YES HE CAN, SKIP RETURN ;FALL INTO "DPXST" ;HERE FROM COMCON, RUN UUO, AND TO CLEAR SP.NR0 AT END OF A UUO DPXST:: MOVSI T1,(SP.NRA!SP.ROP) ANDCAM T1,JBTSPS##(J) POPJ P, ;ROUTINE TO CHECK IF JOB CAN RUN ON EITHER OR BOTH CPUS ;CALL: MOVE J,JOB NUMBER ; PUSHJ P,CHKCPU ; JOB IS SET TO RUN ONLY CPU1 ; JOB WAS SET TO RUN ON ALL CPUS OR LOCKED ON A CPU - T1=CPU ;CALLED BY TRPSET AND RTTRP CHKCPU::MOVE T1,.CPCPN## PUSHJ P,CPLCK ;ONLY ON THIS CPU CAIA JRST CPOPJ1## MOVE T1,JBTSPS##(J) ;JOB CAN RUN BITS IN SECOND CPU STATUS TRNN T1,SP.CR0 ;CAN JOB RUN ON CPU0 POPJ P, ;NO, RETURN ON CPU1 ONLY MOVEI T1,SP.CRA-SP.CR0 ;CLEAR CAN RUN ON CPU1 ANDCAM T1,JBTSPS##(J) ;SO WILL ONLY RUN ON CPU0 SETZ T1, JRST CPOPJ1## ;RETURN ON CPU0 ONLY ;SUBROUTINE TO SEE IF A JOB IS LOCKED ON THE CURRENT CPU CPLCK:: PUSHJ P,SAVE1## MOVEI P1,SP.CR0 ;POSITION A BIT LSH P1,@.CPCPN ; FOR THE CURRENT CPU TRC P1,SP.CRA ;ALL BITS EXCEPT FOR OUR CPU TDNN P1,JBTSPS##(J) ;IF ALL BITS ARE OFF AOS (P) ; IT CAN RUN ONLY ON THIS CPU POPJ P, ;HERE FROM COMCON TO TEST IF JOB ON SLAVE, BEFORE DOING CONTROL C SPSTOP::PUSHJ P,LOKSCD ;TURN ON INTERLOCK MOVSI T2,(SP.CC1) ;SET THE CONTROL C BIT SO SLAVE CANNOT RUN JOB IORM T2,JBTSPS##(J) ;AVOID SLAVE PICKING JOB UP BEFORE IT IS STOPPED MOVSI T2,(SP.CJ0) ;TEST IF JOB IS CURRENT JOB ON SLAVE PROCESSOR LSH T2,@BOOTCP## ;POSITION BIT FOR BOOT CPU TLC T2,(SP.CJA) ;WANT TO ASK IF CURRENT JOB ON ANY OTHER PROCESSOR TDNN T2,JBTSPS##(J) AOS (P) ;NO, SKIP RETURN AND DONT DELAY COMMAND JRST ULKSCD ;TURN OFF INTERLOCK ;HERE TO CLEAR MULTIPROCESSOR STATUS BITS CLRJSP::PUSH P,T2 ;SAVE A WORKING AC MOVSI T2,(SP.CC1) ;CLEAR LEFT HALF ERROR BITS ANDCAM T2,JBTSPS##(J) JRST T2POPJ## ;RESTORE T2 AND RETURN ;ROUTINE TO SET INITIAL CONDITIONS FOR CPU RUNNABILITY ;CALLED FROM CLOCK1 - CLRJBT SETJSP::MOVEI T1,SP.SCA+SP.CPA ;MAKE JOB RUNNABLE ON ALL CPU'S MOVEM T1,JBTSPS##(J) POPJ P, ;AND RETURN ;SUB TO MAKE JOB RUNNABLE ON ALL CPUS ;CLEARING BITS IN LH OF JBTSPS(CALLED FROM COMCON ON KJOB SO LOGOUT CAN RUN ; NO MATER WHAT CPU SPECIFICATION USER MAY HAVE CHANGED TO) ALLJSP::SKIPA T1,ALCPUS ;MAKE JOB RUNABLE ON ALL CPUS ; SKIP INTO CRESET ;SUBROUTINE TO RETURN CPU SPECIFICATION TO THAT SET ;BY LAST "SET CPU" COMMAND. CALLED FROM "RESET" IN UUOCON CRESET::LDB T1,[POINT 6,JBTSPS##(J),29] ;GET LAST COMMAND SET SPECIFICATION DPB T1,[POINT 6,JBTSPS##(J),35] ;OVERRIDE LAST SETUUO ALCPUS: POPJ P,B29+SP.CPA ;CAN RUN ON CPU0 AND 1 ;ROUTINE TO CLEAR CONTROL C TYPED BIT ;CALLED FROM CLOCK1-WHEN JOB CAN BE STOPPED CLRCCB::MOVSI T1,(SP.CC1) ;THIS ROUTINE IS CALLED TO CLEAR SP.CC1 BIT ANDCAM T1,JBTSPS##(J) ;CONTROL C TYPED, SO DON'T RUN ON CPU1. POPJ P, ;AND RETURN ;HERE FROM ANYDEV TO MAKE IT LOOK LIKE JOB HAS ACTIVE DEVICES ;IF JOB IS CURRENTLY BEING RUN ON THE SLAVE PROCESSOR ANYRUN::PUSHJ P,SAVE2## ;SAVE A COUPLE OF WORKING REGS MOVEI P1,.C0CDB## ;START WITH CPU0'S CDB ANYRN: PUSHJ P,LOKSCD ;TURN ON INTERLOCK ANYRN1: CAMN P1,.CPSLF## ;SKIP CALLING CPU JRST ANYRN2 ;STEP TO NEXT IFN FTTRPSET,< CAMN J,.CPSTS##-.CPCDB##(P1) ;STOPPING TIMESHARING FOR THIS JOB JRST ULKSCD ;YES, GO ULKSCD AND POPJ RETURN > MOVE P2,.CPJOB##-.CPCDB##(P1) ;GET JOB CURRENTLY ON THIS CPU CAILE J,JOBMAX## ;CALLER WANT JOB OR SEGMENT NUMBER HRRZ P2,JBTSGN##(P2) ;GET HIGH SEGMENT NUMBER FOR THAT JOB CAIN P2,(J) ;IS JOB RUNNING OR USING SAME SEGMENT JRST ULKSCD ;YES, GIVE NO SWAP RETURN ANYRN2: HLRZ P1,.CPCDB##-.CPCDB##(P1) ;STEP TO NEXT CDB IN SYSTEM JUMPN P1,ANYRN1 ;AND CONTINUE LOOKING AOS (P) ;OK TO SWAP THIS JOB JRST ULKSCD ;UNLOCK SCHEDULER AND RETURN SUBTTL MULTIPROCESSING OPR/USER FAILING CPU INTERFACE ;HERE ON BOOT CPU FROM CLOCK1 ONCE A MINUTE TO CHECK IF OTHER CPU'S ARE RUNNING ;IF CPUN IS NOT RUNNING, TYPE OUT APPROPRIATE MESSAGES TO OPERATOR/USER CP1CHK::PUSHJ P,CPRMIN ;CHECK TO SEE IF ALL JOBS HAVE RUNNABLE SPECIFICATIONS PUSHJ P,SAVE1## ;SAVE P1 MOVEI P1,.C0CDB## ;ADDRESS OF CPU0'S CDB (START THERE) CP1CH1: SKIPLE .CPOK##-.CPCDB##(P1) ;THIS CPU OK? SKIPGE T1,.CPRUN##-.CPCDB##(P1) ;NO, SHOULD IT BE COUNTING ITS OK WORD? JRST CP1CH6 ;EITHER RUNNING OR SHOULDN'D BE, TRECK ON TLNE T1,40000 JRST CP1CH6 HRRZ U,OPRLDB## ;ADDRESS OF THE OPR LDB MOVEI T1,[ASCIZ /% %Problem on /] ;TEXT FOR COMPLAINT PUSHJ P,CONMES## ;GO TELL THE OPR THAT THE CPU DIED MOVE T2,.CPLOG##-.CPCDB##(P1) ;LOGICAL NAME OF THE DEAD CPU PUSHJ P,PRNAME## ;TELL THE OPERATOR THAT MOVEI T1,[ASCIZ/ serial # /] ;TEXT PUSHJ P,CONMES## ;EXPLAINATION OF THE NEXT NUMBER MOVE T1,.CPASN##-.CPCDB##(P1) ;DEAD CPU'S SERIAL NUMBER PUSHJ P,RADX10## ;TELL THE OPERATOR THAT SINCE IT MAY NOT BE OBVIOUS PUSHJ P,PCRLF## ;COMPLETE THE LINE IFN FTKL10,< MOVE J,HIGHJB## ;HIGHEST JOB ON THE SYSTEM CP1CH2: PUSHJ P,RWRTCH ;JOB RIGHT WITH RESPECT TO THE CACHE ON THE DEAD CPU? JRST CP1CH4 ;YES, IT CAN STILL RUN CAMN J,MMUSER## ;OWN THE MM RESOURCE? JRST CP1CH3 ;YES, THAT WOULD HANG THE SYSTEM SO WARN THE OPR >;END IFN FTKL10 IFN FTKI10,< SKIPN J,.CPJOB##-.CPCDB##(P1) ;JOB ON THE DEAD CPU JRST CP1CH4 ;OK IF NO JOB IS RUNNING ON THE DEAD CPU CAMN J,MMUSER## ;DOES THE JOB OWN THE MM RESOURCE? JRST CP1CH3 ;YES, TELL THE OPR ABOUT THE PROBLEM >;END IFN FTKI10 PUSHJ P,FLSDR## ;DOES THE JOB OWN A RESOURCE? JRST CP1CH4 ;NO, JOB DOESN'T JEOPARDIZE THE SYSTEM CP1CH3: MOVEI T1,[ASCIZ /(system will do no useful work until /] PUSHJ P,CONMES## ;EXPLAIN THE PROBLEM TO THE OPERATOR MOVE T2,.CPLOG##-.CPCDB##(P1) ;SICK CPU'S NAME PUSHJ P,PRNAME## ;TELL THE OPR AGAIN MOVEI T1,[ASCIZ / is restarted at 400 or DETACHed) /] PUSHJ P,CONMES## ;TELL THE OPR HOW TO GET IT GOING AGAIN IFN FTKL10,< JRST CP1CH5 ;OPR HAS BEEN TOLD, DON'T COMPLAIN AGAIN ABOUT THIS CPU >;END IFN FTKL10 CP1CH4: IFN FTKL10,< SOJG J,CP1CH2 ;LOOP OVER ALL CPUS >;END IFN FTKL10 CP1CH5: MOVE T1,STATES## ;CURRENT STATES SETTING TRNE T1,ST.NOP ;IS THERE AN OPERATOR IN ATTENDANCE? PUSHJ P,[PUSHJ P,FRCSET## ;SETUP TO A TYPE A COMMAND ON FRCLIN PUSHJ P,INLMES## ;DETACH CPUN ASCIZ /Detach / MOVE T2,.CPLOG##-.CPCDB##(P1) ;CPUN PUSHJ P,PRNAME## ;ADD THAT TO THE COMMAND PJRST PCRLF##] ;END THE COMMAND WITH A BREAK CP1CH6: HLRZ P1,.CPCDB##-.CPCDB##(P1) ;NEXT CPU'S CDB ADDRESS JUMPN P1,CP1CH1 ;LOOP IF THERE IS YET ANOTHER CPU POPJ P, ;RETURN ;SUBROUTINE TO CHECK IF THIS JOB IS RUNNABLE W.R.T. THE CACHE ON THE ; CPU WHOSE CDB IS IN P1 ;CALLING SEQUENCE: ; MOVEI P1,CDB OF THE CPU IN QUESTION ; MOVE J,JOB NUMBER OF JOB IN QUESTION ; PUSHJ P,RWRTCH ; OK TO RUN ON OTHER CPUS ; RUNNABLE ONLY W.R.T. P1 CPUS CACHE ; IFN FTKL10,< RWRTCH: HRRZ T3,JBTST3##(J) ;CDB OF LAST CPU JOB RAN ON SKIPE JBTADR##(J) ;RUNNABLE ON ALL CPUS IF SWAPPED CAME T3,P1 ;DID JOB LAST RUN ON CPU IN QUESTION? POPJ P, ;NO, JOB IS RUNNABLE W.R.T. P1 CPUS CACHE MOVE T4,.CPCSN##-.CPCDB##(P1) ;CACHE SWEEP SERIAL NUMBER FOR P1 CPU CAMLE T4,JBTCSN##(J) ;DID P1 CPU SWEEP SINCE THE LAST TIME IT RAN THIS JOB? CAMN J,.CPJOB##-.CPCDB##(P1) ;CURRENT JOB ON DEAD CPU? AOS (P) ;NO, ONLY RUNNABLE W.R.T. P1 CPUS CACHE POPJ P, ;RETURN > ;ROUTINE TO FIND NEXT STR WHICH CAN NO LONGER BE ACCESSED BECAUSE OF ; A DEAD CPU ;CALLING SEQUENCE: ; MOVEI P1,CDB OF THE DEAD CPU ; PUSHJ P,DEDSTR ; HERE IF NONE (LEFT) ; HERE IF ONE FOUND, T1=STR NAME DEDSTR: MOVE T4,STRAOB## ;POINTER TO TABSTR DEDST1: SKIPN T2,TABSTR##(T4) ;NEXT STR DATA BLOCK JRST DEDST4 ;THAT ENTRY IS ZERO HLRZ T2,STRUNI##(T2) ;FIRST UNIT IN THE FILE STR DEDST2: PUSHJ P,DEDUN ;SEE IF UNIT CAN STILL BE ACCESSED JRST DEDST3 ;YES, ALL IS WELL SO FAR MOVE T1,@TABSTR##(T4);FILE STRUCTURE NAME JRST CPOPJ1## ;FILE STRUCTURE CANNOT BE ACCESSED DEDST3: HLRZ T2,UNISTR##(T2) ;NEXT UNIT JUMPN T2,DEDST2 ;CHECK IT IF THERE IS ONE DEDST4: AOBJN T4,DEDST1 ;NEXT FILE STRUCTURE POPJ P, ;ALL HAVE BEEN REMOVED ;SUBROUTINE TO SEE IF THERE IS STILL A PATH TO A UNIT AFTER A CPU HAS ; DIED ;CALLING SEQUENCE: ; MOVEI P1,CDB OF THE CPU IN QUESTION ; MOVE T2,ADDRESS OF UDB FOR UNIT IN QUESTION ; PUSHJ P,DEDUNI ; RETURNS HERE IF UNIT CAN STILL BE ACCESSED ; HERE IF NO PATH TO THE UNIT ;RETURNS T2 = UDB ;DEDUN PRESERVES T4 DEDUN: DEDUNI: MOVE T1,UNIKON##(T2) ;KONTROLLER LDB T1,KOXCPU## ;CPU THIS KONTROLLER IS ON IFN FTDUAL,< SKIPE T3,UNI2ND##(T2) ;SECOND PORT, IS THERE ONE? SKIPA T3,UNIKON##(T3) ;YES, GET KDB SKIPA T3,T1 ;NO, GET CPU NUMBER FROM ONLY PORT LDB T3,KOZCPU## ;SECOND PORT CPU NUMBER CAMN T3,.CPCPN##-.CPCDB##(P1) ;STILL GET AT THE SECONDARY PORT? > CAME T1,.CPCPN##-.CPCDB##(P1) ;OR AT THE PRIMARY PORT? POPJ P, ;UNIT CAN BE REACHED JRST CPOPJ1## ;NO PATH TO THE UNIT ;HERE TO ATTACH A CPU CPUATT::LSH T1,.CPSOF## ;OFFSET TO CPU CDB ADDI T1,.C0CDB## ;ADDRESS OF CDB MOVSI T2,100000 ;CPU'S DETACHED BIT TDNN T2,.CPRUN##-.CPCDB##(T1) ;IS THE CPU DETACHED? JRST COMERA## ;NO, ERROR TLO T2,400000 ;ALLOW JOBS ANDCAM T2,.CPRUN##-.CPCDB##(T1) ;ALLOW THE CPU TO START HRLI T1,.CSCAT ;CODE FOR ATTACH PJRST CPUCSC ;LOG ATTACH AND RETURN ;HERE TO DETACH A CPU CPUDET::MOVE P1,T1 ;CPU NUMBER TO P1 LSH P1,.CPSOF## ;CDB OFFSET ADDI P1,.C0CDB## ;ADDRESS OF THE CDB SKIPG .CPOK##-.CPCDB##(P1) ;IS THE CPU CURRENTLY RUNNING? JRST COMERA## ;YES, CANNOT DETACH A RUNNING CPU MOVSI T1,500000 ;CPU'S DETACHED BIT IORM T1,.CPRUN##-.CPCDB##(P1) ;INDICATE CPU IS DETACHED PUSH P,J ;SAVE JOB NUMBER MOVEI T1,(P1) ;CDB ADDRESS TO T1 HRLI T1,.CSCDT ;CODE FOR DETACH PUSHJ P,CPUCSC ;LOG DETACH IFN FTKL10,< MOVE J,HIGHJB## ;HIGHEST JOB ON THE SYSTEM CPUDE1: PUSHJ P,RWRTCH ;JOB RUNNABLE W.R.T. THE CACHE ON THE DEAD CPU? CAIA ;YES > IFN FTKI10,< SKIPE J,.CPJOB##-.CPCDB##(P1) ;CURRENT JOB ON THE DEAD CPU > PUSHJ P,CPUZAP ;NO, ZAP THE JOB IFN FTKL10,< SOJG J,CPUDE1 ;LOOP OVER ALL JOBS > ;END FTKL10 POP P,J ;RESTORE JOB NUMBER OF JOB DOING THE COMMAMD SETZM .CPJOB##-.CPCDB##(P1) ;ZERO CURRENT JOB ON DEAD CPU PUSH P,F ;SAVE TTY DDB HLRZ F,HNGLST## ;START OF DEVICE CHAIN CPUD1A: LDB T1,DEYCPF## ;CPU OWNING THIS DEVICE MOVE S,DEVIOS(F) ;I/O STATUS CAMN T1,.CPCPN##-.CPCDB##(P1) ;DEVICE ON CPU BEING DETACHED? TRNN S,IOACT ;YES, WAS I/O ACTIVE WHEN CPU STOPPED? JRST CPUD1B ;NO, LOOK AT NEXT DEVICE PUSHJ P,DEVERR## ;CLEAR IOACT/SET TROUBLE CPUD1B: HLRZ F,DEVSER(F) ;NEXT DEVICE JUMPN F,CPUD1A ;LOOP IF THERE IS ONE POP P,F ;RESTORE F MOVE S,P1 ;SAVE CDB ADDRESS JSP T2,SAVCTD## ;MUST BE AT UUO LEVEL TO REMOVE FILE STRUCTURES MOVE P1,S ;GET CDB ADDRESS BACK ;HERE TO REMOVE FILE STRUCTURES WHICH ARE INACCESSIBLE CPUDE2: PUSHJ P,DEDSTR ;SEE IF THERE ARE ANY FILE STRS WHICH CANNOT BE ACCESSED JRST CPUDE3 ;NONE OR FINISHED PUSHJ P,RMVSTR## ;REMOVE THE INACCESSIBLE FILE STRUCTURE JFCL ;MIGHT NOT SKIP JRST CPUDE2 ;NEXT STR ;HERE TO SEE THAT SWAPPING SPACE IS NOT ALLOCATED ON INACCESSIBLE UNITS CPUDE3: MOVEI T4,0 ;START AT FIRST ENTRY IN SWPTAB PUSHJ P,SAVE4## ;DODELE CLOBBERS P ACS CPUDE4: MOVE P1,-4(P) ;CPU NUMBER SINCE DODELE MAY HAVE BEEN CALLED SKIPE T2,SWPTAB##(T4) ;NEXT UNIT IN THE ACTIVE SWAPPING LIST PUSHJ P,DEDUN ;STILL ABLE TO GET AT THIS UNIT? JRST CPUDE5 ;YES, LOOP ON MOVEI P2,-1 ;+ INFINITY MOVE U,T2 ;UNIT PUSH P,T4 ;DON'T COUNT ON DODELE PRESERRVING T4 PUSHJ P,[PUSHJ P,GGVMM ;OBTAIN MM INTERLOCK JRST DODELE##] ;REMOVE DORMANT SEGMENTS FROM UNREACHABLE UNIT JFCL ;SHOULD NEVER SKIP POP P,T4 MOVN T1,UNIFKS##(T2) ;FREE SWAPPING SPACE ON THIS UNIT ADDM T1,UNIFKS##(T2) ;ZAP, NO FREE SPACE ADDM T1,VIRTAL## ;AND DECREMENT TOTAL AMOUNT OF FREE SPACE AVAILABLE CPUDE5: CAIGE T4,SWPMAX## ;LOOKED AT ALL THE UNITS IN THE A.S.L.? AOJA T4,CPUDE4 ;NO, LOOK AT THE NEXT UNIT HRRZ U,OPRLDB## ;OPR'S LDB MOVE T2,.CPLOG##-.CPCDB##(P1) ;CPU'S NAME PUSHJ P,PRNAME## ;TELL THE OPR WHAT CPU PJSP T1,CONMES## ; WAS DETACHED ASCIZ / Detached / ;SUBROUTINE TO ZAP THE CURRENT JOB ON A DEAD CPU, OR TO ZAP A JOB WHICH ; ATTEMPTS TO DO I/O TO A DEVICE ON A DEAD CPU, OR TO ZAP A JOB WHICH ; MIGHT HAVE DATA IN THE DEAD CPU'S CACHE ;CALLING SEQUENCE: ; MOVE J,JOB NUMBER ; PUSHJ P,CPUZAP ; ALWAYS RETURN HERE CPUZAP: PUSHJ P,SVEUB## ;MAKE SURE THE JOB IS ADDRESSABLE PUSHJ P,GIVRSC## ;GIVE UP ANY RESOURCES THE JOB MAY OWN PUSHJ P,ZAPUSC## ;RELEASE ALL DEVICES PUSHJ P,CLRJOB## ;CLEAR JOBJDA MOVSI T1,(SP.CJ0) ;CURRENT JOB ON CPU0 BIT LSH T1,@.CPCPN##-.CPCDB##(P1) ;POSITION IT TO DEAD CPU TLO T1,(SP.NRA!SP.ROP) ;CLEAR NOT RUNNABLE BITS TOO ANDCAM T1,JBTSPS(J) ;CLEAR CURRENT JOB ON DEAD CPU BIT IFN FTKL10,< PUSHJ P,CLCSN ;CLEAR SWEEP SERIAL NUMBER SO JOB ISN'T STUCK > JSP T1,ERRPNT## ;INFORM THE USER ASCIZ /CPU failed/ PJRST PCSTOP## ;TELL THE USER THE PC AND STOP THE JOB ;SUBROUTINE TO MAKE A DAEMON ENTRY FOR CPU ATTACH/DETACH. ;CALLING SEQUENCE: ; MOVE T1,[CODE,,CDB ADDRESS ; PUSHJ P,CPUCSC ; ALWAYS RETURN HERE CPUCSC: PUSH P,U ;SAVE U PUSH P,F ; AND F MOVEI F,0 ;NO DDB ADDRESS FOR THIS ERROR MOVEI U,.CPLOG##-.CPCDB##(T1) ;U POINTS AT CPU NAME HRRI T1,.ERCSC ;ERROR CODE FOR DAEMON PUSHJ P,DAEEIM## ;NOTIFY DAEMON JRST FUPOPJ## ;RESTORE F AND U AND RETURN SUBTTL INTERLOCK ROUTINES ;INTERLOCK ROUTINES - LOKSCD, ULKSCD ;CALLED BY PUSHJ TO ENTER CODE WHICH MUST RUN TO COMPLETION ;ON THE CURRENT PROCESSOR BEFORE IT (OR ANY INTERLOCKED ;SECTIONS) IS ENTERED BY THE OTHER PROCESSOR. ; ; PUSHJ P,LOKSCD ; ...INTERLOCKED CODE... ; PUSHJ P,ULKSCD ; ;THERE IN FACT CAN EXIST SEVERAL LEVELS OF INTERLOCK, OF WHICH ;ONLY THE LOWEST LEVEL IS REAL, REST ARE VIRTUAL. NECESSARY ;BECAUSE OF THE EXISTENCE OF ROUTINES WHICH MUST THEMSELVES ;BE INTERLOCKED BUT WHICH ARE CALLED BOTH BY INTERLOCKED CODE ;AND UN-INTERLOCKED CODE. (EXAMPLE: QQXFER) ;THE LOCATIONS .C0SCD,.C1SCD SHOULD BE INITIALIZED TO -1 ;AT SYSTEM STARTUP TIME. LOKSCD::AOSE .CPSCD## ;BUMP LEVEL OF INTERLOCK POPJ P, ;JUST NESTING, STILL HAVE INTERLOCK LOKSC1: AOSE SCDLOK## ;GET SYSTEM INTERLOCK AOSA .CPLLC## ;COUNT INTERFERENCE AOSA .CPRSI## ;GOT IT, FILL IN CPU ID JRST LOKSC1 ;TRY AGAIN IFN FTKI10,< CONI PAG,INOSCD## > IFN FTKL10,< APRID INOSCD## > POPJ P, ;RETURN WITH INTERLOCK ;ROUTINE TO LOKSCD, DISPATCH, ULKSCD, AND RETURN. ; CALLED FROM ANY ROUTINE WHICH IS CALLED BY A PUSHJ ; AND EXPECTS TO RETURN WITH POPJ OR AOS (P), POPJ. SBSCD:: PUSHJ P,LOKSCD ;TURN ON INTERLOCK PUSHJ P,@(P) ;DISPATCH TO ROUTINE CAIA AOS -1(P) ;PROVIDE FOR SKIP RETURN POP P,(P) ;FIX PUSHDOWN TO RETURN TO ORIGINAL CALLER ULKSCD::PUSH P,T1 ;SAVE AN AC SOSL T1,.CPSCD## ;DECREMENT LEVEL JRST TPOPJ## ;STILL NESTED ON THIS CPU, RETURN EXCH T1,SCDLOK## ;RELEASE SYSTEM INTERLOCK SETOM INOSCD## ;TELL THE WORLD WE DON'T OWN IT JUMPGE T1,TPOPJ## ;ALL IS WELL IF INTERLOCK TAKEN STOPCD TPOPJ##,DEBUG,SAU, ;++SCHEDULER ALREADY UNLOCKED ;ROUTINE TO ATTEMPT TO OBTAIN THE CORE ALLOCATION RESOURCE ; IN SCHEDULAR CONTEXT ;N.B. MUST OWN THE SCHEDULAR INTERLOCK WHEN CALLING SCDMM ;CALLING SEQUENCE: ; PUSHJ P,GETMM ; RETURNS HERE IF RESOURCE IS NOT CURRENTLY AVAILABLE ; RETURNS HERE, CALLER OWNS THE RESOURCE ;NOTE, THE CALLER MUST TAKE RESPONSIBILITY FOR TRYING AGAIN ; LATER (DLYCOM, SWAPPER, ETC.) IF THE RESOURCE IS NOT CURRENTLY ; AVAILABLE. ANY ROUTINE WHICH OBTAINS THE LOCK BY CALLING GETMM ; MUST GIVE IT UP BY CALLING GIVMM GETMM:: PUSHJ P,SBSCD ;CALL COROUTINE TO GET THE SCHEDULER INTERLOCK ;HERE IF SCHEDULER INTERLOCK IS ALREADY OWNED SCDMM:: AOSE MMREQ## ;SEE IF THE RESOURCE IS AVAILABLE SKIPE MMAVAL## ;OR AVAILABLE, DIDN'T GIVE IT TO A JOB ; WAITING FOR IT BECAUSE IT WAS BEING SWAPPED, ETC. AOSA (P) ;AVAILABLE, SET FOR RESOURCE AVAILABLE RETURN JRST SCDMM1 ;NOT NOW, UNDO THE AOS SETZM MMAVAL## ;MAKE SURE THE SCHEDULAR DOESN'T GIVE IT ; TO A UUO LEVEL WAITER UNTIL WE GIVE IT UP ;MUST HAVE THE SCHEDULAR INTERLOCK TO DO THIS IFN FTKL10,< PUSH P,CORTAL## ;CURRENT VALUE OF CORTAL POP P,SAVCTL## ;SAVE IT TO DETERMINE IF A SWEEP IS NECESSARY ; WHEN THE MM IS GIVEN UP APRID INTLMO## ;NOTE THAT THIS CPU IS THE OWNER > IFN FTKI10,< CONI PAG,INTLMO## ;SERIAL NUMBER OF THE OWNING CPU > POPJ P, ;RETURN WITH THE LOCK SCDMM1: SOS MMREQ## ;UNDO THE AOS POPJ P, ;GIVE RESOURCE NOT AVAILABLE RETURN ;SUBROUTINE TO GIVE UP THE MM RESOURCE WHEN IT WAS OBTAINED BY ; CALLING GETMM ;CALLING SEQUENCE: ; PUSHJ P,GIVMM ; ALWAYS RETURNS HERE GIVMM:: SETOM INTLMO## ;MARK THE FACT THAT THIS CPU NO LONGER OWNS IT PJRST DWNMM ;RETURN THE RESOURCE AND RETURN ;SUBROUTINE TO SEE IF THE CURRENT JOB OWNS THE MM RESOURCE. CPOPJ IF NOT, CPOPJ1 IF SO MMOWN:: PUSH P,J ;SAVE J MOVE J,INTLMO## ;OWNER OF THE MM RESOURCE IF OWNED BY A CPU IFN FTKI10,< LSH J,-^D26 ;ISOLATE THE SERIAL NUMBER > IFN FTKL10,< ANDI J,7777 ;ISOLATE THE SERIAL NUMBER > CAMN J,.CPASN## ;OWN THE RESOURCE AT INTERRUPT LEVEL? JRST JPOPJ1## ;YES, GIVE OWNED RETURN MOVE J,.CPJOB## ;CURRENT JOB CAMN J,MMUSER## ;OWN THE MEMORY MANAGEMENT RESOURCE? JRST JPOPJ1## ;YES JRST JPOPJ## ;NO ;SUBROUTINE TO SEE IF A JOB OWNS THE MM RESOURCE AND GIVE IT UP IF ; THIS ROUTINE REMEMBERS THAT IT WAS OWNED AND A MATCHING CALL TO ; UIFMM MUST FOLLOW IT DIFMM:: PUSHJ P,MMOWN ;OWN THE MM RESOURCE? POPJ P, ;NO PUSH P,T1 ;YES MOVSI T1,(UP.MMO) ;JOB OWNED THE MM BIT IORM T1,.UPMP+.UPBTS ;REMEMBER THAT PUSHJ P,DWNMM ;GIVE IT UP JRST TPOPJ## ;RESTORE T1 AND RETURN ;SUBROUTINE TO GET BACK THE MM RESOURCE IF A JOB OWNED IT WHEN DIFMM ; WAS CALLED UIFMM:: PUSH P,T1 ;SAVE T1 MOVSI T1,(UP.MMO) ;JOB OWNED THE MM RESOURCE BIT TDNE T1,.UPMP+.UPBTS ;DID THE JOB OWN IT? PUSHJ P,UPMM ;YES, GET IT BACK ANDCAM T1,.UPMP+.UPBTS ;CLEAR THE BIT JRST TPOPJ## ;AND RETURN ;COROUTINE TO SAVE AND RESTORE THE STATE OF THE MM RESOURCE REMMM:: PUSHJ P,DIFMM ;SAVE STATE OF MM, FREE IT IF OWNED POP P,(P) ;POP CALLER'S RETURN PC PUSHJ P,@1(P) ;RETURN TO CALLER CAIA ;NON- SKIP AOS (P) ;SKIP JRST UIFMM ;RESTORE IT IF OWNED ;COROUTINE TO GET THE MM RESOURCE AND GIVE IT UP ON RETURN GGVMM:: PUSHJ P,UPMM ;GET THE MM RESOURCE POP P,(P) ;POP CALLER'S RETURN PC PUSHJ P,@1(P) ;RETURN TO CALLER CAIA ;NON-SKIP AOS (P) ;SKIP PJRST DWNMM ;GIVE UP THE MM RESOURCE ;SUBROUTINE TO GET THE MM RESOURCE AND WORRY ABOUT CACHE IF PAGES ; ARE DEALLOCATED UPMM:: PUSH P,F ;SAVE F SETZ F, ;SO SRWAIT DOESN'T WORRY ABOUT EVM PUSHJ P,MMWAIT## ;GET THE MM RESOURCE IFN FTKL10,< MOVE F,CORTAL## ;CURRENT NUMBER OF FREE OR FREEABLE PAGES MOVEM F,SAVCTL## ;REMEMBER TO SEE IF CORE WAS DEALLOCATED > JRST FPOPJ## ;RESTORE F AND RETURN ;SUBROUTINE TO GIVE UP THE MM IF OWNED TGVMM::PUSHJ P,MMOWN ;OWN THE MM? POPJ P, ;NO, NOOP ;FALL INTO DWNMM ;SUBROUTINE TO GIVE UP THE MM RESOURCE AND SWEEP THE CACHE IF CORE ; HAS BEEN DEALLOCATED (NECESSARY SINCE WRITTEN BITS MAY BE ON IN DEALLOCATED PAGES) DWNMM:: PUSH P,F ;SAVE F IFN FTKL10,< MOVE F,CORTAL## ;CURRENT CORTAL PUSHJ P,MLSCSH ;IS THE LOW SEGMENT UNCACHED CAMG F,SAVCTL## ;HAS CORTAL INCREASED SINCE CALL TO UPMM? (DEALLOCATION) JRST DWNMM1 ;NO, OR LAST CPU, DON'T BOTHER WITH SWEEP AOS .CPSDA## ;YES, COUNT THE NUMBER OF SWEEPS REQUIRED BY DEALLOCATION PUSHJ P,CSDMP## ;SWEEP - MUST DO IT WHILE STILL OWNING THE MM DWNMM1:> SETZ F, ;ZERO F (NO EVM) PUSHJ P,MMFREE## ;RETURN THE MM JRST FPOPJ## ;RESTORE F AND RETURN ;THIS ROUTINE IMPLEMENTS A SYSTEM WIDE INTERLOCK. IT IS EXACTLY ; SYNONUMOUS TO TURNING THE PI SYSTEM OFF ON A SINGLE PROCESSOR SYSTEM ; EXCEPT IT DOES NOT ALLOW NESTING, I.E., A CALL TO UNLSPI MUST BE ; EXECUTED BEFORE LOKSPI CAN BE CALLED AGAIN. LOKSPI::CONO PI,PI.OFF ;NO PIS CONI PI,.CPPIS## ;READ CURRENT STATE OF CHANNEL ENABLES CONO PI,PI.ON+SYSOFF## ;TURN THE PI SYSTEM ON, ; LEAVING OFF CHANNELS WHICH OBTAIN THE INTERLOCK AOSE INTRLK## ;INTERLOCK AVAILABLE? JRST .-1 ;NO, WAIT UNTIL IT IS IFN FTKI10,< CONI PAG,INTOLK## ;SERIAL NUMBER OF THE CPU WHICH OWNS THE INTERLOCK > IFN FTKL10,< APRID INTOLK## ;SERIAL NUMBER OF OWNING CPU > POPJ P, ;RETURN WITH THE INTERLOCK ;THIS ROUTINE RETURNS THE SYSTEM WIDE INTERLOCK AND EXITS WITH THE PI ; SYSTEM TURNED OFF UNLSPT::EXCH T1,.CPPIS## ;SAVE T1, GET STATE OF THE PI WHEN INTERLOCK WAS OBTAINED ANDI T1,177 ;ISOLATE CHANNEL ENABLES TRO T1,PI.OFF ;EXIT WITH PI OFF JRST UNLSP1 ;JOIN COMMON CODE ;COMMON EXIT ROUTINE TO RETURN SYSTEM WIDE INTERLOCK AND POPJ ONPOPJ:: ;FALL INTO UNLSPI ; SYSPIN ; POPJ P, ;ROUTINE TO GIVE UP THE SYSTEM WIDE INTERLOCK, RESTORE THE CHANNELS WHICH ; WERE ENABLED WHEN THE INTERLOCK WAS OBTAINED, AND EXIT WITH THE PI IN ; THE STATE IT WAS IN WHEN THE INTERLOCK WAS OBTAINED - ON IF ON/OFF IF OFF UNLSPI::EXCH T1,.CPPIS## ;SAVE T1, GET STATE OF THE PI WHEN INTERLOCK WAS OBTAINED ANDI T1,177 ;ISOLATE CHANNEL ENABLES UNLSP1: TRO T1,PI.TNP ;TURN ON SELECTED CHANNELS EXCH T1,.CPPIS## ;RESTORE T1, SET TO RESTORE PI SYSTEM SETOM INTRLK## ;RELINQUISH INTERLOCK SETOM INTOLK## ;NO LONGER THE OWNER OF THE INTERLOCK CONO PI,@.CPPIS## ;RESTORE THE PI SYSTEM POPJ P, ;AND RETURN ;ROUTINE TO INTERLOCK ON A DEVICE TO ENSURE THAT THE USER PROGRAM USING ; THE DEVICE IS NOT RUNNING AT UUO LEVEL ON ONE PROCESSOR "PIOFF" WHILE AN ; INTERRUPT FROM THE DEVICE IS BEING SERVICED ON ANOTHER PROCESSOR. ; THIS CAN NOT HAPPEN ON A SINGLE CPU BECAUSE OF CONO PI,PI.OFF. ; THE INTERLOCK IS ONLY BETWEEN UUO LEVEL AND THE INTERRUPT LEVEL WHICH ; THE DEVICE INTERRUPTS TO. THE INTERLOCK IS ONLY ON THE CHANNEL THAT THE DEVICE ; INTERRUPTS ON, I.E., IF A PROCESSOR IS WAITING AT AN INTERUPT LEVEL ; FOR AN INTERLOCK OWNED BY SOME OTHER PROCESSOR AT UUO LEVEL, INTERRUPTS ; AT HIGHER PI LEVELS ON THE WAITING PROCESSOR CAN STILL BE SERVICED. LOKDPI::CONO PI,PI.OFF ;TURN THE PI SYSTEM OFF CONI PI,.CPDPI## ;READ PI CHANNEL ENABLES CONO PI,PI.ON+SYSOFF## ;TURN PI ON WITH DEVICE CHANNELS OFF AOSE @DEVCPU(F) ;DDB INTERLOCK AVAILABLE? JRST .-1 ;NO, WAIT FOR IT PUSH P,T1 ;SAVE A TEMPORARY HRRZ T1,DEVCPU(F) ;ADDRESS OF THIS DDB'S INTERLOCK WORD SUBI T1,INTL0## ;OFFSET INTO INTERLOCKS IFN FTKI10,< CONI PAG,INTO0##(T1) ;OWNING PROCESSOR'S SERIAL NUMBER > IFN FTKL10,< APRID INTO0##(T1) ;REMEMBER WHICH CPU OWNS THE INTERLOCK > JRST TPOPJ## ;RESTORE T1 AND RETURN ;COMMON EXIT ROUTINE TO RETURN DEVICE PI INTERLOCK ; AND RETURN WITH PI RESTORED ONPOPD:: ;FALL INTO UNLDPI ; PION ; POPJ P, ;ROUTINE TO RETURN THE DEVICE INTERLOCK, MARK IT AS UNOWNED, AND ; RESTORE THE PI SYSTEM TO THE STATE IT WAS IN WHEN THE DVEICE WAS ; LOCKED UNLDPI::PUSH P,T1 ;SAVE A WORKING AC MOVE T1,.CPDPI## ;CHANNEL ENABLES WHEN INTERLOCK WAS OBTAINED ANDI T1,177 ;ONLY CHANNEL ENABLES TRO T1,PI.TNP ;TURN ON SELECTED CHANNELS MOVEM T1,.CPDPI## ;FOR CONO HRRZ T1,DEVCPU(F) ;ADDRESS OF THIS DDB'S INTERLOCK WORD SUBI T1,INTL0## ;OFFSET INTO INTERLOCK TABLES SETOM INTL0##(T1) ;RETURN THE DDB INTERLOCK SETOM INTO0##(T1) ;AND INDICATE NO LONGER OWNED BY THIS CPU CONO PI,@.CPDPI## ;RESTORE SELECTED PI CHANNELS JRST TPOPJ## ;RESTORE TEMPORARY AND RETURN ;THIS ROUTINE IMPLEMENTS AN INTERLOCK FOR BIT DIDDLERS (SETOS,CLRBTS). ; IT IS SIMILAR TO LOKSPI AND LOKDPI. LOKBTI::CONO PI,PI.OFF ;NO PIS CONI PI,.CPBTI## ;READ CURRENT STATE OF CHANNEL ENABLES CONO PI,PI.ON+SYSOFF## ;TURN THE PI SYSTEM ON AOSE INTLBT## ;INTERLOCK AVAILABLE? JRST .-1 ;NO, WAIT UNTIL IT IS IFN FTKI10,< CONI PAG,INTOBT## ;SERIAL NUMBER OF THE CPU WHICH OWNS THE INTERLOCK > IFN FTKL10,< APRID INTOBT## ;SERIAL NUMBER OF OWNING CPU > POPJ P, ;RETURN WITH THE INTERLOCK ;COMMON EXIT ROUTINE TO RETURN BIT DIDDLER INTERLOCK AND POPJ ONPOPB:: ;FALL INTO UNLBTI ; BTSON ; POPJ P, ;ROUTINE TO GIVE UP THE BIT DIDDLER INTERLOCK AND RESTORE THE PI CHANNELS UNLBTI::EXCH T1,.CPBTI## ;SAVE T1, GET STATE OF THE PI WHEN INTERLOCK WAS OBTAINED ANDI T1,177 ;ISOLATE CHANNEL ENABLES TRO T1,PI.TNP ;TURN ON SELECTED CHANNELS EXCH T1,.CPBTI## ;RESTORE T1, SET TO RESTORE PI SYSTEM SETOM INTLBT## ;RELINQUISH INTERLOCK SETOM INTOBT## ;NO LONGER THE OWNER OF THE INTERLOCK CONO PI,@.CPBTI## ;RESTORE THE PI SYSTEM POPJ P, ;AND RETURN ;ROUTINES TO INTERLOCK/RELEASE SCNSER'S DATA LOKSCI::CONO PI,SCNPIF## AOSE SCNLOK## JRST .-1 IFN FTKL10, IFN FTKI10, POPJ P, UNLSCI::SETOM SCNLOK## SETOM INOSCN## CONO PI,SCNPIN## POPJ P, ;ROUTINES TO INTERLOCK/RELEASE NETSER'S DATA LOKNPI::CONO PI,NETPIF## AOSE NETLOK## JRST .-1 IFN FTKL10, IFN FTKI10, POPJ P, UNLNPI::SETOM NETLOK## SETOM INONET## CONO PI,NETPIN## POPJ P, SUBTTL MULTIPROCESSING SCHEDULING ;THIS ROUTINE IS CALLED AT THE BEGINNING OF SCHED (NXTJOB) ;TO PUT SCAN TABLE ADDRESS INTO AC DAT. THE MASTER PROCESSOR ;IS MADE TO SCAN PQ1,PQ2,PQ3 WHILE THE SLAVE PROCESSOR IS MADE ;TO SCAN PQ3,PQ2,PQ1. IN ADDITION, THIS ROUTINE IS USED ;TO DETERMINE WHETHER TO DO REGULAR SCHEDULING AT THIS TIME ;OR TO RUN EITHER (1) A JOB WHICH HAS STOPPED TIME SHARING ;OR (2) A JOB WHICH WAS RUNNING ON THE SLAVE PROCESSOR THAT ;MUST DO A UUO (PROBABLY FOR I/O) MSCHED:: IFN FTTRPSET,< SKIPE J,.CPSTS## ;DID ANYONE STOP TIME SHARING? JRST MRNBL1 ;YES, SEE IF HE IS RUNNABLE > MSCALL: PUSHJ P,SCHEDJ## ;DISPATCH TO SCHED CODE MSEL: MOVSI T1,(SP.CJ0) ;PICK UP RUN BIT FOR MASTER PROCESSOR LSH T1,@.CPCPN## ;POSITION FOR THIS PROCESSOR MOVE F,.CPJOB## ;GET LAST JOB NUMBER ANDCAM T1,JBTSPS##(F) ;TURN OFF RUNBIT FOR OLD JOB IORM T1,JBTSPS##(J) ;TURN ON RUNBIT FOR NEW JOB JUMPE J,CPOPJ## ;RETURN IF NULL JOB MOVEI T1,JS.SCN ;SET SCANNED BIT IORM T1,JBTST2##(J) ; FOR THE JOB POPJ P, ;AND RETURN ;TEST IF JOB WHICH STOPPED T/S IS RUNNABLE MRNBL1: MOVE T1,NRNMSK ;GET NON RUNNABLE MASK TDNN T1,JBTSTS##(J) ;IS JOB WAITING TO SHUFFLE,SWAP,EXPAND,LOCK,OR REQUE PUSHJ P,DXRUN ;SECOND STATUS WORD BITS OK? MOVEI J,0 ;JOB UNRUNNABLE, GO RUN NULL JOB JRST MSEL ;JOB RUNNABLE, GO TO IT IFN FTLOCK,< NRNMSK: XWD SWP+SHF+JXPN+JRQ+WTMASK,LOK > IFE FTLOCK,< NRNMSK: XWD SWP+SHF+JXPN+JRQ+WTMASK,0 > ;ROUTINE TO DETERMINE IF JOB IS RUNNABLE WITH RESPECT TO JBTSPS BITS ;CALLED FROM SCHED WHEN SCHED IS ENTERED BY ANY PROCESSOR ;SKIP RETURN IF JOB IS RUNNABLE DXRUN:: PUSH P,T1 ;SAVE WORKING REG PUSH P,T2 ;AND ANOTHER MOVEI T1,SP.CP0 ;BIT FOR CPU0 ( ** ALSO SP.CR0 ** ) LSH T1,@.CPCPN## ;MASK FOR THIS CPU'S BITS MOVE T2,T1 ;COPY POSITIVE MASK TRC T1,SP.CPA ;MAKE "ANYWHERE BUT THIS CPU" MASK LDB F,MPYNRN## ;GET JOBS NOT RUNNABLE BITS CAIN F,(T1) ;RUNNABLE ONLY HERE (CONTEXT SWITCHED TO THIS CPU) JRST DXRUN1 ;REALLY GOT TO RUN THIS JOB SKIPL .CPRUN## ;CAN CPU RUN ANY JOBS (SET RUN NO CPUN) TDNN T2,JBTSPS##(J) ;YES, DOES USER WANT THIS CPU (SET CPU COMMAND/UUO) JRST TTPOPJ## ;NO, CANNOT RUN THIS JOB DXRUN1: LSH T1,<^L-^L> ;POSITION MASK TRNN F,(T2) ;MARKED UNRUNNABLE HERE (SWITCHED AWAY) TDNE T1,JBTSPS##(J) ; OR CURRENTLY ON SOME OTHER CPU JRST TTPOPJ## ;YES, CANNOT RUN THIS JOB SKPCPU (1) ;CPU CHECK JRST DXRUN2 ;BOOT, OK TO RUN THIS JOB TRC T2,SP.CPA ;FLIP RUNNABLE MASK MOVSI T1,(SP.CC1) ;CONTROL C BIT CAIE F,(T2) ;MUST RUN UUO TO COMPLETION TDNN T1,JBTSPS##(J) ;NO, WAS ^C TYPED CAIA ;LOOK SOME MORE JRST TTPOPJ## ;DON'T RUN JOB CAMN J,SW0JOB## ;WANT TO SWAP THIS JOB? JRST DXRUN3 ;YES, DONT RUN IT THEN SKIPG F,JBTSGN##(J) ;GET HIGH SEG NO., SPY OR NONE? JRST DXRUN2 ;NO HIGH SEG OR SPY HI SEG - GIVE CAN RUN RETURN MOVE F,JBTSTS##(F) ;YES, HIGH SEG STATUS WORD (OR JOB 0'S) TLNN F,SWP!SHF!JXPN ;IS HIGH SEG BEING SHUFFLED, SWAPPED, OR EXPANDED? DXRUN2: AOSA -2(P) ;JOB IS RUNNABLE ON THIS CPU DXRUN3: MOVEM J,.CPPLT## ;FLAG POTENTIALLY LOST IF CAN'T RUN HIM ; BECAUSE OF MONITOR BIND JRST TTPOPJ## ;GIVE CANNOT RUN THIS JOB RETURN ;SUBROUTINE TO CHECK IF A JOB IS RUNNABLE ON CPU0 AND IF ; CPU0 IS RUNNING ; EXITS CPOPJ1 IF SO, CPOPJ IF NOT RUNNABLE ON CPU0 OR CPU0 NOT RUNNING ;PRESERVES ALL ACS EXCEPT T3 CP0RC:: MOVEI T3,SP.CR0 ;CAN RUN ON CPU0 BIT TDNE T3,JBTSPS##(J) ;CAN THE JOB RUN ON CPU0? SKIPGE .C0RUN## ;AND IS CPU0 RUNNING? POPJ P, ;CAN'T RUN ON CPU0 OR CPU0 NOT RUNNING JRST CPOPJ1## ;RETURN IFN FTKI10,< ;SUBROUTINE TO SEE MI PROG DIS MUST BE OFF ON CPU1 FOR ; THIS JOB TO USE ADDRESS BREAK ;ENTER WITH T4=IP.MID ;EXIT POPJ IF ADDRESS BREAK NOT AVAILABLE, CPOPJ1 IF OK ;PRESERVES T1,T2 CP1AC:: MOVEI T3,SP.CR1 ;CAN RUN ON CPU1 BIT TDNE T3,JBTSPS##(J) ;CAN THE JOB RUN ON CPU1? SKIPGE .C1RUN## ;AND IS CPU1 RUNNING? JRST CPOPJ1## ;NO, ADDRESS BREAK IS OK TDNN T4,.C1APR## ;IS MI PROG DIS SET? AOS (P) ;NO, OK POPJ P, ;RETURN >;END IFN FTKI10 ;SUBROUTINE TO SEE IF JOB # IN J IS ON ANY CPU ;CALL WITH: ; MOVEI J,JOB-TO-TEST ; PUSHJ P,ANYCPU ; RETURN HERE IF ON A CPU ; RETURN HERE IF NOT ON A CPU ANYCPU::MOVSI T2,(SP.CJA) ;CURRENT JOB ANYWHERE MASK TDNN T2,JBTSPS##(J) ;SEE IF JOB IN J IS ON THE OTHER CPU AOS (P) ;NOT--SKIP RETURN POPJ P, IFN FTLOCK,< ;SUBROUTINE TO COPY A PORTION OF THE USER'S MAP INTO ; ALL CPU'S MAPS ;CALLING SEQUENCE: ; MOVE T1,EXEC VIRTUAL PAGE NUMBER ; MOVE T2,NUMBER OF PAGES ; MOVE T3,USER VIRTUAL ADDRESS ; PUSHJ P,MAPUEC ; ALWAYS RETURN HERE MAPUEC::PUSHJ P,SAVE1## ;SAVE P1 MOVEI P1,.C0CDB## ;START AT CPU0'S CDB MAPUE1: CAME P1,.CPSLF## ;CURRENT CPU? IF SO, THE MAP IS ALREADY SET PUSHJ P,MAPCP ;COPY USER'S MAP TO CPU FOUND'S MAP HLRZ P1,.CPCDB##-.CPCDB##(P1) ;NEXT CPU'S CDB JUMPN P1,MAPUE1 ;DONE IF ALL CDB HAVE BEEN LOOKED AT POPJ P, ;RETURN MAPCP: PUSHJ P,SAVT## ;SAVE T ACCUMULATORS SO CAN CONTINUE ADD T1,.CPTOS##-.CPCDB##(P1) ;ADDRESS OF THE CURRENT CPUS MAP PJRST MAPUEI## ;GO COPY MAP TO MAP ;SUBROUTINE TO MAP A PAGE OF A JOB BEING LOCKED INTO ; ALL CPU'S MAPS ;CALLING SEQUENCE: ; MOVE P1,BYTE POINTER TO CPU'S MAP(P3) ; MOVE T3,CONTENTS OF UPMP MAP SLOT ; PUSHJ P,MAPUC ; ALWAYS RETURN HERE ;PRESERVES T1 MAPUC:: PUSHJ P,SAVE4## ;SAVE P1-P4 MOVEI P4,.C0CDB## ;START AT CPU0'S CDB MAPUC1: MOVE P3,.CPTOS##-.CPCDB##(P4) ;ADDRESS OF CURRENT CPU'S MAP DPB T3,P1 ;STORE MAP CONTENTS IN THAT CPUS EPT HLRZ P4,.CPCDB##-.CPCDB##(P4) ;NEXT CPU JUMPN P4,MAPUC1 ;LOOP OVER ALL CPUS POPJ P, ;AND RETURN > IFN FTMOFFL,< ;SUBROUTINE TO INSURE THAT ALL BUT THE BOOT CPU ARE IN THE ACS BEFORE ; CHANGING THE EXEC MAP. ;CALL: PUSHJ P,CP1STP ; RETURN HERE IF SOME OTHER PROCESSOR STILL RUNNING ; RETURN HERE IF ALL OTHERS IN THE ACS ;PRESERVES ALL ACS CP1STP::PUSHJ P,SAVE2## ;SAVE P1-P2 MOVEI P1,.C0CDB## ;START AT CPU0'S CDB MOVEI P2,SR.ACL ;GET "IN AC LOOP" BIT CP1ST1: CAME P1,.CPSLF## ;POINTING AT OURSELF? SKIPL .CPOK##-.CPCDB##(P1) ;NO, THIS CPU STILL RUNNING? JRST CP1ST2 ;NO, IT PASSES TDNN P2,.CPSBR##-.CPCDB##(P1) ;THIS CPU IN THE AC'S? POPJ P, ;NO CP1ST2: HLRZ P1,.CPCDB##-.CPCDB##(P1) ;GET ADDRESS OF NEXT CDB JUMPN P1,CP1ST1 ;LOOP IF MORE PJRST CPOPJ1## ;GIVE SKIP RETURN >;END IFN FTMOFFL SUBTTL MULTIPROCESSING KL10 CACHE CONTROL IFN FTKL10,< ;ROUTINE FOR SCHEDULER TO CHECK THE STATE OF THE CACHE FOR A JOB ; SKIP RETURN MEANS OK, NON-SKIP MEANS JOB IS NOT RUNNABLE ON THIS ; CPU BECAUSE OF CACHE. CALL IS: ; ; MOVE J, ; PUSHJ P,SCDCSH ; ; ; IF ERROR RETURN WAS GIVEN, .CPCLN IS INCREMENTED (# TIMES SCHEDULER ; COULD NOT RUN A JOB BECAUSE OF CACHE) AND .CPCLF IS SET TO THE JOB'S ; NUMBER (POTENTIALLY LOST TIME BECAUSE OF CACHE) SCDCSH::PUSHJ P,CHKCSH ;CHECK STATE OF CACHE JRST CPOPJ1## ;OK, RETURN AOS .CPCLN## ;NOT OK, SCHEDULER HAS TO IGNORE AGAIN MOVEM J,.CPCLF## ;IN CASE NOTHING ELSE IS RUNNABLE POPJ P, ;RETURN AND SAY RUN SOMEONE ELSE ;ROUTINE TO SET UP JBTST3 AND JBTCSN WITH CDB ADDRESS AND CURRENT ; SWEEP SERIAL NUMBER USING CDB IN P4. ; CALL: ; MOVE U, ; MOVE J, ; MOVE P4, ; PUSHJ P,SETCSN ; ; ;CALLED BY CLOCK1 AFTER COMPLETION OF CONTEXT SWITCHING FROM OLD JOB. ; NOT CALLED FOR CONTEXT SWITCH FROM NULL JOB ; MUST BE CALLED INSIDE CPU INTERLOCK ; ANY CACHE SWEEP DONE ON A CPU AFTER THIS ROUTINE IS CALLED ON ; THAT CPU WILL CAUSE JOB THAT THIS ROUTINE WAS CALLED FOR TO BE ; RUNNABLE W.R.T. CACHE ON ANOTHER CPU SETCSN::MOVE T1,.CPSLF## ;THIS CPUS CDB HRRM T1,JBTST3##(U) ;SETUP CDB ADDRESS CONSO APR,LP.CSB+LP.CSD ;SWEEP IN PROGRESS TDZA T1,T1 ;NO, NEXT ONE WILL MAKE JOB RUNNABLE MOVEI T1,1 ;YES, REQUIRE ONE MORE TO BE RUNNABLE ADD T1,.CPCSN## ;COMPUTE SWEEP SERIAL # MOVEM T1,JBTCSN##(U) ;SAVE FOR LATER USE BY SCHED1 POPJ P, ;RETURN ;ROUTINE TO CHECK THE STATE OF CACHE FOR A JOB, CALLED BY SWAPPER ; JUST BEFORE IT IS TO SWAP OUT A JOB OR SEGMENT. ; SKIP RETURN MEANS OK, NON-SKIP MEANS JOB IS NOT SWAPPABLE W.R.T. CACHE. ; CALL IS: ; ; MOVE J, ; PUSHJ P,SWPCSH ; ; ; ; IF ERROR RETURN IS GIVEN, .CPCSD IS INCREMENTED, WHICH IS THE ; NUMBER OF TIMES THE SWAPPER WAS DELAYED FROM SWAPPING A JOB OUT ; BECAUSE OF THE CACHE. SWPCSH::CAILE J,JOBMAX## ;IS THIS A LOWSEG? JRST CPOPJ1## HRRZ T3,JBTST3##(J) ;CDB ADDRESS OF CPU JOB LAST RAN ON JUMPE T3,CPOPJ1## ;CORE 0 IS ALWAYS OK CAMN T3,.CPSLF## ;LAST RUN HERE PUSHJ P,MLSCSH ;YES, DO WE NEED TO WORRY ABOUT THE CACHE PUSHJ P,CHKRCH ;DO THE REAL WORK JRST CPOPJ1## ;EVERY THING IS BEAUTIFUL ; (IN ITS OWN WAY) AOS .CPCSD## ;INCREMENT SWAPPER CACHE DELAY COUNT POPJ P, ;BECAUSE SWAPPER HAS BAD NEWS COMING ;ROUTINE TO CHECK THE STATE OF THE CACHE FOR A JOB ; CALLED ONLY BY SCDCSH, SWPCSH ; CALL: ; MOVE J, ; PUSHJ P,CHKCSH ; ;JOB IS RUNNABLE, SWAPPABLE W.R.T. CACHE ; ;CACHE MUST BE SWEPT ON ANOTHER CPU FOR THIS JOB ; ; SMASHES T3,T4 CHKCSH::HRRZ T3,JBTST3##(J) ;GET CDB ADDR OF LAST CPU JOB RAN ON JUMPE T3,CPOPJ## ;ZERO MEANS SOMEONE SPECIFICALLY GAVE ; THE OK NOT TO SWEEP CACHE CAMN T3,.CPSLF## ;WAS LAST CPU SAME AS THIS ONE? POPJ P, ;YES, ALL IS OK CHKRCH: MOVE T4,.CPCSN##-.CPCDB##(T3) ;NO, MUST CHECK CURRENT SWEEP NUMBER ON OLD CPU CAMLE T4,JBTCSN##(J) ; AGAINST SWEEP NUMBER ON OLD CPU WHEN JOB LEFT IT POPJ P, ;CURRENT SERIAL NUMBER IS LARGER, OLD CPU ; HAS SWEPT SO JOB IS RUNNABLE, SWAPPABLE ;JOB CANNOT BE RUN OR SWAPPED, SO PUT IN A REQUEST TO THE OLD CPU ; TO SWEEP ITS CACHE. MOVEM T4,.CPCSR##-.CPCDB##(T3) ;.CPCSN CAN NEVER BE LESS THAN JBTCSN, SO ; NOW WE KNOW THAT .CPCSN AND JBTCSN ARE EQUAL. ; OTHER CPU WILL SWEEP IF REQUEST IS EQUAL ; OR GREATER IN VALUE THAN CURRENT SWEEP NUMBER ; ON THAT CPU JRST CPOPJ1## ;INDICATE THAT JOB CANNOT BE DEALT ; WITH NOW. ;ROUTINE TO CLEAR JOB'S CACHE SWEEP SERIAL NUMBER DATA, INDICATING ; THAT NO SWEEP NEED BE DONE BEFORE THE JOB SWITCHES CPUS ; CALLED FROM KLSER, COMCON WHEN JOB THROWS AWAY OLD CORE IMAGE. ; CALL: ; MOVE J, ; PUSHJ P,CLCSN ; ; ; RESPECTS ALL ACS CLCSN:: CAIG J,JOBMAX## ;CHECK FOR HIGH SEGMENT NUMBER HLLZS JBTST3##(J) ;JUST CLEAR OUT CDB ADDRESS, MAKING ; JBTCSN ENTRY INVALID POPJ P, ;RETURN ;ROUTINE TO SERVICE CACHE SWEEP REQUEST. CALLED BY ; CLOCK1 BEFORE SCHEDULER IS CALLED SO THAT ; SWEEP REQUESTS CAN BE SERVICED BY ANOTHER CPU BEFORE IT ; ENTERS THE SCHEDULER. ; IF A SWEEP IS DONE, .CPCRN IS INCREMENTED CSREQS::MOVE T1,.CPCSR## ;GET REQUEST NUMBER CAMGE T1,.CPCSN## ;IS IT LESS THAN CURRENT SWEEP NUMBER? POPJ P, ;NO REQUESTED CACHE SWEEP THIS TICK AOS .CPCRN## ;NO, EQUAL(HAPPENS) OR GREATER (NEVER HAPPENS) ; INCREMENT COUNT OF SWEEPS DONE BY REQUEST ;FALL INTO "CTXSWP" CLRPGT (0) ;CLEAR HARDWARE PAGE TABLE AS WELL SINCE EXEC MAP ; MIGHT HAVE CHANGED AS WELL ;ROUTINE TO ANTICIPATE THE NEED FOR A CACHE SWEEP FOR ANOTHER CPU ; CALLED IN CLOCK1 AFTER OLD JOB'S CONTEXT IS SAVED (IF APPLICABLE) ; AND AFTER SETCSN IS CALLED SO THAT IF A CACHE SWEEP IS DONE IT ; WILL MAKE THE JOB IN QUESTION RUNNABLE ON ANOTHER CPU. ; NOTE THAT IT IS CALLED INSIDE INTERLOCK SO THAT MASTER CPU ; WILL NEVER HAVE TO REQUEST A CACHE SWEEP FOR A JOB THAT DID A ; MASTER UUO ON SLAVE BY GETTING TO SCHEDULER BEFORE CSHUUO IS ; CALLED BY SLAVE. ; A SWEEP IS DONE IF LAST JOB RUN WAS ON ; SLAVE CPU AND DID A UUO WHICH MUST BE EXECUTED ON MASTER. HOPEFULLY, ; THIS SAVES CPU0 FROM WAITING FOR CPU1 TO RUN NULL JOB (COULD BE A WHILE) ; OR SERVICING SWEEP REQUEST (COULD TAKE SEVERAL TICKS, SINCE ITS DONE AT ; PI 7 CTXSWP::PUSHJ P,MLSCSH SWPUA POPJ P, ;SUBROUTINE TO SEE IF MONITORS LOW SEGMENT IS CACHED MEANING WE ARE DOWN ; TO ONE PROCESSOR. ;RETURNS: CPOPJ IF NOT CACHED ; CPOPJ1 IF CACHED MLSCSH::PUSH P,T1 ;SAVE T1 MOVSI T1,(ST%LSC) ;LOW SEGMENT CACHED BIT TDNE T1,CNFST2## ;IS IT AOS -1(P) ;YES, GIVE SKIP RETURN JRST TPOPJ## ;RESTORE T1 AND RETURN ;SUBROUTINE TO CALL SETCSN WHEN THE JOB NUMBER ; IS IN J AND THE CONTENTS OF U IS UNKNOWN SETCSJ::PUSH P,U ;SAVE U MOVE U,J ;ARGUMENT FOR SETCSN PUSHJ P,SETCSN ;MAKE JOB UNRUNNABLE ON THE OTHER ; CPU UNTIL A SWEEP IS DONE PJRST UPOPJ## ;RESTORE U AND RETURN ;SUBROUTINE TO CAUSE HIGH SEGMENT PART OF ALL MAPS TO GET CHANGED WHEN UWP CHANGES ;CALLING SEQUENCE: ; MOVEI T1,PREVIOUS STATE OF UWP (0 IF OFF, 1 IF ON) ; PUSHJ P,CLRCSH ;ALWAYS RETURN HERE (CACHE BITS CLEARED OR SET AS APPROPRIATE) CLRCSH::MOVE J,.CPJOB## ;CURRENT JOB SKIPLE J,JBTSGN##(J) ;JOB HAVE A HIGH SEGMENT? TLNN J,SHRSEG ; AND IS IT SHARABLE? POPJ P, ;NO, NOTHING TO DO TLNN J,UWPOFF ;IS THE HIGH SEGMENT WRITE PROTECTED? JRST CLRCS2 ;YES, SEE IF ANY OTHER JOB HAS IT WRITE ENABLED JUMPE T1,CPOPJ## ;NOTHING TO DO IF NOTHING CHANGED MOVEI T1,SETNCH ;SUBROUTINE TO SET NO CACHE BITS PUSHJ P,HGHAPP## ;TURN ON NOCSH!REDOMP FOR ALL JOBS SHARING THIS SEGMENT PUSHJ P,SAVE2## ;SAVE P1,P2 FOR ANYRN CLRCS1: MOVEI P1,.C0CDB## ;FIRST CDB CLRCS3: MOVE J,.CPJOB## ;CURRENT JOB HRRZ J,JBTSGN##(J) ;JOB'S HIGH SEGMENT NUMBER PUSHJ P,ANYRN ;SEE IF ANY OTHER RUNNING JOB IS USING THAT SEGMENT CAIA ;YES, MUST WAIT POPJ P, ;NO, EVERYTHING IS OK MOVE T2,.CPJOB##-.CPCDB##(P1) ;JOB NUMBER USING IT MOVSI T1,REDOMP ;HAS THE MAP BEEN REDONE FOR THE CPU1 JOB? TDNN T1,JBTSGN##(T2) ; ... JRST [HLRZ P1,.CPCDB##-.CPCDB##(P1) ;NEXT CDB JUMPE P1,CPOPJ## ;ALL IS WELL JRST CLRCS3] ;CHECK NEXT CPU AS WELL MOVEI T1,1 ;NO, SLEEP A TIC MOVE J,.CPJOB## ;OUR JOB NUMBER PUSHJ P,SLEEP## ;WAIT A WHILE JRST CLRCS1 ;AND TRY AGAIN CLRCS2: JUMPN T1,CPOPJ## ;RETURN IF NOT CHANGING THE STATE OF UWP MOVEI T1,CHKUWP ;SUBROUTINE TO CHECK IF ANY OTHER JOB HAS UWPOFF SETZ T2, ;INITIALIZE FLAG SAYING NO JOBS FOUND PUSHJ P,HGHAPP## ;ANY OTHER JOB HAVE UWP OFF FOR THIS SEGMENT? JUMPL T2,CPOPJ## ;EXIT IF SOME JOB HAS UWP OFF MOVEI T1,CLRNCH ;CLEAR NOCSH FOR ALL JOBS SHARING THIS SEGMENT PJRST HGHAPP## ;CAUSE MAPS TO BE REDONE WITH CACHE ON SETNCH: MOVSI T1,NOCSH!REDOMP ;DON'T CACHE THE HIGH SEG, CAUSE MAP TO BE REDONE IORM T1,JBTSGN##(J) POPJ P, CHKUWP: MOVSI T1,UWPOFF ;IS USER WRITE PROTECT OFF? TDNE T1,JBTSGN##(J) SETO T2, ;YES, FLAG IT POPJ P, CLRNCH: MOVSI T1,NOCSH ;DON'T CACHE IT ANDCAM T1,JBTSGN##(J) ;CLEAR NO CACHE BIT MOVSI T1,REDOMP ;REDO THE MAP BIT IORM T1,JBTSGN##(J) ;CAUSE MAP TO BE REDONE WITH CACHE BITS ON POPJ P, ;SUBROUTINE TO CHECK TO SEE IF A JOB IS ATTACHING TO A SHARABLE ; WRITABLE HIGH SEGMENT CHKSWS::MOVE J,.CPJOB## ;CURRENT JOB SKIPLE J,JBTSGN##(J) ;JOB HAVE A REAL HIGH SEGMENT? TLNN J,SHRSEG ; AND IS IT SHARABLE? POPJ P, ;NO, NOTHING TO DO MOVEI T1,CHKUWP ;ROUTINE TO LOOK FOR UWPOFF SETZ T2, ;ASSUME IT ISN'T PUSHJ P,HGHAPP## ;SET IF ANY JOB HAS UWPOFF FOR THIS SEGMENT MOVE J,.CPJOB## ;JOB NUMBER MOVSI T1,NOCSH!REDOMP ;FORCE MAP TO BE REDONE UNCACHED SKIPE T2 ;SKIP IF NOT WRITABLE IORM T1,JBTSGN##(J) ;UNCACHE HIGH SEGMENT IN THIS JOB'S MAP POPJ P, ;AND RETURN ;SUBROUTINE TO UNCACHE A PAGE OF THE EXEC ADDRESS SPACE ON ALL CPU'S ; IN THE SYSTEM ;CALLING SEQUENCE: ; MOVE T2,BYTE POINTER TO EXEC MAP SLOT RELOCATED BY .CPTOS ; LDB T3,T2 ; TRZE T3,PM.CSH ;VERIFIY PAGE IS CACHED ; PUSHJ P,UNCACH ;ITS CACHED, UNCACHE IT ; ALWAYS RETURNS HERE, T3 INTACT ; UNCACH::PUSHJ P,SAVE4## ;SAVE WORKING ACS DMOVE P2,T2 ;SAVE ARGUMENTS MOVSI P1,(ST%LSC) ;LOW SEGMENT IS CACHED BIT TDNE P1,CNFST2## ;IS THE LOW SEGMENT CACHED? (ONLY ONE CPU RUNNING) JRST [ANDI P3,17777 ;ISOLATE PAGE NUMBER MOVSI P1,TNCSHB ;TEMPORARY UNCACHED BIT IORM P1,PAGTAB(P3) ;LITE IN CASE CPU GETS "ADDED" POPJ P,] ;RETURN, LEAVING CACHE ON FOR NOW PUSH P,T1 ;SAVE T1 PUSHJ P,FIXOTB ;FIXUP OUCHE TABLE SUB P2,.CPTOS## ;UNRELOCATE, RELOCATED DIFFERENTLY BELOW TLO P2,P4 ;BYTE POINTER INDEXED BY P4 MOVEI T1,UNCACC ;ROUTINE TO REALLY DO THE WORK PUSHJ P,CPUAPP## ;UNCACHE THE PAGE IN EVERY CPU'S MAP MOVE T3,P3 ;RESTORE MAP CONTENTS JRST TPOPJ## ;AND RETURN ;SUBROUTINE TO UNCACHE A PAGE IN EVERY CPU'S MAP UNCACC: MOVE P4,.CPTOS##-.CPCDB##(P1) ;ADDRESS OF THIS CPU'S EXEC MAP DPB P3,P2 ;STORE MAPPING IN THIS CPU'S MAP (PM.CSH OFF) MOVE P4,.CPCSN##-.CPCDB##(P1) ;CURRENT CACHE SWEEP SERIAL NUMBER ON THIS CPU ADDI P4,2 ;ONE MORE SWEEP AND IN CASE ONE COULD BE IN PROGRESS MOVEM P4,.CPCSR##-.CPCDB##(P1) ;REQUEST THAT CPU TO SWEEP UNCAC1: SKIPGE .CPOK##-.CPCDB##(P1) ;DON'T WORRY ABOUT CPUS THAT AREN'T RUNNING CAMGE P4,.CPCSN##-.CPCDB##(P1) ;HAS HE SWEPT YET? POPJ P, ;ITS MAP WILL BE FIXED WHEN IT GETS RESTARTED MOVEI T1,0 ;0 SLEEP TIME (1 TIC) PUSHJ P,SLEEPF## ;WAIT FOR HIM TO SWEEP JRST UNCAC1 ;NO, WAIT SOME MORE ;SUBROUTINE TO FIXUP OUCHTB WHEN TURNING OFF THE CACHE FOR SOME PAGE ; SO THAT OUCHE ALWAYS REFERENCES THROUGH FOUR CACHED PAGES FIXOTB: PUSHJ P,SAVE4## ;ONLY REASON THIS IS A SUBROUTINE IFE MONORG&1000,< MOVE P1,[POINT 18,.EPPM##-.EPMP##+/<2*1000>] > IFN MONORG&1000,< MOVE P1,[POINT 18,.EPPM##-.EPMP##+/<2*1000>,17] > ADD P1,.CPTOS## ;POINT AT THIS CPU'S MAP MOVEI P2,MONORG-PAGSIZ## ;STARTING VIRTUAL ADDRESS ANDI P3,17777 ;PAGE CACHE IS BEING TURNED OFF FOR MOVEI P4,4 ;NEED 4 CACHED PAGES FIXOT1: ADDI P2,PAGSIZ## ;NEXT VIRTUAL ADDRESS CAML P2,MONVFF## ;RUN OUT OF MONITOR PAGES? STOPCD CPOPJ##,JOB,N4C,;++NOT 4 CACHED PAGES ILDB T1,P1 ;NEXT PAGE TRNN T1,PM.CSH ;IS IT CACHED? JRST FIXOT1 ;NO, CAN'T USE IT ANDI T1,17777 ;JUST THE PHYSICAL PAGE NUMBER MOVE T2,PAGTAB(T1) ;PAGTAB ENTRY TLNN T2,TNCSHB ;DON'T USE THIS PAGE IF IT MIGHT GET UNCACHED CAIN T1,(P3) ;IS IT THE PAGE THATS BEING UNCACHED? JRST FIXOT1 ;YES, CAN'T USE THAT PAGE EITHER HRRM P2,OUCHTB##-1(P4) ;OUCHE CAN USE THIS VIRTUAL ADDRESS SOJG P4,FIXOT1 ;FIND A TOTAL OF 4 CACHED PAGES POPJ P, ;ALL DONE, RETURN ;ROUTINE TO HANDLE SETUUO #40 (.STCSB) ; SET/CLEAR CACHE BITS FOR TEMPORARILY UNCACHED PAGED SETCSB::PUSHJ P,SAVE2## ;SAVE P1,P2 MOVE P1,NCPRUN## ;NAME OF RUNNABLE CPU'S SOJG P1,CPOPJ## ;FAIL IF MORE THAN 1 HRRZ P1,.CPTOS## ;ADDRESS OF THE EPT MOVE T4,[POINT 18,.EPLM##-.EPMP##(P1)] MOVE P2,SYSSIZ## ;LAST ADDRESS LSH P2,W2PLSH## ;P2=# OF PAGES TO DO PUSHJ P,SETCS1 ;SET/CLEAR CACHE FOR THE LOW SEGMENT IFE .EPCDB&1000,< MOVE T4,[POINT 18,.EPMP##-.EPMP##+<.EPCDB/<2*1000>>(P1)] > IFN .EPCDB&1000,< MOVE T4,[POINT 18,.EPMP##-.EPMP##+<.EPCDB/<2*1000>>(P1),17] > MOVE P2,MONVFF## ;LAST LOCATION OF DATA BEYOND HIGH SEGMENT SUBI P2,.EPCDB ;NUMBER OF WORDS ALLOCATED LSH P2,W2PLSH## ;CONVERT TO PAGES OF MONITOR HIGHSEG PUSHJ P,SETCS1 ;CLEAR/SET CACHE BITS FOR LDB'S, ETC... CLRPGT (0) ;LET HARDWARE SEE CHANGES MOVSI T1,(ST%LSC) ;LOW SEGMENT IS CACHED BIT TRNN T2,1 ;SETTING CACHE ON OR OFF SKIPA T2,[ANDCAM T1,CNFST2##] ;OFF, SET TO CLEAR BIT MOVE T2,[IORM T1,CNFST2##] ;ON, SET TO LIGHT BIT PUSHJ P,CSDMP## ;ALWAYS SWEEP THE CACHE XCT T2 ;SET/CLEAR BIT IN STATES PUSHJ P,FIXOTB ;MAKE SURE "OUCHE" WORKS JRST CPOPJ1## ;GIVE GOOD RETURN TO UUO SETCS1: ILDB T3,T4 ;GET MAP ENTRY JUMPE T3,SETCS2 ;IGNORE IF NOT MAPPED HRRZ T1,T3 ;GET PHYSICAL PAGE # ANDI T1,17777 ;ISOLATE PAGE NUMBER MOVE T1,PAGTAB(T1) ;GET BITS FOR PAGE TLNN T1,TNCSHB ;PAGE TEMPORARILY UNCACHED JRST SETCS2 ;NO, LEAVE IT ALONE TRNN T2,1 ;WANT CACHE ON OR OFF TRZA T3,PM.CSH ;OFF, CLEAR BIT TRO T3,PM.CSH ;ON, SET IT DPB T3,T4 ;PUT ENTRY BACK IN MAP SETCS2: SOJG P2,SETCS1 ;TRY NEXT PAGE POPJ P, ;RETURN >;END IFN FTKL10 SUBTTL MULTIPROCESSING STOPCD PROCESSING ;ROUTINE TO WAIT FOR ANOTHER CPU TO FINISH PROCESSING A STOPCD. CALLED ;FROM APR INTERRUPT LEVEL ON EACH PROCESSOR IF DIELOK GOES POSITIVE. ;WAITS FOR ONE OF THE FOLLOWING EVENTS: ; 1. DIELOK GOES NEGATIVE ; 2. CRSHWD GOES NON-ZERO (GO DIRECTLY TO REBOOT IN THIS CASE) ; 3. DIELOK STAYS POSITIVE TOO LONG (CPU DIED IN DIE) ;CALL: PUSHJ P,CHKDIE ; CHKDIE::CONO PI,PI.OFF ;TURN OFF THE PI SYSTEM JSR .CPSVA## ;SAVE ALL AC SETS PUSHJ P,SAVT## ;SAVE T1-T4 PUSHJ P,RCDSTB## ;READ CPU AND DEVICE STATUS BLOCKS HRROS .CPSBR## ;INTERLOCK CALL AT REBOOT IFN FTKL10,< PUSHJ P,CSDMP## ;DUMP CACHE PUSHJ P,CHKDI1 ;CALL ROUTINE TO DO THE WORK JRST CHKDI5 ;AND EXIT CHKDI1: PUSHJ P,SVPPC## ;SAVE PROTOCOL, ENTER SECONDARY > CHKDI2: MOVE T1,[^D25000000] ;WAIT THIS LONG FOR INTERLOCK TO CLEAR ;(ABOUT 45 SECONDS ON A MODEL B KL) CHKDI3: SKIPE CRSHWD## ;RELOADING SYSTEM BECAUSE OF STOPCD? PJRST REBOOT## ;YES SKIPGE DIELOK## ;CPU FINISHED WITH STOPCD YET? JRST CHKDI4 ;YES SOJG T1,CHKDI3 ;NO, COUNT DOWN AND LOOP SETOM INODIE## ;TOO LONG, BREAK INTERLOCK SETOM DIELOK## ;... JRST CHKDI2 ;INSURE THAT ANOTHER WASN'T WAITING CHKDI4: HRRZS .CPSBR## ;LET STATUS BLOCKS BE READ AGAIN IFN FTKL10,< POPJ P, CHKDI5: > CONO PI,PI.ON ;TURN ON PI SYSTEM AGAIN POPJ P, ;AND RETURN ;ROUTINE TO SEE IF WE ARE THE LAST CPU RUNNING IN A MULTIPROCESSOR ;SYSTEM. ;CALL: PUSHJ P,LSTCPU ; ; ;PRESERVES ALL BUT T1 LSTCPU::MOVEI T1,.C0CDB## ;START AT CPU0 CDB LSTCP1: CAMN T1,.CPSLF## ;IS THIS ME? JRST LSTCP2 ;YES, DOESN'T COUNT SKIPGE .CPOK##-.CPCDB##(T1) ;THIS CPU STILL RUNNING? POPJ P, ;YES, AT LEAST ONE STILL RUNNING LSTCP2: HLRZ T1,.CPCDB##-.CPCDB##(T1) ;GET ADDRESS OF NEXT CDB JUMPN T1,LSTCP1 ;LOOP IF MORE JRST CPOPJ1## ;WE ARE THE ONLY ONE LEFT $LIT SUBTTL INITIALIZATION AND CRASH PROCEDURES FOR CPUN ;NON-BOOT PROCESSOR INITIALIZATION. JRST HERE FROM 400 STARTUP. $LOW ;THIS CODE MUST BE IN THE LOW SEGMENT SINCE ; THE HIGH SEGMENT ISN'T ADDRESSABLE UNTIL ;CPU1'S MAP IS SETUP FROM CPU0'S MAP SPRINI::CONO PI,CLRPIS## ;CLEAR PI AND PARITY ERROR FLAG CONO APR,AP1RST## ;RESET EVERYTHING AND ENABLE CLOCK IFN FTKL10,< EXECAC ;MAKE SURE AC BLOCKS ARE OK > MOVSI P,300000 ;"CPU IS DOWN" OR "DETACHED" BITS TDNE P,.CPRUN## ;CAN THIS CPU RUN YET JRST .-1 ;NO, WAIT UNTIL IT CAN MOVE P,.CPNPD## ;SET UP PUSH DOWN POINTER IFN FTKL10,< MOVE T1,.CPCPN## PUSHJ P,DTEINI## PUSHJ P,ENTSPC## ;ENTER SECONDARY PROTOCOL >;END IFN FTKL10 PUSHJ P,PRTCPU ;TELL OPR WHO WE ARE MOVSI T1,40000 ;SUPPENDED BIT TDNE T1,.CPRUN## ;RESTART AFTER REBOOT RATHER THAT START OR RESTART? JRST SPRIN1 ;YES, DON'T WAIT FOR A BOOT CPU TO COME TO LIFE MOVE 14,[XWD ACLOOP,2] ;LOAD AC'S WITH WAIT LOOP BLT 14,14 ;CPU1 WILL WAIT UNTIL CPU0 IS GOING MOVE 14,[JRST SPRIN1] ;SET UP RETURN INSTRUCTION JRST 2 ;ENTER LOOP ;INITIALIZE PD LIST SPRIN1: MOVE P,.CPNPD## ;SET UP PUSH DOWN POINTER MOVE T1,.CPTOS## ;SAVE FIRST SLOT IN CPU1'S MAP TEMPORARRLY PUSH P,.E0PM##-.E0MP##(T1) ;MAPINI CLOBBERS THIS PUSHJ P,MAPINI ;COPY THE BOOT CPU'S MAP INTO THE CURRENT CPU'S MAP IFN FTKL10,< MOVEI T1,LG.CSL!LG.CSW;CACHE STRATEGY LOOK, CACHE STRATEGY LOAD IORM T1,.CPEBR## ;MAKE SURE CURRENT CPU'S CACHE IS ON > JRSTF @[EXP IC.UOU+.+1] ;TURN ON USER IOT SO EXECUTE PAGED WORKS ; CORRECTLY AND PROCEED WITH INITIALIZATION CLRPGT (1) CONO PI,10000 ;AND CLEAR PI SYSTEM MOVE T1,.CPTOS## ;RESTORE CONTENTS OF CPU1 EXEC MAP SLOT 0 POP P,.E0PM##-.E0MP##(T1) ;FALL INTO SPRIN2 MOVSI T1,40000 ;SUPPENDED BIT TDNE T1,.CPRUN## ;RESTART AFTER REBOOT? JRST SPRIN5 ;YES, DISKS ARE INITIALIZED SPRIN2: MOVE 17,[ONCLOP,,1] ;WAIT IN ACS FOR CPU0 TO REQUEST IO BLT 17,16 ; DO IT (AT SPRIN3) WHEN REQUESTED SJSP 0,3 SPRIN3: MOVE P,.CPNPD## ;SET UP A PDL SKIPN T1,ONCCOM## ;WHAT CPU0 WANTS US TO DO JRST SPRIN2 ;NOTHING TO DO AOJE T1,SPRIN2 ;RESTARTED IF -1 SOS F,T1 ;COMM WORD INTO F SOJE T1,SPRIN5 ;DONE IF +1 TLNE F,-1 ;IF -1,,UDB JRST SPRIN4 ;DO CPY ROUTINE PUSHJ P,SPRIO## ;0,,DDB - DO IO JRST SPRIN2 ;AND WAIT SOME MORE SPRIN4: HRRZ U,F ;SET U=UDB PUSHJ P,SPRCPY## ;CALL KONCPY JRST SPRIN2 ;AND WAIT SOME MORE ;HERE TO SET UP TO RUN NULL JOB, & SETUP PI SPRIN5: PUSHJ P,MAPINI MOVEI T1,CCTYO## ;GET ADDRESS OF TYPEOUT ROUTINE MOVEM T1,.CPTOA## ; AND TELL SCNSER MOVEI T1,COMTIV## ;GET ADDRESS OF COMMAND INPUT ROUTINES MOVEM T1,.CPTIV## ; AND TELL SCNSER TO USE LDB'S NOW. SETZM .CPTNT## ;JUST STARTING MOVE J,.CPCPN## ; FOR THIS CPU SETZM CLKMIN##(J) ;CLEAR MIN REQUEST SETOM .CPSCD## ;CLEAR SCHED NESTING SETOM .CPDWD## ;GIVE UP DIE RECURSION INTERLOCK SETZM .CPNBI## ;CLEAR NUMBER OF BROKEN INTERLOCKS SETZM .CPAEF## ;CLEAR CPU ERROR/SWEEP FLAGS HRRZS .CPMPC## ;CLEAR SERIOUS MEMORY PARITY HALT FLAG ; HALT AFTER PRINTING ON CPU0 CTY MOVE T1,TIME## ;GET CURRENT TIME MOVEM T1,.CPTML## ;STORE FOR TICKS GONE BY MOVE T2,TICSEC## ;TICK PER SECOND LSH T2,-1 ;DIVIDE BY 2 ADD T1,T2 ;AND ROUND IDIV T1,TICMIN## ;T2 = PARTIAL MINUTE (IN TICKS) IDIV T2,TICSEC## ;T2 = SECONDS, T3 = REMAINDER IN TICKS SUBI T2,^D60 ;COMPUTE TIME TO NEXT MINUTE MOVNM T2,.CPSEC## ;STORE FOR ONCE-A-MINUTE UPDATE SUB T3,TICSEC## ;TIME TO NEXT SECOND MOVNM T3,.CPHTM## ;STORE FOR ONCE-A-SECOND UPDATE MOVEI T1,SR.STS!SR.DIE!SR.ACL ;CLEAR THESE BITS WHEN WE ANDCAM T1,.CPSBR## ; RESTART THE PROCESSOR MOVEI J,JOBMAX## ;MAX JOB NO. MOVSI T1,(SP.CJ0) ;JOB RUNNING ON CPU1 BIT LSH T1,@.CPCPN## SPRLP1: ANDCAM T1,JBTSPS##(J) ;CLEAR FOR ALL JOB IN SYSTEM ; (IN CASE THIS IS A 450 RESTART ON CPU1) SOJGE J,SPRLP1 ;MORE? IFN FTKL10,< APRID T3 ;PROCESSOR HARDWARE OPTIONS DMOVE T1,[M.EBPS## ;ASSUME A MODEL A PROCESSOR M.MBPS##] TRNE T3,ID.XKL ;IS IT A MODEL B PROCESSOR? DMOVE T1,[^D30*M.EBPS##/^D25 ;YES, USE DIFFERENT EBOX/MBOX CALABRATION CONSTANTS ^D30*M.MBPS##/^D25] MOVEM T1,.CPEBS## ;STORE AS EBOX TICS/SEC MOVEM T2,.CPMBS## ;STORE AS MBOX TICS/SEC IDIV T1,TICSEC## ;AND NOW GET EBOX COUNTS/JIFFY IMULI T1,.EBCPT ;MULTIPLY BY EBOX COUNTS/TICK MOVEM T1,.CPEBJ## ;STORE IN CDB VARIABLE MOVE T1,.CPMBS## ;GET MBOX TICKS/SECOND IDIV T1,TICSEC## ;GET MBOX COUNTS/JIFFY IMULI T1,.MBCPT ;MULTIPLY BY MBOX COUNTS/TICK MOVEM T1,.CPMBJ## ;SAVE IFN FTEMRT,< PUSHJ P,ACCMON## ;START UP ACCOUNTING METERS PUSHJ P,CLREMB## ;CLEAR OUT E AND MBOX ACCOUNTING METERS >;END IFN FTEMRT >;END IFN FTKL10 PUSHJ P,SETIME## ;TO INITILIZE 'GGTIME' CLOCK (IN SYSINI) IFN FTKL10,< CONI MTR,T1 ;PRESERVE TIME BASE INFO CONO MTR,AP1CHN##(T1);SETUP INTERVAL TIMER PI MOVSI T1,40000 ;SUPPENDED BIT TDNE T1,.CPRUN## ;THERE MIGHT NOT BE A BOOT CPU AFTER A REBOOT JRST SPRI5A ; SO DON'T WAIT ON IT MOVE T1,BOOTCP## ;BOOT CPU LSH T1,.CPSOF## ;OFFSET TO ITS CDB SKIPE T2,.C0TMF##(T1) ;WAIT UNTIL CLOCK FLAG CLEARS, ZERO T2 JRST .-1 SKIPN .C0TMF##(T1) ;TIME FROM SET UNTIL SET JRST .-1 SKIPE .C0TMF##(T1) AOJA T2,.-1 SKIPN .C0TMF##(T1) AOJA T2,.-1 MOVE T3,.CPCPN## ;OUR CPU NUMBER SUB T3,BOOTCP## ; MINUS THE BOOT CPU NUMBER SKIPG T3 ;IF NEGATIVE, (NEVER EQUALS ZERO) ADDI T3,CPUN## ; MODULO THE NUMBER OF CPU'S IMULI T2,(T3) IDIVI T2,CPUN## ;FRACTION OF A TIC TO WAIT SOJG T2,. ; BEFORE STARTING THE CLOCK SPRI5A: MOVEI T1,^D1666 ;ASSUME 60HZ MOVE T2,STATES## TLNE T2,(ST.CYC) ;IS OUR ASSUMPTION CORRECT? MOVEI T1,^D2000 ;NO, 2000 IS INTERVAL CONO TIM,TO.CTD!TO.CIT!TO.SIT(T1) ;START TIMER GOING > IFN FTKI10,< CTY==120 ;DEVICE CODE FOR CTY CONO CTY,1200+SCNCHN## > CONO APR,AP1NUL## CONO PI,52377 ;TURN ON ALL PI, ENABLE MEMORY PARITY IFN FTKL10,< PPCPT1::PUSHJ P,STAPPC## ;PATCH TO JFCL TO INHIBIT STARTING PRIMARY PROTOCOL JFCL IFN FTEDSK,< PUSHJ P,RNXSAK## ;INSURE ALL RP20 DX20'S ARE RUNNING > > HLRZ U,SYSUNI## ;FIRST UNIT IN THE SYSTEM MOVN J,TICSEC## ;AVOID BRKLOK MOVEM J,.CPOK## ;CALLS BY THE BOOT CPU SPRIN6: HRRZ J,UNIKON##(U) ;KONTROLLER DATA BLOCK LDB T1,KOYCPU## ;CPU THIS CONTROLLER LIVES ON CAME T1,.CPCPN## ;CURRENT CPU? JRST SPRIN7 ;NO, ONWARD AND UPWARD PUSHJ P,ATTCPD## ;YES, ATTACH THE UNIT JFCL ;DON'T CARE JFCL ;THIS ONE EITHER SPRIN7: HLRZ U,UNISYS##(U) ;NEXT UNIT IN THE SYSTEM JUMPN U,SPRIN6 ;GO IF NOT THE LAST SETZB S,P1 ;ALWAYS CALL INI ROUTINE ONCE HLRZ P3,HNGLST## ;LOOK ONLY AT REAL HARDWARE SPRIN8: MOVE F,P3 ;SETUP F FOR INI CODE MOVE P3,DEVSER(P3) ;ADDRESS OF DEVICE DISPATCH VECTOR LDB T1,DEYCPF## ;CPU OWNING THE DEVICE CAMN T1,.CPCPN## ;CURRENT CPU? CAIN P1,(P3) ;YES, ALREADY CALLED INI ROUTINE? JRST SPRIN9 ;YES, SKIP ON MOVSI T1,DVMTA ;SPECIAL CHECK FOR MAGTAPE TDNN T1,DEVMOD(F) ;ALWAYS DO INITIALIZATION FOR MAGTAPE SKIPN .CPAID## ; (SEE TPMINI) OR IF OTHER DEVICES CAIA ; HAVEN'T BEEN INITIALIZED YET JRST SPRIN9 ; OTHERWISE SKIP ON PUSHJ P,DINI(P3) ;NO, CALL INI ROUTINE HRRZ P1,P3 ;NEEDN'T CALL IT AGAIN SPRIN9: HLRZS P3 ;NEXT DDB JUMPN P3,SPRIN8 ;LOOP IF THERE IS ONE SETOM .CPAID## ;INDICATE DEVICES HAVE ALREADY BEEN INITIALIZED MOVSI T1,40000 ;SUPPENDED BIT IFN FTNET,< TDNE T1,.CPRUN## ;IF RESTARTING, PUSHJ P,FEKCPW## ; TELL THE FEK'S > ANDCAM T1,.CPRUN## ;CLEAR IT SINCE RESUMING SJSP U,NULJB1## ;GO START NULL JOB ;SUBROUTINE TO INITIALISE CPU1'S MAP FROM CPU0'S MAP MAPIND: PUSHJ P,SSEUB## MAPINI: MOVE T4,.CPTOS## ;GET ADDRESS OF EPT WE ARE USING MOVE T1,BOOTCP## ;CPU WHO'S MAP WE WANT TO COPY LSH T1,P2WLSH## ;TO OFFSET FROM CPU0'S EPT MOVSI T1,.EPPM##(T1) ;SOURCE = HIGH SEG MAP HRRI T1,.EPPM##-.EPMP##(T4) ;DESTINATION = OUR HIGH SEG MAP BLT T1,.EPPM##-.EPMP##+177(T4) ;MOVE IT ALL IFN FTKL10,< MOVE T1,BOOTCP## ;CPU WHO'S MAP WE WANT TO COPY LSH T1,P2WLSH## ;TO OFFSET FROM CPU0'S EPT MOVSI T1,.EPLM##(T1) ;SOURCE = LOW SEG MAP HRRI T1,.EPLM##-.EPMP##(T4) ;DESTINATION = OUR LOW SEG MAP BLT T1,.EPLM##-.EPMP##+157(T4) ;MOVE IT ALL > JSP T4,SYSTR1## ;REMAP OUR CDB JFCL POPJ P, ;RETURN ;ROUTINE TO TELL THE OPERATOR THE CURRENT CPUS NAME UPON STARTUP PRTCPU: MOVEI T1,[ASCIZ/ [/] ;START ON A NEW LINE WITH OPEN SQUARE BRACKET PUSHJ P,CTYTYP## ;TYPE THAT MOVE T2,.CPLOG## ;CPU'S LOGICAL NAME PRTCP1: MOVEI T1,0 ;ZERO PREVIOUS CHARACTER LSHC T1,6 ;SHIFT IN NEW CHARACTER MOVEI T3,40(T1) ;MAKE IT ASCIZ PUSHJ P,CTYWAT## ;TYPE IT JUMPN T2,PRTCP1 ;JUMP IF YET ANOTHER SIXBIT CHARACTER MOVEI T1,[ASCIZ/] /] ;CLOSE OFF WITH CLOSING SQUARE BRACKET AND NEW LINE PJRST CTYTYP## ;TYPE THAT ;SUBROUTINE TO ASSUME THE ROLE OF THE BOOT CPU ; CALLED WHEN THE BOOT CPU'S OK WORD FLIPPED FROM ; NEGATIVE TO ZERO (CALL IS INTERLOCKED BY BOOT CPU'S OK WORD) BECOM0::PUSHJ P,SAVT## ;SAVE THE T REGS MOVSI T1,(1B0) ;GET BIT FOR BREAKPOINT ON CPU0 MOVN T2,BOOTCP## ;-BOOT CPU NUMBER LSH T1,(T2) ;SHIFT TO BIT FOR BOOT CPU TDNE T1,CPNDDT## ;BOOT CPU AT A BREAKPOINT? POPJ P, ;YES, DON'T ASSUME THE ROLE PUSH P,U ;SAVE U MOVEI T1,LDRCTY## ;THIS IS THE CTY BIT MOVE U,BOOTCT## ;LINE NUMBER OF THE CTY ON THE CPU THAT DIED HRRZ U,LINTAB##(U) ;ADDRESS OF THE LDB ANDCAM T1,LDBDCH##(U) ;ZAP, NO LONGER THE CTY HRRZ T2,.CPCTN## ;OUR CTY LINE NUMBER MOVEM T2,BOOTCT## ;MAKE IT THE "CTY" MOVE T2,LINTAB##(T2) ;LDB FOR OUR CTY CAMN U,OPRLDB## ;WAS "OPR" THE CTY ON THE CPU WHICH WENT AWAY? HRRZM T2,OPRLDB## ;YES, MAKE "OPR" BE OUR CTY IORM T1,LDBDCH##(T2) ;ZAP, WE'RE THE NEW CTY PUSH P,T2 ;SAVE NEW CTY LDB PUSHJ P,TTYNAM## ;MAKE TTY NAME FOR OLD CTY HRRZ U,LDBDDB##(U) ;FIND DDB ATTACHED SKIPE U ;IS THERE ONE MOVEM T2,DEVNAM(U) ;YES, CHANGE NAME MOVSI T1,'CTY' ;NAME OF NEW CTY POP P,T2 ;NEW CTY LDB HRRZ T2,LDBDDB##(T2) ;FIND ATTACHED DDB SKIPE T2 ;ANY DDB THERE MOVEM T1,DEVNAM(T2) ;YES, CHANGE IT IFN FTNET,< MOVE U,OPRLDB## ;GET LOCAL OPR LDB PUSHJ P,NETOPR## ;TELL NETSER IN CASE IT CHANGED JFCL ;ALWAYS SKIPS > POP P,U ;RESTORE U PUSH P,J ;SAVE J (NEED FOR MPYNRN) MOVE J,HIGHJB## ;FOR EVERY JOB IN THE SYSTEM MOVEI T1,SP.CP0 ;BIT FOR CPU0 (1B35) LSH T1,@.CPCPN## ;BIT FOR NEW POLICY CPU TRC T1,SP.CPA ;NOT RUNNABLE ANYWHERE BUT... MOVSI T2,(SP.ROP) ;FORCED TO POLICY CPU BIT TDNE T2,JBTSPS##(J) ;JOB FORCED? DPB T1,MPYNRN## ;YES, SET NEW NOT-RUNNABLE SOJG J,.-2 ;GET ALL THE JOBS POP P,J ;RESTORE J SETOM CLKNEW## ;RECOMP "SYSTEM" CLOCK QUEUE MOVE T1,BOOTCP## ;OLD "CPU0" LSH T1,.CPSOF## ;TO CDB OFFSET MOVEI T1,.C0CDB##(T1) ;POINT TO CDB CAMN T1,.CPSLF## ;ARE WE ALREADY "CPU0" POPJ P, ;YES, SYSINI IS FIXING THE CTY PUSHJ P,BRKLO1 ;RETURN INTERLOCK MOVE T1,DATE## ;GET CURRENT UNIVERSAL DATE/TIME MOVEM T1,RSDTTM## ;SAVE FOR CRASH ANALYSIS PUSHJ P,FRCSET## ;SETUP U TO POINT TO FRCLIN PUSHJ P,INLMES## ASCIZ/SEND CTY / ;SEND MESSAGE TO NEW CTY MOVE T2,.CPLOG## ;GET NAME OF THIS CPU PUSHJ P,PRNAME## ;PUT INTO MESSAGE PUSHJ P,INLMES## ASCIZ/ has assumed the role of policy CPU on / ;TELL WHAT HAPPENED PUSHJ P,DAYTIM## ;ADD DATE/TIME BCOM0:: MOVE T1,.CPCPN## ;OUR CPU NUMBER MOVEM T1,BOOTCP## ;STORE AS NEW "CPU0" MOVE T1,.CPASN## ;OUR SERIAL NUMBER MOVEM T1,SERIAL## ;STORE IN OLD GETTAB MOVEI T1,.C0CDB## ;START OF THE CDB'S MOVE T2,.CPSLF## ;OUR OWN CDB BECOM1: MOVSI T3,(CAI) ;"SKPCPU(0)" FOR THIS CPU MOVSI T4,(CAIA) ;"SKPCPU(1)" CAMN T2,.CPSLF##-.CPCDB##(T1) ;LOOKING AT OURSELF EXCH T3,T4 ;YES, MAKE "SKPCPU(0)" WORK FOR US DMOVEM T3,.CPSK0##-.CPCDB##(T1) ;AND FIX SKIP CPU WORDS MOVEI T3,.CPOK##-.CPCDB##(T2) ;OUR OK WORD'S ADDRESS MOVEM T3,.CPOK1##-.CPCDB##(T1) ;POINT OK WORDS AT THIS CDB MOVEI T3,SSCAN## ;POLICY CPU SCHEDULER SCAN TABLE CAME T2,.CPSLF##-.CPCDB##(T1) ;LOOKING AT OURSELF MOVE T3,SSCN##(T3) ;NO, USE SECONDARY (REVERSED) TABLE MOVEM T3,.CPSCN##-.CPCDB##(T1) ;STORE SCAN TABLE ADDRESS HLRZ T1,.CPCDB##-.CPCDB##(T1) ;STEP TO NEXT CDB JUMPN T1,BECOM1 ;AND FIX IT UP POPJ P, XLIST ;DUMPED LITERALS LIT LIST $HIGH ;BACK TO THE HIGH SEGMENT ;HERE WHEN BOOT CPU COUNTS ANOTHERS OK WORD TO 1 SEC ; ASSUME THAT THE CPU IS DOWN AND BREAK INTERLOCKS ;CALL T1=CDB OF THAT CPU BRKLOK::PUSHJ P,SAVT## ;SAVE THE T REGS MOVSI T2,(1B0) ;GET BIT FOR CPU0 AT A BREAKPOINT MOVN T3,.CPCPN##-.CPCDB##(T1) ;-CPU NUMBER FOR CPU IN QUESTION LSH T2,(T3) ;SHIFT TO BIT FOR THAT CPU TDNE T2,CPNDDT## ;CPU AT A BREAKPOINT? POPJ P, ;YES, DON'T BREAK INTERLOCKS BRKLO1: PUSHJ P,BRKSI1 ;BREAK THE SOFTWARE INTERLOCKS MOVE T2,INODIE## ;CPU OWNING DIE INTERLOCK IFN FTKI10,< LSH T2,-^D26 ;ISOLATE SERIAL NUMBER > IFN FTKL10,< ANDI T2,7777 ;ISOLATE SERIAL NUMBER > CAMN T2,.CPASN##-.CPCDB##(T1) ;THIS CPU OWN THE DIE INTERLOCK? SETOM DIELOK## ;YES, BREAK IT IFN FTNET,< PUSHJ P,BRKFEK## ;DECLARE THE FEKS DOWN > POPJ P, ;ROUTINE TO RETURN THE SOFTWARE INTERLOCKS OWNED BY THIS CPU. ;CALL PUSHJ P,GIVLOK ; RETURN HERE ALWAYS GIVLOK::HRRZ T1,.CPSLF## ;GET ADDRESS OF OUR CDB PUSHJ P,BRKSIW ;BREAK THE LOCKS SETZM .CPNBI## ;WE KNOW WE JUST BROKE THEM POPJ P, ;RETURN ;ROUTINE TO BREAK THE SOFTWARE INTERLOCKS FOR A CPU THAT HAS GONE ;DOWN OR FROM A JOB STOPCD. ;CALL T1=CDB ADDRESS OF THE CPU BRKSIW::PUSHJ P,SAVT## ;SAVE T1-T4 BRKSI1: MOVE T2,.CPASN##-.CPCDB##(T1) ;GET APR ID OF DOWN CPU MOVEI T3,INTRLK## ;FIRST SYSTEM INTERLOCK BRKSI2: SKIPGE 0(T3) ;INTERLOCK TAKEN JRST BRKSI3 ;NO, LOOK AT NEXT MOVE T4,INTOLK##-INTRLK##(T3) ;OWNER OF THIS INTERLOCK IFN FTKI10,< LSH T4,-^D26 ;ISOLATE SERIAL NUMBER > IFN FTKL10,< ANDI T4,7777 ;ISOLATE SERIAL NUMBER > CAIE T2,(T4) ;THAT CPU OWN THE INTERLOCK JRST BRKSI3 ;NO, CONTINUE AOS .CPNBI##-.CPCDB##(T1) ;COUNT THE BROKEN INTERLOCK SETOM 0(T3) ;YES, FREE IT BRKSI3: CAIE T3,INTOLK##-1 ;DO LAST INTERLOCK AOJA T3,BRKSI2 ;NO, GET THEM ALL MOVE T4,INTLMO## ;CPU OWNING "MM" RESOURCE IFN FTKI10,< LSH T4,-^D26 ;ISOLATE SERIAL NUMBER > IFN FTKL10,< ANDI T4,7777 ;ISOLATE SERIAL NUMBER > CAIN T2,(T4) ;DOES IT OWN THE INTERLOCK PUSHJ P,[AOS .CPNBI##-.CPCDB##(T1) ;COUNT THE BROKEN INTERLOCK PJRST GIVMM] ;AND LET THE SWAPPER BACK IN; MOVE T2,.CPCPN##-.CPCDB##(T1) ;CPU NUMBER OF LOST CPU CAME T2,SCNOWN## ;DOES IT OWN SWAPPER RESOURCE POPJ P, ;NO, RETURN SETOM SCNOWN## ;YES, ALLOW SWAPPING AGAIN SETOM SCNCNT## ;... AOS .CPNBI##-.CPCDB##(T1) ;COUNT THE BROKEN INTERLOCK POPJ P, ;RETURN ;ROUTINE TO WAIT IN THE AC'S WHILE MEMORY IS BEING SET OFF-LINE ;BY THE BOOT CPU. ;CALL: JRST CP1MFL ; RETURNS TO SAVPC2 IN CLOCK1 CP1MFL::CONO PI,PI.OFF ;TURN OFF PI SYSTEM MOVEM 17,.CPCAC##+17 ;SAVE 17 MOVEI 17,.CPCAC## ;WHERE TO SAVE THE AC'S BLT 17,.CPCAC##+16 ;SAVE THEM ALL MOVE P,.CPNPD## ;SETUP POINTER TO NULPDL IFN FTKL10,< PUSHJ P,CP1MF1 ;CALL ROUTINE TO WAIT JRST CP1MF3 ;AND JUMP AROUND CODE CP1MF1: PUSHJ P,SVPPC## ;SAVE PROTOCOL, ENTER SECONDARY PUSHJ P,CSDMP## ;INSURE IT'S ALL IN CORE > MOVEM P,.CPPWF##+P ;SAVE P BEFORE LOADING AC LOOP MOVE 14,[ACLOOP,,2] BLT 14,14 ;LOAD THE AC LOOP DMOVE 12,[TDNE 17,.CPSBR## ; WE RELOADED IF BIT NO LONGER SET JRST CP1MF2] ;WHERE TO GO AT END OF LOOP MOVEI 17,SR.ACL ;TELL OTHER CPU'S IORM 17,.CPSBR## ;THAT WE'RE IN THE AC'S JRST 2 ;AND GO THERE $LOW CP1MF2: MOVE P,.CPPWF##+P ;RESTORE P PUSHJ P,MAPIND ;MAP MAY HAVE CHANGED IFN FTKL10,< POPJ P, CP1MF3: > MOVEI 17,SR.ACL ;NO LONGER IN ANDCAM 17,.CPSBR## ; THE AC'S MOVSI 17,.CPCAC## ;WHERE TO RESTORE THE AC'S FROM BLT 17,17 ;RESTORE THEM ALL CONO PI,PI.ON ;TURN PI SYSTEM BACK ON JRST SAVPC2## ;RETURN $HIGH ;ROUTINE TO WAIT IN THE AC'S WHILE ANOTHER CPU IS AT A BREAKPOINT. ;CALL: JRST CPNBPT ; RETURNS @.CPABK CPNBPT::CONO PI,PI.OFF ;TURN OFF PI SYSTEM JSR .CPSVA## ;SAVE ALL AC SETS MOVE P,.CPEPD## ;INSURE A PDL IS SETUP IFN FTKL10,< PUSHJ P,CPNBP1 ;CALL ROUTINE TO DO THE WORK JRST CPNBP3 ;AND SKIP THE SUBROUTINE CPNBP1: PUSHJ P,SVPPC## ;SAVE PROTOCOL, ENTER SECONDARY PUSHJ P,CSDMP## ;MAKE SURE IT'S ALL IN CORE > MOVE 6,[BPLOOP,,2] ;SETUP TO LOAD THE AC LOOP BLT 6,6 ;MOVE IN THE AC LOOP MOVEI 17,SR.ACL ;GET BIT TO TELL OTHERS THAT WE ARE IORM 17,.CPSBR## ;LOOPING IN THE AC'S JRST 2 ;AND GO WAIT $LOW CPNBP2: PUSHJ P,MAPIND ;INSURE THE MAP IS SETUP CORRECTLY IFN FTKL10,< POPJ P, ;RETURN FROM SUBROUTINE IF KL10 CPNBP3: > MOVEI 17,SR.ACL ;NO LONGER LOOPING ANDCAM 17,.CPSBR## ; IN THE AC'S HRLZ 17,.CPACA## ;WHERE TO RESTORE THE AC'S FROM BLT 17,17 ;RESTORE THEM ALL CONO PI,PI.ON ;TURN ON PI SYSTEM JRSTF @.CPABK## ;RETURN TO CALLER $HIGH ;HERE ON ALL CPU'S BUT THE BOOT CPU WITH THE AC'S AND MACHINE ;STATE SAVED TO LOOP IN THE AC'S WAITING FOR THE SYSTEM TO BE RELOADED ;OR FOR THE OPERATOR TO RESTART THE CPU. IF SR.DIE IS SET IN .CPSBR, ;THE PROCESSOR WILL NOT RESTART (EVEN AFTER A RELOAD) UNLESS THE ;OPERATOR MANUALLY STARTS IT AT 400. CP1CRS:: IFN FTKL10,< MOVE P,.CPEPD## ;INSURE STACK IS SETUP PUSHJ P,ENTSPC## ;ENTER SECONDARY PROTOCAL > MOVEI 17,SR.ACL ;GET LOOPING IN THE AC'S BIT IORM 17,.CPSBR## ; AND TELL OTHERS MOVEI T1,SR.DIE ;BIT TELLING US NOT TO RESTART TDNE T1,.CPSBR## ;SET FOR THIS CPU? PJRST RMVCPU ;YES, JRST 1 FOREVER MOVE 14,[ACLOOP,,2] ;LOAD BLT POINTER TO AC LOOP BLT 14,14 ;LOAD THE AC LOOP JRST 2 ;JUMP INTO THE AC'S $LIT $LOW ;THE FOLLOWING LOOPS ARE LOADED INTO THE AC'S WHEN A CPU WANTS TO ;WAIT FOR AN EVENT. ACLOOP AND BP LOOP ARE BOTH ENTERED WITH AC ;17 CONTAINING SR.ACL. ACLOOP: MOVEI 1,20 ;2 INITIALIZE ITERATION COUNT MOVE 0,.CPOK## ;3 GET CURRENT .C1OK CAMN 0,.CPOK## ;4 SEE IF .C1OK HAS CHANGED JRST 4 ;5 NO, WAIT UNTIL IT DOES CHANGE AOS 0 ;6 COUNT OLD .C1OK BY ONE CAME 0,.CPOK## ;7 DID .C1OK INCREASE BY EXACTLY ONE JRST 2 ;10 NO, START OVER AGAIN SOJG 1,4 ;11 WAIT FOR 20 COUNTS TO BE SURE JFCL ;12 PATCHED JFCL ;13 PATCHED JRST SYSDSP## ;14 GO RESTART SLAVE BPLOOP: SKIPE CPNDDT## ;2 IS DDT FINISHED YET? JRST 2 ;3 NO, LOOP TDNE 17,.CPSBR## ;4 IF NOT STILL SET, WE RELOADED JRST CPNBP2 ;5 RETURN TO CALLER JRST SYSDSP## ;6 GO RESTART CPU ;NOTE THAT WE ENTER AT 3 THE FIRST TIME, WITH 0 NON-0 ONCLOP: MOVE 0,.CPOK## ;1 RESYNCHRONIZE SKIPE 17 ;2 DID BOOTS ZERO CORE? MOVE 17,[1] ;3 NO. THIS LITERAL SHOULD BE RIGHT IF SAME MONITOR CAMN 0,.CPOK## ;4 WAIT TILL .CPOK COUNTS UP BY 1 JRST 2 ;5 DIDNT COUNT, WAIT A WHILE AOS 0 ;6 COUNTED. BY 1? CAME 0,.CPOK## ;7 JRST 1 ;10 NO, WAIT TILL IT COUNTS BY EXACTLY 1 MOVE 0,[1] ;11 IS THE LITERAL STILL INTACT? SOJN 0,1 ;12 NO, DIFFERENT MONITOR WAS LOADED JUMPE 17,SYSDSP## ;13 YES, 17=0 IF BOOTS RELOADED THE MONITOR SKIPE ONCCOM## ;14 ALL SEEMS OK. SOMETHING FOR US TO DO? JRST SPRIN3 ;15 YES, GO DO WHAT CPU0 TELLS US JRST 1 ;16 NOTHING TO DO, WAIT SOME MORE LIT $HIGH SUBTTL MULTIPROCESSING COMMANDS AND UUOS ;CODE TO IMPLEMENT THE SETUUO'S NUMBER 14 (.STCPU) ;AND 15 (.STRUN) SETCRN::MOVEI T4,.C0CDB## ;ADDRESS OF FIRST CDB SETCR1: MOVE T3,.CPRUN##-.CPCDB##(T4) ;GET RUN BIT FOR CPU TRNE T2,1 ;CHECK BIT FOR CPU RUNNABILITY TLZA T3,400000 ;CLEAR SIGN BIT TO ALLOW CPU TO RUN TLO T3,400000 ;SET SIGNBIT TO TURN CPU OFF MOVEM T3,.CPRUN##-.CPCDB##(T4) ;PUT BACK IN CDB HLRZ T4,.CPCDB##-.CPCDB##(T4) ;GET ADDRESS OF NEXT CDB PJUMPE T4,CPOPJ1## ;NO ERROR RETURNS LSH T2,-1 ;MOVE NEXT BIT TO 35 JRST SETCR1 ;AND CHECK OUT THIS ONE .ERNAR==0 ;NONE ARE RUNNING ERROR CODE .ERDHP==1 ;DOESN'T HAVE PRIVILEGES ERROR ;ROUTINE TO HANDLE SETUUO #14 (.STCPU) USER SET ;CPU SPECIFICATION SETCPU::MOVSI T3,JP.CCC ;CAN CHANGE CPU SPECIFICATION BIT TDNE T3,JBTPRV##(J) ;USER PRIVILEGED TO CHANGE? JRST SETCP1 ;YES, PROCEED PUSHJ P,PRVJ## ;NO, IS HE [1,2] OR IS JACCT SET? JRST SETCP1 ;YES, OK TO PROCEED MOVEI T1,.ERDHP ;NO, GIVE ERROR RETURN PJRST STOTAC## ;WITH DOESN'T HAVE PRIVILEGE CODE SETCP1: MOVE T1,T2 ;HOLD BITS IN T1 MOVEI T4,.C0CDB## ;GET ADDRESS OF CPU0 CDB TRZ T2,777700 ;EXTRACT THE BITS WE WANT SETCP2: TRNE T2,1 ;DO WE CARE ABOUT THIS CPU? SKIPGE .CPRUN##-.CPCDB##(T4) ;YES, IS IT RUNNING? JRST SETCP3 ;NO, CHECK NEXT DPB T1,[POINT 6,JBTSPS##(J),35] ;YES, WE ARE SATISFIED. JRST CPOPJ1## ;AND SKIP RETURN SETCP3: HLRZ T4,.CPCDB##-.CPCDB##(T4) ;GET ADDRESS OF NEXT CDB JUMPE T4,SETCP4 ;IF NO MORE, ERROR LSH T2,-1 ;MOVE NEXT BIT INTO POSITION JRST SETCP2 SETCP4: MOVEI T1,.ERNAR ;GET NONE ARE RUNNING CODE PJRST STOTAC## ;GIVE TO USER AND CPOPJ ;ROUTINE TO HANDLE SETUUO #37 (.STCDN) ; SET CPU UP/DOWN STATUS SETCDN::HRRZ T1,T2 ;COPY CPU NUMBER TRZE T1,1B19 ;SUPPEND A CPU? JRST SETCD3 ;YES TRZN T1,1B18 ;ADD OR REMOVE A CPU JRST SETCD1 ;ADDING MOVE T3,[SOS NCPRUN##] ;REMOVE, SET TO DECREMENT MOVE T4,NCPRUN## ;HOW MANY CPUS ARE LEFT SOJLE T4,CPOPJ## ;CAN'T REMOVE THE LAST JRST SETCD2 ;JOIN COMMON PART SETCD1: MOVE T3,[AOS NCPRUN##] ;ADD, SET TO BUMP COUNT MOVSI T4,(ST%LSC) ;LOW SEG CACHED BIT TDNN T4,CNFST2## ;CACHE RIGHT FOR ADDING SETCD2: CAIL T1,CPUN## ;RANGE CHECK CPU NUMBER POPJ P, ;CACHE WRONG OR BAD CPU LSH T1,.CPSOF## ; TO CDB OFFSET FROM CPU0'S SKIPL T4,.C0RUN##(T1) ;GET RUN BITS FOR CPU TRNN T2,1B18 ;STILL RUNNABLE, TRYING TO ADD SKIPA ;YES, ALWAYS OK TO ADD A CPU POPJ P, ;CPU STILL RUNNABLE, IGNORE TRNN T2,1B18 ;ADDING OR REMOVING IT TLZA T4,200000 ;ADD, CLEAR "GO AWAY" BIT TLO T4,200000 ;MARK FOR REMOVAL CAME T4,.C0RUN##(T1) ;DID WE CHANGE STATES XCT T3 ;YES, ADJUST COUNT OF CPUS MOVEM T4,.C0RUN##(T1) ;STORE NEW BITS JRST CPOPJ1## ; AND ALL DONE SETCD3: CAIL T1,CPUN## ;LEGAL CPU NUMBER? POPJ P, ;NO, ERROR RETURN LSH T1,.CPSOF## ;OFFSET INTO THE APPROPRIATE CDB MOVSI T2,40000 ;CPU IS TO BE SUPPENDED BIT IORM T2,.C0RUN##(T1) ;LITE THE BIT JRST CPOPJ1## ;TELL THE USER HE DID GOOD ;HERE FROM CLOCK1 WHEN ITS TIME TO REMOVE THIS CPU OR ON A CPU STOPCODE RMVCPU:: IFN FTKL10,< MOVEI T1,LG.CSL!LG.CSW ;TURN OFF CACHE BITS ANDCAM T1,.CPEBR## ;FOR 400 RE-START MOVE F,.CPCPN## ;CPU NUMBER MOVE F,DTEMAS##(F) ;THE MASTER DTE PUSHJ P,TTDRLD## ;CLEAR F.E. TTY STATUS PUSHJ P,SVPPC## ;TURN OFF "KEEP ALIVE" PUSHJ P,CSDMP## ;EMPTY CACHE AOS .CPCSN## ;INSURE SWEEP GETS RECORDED > CONO PI,CLRPIS## ;DON'T MAINTAIN OK WORDS CONO APR,AP1RST## ;BLAST THE PROCESSOR MOVE 1,.+1 ;GET AN INFINITE LOOP JRST 1 ;AND DISAPPEAR CPUCMD::PUSHJ P,SAVE1## ;SAVE P1 MOVSI P1,JP.CCC ;GET CAN CHANGE CPU SPECIFICATION BIT PUSHJ P,SETLGL## ;IS THIS THE OPR OR A [1,2] JOB, TDNE P1,JBTPRV##(J) ; OR DOES THE JOB HAVE PRIVILEGES? JRST CPUCM1 ;YES, PROCEED PJSP T1,ERRMES## ;NO, ERROR MESSAGE ASCIZ /No privileges to SET CPU / CPUCM1: PUSHJ P,CTEXT## ;GET NEXT ARGUMENT MOVE P1,T2 ;SAVE IN P1 PUSHJ P,CPUFND ;SEE IF IT IS CPXN JRST CPUCM2 ;NO, GET REST OF COMMAND IORM T3,JBTSPS##(J) ;WAS SET CPU CPXN, BITS IN T3 JRST CPUCM5 ;AND RETURN CPUCM2: PUSHJ P,CTEXT## ;GET NEXT ARGUMENT JUMPE T2,CPUCM4 ;NO MORE, MUST BE SET CPU ALL PUSHJ P,CPUFND ;FIND CPU AND SET MASK BITS PJRST COMERR## ;NOT FOUND, ERROR CAME P1,[SIXBIT /NO/] ;WAS THIRD ARGUMENT "NO"? JRST CPUCM3 ;NO, CHECK OTHERS ANDCAM T3,JBTSPS##(J) ;YES, CHANGE SPECIFICATION JRST CPUCM5 ;AND RETURN CPUCM3: CAME P1,[SIXBIT /ONLY/] ;WAS THIRD ARGUMENT ONLY? PJRST COMERR## ;NO, ERROR DPB T3,[POINT 12,JBTSPS##(J),35] ;CHANGE SPECIFICATION JRST CPUCM5 ;AND RETURN. CPUCM4: CAME P1,[SIXBIT/ALL/];ARGUMENT #3 MUST BE "ALL" PJRST COMERR## ;WASN'T, ERROR MOVEI T3,7777 ;GET BITS FOR ALL POSSIBLE CPU'S DPB T3,[POINT 12,JBTSPS##(J),35] ;CHANGE SPECIFICATION CPUCM5: PUSHJ P,CPRONE ;CHECK TO SEE IF NEW SPECIFICATION IS VALID PJRST CPOPJ1## ;AND RETURN ;SUBROUTINE TO DETERMINE IF CPU DESIGNATOR IN SET CPU COMMAND ;IS LOGICAL OR PHYSICAL CPU NAME. IF PHYSICAL, MAKE SURE IT EXISTS AND ;SET UP BIT MASK FOR JBTSPS. CALLED WITH SIXBIT ARGUMENT IN T2, ;CPU NUMBER RETURNED IN T1, T2 RETURNED WITH ORIGINAL ARGUMENT, BIT MASK ;RETURNED IN AC T3. T4 RESPECTED. CPUFND::HLLZ T1,T2 ;GET LEFT MOST 3 CHARACTERS CAMN T1,[SIXBIT /CPU/] ;IS ARGUMENT LOGICAL NAME? JRST CPUFN2 ;YES, DOESN'T MATTER IF IT EXISTS MOVEI T3,.C0CDB## ;GET ADDRESS OF FIRST CDB CPUFN1: CAMN T2,.CPPHY##-.CPCDB##(T3) ;THIS CPU? JRST CPUFN2 ;YES, OK TO PROCEED HLRZ T3,.CPCDB##-.CPCDB##(T3) ;GET ADDRESS OF NEXT CDB JUMPE T3,CPOPJ## ;NON-SKIP RETURN IF NON EXISTANT JRST CPUFN1 ;GO LOOK AT NEXT CPUFN2: HRRZ T1,T2 ;CPU NAME OK, MAKE A BIT MASK LSH T1,-14 ;GET SIXBIT NUMBER RIGHT JUSTIFIED SUBI T1,20 ;REDUCE TO BINARY CAIG T1,5 ;LEGAL CPU NUMBER? SKIPGE T1 ; POPJ P, ;ERROR RETURN IF NON EXISTANT MOVEI T3,101 ;MASK FOR CPU0 CPUFN3: LSH T3,(T1) ;POSITION MASK JRST CPOPJ1## ;AND GIVE FOUND RETURN ;SUBROUTINE CALLED BY SIMCHK IN CLOCK1 TO SEE IF JOB WITH EXEC ;MODE PC HAS A RUNNABLE CPU SPECIFICATION. RETURN CPOPJ IF NONE, CPOPJ1 IF RUNNABLE CPSCHK::PUSHJ P,CPRBIT ;SET UP MASK OF RUNNING CPU'S TDNN T2,JBTSPS##(J) ;SKIP IF JOB HAS A RUNNABLE CPU POPJ P, ;NO RUNNABLE CPU'S, STOP JOB MOVE T2,JBTSPS##(J) ;PICK UP SECOND PROCESSOR STATUS TLNE T2,(SP.CC1) ;SKIP IF CONTROL C NOT ON CPU1 TLNE T2,(SP.NR1) ;WAS ON CPU1, SKIP IF NOT IN MIDDLE OF UUO JRST CPOPJ1## ;IS RUNNABLE, CATCH AT UUO EXIT TRNN T2,SP.CR0 ;SINCE CAN'T RUN ON CPU1, SKIP IF RUNNABLE ONCPU0 POPJ P, ;IS NOT RUNNABLE, STOP JOB. JRST CPOPJ1## ;JOB IS RUNNABLE, DEFER STOPPING. ;SUBROUTINE TO BUILD A BIT MASK FOR TESTING JBTSPS ENTRIES. AN ;APPROPRIATE BIT IS SET FOR EACH RUNNING CPU. RETURNS MASK IN T2. CPRBIT: MOVEI T4,.C0CDB## ;GET ADDRESS OF FIRST CDB MOVEI T3,1 ;GET BIT INDICATING CPU0 IS RUNNING SETZ T2, ;CLEAR T2 CPRBT1: SKIPL .CPRUN##-.CPCDB##(T4) ;SKIP IF CPU NOT RUNNING ADD T2,T3 ;SET BIT IN MASK HLRZ T4,.CPCDB##-.CPCDB##(T4) ;GET ADDRESS OF NEXT CDB JUMPE T4,CPOPJ## ;EXIT IF THROUGH LSH T3,1 ;MOVE BIT TO NEXT POSITION JRST CPRBT1 ;AND LOOK AT NEXT CPU ;SUBROUTINE TO CHECK IF A JOB IS RUNNABLE ON ANY PROCESSOR CALLED ;WITH MASK OF RUNNING PROCESSORS IN AC T2 AND JOB NUMBER TO CHECK IN J. CPRONE: PUSHJ P,CPRBIT ;SET UP MASK OF RUNNING CPU'S CPRCHK: TDNE T2,JBTSPS##(J) ;SKIP IF NO RUNNABLE CPU FOR THIS JOB POPJ P, ;OK, RETURN SKIPE U,TTYTAB##(J) ;GET TTY DDB HRRZ U,DDBLDB##(U) ;LDB ADDRESS JUMPE U,CPOPJ## ;NO MESSAGE IF NO TTY PJSP T1,CONMES## ;PRINT MESSAGE TO USER AND CPOPJ ASCIZ /%No Running CPU's in specification / CPRMIN: PUSHJ P,CPRBIT ;GET MASK FOR TESTING JBTSPS SKIPLE J,HIGHJB## ;GET HIGHEST USED JOB NUMBER ; -1 IF NO JOBS HAVE LOGGED IN YET PUSHJ P,CPRCHK ;CHECK TO SEE IF RUNNABLE ON SOME CPU SOJG J,.-1 ;NEXT? POPJ P, ;NO, EXIT $LIT ;GENERATE LITERALS SO CAN CHECK ASCII OCTAL CPNEND: END