Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - cp1ser.mac
There are 2 other files named cp1ser.mac in the archive. Click here to see a list.
TITLE	CP1SER - SECOND PROCESSOR CONTROL V141
SUBTTL	M. CHURCH - LNS/MIT     P. HURLEY - DEC    08 MAR 77
	SEARCH	F,S

IFN FTKL10,<
	SEARCH DTEPRM		;IF KL10, SEARCH DTE SYMBOLS
>
	$RELOC
	$HIGH
;***COPYRIGHT 1973,1974,1975,1976,1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VCP1SR,141		;VERSION NUMBER FOR LOADER STORAGE MAP



CP1SER:	ENTRY	CP1SER		;LOAD IF SPECIFIED BY COMMON



	EXTERNAL JOBMAX,SYSDSP,.CPUFC,UFC0,TWOREG
	EXTERNAL COMERR,JBTPRV,STOTAC,.C0CDB,.CPCDB,.CPPHY,.CPRUN
	EXTERNAL CPOPJ,INLMES,NXMMES,OPRLDB,PDLMES
	EXTERNAL TTYFNU
	EXTERNAL CONMES,CPOPJ1

;LOW PRIORITY CLOCK ROUTINE FOR SECOND PROCESSOR

	INTERNAL CK1INT
	EXTERNAL .C1CKF,.C1S17,CK1CHL,.C1SCF,.C1ADR,.C1NJD,.C1NPD,.CPAEF,NU1DAT,RSCHED
	EXTERNAL JOBD16,JOBD15,JOBDAC,JBTSPS,JBTSTS
	EXTERNAL JOBD17
	EXTERNAL JBTDAT

CK1INT:	SKIPN	.C1CKF		;CK1 INTERRUPT REQUEST?
	JRST	CK1INT		;NO, CHECK OTHER DEVICES
IFN FTKI10!FTKL10,<
	CONO	PI,II.CCI##	;KI10, CLEAR SOFTWARE REQUESTED INTERRUPT
>
IFN FTKL10,<
	DATAI	PAG,SVPG17	;SAVE CURRENT AC STATUS
	EXECAC			;SWITCH TO EXEC AC BLOCK
>
	MOVEM	17,.C1S17	;SAVE AC 17
	JSR	CT1CLK		;CK FOR CTY CHAR.
	MOVE	17,CK1CHL	;IS CURRENT JOB IN USER MODE?
	TLNN	17,(XC.USR)	;PC IN USER MODE?
	SKIPE	.C1SCF		;NO, IS THIS A FORSCED RESCHEDULING INTERRUPT?
	JRSTF	@[XWD XC.UOU##,SAVPC1] 	;YES, IT IS OK TO RESCHEDULE NOW
	MOVE	17,.C1S17	;NO, LEAVE TIMEF SET AND DISMISS INT.
IFN FTKL10,<
	DATAO	PAG,SVPG17	;RESTORE AC SET
>
	JEN	@CK1CHL		;DISMISS

SAVPC1:	MOVEM	17,.C1PC	;SAVE PC IN PROTECTED PART OF SYSTEM DATA
				; STORAGE FOR CURRENT JOB
IFN FTKI10!FTKL10,<
	TLNE	17,(XC.USR)	;PC IN USER MODE?
	JRST	CK1SPD		;PC IN USER MODE, DON'T NEED TO SAVE ACS
				; SINCE IT WILL BE DONE AT CONTEXT SWITCH
>
	SKIPN	17,.C1ADR	;CURRENT JOB DATA AREA, IS THERE ONE?
	MOVE	17,.C1NJD	;NO, MUST BE NULL JOB OR CORE 0
				; RUNS AT UUO LEVEL,REQUESTS CK1 INT. TO STOP
	MOVEM	16,JOBD16(17)	;SAVE AC 16 IN DUMP AC PART OF JOB DATA AREA
	MOVEI	16,JOBDAC(17)	;SOURCE=0,DESTINATION=DUMP AC 0
	BLT	16,JOBD15(17)	;SAVE ACS 0-15 JUST BELOW AC 16
	MOVE	T1,.C1S17	;NOW SAVE 17 IN JOB DATA AREA
	MOVEM	T1,JOBD17(17)	;ALONG WITH OTHER ACS
CK1SPD::MOVE	P,.C1NPD	;SET UP PUSH DOWN LIST IN NULL JOB DATA
				; AREA IN LOWER CORE
	MOVEI	P4,.C1CDB	;GET CDB OFFSET FOR THIS PROCESSOR
	MOVE	S,.C1AEF##	;IT THIS AN ERROR INTERRUPT?
	JUMPE	S,RSCHED	;NON-ZERO IF YES
	PUSHJ	P,AP1ERR	;YES, GO PROCESS ERROR,APRILM WILL CLEAR .CPAEF
				; FLAG IMMEDIATELY 
	  JRST	RSCHED		;NOT PDL OV - RESCHEDULE

;CALL SCHEDULER TO GET NEXT JOB FOR SLAVE
;SCHEDULER IS PURE EXCEPT FOR ENTRY AND DISMISSING
;SCHEDULER WILL RETURN HERE TO START THE NEXT JOB ON THE SLAVE

	INTERNAL SCIP8A
	EXTERNAL CURJOB
SCIP8A:	HRLM	J,CURJOB	;DISPLAY JOB NUMBER IN LOW CORE
IFN FTKI10!FTKL10,<
	MOVE	T1,.C1PC	;GET THE PC
	TLNE	T1,(XC.USR)	;IS THE PC IN USER MODE?
IFN FTKI10,<
	JEN	@.C1PC		;PC IN USER MODE, USER ACS ARE ALREADY SETUP
>
IFN FTKL10,<
	JRST	[USERAC		;SETUP USER AC BLOCK
		JEN @.C1PC]	;GO TO THE USERS
>
>
	MOVSI	17,JOBDAC(R)	;RESTORE DUMP ACS FROM REL.20 IN JOBDATA
	BLT	17,17	
	JEN	@.C1PC		;DISMISS

IFN FTKL10,<
	$LOW
SVPG17:	0			;SAVE CONTENTS OF PAG HERE
	$HIGH
>
;HERE ON UUO FROM USER ON SECOND PROCESSOR.
;USER AC17 SAVED IN LOC USRSAV+OFFSET

	EXTERNAL MJOBPD,JOBPDL,JOBAC
	EXTERNAL SPTRAP,.C1SAV,JOBDAC,UUOSP0,MPUUO
	EXTERNAL .C0SCN,.C1CDB,.C1PC,.C1JOB,.C1LJU,.C1PUC,.C1QUE,.C1SCN
	INTERNAL UUOUSP

UUOUSP:	PUSH	P,UUOSP0	;SAVE RETURN ON PD LIST
	MOVE	M,SPTRAP	;GET CONTENTS OF 140 INTO AC M
IFN FTKA10,<
	MOVEI	P4,.C1CDB##	;POINT TO CPU1'S CDB
>
	LDB	T1,[POINT 9,M,8];GET THE UUO OP CODE
	ROT	T1,-1		;DIVIDE BY 2, SAVE REMAINDER IN BIT 0
	MOVE	T2,CHKTAB##-20(T1)
UUOUS1:	SKIPL	T1		;ODD OR EVEN OPCODE?
	MOVSS	T2		;EVEN, SWAP HALVES
	TRNN	T2,UU.CP1	;CAN THIS UUO BE EXECUTED ON CPU1?
	JRST	UUOUS2		;CAN'T BE EXECUTED ON CPU1
	ROT	T1,1		;RESTORE ORIGIONAL OPCODE
	CAIE	T1,<CALLI>B62	;THIS DEPENDS ON CALLI 47 BEING
				; EXECUTABLE ON CPU1
	JRST	SMUUO2		;CAN BE BUT NOT A CALLI
	HRRE	T1,M		;CALLI NUMBER (NEGATIVE IF CUSTOMER DEFINED)
	TRNN	T1,400000	;POSITIVE CALLI NUMBER?
	TRZA	T1,UPHNLY	;YES, CLEAR PHYSICAL ONLY BIT
	TRO	T1,UPHNLY	;NEGATIVE, MAKE SURE TRUE NEGATIVE INDEX
	CAML	T1,MCCLEN##	;LESS THAN THE MAXIMUM CUSTOMER DEFINED CALLI?
	CAIL	T1,UCILEN##	;OR GREATER THAN THE MAXIMUM DIGITAL DEFINED CALLI
	JRST	USPRET##	;YES, POPJ NOP
	ROT	T1,-1		;DIVIDE BY 2 AGAIN
	MOVE	T2,CHKTBC##(T1)	;GET CALLI CHECK BITS
	JRST	UUOUS1		;SEE IF THE CALLI CAN BE EXECUTED ON CPU1
;HERE TO RESCHEDULE JOB ON MP (MASTER PROCESSOR) WHEN CANNOT DO UUO ON SP
UUOUS2:	MOVEM	P,JOBDAC+P(R)	;SAVE P
	MOVEM	R,JOBDAC+R(R)	;SAVE PROG
	MOVEM	M,JOBDAC+M(R)	;ALL NECESSARY AC'S HAVE BEEN SAVED
	MOVE	T1,[XWD XC.UOU##,SMUUO1] ;GET START ADR ON MASTER
;HERE TO RESCHEDULE JOB ON THE MASTER WHEN A UUO CANNOT COMPLETE ON SP
UUOUS3:	MOVE	J,.C1JOB	;CURRENT CPU1 JOB NUMBER
	HRL	J,.C1QUE	;SAVE THE QUE CODE FOR THIS JOB ALSO
	MOVEM	J,.C1LJU	;SAVE LAST JOB WHICH DID A UUO
	AOS	.C1PUC		;MARK THAT A UUO MUST BE DONE BY MASTER
UUOUS4:	MOVSI	T2,(SP.NR1)	;MAKE UNRUNNABLE ON SLAVE
	IORM	T2,JBTSPS(J)	;BY LIGHTING UNRUNNABLE(SLAVE) BIT
UUOUS5:	MOVEM	T1,.C1PC##	;STORE THE PC
	JRST	CK1SPD		;THEN GO RESCHEDULE

;HERE AFTER RESCHEDULED ON MASTER CPU
SMUUO1:	MOVE	T1,(P)		;PC STORED BY UUO TRAP (ON CPU1)
	MOVEM	T1,UUO0##	;STORE AS IF UUO TRAP HAPPENED ON CPU0
				; (ONLY NEEDED IN CASE ANY CALL TO UUOERR)
	MOVEM	M,MPTRAP##
	MOVEI	P4,.C0CDB##
SMUUO2:	MOVE	J,.CPJOB##(P4)	;UUOERR CALLS GIVRES, WHICH NEEDS J
	MOVEI	F,0		;ALSO F DOES NOT POINT TO ADDB
	TLNE	M,740000	;TO MONITOR UUO (40-77)?
	JRST	MPUUO		;YES, GO DO UUO
	JRST	UUOERR##	;NO, PRINT ERROR (CHECK OCCURS BEFORE
				; STUFF IS PUT ON PD LIST WHICH OBSCURES LAST POPJS

;SUBROUTINE TO INSURE JOB IS ON CPU0
;CALLING SEQUENCE:
;	PUSHJ	P,ONCP0S
;RETURNS CPOPJ IF ALREADY ON CPU0, CPOPJ1 IF
; RESCHEDULING WAS REQUIRED TO GET THERE

ONCP0S::SKPCPU	(1)		;ALREADY ON CPU0?
	POPJ	P,		;YES, NON-SKIP RETURN
	AOS	(P)		;SKIP RETURN
;FALL INTO ONCPU0

;SUBROUTINE TO INSURE THAT A JOB IS ON CPU0
;CALLING SEQUENCE:
;	PUSHJ	P,ONCPU0
;ALWAYS RETURNS CPOPS ON CPU0

ONCPU0::SKPCPU	(1)		;ALREADY ON CPU0?
	POPJ	P,		;YES, JUST RETURN
	PUSH	P,UUOSP0##	;ON CPU1, SAVE CPU1 MUUO
	MOVEM	17,JOBD17##(R)	;SAVE AC17
	MOVEI	17,JOBDAC##(R)	;SAVE ACS 0-16
	BLT	17,JOBD16##(R)	; IN THE JOB DATA AREA
	JSP	T1,UUOUS3	;CAUSE THE JOB TO BE RESCHEDULED ONTO CPU0
;RETURN HERE ON CPU0
	POP	P,UUO0		;RESTORE MUUO PC WHERE CPU0 EXPECTS IT
	POPJ	P,		;RETURN TO THE CALLER ON CPU0

;CODE CALLED FROM USRXIT TO SEE IF MUST RESCHEDULE

	EXTERNAL USCHED,JBTSPS,.C0JOB
	INTERNAL UXITMP

UXITMP:	MOVEI	T1,SP.CR0	;TEST IF USER CAN RUN ON MASTER
	TDNE	T1,JBTSPS(J)	
	AOS	(P)		;YES HE CAN, SKIP RETURN
	POPJ	P,		;AND RETURN

;HERE TO EXIT FROM A UUO WHICH WAS EXECUTED ON CPU1

USPXIT::MOVE	J,.C1JOB##	;CURRENT CPU1 JOB NUMBER
	MOVE	T2,[XWD STOPIO!CNTRLC,JS.DEP!JS.MPE]
	TDNN	T2,JBTSTS##(J)	;SHOULD THE JOB BE STOPPED? (USER TYPED
				; CONTROL C DURING THE UUO, MEMORY PARITY
				; ERROR IN UUO ARGUMENT LIST, DAEMON ERROR
				; PAUSE, OR TRYING TO STOP I/O)
	SKIPE	.C1TMF##	;CLOCK TICK DURING UUO PROCESSING?
	SKIPA	T1,[XWD XC.UOU##,UUODON##]
	JRST	USRRET##	;CONTINUE WITH CURRENT USER
	MOVEM	R,JOBDAC##+R(R)	;SAVE PROTECTION,,RELOCATION
	MOVEM	J,JOBDAC##+J(R)	;SAVE CURRENT JOB NUMBER
	MOVEM	P,JOBDAC##+P(R)	;SAVE PUSH DOWN LIST POINTER
	TDNN	T2,JBTSTS##(J)	;MUST THE JOB BE RUN ONLY ON CPU0?
	JRST	UUOUS4		;YES, MAKE IT UNRUNNABLE ON CPU1
	JRST	UUOUS5		;NO, CLOCK JUST TICKED (CALL SCHEDULAR)
				; LEAVING THIS JOB RUNNABLE ON CPU1


;MTSUUO MAKES A JOB DOING A UUO STAY ON THE MASTER CPU FOR THE
; DURATION OF THE UUO.  SP.NR1 GETS CLEARED AT USRXIT.

	INTERNAL MSTUUO
MSTUUO:	MOVE	J,.C0JOB	;GET JOB NUMBER ON CPU0
;SUBROUTINE TO MAKE SURE JOB CAN GET SCHED ON CPU0 FOR APR ERROR MESSAGE
; NEEDED IN CASE JOB IS SET TO RUN ON CPU1 ONLY
CP1APE::MOVSI	T2,(SP.NR1)	;PREPARE TO SET NO RUN SLAVE BIT
	IORM	T2,JBTSPS(J)	;SET BIT
	POPJ	P,		;AND RETURN
;ROUTINE TO CHECK IF JOB CAN RUN ON EITHER OR BOTH CPUS
;CALL:	MOVE	J,JOB NUMBER
;	PUSHJ	P,SAVE4		;P4 SAVED
;	PUSHJ	P,CHKCPU
;	  JOB IS SET TO RUN ONLY CPU1 - P4=CPU1CB
;	JOB WAS SET TO RUN ON ALL CPUS OR JUST CPU0 - NOW SET TO CPU0 ONLY
;	P4=CPU0CB
;CALLED BY TRPSET AND RTTRP

CHKCPU::MOVEI	P4,.C1CDB##	;ASSUME JOB IS ON CPU1
	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	P4,.C0CDB##	;YES, RETURN CPU0 CDB ADR
	MOVEI	T1,SP.CR1	;CLEAR CAN RUN ON CPU1
	ANDCAM	T1,JBTSPS(J)	;SO WILL ONLY RUN ON CPU0
	JRST	CPOPJ1		;RETURN ON CPU0 ONLY

;SUBROUTINE TO CHECK IF TRPSET UUO IS ALLOWED ON DUAL SYSTEM
;CALL:	MOVE	J,JOB NUMBER
;	PUSHJ	P,CPUTRP
;	  CANNOT - ON CPU1 ONLY AND NOT LOCKED IN CORE
;	OK - WAS ON BOTH CPUS OR JUST CPU0 - NOW ON CPU0 ONLY

IFN FTTRPSET,<			;TRPSET UUO FEATURE?
CPUTRP::PUSHJ	P,CHKCPU	;IF JOB IS ON BOTH CPUS FORCE TO CPU0
IFN FTLOCK,<			;LOCK UUO FEATURE?
	  PUSHJ	P,LOKCHK##	;JOB IS ONLY ON CPU1 - IS IT LOCKED IN CORE?
>
IFE FTLOCK,<			;LOCK UUO FEATURE?
	  POPJ	P,		;JOB IS ONLY ON CPU1 - CANNOT BE LOCKED
>
	JRST	CPOPJ1##	;OK RETURN, JOB WAS ON CPU0 OR BOTH - NOW ONLY ON CPU0
				; OR IS ON CPU1 ONLY AND LOCKED IN CORE
IFN FTLOCK,<
	POPJ	P,		;ERROR RETURN JOB IS ON CPU1 ONLY AND ISN'T LOCKED IN CORE
>
>				;END FTTRPSET FEATURE

;HERE FROM COMCON TO TEST IF JOB ON SLAVE, BEFORE DOING CONTROL C

	INTERNAL SPSTOP

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.CJ1)	;TEST IF JOB IS CURRENT JOB ON SLAVE PROCESSOR
	TDNN	T2,JBTSPS(J)
	AOS	(P)		;NO, SKIP RETURN AND DONT DELAY COMMAND
	JRST	ULKSCD		;TURN OFF INTERLOCK


;HERE FROM COMCON, RUN UUO, AND TO CLEAR SP.NR1 AT END OF A UUO

	INTERNAL DPXST

DPXST:	MOVSI	T1,(SP.NR1)	;CLEAR THE UNRUNNABLE BIT FOR SLAVE
	ANDCAM	T1,JBTSPS(J)	;JOB CAN NOW RUN ON SLAVE
	POPJ	P,


;HERE TO CLEAR MULTIPROCESSOR STATUS BITS

	INTERNAL CLRJSP

CLRJSP:	PUSH	P,T1		;SAVE A WORKING AC
	MOVSI	T1,(SP.NR1)	;MAKE JOB UNRUNNABLE ON SLAVE
	IORM	T1,JBTSPS(J)
	HRLOI	T1,(SP.NR1+SP.CJ0+SP.CJ1) ;CLEAR LEFT HALF OF ALL BUT TWO RUN BITS
	ANDM	T1,JBTSPS(J)
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

;ROUTINE TO SET INITIAL CONDITIONS FOR CPU RUNNABILITY
;CALLED FROM CLOCK1 - CLRJBT

	INTERN SETJSP
SETJSP:	MOVEI	T1,<SP.CR0+SP.CR1>B29+SP.CR0+SP.CR1	;MAKE JOB RUNNABLE ON ALL CPU'S
	MOVEM	T1,JBTSPS(J)
	POPJ	P,		;AND RETURN

;ROUTINE TO CLEAR CONTROL C TYPED BIT
;CALLED FROM CLOCK1-WHEN JOB CAN BE STOPPED

	INTERN CLRCCB

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

	INTERNAL ANYRUN

ANYRUN:	PUSHJ	P,LOKSCD	;TURN ON INTERLOCK
IFN FTTRPSET,<
	CAMN	J,.C1STS	;ALSO LOOK LIKE ACTIVE DEV IF STOPTS ON SLAVE
	JRST	ULKSCD		;YES, GO ULKSCD AND POPJ RETURN
>
	PUSH	P,T2		;SAVE AN AC
IFN FT2REL,<	EXTERNAL JBTSGN
	MOVE	T2,.C1JOB	;GET SLAVE PROCESSOR JOB NUMBER
	HRRZ	T2,JBTSGN(T2)	;GET HIGH SEGMENT NUMBER FOR THAT JOB
	CAIN	T2,(J)		;IS THIS A HIGH SEGMENT RUNNING ON SLAVE?
	JRST	ANYRN1		;YES, GIVE NO SHUFFLE RETURN
	CAILE	J,JOBMAX	;IS THIS A HIGH SEGMENT?
	JRST	ANYRN0		;YES, DONT CHECK JBTSPS TABLE
>
	MOVSI	T2,(SP.CJ1)
	TDNN	T2,JBTSPS(J)	;TEST IF RUNNING ON SLAVE
ANYRN0:	AOS	-1(P)		;NOT RUNNING, GIVE SKIP RETURN
ANYRN1:	POP	P,T2		;RESTORE WORKING AC
	JRST	ULKSCD		;GO ULKSCD AND POPJ RETURN

;HERE ON MASTER FROM CLOCK1 ONCE A MINUTE TO CHECK IF CPU1 IS RUNNING
;IF CPU1 IS NOT RUNNING, TYPE OUT APPROPRIATE MESSAGES TO OPERATOR

	INTERNAL CP1CHK
CP1CHK:	PUSHJ	P,CPRMIN	;CHECK TO SEE IF ALL JOBS HAVE RUNNABLE SPECIFICATIONS
	SKIPG	.C1OK		;IS DUAL PROCESSOR OK?
	POPJ	P,		;YES, JUST RETURN
	MOVEI	T1,.C1CDB	;NO, FIND OUT IF CPU1 IS RUNNABLE
	SKIPGE	.CPRUN(T1)	;IS CPU1 RUNNABLE?
	POPJ	P,		;NO, NO MESSAGE
	HRRZ	U,OPRLDB	;YES, GET OPR TTY DDB
	MOVEI	T1,[ASCIZ/%
%Problem on CPU1
/]
	JRST	CONMES		;GO TYPE OUT MESSAGE
;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)

	INTERNAL MSCHED,SSCHED
	EXTERNAL SCHEDJ,.C0PUC,.C1PUC

MSCHED:
IFN FTTRPSET,<
	SKIPE	J,.C0STS##	;DID ANYONE STOP TIME SHARING?
	JRST	MRNBL1		;YES, SEE IF HE IS RUNNABLE
>
	SKIPE	J,.C1PUC	;SLAVE PROCESSOR FLAG ON?
	JRST	MRNBL2		;YES, GO SEE IF SLAVE JOB TO RUN
	
	EXTERNAL SSCAN		;SSCAN DEFINED IN SCHED

MSCALL:	SETZM	.CPUFC(P4)	;CLEAR UUO FAIRNESS COUNT
	PUSHJ	P,SCHEDJ	;DISPATCH TO SCHED CODE
MSEL:	MOVSI	T1,(SP.CJ0)	;PICK UP RUN BIT FOR MASTER PROCESSOR
	MOVE	F,.C0JOB	;GET LAST JOB NUMBER
	ANDCAM	T1,JBTSPS(F)	;TURN OFF RUNBIT FOR OLD JOB
	IORM	T1,JBTSPS(J)	;TURN ON RUNBIT FOR NEW 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,MPRUN		;SECOND STATUS WORD BITS OK?
	  JRST	MSNULL		;JOB UNRUNNABLE, GO RUN NULL JOB
	JRST	MSEL		;JOB RUNNABLE, GO TO IT

;TEST IF JOB WHICH NEEDS UUO IS RUNNABLE, AND CLEAR FLAG
	EXTERNAL .C0QUE,QSCAN,SSCAN

MRNBL2:	AOS	T1,.CPUFC(P4)	;COUNT UP UUO FAIRNESS COUNT
	CAILE	T1,UFC0		;IS IT GREATER THAN THE MAXIMUM?
	JRST	MSCALL		;YES, GO DO A NORMAL SCHEDULE
	SKIPN	J,.C1LJU	;WHAT WAS THE LAST JOB TO DO A UUO
	JRST	MRNBL3		;THERE WASN'T1 ONE
	SETZM	.C1LJU		;ZERO FLAG SO WE DONT TRY TO USE IT TWICE
	HLLZ	T2,J		;GET THIS JOB'S QUEUE CODE
	HRRZS	J		;GUARANTEE THAT J IS ONLY JOB NUMBER
	LDB	T1,PJBSTS##	;T1=JOBS QUEUE CODE
	JUMPN	T1,MRNBL3	;JUMP IF THE JOB IS NOT RUNNABLE NOW
				; CAN HAPPEN IF MASTER RAN THE JOB BEFORE
				; SLAVE SETUP .C1LJU
	SKIPGE	T1,JBTSTS(J)	;IS THIS JOB RUNNABLE
	TLNE	T1,SWP+SHF+JXPN+JRQ
	JRST	MRNBL3		;NO, JOB IS NOT RUNNABLE
IFN FTKL10,<
	PUSHJ	P,CHKCSH	;IS JOB RUNNABLE W.R.T. CACHE?
				; (ALWAYS IS SINCE CPU1 DOES SWEEP
				;  IF IT SEES JOB DID MASTER UUO,
				;  THIS CALL IS FOR SAFETY)
	  JRST	.+2		;SUCCESS RETURN, OK
	JRST	MRNBL3		;SORRY, LOOK FOR OTHER UUO DOERS
>;END IFN FTKL10
IFN FTLOCK,<
	TRNN	T1,LOK>		;OR IS JOB TRYING TO LOCK?
	PUSHJ	P,MPRUN		;TEST SECOND STATUS WORD BITS
MRNBL3:	  SKIPA	U,.C1SCN	;NOT RUNNABLE, CALL SCHEDULER WITH U SET UP
	JRST	MRNBL4		;IS RUNNABLE, RUN IT NOW
	JSP	T1,QSCAN	;GO SCAN RUN QUEUES
	  JRST	MRNBL5		;NO RUNNABLE JOBS NOW (COULD HAPPEN IF SWAPPER DECIDES
				; TO SWAP OUT JOB AFTER IT HAS DONE UUO ON CPU1
	MOVE	F,JBTSPS(J)	;GET STATUS BITS
	TLNN	F,(SP.NR1)	;DID THIS JOB DO A UUO (NOT RUNABLE ON CPU1)
	JRST	(T2)		;NO, CONTINUE SCANING
	MOVE	F,NRNMSK	;GET OTHER STATUS BITS
	TDNN	F,JBTSTS(J)	;JOB RUNNABLE?
	PUSHJ	P,MPRUN		;YES, MAYBE
	  JRST	(T2)		;NO, CONTINUE SCANNING
IFN FTKL10,<
	PUSHJ	P,CHKCSH	;IS JOB RUNNABLE W.R.T. CACHE?
				; (ALWAYS IS, SEE COMMENT AT PUSHJ
				;  TO CHKCSH ABOVE)
	  JRST	MRNBL4		;OK, HE WINS
	JRST	(T2)		;NOT OK, LOOK FOR NEXT JOB
>;END IFN FTKL10
MRNBL4:	SOS	.C1PUC		;YES, COUNT DOWN NUMBER OF UUO'S TO BE DONE
	HLREM	T2,.C0QUE	;SAVE THE QUEUE NUMBER FOR CPU0
	JRST	MSEL		;AND GO RUN IT

;SELECT NULL JOB BECAUSE JOB WHICH STOPPED TIME SHARING CANNOT RUN
MSNULL:	SETZ	J,
	JRST	MSEL
;HERE WHEN COULD NOT FIND A JOB WHICH HAD JUST DONE A CPU1 UUO AND IS STILL RUNABLE

MRNBL5:	SOS	.C1PUC		;COUNT DOWN UUO COUNTER TO AVOID OVERHEAD SCANNING
	JRST	MSCALL		;GO LOOK FOR ANY RUNNABLE JOB
;CALLED BY SLAVE PROCESSOR
SSCHED:
IFN FTTRPSET,<
	SKIPE	J,.C1STS##	;T/S STOPPED (TRPSET UUO)?
	JRST	SRNBL1		;YES, SEE IF JOB IS RUNNABLE
>
	SKIPE	J,.C0PUC	;FLAG FROM MASTER PROCESSOR ON?
	SETZM	.C0PUC		;CLEAR MASTER PROCESSOR'S FLAG WORD

	PUSHJ	P,SCHEDJ	;DISPATCH TO SCHED CODE
SSEL:	MOVSI	T1,(SP.CJ1)	;GET SLAVE RUN BIT
	MOVE	F,.C1JOB	;GET LAST JOB NUMBER
	ANDCAM	T1,JBTSPS(F)	;CLEAR RUNBIT FOR LAST JOB
	IORM	T1,JBTSPS(J)	;SET RUNBIT FOR NEW JOB
	POPJ	P,		;AND RETURN


;TEST IF JOB WHICH STOPPED T/S IS RUNNABLE
SRNBL1:	MOVE	T1,NRNMSK	;GET NON RUNNABLE MASK
	TDNN	T1,JBTSTS(J)
	PUSHJ	P,SPRUN		;TEST JBTSPS BITS
	MOVEI	J,0		;JOB UNRUNNABLE, RUN NULL JOB
	JRST	SSEL		;JOB RUNNABLE, GO RUN 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 EITHER PROCESSOR

	INTERNAL DXRUN

DXRUN:	SKPCPU	(1)		;TEST WHICH PROCESSOR
	JRST	MPRUN		;WAS MASTER PROCESSOR
				;WAS SLAVE, FALL INTO SPRUN



;ROUTINE CALLED WHEN SLAVE IS RUNNING SCHED, TO SEE
;IF JBTSPS BITS PERMIT JOB TO RUN ON SLAVE.
;SKIP RETURN IF JOB IS RUNNABLE.

SPRUN:	SKIPGE	.CPRUN##(P4)	;IS CPU RUNNABLE?
	POPJ	P,		;NO, TAKE CAN NOT RUN RETURN
	MOVE	F,JBTSPS(J)	;GET DUPLEX STATUS
	TLNE	F,(SP.NR0)	;DOES THIS JOB HAVE A UUO TO BE DONE ON SLAVE
	JRST	SPRUN1		;YES, GO DO IT
	TRNN	F,SP.CR1	;JOB OK TO RUN ON SLAVE
	POPJ	P,		;NO, TAKE NON-SKIP RETURN

SPRUN1:	TLNE	F,(SP.NR1+SP.CJ0+SP.CC1) ;RUNNING ON MASTER OR UNRUNNABLE ON SLAVE?
	POPJ	P,		;YES, GIVE CANNOT RUN THIS JOB RETURN
	MOVEI	F,JS.APE	;CHECK APR ERROR BIT
	TDNE	F,JBTSTS(J)	;IF SET DON'T RUN JOB
	POPJ	P,		;JOB HAD AN ERROR, LET CPU0 TYPE MESSAGE
	MOVEM	J,.CPPLT##(P4)	;NO, FLAG POTENTIALLY LOST IF CAN'T RUN HIM
				; BECAUSE OF MONITOR BIND
	CAMN	J,SW0JOB##	;WANT TO SWAP THIS JOB?
	POPJ	P,		;YES, DONT RUN IT THEN
	SKIPG	F,JBTSGN(J)	;GET HIGH SEG NO., SPY OR NONE?
	JRST	CPOPJ1		;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?
				; BY THE MASTER
	AOS	(P)		;NO, GIVE CAN RUN THIS JOB RETURN
	POPJ	P,		;YES, GIVE CAN NOT RUN THIS JOB RETURN
;ROUTINE CALLED WHEN MASTER IS RUNNING SCHED, TO SEE IF JOB IS RUNNABLE
;ON MASTER.  SKIP RETURN IF IS.  NOTE AC ASSIGNMENTS SENSITIVE.


MPRUN:	MOVE	F,JBTSPS(J)	;GET STATUS WORD
	TLNE	F,(SP.NR1)	;DOES JOB HAVE UUO TO BE DONE
	JRST	MPRUN1		;YES
	SKIPL	.CPRUN##(P4)	;SKIP IF CUP0 NOT RUNNABLE
	TRNN	F,SP.CR0	;CAN JOB RUN ON MASTER
	POPJ	P,		;NO, TAKE NON-SKIP RETURN

MPRUN1:	TLNN	F,(SP.NR0+SP.CJ1)	;NOT RUNNABLE OR SLAVE CURRENT JOB?
	AOS	(P)		;OK TO RUN, TAKE SKIP RETURN
	POPJ	P,		;RETURN

;ROUTINE TO FORCE MASTER TO DO FAST SCHEDULING
;OF JOBS WAITING FOR UUO'S TO BE DONE

	INTERNAL MSRQT,MSIPUC

MSRQT:	JUMPE	U,CPOPJ##	;IF JOB IS COMING OUT OF WS, TS, OR DS
	CAIG	U,DSQ##		;NOTE THAT WE NOW HAVE A RUNNABLE
MSIPUC:	AOS	.C1PUC		; JOB WHICH THE MASTER MUST HANDLE
	POPJ	P,		; RETURN

IFN <FTKI10!FTKL10>&FTSET,<
;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 SOME OTHER CPU
;CALL WITH:
;	MOVEI	J,JOB-TO-TEST
;	PUSHJ	P,OTHCPU
;	  RETURN HERE IF ON OTHER CPU
;	RETURN HERE IF NOT ON OTHER CPU
;

OTHCPU::MOVSI	T2,(SP.CJ1)	;ASSUME ON CPU0
	SKPCPU	(0)		;ON CPU0?
	MOVSI	T2,(SP.CJ0)	;ON CPU1, SEE IF THIS IS CPU0 JOB
	TDNN	T2,JBTSPS##(J)	;SEE IF JOB IN J IS ON THE OTHER CPU
	AOS	(P)		;NOT--SKIP RETURN
	POPJ	P,
IFN <FTKI10!FTKL10>&FTLOCK,<
;SUBROUTINE TO COPY A PORTION OF THE USER'S MAP INTO
; CPU1'S MAP.
;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::ADDI	T1,.E12OF##	;OFFSET TO MAKE MAPUEI COPY USER'S MAP TO CPU1'S MAP
	PJRST	MAPUEI##	;COPY USER'S MAP TO CPU1'S MAP
>
IFN FTLOCK&FTVM,<
;SUBROUTINE TO MAP THE UPMP OF A JOB BEING LOCKED INTO
; CPU1'S MAP
;CALLING SEQUENCE:
;	MOVE	T2,BYTE POINTER TO CPU0'S MAP
;	MOVE	T3,CONTENTS OF UPMP MAP SLOT
;	PUSHJ	P,MAPUC
;	ALWAYS RETURN HERE
;PRESERVES T1

MAPUC::	ADDI	T2,.E1OFS##	;ADD OFFSET FROM CPU0'S TO CPU1'S MAP
	DPB	T3,T2		;MAP THE UPMP THERE
	POPJ	P,		; AND RETURN
>
IFN FT2SEGMON&FTMOFFL,<
;SUBROUTINE TO INSURE THAT CPU1 IS IN ITS ACS BEFORE CHANGING
; THE EXEC MAP.  RETURNS POPJ OF NOT, CPOPJ1 IF SO

CP1STP::SKIPL	.C1OK		;CPU1 RUNNING?
	JRST	CPOPJ1##	;NO, OK TO CHANGE THE EXEC MAP
	MOVE	T1,.E1IL##	;"140",SETOMED IF CPU1 STUCK IT HEAD IN THE SAND
	AOJE	T1,CPOPJ1##	;IF MINUS ONE, CPU1 IS QUIENTLY RELAXING
	POPJ	P,		;CPU1 IS BUSY, WAIT AWHILE
>
;ROUTINES TO HANDLE VARIOUS CPU1 ERROR CONDITIONS ON CPU1
; ONLY GET HERE ON SERIOUS EXEC MODE ERRORS OR MEM PARITY

	INTERN SVTYPE,SVMES

AP1ERR:	JUMPGE	S,AP1ER0	;APR ERROR
	PUSHJ	P,PARSWP##	;NO, MEM PARITY - SWEEP CORE ON CPU1
				; FLAG JOBS WITH BAD PARITY
				; DO NOT PRINT SINCE THIS IS CPU1
	SETZM	.C1AEF##	;CLEAR CPU1 APR ERROR FLAG
	PJSP	T1,SPTOPR	;FLAG CPU0 TO PRINT MESSAGE ON NEXT
				; CLOCK TICK TO OPR.  CPU1 LOOP UNTIL
				; CPU0 STARTS MESSAGE
	ASCIZ	/Mem par err/	;THE MESSAGE
;NOTE: CPU1 HAS REQUESTED CPU0 TO PRINT RANGE ON OPR
; AND USER'S CONSOLES.  BOTH OF THESE MESSAGES ARE IN ADDITION TO THIS ONE ABOVE
;HERE ON ANY APR ERROR ON CPU1
AP1ER0:	SETZM	.CPAEF(P4)	;CLEAR SLAVE ERROR FLAG
	TRNN	S,AP.NXM	;IS THIS A NXM ERROR FOR EXEC
	JRST	AP1EPD		;NO, CHECK IF IT IS A PDL OV ERROR
	MOVEI	T1,NXMMES	;PREPARE TO TYPE OUT "NXM ERROR"
AP1TYP:	PUSHJ	P,SPTYPE	;GO TYPE OUT MESSAGE POINTED TO BY T1
	STOPCD	CPOPJ,DEBUG,C1N, ;++CPU 1 NXM

AP1EPD:	TRNN	S,AP.POV	;IS THIS A PDL OV ERROR
	JRST	AP1EHD		;AWK! THIS IS A HARDWARE ERROR PERHAPS
	MOVEI	T1,PDLMES	;TYPE OUT PDL OV MESSAGE
	JRST	AP1TYP

AP1EHD:	MOVEI	T1,[ASCIZ/Unexplicable APR error/]
	JRST	AP1TYP		;TYPE THIS ERROR MESSAGE AND HALT

IFN FTKL10,<
SUBTTL MULTIPROCESSING KL10 CACHE CONTROL



;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	P4,<CPU DATA BLOCK ADDR>
;	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##(P4)	;NOT OK, SCHEDULER HAS TO IGNORE AGAIN
	MOVEM	J,.CPCLF##(P4)	;IN CASE NOTHING ELSE IS RUNNABLE
	POPJ	P,		;RETURN AND SAY RUN SOMEONE ELSE
;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>
;	MOVE	P4,<CPU DATA BLOCK ADDR>
;	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?
	POPJ	P,
SWPCS1:	PUSHJ	P,CHKCSH	;DO THE REAL WORK
	  JRST	CPOPJ1##	;EVERY THING IS BEAUTIFUL
				; (IN ITS OWN WAY)
	AOS	.CPCSD##(P4)	;INCREMENT SWAPPER CACHE DELAY COUNT
	POPJ	P,		;BECAUSE SWAPPER HAS BAD NEWS COMING


;SUBROUTINE TO INSURE CPU1'S CACHE HAS BEEN SWEPT IF NECESSARY
; CALL IS:
;
;	MOVE	J,<JOB NUMBER>
;	PUSHJ	P,CKCP1C
;	  <OK TO PROCEED>
;	<NEED TO DELAY>

CKCP1C::PUSH	P,P4		;SAVE P4
	MOVEI	P4,.C1CDB##	;ASK ABOUT CPU1
	PUSHJ	P,CHKCSH	;CHECK STATE OF CPU1'S CACHE W.R.T. THIS JOB
	  CAIA			;OK
	AOS	-1(P)		;NEED TO WAIT FOR A SWEEP
	POP	P,P4		;RESTORE P4
	POPJ	P,		;AND RETURN
;ROUTINE TO CHECK THE STATE OF THE CACHE FOR A JOB
; CALLED ONLY BY SCDCSH, SWPCSH
; CALL:
;	MOVE	P4,<CPU DATA BLOCK ADDRESS>
;	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


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
	CAIN	T3,(P4)		;WAS LAST CPU SAME AS THIS ONE?
	POPJ	P,		;YES, ALL IS OK
	MOVE	T4,.CPCSN##(T3)	;NO, MUST CHECK CURRENT SWEEP NUMBER ON OLD CPU AGAINST
	CAMLE	T4,JBTCSN##(J)	; 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##(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::	PUSH	P,T1		;SAVE T1
	SETZ	T1,
	HRRM	T1,JBTST3##(J)	;JUST CLEAR OUT CDB ADDRESS, MAKING
				; JBTCSN ENTRY INVALID
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

;ROUTINE TO SET UP JBTST3 AND JBTCSN WITH CDB ADDRESS AND CURRENT
; SWEEP SERIAL NUMBER USING CDB IN P4.
;	CALL:
;	MOVE	U,<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::HRRM	P4,JBTST3##(U)	;SETUP CDB ADDRESS
	MOVE	T1,.CPCSN##(P4)	;GET CACHE SWEEP SERIAL #
	MOVEM	T1,JBTCSN##(U)	;SAVE FOR LATER USE BY SCHED1
	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##(P4)	;GET REQUEST NUMBER
	CAMGE	T1,.CPCSN##(P4)	;IS IT LESS THAN CURRENT SWEEP NUMBER?
	POPJ	P,		;NO REQUESTED CACHE SWEEP THIS TICK
	AOS	.CPCRN##(P4)	;NO, EQUAL(HAPPENS) OR GREATER (NEVER HAPPENS)
				; INCREMENT COUNT OF SWEEPS DONE BY REQUEST
	PJRST	CSDMP##		;SWEEP AND RETURN
				; MEANS A REQUEST IS IN.

;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
;
;CALL WITH NEW JOB IN J, OLD JOB IN U.

CSHUUO::SKPCPU	(1)		;IF ON MASTER,
	POPJ	P,		;DON'T DO ANY MORE
	MOVE	T1,JBTSPS##(U)	;GET MS STATUS WORD OF OLD JOB
	TLNE	T1,(SP.NR1)	;HAS HE DONE A UUO FOR MASTER?
	PJRST	CSDMP##		;YES, DO A SWEEP
	POPJ	P,		;NO, DO NOTHING

;SUBROUTINE TO CALL SETCSN WHEN THE JOB NUMBER
; IS IN J AND THE CONTENTS OF P4 IS UNKNOWN

SETCSJ::PUSHJ	P,SCPCDB##	;SETUP P4 FOR THIS CPU
	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,.C0JOB##	;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
CLRCS1:	MOVE	J,.C0JOB##	;CURRENT JOB
	HRRZ	J,JBTSGN##(J)	;JOB'S HIGH SEGMENT NUMBER
	MOVE	T2,.C1JOB##	;CPU1'S CURRENT JOB
	SKIPLE	T1,JBTSGN##(T2)	;HIGH SEGMENT JOB ON CPU1 IS USING
	CAIE	J,(T1)		;SAME AS THE HIGH SEGMENT WHICH WAS JUST W.E.'ED?
	POPJ	P,		;NO, EVERYTHING IS OK
	MOVSI	T1,REDOMP	;HAS THE MAP BEEN REDONE FOR THE CPU1 JOB?
	TDNN	T1,JBTSGN##(T2)	; ...
	POPJ	P,		;YES, ALL IS WELL
	MOVEI	T1,1		;NO, SLEEP A TIC
	MOVE	J,.C0JOB##	;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,.C0JOB##	;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,.C0JOB##	;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

>;END IFN FTKL10
CP1SBP::MOVSI	T1,(DF.RDC!DF.RJE)  ;SET DEBUGF SO THAT
	IORM	T1,DEBUGF##	;ALL STOPCD'S CRASH
	JRST	CP1TY2		;SETUP TO RETURN INTO
				;DIE CODE FOR CPU1'S STOPCD

CP1TYP::CONI	PI,.C0CPI##	;SAVE STATE OF CPU0
	CONO	PI,1177		;..
	MOVEM	17,.C0CAC##+17	;..
	MOVEI	17,.C0CAC##	;..
	BLT	17,.C0CAC##+16	;..
CP1TY2:	MOVE	P,.C1CAC##+P	;SETUP P AS CPU1'S P
	MOVE	F,.C1CAC##+F	;AND F AS CPU1'S F
	MOVEI	P4,.C1CDB##	;POINT TO CPU1 CDB
	SETOM	CP1HLT		;MARK CPU1 DIE IN PROGRESS
IFN FTKI10,<
	DATAI	PAG,CP0EUB	;SAVE CPU0
	MOVE	T1,CP1EUB
	TLO	T1,(PG.LUB)
	DATAO	PAG,T1		; AND PRETEND WE ARE CPU1
>
IFN FTKL10,<
	DATAI	PAG,CP0UPT	; SAVE CPU0 UPT
	MOVE	T1,CP1UPT
	TDC	T1,[LG.LAB!LG.LPC!LG.IAM]
	DATAO	PAG,T1		;AND PRETEND TO BE CPU1
>
	JRST	DIETYP##	;TYPE CPU1 STOPCD INFO

;HERE IF CPU1 DOES A STOPCD
CP1DIE::CONI	APR,AP1STS	;SAVE STATE OF
	CONI	PI,.C1CPI##	; THE HARDWARE
	CONO	PI,PIOFF	;NO PIS
IFN FTKI10,<
	DATAI	PAG,CP1EUB	; AT TIME OF CRASH
>
IFN FTKL10,<
	CONI	PAG,CP1EPT	;SAVE EPT AND
	DATAI	PAG,CP1UPT	; UPT STATUS
>;END IFN FTKL10
	MOVEM	17,.C1CAC##+17	;SAVE THE AC'S
	MOVEI	17,.C1CAC##	;..
	BLT	17,.C1CAC##+16	;..
	MOVE	T1,SPTRAP##	;GET LAST MUUO
	MOVEM	T1,.C1TRP##	;SAVE IN CPU DATA BLOCK
	AOS	CP1HLT		;TELL CPU0 WE DIED
CP1DI1:	SKIPE	CRSHWD##	;RELOADING?
	JRST	CP1DI2		;YES, GO HIDE IN AC'S
	SKIPE	CP1HLT		;CPU0 DONE YET?
	JRST	CP1DI1		;NO, WAIT
	MOVEI	T1,177		;POINT TO ALL PI CHANNELS
	AND	T1,.C1CPI##	;RESTORE ONLY THOSE THAT WERE ON
	IORI	T1,PI.TNP	;SET BIT TO TURN THEM ON
	MOVEM	T1,.C1CPI##	;SAVE FOR LATER
	MOVSI	17,.C1CAC##	;RESTORE THE AC'S
	BLT	17,17
	CONO	PI,@.C1CPI##	;TURN PI SYSTEM BACK ON
	POPJ	P,		;CONTINUE
;CONSOLE TELETYPE (CTY1)

IFN FTCTY1,<

	CT1==120		;DEVICE CODE

;--------THIS CODE EXECUTED BY CPU1----------

;	INTERRUPT ROUTINE

IFN FTKA10!FTKI10,<
CT1INT::CONSO	CT1,50
	JRST	.-1
	CONSO	CT1,40		;WHAT?
	JRST	CT1OUT		;OUTPUT DONE
	DATAI	CT1,CT1REC	;INPUT - GET CHARACTER
	JRST	CT1XIT

CT1OUT:	CONO	CT1,200+CT1CHN##  ;CLEAR INTERRUPT
	JEN	@CT1CHL
CT1XIT:	SETOM	ST1IRP		;SET 'INTERRUPT' FLAG
	JEN	@CT1CHL##
>;END IFN FTKA10!FTKI10

IFN FTKL10,<

	$LOW
CT1INT::0
	CONO	DTE0,CL11PT	;CLEAR INTERRUPT
	SKIPN	DT1MTI##	;INPUT READY?
	JEN	@CT1INT		;NO, LET CT1CLK LOOK AT DT1MTD
	EXCH	17,DT1F11##	;YES, GET CHARACTER
	MOVEM	17,CT1REC	;LET CPU0 KNOW WHAT IT IS
	MOVE	17,DT1F11##	;RESTORE 17
	SETOM	ST1IRP		;LET CPU0 TAKE BALL
	SETZM	DT1MTI##	;ALLOW ANOTHER CHARACTER
	JEN	@CT1INT		;RETURN

	$HIGH
>;END IFN FTKL10

	$LOW
CT1REC::0			;REC'D CHAR STORED HERE
CT1XMT::0			;NON-0 WHEN XMT-DONE SEEN
ST1IRP::0			;NON-0 TO GENERATE ST1 IRP. ON CPU0
	$HIGH

;	INITILIZATION

IFN FTKL10,<
	$HIGH
	LIT
	$LOW
>
CT1INI:	SETZM	CT1REC
	SETOM	CT1XMT
	SETOM	ST1IRP
	SETZM	CT1TYP
IFN FTKA10!FTKI10,<
	CONO	CT1,1200+CT1CHN##
	POPJ	P,
>;END IFN FTKA10!FTKI10

IFN FTKL10,<

	MOVE	T1,[DT1DBG##,,DT1DBG+1] ;CLEAR OUT DTE SOFTWARE AREA
	SETZM	DT1DBG##
	BLT	T1,DT1DND##
	MOVE	T1,[JSR CT1INT]	;SETUP EPT LOCATION
	MOVEM	T1,DT1II##	;WITH INTERRUPT JSR FOR DTE
	MOVE	T1,[DT1EPW##,,DT1EPW+1]
	SETZM	DT1EPW##	;CLEAR OUT DTE HARDWARE AREA
	BLT	T1,DT1DRW##
	CONO	DTE0,CL11PT+PILDEN+CT1CHN## ;SETUP DTE PI LEVEL
	MOVEI	T1,DT.ESP	;ENTER SECONDARY PROTOCOL
	MOVEM	T1,DT1CMD##
	CONO	DTE0,TO11DB	;DO COMMAND
	MOVSI	T1,10		;WAIT, BUT NOT TOO LONG
	SKIPN	DT1FLG##
	SOJG	T1,.-1
	POPJ	P,
	LIT			;FORCE LITERALS TO BE IN LOWSEG
	$HIGH
>;END IFN FTKL10


;	CALLED AT CLOCK LEVEL TO TYPE OUT WAITING CHARACTER

	$LOW
IFN FTKA10!FTKI10,<
CT1CLK:	0
	CONSZ	CT1,20
	JRST	@CT1CLK
	SETZM	17		;CHARACTER TO TYPE?
	EXCH	17,CT1TYP
	JUMPE	17,@CT1CLK
	DATAO	CT1,17		;YES - TYPE IT
	SETOM	CT1XMT
	SETOM	ST1IRP
	JRST	@CT1CLK
>;END IFN FTKA10!FTKI10

IFN FTKL10,<

CT1CLK:	0
	SKIPN	DT1MTD##	;OUTPUT NOT BUSY?
	JRST	@CT1CLK		;OUTPUT STILL BUSY, TRY NEXT TIME
	SETZM	17
	EXCH	17,CT1TYP	;GET CHARACTER, IF ANY
	JUMPE	17,@CT1CLK	;NONE
	SETZM	DT1MTD##	;CLEAR DONE
	ANDI	17,377		;JUST CHARACTER
	MOVEI	17,DT.MTO(17)	;OUTPUT IT
	MOVEM	17,DT1CMD##
	CONO	DTE0,TO11DB	;RING 11 DOORBELL
	SETOM	CT1XMT		;TELL 10 WE HAVE CHAR
	SETOM	ST1IRP
	JRST	@CT1CLK		;AND RETURN
>;END IFN FTKL10
	$HIGH
;--------THIS CODE EXECUTED ON CPU0--------

;ST1IRP IS CHECKED AT APR LEVEL AND IF NON-0
;  A PI REQUEST IS MADE FOR ST1INT WHO INTERFACES WITH SCNSER

ST1INT::SKIPN	ST1IRP		;SOFTWARE INTERRUPT?
	JRST	.-1
IFN FTKI10!FTKL10,<
	CONO	PI,CLRST1##
>
	SETZM	ST1IRP		;YES - CLEAR FLAG
	JSR	ST1SAV##	;SAV AC'S
	MOVEI	U,CT1LIN##	;LOAD LINE NUMBER
	SETZM	T3
	EXCH	T3,CT1REC	;WAS IT RECEIVE?
	JUMPE	T3,ST1XMT	;NO
	PUSHJ	P,RECINT##	;YES - GIVE IT TO SCNSER
	SKIPE	CT1XMT		;IF XMT WAITING - CATCH IT NEXT TICK
	SETOM	ST1IRP
	POPJ	P,

ST1XMT:	EXCH	T3,CT1XMT	;WAS IT XMIT - DONE?
	PJUMPN	T3,XMTINT##	;YES - TELL SCNSER
	POPJ	P,		;NO - IGNORE IT


;	HERE FROM SCNSER TO TYPE A CHARACTER

CT1TYO::TLO	T3,400000	;SO NULLS WON'T BE OVERLOOKED
	MOVEM	T3,CT1TYP	;CUP1 APR CLOCK WILL SEE
	POPJ	P,		;  THIS AND TYPE IT

	$LOW
CT1TYP:	0			;CHARACTER TO TYPE OUT.
	$HIGH


>	;IFN FTCTY1


IFE FTCTY1,<			;IF NO CTY1

CT1INI==CPOPJ##
CT1CLK==CPOPJ##

>	;IFE FTCTY1
;ROUTINES TO TYPE OUT ERROR MESSAGES

;CALLED BY CLOCK1 TO TYPE OUT TIME LIMIT EXCEEDED MESSAGE

IFN FTTLIM,<	INTERN STIMLM
STIMLM:	MOVEI	T1,JS.APE	;THIS IS AN ERROR FOR MASTER TO TYPE OUT
	TDNE	T1,JBTSTS##(J)	;IS THERE ALREADY A "REAL" APR ERROR TO BE PROCESSED?
	POPJ	P,		;YES, FORGET ABOUT TIME LIMIT EXCEEDED
	IORM	T1,JBTSTS(J)	;SET ERROR BIT
	MOVSI	T1,(SP.TLE+SP.NR1)
	IORM	T1,JBTSPS(J)	;SET ERROR BITS ON FOR CIP8A TO SEE
	POPJ	P,		;AND RETURN (JOB WILL NOW BE RESCHEDULED)
>

;ROUTINE TO CAUSE THE MASTER TO TYPE OUT A MESSAGE
;CALL:	MOVEI	T1,MESSAGE	;GET ADR OF MESSAGE TO TYPE IN T1
;	HRLI	T1,JOB NO., 0 ASSUMES OPR WHERE TO TYPE MESSAGE
;	PUSHJ	P,SPTYPE	;RETURN WHEN MESSAGE HAS BEEN TYPED

	INTERN SPTYPE
SPTOPR::HRLI	T1,0		;FORCE MESSAGE ON OPR TTY
SPTYPE:	MOVEM	T1,SVMES	;STORE ADDR OF ERROR MESSAGE FOR MASTER
SPTP1:	SKIPN	SVMES		;HAS FLAG BEEN CLEARED YET BY MASTER
	POPJ	P,		;YES, MESSAGE MUST HAVE GONE OUT
	ROT	T1,^D72		;NOP SO NOT TO SLOW DOWN MEMORY
	JRST	SPTP1		;GO SEE IF MESSAGE FINISHED YET

;ROUTINE CALLED BY THE MASTER TO TYPE OUT MESSAGES FROM SLAVE

SVTYPE:	HRRZ	U,OPRLDB	;FIND THE OPR TTY
	HLRZ	J,SVMES		;GET SLAVE JOB NUMBER IF ANY
	SKIPE	J		;IS THERE A JOB NUMBER
	PUSHJ	P,TTYFNU	;YES, FIND ITS LDB FOR ITS TTY
	PUSHJ	P,INLMES	;TYPE OUT FOLLOWING MESSAGE
	ASCIZ	/?
?Error ON CPU1
?/
	HRRZ	T1,SVMES	;GET ADDRESS OF MESSAGE TO GO OUT
	PUSHJ	P,CONMES	;TYPE IT OUT (T1 CONTAINS POINTER TO MESSAGE)
	SETZM	SVMES		;CLEAR FLAG TO SIGNAL END OF TYPE OUT
	PJRST	CRLF##		;RETURN AND PRINT CRLF


;ROUTINE TO CHECK FOR APR ERRORS DETECTED ON CPU1

; JUST BEFORE CPU0 IS ABOUT TO RUN JOB (CONTEXT HAS BEEN SWITCHED)
;CALL:	MOVEI	T1,JS.APE
;	MOVE	J,JOB NUMBER
;	MOVE	R,JOB DATA AREA EXEC VIRTUAL ADDRESS
;	PUSHJ	P,CSPTLE
;	  EXCEEDED TIME LIMIT ON CPU1 - JS.APE CLEARED IN JPTSTS
;	MUST BE ANOTHER APR ERROR - JS.APE NOT CLEARED (ERRCON MUST ANYWAY)
;	  ERROR FLAGS SET (.C0AEF) SO ERRCON WILL BE CALLED INSTEAD OF RUNNING USER

IFN FTTLIM,<
CSPTLE::MOVSI	T2,(SP.TLE)	;TIME LIMIT EXCEEDED ON CPU1
	TDNN	T2,JBTSPS##(J)	;IS LIMIT EXCEEDED FOR THIS JOB?
	JRST	CPOPJ1##	;NO, SOME OTHER APR ERROR
	ANDCAM	T2,JBTSPS##(J)	;CLEAR TIME LIMIT EXCEEDED
	ANDCAM	T1,JBTSTS##(J)	;YES, CLEAR APR ERROR BIT
	POPJ	P,		;AND DO TIME LIMIT MESSAGE OR INTERCEPT
				; NOW THAT JOB IS ON CPU0
>	;END COND ON FTTLIM
	$LIT
;SLAVE PROCESSOR INITIALIZATION.  JRST HERE FROM 400 STARTUP.

INTERNAL SPRINI
EXTERNAL AP1RST,UUOSP0,UUOSP2,CTYTYP
	EXTERNAL .C1SCD,.C1NPD,NULJB1

	$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
>
	MOVE	P,.C1NPD	;SET UP PUSH DOWN POINTER
IFN FTKI10,<
	CONI	PAG,T1		;READ SERIAL NUMBER
	LSH	T1,-^D26	;RIGHT ADJUST
	MOVEM	T1,.C1ASN##	;STORE
>
IFN FTKL10,<
	APRID	T1		;READ SERIAL NUMBER
	ANDI	T1,7777		;MASK OUT U CODE
	MOVEM	T1,.C1ASN##	;STORE
	PUSHJ	P,CT1INI	;IF KL10, INITIALIZE CTY NOW SO THIS WILL
				; COME OUT
>;END IFN FTKL10
	MOVEI	T1,[ASCIZ/
[CPU1]
/]
	PUSHJ	P,CTYTYP	;TELL OPERATOR THAT THIS IS THE SECOND CPU
	SETZM	.E1IL##
	MOVE	14,[XWD ACLOOP,2]	;LOAD AC'S WITH WAIT LOOP
	BLT	14,14		;CPU1 WILL WAIT UNTIL CPU0 IS GOING
	MOVE	13,[JRST SPRIN1]	;SET UP RETURN INSTRUCTION
	JRST	2		;ENTER LOOP

;INITIALIZE PD LIST
SPRIN1:	MOVE	P,.C1NPD	;SET UP PUSH DOWN POINTER
IFN FTKI10!FTKL10,<
	PUSH	P,.E1PM##	;SAVE FIRST SLOT IN CPU1'S MAP TEMPORARRLY
IFN FT2SEGMON,<
	PUSHJ	P,MAPINI
>
IFN FTKL10,<
	MOVEI	T1,LG.CSL!LG.CSW
	IORM	T1,.C1EBR
>
	MOVEI	T1,.C1DBL##	;ADDRESS OF CPU1'S DOORBELL
	LSH	T1,W2PLSH##	;CONVERT TO PAGE NUMBER
	TRO	T1,PM.ACC+PM.PUB;ACCESS ALLOWED AND PUBLIC (NULL JOB RUNS
				; IN PUBLIC USER MODE)
	MOVEI	T2,400000+.C1DBL##
	ROT	T2,W2PLSH##-1	;MAP SLOT IN THE NULL JOBS MAP WHICH
				; WILL MAP CPU1'S DOORBELL FOR CPU1'S NULL JOB
	MOVEI	T3,NLUPMP##(T2)	;ADDRESS OF THE NULL JOB'S UPMP+DOORBELL OFFSET
	HRLI	T3,222200	;ASSUME LEFT HALF WORD MAPS DOORBELL
	SKIPGE	T2		;IS IT AN ODD PAGE?
	HRLI	T3,002200	;NO, RIGHT HALF WORD MAPS THE DOORBELL
	DPB	T1,T3		;MAP THE DOORBELL FOR CPU1'S NULL JOB
	JRSTF	@[EXP IC.UOU+SPRIN4] ;TURN ON USER IOT SO EXECUTE PAGED
				; CORRECTLY AND PROCEED WITH INITIALIZATION
>
IFN FTKA10,<
SPRIN2:	PUSH	P,SPTRAP+1	;SAVE 141
	PUSH	P,SPTRAP+2	;AND 142
	MOVE	T1,[JSR ENDTST]
	MOVEM	T1,SPTRAP+1	;SET UP FOR UUO TRAP
	MOVEM	T1,SPTRAP+2	;AND FOR CHANNEL 1 INTERRUPT
	CONO	APR,633551	;TURN APR ON TO CHANNEL 1
	CONO	PI,12300	;ALLOW INTERRUPTS ONE 1
	DATAO	APR,[XWD 376776,400]	;SET UP KT10A
	JRST	1,.+1		;GO TO USER MODE
	MOVE	T1,400100	;TRY A MEMORY REFERENCE
SPRIN3:	MOVEI	17,400000	;BLT SHADOW ACS TO THEIR SELF
	BLT	17,400017	; TO CLEAR POSSIBLE PARITY ERRORS
	SETZ	T2,		;ZERO AN AC
	SETOM	400000+T2	;SET SHADOW AC TO SEE IF AC GETS CLOBBERED
	CALL			;GO BACK TO MONITOR MODE

ENDTST:	0			;JSR IS DONE HERE FROM CALL UUO
	POP	P,SPTRAP+2	;RESTORE 142
	POP	P,SPTRAP+1	;AND 141
	CONSZ	APR,@.C1ILM##	;WAS THERE AN ILM. (NO TWO REGISTERS?)
	PUSHJ	P,NKT10A	;ONLY ONE REGISTER EXISTS
	CONO	APR,@.C1ILM##	;CLEAR ILM
>
SPRIN4:	CONO	PI,10000	;AND CLEAR PI SYSTEM
IFN FTKI10!FTKL10,<
	POP	P,.E1PM##	;RESTORE CONTENTS OF CPU1 EXEC MAP SLOT 0
>
IFN FTKA10,<
	JUMPE	T2,SPRIN5	;IF FAST ACS ARE ON CONTINUE
	MOVEI	T1,[ASCIZ/CPU1 fast acs are off - set FM ENB/]
	MOVEM	T1,SVMES	;TYPE THIS OUT ON MASTER
	PUSHJ	P,CTYTYP	;AND ON THE SLAVE TTY
				; SPLIT CYCLE ON, 2 CPUS CONFLICT
				; ON MEMORY REFERENCES
	STOPCD	SYSDSP,HALT,SCO, ;++SPLIT CYCLE ON

NKT10A:	SKIPN	TWOREG		;DOES MASTER HAVE TWO REGISTERS
	POPJ	P,		;NO, RETURN
	STOPCD	.,HALT,KN1,	;++KT10A NOT ON CPU1
>
;HERE TO SET UP TO RUN NULL JOB, & SETUP PI
SPRIN5:	HRRZS	.C1MPC##	;CLEAR SERIOUS MEMORY PARITY HALT FLAG
				; HALT AFTER PRINTING ON CPU0 CTY
	MOVEI	J,JOBMAX##	;MAX JOB NO.
	MOVSI	T1,(SP.CJ1)	;JOB RUNNING ON CPU1 BIT
SPRLP1:	ANDCAM	T1,JBTSPS##(J)	;CLEAR FOR ALL JOB IN SYSTEM
				; (IN CASE THIS IS A 450 RESTART ON CPU1)
	SOJGE	J,SPRLP1	;MORE?
	MOVEI	P4,.C1CDB##	;SETUP P4
IFN FTKL10,<
	MOVE	T1,.CPEBS##(P4)	;GET EBOX TICKS/SECOND
	IDIV	T1,TICSEC##	;AND NOW GET EBOX COUNTS/JIFFY
	IMULI	T1,.EBCPT	;MULTIPLY BY EBOX COUNTS/TICK
	MOVEM	T1,.CPEBJ##(P4)	;STORE IN CDB VARIABLE

	MOVE	T1,.CPMBS##(P4)	;GET MBOX TICKS/SECOND
	IDIV	T1,TICSEC##	;GET MBOX COUNTS/JIFFY
	IMULI	T1,.MBCPT	;MULTIPLY BY MBOX COUNTS/TICK
	MOVEM	T1,.CPMBJ##(P4)	;SAVE

IFN FTEMRT,<
	PUSHJ	P,ACCMON##	;START UP ACCOUNTING METERS
	PUSHJ	P,CLREBT##	;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
	MOVE	T1,[JSR	TM1INT##]	;GET TIMER INTERRUPT INST.
	MOVEM	T1,.E1TII##	;MOVE INTO EPT TRAP LOC
	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 FTKA10!FTKI10,<
	PUSHJ	P,CT1INI	;INIT CTY1 CODE
>
	CONO	APR,AP1NUL##
	CONO	PI,52377	;TURN ON ALL PI, ENABLE MEMORY PARITY
IFN FTKL10,<
	SETOM	DT1MTD##	;SET DONE INITIALLY SO CT1CLK WILL TYPE
				; CHARACTERS
>
	JRST	NULJB1		;GO START NULL JOB

;SUBROUTINE TO INITIALISE CP11'S MAP FROM CPU0'S MAP
IFN FT2SEGMON,<
MAPINI:	PUSH	P,.E1MP##+.MSKPC
	MOVE	T1,[.EPPM##,,.E1PM##]
	BLT	T1,.E1PM##+177
IFN FTKL10,<
	MOVE	T1,[.EPLM##,,.E1LM##]
	BLT	T1,.E1LM##+157
>
	POP	P,.E1MP##+.MSKPC
	CLRPGT	(1)
	POPJ	P,
>
SUBTTL DUAL CPU INITIALIZATION
;ROUTINE TO CHECK IF BOTH PROCESSORS ARE IN SYSINI TOGETHER
;NOTE:  THIS ROUTINE CANNOT USE A PD LIST SINCE BOTH CPUS CAN GET HERE
; IF OFFSET SWITCHES SET THE SAME WAY
;CALL:	JSP	T1,TWOCHK
;	RETURN HERE IF ALL IS OK
	INTERN	TWOMAS,ONCCHK,TWOCHK
	EXTERN	.C0OK,CTYTYP
TWOCHK:	MOVEI	T3,^D34000	;SET UP FOR 10 CLOCK TIC LOOP
	SETZM	.C0OK		;INITIALIZE MASTER OK WORD
	SETZB	T2,ONCCHK	;ZERO COUNTER AC AND WORD
SYS2MC:	AOS	T2		;COUNT THE AC
	AOS	ONCCHK		;AND THEN THE MEMORY LOCATION
	SOJG	T3,SYS2MC	;LOOP FOR THE SPECIFIED TIME
	CAMN	T2,ONCCHK	;ARE THE AC AND MEMORY WORD THE SAME
	SKIPGE	.C0OK		;AND THE MASTER OK WORD STILL ZERO
	JRST	TWOMAS		;NO, GO TYPE OUT A MESSAGE
	JRST	(T1)		;OK, RETURN

TWOMAS:	MOVEI	T1,[ASCIZ/
?Change the CPU1 MA TRP OFFSET switch in bay 1
/]
	MOVEM	T1,SVMES	;TYPE OUT MESSAGE ON MASTER
	MOVEI	P,T1		;SET UP PUSH DOWN LIST IN AC'S
				; SINCE BOTH CPUS COULD GET HERE
	PUSHJ	P,CTYTYP	;AND TYPE OUT MESSAGE
	STOPCD	SYSDSP,HALT,TOW,	;++TRAP OFFSET WRONG
ONCCHK:	0			;MEMORY LOCATION COUNTER WORD
	LIT
	$HIGH			;BACK TO THE HIGH SEGMENT
;ROUTINE TO SAVE AC'S ANDLOOP IN THE AC'S WAITING FOR MASTER
;TO BE RELOADED.  HERE AT APR PI WHEN MASTER STOPPED, OR 30 NON-ZERO
	INTERN CP1CRS

	EXTERNAL SYSDSP,.C0OK,.C1OK
	XP DEDTIM,^D10000	;TIME OUT TO GUARANTEE MASTER IS DEAD

CP1CRS:	CONI	APR,AP1STS	;SAVE APR STATUS FOR DUMP
	CONI	PI,.C1CPI##	;SAVE PI STATUS FOR DUMP
	CONO	PI,PI.OFF	;TURN OFF ALL INTERRUPTS DURING MASTER CRASH
IFN FTKI10,<
	DATAI	PAG,CP1EUB
>
IFN FTKL10,<
	CONI	PAG,CP1EPT	;SAVE EPT STATUS
	DATAI	PAG,CP1UPT	;AND UPT STATUS
	EXECAC
				;SWITCH TO EXEC ACS SO A PDP IS IN P,
				; AND SO WE DON'T SMASH USER ACS
>
	MOVEM	17,.C1CAC##+17	;SAVE AC 17
IFN FT2SEGMON&FTMOFFL,<
	SKIPE	MOFLPG##	;SETTING MEMORY OFF
	JRST	CP1DI0		;YES, JUST RELAX UNTIL ITS DONE
>
MPD1:	AOSN	17,.C0OK	;START COUNTING UP MPOK
	JRST	MPDR		;MASTER IS GOING AGAIN (MPOK WAS -1)
	CAIG	17,DEDTIM	;MASTER REALLY SICK NOW?
	JRST	MPD1		;NOT YET
CP1DI0:	MOVEI	17,.C1CAC##	;SAVE ALL AC'S
	BLT	17,.C1CAC##+16
IFN FTKL10,<
	PUSHJ	P,CSDMP##	;MAKE SURE ITS ALL IN CORE FOR THE DUMP
>
CP1DI2:
IFN FTKL10,<
	PUSHJ	P,CSDMP##	;MAKE SURE ITS ALL IN CORE FOR THE DUMP
>
	MOVE	17,[XWD ACLOOP,2]	;SET UP AC LOOP
	BLT	17,17
	MOVE	.E1IL##		;SAVE 140
	MOVEM	SAV140		;IN CASE WE CAN CONTINUE AGAIN
	SETOM	.E1IL##		;ZERO 140  (MASTER WILL SETOM 140 IF RESTARTED)
	JRST	2		;START LOOP IN AC'S
	$LOW
MPD2:
IFN FT2SEGMON&FTMOFFL,<
	MOVE	P,.C1CAC##+P
	PUSHJ	P,MAPINI
>
	MOVE	SAV140		;MASTER RECOVERED
	MOVEM	.E1IL##		;RESTORE 140
	MOVSI	17,.C1CAC##	;AND THE AC'S
	BLT	17,17
	JRST	MPDR1		;AND RETURN TO CLOCK ROUTINE

MPDR:	MOVE	17,.C1CAC##+17	;RESTORE AC 17
MPDR1:
IFN FTKI10,<
	DATAO	PAG,CP1EUB	;RESTORE OLD UBR,EBR
>
IFN FTKL10,<
	DATAO	PAG,CP1UPT	;RESTORE OLD AC BLOCK, UPT
>;END IFN FTKL10
	CONO	PI,PI.ON	;RESTORE INTERRUPTS AGAIN
	JRST	AP1BCK##	;GO CONTINUE AGAIN WITH APR INTERRUPT FOR CPU1

ACLOOP:	MOVEI	1,20		;2  INITIALIZE ITERATION COUNT
	MOVE	0,.C1OK		;3  GET CURRENT .C1OK
	CAMN	0,.C1OK		;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,.C1OK		;7  DID .C1OK INCREASE BE EXACTLY ONE
	JRST	2		;10 NO, START OVER AGAIN
	SOJG	1,4		;11 WAIT FOR 20 COUNTS TO BE SURE
	AOSE	.E1IL##		;12 WAS 140 SET TO -1 BY MASTER
	JRST	SYSDSP		;13 YES, GO RESTART SLAVE
	JRST	MPD2		;14 NO, JUST CONTINUE

	INTERNAL SAV140
SAV140:	0			;LOCATION OF 140 DURING A SLAVE CRASH
AP1STS::0			;APR STATUS ON CRASH
IFN FTKI10,<
CP1EUB::0			;EXEC USER BASE REG
CP0EUB::0			;SAVE CPU0 BASE REG WHILE DOING STOPCD AS CPU1
>
IFN FTKL10,<
CP1EPT:	0			;EXEC BASE REGISTER
CP1UPT:	0			;USER BASE REGISTER
CP0UPT::0			; AND USER BASE REG WHILE MASQUERADING
>
CP1HLT::0			;SET TO -1 ON A CPU1 STOPCD
	$HIGH
;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.

INTERNAL LOKSCD,ULKSCD
EXTERNAL .C0SCD,.C1SCD,PION,PIOFF	;LOCS DEFINED IN COMMON

;HERE TO TURN ON INTERLOCK
LOKSCD:	SKPCPU	(0)		;TEST TRAP OFFSET BIT TO SEE WHICH PROCESSOR CALLED US
	JRST	LOCKS		;SLAVE PROCESSOR

;MASTER PROCESSOR LOKSCD ROUTINE
LOCKM:	AOS	.C0SCD		;REQUEST INTERLOCK
LOCKML:	SKIPGE	.C1SCD		;DOES THE SLAVE HAVE IT?
	POPJ	P,		;NO, RETURN
	AOS	.C0LLC##	;YES, COUNT NO. OF TIMES IN LOOP
IFN FTKL10,<
	PUSHJ	P,LOCKCR	;SWEEP CACHE IF NEEDED
>
	JRST	LOCKML		;WAIT FOR SLAVE

;SLAVE PROCESSOR LOKSCD ROUTINE
LOCKS:	CONO	PI,PIOFF	;THIS MAKES SLAVE INTERRUPT CALLS LEGAL
	AOS	.C1SCD		;REQUEST INTERRLOCK
	SKIPGE	.C0SCD		;DID WE GET IT?
	JRST	LOCKS2		;YES
	SOSL	.C1SCD		;TAKE AWAY REQUEST
	JRST	LOCKS1		;SLAVE ALREADY HAS INTERLOCK, ALL IS OK
	CONO	PI,PION		;WAIT FOR INTERLOCK TO BE FREE
LOCKSL:	SKIPGE	.C0SCD		;DOES MASTER HAVE IT?
	JRST	LOCKS		;NO, TRY AGAIN
	AOS	.C1LLC##	;YES, COUNT NO. OF TIMES IN LOOP
IFN FTKL10,<
	PUSHJ	P,LOCKCR	;SWEEP CACHE IF NEEDED
>
	JRST	LOCKSL		;WAIT FOR MASTER

LOCKS1:	AOS	.C1SCD		;COUNT LEVEL UP AGAIN
LOCKS2:	CONO	PI,PION		;TRUN ON PI AGAIN
	POPJ	P,		;AND RETURN

;HERE TO TURN OFF INTERLOCK
ULKSCD:	SKPCPU	(0)		;WHICH PROCESSOR?
	JRST	UNLOKS		;SLAVE

;MASTER PROCESSOR ULKSCD ROUTINE
UNLOKM:	SKIPGE	.C0SCD		;TEST INTERLOCK LEVEL
	STOPCD	CPOPJ,DEBUG,MAU,	;++MASTER ALREADY UNLOCKED
	SOS	.C0SCD		;DECREMENT LEVEL
UNLKM1:	POPJ	P,		;AND RETURN

;SLAVE PROCESSOR ULKSCD ROUTINE
UNLOKS:	SKIPGE	.C1SCD		;TEST LEVEL
	STOPCD	CPOPJ,DEBUG,SAU, ;++SLAVE ALREADY UNLOCKED
	SOS	.C1SCD		;DECREMENT LEVEL
UNLKS1:	POPJ	P,		;AND RETURN

IFN FTKL10,<
;SUBROUTINE TO CHECK FOR CACHE SWEEP REQUEST WHILE
; WAITING FOR THE SCHEDULAR INTERLOCK

LOCKCR:	PUSHJ	P,SCPCDB##	;SAVE AND SETUP P4
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,CSREQS	;SWEEP CACHE IF REQUESTED
	PJRST	TPOPJ##		;RESTORE T1 AND RETURN
>
;CODE TO IMPLEMENT THE SETUUO'S NUMBER 14 (.STCPU) 
;AND 15 (.STRUN)

	INTERN	SETCRN

SETCRN:	MOVEI	T4,.C0CDB	;ADDRESS OF FIRST CDB
	TRZ	T2,777700	;GET ONLY BITS OF INTEREST
SETCR1:	MOVE	T3,.CPRUN(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(T4)	;PUT BACK IN CDB
	HLRZ	T4,.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

	INTERN SETCPU

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(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(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
	INTERNAL CPUCMD

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, 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(T3)	;THIS CPU?
	JRST	CPUFN2		;YES, OK TO PROCEED
	HLRZ	T3,.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:	SOJL	T1,CPOPJ1	;EXIT WHEN MASK IN RIGHT POSITION
	LSH	T3,1		;NOT THIS CPU, SHIFT LEFT
	JRST	CPUFN3		;AND PROCEED

;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

	INTERNAL CPSCHK

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(T4)	;SKIP IF CPU NOT RUNNING
	ADD	T2,T3		;SET BIT IN MASK
	HLRZ	T4,.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.

CPRCHK:	TDNE	T2,JBTSPS(J)	;SKIP IF NO RUNNABLE CPU FOR THIS JOB
	POPJ	P,		;OK, RETURN
	MOVE	U,TTYTAB##(J)	;GET TTY DDB
	HRRZ	U,DDBLDB##(U)	;LDB ADDRESS
	PJSP	T1,CONMES##	;PRINT MESSAGE TO USER AND CPOPJ
ASCIZ	/%No Running CPU's in specification
/

CPRONE:	PUSHJ	P,CPRBIT	;SET UP MASK OF RUNNING CPU'S
	PJRST	CPRCHK		;CHECK TO SEE IF WE HAVE ONE RUNNING

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

;SUBROUTINE TO RETURN CPU SPECIFICATION TO THAT SET
;BY LAST "SET CPU" COMMAND.  CALLED FROM "RESET" IN UUOCON

	INTERN CRESET
;SUB TO MAKE JOB RUNABLE 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

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.CR0+SP.CR1>B29+SP.CR0+SP.CR1 ;CAN RUN ON CPU0 AND 1
REPEAT 0,<		;IF "SBLOK (SCD)" IS EVER USED, REMOVE THIS CONDITIONAL

;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.

	INTERNAL SBSCD

SBSCD:	PUSHJ	P,LOKSCD	;TURN ON INTERLOCK
	PUSHJ	P,@(P)		;DISPATCH TO ROUTINE
	SKIPA
	AOS	-1(P)		;PROVIDE FOR SKIP RETURN
	POP	P,XXXX		;FIX PUSHDOWN TO RETURN TO ORIGINAL CALLER
	JRST	ULKSCD		;TURN OFF INTERLOCK AND RETURN WITH POPJ

XXXX:	0			;(LOC TO HOLD JUNK)

>

	INTERN SVMES
	$LOW
CP1ERR:	0			;LOCATION FOR WAITING FOR A PARITY ERROR TO BE HANDLED
SVMES:	0			;XWD JOB#,ADR OF MESSAGE  FOR MASTER TO TYPE
	$HIGH

	$LIT			;GENERATE LITERALS SO CAN CHECK ASCII OCTAL

CL2END:	END