Trailing-Edge
-
PDP-10 Archives
-
BB-J092C-SB_1982
-
cpnser.mac
There are 11 other files named cpnser.mac in the archive. Click here to see a list.
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<IO,,0>] ;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,<SP.CPA>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,<APRID INOSCN##>
IFN FTKI10,<CONI PAG,INOSCN##>
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,<APRID INONET##>
IFN FTKI10,<CONI PAG,INONET##>
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<SP.CR0>-^L<SP.CJ0>> ;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,<JOB NUMBER>
; PUSHJ P,SCDCSH
; <JOB NOT RUNNABLE W.R.T. CACHE>
; <JOB RUNNALBE W.R.T. CACHE>
; 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,<OLD JOB NUMBER>
; MOVE J,<NEW JOB NUMBER>
; MOVE P4,<CDB ADDRESS>
; PUSHJ P,SETCSN
; <ONLY RETURN>
;
;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,<SEGMENT NUMBER>
; PUSHJ P,SWPCSH
; <JOB CANNOT BE SWAPPED BECAUSE OF CACHE>
; <OK TO SWAP JOB>
;
; 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,<JOB NUMBER>
; PUSHJ P,CHKCSH
; <SUCCESSFUL RETURN> ;JOB IS RUNNABLE, SWAPPABLE W.R.T. CACHE
; <ERROR RETURN> ;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,<JOB NUMBER>
; PUSHJ P,CLCSN
; <ONLY RETURN>
;
; 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##+<MONORG-400000>/<2*1000>]
>
IFN MONORG&1000,<
MOVE P1,[POINT 18,.EPPM##-.EPMP##+<MONORG-400000>/<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
; <RETURN HERE ON EVENTS 1 AND 3>
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
; <RETURN HERE IF OTHERS RUNNING>
; <RETURN HERE IF WE ARE THE ONLY ONE>
;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