Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - sched1.mac
There are 13 other files named sched1.mac in the archive. Click here to see a list.
TITLE	SCHED1 - SCHEDULING ALGORITHM FOR SWAPPING SYSTEM (10/50)  V720
SUBTTL R.KRASIN/TH/CMF/AF/RCC/DAL/EVS  08 MAR 77
	SEARCH	F,S
	$RELOC
	$HIGH
;***COPYRIGHT 1973,1974,1975,1976,1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VSCHED,720
		;PUT VERSION NUMBER IN GLOB LISTING AND LOADER STORAGE MAP
ENTRY SCHED,SCHED1	;THIS UNDEFINED GLOBAL IN COMMON CAUSES THIS
			; ROUTINE TO BE LOADED.
SCHED1::		;MODULE ORIGIN

;THIS SCHEDULER BASED ON WORK DONE AT WMU BY E.SMOLSKY AND N.GRANT

;NXTJOB DECREMENTS CURRENT JOB'S QUANT. RUN
;TIME AND REQUEUES IT IF QUANT. TIME GONE TO 0.
;SERVICES ANY JOB REQUEUING REQUESTED AT OTHER PRIORITY
;LEVELS THEN CALLS SHUFFLER,SWAPPER AND SCHEDULAR.
;RETURNS NEXT JOB TO RUN IN J.



NXTJOB::SETZM	PASFLG##	;SET FLAG THAT THIS IS FIRST PASS THROUGH SCHED
	SKIPN	.C0TMF##	;CLOCK TIC?
	JRST	NXTJB1		;NO
IFN FTNSCHED,<
	PUSHJ	P,SCDTYP	;SET P3 UP TO SCHEDULER TYPE (0,1)
>;END IFN FTNSCHED
	MOVE	T4,TIME##	;GET TIME IN JIFFIES
	TRNN	T4,1B35		;ONLY DECREMENT IN CORE TIME ON ODD TICKS
	JRST	NXTJBX
	MOVE	J,HIGHJB##	;ANY JOBS AT ALL?
	JUMPLE	J,NXTJBX	;NO.
	MOVEI	T4,JS.SCN	;JOB SCANNED DURING TICK BIT
NXTJBA:	MOVE	T2,JBTSTS##(J)	;JOB STATUS WORD
	TLNN	T2,SWP		;SWAPPED IN?
	TLNN	T2,JNA		;AND JOB NUMBER ASSIGNED?
	  JRST	NXTJBF		;NO. GET NEXT JOB
	LDB	T1,PJBSTS##
	CAIGE	T1,SLPQ		;IF STATE .GE. SLP, ALWAYS DECREMENT
				; (JOBS IN LONG TERM WAIT STATES, NAP
				; ARE THUS CHARGED FOR BEING IN CORE
	TDNE	T4,JBTST2##(J)	;OR IF JOB WAS ACTUALLY SCANNED
	JRST	.+2		;WE WILL DECREMENT
	  JRST	NXTJBF		;DO NOT DECREMENT THIS JOB
	ANDCAM	T4,JBTST2(J)	;CLEAR SCANNED BIT FOR NEXT TIME
IFN FTPDBS,<
	PUSHJ	P,FNDPDB##	;GET PDB ADDRESS
	  JRST	NXTJBF		;NO PDB IMPLIES NO ICPT
>
IFE FTPDBS,<
	HRRZ	W,JBTPDB##(J)	;GET PDB ADDRESS
	  JUMPE	W,NXTJBF	;NO ICPT IF NO PDB
>
	.LDB	T3,PDYIPT##	;GET ICPT
	SOJG	T3,NXTJBE	;IF STILL POSITIVE, JUST DEPOSIT
	MOVSI	T3,PDMSWP	;MARK SWAPPABLE IN PDB
	.IORM	T3,.PDIPT##(W)	;..
	PUSHJ	P,SETIPT	;AND RESET ICPT SO WILL CYCLE
				; EVEN IF DOESN'T NEED TO SWAP
	TLNE	T2,CMWB!JRQ	;COMMAND WAIT OR REQUE?
	JRST	NXTJBD		;YES. GET OUT
	PUSHJ	P,INRNQ		;IS JOB IN A RUN QUEUE?
	 JRST	NXTJBF		;NO. CAN'T REQUE HIM NOW.
IFN FTPSCD,<
	PUSHJ	P,CNTICP	;COUNT NUMBER WHO EXPIRED IN-CORE BY QUE
>
IFE FTNSCHED,<
	MOVEI	U,QTIME0	;REQUE AROUND RUN QUEUES
>
IFN FTNSCHED,<
	MOVE	U,[EXP QTIME0
		   EXP QTIME1](P3)
				;GET PROPER TABLE FOR PROPER SCHEDULER
>
	PUSHJ	P,QXFER		;DO TRANSFER
	JRST	NXTJBF		;GO TO NEXT JOB
NXTJBD:	SETZ	T3,		;PUT IN A ZERO FOR COMMAND WAIT, JRQ
NXTJBE:	.DPB	T3,PDYIPT##	;OR JUST STORE NEW VALUE
NXTJBF:	SOJG	J,NXTJBA	;LOOP FOR THE REST
NXTJBX:
IFN FTNSCHED,<
	PUSHJ	P,SCDQTA	;RESET CLASS QUOTA STUFF IF ITS THE
				;END OF A SCHEDULING INTERVAL
>;END IFN FTNSCHED

IFN FTRSP,<		;KEEP TRACK OF WANT-TO-RUN TIME
RQTPAT::JRST	NXTJ1A		;PATCH TO JFCL TO INCLUDE EXPENSIVE
				; WANT-TO-RUN TIME CALCULATION
	MOVSI	T1,WTMASK	;TO CHECK FOR RUN STATE CODE
	HRRE	J,JBTQ##-PQ1	;CHECK PQ1
	PUSHJ	P,RQT2
	HRRE	J,JBTQ##-PQ2	;  PQ2
	PUSHJ	P,RQT2
	JRST	RQT3

RQT1:	TDNN	T1,JBTSTS##(J)	;SKIP IF NOT IN RUN STATE
	AOS	JBTRQT##(J)	;BUMP JBTRQT FOR ALL
	HRRE	J,JBTQ##(J)	;  JOBS IN THIS QUEUE
RQT2:	JUMPG	J,RQT1
	POPJ	P,

RQT3:
>	; END OF CONDITIONAL ASSEMBLY ON FTRSP
IFN FTNSCHED,<
	JRST	NXTJ1A
>
;CPU1 ENTERS HERE FROM CIP6

NXTJB1::
IFN FTNSCHED,<
	PUSHJ	P,SCDTYP	;SET P3 TO SCHEDULER TYPE (1 = CLASSES)
NXTJ1A:>
	SKIPN	J,.CPJOB##(P4)	;CURRENT JOB NO., IS IT NULL JOB?
	JRST	CKJB1		;YES,GO SEE IF OTHER JOBS NEED RESCHEDULING
	MOVEI	F,0		;GET READY IN CASE CURRENT JOB UNRUNABLE
IFN FTHPQ,<
	SKIPE	.CPHQU##(P4)	;IF THE CURRENT JOB JUST DID AN HPQUUO, IT IS ALWAYS
	JRST	CKJB0A		; RUNNABLE BUT IT MUST BE REQUED INTO THE NEW HPQ
>
	HLRZ	T2,JBTSTS##(J)	;GET JOB STATUS BITS AND CODES
	TRZ	T2,RUNMSK+CMWB	;MASK OUT DO NOT CARE BITS
	CAIE	T2,RUNABLE	;IS CURRENT JOB RUNABLE?
	JRST	CKJB0		;NO, REQUE CURRENT JOB
	PUSHJ	P,FNDPDB##	;YES. GET PDB ADR FOR CURRENT JOB
	  JRST	CKJB1		;GO AWAY IF NONE
	.LDB	T2,PDYIPT##	;GET ICPT
	JUMPE	T2,NXTJB4	;ALWAYS REQUE IF ZERO
	.LDB	T2,PDYQNT##	;GET IN QUE TIME
	JUMPN	T2,CKJB1	;EXIT IF STILL POSITIVE
IFN FTRSP,<		;RESPONSE DATA?
	MOVEI	T1,.CPARR##(P4)	;BASE ADR OF 3 WORDS FOR QUANTUM REQUEING
	MOVSI	T2,(JR.RRR)	;RECORD THIS TYPE OF RSP FOR THIS JOB
	PUSHJ	P,RSPRC2##	;RECORD ELAPSED TIME FOR RESPONSE
				; AND FOR ANY OF TTY IN, TTY OUT, THIS
>	; END OF CONDITIONAL ASSEMBLY ON FTRSP
IFN FTPSCD,<
	PUSHJ	P,CNTINQ	;COUNT NUMBER WHO EXPIRED IN QUE BY QUE
	JRST	NXTJ4A
>
NXTJB4:
IFN FTPSCD,<
	PUSHJ	P,CNTICP	;COUNT NUMBER WHO EXPIRED IN-CORE BY QUE
>
NXTJ4A:	SETZM	.CPLJU##(P4)	;IF REQUEING, ZERO THE LAST JOB TO DO A UUO WORD
				;SINCE JOBQUE FOR THAT JOB WILL THEN BE WRONG
	PUSHJ	P,QARNDT	;YES - REQUEUE AND RESET QUANT TIMES.
	JRST	CKJB1		;DO ONCE A CLOCK TICK STUFF

CKJB0:	TRZ	T2,JXPN!SHF!SWP	;JOB NOT RUNNABLE, BUT MAY NOT NEED REQUEUE
	CAIN	T2,RUNABLE	;DOES IT REALLY NEED TO BE REQUEUED?
	JRST	[		;NO, DON'T GIVE HIM EXTRA PRIORITY
IFN FTMS,<
		SKPCPU	(1)	;JUST SELF ON CPU1
>;END IFN FTMS
		SKIPN	.CPTMF##(P4)	;CLOCK TICK?
		JRST	CKJB3A		;NO, DON'T REQUEUE ANYONE
		JRST	CKJB1		;YES, DO EVERYONE
				]
	MOVSI	T2,JRQ		;DID SOMEONE SET JRQ FOR CURRENT JOB?
	TDNN	T2,JBTSTS##(J)
	JRST	CKJB0A		;NO, OK
	SOS	QJOB		;YES, DECREMENT QJOB
	ANDCAM	T2,JBTSTS##(J)	; AND CLEAR JRQ
CKJB0A:

IFN FTMS,<
	SKPCPU	(1)		;IF SLAVE PROCESSOR, ALWAYS GO TO CKJB3
				;THIS MUST BE DONE SINCE REQUE IS NOT REENTRANT
>	; END OF CONDITIONAL ASSEMBLY ON FTMS
	SKIPN	.CPTMF##(P4)	;HAS CLOCK TICKED?
	JRST	CKJB3		;NO, REQUEUE ONLY THE CURRENT JOB
				; (THIS HAPPENS OFTEN WHEN CURRENT JOB
				; GOES INTO IO WAIT)
	CAMG	J,HIGHJB##	;DON'T SET JRQ IF NOT A JOB
	PUSHJ	P,REQUE##	;YES, FLAG CURRENT JOB TO BE REQUEUED
				; WITH ALL THE REST OF THE JOBS (IF ANY)
				; THUS SWAPPER WILL GET CALLED AT CKJB7
CKJB1:	AOSN	F,CHKQJB	;TIME FOR ONCE A MINUTE CHECK? (IN CASE QJOB WAS TOO LOW)
	SOJA	F,CKJB1A	;YES, MAKE F-1 AND START LOOKING
	SKIPN	F,QJOB		;NO, ANYTHING TO DO?
	JRST	CKJB5		;NO, SKIP QJOB STUFF
CKJB1A:				;SCAN ALL JOBS EVERY MINUTE IN CASE QJOB WAS OFF
	MOVE	J,HIGHJB##	;START WITH HIGHEST JOB NUMBER ASSIGNED
CKJB2:	MOVSI	T2,JRQ		;JOB NEEDS REQUEUEING BIT
	TDNN	T2,JBTSTS##(J)	;THIS JOB?
	SOJG	J,.-1		;NO,KEEP LOOKING
	JUMPLE	J,CKJB5		;YES,LOOKED AT ALL JOBS?
				; (MAY NOT FIND A KJOBED JOB IF HIGHEST
				; GO DECR. COUNT QJOB ANYWAY)
	ANDCAM	T2,JBTSTS##(J)	;NO,MARK THIS JOB AS DONE
	PUSHJ	P,DECHJB##	;DECREMENT HIGHJB, IF THIS JOB NOW GONE.
CKJB3:	PUSHJ	P,QREQ		;GO REQUE THE JOB
CKJB3A:	JUMPE	F,SCHED		;IF FROM NXTJOB GO DIRECTLY TO SCHED
				; I.E. CURRENT JOB NO LONGER RUNNABLE(IOW)
				; BUT JRQ WASN'T SET SO DON'T DECR QJOB
	JUMPG	F,CKJB4D	;ONCE A MINUTE?
	SKIPE	QJOB		;YES DECREMENT IF GTR THAN 0
	SOS	QJOB
	JRST	CKJB4E		;AND LOOK AT NEXT JOB
CKJB4D:	SOSLE	F,QJOB		;ANY MORE JOBS TO REQUEUE?
CKJB4E:	SOJG	J,CKJB2		;YES,BUT LOOK AT EACH JOB ONLY ONCE PER CLOCK TICK
CKJB5:
IFN FTKI10!FTKL10,<
	SKIPN	EVAVAL##	;EV AVAILABLE AND SOMEONE WAITING?
	JRST	CKJB7		;NO.
	SETZM	EVAVAL		;YES. CLEAR FLAG
	SKIPG	J,HIGHJB##	;ANY JOBS?
	JRST	CKJB7		;NO. SHOULDN'T HAPPEN
	MOVSI	T2,WTMASK	;YES. TAKE EVERYBODY OUT OF EV WAIT
CKJB5A:	LDB	T1,PJBSTS##	;GET JOBS STATE CODE
	CAIN	T1,EVQ		;EV?
	ANDCAM	T2,JBTSTS##(J)	;YES. TAKE HIM OUT
	SOJG	J,CKJB5A	;AND LOOP FOR ALL JOBS
>	;END IFN <FTKI10!FTKL10>
CKJB7:
IFN FTMS,<
	SKPCPU	(0)		;IF SLAVE, DON'T CALL SWAPPER
	JRST	SCHED		;IF THIS IS CPU 1, DONT SHUFFLE OR SWAP
>	; END OF CONDITIONAL ASSEMBLY ON FTMS
IFN FTHPQ,<
	SKIPG	.C0RTF##	;IF AN HPQ JOB ON DISK WOKE UP
>
	SKIPN	.C0JOB##	;OR IF RUNNING NULL JOB
	JRST	CKJB6		;CALL SWAP/SHUFFLE
	SKIPN	.C0TMF##	;ALWAYS CALL SWAP/SHUFFLE ON TICK
	JRST	SCHED		;NOT TICK OR OTHERWISE
CKJB6:
IFE FTSWAP,<
	PUSHJ	P,CHKSHF##
>	; END OF CONDITIONAL ASSEMBLY ON FTSWAP

IFN FTSWAP,<
IFN FTTRPSET,<
	SKIPN	STOPTS##	;DON'T SWAP IF TIMESHARING TURNED OFF.
>
	PUSHJ	P,SWAP
>	; END OF CONDITIONAL ASSEMBLY ON FTSWAP
IFN FTLOCK,<
	  SKIPA		;NOT TRYING TO LOCK A JOB, PROCEED.
	PUSHJ	P,LOCK0##	;SHUFFLER AND SWAPPER ARE IDLE - SO SEE IF JOB CAN BE LOCKED
	  JFCL			;IGNORE POSSIBLE SKIP RETURN
>	; END OF CONDITIONAL ASSEMBLY ON FTLOCK

	MOVEI	P4,.C0CDB##	;SHUFFLER AND SWAPPER CLOBBER P4
				; SETUP CPU DATA BLOCK ADR AGAIN
;SCHEDULAR--SEARCH THRU QUEUES ACCORDING TO SSCAN TABLE
;FOR 1ST JOB IN CORE--RETURN ITS NO. IN J

SCHED::	SETZM	.CPPLT##(P4)	;CLEAR POTENTIALLY LOST TIME FLAG
	PJRST	@.CPSCH##(P4)	;GO DO CPU DEPENDENT SCHEDULING
				;EACH SCHEDULER CALLS SCHEDJ TO FIND RUNNABLE JOBS

;SCHEDJ IS CALLED TO FIND A RUNNABLE JOB
;IT RETURNS WITH THE HIGHEST PRIORITY RUNNABLE JOB IN J
;CALL:	PUSHJ	P,SCHEDJ
;	RETURN HERE WITH J SET UP

SCHEDJ::
IFN FTTRPSET,<
	SKIPE	J,.CPSTS##(P4)	;TIMESHARING TURNED OFF? (TRPSET)
	JRST	[SKIPGE	JBTSTS##(J)	;RUNNABLE?
		 PUSHJ	P,INRNQ		;YES, IN A RUN QUEUE?
		 JRST	SCHD1		;NO TO EITHER QUESTION
		 MOVEI	T2,SCHD1	;IN CASE HE'S NOT REALLY RUNNABLE
		 JRST	SCHEDB		;GO SEE
]
>;END IFN FTTRPSET
	MOVE	U,.CPSCN##(P4)	;ADDRESS OF SCAN TABLE
	MOVE	T1,.CPSFC##(P4)	;GET COUNT OF UNFAIR SCHEDULES
	CAMGE	T1,MFC##(U)	;HAS IT REACHED MAXIMUM FAIRNESS COUNT?
	JRST	SCHDJ1		;NO, DONT USE SECONDARY SCAN TABLE
	SETZM	.CPSFC##(P4)	;YES, CLEAR SCHEDULER FAIRNESS COUNT
	MOVE	U,SSCN##(U)	;AND GET ADDRESS OF SECONDARY SCAN TABLE
				; (PQ1 AND PQ2 REVERSED)
SCHDJ1:	MOVEM	U,.CPSUD##(P4)	;RECORD WHICH SCAN WE USED
	SETZM	UNWIND		;FLAG THAT WE ONLY UNWIND ONCE/SCAN
IFN FTDISK,<
	SKIPE	J,FORCEF	;FORCING ANYONE WITH SHAR. RESOURCE?
	PUSHJ	P,INRNQ		;IS JOB IN A RUN QUEUE?
	 JRST	SCHED2		;NO! DON'T BOTHER CHECKING
	MOVEI	T2,SCHED2	;PREPARE TO SCAN NORMALLY
				;BUT START WITH JOB IN FORCEF 
	SKIPGE	JBTSTS##(J)	;IF NOT RUNNABLE, SCHED NORMALLY. (POSSIBLE
				; IF JOB HAS STOPPED AND GIVEN UP RESOURCE
	JRST	SCHEDB		; BUT FLAG HAS NOT YET BEEN CLEARED)
>	;END OF FTDISK CONDITIONAL
SCHED2:	JSP	T1,QSCAN	;BEGIN SCAN
	  JRST	SCHD1		;NO MORE JOBS--RETURN NULLJOB
SCHEDB:
IFN FTMS,<
	PUSHJ	P,DXRUN##	;GO CHECK IF JOB IS RUNNABLE ON THIS PROCESSOR
	  JRST	(T2)		;NO, GO CONTINUE SCANNING
				; (ALSO SETS .CPPLT IF CAN'T RUN ON CPU1 BECAUSE HI-SEG
				; BEING SHUFFLED, SWAPPED, OR EXPANDED ON CPU 0)
>	; END OF CONDITIONAL ASSEMBLY ON FTMS

	MOVE	T3,JBTSTS(J)	;JOB STATUS
	MOVEI	F,JS.SCN	;JOB SCANNED BIT
	TLNN	T3,SWP		;SWAPPED IN?
	IORM	F,JBTST2(J)	;YES. SET SCANNED BIT

	LDB	F,PJBSTS##	;GET STATE CODE
	JUMPE	F,SCHEDC	;IF ZERO, LET HIM THROUGH
IFN FTDISK,<
	PUSHJ	P,CJFRCX	;IF JOB IS IN FORCEF WITH RESOURCE, IGNORE JXPN
				; SO JOB CAN BE RUN + THEN SWAPPED
>
IFN FTKI10!FTKL10,<
	CAIE	F,EVQ		;EV IS HANDLED SEPARATELY ABOVE.
>
	TLNE	T3,SWP+JRQ+SHF+JXPN	;IF SWAPPED, SHUFFLING,
	  JRST	(T2)		;REQUEING, OR EXPANDING - GIVE UP
	CAIL	F,MINQ		;NON-ZERO. IS HE WAITING FOR A
	CAILE	F,MAXQ		;SHAREABLE RESOURCE?
	  JRST	(T2)		;NO. CAN'T HELP HIM
	SKIPE	AVTBMQ##(F)	;YES - IS IT FREE?
	JRST	SCHEDA		;YES. TRY TO GIVE IT TO HIM
	SKIPE	UNWIND		;SHOULD WE UNWIND?
	 JRST	(T2)		;NO. ALREADY TRIED ONCE THIS SCAN
	PUSH	P,J		;SAVE J SO WE CAN CONTINUE SCAN LATER
	SETOM	UNWIND		;SAY WE HAVE UNWOUND ONCE
	SETZ	T4,		;CLEAR LEVEL COUNTER
UNWND1:
IFN FTDISK,<
	CAIN	F,MQQ		;MON BUF QUE?
	JRST	MQUNWD		;YES. #@!%$&
>
	HRRZ	J,USTBMQ##(F)	;GET USER OF RESOURCE WE WANT
	JUMPE	J,UNWNDF	;FAIL IF NO ONE.
	CAMN	J,(P)		;SAME AS US?
	JRST	UNWNDF		;SHOULD NEVER HAPPEN %&'#@!
	LDB	F,PJBSTS##	;GET HIS STATE CODE
	JUMPE	F,UNWNDS	;RUN. TRY TO RUN HIM
	CAIL	F,MINQ		;NOT RUN. SHAREABLE RESOURCE?
	CAILE	F,MAXQ
	  JRST	UNWNDF		;NO. FAIL EXIT
IFN FTKI10!FTKL10,<
	CAIN	F,EVQ		;WAITING FOR EV?
	JRST	UNWNDF		;YES. CAN'T UNWIND THAT!
>
	SKIPE	AVTBMQ##(F)	;AVAILABLE?
	  JRST	UNWNDS		;YES. TRY TO SELECT
	CAIGE	T4,^D10		;LOOPING?
	AOJA	T4,UNWND1	;NOT YET
	JRST	UNWNDF		;APPEAR TO BE LOOPING
IFN FTDISK,<
MQUNWF:	POP	P,P2		;RESTORE ACS
	POP	P,P1
>
UNWNDF:	POP	P,J		;RESTORE JOB NUMBER FROM SCAN
	JRST	(T2)		;AND CONTINUE SCAN

IFN FTDISK,<
MQUNW5:	HLRZ	J,P2		;GET NUMBER OF THE DESIRED JOB
	POP	P,P2		;RESTORE ACS
	POP	P,P1
	JUMPE	J,UNWNDF	;FAIL IF FOUND NO ONE
>
UNWNDS:	PUSHJ	P,CHKRUN	;MAKE SURE WE CAN RUN HIM
	  JRST	UNWNDF		;CAN'T. #%$&@!
	POP	P,T3		;FIX UP PDL
	MOVEI	T3,JS.OOO	;FLAG FOR CLOCK1 TO STOP WHEN GIVES UP
	IORM	T3,JBTST2##(J)	;ALL HIS SHAREABLE RESOURCES
	AOS	UNWNDC##	;COUNT AN UNWIND
	LDB	F,PJBSTS##	;GET STATE CODE.
	JUMPE	F,SCHEDC	;RUN HIM IF ZERO
	JRST	SCHEDE		;GIVE HIM RESOURCE AND RUN

IFN FTDISK,<
MQUNWD:	PUSH	P,P1		;SAVE SOME ACS
	PUSH	P,P2
	SETZ	P1,		;CLEAR P1 FOR NXTJBB
	MOVEI	P2,777777	;PUT LARGE SMALLEST CHAIN SO FAR VALUE AND JOB 0
MQUNW1:	SETZ	T4,		;INIT LENGTH OF THIS CHAIN
MQUNW2:	PUSHJ	P,NXTJBB##	;GET OWNER OF NEXT MQ
	  JRST	MQUNW5		;NO MORE BUFFERS. EXIT
	MOVE	J,T3		;PUT NUMBER IN J
MQUNW3:	JUMPE	J,MQUNWF	;IF ZERO, QUIT. NOT SUPPOSED TO BE
	LDB	F,PJBSTS##	;GET STATE CODE
	JUMPE	F,MQUNW4	;END OF CHAIN IF ZERO
	CAIL	F,MINQ		;WAITING FOR SHAREABLE RESOURCE TOO?
	CAILE	F,MAXQ
	  JRST	MQUNW1		;NO. TRY NEXT BUFFER
	CAME	J,-2(P)		;SAME AS US?
	CAIN	F,MQQ		;OR MQ?
	JRST	MQUNW1		;YES - TRY NEXT CHAIN
IFN FTKI10!FTKL10,<
	CAIN	F,EVQ		;WAITING FOR EV?
	JRST	MQUNW1		;YES. CAN'T UNWIND THAT!
>
	SKIPE	AVTBMQ##(F)	;IS IT AVAILABLE?
	  JRST	MQUNW4		;YES. END OF CHAIN
	HRRZ	J,USTBMQ##(F)	;NO. TRY NEXT LEVEL
	CAIGE	T4,^D10		;LOOPING?
	AOJA	T4,MQUNW3	;NO. COUNT DEPTH
	JRST	MQUNW1		;YES. TRY NEXT CHAIN

MQUNW4:	PUSHJ	P,CHKRUN	;IS HE RUNNABLE?
	  JRST	MQUNW1		;NO. TRY NEXT BUFFER.
	CAIL	T4,(P2)		;YES. WHOSE CHAIN IS SHORTER?
	JRST	MQUNW1		;OLD CHAIN SHORTER
	MOVE	P2,T4		;SAVE LENGTH OF NEW CHAIN
	HRLI	P2,(J)		;AND JOB NUMBER
	JRST	MQUNW1		;AND LOOK AT CHAIN FROM NEXT BUFFER
	>;END OF IFN FTDISK
; SUBROUTINE TO CHECK THAT JOB FOUND BY UNWIND CAN BE RUN
;	CALL IS
;			MOVE	J,JOB-NUMBER
;			PUSHJ	P,CHKRUN
;			  NOT RUNNABLE RETURN
;			RUNNABLE RETURN
; SETS T3 TO JBTSTS(J). MAY DESTROY F

CHKRUN:	SKIPL	T3,JBTSTS##(J)	;RUN BIT ON?
	 POPJ	P,		;NO.
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,INRNQ		;IS JOB IN A RUN QUEUE?
	 JRST	TPOPJ		;NO. CAN'T RUN IT
	POP	P,T1		;RESTORE T1
IFN FTDISK,<
	PUSHJ	P,CJFRCX	;CHECK FOR JOB IN FORCEF WITH RESOURCE
				;IF SO, IGNORE JXPN TEMPORARILY SO HE
				; CAN GIVE UP THE RESOURCE TO GET SWAPPED
>
IFN FTLOCK,<
	TRNN	T3,LOK
>
	TLNE	T3,SWP+JRQ+SHF+JXPN+CMWB ;FLAGS THAT CAN'T USE
	 POPJ	P,		;NOT RUNNABLE
IFE FTMS,<
	JRST	CPOPJ1##	;RUNNABLE!
>
IFN FTMS,<
	PJRST	DXRUN##		;CHECK THAT WILL RUN ON THIS CPU
				;AND EXIT SKIP/NON-SKIP
>

;ROUTINE TO IGNORE JXPN FOR JOB IN FORCEF WITH SHAREABLE RESOURCE
;ENTER WITH JBTSTS IN T3 (OR MASK INCLUDING JXPN)
;ALWAYS EXITS NONSKIP
IFN FTDISK,<
CJFRCX:	CAMN	J,FORCEF	;JOB IN FORCEF?
	PUSHJ	P,FLSDR##	;DOES HE HAVE DISK RESOURCE?
	  POPJ	P,		;NO, OK AS IS
	TLZ	T3,JXPN		;YES, IGNORE JXPN TEMPORARILY
	POPJ	P,		;RETURN

;ROUTINE TO ASSURE JOB IN FORCEF DOESN'T RUN IF HAS NO RESOURCE
; BUT IGNORE JXPN IF JOB IS IN FORCEF WITH RESOURCE SO HE CAN GIVE
; IT BACK
;ENTER WITH JOBSTS OR MASK IN F
;RETURN NON-SKIP IF IN FORCEF AND HAS NO RESOURCE, OTHERWISE SKIP
CJFWRX:	CAME	J,FORCEF	;JOB IN FORCEF?
	  JRST	CPOPJ1##	;NO, SKIP RETURN
	PUSHJ	P,FLSDR##	;SHAREABLE DISK RESOURCE?
	  POPJ	P,		;NO, DON'T LET HIM RUN
	TLZ	F,JXPN		;IGNORE JXPN
	JRST	CPOPJ1##	; AND SKIP
>
SCHEDA:
IFN FTDISK,<
	CAME	J,FORCEF	;FORCING JOB WITH SHAREABLE RESOURCE?
	  JRST	SCHEDE		;NO. GIVE HIM RESOURCE AND RUN HIM
	PUSHJ	P,FLSDR##	;DOES HE STILL HAVE THE RESOURCE?
	  JRST	(T2)		;NO - DON'T GIVE HIM ONE
				;YES - LET HIM HAVE MORE
>	;END FTDISK
SCHEDE:
IFN FTDISK,<
	CAIN	F,MQQ		;IS THIS THE MONITOR BUFFER QUEUE?
	SOSGE	MQFRE1##	;YES. DON'T RESET MQAVAL IF STILL FREE MON BUF
>	;END OF FTDISK CONDITIONAL
	SETZM	AVTBMQ##(F)	;CLEAR AVAL FLAG
	MOVEM	J,USTBMQ##(F)	;REMEMBER WHO THE RESOURCE WAS GIVEN
				; TO SO IT CAN BE RETURNED IN THE EVENT OF
				; A CATASTROPHIC ERROR, E.G., SWAP READ ERROR
	MOVSI	T3,WTMASK	;CLEAR WAIT STATE
	ANDCAM	T3,JBTSTS##(J)
SCHEDC:	MOVEM	J,.CPPLT##(P4)	;SET POTENTIALLY LOST TIME FLAG FOR CLOCK1
	MOVE	F,JBTSTS##(J)	;IS THIS JOB SWAPPED OUT
IFN FTDISK,<
	PUSHJ	P,CJFWRX	;CHECK FOR JOB IN FORCEF
	  JRST	(T2)		;IN FORCEF BUT NO RESOURCE, DON'T RUN
				;EITHER NOT IN FORCEF, OR IS AND HAS
				; RESOURCE, IN WHICH CASE JXPN CLEARED IN F
>
IFN FTLOCK,<
	TRNN	F,LOK		;DON'T RUN JOB CURRENTLY BEING LOCKED IN CORE
>	; END OF CONDITIONAL ASSEMBLY ON FTLOCK
	TLNE	F,SWP+SHF+JXPN+JRQ ;MONITOR WAITING FOR I/O TO STOP,
				; OR JOB EXPANDING CORE?
				; OR JOB NEEDS REQUEING (SWAP READ ERROR)?
	JRST	(T2)		;YES--CONTINUE SCAN,JOB CANNOT BE RUN

IFN FTKL10&FTMS,<
	PUSHJ	P,SCDCSH##	;IS THIS JOB RUNNABLE WITH RESPECT TO THE
				; CACHE?
	  JRST	(T2)		;NO, GO FIND ANOTHER JOB TO RUN
				; NOTE THAT THIS IS DONE AFTER LOST
				; TIME FLAG IS SET SO THAT CACHE LOST
				; TIME IS INCLUDED IN SYSTEM LOST TIME
>;END IFN FTKL10&FTMS

	CAMN	J,FORCEF	;FORCING A GUY WITH SHARABLE RESOURCE?
	AOS	FORCFC##	;YES, COUNT A FORCED SCHEDULE
IFN FTNSCHED,<
	SETZM	.CPSQF##(P4)	;ASSUME NOT FROM SUBQUE
	MOVEI	T1,SQFORA
	CAIN	T1,(T2)		;FROM SUBQUE?
	SETOM	.CPSQF##(P4)	;YES, TELL CLOCK1

>;END IFN FTNSCHED
	HLREM	T2,.CPQUE##(P4)	;YES--SAVE ITS Q
IFN FTRSP,<		;RESPONSE DATA?
	MOVEI	T1,.CPACR##(P4)	;BASE ADR FOR CPU RESPONSE DATA THIS CPU
	MOVSI	T2,(JR.RCR)	;RECORDED CPU RESPONSE FOR THIS JOB
	PUSHJ	P,RSPREC##	;RECORD RESPONSE TIME (UNLESS ALREADY REC)
	MOVE	T1,.CPACR##(P4)	;STORE DATA IN
	MOVE	T2,.CPACR##+1(P4)	; THE WRONG
	MOVEM	T1,.CPODA##(P4)	; PLACE FOR
	MOVEM	T2,.CPODA##+1(P4)	; OLD CUSPS
				; (DO NOT RECORD AS ONE OF TI, TO, RN, ALSO)
>	; END OF CONDITIONAL ASSEMBLY ON FTRSP
	SETZM	.CPPLT##(P4)	;CLEAR POTENTIALLY LOST TIME AS A USER IS TO BE RUN
IFN FTKL10&FTMS,<
	SETZM	.CPCLF##(P4)	;CLEAR CACHE LOST FLAG ALSO
>;END IFN FTKL10&FTMS
	MOVE	T2,.CPSUD##(P4)	;GET START OF SCAN TABLE USED
	CAME	T2,.CPSCN##(P4)	;WAS IT PRIMARY SCAN?
	 POPJ	P,		;NO. IT WAS FAIRNESS SCAN
	CAMGE	U,FSCN##(T2)	;DID THIS SCAN REACH FAIR TERRITORY
	AOSA	.CPSFC##(P4)	;NO, COUNT UP UNFAIR SCANS
	SETZM	.CPSFC##(P4)	;YES, CLEAR SCHED FAIRNESS
	POPJ	P,		;RETURN

SCHD1:	SETZ	J,		;RETURN NULL JOB
IFN FTMS,<
	SKPCPU	(0)		;ONLY REQUE AND RETRY FOR CPU0
	POPJ	P,		;RETURN NULL JOB
>
	SKIPN	PASFLG##	;LOOPING?
	SKIPG	QJOB		;NO. ANY JOBS TO REQUE?
	POPJ	P,		;LOOPING OR NONE TO REQUE
	SETOM	PASFLG##	;SAY WE ARE NOW LOOPING
	JRST	CKJB1		;AND GO REQUE EVERYBODY
; THIS SUBROUTINE DETERMINES HOW TO REQUE THE JOB

QREQ:	MOVE	T2,JBTSTS##(J)	;JOB STATUS WORD
	TDNE	T2,[JDC+JS.DEP+(CMWB)]	;ANY STRANGE BITS ON?
	JRST	QREQ1		;YES, GO DO SOME SPECIAL THINGS
QREQ0:	LDB	U,PJBSTS##	;GET QUEUE CODE
	JUMPGE	T2,QSTOPT	;IS RUN BIT ON? IF NOT, JOB GOES TO STOP Q.
IFN FTMS,<
	PUSHJ	P,MSRQT##	;GO CHECK IF JOB COMING OUT OF WS,TS, OR DS
				; (SETS UUO COUNTER IN CASE JOB WAS DOING
				; I/O UUO THAT STARTED ON SLAVE AND GOT 
				; SWITCHED TO MASTER.
>
	HLRZ	T1,QBITS(U)	;GET DISPATCH ADDRESS FOR REQUE METHOD
	JRST	(T1)
QREQ1:	MOVEI	U,QCMW		;ASSUME COMMAND WAIT
	TLNN	T2,CMWB		;IS JOB IN COMMAND WAIT?
	JRST	QREQ2		;NO--WAIT STATE CODE DETERMINES NEW QUEUE
	TLNE	T2,SWP+JXPN	;YES--IS JOB ON DISK, OR TRYING TO EXPAND?
	PJRST	QXFER		;YES--PUT JOB IN COMMAND WAIT QUEUE

IFN FTDAEM,<
QREQ2:	MOVEI	U,QJDCW		;ASSUME DAEMON WAIT
	TRNN	T2,JDC!JS.DEP	;IS IT?
	JRST	QREQ0		;NO, JUST REQUE BY STATE CODE
	TRNE	T2,JS.DEP	;ERROR LOGGING? (JDC IS BY REQUEST ONLY)
	PUSHJ	P,FLSDR##	;YES. PUT IN DAEMON QUEUE IF JOB HAS NO RESOURCES.
	  JRST	.+2		;(DOESN'T)
	JRST	QREQ0		;HAS A RESOURCE, DON'T PUT HIM IN JDCQ.
	PUSHJ	P,ZERIPT	;CLEAR IN-CORE PROTECT TIME
	PJRST	QXFER		;INTO JDCQ
>;END IFN FTDAEM

IFE FTDAEM,<QREQ2==QREQ0>
DEFINE X(A,B,C)
<	XLIST
	Q'A'T==QREQ6
	Q'A'W==-1
	LIST
>

	RWAITS
QIOWT==QREQ6
QDIOWT==QREQ6
QPIOWT==QREQ6
QNAPT==QREQ6			;IN CASE OF CONTROL C WHILE IN NAP, ETC.

QARNDT:
IFN FTNSCHED,<
	JUMPN	P3,QARND2	;IF RUNNING CLASS SYSTEM SCHEDULER,
				; DON'T CLEAR IN CORE PROTECT TIME.
>;END IFN FTNSCHED
	LDB	T1,PJBST2##	;GET REAL QUEUE
	CAIN	T1,PQ2		;IS IT PQ2?
	 JRST	QARND1		;YES. REQUE CLEARING ICPT
	LDB	T1,PDYIPT	;NOT PQ2. ANY ICPT LEFT?
	JUMPG	T1,QARND2	;IF ANY LEFT, DON'T CHANGE IT
QARND1:	PUSHJ	P,CLRIPT	;SET BIT FOR NO ICPT
	PUSHJ	P,SETIPT	;RESET ICPT SO JOB WILL CYCLE
QARND2:
IFE FTNSCHED,<
	MOVEI	U,QTIME0	;REQUE AROUND RUN QUEUES
>
IFN FTNSCHED,<
	MOVE	U,[EXP QTIME0
		   EXP QTIME1](P3)
				;GET PROPER TABLE FOR PROPER SCHEDULER
>
	PJRST	QXFER		;DO TRANSFER
REPEAT 0,<
QPST:
	PUSHJ	P,INRNQ		;IS JOB IN A RUN QUEUE?
	  PUSHJ	P,QCHNG		;NO. PUT HIM INTO A RUN QUEUE
	CAMN	J,VMQJOB##	;HAS JUST THIS JOB EXCEEDED PAGE RATE?
	JRST	QPST1		;YES. REQUE TO REAR
	SKIPGE	VMQJOB		;SYSTEM PAGE RATE EXCEEDED?
	SKIPN	SLECNT##	;SOMEONE WANT TO USE THE SWAPPING/PAGING CHANNEL?
	JRST	QPSTN		;NO
QPST1:	PUSHJ	P,FNDPDB	;NEED PDB
	  JRST	QPSTN		;...
	PUSHJ	P,TOBACK	;PUT TO REAR OF QUEUES, DON'T RESET Q.R.T.

	JRST	QPSTN		;AND FALL INTO NORMAL QUEUE TRANSFER
>;END REPEAT 0

QWST:
QDST:	PUSHJ	P,INRNQ		;IS JOB IN A RUN QUEUE?
	PUSHJ	P,QCHNG		;NO. PUT HIM IN A RUN QUEUE

QPST:
QPSTN:	MOVSI	T1,WTMASK	;CLEAR WAIT STATE CODE
	ANDCAM	T1,JBTSTS##(J)
	POPJ	P,		;AND EXIT QREQ. (NO QUE TRANSFER)

QTIOWT:
QJDCT:	PUSHJ	P,ZERIPT	;TI, DAEMON CLEARS IN CORE TIME
	JRST	QREQ3		;GO DO THE REQUE

QTST:	MOVSI	T1,WTMASK	;CLEAR WAIT STATE
	ANDCAM	T1,JBTSTS##(J)
;	JRST	QREQ3		;AND PERFORM QUEUE TRANSFER
QRNT:
QSLPT:
QEWT:
QNULT:
QREQ3:	HRRZ	U,QBITS(U)	;PICK UP TRANSFER TABLE ADDRESS
	PJRST	QXFER		;REQUE THE JOB

QSTOPT:	CAIN	U,NULQ		;IS HE REALLY GOING TO THE NULL Q?
	JRST	QNULT		;YES. PUT HIM THERE
	MOVEI	U,QSTOP		;TRANSFER TABLE FOR STOP QUEUE
	PUSHJ	P,ZERIPT	;CLEAR ICPT
	JRST	QXFER		;GO REQUE JOB

QREQ6:	PUSHJ	P,INRNQ		;IS JOB IN RUN QUEUE?
	PUSHJ	P,QCHNG		;NO. PUT IT IN RUN QUEUE
	POPJ	P,
; SUBROUTINE TO PUT JOB INTO A RUN QUEUE.
; DESTROYS U,T1,T2,R,W.  SAVES J
QCHNG:	MOVEI	U,QRNW1		;PUT IN BACK OF PQ1
	PJRST	QXFER		;WITHOUT ASSIGNING QUANTUM TIME

; SUBROUTINE TO DETERMINE IF JOB IS IN A RUN QUEUE.
; RETURN NON-SKIP IF NOT RUN QUEUE
;  RETURN SKIP IF IN RUN QUEUE
; RETURNS PHYSICAL QUEUE NUMBER IN T1
INRNQ::	LDB	T1,PJBST2##	;GET PHYSICAL QUEUE NUMBER
	CAIL	T1,PQ1		;LESS THAN PROCESSOR QUEUE?
	CAIN	T1,CMQ		;NO. COMMAND WAIT?
	 POPJ	P,		;YES. NOT RUN QUEUE
	JRST	CPOPJ1		;RUN QUEUE. GIVE SKIP RETURN

; ROUTINE TO SET ICPT. J AND W MUST BE SET UP AND PDB MUST EXIST
; PRESERVES ALL ACS
SETIPT::PUSH	P,T1
	MOVE	T1,PROT1##	;MINIMUM
	LSH	T1,-1		;IPT IS DECREMENTED EVERY OTHER TICK
	.DPB	T1,PDYIPT##
	JRST	TPOPJ##

; ROUTINE TO CLEAR ICPT. SET UP W. NEEDS J
; PRESERVES ALL ACS EXCEPT W
ZERIPT::PUSHJ	P,FNDPDB##	;FIND PDB
	  POPJ	P,		;NO PDB. NOTHING TO DO.
;	PJRST	CLRIPT		;FALL INTO CLRIPT

; ROUTINE TO SET BIT TO EXPIRE ICPT
; PRESERVES ALL ACS
CLRIPT::PUSH	P,T1
	MOVSI	T1,PDMSWP	;SWAPPABLE BIT
	.IORM	T1,.PDIPT##(W)	;SET IT
	PJRST	TPOPJ##

; SAME AS CLRIPT BUT EXPECTS PDB ADDRESS IN T1
CLRIP1::PUSH	P,T2
	MOVSI	T2,PDMSWP	;SWAPPABLE BIT
	.IORM	T2,.PDIPT##(T1)	;SET IT
	PJRST	T2POPJ##

;SUBROUTINE TO PUT JOB TO BACK OF PQ2
; USES SAME REGISTERS AS QCHNG

TOBACK:	MOVEI	U,QRNW2		;TRANSFER TABLE TO BACK OF PQ2, DONT
	PJRST	QXFER		;CHANGE QUANTUM RUN TIME.


IFN FTNSCHED,<;IF CLASS SYSTEM AND TWO-MODE SCHEDULER
;AS OF THE 603 MONITOR RELEASE, THE SCHEDULER WILL RUN IN TWO
; MODES. ONE MODE IS VERY NEARLY IDENTICAL TO THE ORIGINAL WMU
; SCHEDULER ALGORITHM. THE OTHER MODE IS THE ALGORITHM USED
; IN THE DEC SCHEDULER IN THE 602 MONITOR RELEASE. THE 602
; SCHEDULER MODE IS PROVIDED BOTH FOR THOSE WHO FOUND THE 602
; ALGORITHM SATISFACTORY AND FOR THOSE INSTALLATIONS WHICH RUN
; THE CLASS SYSTEM.  THE WMU ALGORITHM CANNOT SUPPORT THE
; CLASS SYSTEM.
;
;THIS ROUTINE IS CALLED AT THE BEGINNING OF THE SCHEDULER. P3 IS
; SET TO 0 IF THE SCHEDULER IS RUNNING IN "WMU" MODE, OR SET
; TO 1 IF THE SCHEDULER IS RUNNING IN "DEC" MODE. THE USE OF P3
; AS A GLOBAL FLAG IS TO REDUCE OVERHEAD.
; WARNING: THE SWAPPER CALLS ROUTINES THAT SMASH P3, SO P3 MUST
; BE SAVED SOMEWHERE.

SCDTYP:	EXCH	P3,(P)		;SAVE P3 ON STACK, GET CALLING PC
	MOVE	T1,P3		;SAVE PC IN T1 FOR CALL BACK
	MOVE	P3,TYPSCD	;SET P3 TO BE ZERO FOR WMU MODE OR
				; ONE FOR CLASS SYSTEM MODE.
	PUSHJ	P,(T1)		;CALL THE CALLER
	  JRST	.+2		;NON-SKIP RETURN (ALWAYS GET HERE REALLY)
	AOS	-1(P)		;SKIP RETURN (NEVER GET HERE)
	POP	P,P3		;RESTORE ORIGINAL P3
	POPJ	P,		;RETURN
>;END IFN FTNSCHED
IFN FTPSCD,<
; ROUTINE TO COUNT NUMBER OF TIMES JOB EXPIRED IN CORE PROTECT BY QUE
CNTICP:	PUSH	P,T1		;SAVE T1
	LDB	T1,PJBST2##	;GET PHYICAL STATE CODE
	CAIN	T1,PQ1		;PQ1?
	AOS	XPICP1		;YES
	CAIN	T1,PQ2		;PQ2?
	AOS	XPICP2		;YES
	CAILE	T1,CMQ		;AN HPQ?
	AOS	XPICHP		;YES
	JRST	TPOPJ		;RESTORE T1 AND EXIT

; ROUTINE TO COUNT NUMBER OF TIMES JOB EXPIRED IN QUE TIME BY QUE
CNTINQ:	PUSH	P,T1		;SAVE T1
	LDB	T1,PJBST2##	;GET PHYSICAL STATE CODE
	CAIN	T1,PQ1		;PQ1?
	AOS	XPQRP1		;YES
	CAIN	T1,PQ2		;PQ2?
	AOS	XPQRP2		;YES
	CAILE	T1,CMQ		;AN HPQ?
	AOS	XPQRHP		;YES
	JRST	TPOPJ		;RESTORE T1 AND EXIT
$LOW
SCDPER::		;PERFORMANCE STATS TABLE
%DTASL::BLOCK	1	;DTA GENERATED SLEEPS
%MTASL::BLOCK	1	;DTA GENERATED SLEEPS
%EWCNT::BLOCK	1	;MTA GENERATED SLEEPS
%TISJB::BLOCK	1	;TTY INPUT SATISFIED
%TOSJB::BLOCK	1	;TTY OUTPUT SATISFIED
%PISJB::BLOCK	1	;PTY INPUT SATISFIED
%POSJB::BLOCK	1	;PTY OUTPUT SATISFIED
REQSS::	BLOCK	1	;NUMBER OF REQUEUES FROM SS INTO PQ1
REQWK::	BLOCK	1	;NUMBER OF REQUEUES FROM WAKE INTO PQ1
REQJSD::BLOCK	1	;NUMBER OF REQUEUES FROM DAEMON SATISFIED INTO PQ1
REQPQ1:	BLOCK	1	;NUMBER OF OTHER REQUEUES INTO PQ1
XPQRP1:	BLOCK	1	;NUMBER OF JOBS IN PQ1 WHICH EXPIRED QUANTUM RUN TIME
XPQRP2:	BLOCK	1	;NUMBER OF JOBS IN PQ2 WHICH EXPIRED QUANTUM RUN TIME
XPQRHP:	BLOCK	1	;NUMBER OF JOBS IN HPQ WHICH EXPIRED QUANTUM RUN TIME
XPICP1:	BLOCK	1	;NUMBER OF JOBS IN PQ1 WHICH EXPIRED INCORE PROTECT
XPICP2:	BLOCK	1	;NUMBER OF JOBS IN PQ2 WHICH EXPIRED INCORE PROTECT
XPICHP:	BLOCK	1	;NUMBER OF JOBS IN HPQ WHICH EXPIRED INCORE PROTECT
SWPKP1:	BLOCK	1	;NUMBER OF K SWAPPED IN FOR PQ1 JOBS
SWPKP2:	BLOCK	1	;NUMBER OF K SWAPPED IN FOR PQ2 JOBS
SWPKHP:	BLOCK	1	;NUMBER OF K SWAPPED IN FOR HPQ JOBS
SWPJP1:	BLOCK	1	;NUMBER OF PQ1 JOBS SWAPPED IN
SWPJP2:	BLOCK	1	;NUMBER OF PQ2 JOBS SWAPPED IN
SWPJHP:	BLOCK	1	;NUMBER OF HPQ JOBS SWAPPED IN
RNTPQ1::BLOCK	1	;TICKS CHARGED TO PQ1
RNTPQ2::BLOCK	1	;TICKS CHARGED TO PQ2
RNTHPQ::BLOCK	1	;TICKS CHARGED TO HPQS
%PERLN==:<.-1-SCDPER>B26
	BLOCK	10
$HIGH
CNTSWP:	PUSH	P,T1		;SAVE ACS
	PUSH	P,T2
	PUSH	P,J
	LDB	T1,IMGIN	;GET INPUT SIZE
	LDB	T2,IMGOUT	;AND OUTPUT SIZE IN T2
	CAMLE	T1,T2		;GET MINIMUM IN T1
	MOVE	T1,T2		;T2 WAS SMALLER
	LSH	T1,P2KLSH##	;IN K
	CAILE	J,JOBMAX	;HIGH SEG?
	MOVE	J,SWPIN		;YES
	LDB	T2,PJBST2##	;GET PHYSICAL QUE
	POP	P,J		;RESTORE JOB
	CAIN	T2,PQ1		;PQ1?
	 JRST	CNTSP1		;YES
	CAIN	T2,PQ2		;PQ2?
	 JRST	CNTSP2		;YES
	CAIG	T2,CMQ		;HPQ?
	 JRST	CNTSXT		;NO. EXIT
	ADDM	T1,SWPKHP	;STORE K
	CAIG	J,JOBMAX	;LOWSEG?
	AOS	SWPJHP		;YES. COUNT A JOB
CNTSXT:	POP	P,T2
	JRST	TPOPJ		;RESTORE ACS
CNTSP1:	ADDM	T1,SWPKP1	;COUNT K IN PQ1
	CAIG	J,JOBMAX	;LOWSEG?
	AOS	SWPJP1		;YES. COUNT JOB
	JRST	CNTSXT		;EXIT
CNTSP2:	ADDM	T1,SWPKP2	;COUNT K IN PQ2
	CAIG	J,JOBMAX	;LOWSEG?
	AOS	SWPJP2		;YES. COUNT JOB
	JRST	CNTSXT		;EXIT
> ;IFN FTPSCD
SUBTTL	QCSS R. KRASIN

;THIS ROUTINE MUST BE ASSEMBLED WITH THE CONFIGURATION
;TAPE TO DEFINE NUMBER OF JOBS
;THIS SECTION CONTAINS 2 ROUTINES FOR Q MANIPULATION
;AND NECESSARY TABLES FOR SPECIFING OPERATIONS PERFORMED
;BY THEM.


;STORAGE:
;EACH Q IS A RING STRUCTURED, FOWARD AND BACKWARD
;LINKED SRING LIST. THE "FIRST" LINK IN A Q IS
;A Q-HEADER POINTING TO THE FIRST AND LAST MEMBERS OF THE Q.
;A NULL Q HAS ONE LINK--THE Q-HEADER ITSELF.  THE LINKS MAKING
;UP THE QS ARE CONTAINED IN A TABLE (JBTQ) WITH NEGATIVE
;INDICIES (ADDRESSES LESS THAN JBTQ) USED FOR Q-HEADERS AND
;POSITIVE INDICIES USED FOR MEMBERS (JOBS). THUS ONLY ONE WORD
;PER LINK IS NECESSARY--ITS ADDRESS RELATIVE TO JBTQ GIVES THE
;JOB NO. (OR Q NO. IF NEGATIVE) WHICH IT REPRESENTS WHILE
;ITS CONTENTS CONTAINS THE LINKING POINTERS. THESE
;POINTERS ARE ALSO INDICIES RELATIVE TO JBTQ RATHER THAN
;ABSOLUTE ADDRESSES--RH(LINK)=FOWARD POINTER;
;LH(LINK)=BACKWARD POINTER.
;A JOB IS ASSUMED TO BE IN NO MORE THAN ONE Q AT A TIME, AND
;THE NULL JOB (JOB 0) DOES NOT APPEAR IN THE QS  (I.E. JBTQ
;ITSELF IS THE Q-HEADER FOR Q 0).

;ROUTINES:
;BOTH ROUTINES ARE "TABLE DRIVEN" IN THE SENSE THAT THE
;CALLING ROUTINE PROVIDES THE ADDRESS OF A TABLE WHICH
;DEFINES THE SPECIFIC OPERATIONS TO BE PERFORMED.

EQFIX==QFIX+1B0
EQLNKZ==QLNKZ+1B0
QXFER:
IFN FTHALT,<
	SKIPLE	J		;TRYING TO REQUE JOB 0?
	CAILE	J,JOBMAX##	; OR IS THE JOB NUMBER OUT OF RANGE?
	STOPCD	.,STOP,RJZ,	;++REQUEUE JOB ZERO
				; MESSED UP AND SYSTEM WILL HANG IF ALLOWED
>	; END OF CONDITIONAL ASSEMBLY ON FTHALT
	MOVE	R,1(U)		;GET TRANSFER TABLE ADDRESS
	JRST	@(U)		;DISPATCH




;DEST-Q AS FUNCTION OF JOB QUE, QUANTUM AS FUNCTION OF JOB SIZE

QLNKZ:	PUSHJ	P,JOBSIZ##	;GET SIZE OF JOB
	PUSHJ	P,INRNQ		;IS JOB IN A RUN QUEUE?
	STOPCD	.,STOP,NTE,	;NOT PROCESSOR QUE. ERROR.
	ADD	T1,1(U)		;ADD TABLE ADDRESS TO QUE NUMBER
	HRRO	R,0(T1)		;GET QUE HE GOES TO
	HLRZ	T1,0(T1)	;GET PARAMETERS FOR QUE HE IS GOING TO
	SKIPGE	1(U)		;WANT QUANTUM TIME?
	JRST	QFIXD		;NO - ALL FIXED
	IMUL	T2,QMLTBL##(T1)	;SIZE * MULTIPLIER
	PUSH	P,T3		;SAVE T3
	IDIV	T2,QRANGE##	;GET IN PROPER UNITS
	POP	P,T3		;GET T3 BACK
	ADD	T2,QADTBL##(T1)	;ADD IN BASE AMOUNT FOR QUE
	CAMLE	T2,QMXTBL##(T1)	;LESS THAN MAXIMUM ALLOWED?
	MOVE	T2,QMXTBL##(T1)	;NO. USE MAXIMUM
	MOVEM	T2,QNTRUN	;STORE IT FOR QFIX
	HRLI	R,QNTRUN	;AND TELL QFIX WHERE WE PUT IT
	JRST	QFIXD		;DO TRANSFER

	$LOW
QNTRUN:	0
	$HIGH

;FIXED DEST-Q
QFIX:
IFN FTHPQ,<
	HRRZ	T2,R		;PICK UP QUEUE
	CAIL	T2,-PQ2		;IS IT A RUN QUEUE?
	CAILE	T2,-PQ1
	 JRST	QFIXD		;NO.
	LDB	T2,HPQPNT##	;YES. SHOULD IT GO TO A HPQ
	JUMPE	T2,QFIXD	;NO. DON'T DO ANYTHING
	HRR	R,QTTAB##-1(T2)	;YES. GET HPQ POSITION
	SKIPL	R		;WAS QUANTUM TIME REQUESTED?
	HRLI	R,QQSTAB##-1(T2) ;YES. GIVE QUANTUM TIME
>	; END OF CONDITIONAL ASSEMBLY ON FTHPQ
QFIXD:	AOS	RQCNT##		;COUNT A REQUEUE

IFN FTMETR,<
	SKIPL	T2,MP1##	;METER QUEUE XFERS?
	JRST	QFIXA		;NO
	HRRI	T1,(J)		;YES, GET JOB NR
	HRLI	T1,(R)		;AND QUEUE#
	CAME	J,MPDPAR##(T2)	;RIGHT JOB?
	SKIPGE	MPDPAR##(T2)	;OR WANT ALL JOBS?
	PUSHJ	P,@MPDPRA##(T2)	;YES, CALL POINT ROUTINE
QFIXA:
>	;END CONDITIONAL ON FTMETR
IFN FTNSCHED,<
	JUMPE	P3,QFIXB	;DON'T MAINTAIN SUBQUEUES IN NON-CLASS SCHEDULER
	LDB	T1,PJBST2##	;GET SOURCE QUEUE
	CAIE	T1,PQ2		;FROM PQ2?
	JRST	QFIXB		;NO
	MOVE	T2,JBTSQ##(J)	;YES, DELETE FROM CURRENT SUBQUEUE (CLASS)
	MOVS	T1,T2
	HRRM	T2,JBTSQ##(T1)	;NEW FORWARD LINK
	HRLM	T1,JBTSQ##(T2)	;AND BACK LINK

>;END IFN FTNSCHED

QFIXB:	HRRE	T1,R		;PICK UP QUEUE NUMBER
	MOVMS	T1		;ABS VALUE
	DPB	T1,PJBST2##	;STORE HIS REAL QUEUE
IFN FTPSCD,<
	CAIN	T1,PQ1		;TO PQ1?
	AOS	REQPQ1		;YES. COUNT IT
>
	MOVE	T2,JBTQ##(J)	;DELETE JOB FROM SOURCE-Q
	MOVS	T1,T2		;T2=FORW. LINK, T1=BACK LINK
	HRRM	T2,JBTQ##(T1)	;FORW. LINK PAST JOB
	HRLM	T1,JBTQ##(T2)	;BACK LINK PAST JOB
	SKIPL	(U)		;TRYING TO REQUEUE TO BEGINNING OF QUEUE?
	STOPCD	(.,STOP,RBQ)	;++REQUEUEING TO BEGINNING OF QUEUE
	HLR	R,JBTQ##(R)	;END--THIS WILL LEAVE R=IDX OF
				; CURRENT LAST LINK;T1=IDX OF Q-HEADER
	MOVE	T1,JBTQ##(R)	;T1=IDX OF CURRENT 1ST LINK
				; R=IDX OF Q-HEADER
	HRRM	J,JBTQ##(R)	;INSERT JOB IN DEST-Q
	HRLM	J,JBTQ##(T1)
	HRRM	T1,JBTQ##(J)
	HRLM	R,JBTQ##(J)
	JUMPL	R,QX3
IFE FTPDBS,<	;IF WE DO NOT SWAP PDB'S
	HLRZ	U,R		;GET QUANTUM TIME ADDRESS FOR DPB
	MOVE	U,(U)		;GET QUANTUM TIME
	SKIPN	W,JBTPDB##(J)	;GET PDB ADR
	STOPCD	.,STOP,NPC,	;++NO PDB IN CORE
	.DPB	U,PDYQNT##	;STORE QUANTUM RUN TIME
> ;END CONDITIONAL ON FTPDBS
IFN FTPDBS,<	;IF WE SWAP PDB'S
	HLRZ	T1,R		;SET UP QUANTUM RUN TIME ADDRESS
	MOVE	T1,(T1)		;GET QUANTUM TIME
	PUSHJ	P,SETQNT##	;STORE IN PDB
> ;END CONDITIONAL ON FTPDBS
IFN FTNSCHED,<
QX3:	JUMPE	P3,CPOPJ##	;DON'T MAINTAIN SUBQUEUES IN NON-CLASS SCHEDULER
	LDB	T1,PJBST2##	;GET DESTINATION QUEUE NUMBER
	CAIE	T1,PQ2		;DID WE JUST PUT HIM IN PQ2?
	POPJ	P,		;NO, JUST RETURN

;HERE IF WE JUST PUT A JOB INTO PQ2. MUST ALSO PUT IT INTO
; A PARALLEL SUBQUEUE.

	LDB	T1,JBYCLS##	;YES, GET HIS CLASS NUMBER
	MOVNI	T1,1(T1)	;GET NEGATIVE INDEX TO JBTSQ
	HLRZ	T2,JBTSQ##(T1)	;GET OLD LAST MEMBER OF QUEUE
	HRRM	J,JBTSQ##(T2)	;MAKE HIM POINT TO US AS LAST MEMBER
	HRLM	J,JBTSQ##(T1)	;MAKE BACK POINTER IN HEADER POINT TO US AS LAST MEMBER
	HRL	T1,T2		;T1 = OLD LAST MEMBER,,-SQ
	MOVEM	T1,JBTSQ##(J)	;SAVE AS OUR JBTSQ ENTRY
	POPJ	P,		;AND RETURN
>;END IFN FTNSCHED
IFE FTNSCHED,<
QX3:	POPJ	P,		;RETURN
>;END IFE FTNSCHED
;SCANS THE QS RETURNING THE NUMBERS OF THE JOBS IN THE QS.
;THE ORDER AND MANNER IN WHICH THE QS ARE SEARCHED IS
;DETERMINED BY A "SCAN TABLE" ADDRESSED IN THE CALLING SEQ.
;THE SCAN TABLE HAS THE FORM:
;
;SCANTAB:	XWD <Q1>,<CODE1>	;SCN Q1 ACCRDING TO CODE1
;		...
;		XWD <QN>,<CODEN>	;QN ACCORDING TO CODEN
;		Z		;ZERO TERMINATES TABLE
;
;EACH Q MAY BE SCANNED IN ONE OF FOUR WAYS SPECIFIEDBY <CODE>
;THE CODES ARE:
;
;QFOR	SCAN WHOLE Q FOWARD
;QFOR1	SCAN FOR ONY THE 1ST MEMBER (IF ANY)
;QBAK	SCAN WHOLE Q BACKWARD
;QBAK1	SCAN BACKWARD FOR ALL MEMBERS EXCEPT THE 1ST
;SQFOR	SCAN SUBQUEUES FORWARD ACCORDING TO SQSCAN TABLE IF RRFLAG .NE. 0,
;	ELSE SCAN PQ2 VIA QFOR ROUTINE.
;
;CALLING SEQ.
;
;	MOVEI U,SCAN TABLE ADDRESS
;	JSP T1,QSCAN	;SET UP PC FOR REPEATED RETURNS
;	...		;RETURN HERE WHEN NO MORE JOBS
;	...		;RETURN HERE WITH NEXT JOB IN AC J
;			; AND ITS Q IN LH(T2)
;
;	PERFORM ANY NECESSARY TESTING OF THIS JOB
;	J,U,T1,T2 MUST BE PRESERVED
;
;	JRST (T2)	;RETURN TO QSCAN TO GET NEXT JOB
;			; IF THIS ONE NOT ACCEPTABLE
;
QSCAN::	SKIPN	T2,(U)		;END OF SCAN TABLE?
	JRST	(T1)		;YES--RETURN TO CALL+1
	HLRE	J,T2		;NO--GET NO. OF Q
	JRST	(T2)		;DISPATCH

QFOR1::	MOVEI	T2,QFOR2	;ONLY THE FIRST JOB

QFOR::	HRRE	J,JBTQ##(J)	;SCAN FOWARD ALL JOBS
IFN FTNSCHED,<
	JUMPE	P3,QFOR0	;IF RUNNING NON-CLASS SYSTEM SCHEDULER, JUMP
	JUMPL	J,QFOR2		;JUMP IF END OF THIS QUEUE
	SKIPL	JBTSCD##(J)	;JOB IN A FIXED CLASS?
	JRST	1(T1)		;NO, WE CAN RETURN IT
	HLRZ	T3,(U)		;GET MINUS QUEUE NUMBER WE'RE SCANNING
	CAIE	T3,-PQ2		;PQ2?
	JRST	1(T1)		;NO, JUST RETURN THE JOB
	JRST	(T2)		;YES, ONLY RUN HIM IF SQFOR WANTS TO.
>;END IFN FTNSCHED

QFOR0:	JUMPG	J,1(T1)		;RETURN THIS JOB NUMBER CALL+2 UNLESS--
QFOR2:	AOJA	U,QSCAN		;END OF THIS Q--GET NEXT Q

QBAK1::	HLRE	J,JBTQ##(J)	;SCAN BACKWARD ALL JOBS EXCEPT 1ST
	SKIPLE	JBTQ##(J)		;IS THIS THE FIRST MEMBER?
	JRST	1(T1)		;NO--RETURN CALL+2
	AOJA	U,QSCAN		;YES--GET NEXT Q

QBAK::	HLRE	J,JBTQ##(J)	;SCAN BACKWARD ALL JOBS
	JUMPG	J,1(T1)		;RETURN CALL+2 WITH JOB NO. UNLESS
	AOJA	U,QSCAN		;BEG OF THIS Q--GET NEXT Q


IFN FTNSCHED,<
SQFOR::	JUMPE	P3,QFOR2	;NO CLASSES, SO GO AWAY IMMEDIATELY
	SKIPG	RRFLAG##	;COUNT OF CLASSES WITH NON ZERO QUOTA .LE. ZERO?
	JRST	SQFR1A		;YES, JUST SCAN PQ2 FORWARD
	MOVEI	M,SQSCAN##	;SOME CLASSES HAVE QUOTAS LEFT, SCAN THEM
	MOVEI	T2,SQFORA	;RETURN ADDRESS FOR MORE JOBS, IF ANY
SQFOR1:	SKIPN	T3,(M)		;ANY ENTRIES LEFT IN SUBQUEUE LIST?
SQFR1A:	AOJA	U,QSCAN		;NO, STEP TO NEXT MAJOR QUEUE
SQFOR2:	SKIPG	(T3)		;YES, ANY QUOTA LEFT?
				;(RH OF SQSCAN ENTRY IS ADDR OF QUOTA LEFT WORD)
	AOJA	M,SQFOR1	;NO,GET NEXT SUBQUEUE
	HLRE	J,T3		;YES, GET -SQ NUMBER IN J

SQFORA:	HRRE	J,JBTSQ##(J)	;GET NEXT JOB IN QUEUE
	JUMPG	J,1(T1)		;TO TO CALL+1 IF HAVE A JOB
	AOJA	M,SQFOR1	;ELSE STEP TO NEXT SUBQUEUE
>;END IFN FTNSCHED
DEFINE X(A,B,C)
<
	A'Q==:ZZ
	ZZ==ZZ+1>

	ZZ==0
	QUEUES
	XP	MINQ,ZZ
DEFINE X(A,B,C)
<	A'Q==:ZZ
	EXTERNAL	A'AVAL
	ZZ==ZZ+1>
	RWAITS

	NQUEUE==ZZ
	XP	MAXQ,NQUEUE-1
	XP	AVLNUM,MAXQ-MINQ


DEFINE X(A,B,C)
<	A'Q==:ZZ
	ZZ==ZZ+1>

	CODES

	XP	MXCODE,ZZ-1


	PQ1==:ZZ
	ZZ==ZZ+1
	PQ2==:ZZ
	ZZ==ZZ+1
	CMQ==:ZZ
;CORRESPONDENCE TABLE BETWEEN JOB STATUS CODES AND QUEUE TRANSFER TABLES
;USED BY SCHEDULER
;RUNCSS SETS JOB STATUS WORD TO NEW STATE CODE.
;SCHEDULER SETS UP QUEUE TRANSFER TABLE ADDRESS FROM
;FOLLOWING TABLE USING NEW STATE CODE AS INDEX

DEFINE X(A,B,C)
<	XWD Q'A'T, Q'A'W
>
QWSW==-1
QIOWW=-1
QDIOWW==-1
QDSW==-1
QPIOWW==-1
QPSW==-1
QNAPW==-1


QBITS::	QUEUES
	RWAITS
	CODES
;SHARABLE DEVICE REQUEST TABLE(GENERALIZED FOR OTHER QUEUES TOO)
;CONTAINS THE NUMBER OF JOB WAITING TO USE SHARBLE DEVICE
;WSREQ AND RNREQ ARE UNUSED

	$LOW
DEFINE X(A,B,C)
<A'REQ::	0
>


REQTAB::RWAITS	;GENERATE REQ TABLE
XP RQTBMQ,REQTAB-MINQ
	$HIGH




	$LOW
QJOB::	0	;NUMBER OF JOBS NEEDING QUEUE TRANSFERS AT
		;OTHER THAN CLOCK LEVEL
XJOB::	0	;NUMBER OF JOBS NEEDING EXPANSION BY SWAPOUT-IN
UNWIND:	0	;FLAG THAT SAYS WE'VE UNWOUND ONCE THIS SCHEDULER CYCLE
	$HIGH
DEFINE TTAB(FCTN,QUEUE,QUANT)
<		EXP FCTN
		XWD QUANT,-QUEUE
>
DEFINE PTTAB(FCTN,QUEUE,QUANT)
<		EXP FCTN
		XWD QUANT,QUEUE
>

QNULW:	TTAB	EQFIX,NULQ,-1	;NULL QUEUE JOB NO. NOT ASSIGNED
QSTOP::QSTOPW:	TTAB EQFIX,STOPQ,-1	;UNRUNABLE JOBS TO END OF STOPQ
IFN FTDAEM,<
QJDCW:	TTAB	EQFIX,JDCQ,-1
>	; END OF CONDITIONAL ASSEMBLY ON FTDAEM
QCMW::	TTAB	EQFIX,CMQ,-1	;COMMAND WAIT TILL JOB IN CORE
QTSW:					;TTY IO WAIT SATISFIED(ENTER BACK OF PQ1)
QRNW:	TTAB	EQFIX,PQ1,QADTAB##	;JUST RUNABLE JOBS
	;WHICH ARE NOT IN SOME WAIT STATE BELOW

QRNW1:	TTAB	EQFIX,PQ1,-1	;PUT IN BACK OF PQ1. NO QUANTUM FOR SPECIAL TRANSFER
QRNW2:	TTAB	EQFIX,PQ2,-1		;PUT IN BACK OF PQ2, NO QUANTUM CHANGE

QTIOWW:	TTAB	EQFIX,TIOWQ,-1	;TTY IOW HELD IN TIOWQ
QSLPW:	TTAB	EQFIX,SLPQ,-1	;SLEEP UUO
QEWW:	TTAB	EQFIX,EWQ,-1	;EVENT WAIT
IFN FTNSCHED,<
QTIME1::TTAB	EQFIX,PQ2,RNQUNT##	;WHEN QUANT. TIME EXCEEDED.
>
QTIME0::PTTAB	EQLNKZ,QRQTBL##,0	;WHEN QUANT. TIME EXCEEDED.
	;WHEN QUANT. TIME EXCEEDED AND RESET QUANT. TIME
SUBTTL	SWAP R. KRASIN

;SWAPPER CALLED EVERY CLOCK TIC.
;SINCE MOST OPERATIONS STARTED BY THE SWAPPER REQUIRE SEVERAL
;TICS TO RUN TO COMPLETION, SEVERAL FLAGS(FINISH,FIT,FORCE
;ARE USED TO "REMEMBER" PREVIOUS STATES.
;THE BASIC ALGORITHM:
;IS CORE SHUFFLER WAITING FOR IO TO FINISH FOR SOME JOB?
;  YES--TRY AGAIN TO SHUFFLE(WHEN IO STOPS)
;IS CORE SHUFFLER STILL WAITING FOR IO TO FINISH?
;  YES--RETURN AND DO NOTHING
;IS SWAPPER STILL BUSY?
;  YES--RETURN AND DO NOTHING
;SCAN QS FOR 1ST JOB OUT OF CORE.
; IF NONE--RETURN
;A:
; IF ONE--WILL LOW(HIGH) SEG FIT IN LARGEST HOLE IN CORE?
;  YES--START INPUT AND RETURN
;  NO--IS TOTAL FREE CORE(CORTAL) ENOUGH TO ACCOMMODATE LOW(HIGH) SEG?
;    YES--CALL CORE SHUFFLER
;      IS SHUFFLER WAITING FOR IO TO STOP?
;        YES--RETURN AND DO NOTHING
;        NO--GO TO A:
;   NO--"REMEMBER" THIS JOB FOR INPUT AND LOOK FOR OUTPUT:
;ANY JOBS WAITING TO XPAND CORE BY SWAP OUT/IN?
; YES--OUTPUT ONE AND RETURN
; NO--SCAN QS BACKWARD FOR JOB IN CORE WHOSE PROTECT TIME
;		(SET ON INPUT) HAS GONE TO 0.
;  IF NONE--RETURN
;  IF ONE--IS IT SWAPPABLE(NO ACTIVE IO AND NOT CURRENT JOB)?
;   YES--OUTPUT HIGH SEG(IF ANY AND NOT ON DISK) THEN LOW SEGMENT
;   NO--SET SWP BIT(SO SCHEDULER WILL NOT RUN), IO WILL CONTINUE
;	IN LOW SEGMENT AS LONG AS IT CAN
;	IO ROUTINES NO LONGER STOP IF SWP SET, JUST SHF)
;ALL DEVICE DEPENDENT CODE MARKED WITH A "*"

SWAP::
IFN FTVM,<
	PUSHJ	P,SAVE3##
>
IFE FTVM,<
IFN FTSHFL,<			;SHUFFLER PRESENT?
	CPUNLK (SCD)		;UNLOCK CALL TO SHUFFLER
	SKIPE	SHFWAT##	;IS CORE SHUFFLER WAITING FOR IO TO STOP
				; FOR SOME JOB?
	PUSHJ	P,CHKSHF##	;YES, CALL CORE SHUFFLER TO SEE IF
				; IO STOPPED YET
	CPLOCK (SCD)		;LOCK CP AGAIN
	SKIPN	SHFWAT##	;IS SHUFFLER STILL WAITING?
>	; END OF CONDITIONAL ASSEMBLY ON FTSHFL
	SKIPE	SQREQ##		;*NO--IS SWAP SERV. ROUT. STILL BUSY WITH LAST JOB?
	POPJ	P,		;*YES--RETURN
>
IFN FTPDBS,<	;IF WE SWAP PDB'S
	SKIPL	SCREQ		;CAN WE GET THE SWAPPER IF WE DECIDE
				; THAT WE WANT IT.
	SKIPN	SCUSER##	; ..
	JRST	SWAP0		;YES--TRY TO SWAP
	POPJ	P,		;NO--RETURN NOW.
SWAP0:> ;END CONDITIONAL ON FTPDBS
IFN FTHPQ,<
	SKIPE	FIT		;IS FIT SET?
	SKIPG	J,.CPRTF##(P4)	;AND HPQ JOB ON DISK?
	JRST	SWAP0A		;NO. CONTINUE
	LDB	T4,HPQPNT##	;GET ITS HPQ NUMBER
	MOVE	J,FIT		;GET NUMBER FROM FIT
IFN FT2REL,<
	PUSHJ	P,FITHPQ	;GET LOW SEG NUMBER OF JOB IN FIT
>
	LDB	T2,HPQPNT	;GET HPQ NUMBER OF JOB IN FIT
	CAIL	T2,(T4)		;IS IT LESS THAN JOB IN .CPRTF?
	JRST	SWAP0A		;NO. PROCEED NORMALLY
IFN FT2REL,<
	SKIPLE	T1,JBTSGN##(J)	;REAL HIGH SEG?
	SKIPE	JBTADR(T1)	;YES. IN CORE, IF NOT, COULD BE IN FIT
>
	PUSHJ	P,ZERFIT	;NO. CAN CLEAR FIT AND RESELECT
SWAP0A:>	; END OF CONDITIONAL ASSEMBLY ON FTHPQ
IFE FTVM,<
	MOVEI	F,SWPDDB##	;POINT TO SWAP DDB
	HRRZ	S,DEVIOS(F)	;ERROR FLAGS
;BACK HERE AFTER SWAP OUT OR IN ERROR (ERR BITS (S) CLEARED SO DO NORMAL
; POST PROCESSING)
SWAP1:	SKIPN	J,FINISH##	;ANY IN/OUTPUT TO FINISH?
	JRST	SWP2		;NO-
IFE FTPDBS,<	;IF WE DO NOT SWAP PDB'S
	JUMPL	J,FINOUT	;YES--INPUT OR OUTPUT?
> ;END CONDITIONAL ON FTPDBS
IFN FTPDBS,<	;IF WE SWAP PDB'S
	SKIPN	SWAPIN##	;IS THIS A SWAP IN?
	JRST	FINOUT		;NO--MUST BE SWAP OUT
> ;END CONDITIONAL ON FTPDBS
>	;END CONDITIONAL ON FTVM
IFN FTVM,<
SWAP1:
IFN FTIPCF,<
	PUSHJ	P,GVIPCP##	;RETURN ANY IPCF PAGES WHICH
				; WERE SWAPPED OUT TO THE FREE CORE LIST
>
	SKIPN	SWPCNT##	;ANY SWAP REQUESTS COMPLETED?
	JRST	SWP2		;NO, PROCEED
	PUSHJ	P,FNDSLE##	;FIND A COMPLETED SWPLST ENTRY
	  STOPCD	CPOPJ,DEBUG,SMU,	;++SWPCNT MESSED UP
FININN:	PUSHJ	P,GETIOS##	;GET ERROR PLUS DIRECTION OF I/O BITS
	TLNE	S,IO		;SWAP OUT?
	JRST	FINOUT		;YES, FINISH UP OUTPUT
>	;END CONDITIONAL ON FTVM
	JUMPN	S,INERR		;JUMP IF SWAP READ ERROR
FININ0:		;HERE IF NOTHING TO SWAP IN(HIGH OR LOW SEG EXPANDING FROM 0)
IFN FTPDBS,<	;IF WE SWAP PDB'S
	JUMPL	J,PDBIN		;JUMP IF PDB
> ;END CONDITIONAL ON FTPDBS
IFN FT2REL,<
	CAILE	J,JOBMAX##	;WAS SEG JUST SWAPPED IN, A LOW SEG?
IFE FTDHIA&FT2SWP,<
	JRST	FININ1		;NO, GO FINISH HIGH SEG SWAP IN
>
IFN FTDHIA&FT2SWP,<
	JRST	FININH
>
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
IFN FTVM,<
	PUSHJ	P,GIVBAK	;RETURN DISK SPACE, 4-WORD BLOCKS
FININ5:
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
IFN FTKA10,<
	MOVE	R,JBTDAT##(J)	;SETUP LOW SEG PROTECTION,RELOCATION
	MOVE	F,JOBPC##(R)	;JOB STOPPED IN EXEC MODE?
	TLNE	F,USRMOD	;TEST PD FLAG
	JRST	FININ1		;NO
	HRRZ	F,JOBDPG##(R)	;YES, ADJUST R AND P IN DUMP AC AREA
	SUBI	F,(R)		;OLD RELOC-NEW RELOC
	MOVNS	F		;NEW RELOC-OLD RELOC
	HRRZ	T2,JOBDPD##(R)	;OLD PD LIST POINTER
	CAMLE	T2,SYSSIZ##	;IS IT IN THE MONITOR(EXTENDED PD LIST,NULL PD LIST)
	ADDM	F,JOBDPD##(R)	;NO, ADJUST DUMP PUSH DOWN POINTER
	MOVEM	R,JOBDPG##(R)	;STORE NEW AC R
>	; END OF IFE FTKI10
IFN FTDHIA&FT2SWP,<
	JRST	FININ1		;CONTINUE
FININH:	MOVE	T1,SWPIN	;LOW-SEG NUMBER
	CAMN	T1,MIGRAT##	;SWAP IN CAUSE MIGRATING FROM BAD UNIT?
	PUSHJ	P,ZERSWP	;YES, GIVE UP HI-SEG SWAPPING SPACE
>
FININ1:
IFN FT2REL,<
	CPUNLK (SCD)		;UNLOCK CALL TO SHUFFLER
	PUSHJ	P,FININ##	;IS THERE A HIGH SEG WHICH MUST BE SWAPPED IN?
IFN FTVM,<
	  JRST	[CPLOCK	(SCD)	;SWAPPING I/O IN PROGRESS FOR HI SEG
	 	 PUSHJ	P,NXTSLE##
		   POPJ	P,
		 JRST FININN]
>
	  JRST	FININ2		;YES, GO SWAP IT IN(J SET TO HIGH SEG NO,JOB # IN INPJOB)
	CPLOCK (SCD)		; NO, EITHER HIGH SEG ALREADY IN FOR ANOTHER USER
				; OR THERE IS NONE, J STILL JOB NO. (IE LOW SEG)
	JRST	FININ3		;

FININ2:	CPLOCK (SCD)		;LOCK SCHEDULER AGAIN
	JRST	FIT1		;GO SWAP IN HIGH SEG
FININ3:
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL



IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
;HERE WHEN PDB IS IN CORE

PDBIN:	HRRE	J,J		;CLEAR BITS IN LH(J)
	PUSHJ	P,SEGSIZ##	;T2 = SIZE OF PDB IN PAGES
	PUSHJ	P,ZERSWP	;GIVE UP DISK SPACE
				; ALSO FIX VIRTAL
	MOVM	J,J		;MAKE J POSITIVE
	MOVEI	T2,JS.RQR	;IF THE QUANTUM RUN TIME WAS RESET
	MOVE	T1,RNQUNT##	; WHILE PDB WAS ON THE DISK WE MUST
	TDNE	T2,JBTSTS##(J)	; DO THE ACTUAL DPB NOW.
	PUSHJ	P,SETQNT##	;GO STORE IN PDB
	ANDCAM	T2,JBTSTS##(J)	;AND CLEAR THE FLAG BIT
	LDB	T2,IMGIN##	;GET SIZE OF LOWSEG
	JUMPE	T2,SWP1		;IF ZERO GO SCAN SWAP IN QUEUE.
	MOVEM	J,FIT##		;ELSE GO SWAP IN LOWSEG
	CAMG	T2,BIGHOL##	;IS THERE STILL ROOM IN CORE?
	JRST	SWAPI		;YES--GO SWAP IN LOW SEGMENT
	JRST	FIT1A		;NO--SWAP SOMEONE OUT. THIS HAPPENS
				; ONLY IF SOME JOB DID A CORE UUO
				; WHILE THE SWAPPER WAS BUSY AND GOT
				; THE SPACE IN CORE.
> ;END FTPDBS
IFN FTKI10!FTKL10,<
	PUSHJ	P,MAPUSR##	;SETUP THE MAP INCLUDING THE TRAP LOCATIONS
				; FOR THE JOB JUST SWAPPED IN
IFN FTVM,<
	PUSHJ	P,SXOPFH##	;MAKE PFH CONCEALED IF IT SHOULD BE
>
>	; END OF CONDITIONAL ASSEMBLY ON FTKI10

	LDB	F,IMGIN##	;NEW CORE SIZE
	LDB	T2,IMGOUT##	;OLD SIZE WHEN ON DISK
	SUB	T2,F		;OLD-NEW=DECREASE
				; HAS USER DECREASED VIRTUAL MEMORY FROM M TO N(N GR 0)
				; WHILE OUT ON DISK(R,RUN,GET,KJOB) TO 140 WORDS?
				; CORE COMMAND ALWAYS FORCES SWAP IN BEFORE
				; CORE REASSIGNMENT SO NOT IN THIS CATEGORY
				; FRAGMENTED USER TOO HARD TO PARTIALLY
				; RECLAIM DISK SPACE
				; ON REDUCTION WHICH DOES NOT GO TO 0
	SKIPLE	T2		;DECREASED?
	ADDM	T2,VIRTAL##	;YES, NOW INCREASE VIRTUAL MEMORY AVAILABLE BY
				; AMOUNT OF DECREASE IN HIGH OR LOW SEG
IFE FTVM,<
	PUSHJ	P,ZERSWP	;RETURN LOW SEG DISK SPACE, SET IMGOUT,IMGIN
				; AND SWP!SHF(JBTSTS) TO 0
>;	; END OF CONDITIONAL ON FTVM
IFN FTVM,<
	PUSHJ	P,UNSWAP	;MARK JOB IN CORE AGAIN
>
	PUSHJ	P,SEGSIZ##	;COMPUTE AND SET IN CORE PROTECT TIME FROM
	MOVEI	F,-1(T2)	; SIZE OF JOB(1K BLOCKS-1)
	IMUL	F,PROT##	;ADD VARIABLE AMOUNT DEPENDING ON CORE SIZE
	ADD	F,PROT0##	;ADD FIXED AMOUNT INDEPENDENT OF CORE SIZE
	ADDI	F,^D8333	;CONVERT TO TICKS FROM US
	IDIVI	F,^D16667*2	;AND ACCOUNT FOR THE FACT THAT WE DECREMENT EVERY OTHER TICK
	PUSHJ	P,FNPDBS##	;FIND THE PDB OR STOP
	.DPB	F,PDYIPT##	;SET IN-CORE PROTECT TIME.
	MOVSI	F,PDMSWP
IFN FTDHIA&FT2SWP,<
	CAME	J,MIGRAT##	;IF JUST SWAPPING IN TO GET OFF A UNIT GOING
				; DOWN DONT CLEAR SWAPPABLE BIT
>
	ANDCAM	F,.PDIPT##(W)	;CLEAR SWAPPABLE BIT
	MOVE	F,[JS.HNG,,JS.SCN!JS.TFO] ;CLEAR SCANNED, FORCED BY TIMER, AND HUNG
	ANDCAM	F,JBTST2##(J)	;IN SECOND STATUS TABLE
	SETZM	INFLG		;CLEAR FRUSTRATION FLAGS
	SETZM	INFLGJ
	SETZM	INFLGC
IFN FTHPQ,<
	CAMN	J,FITJBZ	;WAS THIS GUY IN THE TIMER?
	SETZM	FITJBZ		;YES. REMOVE HIM
>
	JRST	SWP1
;HERE ON SWAP INPUT ERROR IN LOW OR HIGH SEG
INERR:	MOVE	R,JBTADR##(J)	;SETUP RELOC,PROTECTION FOR HIGH OR LOW SEG
IFN FTSWPERR,<			;SWAP READ ERROR RECOVERY CODE
IFN FT2REL,<
	CAILE	J,JOBMAX##	;IS THIS A HIGH SEGMENT JUST SWAPPED IN?
	JRST	INERR2		;YES
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	PUSHJ	P,SWPREC	;RECORD ERRORS AND DECREASE AMOUNT OF
				;VIRTUAL CORE LEFT BY SIZE OF DISK SPACE LOST (IMGOUT)
	MOVSI	T1,JACCT	;CLEAR JACCT SO THAT A START COMMAND
	ANDCAM	T1,JBTSTS##(J)	; WILL NOT START A DAMAGED PROGRAM
				; WITH PRIVILEDGES AND SO DAEMON WON'T
				; GET RESTARTED
IFE FTVM,<
	MOVEI	T1,0		;NO, PRETEND DISK SPACE WITH ERROR IN IT
	DPB	T1,IMGOUT##	; IS NO LONGER ON DISK (ZERSWP WILL NOT
				; FREE IT UP)
>
	PUSHJ	P,ZAPUSR##	;CLEAR ALL DDB'S, IO CHANS
	PUSHJ	P,CLRJOB##	;CLEAR PROTECTED PART OF JOB DATA AREA
INERR2:
IFN FTVM,<
	PUSH	P,J		;SAVE SEGMENT NUMBER
>

IFN FT2REL, <
	PUSHJ	P,SEGERR##	;GO CHECK IF HIGH SEG WHICH HAD ERROR
				; IF YES, CLEAR HIGH SEG NAME SO NO NEW
				; USERS WILL USE. ALWAYS RETURN JOB NO.
				;RECORD ERROR AND DECREASE VIRTUAL CORE LEFT (SWPREC) IF THIS IS
				; FIRST READ ERROR ONLY.

>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	PUSHJ	P,ERRSWP##	;PRINT "SWAP READ ERROR"
IFN FTVM,<
	POP	P,J		;RESTORE SEGMENT NUMBER
	LDB	T1,[POINT 9,SWPLST##(P1),26] ;FIRST PAGE IN
	CAILE	J,JOBMAX##	;A HIGH SEGMENT?
	JRST	FININ0		;NO
	HLL	T1,JBTUPM##(J)	;PICK UP LH FOR COMPARE
	CAME	T1,JBTUPM##(J)	;UPMP?
	JRST	FININ0		;NO, WE'RE NOT TOO BAD OFF
	PUSHJ	P,GVPAGS##	;YES, WE'RE IN BAD TROUBLE
	HLRZ	T1,JBTSWP##(J)	;GIVE BACK ALL CORE FOR THE JOB
	PUSHJ	P,GVPAGS
	PUSHJ	P,DLTSLE##	;CLEAR THE SWPLST ENTRY
	SETZM	JBTADR##(J)	;THE JOB HAS NO CORE IN CORE
	SETZM	JBTUPM##(J)
	SETZM	JBTSWP##(J)	;NO CORE ON DSK EITHER
IFN FT2REL,<
	SKIPLE	T1,JBTSGN##(J)	;SKIP IF SPY OR NO HI SEG
	TLNE	T1,SHRSEG	;SHARABLE?
	CAIA			;YES, LET SEGCON REMOVE IT
	SETZM	JBTSGN##(J)	;NO, JUST ZAP IT
	PUSHJ	P,KILHGH##	;ALSO REMOVE HI SEG FROM ADR SPACE
>
	PJRST	UNSWAP		;CLEAR SWP AND RETURN
>	;END FTVM

IFE FTVM,<
	MOVEI	S,0		;CLEAR ERROR FLAGS SO CAN
				; REENTER SWAPPER
	JRST	SWAP1		;GO BACK AND START OVER AFTER HAVING
>	;END FTVM
>	; END OF CONDITIONAL ASSEMBLY ON FTSWPERR
				; CLEARED S SO LOOK LIKE NO ERROR
IFE FTSWPERR,<
	SETZM	FINISH##	;CLEAR FINISH FLAG SO SWAPPING CAN CONTINUE
IFN FTPDBS,< ;IF THE SC RESOURCE EXISTS
	SKIPL	SCREQ		; AND IF WE OWN IT
	PUSHJ	P,SCFREE##	;RETURN IT.
> ;END FTPDBS
	PUSHJ	P,KCORE1##	;RETURN CORE
	PJRST	ERRSWP##	;TYPE SWAP READ ERROR MESSAGE AND STOP JOB
>	; END OF CONDITIONAL ASSEMBLY ON FTSWPERR
FINOUT:	
IFE FTVM,<
IFE FTPDBS,< ;ONLY NEEDED IF WE DO NOT SWAP PDB'S
	MOVNS	J		;ON OUTPUT FINISH IS NEGATIVE THIS
				; CONVERTS IT BACK TO POSITIVE.
> ;END FTPDBS
	JUMPN	S,OUTERR	;JUMP IF SWAP OUT ERROR
>	; END OF CONDITIONAL ASSEMBLY OF FTVM
IFN FTVM,<
	TRNE	S,-1		;ANY ERRORS?
	JRST	OUTERR		;YES, PROCESS SWAP OUT ERRORS
	PUSHJ	P,DLTSLE##	;DELETE THE SWPLST ENTRY
>	; END OF CONDITIONAL ASSEMBLY ON FTVM

IFN FTDHIA&FT2SWP,<
	CAILE	J,JOBMAX##	;HI-SEG?
	JRST	FINOU2		;YES, WE'LL GET IT LATER
;****************
;WHAT ABOUT HI SEGS, WILL DODELE WORK FOR ALL SHARABLE HI SEGS,
;WHAT ABOUT NON-VM NON-SHARABLE HI SEGS?
;**********************
IFE FTVM,<
	MOVEI	T1,JS.MIG	;LIGHT A BIT INDICATING THIS JOB
	SKIPE	MIGRAT##	; HAS BEEN MIGRATED TO ANOTHER UNIT
	IORM	T1,JBTST2##(J)	; IF WE ARE TURNING OFF A SWAPPING UNIT
>	;END IFE FTVM
IFN FTVM,<
	SKIPN	MIGRAT##
	JRST	FINOU2
	PUSHJ	P,PGOFF##	;INSURE ALL PAGES OF JOB ARENT ON BAD UNIT(S)
	  TDZA	T1,T1		;NOT COMPLETELY MIGRATED YET
	MOVEI	T1,JS.MIG	;COMPLETELY OFF THE BAD UNIT
	IORM	T1,JBTST2##(J)	;LIGHT BIT IF ALL OFF
>	;END IFN FTVM
>	;END FTDHIA&FT2SWP
FINOU2:	MOVE	R,JBTADR##(J)	;XWD PROTECT,,RELOC. FOR LOW SEG
	CPUNLK (SCD)		;UNLOCK CALLS TO SHUFFLER
	PUSHJ	P,KCORE1##	;RETURN CORE FOR LOW OR HIGH SEG JUST SWAPPED OUT
				; EVEN IF
				; ANOTHER JOB STARTED TO SHARE HIGH SEG DURING
				; SWAP OUT (GET) SINCE JOB IS MARKED WITH
				; SWP BIT ON AND CANNOT RUN UNTIL HIGH SEG
				; IS SWAPPED BACK IN
	CPLOCK (SCD)		;LOCK SCHEDULER AGAIN

FINOU0:
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	CAILE	J,JOBMAX##	;IS THIS A HISEG?
	JRST	FINOU1		;YES--SEE ABT LOW SEG
	JUMPL	J,SWP1		;IF THIS WAS THE PDB WE ARE DONE
	MOVN	J,J		;CONVERT TO PDB
	MOVEM	J,FORCE##	;SAVE SEG #
	JRST	SWAPO		;GO SWAP OUT
FINOU1:> ;END FTPDBS
IFN FT2REL,<
	PUSHJ	P,FINOT##	;IS THIS A HIGH SEG WHICH WAS JUST SWAPPED OUT?
	  JRST	FORCEL		;YES, J SET TO LOW SEG NO, GO TRY SWAP IT OUT
				; NO, THIS WAS A LOW SEG, ALL SWAPPING FOR THIS USER
				; IS FINISHED.
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
SWP1:	SETZM	FINISH##	;CLEAR FINISH FLAG

IFN FTPDBS,< ;IF THE SC RESOURCE EXISTS
	SKIPL	SCREQ		; AND IF WE OWN IT
	PUSHJ	P,SCFREE##	;GIVE IT UP
> ;END FTPDBS

SWP2:	SKIPE	J,FORCE##	;WAITING FOR JOB TO BECOME SWAPPABLE?
	JRST	FORCE1		;YES, TRY TO SWAP OUT
FIT0:
IFN FTVM,<
	SKIPE	SPRCNT##	;ARE THERE ALREADY SWAPS IN PROGRESS?
	JRST	CHKXPN		;YES, LOOK ONLY FOR EXPANDING JOBS
	SKIPE	SWPCNT##	;ANY SWAPPING I/O DONE (PROBABLY ONLY IF
				; ONE PASS HAS ALREADY BEEN MADE THROUGH THE
				; MAJOR LOOP OF THE SWAPPER)
	JRST	SWAP1		;YES, GO PROCESS THAT FIRST
>
	SKIPE	J,FIT##		;NO-- WAITING TO FIT JOB IN CORE?
	JRST	FIT1		;YES, TRY TO SWAP IN
IFN FTLOCK,<
	SKIPE	J,LOCK##	;WAITING TO LOCK A JOB IN CORE?
	JRST	CPOPJ1##	;YES, TRY TO POSITION JOB FOR LOCKING
>	; END OF CONDITIONAL ASSEMBLY ON FTLOCK
;SCAN FOR INPUT
	MOVEI	U,ISCAN##
	MOVE	T1,SWPIFC	;NUMBER OF UNFAIR INPUT SCANS
	CAMGE	T1,MAXIFC	;REACH MAXIMUM?
	JRST	FITPRM		;NO
	SETZM	SWPIFC		;YES
	MOVEI	U,ISCAN1##	;USE SECONDARY
FITPRM:	JSP	T1,QSCAN
	  JRST	ZCKXPN		;NO INPUT TO DO--CK FOR EXPANDING JOBS
	MOVE	F,JBTSTS##(J)	;JOB STATUS WORD
IFN FT2REL,<	TLNE	F,SWP		;ARE ALL OF THIS JOB'S SEGS IN CORE?
	PUSHJ	P,CKXPN##	;NO, IS HIGH SEG EXPANDING?
	  JRST (T2)		;YES, CONTINUE SCAN FOR SOME OTHER JOB
	MOVEM	J,FIT##		;NO, REMEMBER JOB (OR HI SEG) TRYING TO FIT IN
	CAIGE	U,FISCAN##	;REACH FAIR TERRITORY
	AOSA	SWPIFC		;NO. COUNT UP
	SETZM	SWPIFC		;YES. CLEAR COUNT
	JRST	FIT1A		; TRY TO FIT JOB INTO CORE
				; (BYPASS SECOND CALL TO CKXPN FOR SPEED)
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
IFE FT2REL,<
	TLNN	F,SWP		;ARE ALL OF THIS JOB'S SEGS IN CORE?
	JRST	(T2)		;YES, CONTINUE SCAN FOR SOME OTHER JOB
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL

;HERE TO TRY TO FIT A SWAPPED JOB (OR HI SEG) INTO CORE (AGAIN)
FIT1::
IFN FTRSP,<
	SETOM	SWPPLT##	;SET POTENTIALLY LOST TIME FLAG FOR SWAPPER
>
	MOVEM	J,FIT##		;REMEMBER JOB (OR HI SEG) TRYING TO FIT IN
IFN FT2REL,<
	PUSHJ	P,CKXPN##	;IS THIS A LOW SEG WHICH IS CONNECTED TO
				; AN EXPANDING HIGH SEG? (SHOULD BE RARE)
	  JRST NOFITZ		;YES. DESELECT IT AND GET OUT.
FIT1A:
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	LDB	P1,IMGIN##	;CORE SIZE NEEDED FOR THIS SEG(0 IF LOW SEG
				; OR HIGH SEG WITH UWP OFF ALREADY IN CORE
IFN FTKI10!FTKL10,<
	CAIG	J,JOBMAX##	;ON LOW SEGMENT SWAP-IN, MUST ALSO ALLOCATE
	ADDI	P1,UPMPSZ##	; A USER PAGE MAP PAGE SO ADD THAT TO
				; TOTAL CORE REQUIRED TO SWAP IN JOB OR LOW SEGMENT
>	; END OF CONDITIONAL ASSEMBLY ON FTKI10
	SKIPE	JBTADR##(J)	;IS LOW OR HIGH SEG ALREADY IN CORE?
	MOVEI	P1,0		;YES (RARE) CAN HAPPEN IF JOB IN CORE EXPANDS
				; DURING LOW SEG SWAP IN SO HIGH SEG COULD NOT
				; FIT AND COUND NOT FIND ENOUGH JOBS TO SWAP OUT
				;;(SO CLEARED FIT AT NOFIT).
IFE FT2REL,<
	CAMLE	P1,CORTAL##	;WILL LOW SEG FIT IN FREE+DORMANT CORE?
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
IFN FT2REL,<
	PUSHJ	P,FITSIZ##	;COMPUTE AMOUNT OF CORE NEEDED TO BRING IN
				; 1. THIS JOBS LOW SEG AND HIGH SEG
				; 2. THIS JOBS LOW SEG(HIGH ALREADY IN OR NONE)
				; 3. THIS HIGH SEG BECAUSE LOW SEG ALREADY IN
				;WILL LOW SEG FIT IN FREE+DORMANT+IDLE CORE?
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	  JRST	SCNOUT		;NO,WILL NOT FIT EVEN IF ALL DORMANT SEGS DELETED
				; P1=TOTAL CORE NEEDED(IN K)
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	CAIG	J,JOBMAX##	;SKIP IF HISEG -- NO PDB IN THAT CASE
	ADDI	P1,PDBPGS##	;P1=TOTAL CORE NEEDED IN PAGES INCLUDING
				; THE PDB.
> ;END FTPDBS
FIT1B:	CAMG	P1,BIGHOL##	;YES, WILL THIS SEG FIT IN BIGGEST HOLE OF FREE CORE
				; WITHOUT DELETEING ANY DORMANT OR IDLE SEGS?
				; (P1 RESTORED TO SIZE FOR JUST THIS LOW OR HIGH SEG)
				; BIGHOL CONTAINS THE NUMBER OF FREE PAGE ON
				; THE KI10 RATHER THAN THE LARGEST SET OF
				; CONTIGUOUS FREE PAGES
	JRST	SWAPI		;YES, GO SWAP IN THIS LOW OR HIGH SEG
IFN FT2REL,<
	PUSHJ	P,FRECR1##	;NO, GO DELETE ONE DORMANT OR IDLE SEG IN CORE
				; (THERE MUST BE AT LEAST ONE, OTHERWISE
				; CORTAL WOULD EQUAL BIGHOL).
				; SKIP RETURN (USUAL) EXCEPT IF AN IDLE SEGMENT
				; WAS FOUND WITH NO COPY ON DISK (UWP OFF).
	  JRST FORIDL		; GO SWAP OUT IDLE HIGH SEG WITH NO DSK COPY.
	  JRST FIT1B		; ONE DORMANT OR IDLE SEGMENT HAS BEEN DELETED, GO 
				; TRY TO SWAP IN NOW.
IFN FTSHFL,<			;SHUFFLER?
;TAG TO PATCH OUT SHUFFLER FOR EXPERIMENTS - PATCH TO JFCL
SHFPAT::  SKIPN	HOLEF##		;NO, ARE THERE ANY HOLES IN CORE WHICH THE SHUFFLER
				; COULD ELIMINATE(NOT COUNTING ONE AT TOP)?
>	; END OF CONDITIONAL ASSEMBLY ON FTSHFL
	JRST SCNOUT		;MEMORY IS FRAGMENTED AND THERE ARE NO 
				;DORMANT HIGH SEGMENTS OR HOLES.  SCAN FOR OUTPUT
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
IFN FTSHFL,<			;SHUFFLER?
	CPUNLK (SCD)		;UNLOCK ALL CALLS TO SHUFFLER
	PUSHJ	P,CHKSHF##	;YES, CALL CORE SHUFFLER TO MOVE ONE SEG DOWN
	CPLOCK (SCD)		;LOCK AGAIN
	SKIPN	SHFWAT##	;SHUFFLER WAITING FOR IO TO STOP?
	JRST	FIT0		;NO, SEE IF JOB WILL FIT NOW.
	POPJ	P,		;YES, RETURN AND WAIT TILL IO STOPS
>	; END OF CONDITIONAL ASSEMBLY ON FTSHFL
;HERE ON SWAP OUT ERROR
;CANNOT BE MEMORY PARITY ON CHANNEL READ BECAUSE ARR INTERRUPTS
; OR PROCESSOR STOPS WHEN CONTROLLER ROUTINE TOUCHES BAD PARITY.

OUTERR:	TRNN	S,IOCHMP	;CHANNEL (READ) MEMORY PAR ERROR?
	JRST	OUTER1		;NO, ERROR ON DISK (WRITE)
	PUSHJ	P,SWPRC1	;RECORD ERROR FLAGS AND NO. OF SWAP ERRORS
IFN FT2REL,<			;2 RELOC REG SOFTWARE?
	PUSHJ	P,HGHSWE##	;IF HIGH SEG, PRINT ERROR FOR ALL JOBS USING
	  JRST	OUTER0		;YES, ALL JOBS USING HIGH SEG GOT ERROR MESSAGE
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	MOVEI	T2,JOBPFI##+1	;NO, TEMP UNTIL GET REL ADR OF PAR AREA?
	CAIG	T2,JOBPFI##	;IS ERROR IN PROTECTED PART OF JOB DATA
	PUSHJ	P,[PUSHJ P,CHGSWP  ;YES, RETURN DISK SPACE
				; CANNOT TRUST JOB DATA AREA
				; INCREASE FREE VIRTUAL CORE
		   PJRST ZAPUSR##];CLEAR ALL HIS DDB'S, IO CHANS
	PUSHJ	P,SWOMES##	;PRINT ERROR MESSAGE AND STOP JOB
				; "SWAP OUT CHN MEM PAR ERR"
OUTER0:
IFE FTVM,<
	MOVEI	S,0		;CLEAR ERROR FLAGS
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
IFN FTVM,<
	MOVSI	T1,(SL.CHN+SL.ERR)
	ANDCAM	T1,SWPLST##(P1)
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
	JRST	SWAP1		;REENTER SWAPPER AS IF NO ERROR
				; AND FINISH SWAP OUT PROCESSING

;HERE IF SWAP OUT ERROR IS ON THE DEVICE (NOT CORE MEMORY)
OUTER1:	PUSHJ	P,SWPREC	;RECORD ERRORS
IFE FTVM,<
	SETZ	T1,
	DPB	T1,IMGOUT##
>	;END IFE FTVM
IFN FTVM,<
	PUSHJ	P,MAPBAK##	;RESET THE MAP (SETOMT WIPED IT OUT)
>
	JRST	SWAPO		;TRY AGAIN IN A DIFFERENT PLACE

;SUBROUTINE TO RECORD SWAP IN/OUT ERRORS - REDUCE AMOUNT OF VIRTUAL CORE
; CALLED FROM SEGERR ON FIRST HIGH SEG ERROR


SWPREC::LDB	T1,IMGOUT##	;KEEP COUNT OF NO. OF OCCURANCES
	ADDM	T1,SWPERC##	;AND TOTAL VIRTUAL CORE LOST IN TH
IFN FTVM,<
	CAIG	J,JOBMAX##	;HIGH SEGMENT?
	ADDI	T1,UPMPSZ##	;NO, THE SPACE OCCUPIED BY THE UPMP IS LOST TOO
>	;END IFN FTVM
	MOVNI	T1,(T1)		;DECREASE TOTAL AMOUNT OF VIRTUAL CORE
				;IF THIS IS HIGH SEG
	ADDM	T1,VIRTAL##	;BY THE AMOUNT BEING GIVEN UP
				;FALL INTO SWPRC1
;SUBROUTINE TO RECORD SWAP OUT ERROR FROM MEMORY
SWPRC1:	IORM	S,SWPERC##	;OR IN FLAGS FOR ERROR REPORTING (18-23)
	MOVSI	T1,1		;INCREASE COUNT OF NO OF SWAP ERRORS
	ADDM	T1,SWPERC##
	POPJ	P,

;NO INPUT TO DO, CHECK FOR EXPANDING JOBS
ZCKXPN:
	SETZM	SWPIFC		;CLEAR SWAPPER FAIRNESS SCAN
CHKXPN:	SKIPG	XJOB		;ANY JOBS TO EXPAND?
	JRST	CHKMIG		;NO, NO REGULAR WORK FOR SWAPPER TO DO
				; YES, FALL INTO SCNOUT WHICH WILL SWAP OUT EXPANDING
				; JOB SINCE THERE IS ONE
;INPUT TO DO, CHECK TO SEF IF ANY JOBS JUST HAPPEN TO WANT TO EXPAND
SCNOUT:	SKIPE	J,FORCE##	;ALREADY SCANNED FOR OUTPUT, AND FOUND A JOB
				; (BUT HAS ACTIVE IO, SO FINISH NOT SET YET)
	JRST	SCNOU1		;YES, TRY TO FORCE IT OUT AGAIN INSTEAD OF
				; SCANNING AGAIN AND POSSIBLY FINDING A DIFFERENT JOB
				; AND LEAVE THIS JOB IN CORE WITH SWP BIT ON SO CAN NOT
				; RUN (CAN HAPPEN ONLY IF JOBS IN CORE EXPAND
				; WHILE SWAPPING LOW SEG, SO HIGH SEG NO LONGER FITS)
				; BUT DO SOME CHECKING FIRST.
	SKIPG	XJOB		;NO, ANY JOBS WAITING TO EXPAND?
	JRST	SCNJOB		;NO, SCAN ALL JOBS IN PRIORITY ORDER LOOKING
				; FOR ONE TO SWAP OUT
	MOVE	J,HIGHJB##	;YES, START WITH HIGHEST JOB NUMBER ASSIGNED
	MOVSI	F,JXPN		;SETUP JOB EXPANDED BIT
	TDNN	F,JBTSTS##(J)	;IS THIS JOB EXPANDING?
	SOJG	J,.-1		;NO, KEEP LOOKING
IFN FTRCHK,<
	JUMPG	J,SCNOK
	STOPCD	.+1,DEBUG,XTH,		;++XJOB TOO HIGH
	SETZM	XJOB		;CLEAR XJOB SO MESSAGE WILL PRINT
	JRST	SCNJOB		;SCAN FOR OUTPUT
>	; END OF CONDITIONAL ASSEMBLY ON FTRCHK
SCNOK:
IFN FTVM,<
	SKIPE	JBTADR##(J)	;DOES THIS JOB HAVE CORE IN CORE?
	JRST	FORCE0		;YES, DON'T CLEAR JXPN UNTIL THE JOB IS ON WAY OUT
>	;END IFN FTVM
	SOS	XJOB		;DECREMENT COUNT OF EXPANDING JOBS
	ANDCAM	F,JBTSTS##(J)	;CLEAR EXPAND BIT IN JOB STATUS WORD
	JRST	FORCE0		;GO TRY TO SWAP JOB OUT
CHKMIG:
IFN FTDHIA&FT2SWP,<
IFN FTVM,<
	SKIPN	SPRCNT##	;IF THE SWAPPER IS BUSY,
	SKIPE	SWPCNT##	; DONT TRY TO START ANYTHING
	JRST	FLGNUL
>
	SKIPN	J,MIGRAT##	;TRYING TO FORCE JOBS OFF A SWAPPING UNIT?
	JRST	FLGNUL		;NO, EXIT SWAPPER
CHKMI1:	CAMLE	J,HIGHJB##	;YES, DONE ALL JOBS?
	JRST	MIGDON		;YES, THROUGH
	MOVE	T1,JBTSTS##(J)	;NO, GET SOME INFO ON JOB
	HRR	T1,JBTST2##(J)
IFN FTVM,<
	TLNE	T1,SWP
	JRST	CHKMI2		;IF JOB IS NOT SWAPPED,
	PUSHJ	P,PGOFF##	; DOES IT HAVE ANY PAGES ON UNIT GOING DOWN?
	  JRST	[MOVEM J,MIGRAT##  ;YES, SWAP IT OUT AND BACK IN TO GET
		 JRST  FORCE0]	   ; PAGES OFF THE BAD UNIT
	AOJA	J,CHKMI1	;NO, GO CHECK NEXT JOB
CHKMI2:> ;END FTVM
IFE FTVM,<
	TLNE	T1,SWP		;IF JOB IS SWAPPED,
>
	TRNE	T1,JS.MIG	; AND WE'RE NOT SURE IT MIGRATED FROM BAD UNIT,
	AOJA	J,CHKMI1
	CAMN	J,FINISH	; IF IT ISNT BEING SWAPPED NOW,
	JRST	FLGNUL
	MOVEM	J,MIGRAT##	; SWAP IT IN, SO IT WILL SWAP OUT ONTO
	JRST	FIT1		; ANOTHER SWAPPING UNIT
MIGDON:	SETZM	MIGRAT##	;DONE - CLEAR FLAG
				;FALL INTO FLGNUL
>	;END FTDHIA&FT2SWP
IFN FTRSP,<
FLGNUL:	SETOM	SWPNUF##	;TELL CLOCK1 THAT SWAPPER WILL BE
				;IDLE THIS TICK
	POPJ	P,		;RETURN
>;END IFN FTRSP
				;EXIT SWAPPER IF NO RESPONSE DATA
IFE FTRSP,<
FLGNUL:	POPJ	P,		;IF NO RESPONSE DATA
>



;HERE IF WE ARE TRYING TO FORCE OUT A JOB LEFT OVER FROM LAST TICK.

IFN FTDISK,<
SCNOU1:	CAME	J,FORCEF	;IS THIS A JOB WE MUST RUN TO FREE A SHAR. RESOURCE?
	JRST	FORIDL		;NO, INSURE SWAP GETS SET
	JRST	FORCE1		;YES, SEE IF WE CAN GET IT BEFORE TURNING ON SWAP, WHICH
				; WOULD PREVENT US FROM GETTING IT BACK
				; IF THE JOB DID HAVE IT
>
IFE FTDISK,<
SCNOU1==FORIDL
>
;SCAN FOR JOB TO OUTPUT IN ORDER TO MAKE ROOM FOR JOB TO COME IN
;SIZE(IN K) NEEDED TO GET THIS USER IN CORE IS IN P1(FITSIZ)
;JUST LOW SEG SIZE IF NO HIGH OR HIGH ALREADY IN, JUST HIGH IF LOW ALREADY IN,
;OR SUM IF BOTH MUST BE SWAPPED IN

SCNJOB:	MOVE	F,CORTAL##	;INITIALIZE FREE CORE COUNTER
	MOVEM	F,SUMCOR##
	SETZM	MAXJBN##	;CLEAR SWAP OUT JOB NUMBER
IFN FTHPQ,<			;HIGH PRIORITY QUEUES?
	MOVE	J,FIT##		;JOB (OR HI SEG) BEING FIT IN
IFN FT2REL,<			;2 RELOC REG SOFTWARE?
	PUSHJ	 P,FITHPQ##	;GET JOB NO. IF TRYING TO FIT A HIGH SEG
				; (IN CASE HIGH PRIORITY JOB HAMPERED BY
				; USER IN CORE EXPANDING DURING HIS SWAP IN

>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	MOVEM	J,FITLOW##	;REMEMBER JOB WE ARE FITTING
	LDB	T4,HPQPNT##	;GET CURRENT HIGH PRIORITY Q NO, 0 IF NONE
	MOVEI	T1,JS.TFO	;FORCED OUT BY TIMER?
	TDNE	T1,JBTST2##(J)	;...
	SETZ	T4,		;YES. DON'T IGNORE ICPT
>	; END OF CONDITIONAL ASSEMBLY ON FTHPQ
IFN FTNSCHED,<
	SETZM	SCNSTP		;ASSUME WE CAN STOP AT JOB IN FIT
	SKIPN	TYPSCD		;IS THIS THE CLASS SCHEDULER?
	JRST	NOTCLS		;NO
	LDB	T3,PJBST2	;GET JOB'S QUEUE
	MOVEI	T1,LOSCAN##	;ASSUME FIT JOB IS IN PQ2
	CAIN	T3,PQ2		;IS IT IN PQ2?
	MOVEM	T1,SCNSTP	;YES
NOTCLS:>;END IFN FTNSCHED
	MOVEI	U,OSCAN##	;SCAN ALL JOBS RANKED IN PRIORITY TO BE SWAPPED OUT
	JSP	T1,QSCAN
	  JRST	NOFIT		;NO MORE JOBS LEFT, CANNOT FIT JOB IN CORE
IFN FTNSCHED,<
	SKIPN	SCNSTP		;SCANNING ALL OF PQ2?
	JRST	USEFIT		;NO, COMPARE AGAINST FIT
	CAMLE	U,SCNSTP	;YES. HAVE WE REACHED END OF PQ2?
	SKIPE	INFLG		;YES. IGNORE IF IMPATIENT
	JRST	.+2		;NOT END OF PQ2 OR TIMER WENT OFF
	JRST	NOFIT		;CAN'T FIT JOB IN, GO TELL TIMER
	CAMN	J,FITLOW##		;DON'T SWAP OUT SWAP-IN JOB
	JRST	(T2)		;IT'S US
	JRST	SCNJB0		;IT'S NOT, TRY TO SWAP THIS JOB OUT
USEFIT:>;END IFN FTNSCHED
	CAMN	J,FITLOW##		;IS THIS JOB WE ARE TRYING TO FIT IN?
	JRST	[ SKIPE	INFLG		;IGNORE POSITION IF IMPATIENT
		 JRST	(T2)		;TIMER HAS GONE OFF
		 JRST	NOFIT		;TIMER HASN'T GONE OFF
]

SCNJB0:	SKIPN	JBTADR##(J)	;DOES JOB HAVE LOW SEG PHYSICAL CORE?
	JRST	(T2)		;NO, CONTINUE SCAN TO FIND ANOTHER JOB
				; (HIGH SEG ALREADY SWAPPED OUT IF NO LOW
				; SEG IN CORE)
IFE FTPDBS,<	;IF WE DO NOT SWAP PDB'S
	MOVE	F,JBTSTS##(J)	;NO, PICK UP JOB STATUS WORD.
	HRRZ	W,JBTPDB##(J)	;GET PDB ADR
	JUMPE	W,SCNJB1	;NO PDB, FORGET PROTECT TIME

IFN FTLOCK,<
	TLZE	F,NSWP		;IS THIS SEGMENT LOCKED?
	TLNN	F,SWP		;YES, IS IT ALREADY SWAPPED?  (OTHER SEGMENT LOCKED)
	PUSHJ	P,LOKCHK##	;NO, IT CAN BE SWAPPED (BOTH SEGMENTS NOT LOCKED)?
	  JRST	(T2)		;YES, CONTINUE SCAN
>	;END IFN FTLOCK
> ;END FTPDBS
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	MOVE	F,JBTSTS##(J)	;NO, PICK UP JOB STATUS WORD.
	PUSHJ	P,FNDPDB##	;GET PDB ADDRESS
	  JRST	SCNJB1		;NO PDB -- NO PROTECT TIME
> ;END FTPDBS
	TLNN	F,SWP		;NO ICPT IF SWP BIT SET
	.SKPGE	.PDIPT##(W)	;PROTECTED TIME PAST?
SCNJB1:	TLNE	F,NSWP		;YES, IS THIS JOB NOT TO BE SWAPPED?
				; (DISPLAY, REAL TIME)?
IFN FTHPQ,<			;HIGH PRIORITY QUEUE
	JUMPE	T4,(T2)		;IF JOB BEING FIT IN IS NOT HIGH PRIORITY
				; CONTINUE SCAN
	TLNE	F,NSWP		;IS THIS JOB NOT TO BE SWAPPED?
				; (DISPLAY, LOCKED IN CORE)?
>	; END OF CONDITIONAL ASSEMBLY ON FTHPQ
	JRST	(T2)		;YES,CONTINUE SCAN TO FIND ANOTHER
IFN FT2REL,<
	SKIPLE	T3,JBTSGN##(J)	;DOES THIS JOB HAVE A HIGH SEGMENT?
	CAME	T3,FIT##	;YES, IS IT THE ONE WE ARE TRYING TO FIT IN?
	JRST	SCNJB2		;NO. CONTINUE
	CAMN	J,SWPIN##	;YES. IS THIS THE LOW SEG WE ARE GETTING IT FOR?
	JRST	(T2)		;YES. DON'T TRY TO SWAP HIM OUT
SCNJB2:
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
IFN FTVM,<
	LDB	F,IMGOUT##	;OUTPUT SIZE
	JUMPN	F,[SKIPN INFLG	;STILL HAVE A DISK COPY?
		   JRST (T2)	;IF TIMER HASN'T GONE OFF, IGNORE THIS JOB
		   SKIPN SPRCNT## ; OTHERWISE, WE MAY WANT TO SWAP THIS JOB ANYWAY
		   SKIPE SWPCNT## ;IF THE SWAPPER IS IDLE, WE CAN'T
				; FINISH SWAPPING IT IN
		   JRST (T2)
		   JRST .+1]	;SO WE'D BETTER SWAP IT OUT (OR SYS WILL HANG)
				;THIS COULD HAPPEN IF A JOB EXPANDED IN CORE
				; BEFORE THE HIGH SEGMENT COULD SWAP IN AND
				; FIT GOT CLEARED BECAUSE THERE WAS NO MORE ROOM
	LDB	F,IMGIN##
	ADDI	F,UPMPSZ##
>	;END IFN FTVM
IFE FTVM,<
	HLRZ	F,JBTADR##(J)	;PICK UP SIZE OF JOB
	ASH	F,W2PLSH##	;CONVERT TO 1K BLOCKS
	ADDI	F,1+UPMPSZ##
>	;END IFE FTVM
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	ADDI	F,PDBPGS##	;ACCOUNT FOR CORE FREED UP BY SWAPPING
				; OUT THE PDB.
> ;END FTPDBS
IFN FT2REL,<
	PUSHJ	P,FORSIZ##	;INCREASE SIZE(F) BY HIGH SEG SIZE/# IN CORE LO SEGS +1
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	SKIPE	MAXJBN##	;PICKED ONE YET?
	JRST	FORCE2		;NO
IFN FTMS,<
	PUSHJ	P,ANYRUN##	;JOB CURRENTLY RUNNING ON CPU1?
	JRST	[MOVEM J,SW0JOB	;YES, DON'T SELECT THIS JOB
		 JRST (T2)]	; SINCE IT MAY HAVE A HI SEG WITH
				; AN IN-CORE COUNT OF 1 WHICH COULD
				; GET DELETED BY FORHGH
>
	PUSH	P,J		;SAVE J
	SKIPG	J,JBTSGN##(J)	;A REAL HIGH SEGMENT?
	JRST	FORCE3		;NO
	PUSH	P,F		;SAVE F
	PUSHJ	P,ANYSAV##	;MAKE SURE THIS CAN SWAP
	 JRST	[POP P,F	;RESTORE SIZE
		 POP P,J	;AND JOB
		 JRST (T2)]	;AND REJECT JOB
	POP	P,F		;RESTORE SIZE
FORCE3:	POP	P,J
	MOVEM	J,MAXJBN##	;SAVE JOB NUMBER
FORCE2:	ADDM	F,SUMCOR##	;ADD TO TOTAL
	CAMLE	P1,SUMCOR##	;FOUND ENOUGH CORE FOR JOB TO BE FIT IN?
	JRST	(T2)		;NO. LOOK FOR MORE
	EXCH	J,MAXJBN##	;YES, SWAP OUT FIRST
	MOVEI	F,JS.TFO
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,INRNQ		;DON'T SET IF NOT IN RUN Q
	  SETZ	F,		;NOT IN RUN Q
	POP	P,T1		;RESTORE T1
	SKIPE	INFLG		;BECAUSE OF TIMER?
	IORM	F,JBTST2##(J)	;YES. MARK IT
	JRST	FORC00		;AND DO PROPER ENTER
;HERE FROM SCNOUT OR LOCK


FORCE0::MOVEI	T2,FLGNUL	;GET READY TO FLAG SWAPPER NULL TIME IF ACTIVE DEVICES
FORC00:
IFN FTKL10&FTMS,<
	PUSHJ	P,SWPCSH##	;JOB MUST BE RUNNABLE W.R.T. CACHE IN ORDER
				; TO SWAP IT OUT, SINCE SOME OF IT MAY
				; ONLY EXIST ON ANOTHER CPU'S CACHE
	  JRST	(T2)		;NO GOOD, DO NOTHING THIS TICK, WAIT
				; FOR OTHER CPU TO SWEEP ITS CACHE
				; (HOPE THIS DOESNT HAPPEN TOO OFTEN)
>;END IFN FTKL10&FTMS
IFN FT2REL,<
	PUSHJ	P,ANYSAV##	;NO CAN THIS JOB BE STOPPED IN ORDER TO DO SWAP?
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	  JRST	(T2)		;NO, NSWP OR NSHF SET(DISPLAY,REAL TIME) OR
				; SAVE OR GET IN PROGRESS WITH DEVICE STILL ACTIVE
				; LOOK FOR AN OTHER JOB TO SWAP

	CAILE	J,JOBMAX##	;HIGH OR LOW?
	JRST	FORCEA		;HIGH
	MOVSI	F,JS.HNG	;SET TO TEST FOR JOB HUNG
	SKIPE	R,JBTADR##(J)	;CORE IN CORE?
	TDNN	F,JBTST2##(J)	;AND WAS JOB HUNG?
	JRST	FORC0A		;NO. CONTINUE CHECKING
	PUSHJ	P,ANYDEV##	;IS JOB STILL HUNG?
	  SKIPA	J,MAXJBN##	;YES. LOOK FOR ANOTHER
	JRST	SWAPO		;NO LONGER HUNG. SWAP IT OUT
	JRST	0(T2)
FORC0A:
IFN FTDISK,<
	PUSHJ	P,FLSDR##	;LOW. ANY SHAREABLE DISK RESOURCES?
	  JRST	FORCEA		;HIGH SEG OR NO RESOURCES - SO OK
	MOVEM	J,FORCE##	;SET FOR LATER RETRIES
	MOVEM	J,FORCEF	;AND FLAG THE PROBLEM
	JRST	FLGNUL		;QUIT FOR NOW SINCE CAN'T SWAP HIM
>	;END OF FTDISK CONDITIONAL
FORCEA:
IFN FT2REL,<
	PUSHJ	P,FORHGH##	;IS THERE A HIGH SEG TO BE WRITTEN BEFORE
				; TRYING TO SWAP OUT LOW SEGMENT?
				; WRITE HIGH SEG IF ALL OF THE FOLLOWING ARE TRUE:
				; 1. JOB HAS A HIGH SEG AND
				; 2. IT HAS NOT BEEN SWAPPED FOR THIS USER
				;    (SWP=0 FOR JOB)
				; 3. IT IS IN CORE(NOT XPANDH)
				; 4. IF IN-CORE COUNT IS EXACTLY 1 MEANING
				;    THIS ONLY USER USING IN CORE
				; 5. HIGH SEG NOT ON DISK YET
				; 6. THIS HIGH SEG IS NOT THE SAME ONE AS JOB
				;    BEING FITTED IN IS GOING TO WANT
				; RETURN HIGH SEG NO. IN J IF YES, OTHERWISE
				; RETURN LOW SEG NO.
				; IF JOB JUST HAS LOW SEG, SHF BIT IS SET IN JBTSTS
				;    FOR JOB SO IO WILL STOP NEXT BUFFER
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
;HERE FROM LOKCON TOO TO FORCE OUT IDLE HIGH SEG
FORIDL::MOVSI	F,SWP!IFE FT2REL,<SHF>	;SET SWAPPED OUT BIT FOR LOW OR HIGH SEG
	IORM	F,JBTSTS##(J)	;SCHEDULER WILL NO LONGER RUN THIS JOB
				; SET SHF BIT IF ONE SEG SOFTWARE, SO IO WILL
				; STOP AFTER NEXT BUFFERFUL.
				; HERE TO FORCE OUT IDLE HIGH SEG WHEN IT
				; HAS NO COPY ON DISK (UWP OFF)

FORCEL:	MOVEM	J,FORCE##	;ASSUME NOT SWAPPABLE--IS IT?

IFE FTPDBS,<	;IF WE DO NOT SWAP PDB'S
FORCE1:
> ;END FTPDBS
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
FORCE1:	JUMPL	J,SWAPO		;NO I/O INTO PDB

> ;END FTPDBS
IFN FTDISK,<
	SKIPN	FORCEF		;TRYING TO SWAP GUY WITH DISK RESOURCE?
	JRST	FORCEB		;NO. PROCEED NORMALLY
	PUSHJ	P,FLSDR##	;YES. DOES HE STILL HAVE IT
	  JRST	.+2		;NO. SWAP HIM
	JRST	FLGNUL		;YES. TRY LATER
	SETZM	FORCEF		;CLEAR FLAG
	JRST	FORCE0		;COMPLETE THE WORK SKIPPED EARLIER
FORCEB:>	;END OF FTDISK CONDITIONAL
	SKIPN	R,JBTADR##(J)	;LOC. IN PHYSICAL CORE, IS CORE
				; ASSIGNED IN MEMORY?
	JRST	SWAPO		;NO, CANNOT HAVE ACTIVE DEVICES
	CAME	J,.C0JOB##	;IF THIS IS CURRENT JOB, WAIT UNTIL
				; PROTECTED AREA IS MOVED BACK TO JOB DATA AREA
	PUSHJ	P,ANYDEV##	;ANY ACTIVE DEVICES?(2ND HALF OF ANYACT ROUT.)
	  JRST	NOFIT		;YES--RETURN AND WAIT FOR I/O TO STOP.
				; IF FIT TIMER HAS EXPIRED, CONSIDER THIS JOB
				; HUNG AND REMOVE IT FROM FORCE SO ANOTHER
				; JOB CAN BE SWAPPED
;SWAP OUT LOW OR HIGH SEGMENT



SWAPO:
IFE FTVM,<
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	CAILE	J,JOBMAX##	;HISEG?
	JRST	SWAPO2		;YES--JUST SWAP
	MOVM	J,J		;YES--LOOK AT JOB
	SKIPN	JBTADR##(J)	;SKIP IF JOB IN CORE
SWAPO1:	MOVN	J,J		;JOB SWAPPED TRY PDB
SWAPO2:> ;END FTPDBS
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
IFN FTTRACK,<	MOVEM	J,LASOUT##	;SAVE LAST SWAP OUT FOR DEBUGGING ONLY
>	; END OF CONDITIONAL ASSEMBLY ON FTTRACK
	SETZM	FORCE##		;CLEAR FORCE FLAG
	SETZM	SW0JOB
IFN FTLOCK,<
	MOVE	F,JBTSTS(J)	;GET SEGMENT STATUS
	TLNE	F,NSWP		;IS THIS SEGMENT LOCKED IN CORE?
IFN FTVM,<
	JRST	[PUSHJ	P,FIXXPN  ;YES, RETURN AND PRETEND IT WAS SWAPPED OUT
		 JRST	FINOU0]
>
IFE FTVM,<
	JRST	FINOU0
>
>	;END IFN FTLOCK
	HLRZ	F,JBTADR##(J)	;COMPUTE CORE IMAGE
	JUMPE	F,SWP1		;DONT OUTPUT IF 0 CORE(IMGOUT ALREADY SET TO 0
				; WHEN CORE WAS RETURNED

IFE FTVM,<
	LDB	T2,IMGOUT##	;ASSUME SWAPING SPACE
	JUMPN	T2,FINOU2	; IS NOT ALREADY ALLOCATED
	HRRZ	T2,JBTADR##(J)
	MOVNM	F,T1		;*SAVE COUNT FOR CALL TO SQOUT
	ASH	F,W2PLSH##	;CONVERT TO 1K BLOCKS
	ADDI	F,1
	DPB	F,IMGOUT##	;RECORD AS OUT IMAGE
	HRLI	T2,-1(T1)	;*BUILD AND SAVE IOWD FOR SQOUT
	PUSH	P,T2		;*
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
	LDB	U,IMGIN##	;HAS SIZE OF CORE NEEDED WHEN NEXT SWAPPED IN
IFN FTVM,<
	MOVSI	F,SHF		;ASSUME A LOW SEGMENT
	CAIG	J,JOBMAX	;IS IT?
	IORM	F,JBTSTS##(J)	;YES, INDICATE SWAPPING OUTPUT IN PROGRESS
	LDB	F,IMGOUT##	;OUTPUT IMAGE SIZE
	SKIPE	F		;HAS IT BEEN SET BY XPAND?
	SKIPA	U,F		;YES, DON'T CHANGE IT
	DPB	U,IMGOUT##	;NO, SET OUTPUT IMAGE
>
IFE FTVM,<
	SKIPN	U		;ALREADY BEEN SET(XPAND)
	DPB	F,IMGIN##	;NO, SO SET TO # 1K BLOCKS OF CORE NEEDED
	MOVE	U,F		;*CONVERT CORE IMAGE TO 128 WD BLOCKS
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
IFN FTVM,<
	CAIG	J,JOBMAX##	;A HIGH SEGMENT?
	MOVEI	U,UPMPSZ##(U)	;NO, ACCOUNT FOR THE UPMP
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
	LDB	F,IMGOUT##	;GET OUTPUT IMAGE SIZE
	MOVEI	T2,0		;ZERO IMGOUT SO IF A HIGH SEGMENT IT WON'T
	DPB	T2,IMGOUT##	; LOOK LIKE IT ALREADY HAS DISK SPACE TO DODELE
	PUSHJ	P,SWPSPC##	;*GET DEVICE STORAGE, SAVE DEVICE ADDR IN JBTSWP
	  JRST	SWAPO3		;DIDN'T MAKE IT
	DPB	F,IMGOUT##	;NOW, SAFELY STORE OUTPUT SIZE
IFE FTVM,<
IFE FTPDBS,<	;IF WE DO NOT SWAP PDB'S
	MOVNM	J,FINISH##	;DISK SWAP SPACE ASSIGNED, NOW SET FINISH FLAG
> ;END FTPDBS
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	SETZM	SWAPIN##	;FLAG AS SWAP OUT
	MOVEM	J,FINISH##	;DISK SWAP SPACE ASSIGNED, NOW SET FINISH FLAG
> ;END FTPDBS
				; SO THAT SWAPPER WILL KNOW WHICH SEG FINISHED
				; WHEN IO COMPLETED(SQREQ BECOMES ZERO)
	POP	P,T2		;*GET IOWD
IFN FTRSP,<
	SETZM	SWPPLT##	;CLEAR LOST TIME FLAG, WE'RE ACTIVE
>;END IFN FTRSP
	JRST	SQOUT##		;*START OUTPUT AND RETURN
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
IFN FTVM,<
	PUSH	P,J		;FILSER CLOBBERS J
	PUSHJ	P,BOSLST##	;BUILD AN OUTPUT SWPLST ENTRY
	AOS	SPRCNT##	;COUNT UP THE NUMBER OF SWAPS IN PROGRESS
IFN FTRSP,<
	SETZM	SWPPLT##	;CLEAR LOST TIME FLAG
>;END IFN FTRSP
	PUSHJ	P,SQOUT##	;START I/O IF NOT ALREADY GOING
	POP	P,J		;RESTORE SEGMENT NUMBER
	PUSHJ	P,FIXXPN	;FIX JXPN BIT
	JRST	CHKXPN
FIXXPN:	MOVSI	T1,JXPN		;JOB IS EXPANDING BIT
	CAIG	J,JOBMAX##	;HIGH SEGMENT?
	TDNN	T1,JBTSTS##(J)	;NO, IS THIS JOB EXPANDING?
	POPJ	P,		;NO, RETURN
	ANDCAM	T1,JBTSTS##(J)	;YES, CLEAR JXPN SO JOB WON'T BE SEEN AGAIN
	SOS	XJOB		;DECREMENT THE COUNT OF EXPANDING JOBS
	POPJ	P,		;AND RETURN
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
SWAPO3:
IFE FTVM,<
	POP	P,(P)		;POP OFF JUNK
>
IFN FTVM,<
	LDB	T1,IMGIN##	;INPUT SIZE SET BY XPAND
	CAIN	T1,(F)		;INPUT AND OUTPUT SIZES DIFFERENT?
	MOVEI	F,0		;NO, NOT SET OUTPUT SIZE TO ZERO
	DPB	F,IMGOUT##	;STORE AS OUTPUT SIZE
>
	MOVEM	J,FORCE##	;REMEMBER WHO WE WERE TRYING TO SWAP OUT
	JRST	FLGNUL		;RETURN, TRY SWAP NEXT TICK
NOFIT:	SKIPE	J,FIT##		;PICK UP JOB NUMBER WE COULDNT FIT IN NOW
	CAILE	J,JOBMAX
	JRST	FLGNUL
IFN FTHPQ,<
	CAME	J,FITJBZ	;WAS THIS PERSON IN FIT AND TIMING?
	JRST	NOFIT0		;NO. JUST NORMAL
	MOVEM	J,INFLGJ	;YES. PUT HIM BACK WHERE HE WAS BEFORE
	MOVE	F,UPTIME##	; THE HPQ JOB ZAPPED HIM
	SUB	F,FITTIM	;CURRENT TIME MINUS TIME HE WAITED
	MOVEM	F,INFLGC	; LAST TIME IS NEW TIMER
	SETZM	FITJBZ		;NOW CLEAR REMEMBRANCE OF IT
	JRST	NOFIT1		;AND PROCEED
NOFIT0:>	;END IFN FTHPQ
	CAMN	J,INFLGJ	;SAME JOB WE COULDNT FIT IN LAST TICK?
	JRST	NOFIT1		;YES. COUNT HIS FRUSTRATION INDEX
	MOVEM	J,INFLGJ	;NO. REMEMBER HIM FOR FUTURE REFERENCE
	MOVE	F,UPTIME##	;AND START TIMER
	MOVEM	F,INFLGC
	JRST	FLGNUL		;FINISH UP
NOFIT1:	MOVE	F,UPTIME##	;CURRENT TIME
	SUB	F,INFLGC	;COMPUTE TIME WE'VE BEEN WAITING
	CAIGE	F,^D360		;FRUSTRATION TIMED OUT? (ABOUT 6 SEC)
	JRST	FLGNUL		;NO. PATIENCE PLEASE.
	SETOM	INFLG		;GIVE HIM A QUICKER IN
	AOS	CINFLG		;COUNT # OF TIMES INFLG WAS SET.
	SKIPE	J,FORCE##	;IS THERE A JOB IN FORCE?
	CAILE	J,JOBMAX##	;AND IS IT A LOW SEGMENT?
	JRST	FLGNUL		;NO, WORK IS DONE
	MOVSI	F,JS.HNG	;YES, INDICATE THAT THIS JOB SHOULD NO LONGER BE
	IORM	F,JBTST2##(J)	; FORCED. SWAP IT OUT ONLY WHEN I/O IS INACTIVE
	MOVSI	F,SHF		;AND IT SHOULD NOT BE ALLOWED TO ADVANCE BUFFERS
	IORM	F,JBTSTS##(J)	; SINCE THE JOB MAY BE THE ONLY ONE ELIGIBLE FOR SWAP OUT
	AOS	CJHUNG		;COUNT # OF TIMES A JOB HUNG WITH ACTIVE I/O
	SETZM	FORCE##		;ALLOW SWAPPER TO PICK ANOTHER JOB IF POSSIBLE
	JRST	FLGNUL		;RETURN AND TRY TO SWAP NEXT TICK

	$LOW
INFLGJ::0		;FRUSTRATED JOB NUMBER WAITING TO BE SWAPPED IN
INFLGC::0		;TIME HE STARTED WAITING
INFLG::	0		;HE IS FRUSTRATED
CINFLG::0		;NUMBER OF TIMES WE GOT FRUSTRATED
CHKQJB::0		;IF SET TO -1, CKJB1 WILL SCAN ALL JOBS FOR JRQ
CJHUNG::0		;NUMBER OF TIMES FORCE WAS CLEARED TO AVOID
				; HANGING THE SYSTEM
SW0JOB::0

IFN FTHPQ,<
FITJBZ::0		;JOB THAT WAS IN FIT WHEN HPQ ZEROED
FITTIM::0		;HOW LONG HE WAS THERE
>;END IFN FTHPQ

SWPIFC::0		;SWAPER FAIRNESS COUNT
MAXIFC::IFC0##		;MAXIMUM FAIRNESS COUNT FOR SWAPPER
IFN FTNSCHED,<
TYPSCD::0		;PLACE FOR SWAPPER TO CHECK SCHEDULER TYPE
SCNSTP:	0		;IF SCHEDULER IS IN CLASS MODE AND JOB BEING
			; FIT IS IN PQ2,
			;CONTAINS ADDRESS IN OSCAN OF FIRST QUEUE AFTER PQ2
			; ZERO OTHERWISE.
>;END IFN FTNSCHED

	$HIGH

IFN FTDISK,<
	$LOW
FORCEF::0
	$HIGH
>

NOFITZ:	SETZM	FIT##		;CLEAR JOB BEING FIT IN
	JRST	FLGNUL		;EXIT SWAPPER. NEW JOB WILL BE SELECTED NEXT TIME

IFN FTHPQ,<
ZERFIT:	SETZM	FIT##		;CLEAR FIT SO WE CAN RESELECT
	SKIPE	FITJBZ		;ARE WE ALREADY REMEMBERING SOMEONE?
	POPJ	P,		;YES. REMEMBER OLDEST
	MOVEM	J,FITJBZ	;REMEMBER HIM
	MOVE	T2,UPTIME##	;NO. SEE HOW LONG THIS GUY WAITED
	SUB	T2,INFLGC
	MOVEM	T2,FITTIM	;AND REMEMBER THAT TOO
	MOVE	J,.C0RTF##	;SELECT HPQ JOB TO SWAP IN
	MOVEM	J,FIT##
	POPJ	P,
>
;SWAP IN A JOB OR HIGH SEGMENT

SWAPI:
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	CAILE	J,JOBMAX##	;IS THIS A HISEG
	JRST	SWAPI2		;YES--NO PDB TO WORRY US
	MOVM	J,J		;GET THE PDB NUMBER
	MOVN	J,J		; FOR THIS JOB
	SKIPE	JBTADR##(J)	;IS THE PDB IN CORE?
	MOVM	J,J		;YES--BRING IN THE LOWSEG
SWAPI2:> ;END FTPDBS

IFN FTTRACK, <	MOVEM	J,LASIN##	;SAVE LAST SWAP IN FOR DEBUGGING ONLY
>	; END OF CONDITIONAL ASSEMBLY ON FTTRACK

IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	SETOM	SWAPIN##	;FLAG AS A SWAP IN.
> ;END FTPDBS
	SETZM	FIT##		;CLEAR FIT FLAG
	LDB	T1,IMGIN##	;SIZE OF CORE TO BE ASSIGNED WHEN SWAPPED IN (IN K)
IFE FTPDBS,<	;IF WE DO NOT SWAP PDB'S
	LSH	T1,P2WLSH##		;CONVERT TO HIGHEST ADR
> ;END FTPDBS
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	JUMPE	T1,FININ0	;ALL DONE IF LOWSEG SIZE IS ZERO.
	LSH	T1,P2WLSH##	;CONVERT TO HIGHEST ADR
> ;END FTPDBS
	MOVEI	T1,-1(T1)	;-1 FOR CALL TO CORGET (ALWAYS POSITIVE)
	SKIPE	R,JBTADR##(J)	;IS (LOW) SEG ALREADY IN CORE ?
IFE FTVM,<
	JRST	FININ0		;YES, POSSIBLE IF THIS IS LOW SEG AND ONLY
				; HIGH SEG WAS SWAPPED OUT.
>
IFN FTVM,<
	JRST	FININ5		;YES, TREAT AS SWAP IN - GO CLEAN UP
>
	MOVEM	J,FINISH##	;SET FINISH FLAG TO INPUT
	CPUNLK (SCD)		;UNLOCK ALL CALLS TO SHUFFLER
	PUSHJ	P,CORGET##	;NO, GET CORE FOR LOW OR HIGH SEG
	  STOPCD .,STOP,CNA,	;++CORE NOT AVAILABLE
	SKIPN	JBTADR##(J)	;IS SPACE IN CORE?
	STOPCD	.,STOP,SOD,	;++SPACE ON DISK
				;SPACE IS ON THE DISK. THIS HAPPENS
				; IF PDB FRAGMENTS CORE.
	CPLOCK (SCD)		;LOCK AGAIN
IFN FT2REL, <	PUSHJ	P,FITHGH##	;INCREASE INCORE COUNT FOR THIS JOB'S HIGH SEG.
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	LDB	F,IMGOUT##	;GET OUTPUT IMAGE
	JUMPE	F,FININ0	;DON'T INPUT IF OUT IMAGE IS 0
IFN FTPSCD,<
	PUSHJ	P,CNTSWP	;RECORD DATA ON SWAPPING
>
IFE FTVM,<
	LDB	T2,IMGIN##	;IS SIZE OF CORE SMALLER THAN DISK SPACE ?
	CAMGE	T2,F		;WELL ?
	MOVE	F,T2		;YES, ONLY INPUT SMALLER AMOUNT (X,RUN,GET,KJOB)
	LSH	F,^D18+P2WLSH##	;*BUILD IOWD FOR SQIN
	MOVN	T2,F		;*
	HRR	T2,JBTADR##(J)	;*
	HLRZ	T1,JBTSWP##(J)	;*GET DEVICE ADDRESS
>	; END OF CONDITIONAL ASSMBLY ON FTVM
IFN FTVM,<
	PUSHJ	P,BUSLST##	;SETUP TO SWAP IN THE UPMP
	AOS	SPRCNT##	;COUNT UP NUMBER OF SWAPPING OPERATIONS IN PROGRESS
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
IFN FTRSP,<
	SETZM	SWPPLT##	;CLEAR POT LOST FLAG, WE'RE DOING 
>;END IFN FTRSP
				;SOMETHING
	JRST	SQIN##		;*START INPUT
;ROUTINE TO CHANGE DISK SWAPPING SPACE ALLOCATION (OR SET TO 0)
;DIFFERS FROM ZERSWP IN THAT VIRTUAL TALLY FOR SYSTEM IS ALSO CHANGED
;CALLED FROM CORE0
;CALL:	MOVE J,JOB OR HIGH SEG NUMBER
;	MOVE T1,#1K BLOCKS TO BE NEW ASSIGNMENT
;	PUSHJ P,CHGSWP
;	ALWAYS RETURN
;CALLED ONLY FROM VIRTUAL+PHYSICAL CORE ROUTINE CORE0


CHGSWP::LDB	T2,IMGIN##	;SIZE WHEN SEG NEXT SWAPPED IN
	JUMPE	T1,CHG1		;IS ZERO BEING ASKED FOR ?
	LSH	T1,W2PLSH##	;NO, CONVERT TO 1K BLOCKS
	ADDI	T1,1		;BUT DO NOT ATTEMPT TO RETURN DISK SPACE
				; SINCE IT MIGHT BE FRAGMENTED (SWAPPER WILL
				; RETURN ALL OF DISK SPACE ON NEXT SWAPIN)
				; HAPPENS ONLY ON X,RUN,GET,KJOB
	DPB	T1,IMGIN##	;STORE NEW SIZE WHEN NEXT SWAPPED IN
	PUSH	P,J		;SAVE AN AC
IFN FTVM,<
	MOVNI	J,UPMPSZ##	;UPMP SIZE
	SKIPN	T2		;IF GOING FROM 0 TO POSITIVE CORE,
	ADDM	J,VIRTAL##	; DECREMENT VIRTAL FOR UPMP
>
	LDB	J,IMGOUT##	;GET OLD DISK SIZE OF THIS USER (USES ITEM)
	CAMGE	T2,J		;IS OLD IN-CORE SIZE BIGGER ?
	MOVE	T2,J		;NO, USE DISK SIZE AS USER'S OLD VIRTUAL CORE
	CAMGE	T1,J		;IS NEW IN-CORE SIZE BIGGER ?
	MOVE	T1,J		;NO, USE DISK SIZE AS USER NEW
				; VIRTUAL CORE
	SUB	T2,T1		;DECREASE OF USER VIRTUAL CORE=OLD-NEW
	ADDM	T2,VIRTAL##	;USER'S DECREASE=SYSTEM'S INCREASE OF VIRTUAL
				; CORE
	JRST	IPOPJ##		;RESTORE J AND RETURN
;ROUTINE TO RETURN ALL OF DISK SPACE FOR A LOW OR HIGH SEG
;THIS IS A PHYSICAL DEALLOCATION ONLY AND HAS NO EFFECT ON A SEGMENTS
;VIRTUAL CORE ASSIGNMENT
;CALL:	MOVE J,JOB NUMBER OR HIGH SEG NUMBER
;	PUSHJ P,ZERSWP
;CALLED FROM SEGCON IN MANY PLACES (5)
;AND FININ0 HERE IN SWAP


CHG1:
IFN FTVM,<
	JUMPE	T2,ZERSWP	;HAVE CORE ON DISK?
	CAIG	J,JOBMAX##	;LOW SEGMENT?
	ADDI	T2,UPMPSZ##	;YES, ACCOUNT FOR THE UPMP
>
	ADDM	T2,VIRTAL##	;INCREASE SIZE OF VIRTUAL CORE AVAILABLE IN SYSTEM
				; AND THEN RETURN ALL OF DISK SPACE (CHGSWP)
ZERSWP::PUSH	P,U		;SAVE TTY OUTPUT BYTE POINTER (COMMAND DECODER)
	LDB	U,IMGOUT##	;*SIZE ON DISK (1K BLOCKS)
	JUMPE	U,CHG10		;DID SEG HAVE ANY DISK SPACE ?
	HLRZ	T1,JBTSWP##(J)	;*YES, LOGICAL DISK BLOCK+FRGSEG BIT
IFN FT2REL,<	PUSHJ	P,ZERSWH##	;IS THIS A HIGH SEG WITH AN ERROR?
				;T2 SETUP AS ARG
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
IFE FTVM,<
	  PUSHJ P,FXSAT##	;*NO, FREE THE DISK BLOCKS NO LONGER NEEDED
>	; END OF CONDITIONAL ASSEMBLY ON FTVM
IFN FTVM,<
	  PUSHJ	P,GIVBKH	;GIVE BACK HIGH SEGMENT SWAPPING SPACE
>	; END CONDITIONAL ASSEMBLY OF FTVM
CHG10:	POP	P,U		;RESTORE U

UNSWAP:	MOVSI	T2,SWP!SHF	;CLEAR SWAPPED OUT BIT IN JOB OR SEG
	ANDCAB	T2,JBTSTS##(J)	;STATUS WORD (SHF SET IF I/O WAS TO BE STOPPED
				; FOR SWAP OR CORE SHUFFLE

	HRRZ	T1,J		;GET JOB NUMBER IN T1
	CAME	T1,FORCE	;SWAPPER REMEMBERING US?
	JRST	UNSWP1		;NO, CONTINUE
	SETZM	FORCE		;YES, CLEAR FLAGS THAT HAVE OUR NUMBER
IFN FTDISK,<
	SETZM	FORCEF		;FORCEF MAY HAVE OUR JOB NUMBER TOO
>
				;(FORCEF SHOULD EITHER BE ZERO OR SAME AS FORCE)
UNSWP1:	MOVEI	T1,0		;0 IS NEW DISK ASSIGNMENT
	DPB	T1,IMGOUT##	;SET DISK ASSIGNMENT TO 0
IFN FTVM,<
	CAIG	J,JOBMAX##	;A LOW SEGMENT?
	HRRZS	JBTSWP##(J)	;SO IT WONT LOOK LIKE IT HAS CORE
				;WHEN IT DOESNT
>
IFE FTVM,<
	DPB	T1,IMGIN##	;SET NEW CORE IMAGE BLOCK SIZE WHEN NEXT SWAPPED IN
>
				; HERE FROM CHGSWP IF NOT ASKING FOR 0
	POPJ	P,		;RETURN

IFN FTVM,<
RTNDSP::TLNE	T1,(SL.ERR+SL.CHN)	;DONT GIVE BACK SWAPPING SPACE IF BAD
	POPJ	P,		;RETURN
	LDB	U,[POINT 9,T1,35] ;NUMBER OF PAGES OF SWAPPING SPACE
	LDB	T1,[POINT 13,T1,26] ;FIRST PHYSICAL PAGE I/O WAS DONE INTO OR OUT OF
	LDB	T1,[POINT 17,MEMTAB(T1),35] ;FIRST DISK ADDRESS
	PJRST	FXSAT1##	;RETURN THE DISK SPACE
;SUBROUTINE TO GIVE BACK DISK SPACE AND CORE BLOCKS
;CALL WITH P1=LOC OF SWPLST ENTRY
GIVBAK:	LDB	T1,IMGOUT##	;OUTPUT IMAGE SIZE
	JUMPE	T1,CPOPJ##	;RETURN IF NO OUTPUT IMAGE
	PUSHJ	P,ZERSLE	;RETURN THE DISK SPACE
	PJRST	DLTSLE##	;AND DELETE THE SWPLST ENTRY

ZERSLE::SKIPL	T1,SWPLST##(P1)	;FRAGMENTED?
	PJRST	RTNDSP		;NO, JUST RETURN THE DISK SPACE
	PUSHJ	P,SAVE1##	;SAVE AN AC
	HRRZ	P1,T1		;ADDRESS OF THE FRAGMENT TABLE
GIVBK1:	MOVE	T1,(P1)		;NEXT ENTRY IN THE FRAGMENT TABLE
	JUMPLE	T1,GIVBK2	;JUMP IF A LINK WORD
	PUSHJ	P,RTNDSP	;RETURN THE DISK SPACE REPRESENTED IN THIS ENTRY
	AOSA	P1		;STEP ON TO THE NEXT ENTRY IN THE TABLE
GIVBK2:	HRRZ	P1,T1		;LINK TO NEXT ENTRY
	JUMPN	P1,GIVBK1	;JUMP IF NOT THE LAST ENTRY
	POPJ	P,		;ALL DONE, RETURN

GIVBKH:	PUSHJ	P,SAVE1##	;SAVE P1
	MOVSI	P1,MJBTMX##	;- TOTAL NUMBER OF SEGMENTS ALLOWED
CHG4:	SKIPN	SWPLST##(P1)	;NON-ZERO ENTRY IN SWPLST?
	JRST	CHG6		;NO, LOOK AT THE NEXT ENTRY
	HRRZ	T1,SW3LST##(P1)	;SEGMENT NUMBER ASSOCIATED WITH THIS ENTRY
	CAIN	T1,(J)		;SAME AS THE ONE WE ARE LOOKING FOR?
	PJRST	GIVBAK		;YES, GIVE BACK THE DISK SPACE
CHG6:	AOBJN	P1,CHG4		;LOOP FOR THE NEXT ENTRY
	HLRZ	T1,JBTSWP##(J)	;GET SWAPPING POINTER
	PJRST	FXSAT##		;GIVE BACK THE DISK SPACE
>
;XPAND SETS CONDITIONS TO GET MORE CORE FOR A JOB BY SWAPPING IN OUT
;THEN BACK IN TO DESIRED AMOUNT.
;JOBS POSITION IN QS NOT AFFECTED.
;CALLED ONLY FROM CORE COMMAND
;ASSUMES CALL FOR CURRENT JOB IF EXPANDING HIGH SEG,IE ASSUME AT UUO LEVEL
;THIS IS TRUE SINCE THERE IS NO CORE COMMAND WHICH CAN EXPAND HIGH SEG
;CALL:	MOVE J,[JOB NUMBER]
;	MOVE T1,[HIGHEST LEGAL ADDRESS DESIRED]
;	PUSHJ P,XPAND
;	RETURN, T1 DESTROYED

XPAND::
IFN FTVM,<
	CAILE	J,JOBMAX##	;IS THIS A LOW SEG?
	TLNN	J,SHRSEG	;SHAREABLE HIGH SEG?
	CAIA			;OK TO CHANGE JBTADR
	JRST	XPAND2		;DON'T CHANGE JBTADR FOR SHR SEG
	SKIPE	R		;DON'T MAKE JBTADR NON-ZERO IF NO CORE IN CORE
	HRLM	T1,JBTADR##(J)	;MAKE JBTADR RIGHT
XPAND2:>
	ADDI	T1,1		;CONVERT HIGHEST DESIRED ADDRESS
	LSH	T1,W2PLSH##	;TO 1K BLOCKS
IFN FTVM,<
	CAILE	J,JOBMAX##	;A LOW SEGMENT?
	JRST	XPANDP		;NO, A SHARABLE HIGH SEGMENT, DON'T CHANGE
				; THE WORKING SET
	JUMPE	R,XPAND1	;IF NO CORE, NO WORKING SET TO MAKE RIGHT

	PUSHJ	P,ADJWS##	;TURN ON BITS IN WSBTAB WHICH REPRESENT PAGES
				; BEING ADDED TO THE WORKING SET
XPANDP::LDB	T2,IMGIN##	;CURRENT PHYSICAL SIZE
	DPB	T2,IMGOUT##	;STORE AS OUTPUT IMAGE SIZE
XPAND1:>
	DPB	T1,IMGIN##	;STORE, SO SWAPPER WILL KNOW HOW MUCH CORE
				; TO REQUEST WHEN NEXT SWAPPED IN

;ROUTINE TO FLAG JOB TO BE STOPPED AND SWAPPED OUT
;BECAUSE IT HAS JUST BEEN CONNECTED TO A HIGH SHARABLE SEG WHICH IS ON DISK
;OR ON ITW WAY IN OR OUT.  THE SIZE OF THE HIGH SEG IS UNCHANGED
;THE JOB MUST BE STOPPED UNTIL HIGH SEG SWAPPED IN JUST AS IF JOB HAS
;EXPANDED HIGH SEG (MUST BE CALLED FROM UUO LEVEL FOR CURRENT JOB IF HIGH SEG)
;ALSO CALLED FROM HIBERNATE UUO IF USER WANTS TO BE SWAPPED OUT
; AND MEMORY PARITY ERROR RECOVERY
; IF JOB (LOW OR HIGH SEG) IS LOCKED OR HIGH SEG LOCKED
; NOTHING IS SWAPPED OUT (INCLUDING OTHER JOBS USING HIGH SEG)
;CALL:	MOVE J,HIGH SEG NUMBER
;	PUSHJ P,XPANDH


XPANDH::
IFN FTLOCK,<			;LOCK UUO FEATURE?
	PUSHJ	P,LOKCHK##	;IS THIS JOB (LOW OR HIGH SEG) OR HIGH SEG LOCKED?
	  POPJ	P,		;YES, CANNOT SWAP OUT
>	; END OF CONDITIONAL ASSEMBLY ON FTLOCK
IFN FT2REL,<			;2 RELOC REG SOFTWARE?
	PUSH	P,J		;SAVE JOB NUMBER
	PUSHJ	P,XPNHGH##	;CHECK IF THIS IS A HIGH SEG EXPANDING
				; IF YES, SCAN OTHER JOBS, CALL XPANDH
				; FOR EACH JOB WHICH IS STILL IN CORE
				; SET JXPN FOR THIS HIGH SEG.  THUS NO JOB
				; WILL BE ABLE TO USE THIS HIGH SEG UNTIL
				; IT IS SWAPPED BACK IN FOR SOME JOB.
				; ALWAYS RETURN JOB NO.
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
	MOVSI	T2,JXPN		;SET THIS JOB EXPANDING BIT SO IT WILL NOT BE RUN
IFN FTPDBS,<	;THIS IS INCLUDED IF WE SWAP PDB'S
	MOVM	J,J		;MAKE SURE WE HAVE A JOB NUMBER
	CAMLE	J,HIGHJB##	;IS THIS NUMBER GREATER THAN THE HIGHEST
				; JOB NUMBER IN THE SYSTEM.
	MOVEM	J,HIGHJB##	;YES--FIX UP HIGHJB. THIS HAPPENS IF
				; CREPDB IS CALLED FOR A NEW PROCESS
				; AND WE NEED TO PLACE THE PDB ON THE
				; DISK FOR A WHILE.
> ;END FTPDBS
	TDNN	T2,JBTSTS##(J)	;IS IT ALREADY SET FOR THIS JOB?(UNLIKELY)
	AOS	XJOB		;NO, INCREMENT COUNT ONLY ONCE FOR EACH JOB EXPANDING
	IORM	T2,JBTSTS##(J)	;AND SET JOB EXPANDING BIT
IFE FT2REL, <
	POPJ	P,		;RETURN
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
IFN FT2REL, <
	JRST	IPOPJ##		;RESTORE JOB OR HIGH SEG NUMBER (ITEM) AND RETURN
>	; END OF CONDITIONAL ASSEMBLY ON FT2REL
SUBTTL SCHED. UUO

IFN FTNSCHED,<
;SCHED. UUO USED TO SET SCHEDULER PARAMETERS
; CALL:
;	MOVE	AC,[XWD	N,ADDR]
;	SCHED.	AC,		;OR CALLI AC,150
;	  ERROR RETURN
;	GOOD RETURN
;
; THE FORMAT OF ADDR THROUGH ADDR+N-1 IS
;
; ADDR:	XWD FN CODE,BLOCK
;	XWD FN CODE,BLOCK
;		.
;		.
;		.
; WHERE FN CODE IS THE FUNCTION CODE DESIRED. BIT 0 CONTROLLS WHETHER
; THE READ PART OR THE WRITE PART OF THE FUNCTION IS SELECTED, A 1 MEANING
; WRITE.
; THE FORMAT OF BLOCK DIFFERS WITH EACH FUNCTION, AND IS DESCRIBED BEFORE
; EACH FUNCTION'S SUBROUTINE.

	SC.WRT==1B0		;WRITE BIT (MUST BE SIGN BIT)

SCHED.::PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,T1		;SAVE C(AC) IN P1
	PUSHJ	P,PRVJ##	;PRIVELEGED?
	  JRST	.+2		;YES, CONTINUE
	JRST	SCHNPE		;NO,GIVE ERROR
	HLRE	T1,P1		;GET NUMBER OF OPERATIONS
	JUMPLE	T1,CPOPJ1	;DONE IF ZERO OR NEG.
	MOVNS	T1
	HRL	P1,T1		;-N,,ADDR IS AOBJN POINTER
SCHDU1:	HRR	M,P1		;GET ADDR OF BLOCK
	PUSHJ	P,SCHGET	;GET A FUNCTION
	HRR	M,T1		;GET ADDRESS IN M
	HLRZ	T2,T1		;GET FUNCTION, BITS IN T2
	TRZ	T2,(SC.WRT)	;CLEAR WRITE BIT (MUST BE SIGN BIT)
	CAILE	T2,SCDFMX	;OVER MAXIMUM FUNCTION?
	JRST	SCHFNE		;YES, FUNCTION NUMBER ERROR
	MOVE	T4,LNCSFM	;LEGAL NON-CLASS SCHED. FUNCTION MASK
	LSH	T4,0(T2)		;POSITION FLAG AS SIGN BIT
	SKIPN	TYPSCD		;CLASSES ENABLED? ALL FUNCTIONS LEGAL
	JUMPGE	T4,SCHNSS	;IF CLASS FUNCTION AND CLASSES DISABLED
	MOVE	T3,SCDDIS(T2)	;ASSUME WRITE OPERATION
	JUMPL	T1,.+2		;TEST WRITE BIT
	MOVSS	T3		;FUNCTION IS REALLY READ.
	PUSHJ	P,(T3)		;DISPATCH TO ROUTINE
	  POPJ	P,		;ERROR - CODE IS STORED IN USER AC
	AOBJN	P1,SCHDU1	;CONTINUE FOR ALL FUNCTIONS
	JRST	CPOPJ1		;FINISHED. RETURN SUCCESSFULLY

;DISPATCH TABLE.  LEFT HALF IS ADDRESS OF READ PART OF FUNCTION,
; RIGHT HALF IS ADDRESS OF WRITE PART.

SCDDIS:	XWD	SCHRSI,SCHWSI	;(0)READ/SET SCHEDULING INTERVAL
	XWD	SCHRMI,SCHWMI	;(1)READ/SET MCU INTERVAL
	XWD	SCHRQT,SCHWQT	;(2)READ/SET CLASS QUOTAS AND FLAGS
	XWD	SCHRTS,SCHWTS	;(3)READ/SET TIME SLICES FOR PQ1 AND PQ2
	XWD	SCHRDC,SCHWDC	;(4)READ/SET DCUF
	XWD	SCHRJC,SCHWJC	;(5)READ/SET JOB'S CLASS
	XWD	SCHRMC,SCHWMC	;(6)READ/SET PROT0 (MCU CONSTANT)
	XWD	SCHRCT,SCHFNE	;(7)READ QUOTAS USED FOR EACH CLASS SINCE STARTUP
	XWD	SCHREF,SCHWEF	;(10)READ/SET EXPONENTIAL FACTOR
	XWD	SCHRPF,SCHWPF	;(11)READ/SET MCU MULTIPLIER (PROT)
	XWD	SCHRCD,SCHWCD	;(12)READ/SET NEW JOBS' DEFAULT CLASS
	XWD	SCHRSC,SCHWSC	;(13)READ/SET SWAPPABLE CYCLING TIME

	SCDFMX==.-SCDDIS-1	;MAXIMUM FUNCTION NUMBER

;DEFINE BIT TABLE OF LEGAL FUNCTIONS IN NON CLASS SCHEDULER
LNCSFM:	EXP	1B3!1B4!1B6!1B<^O11>!1B<^O13>
;ROUTINES TO PERFORM SCHED. UUO FUNCTIONS. CALLED FROM SCHED. UUO
; WITH M SET TO ADDRESS OF BLOCK. THESE ROUTINES PRESERVE P1-P4, USE
; T1,T2,T3,T4

;FUNCTION 0
;READ/SET SCHEDULING INTERVAL
; READ FUNCTION RETURNS INTERVAL VALUE AT LOCATION BLOCK
; FORMAT OF ARGUMENT BLOCK ON WRITE:
; WARNING: NOT RESPONSIBLE FOR EFFECTS ON QUOTA ENFORCEMENT IF MEDIUM
; TERM SCHEDULING INTERNAL IS CHANGED FROM ONE NON-ZERO VALUE TO ANOTHER
; NON-ZERO VALUE.
;
; BLOCK:	<DESIRED VALUE>

SCHRSI:	MOVE	T1,SCDINT##	;GET INTERVAL
	JRST	SCHPVL		;

SCHWSI:	PUSHJ	P,SCHGET	;GET ARGUMENT FROM ADDRESS IN M
	MOVEM	T1,SCDINT	;USE AS SCHEDULING INTERVAL
	MOVEM	T1,UTMEAR##	;USE THIS AS START FOR EXPONENTIALLY AVERAGED
				;USER TIME (WILL DECREASE, BUT THIS IS
				;CLOSER THAN ZERO
	JUMPN	T1,SCHWS2	;IF NOT TURNING OFF CLASSES, SKIP THIS NEXT STUFF
	MOVEI	T2,M.CLSN##	;GET NUMBER OF CLASSES = LENGTH OF CLSSTS
	SETZM	CLSQTA##	;CLEAR QUOTA WORDS THAT SQ FOR LOOKS AT
	MOVE	T1,[CLSQTA,,CLSQTA+1]
	BLT	T1,CLSQTA-1(T2)
	SETZM	RRFLAG##	;NO MORE CLASSES WITH QUOTA NOW
	SETZM	CLSEAR##	;CLEAR OUT EXPONENTIAL AVERAGES TOO.
	MOVE	T1,[CLSEAR,,CLSEAR+1]
	BLT	T1,CLSEAR-1(T2)
	SETZM	CLSSTS##	;CLEAR FIRST WORD AS USUAL
	MOVE	T1,[CLSSTS##,,CLSSTS##+1] ;BLT POINTER TO CLEAR
	BLT	T1,CLSSTS##-1(T2)	;CLEAR TO LAST WORD

;NOW TURN OFF ALL FIXED QUOTA BITS FOR JOBS IN THEIR JBTSCD ENTRY,
; SINCE THATS WHAT QSCAN LOOKS AT.

	MOVE	J,HIGHJB	;HIGHEST JOB TO WORRY ABOUT (CLRJBT TAKES CARE OF THE REST)
	MOVSI	T2,(JS.FXC)	;THE BIT
SCHWS1:	ANDCAM	T2,JBTSCD##(J)	;CLEAR IT
	SOJG	J,SCHWS1	;FOR ALL JOBS

SCHWS2:	SETZM	SCDTIM##	;FORCE NEW SCHEDULING INTERVAL
	JRST	CPOPJ1##	;GIVE GOOD RETURN

;FUNCTION 1
;
;HERE TO READ MCU INTERVAL
; FORMAT OF BLOCK SAME AS THAT FOR SCHEDULING INTERVAL FUNCTION
;

SCHRMI:	MOVE	T1,MCUINT##	;GET MCU INTERVAL
SCHPVL:	PUSHJ	P,PUTWRD##	;SEND TO USER
	  JRST	SCHAER		;ADDRESS PROBLEM...
	JRST	CPOPJ1		;OK

SCHWMI:	PUSHJ	P,SCHGET	;GET ARG
	MOVEM	T1,MCUINT##	;STORE
	SETZM	MCUTIM##	;FORCE NEW MCU CALCULATION RIGHT AWAY
	JRST	CPOPJ1
;FUNCTION 2
;
;HERE TO READ CLASS QUOTAS
; ARGUMENT BLOCK SETUP FOR READ CLASS QUOTA FUNCTION:
;
; BLOCK:	N		;NUMBER OF CLASSES TO READ QUOTAS OF
; BLOCK+1:			;QUOTA AND BITS OF CLASS 0 RETURNED HERE
; BLOCK+2:			;QUOTA AND BITS OF CLASS 1 RETURNED HERE
;		.
; BLOCK+N:			;QUOTA AND BITS OF CLASS N-1 RETURNED HERE
;

SCHRQT:	PUSHJ	P,SCHGET	;GET NUMBER OF CLASSES TO RETURN
	SKIPLE	T1		;TOO LOW OR
	CAILE	T1,M.CLSN##	;TOO HIGH?
	JRST	SCHCLE		;YES, TELL HIM SO
	MOVN	T4,T1		;GET AN AOBJN POINTER
	HRLZS	T4
SCHRQ1:	MOVE	T1,CLSSTS##(T4)	;GET QUOTA, BITS FOR CLASS
	JSP	T2,SCHBLK	;STORE WORD
	JRST	SCHRQ1		;LOOP FOR MORE

;HERE TO SET QUOTAS FOR CLASS
;
; FORMAT OF BLOCK:
;
; BLOCK:	N		;NUMBER OF WORDS FOLLOWING
; BLOCK+1:	XWD <BITS>+CLASS,QUOTA
; BLOCK+2:	XWD <BITS>+CLASS,QUOTA
;		.
; BLOCK+N:	XWD <BITS>+CLASS,QUOTA
;

SCHWQT:	PUSHJ	P,SCHGET	;GET NUMBER OF ARGS
	JUMPLE	T1,CPOPJ1	;DONE IF LE ZERO
	MOVE	T4,T1		;SAVE IN T4
SCHWQ1:	PUSHJ	P,SCHGT1	;GET ARG
	LDB	T3,[POINT 5,T1,17] ;GET CLASS
	CAIL	T3,M.CLSN##	;TOO HIGH?
	JRST	SCHCLE		;YES, REPORT IT.
	TLZ	T1,(JS.CLS)	;CLEAR CLASS PART OF ARG
	HRRZM	T1,CLSEAR##(T3)	;SAVE QUOTA AS START FOR NEW EXP. AUG.
	EXCH	T1,CLSSTS##(T3)	;AND SAVE QUOTA AND BITS
	XOR	T1,CLSSTS##(T3)	;SEE IF FIXED QUOTA BIT HAS CHANGED
	JUMPGE	T1,SCHWQ4	;NO. (THIS CHECK DEPENDS ON SIGN BITS
				; BEING THE FLAGS FOR BOTH WORDS)
	MOVSI	F,(JS.FXC)	;OH WELL, HAVE TO LOOP THRU ALL JOBS
	MOVE	W,[ANDCAM F,JBTSCD##(J)] ;ASSUME IT'S NOT FIXED
	SKIPGE	CLSSTS##(T3)	;IS IT REALLY NOT FIXED?
	MOVE	W,[IORM F,JBTSCD##(J)] ;IT'S FIXED
	MOVE	J,HIGHJB	;HIGHEST JOB

SCHWQ2:	LDB	T2,JBYCLS##	;GET CLASS NUMBER
	CAMN	T2,T3		;SAME AS CLASS WE'VE CHANGED FIXED BIT ON?
	XCT	W		;YES, THEN DO THE INSTRUCTION
SCHWQ3:	SOJG	J,SCHWQ2	;AND LOOP FOR ALL JOBS
SCHWQ4:	SOJG	T4,SCHWQ1	;AND LOOP UNTIL DONE.
	MOVEI	T2,M.CLSN##-1	;COMPUTE END ADDRESS
	MOVE	T1,[CLSRTM##,,CLSRTM##+1]
	CONO	PI,PIOFF##	;DON'T INTERRUPT US
	SETZM	CLSRTM##	;CLEAR CLSRTM
	BLT	T1,CLSRTM##(T2)
	SETZM	RTCTOT##	;CLEAR USER TIME SINCE WE LAST DID THIS
	CONO	PI,PION##	;PI BACK ON
	JRST	CPOPJ1		;GOOD RETURN.
;FUNCTION 4
;
;HERE TO READ DESIRED CHANNEL USAGE FRACTIONS (DCUF)
; FORMAT OF BLOCK:
;
; BLOCK:	N		;NUMBER OF CHANNELS TO READ DCUF OF, STARTING
				;WITH CHANNEL 0
; BLOCK+1:			;CHANNEL 0 DCUF RETURNED HERE
; BLOCK+2:			;CHANNEL 1 DCUF RETURNED HERE
;		.
; BLOCK+N:			;CHANNEL N-1 DCUF RETURNED HERE
;

SCHRDC:	PUSHJ	P,SCHGET	;GET NUMBER OF CHANNELS TO READ
	SKIPLE	T1		;NEGATIVE OR
	CAILE	T1,M.CHN##	;TOO HIGH?
	JRST	SCHCNE		;YES, ERROR.
	MOVN	T4,T1
	HRLZS	T4		;MAKE AOBJN POINTER
SCHRD1:	MOVE	T1,.GTDCF##(T4)	;GET FRACTION
	JSP	T2,SCHBLK
	JRST	SCHRD1

;HERE TO WRITE SELECTED DCUFS
; FORMAT OF BLOCK:
;
; BLOCK:	N		;NUMBER OF WORDS FOLLOWING
; BLOCK+1:	XWD CHANNEL,PERCENT 
; BLOCK+2:	XWD CHANNEL,PERCENT
;		.
; BLOCK+N:	XWD CHANNEL,PERCENT
;

SCHWDC:	PUSHJ	P,SCHGET	;GET NUMBER OF WORDS FOLLOWING
	JUMPLE	T1,CPOPJ1	;DONE IF LE ZERO
	MOVE	T4,T1		;COPY
SCHWD1:	PUSHJ	P,SCHGT1
	HLRZ	T2,T1		;GET CHANNEL NUMBER IN T2
	CAIL	T2,M.CHN##	;LEGAL?
	JRST	SCHCNE		;NO
	HRRZM	T1,.GTDCF##(T2)	;STORE
	SOJG	T4,SCHWD1	;AND LOOP.
	JRST	CPOPJ1		;DONE.
;FUNCTION 3
;
;HERE TO READ TIME SLICES FOR EITHER PQ1 OR PQ2
; FORMAT OF BLOCK:
;
; BLOCK:	N		;NUMBER OF QUEUES TO READ TIME SLICES FOR
;				;(CAN ONLY BE 1 OR 2)
; BLOCK+1:			;TIME SLICE FOR PQ1 RETURNED HERE
; BLOCK+2:			;TIME SLICE FOR PQ2 RETURNED HERE
;				;(IF N WAS BIG ENOUGH)
;

SCHRTS:	PUSHJ	P,SCHGET	;GET N
	SKIPLE	T1
	CAILE	T1,2		;LEGAL ARG?
	JRST	SCHQNE		;NO
	MOVN	T4,T1
	HRLZS	T4		;AOBJN POINTER
SCHRT1:	MOVE	T1,QADTAB##(T4)	;GET SLICE
	IMULI	T1,^D1000	;MILLITICKS
	IDIV	T1,TICSEC##	;CONVERT TO MILLISECS
	JSP	T2,SCHBLK
	JRST	SCHRT1


;HERE TO WRITE TIME SLICES FOR PQ1 OR PQ2
; FORMAT OF BLOCK:
;
; BLOCK:	N		;NUMBER OF WORDS FOLLOWING
; BLOCK+1:	XWD Q#,TIME SLICE(MS)
; BLOCK+2:	XWD Q#,TIME SLICE(MS)
;		.
; BLOCK+N:	XWD Q#,TIME SLICE
;

SCHWTS:	PUSHJ	P,SCHGET	;GET N
	JUMPLE	T1,CPOPJ1	;DONE IF LE ZERO
	MOVE	T4,T1		;COPY N
SCHWT1:	PUSHJ	P,SCHGT1	;GET ARG
	MOVE	T2,TICSEC##	;GET JIFSEC
	IMULI	T2,(T1)		;GET MILLITICS IN T2
	IDIVI	T2,^D1000	;CONVERT TO TICKS (ARG WAS IN MS)
	HLRZ	T3,T1		;GET Q NUMBER
	SKIPE	T3		;ZERO IS NOT LEGAL
	CAILE	T3,2		;LEGAL?
	JRST	SCHQNE		;NO, Q NUMBER ERROR
	MOVEM	T2,QADTAB##-1(T3);SAVE
	SOJG	T4,SCHWT1	;AND LOOP
	JRST	CPOPJ1		;FINISHED.
;FUNCTION 5
;
;HERE TO READ CLASS NUMBERS FOR ALL JOBS ON THE SYSTEM UP TO
; THE NUMBER IN ADDRESS
; FORMAT OF BLOCK:
;
; BLOCK:	N		;NUMBER OFJOBS TO READ CLASS FOR
; BLOCK+1:			;RETURN CLASS OF JOB 1 HERE
; BLOCK+2:			;RETURN CLASS OF JOB 2 HERE
;		.
; BLOCK+N:			;RETURN CLASS OF JOB N HERE
;

SCHRJC:	PUSHJ	P,SCHGET	;GET NUMBER OF JOBS TO DO
	PUSHJ	P,LGLPRC##	;IS THIS A LEGAL JOB NUMBER?
	  JRST	SCHBJN		;NO
	MOVN	T4,T1
	HRLZS	T4
	AOS	T4		;START WITH JOB 1
SCHRJ1:	LDB	T1,JBYCL4##	;GET CLASS
	JSP	T2,SCHBLK
	JRST	SCHRJ1

;HERE TO PUT A JOB INTO A CPU CLASS
; FORMAT OF BLOCK:
;
; BLOCK:	N		;NUMBER OF WORDS FOLLOWING
; BLOCK+1:	XWD JOB,CLASS
; BLOCK+2:	XWD JOB,CLASS
;		.
; BLOCK+N:	XWD JOB,CLASS
;

SCHWJC:	PUSHJ	P,SCHGET	;GET N
	JUMPLE	T1,CPOPJ1	;RETURN IF NO WORK TO DO
	MOVE	T4,T1		;COPY N
SCHWJ1:	PUSHJ	P,SCHGT1	;
	HRRZ	T2,T1		;SAVE CLASS NUMBER IN T2
	HLRZS	T1		;GET JOB NUMBER IN RHOF T1 FOR LGLPRC
	CAIN	T1,-1		;US?
	MOVE	T1,J		;YES, USE OUR JOB NUMBER
	PUSHJ	P,LGLPRC##	;LEGAL JOB NUMBER?
	  JRST	SCHBJN		;NO
	MOVSI	T3,JNA
	TDNN	T3,JBTSTS##(T1)
	  JRST	SCHBJN		;NO GOOD IF JOB NOT ASSIGNED
	CAIL	T2,M.CLSN##	;BAD CLASS NUMBER?
	JRST	SCHCLE		;YES.
	MOVSI	T3,(JS.FXC)	;FIXED CLASS BIT (MUST BE SIGN BIT)
	MOVE	F,[ANDCAM T3,JBTSCD##(T1)] ;ASSUME NEW CLASS NOT FIXED QUOTA
	SKIPGE	CLSSTS##(T2)	;IS HIS NEW CLASS FIXED QUOTA?
	MOVE	F,[IORM T3,JBTSCD##(T1)] ;ITS FIXED
	XCT	F		;DO THE PROPER THING TO THE BIT
	DPB	T2,JBYCL1##	;DEPOSIT
	LDB	T3,PJ2ST1##	;GET Q NUMBER OF JOB IN T1
	CAIE	T3,PQ2		;IF IN PQ2, REQUEUE
	JRST	SCHWJ2		;NOT IN PQ2
	PUSH	P,J		;SAVE OUR JOB NUMBER
	MOVE	J,T1		;GET TARGET JOB IN J
	PUSHJ	P,REQUE##	;REQUEUE HIM SO HE WILL WIND UP IN PROPER SUBQUE
	POP	P,J
SCHWJ2:	SOJG	T4,SCHWJ1		;AND LOOP FOR NEXT SPEC.
	JRST	CPOPJ1
;FUNCTION 6
;
;HERE TO READ MCU CONSTANT (PROT0)
; FORMAT OF BLOCK
;
; BLOCK:			;PROT0 RETURNED HERE
;

SCHRMC:	MOVE	T1,PROT0##
	PJRST	SCHPVL		;STORE VALUE IN USERS AREA AND RETURN

;HERE TO WRITE MCU CONSTANT (PROT0)
; FORMAT OF BLOCK:
;
; BLOCK:	<DESIRED VALUE OF PROT0>

SCHWMC:	PUSHJ	P,SCHGET
	MOVEM	T1,PROT0##
	JRST	CPOPJ1

;FUNCTION 7
;
;HERE TO READ TIME SINCE SYSTEM STARTUP EACH CLASS HAS USED.
; FORMAT OF BLOCK
;
; BLOCK:	N		;NUMBER OF CLASSES TO READ RUNTIMES FOR
; BLOCK+1:			;CLASS 0 RUNTIME RETURNED HERE
; BLOCK+2:			;CLASS 1 RUNTIME RETURNED HERE
;		.
; BLOCK+N:			;CLASS N-1 RUNTIME RETURNED HERE
;

SCHRCT:	PUSHJ	P,SCHGET
	SKIPLE	T1		;BOMB IF OUT OF RANGE
	CAILE	T1,M.CLSN##
	JRST	SCHCLE
	MOVN	T4,T1
	HRLZS	T4
SCHRC1:	MOVE	T1,CLSRTM##(T4)	;GET TIME
	JSP	T2,SCHBLK
	JRST	SCHRC1

;FUNCTION 10
;
;HERE TO READ EXPONENTIAL FACTOR USED IN KEEPING CLSEAR
; FORMAT OF BLOCK:
;
; BLOCK:			;RETURN VALUE HERE

SCHREF:	MOVE	T1,SCDEXF##	;GET VALUE
	PJRST	SCHPVL		;PUT INTO USERS AREA AND RETURN


;HERE TO WRITE EXPONENTIAL FACTOR. VALUE MUST BE BETWEEN
; ZERO AND 10000., SINCE THE FACTOR IS A SCALED FRACTION
; WITH THE SCALE FACTOR BEING 10000.
;
; FORMAT OF BLOCK:
;
; BLOCK:	<DESIRED VALUE>

SCHWEF:	PUSHJ	P,SCHGET	;GET DESIRED VALUE
	JUMPL	T1,SCHBFE
	CAILE	T1,^D10000	
	JRST	SCHBFE		;BAD VALUE
	MOVEM	T1,SCDEXF##	;SAVE
	JRST	CPOPJ1		;AND GIVE GOOD RETURN
;FUNCTION 11
;
;HERE TO READ VALUE OF PROT (MCU MULTIPLIER) WHICH CAN BE SET EITHER
; BY THE MCU ALGORITHM OR MANUALLY (BUT NOT BOTH).
;
; FORMAT OF BLOCK:
;
; BLOCK:			;RETURN VALUE HERE
;

SCHRPF:	MOVE	T1,PROT##	;GET DESIRED VALUE
	PJRST	SCHPVL		;STORE AND RETURN


;HERE TO WRITE PROT "MANUALLY", MEANING WITHOUT THE MCU
; CALCULATOR OPERATING.  IF MCUINT IS NONZERO, AN ERROR RETURN IS GIVEN.
;
; FORMAT OF BLOCK:
;
; BLOCK:	<DESIRED VALUE OF PROT>

SCHWPF:	SKIPE	MCUINT##	;IS MCUINT ZERO?
	JRST	SCHMIS		;NO, PROT WOULD HAVE BEEN OVERWRITTEN ANYWAY
	PUSHJ	P,SCHGET	;YES, GET DESIRED VALUE
	MOVEM	T1,PROT##	;SAVE DESIRED VALUE (IN MICROSECS)
	PJRST	CPOPJ1		;AND RETURN WELL.

;FUNCTION 12
;
;HERE TO READ VALUE OF DEFAULT CLASS FOR NEW JOBS
;
; FORMAT OF BLOCK:
;
; BLOCK:			;RETURN VALUE HERE
;

SCHRCD:	MOVE	T1,DEFCLS##	;GET DEFAULT CLASS
	ANDI	T1,37		;JUST CLASS BITS, NO OTHER GARBAGE
	PJRST	SCHPVL		;STORE VALUE AND RETURN

;HERE TO WRITE THE DEFAULT CLASS OF NEW JOBS
;
; FORMAT OF BLOCK:
;
; BLOCK:	<DESIRED VALUE OF DEFALT CLASS, BITS 31-35>
;

SCHWCD:	PUSHJ	P,SCHGET	;GET ARG
	CAIL	T1,M.CLSN##	;IS IT A LEGAL CLASS?
	JRST	SCHCLE		;NO, GIVE ILLEGAL CLASS NUMBER ERROR
	MOVEM	T1,DEFCLS##	;STORE
	PJRST	CPOPJ1##	;AND GIVE GOOD RETURN
;FUNCTION 13
;
;HERE TO READ SWAPPABLE CYCLING TIME, WHICH CONTROLS THE RATE
; AT WHICH SWAPPABLE JOBS IN CORE GET REQUEUED IF THEY HAVEN'T
; USED UP THEIR QUANTUM RUN TIME.
;
; FORMAT OF BLOCK:
;
; BLOCK:			;RETURN VALUE HERE

SCHRSC:	MOVE	T1,PROT1##	;GET THE VALUE
	PJRST	SCHPVL		;STORE AND RETURN


;HERE TO WRITE THE SWAPPABLE CYCLING TIME PARAMETER
;
; FORMAT OF BLOCK:
;
; BLOCK		<DESIRED VALUE OF SWAPPABLE CYCLING TIME>
;

SCHWSC:	PUSHJ	P,SCHGET	;GET THE VALUE
	MOVEM	T1,PROT1##
	PJRST	CPOPJ1##	;JUST CHANGE IT.
;GET A WORD FROM USER (ERROR CODE 1 IF BAD ADDRESS)
SCHGT1:	HRRI	M,1(M)
SCHGET:	PUSHJ	P,GETWRD##	;GET WORD
	JRST	[POP	P,(P)	;ADDRESS CHECK
		 JRST	SCHAER]
	POPJ	P,0		;GOT IT

;SUBROUTINE TO STORE A WORD INTO A BLOCK
;CALL WITH:
;	T1 = WORD
;	M = ADDRESS
;	T4 = AOBJN WORD
;	JSP	T2,SCHBLK
;	RETURN HERE IF MORE
SCHBLK:	PUSHJ	P,PUTWR1##
	  JRST	SCHAER
	AOBJP	T4,CPOPJ1##
	JRST	(T2)
;ERROR RETURNS
	ERCODE	SCHAER,SCHAC%	;(1) ADDRESS CHECK ERROR
	ERCODE	SCHFNE,SCHUF%	;(2) BAD FUNCTION NUMBER
	ERCODE	SCHBJN,SCHUJ%	;(3) BAD JOB NUMBER
	ERCODE	SCHNPE,SCHNP%	;(4) NO PRIVELEGES
	ERCODE	SCHCLE,SCHUC%	;(5) BAD CLASS NUMBER
	ERCODE	SCHQNE,SCHUQ%	;(6) BAD QUEUE NUMBER
	ERCODE	SCHCNE,SCHNC%	;(7) BAD CHANNEL NUMBER
	ERCODE	SCHBFE,SCHEB%	;(10) BAD EXPONENTIAL FACTOR VALUE
	ERCODE	SCHMIS,SCHMI%	;(11) ATTEMPT TO SET PROT WHILE MCUINT NON ZERO.
	ERCODE	SCHNSS,SCHNS%	;(12) NOT SUBQUE SCHEDULER

>;END IFN FTNSCHED
SUBTTL MEDIUM TERM SCHEDULING INTERVAL ROUTINES

IFN FTNSCHED,<
;HERE EVERY MEDIUM TERM SCHEDULING INTERVAL TO MAINTAIN
; THE EXPONENTIALLY AVERAGED RUNTIMES FOR EACH CLASS
; AND VARIOUS OTHER DATA ABOUT QUOTAS.
;THIS ROUTINE COMPUTES THE EXPONENTIAL AVERAGING FORMULA
; (1-ALPHA)*LAST AVERAGE+(ALPHA)*INCREMENT.  THE FORMULA
; ACTUALLY USED IN THE ROUTINE USES SCALED ARITHMETIC,
; WHERE ALPHA IS EXPRESSED IN UNITS OF 1/10000. THS,
; AND FOR EASE OF COMPUTATION USES THE FORMULA
; (SF*CLSEAR+ALPHA(CLSITM-CLSEAR))/SF
; WHERE SF IS THE SCALE FACTOR 10000.
;
;CLSQTA, THE REAL QUOTA WHICH SQFOR USES WHEN SCANNING FOR JOBS,
; IS COMPUTED VIA THE FORMULA
;	CLSQTA = CLSSTS + (CLSSTS-CLSEAR)
;	       = 2* CLSQTA - CLSEAR
;
;
;SCDQTA USES AC'S T1,T2,T4.

SCDQTA::SKIPN	T1,SCDINT##	;ANY INTERVAL AT ALL?
	POPJ	P,		;NO, DON'T DO ANYTHING
	MOVE	T2,UPTIME##	;GET UPTIME
	CAMGE	T2,SCDTIM##	;IS IT TIME FOR ANOTHER SCHED INTERVAL?
	POPJ	P,		;NO, RETURN
	ADD	T1,T2		;GET NEXT UPTIME FOR INTERVAL
	MOVEM	T1,SCDTIM##	;SAVE
	SETZM	RRFLAG##	;CLEARCOUNT OF SUBQUEUES WITH
				;NONZERO QUOTA


;HERE TO COMPUTE THE VALUE OF UTMEAR, THE EXPONENTIALLY AVERAGED
; VALUE OF THE NUMBER OF JIFFIES OF USER TIME WE HAVE GIVEN AWAY
; PER SCHEDULING INTERVAL.  THIS VALUE IS AVAILABLE THROUGH GETTAB.
; IT IS COMPUTED USING THE SAME FORMULA
; FOR EXPONENTIAL AVERAGING THAT IS USED FOR CLSEAR VALUES.
; THE EXPONENTIAL FACTOR IS THE MONGEN SYMBOL M.UTEF, WHICH ASSUMES
; A DEFAULT VALUE OF .3333 .  THE USE OF THIS NUMBER NOT ONLY MAKES
; QUOTA ENFORCEMENT MORE ACCURATE BY BASING THE QUOTAS ON ACTUAL AVAILABLE
; USER TIME, BUT AUTOMATICALLY COMPENSATES FOR DUAL CPUS AS WELL

;

	SETZ	T1,
	EXCH	T1,TOTUTM##	;GET AND CLEAR USER TIME GIVEN THIS INTERVAL
	MOVE	T2,UTMEAR##	;GET LAST AVERAGE
	SUB	T1,T2
	IMUL	T1,SCDEXF##	;
	IMULI	T2,^D10000	;SCALE FACTOR 10000.
	ADD	T1,T2
	IDIVI	T1,^D10000
	MOVEM	T1,UTMEAR##	;SAVE
;HERE TO COMPUTE QUOTAS AND AVERAGES FROM THE LAST INTERVAL

	MOVEI	T4,M.CLSN##-1	;START WITH HIGHEST CLASS NUMBER
SCDQT1:	SETZ	T1,
	EXCH	T1,CLSITM##(T4)	;GET AND CLEAR TIME USED LAST INTERVAL
	MOVE	T2,CLSEAR##(T4)	;GET LAST AVERAGE
	SUB	T1,T2
	IMUL	T1,SCDEXF##	;MULTIPLY BY ALPHA (SCALED BY 10000.)
	IMULI	T2,^D10000	;SCALE LAST AVERAGE BY 10000.
	ADD	T1,T2		;ADD INTO T1
	IDIVI	T1,^D10000	;GET RID OF SCALE FACTOR
	MOVEM	T1,CLSEAR##(T4)	;SAVE AS NEW AVERAGE
	HRRZ	T2,CLSSTS##(T4)	;GET QUOTA
	IMUL	T2,UTMEAR##	;MULTIPLY BY AVAILABLE TIME
	IDIVI	T2,^D100	;CONVERT TO A JIFFY QUOTA
	LSH	T2,1		;MULTIPLY BY 2
	SUB	T2,T1		;MINUS OUT WHAT WE'VE ALREADY GOT
	MOVEM	T2,CLSQTA##(T4)	;THIS IS THE REAL QUOTA
	JUMPLE	T2,SCDQT2	;IF IT'S POSITIVE
	AOS	RRFLAG##	;INCREMENT COUNT OF CLASSES WITH NONZERO
				;QUOTAS
SCDQT2:	SOJGE	T4,SCDQT1	;LOOP FOR ALL CLASSES
	POPJ	P,		;DONE.
>;END IFN FTNSCHED
SUBTTL MINIMUM CORE UTILIZATION CALCULATION

IFN FTNSCHED,<
;HERE EVERY SECOND TO DETERMINE IF ITS TIME TO CALCULATE
; VALUES FOR PROT BASED ON WHICH SWAPPING UNITS
; WE'RE USING.  IF MCUINT IS ZERO, NO CALCULATIONS ARE MADE.

MCUCAL::SKIPE	T1,MCUINT##	;NON-ZERO INTERVAL SPECIFIED?
	SOSLE	MCUTIM##	;YES, TIME TO EVALUATE?
	POPJ	P,		;NO TO EITHER
	MOVEM	T1,MCUTIM##	;RESTORE MCUTIM FOR NEXT CYCLE
	SETZM	MCUCKS##	;CLEAR OUT DATA CHANNEL K FOR SWAP
	MOVE	T1,[MCUCKS##,,MCUCKS##+1]
	MOVE	T2,CNFCHN##
	BLT	T1,MCUCKS##-1(T2)

	SETZB	P1,P2		;CLEAR OUT P1,P2
	SETZ	T4,		;T4 USED FOR INDEX TO SWPTAB
	SKIPN	U,SWPTAB##(T4)	;GET FIRST NONZERO SWPTAB ENTRY
				;(MIGHT BE MESSED UP)
	AOBJN	T4,.-1		;HAS TO BE AT LEAST ONE, OR ELSE ONCMOD COMPLAINS

;HERE WITH T4 POINTING TO FIRST UNIT IN ASL

MCUCL1:	LDB	T3,UNYKTP##	;GET KONTROLLER TYPE
	MOVE	T3,TYPTAB##(T3)	;GET INDEX INTO TABLES FOR KONTROLLER TYPE
	LDB	T2,UNYUTP##	;UNIT TYPE WITHIN KONTROLLER
	ADD	T3,T2		;GET INDEX INTO UNIT TABLES
	MOVE	T1,MCUALT##(T3)	;GET AVERAGE LATENCY AND SEEK FOR THIS UNIT
	IDIV	T1,AVJSIZ##	;DIVIDE BY AVERAGE JOB SIZE
	ADD	T1,MCUATP##(T3)	;PLUS AVERAGE TIME PER PAGE FOR THIS UNIT
	LDB	T2,UNYK4S##	;GET K FOR SWAPPING FOR THIS UNIT (ALWAYS K)
	LSH	T2,K2PLSH##	;CONVERT TO PAGES
	SUB	T2,UNIFKS##(U)	;GET PAGES OF SWAPPING IN USE
	LDB	T3,UNYSCN##	;GET CHANNEL NUMBER OF THIS UNIT
	ADDM	T2,MCUCKS##(T3)	;INCREMENT SWAP SPACE IN USE FOR THIS CHANNEL
	ADD	P2,T2		;ACCUMULATE TOTAL SWAP SPACE USED
	IMUL	T1,T2		;SWAP SPC USED ON UNIT * EXPECTED SWAP TIME IN T2
	ADD	P1,T1		;ACCUMULATE THIS
	SKIPE	U,SWPTAB##+1(T4)	;ANY MORE UNITS IN ACTIVE SWAPPING LIST?
	AOJA	T4,MCUCL1	;YES,GO DO MORE CALCULATION.

;HERE WHEN THROUGH WITH FIRST PART OF MCU CALCULATION
;P1 HAS ACCUMULATED RESULT OF EXPECTED SWAP TIME * K IN USE ON
;UNIT FOR ALL UNITS IN ACTIVE SWAPPING LIST, P2 HAS TOTAL K (P) IN
;USE FOR ALL UNITS IN ASL IN CASE THE DESIRED CHANNEL USAGE
;FRACTIONS ARE ALL ZERO (MEANING WE MUST DIVIDE BY TOTAL K IN USE.

	
	

	MOVEI	T4,M.CHN##-1	;GET MAXIMUM DF10 NUMBER
	SETZ	T3,		;RESULT WILL BE IN T3
MCUCL2:	MOVE	T1,.GTDCF##(T4)	;GET PERCENTAGE FOR THIS CHANNEL
	IMUL	T1,MCUCKS##(T4)	;MULTIPLY BY SPACE USED ON CHANNEL
	IDIVI	T1,^D100	;* 100 BECAUSE .GTDCF CONTAINS %AGES
	ADD	T3,T1		;ACCUMULATE RESULTS
	SOJGE	T4,MCUCL2	;LOOP FOR ALL CHANNELS
	JUMPN	T3,.+2		;IF NONZERO, OK
	MOVE	T3,P2		;OTHERWISE, USE TOTAL K FOR SWAPPING
				;WHICH IS EQUIVALENT TO ALL DCUFS = 100%
	LSH	P1,1		;*2 (IN, OUT)
;	MOVE	T1,MAXMAX##	;GET MAX USER CORE IN WORDS
;	LSH	T1,W2PLSH##	;CHANGE TO PAGES
;	IMUL	P1,T1
;	SKIPE	T1,AVJSIZ##	;IF NOT COMPUTED YET, USE 1 BY SKIPPING
;	IDIV	P1,T1		;TIMES MULTIPROGRAM LEVEL (AVG # JOBS IN CORE)
	IDIV	P1,T3		;FINAL RESULT OVER DCUF NUMBER
	MOVEM	P1,PROT##	;SAVE
	POPJ	P,		;RETURN
>;END FTNSCHED



	$LIT
SCHEND:	END