Google
 

Trailing-Edge - PDP-10 Archives - de-10-omona-v-mc9 - swpser.mac
There are 6 other files named swpser.mac in the archive. Click here to see a list.
TITLE SWPSER - HANDLES I/O FOR SWAPPER - V11113
SUBTTL	SWPSER   R.KRASIN/AW/CMF/AF/DJB/DAL  08 NOV 77
	SEARCH	F,S
	$RELOC
	$HIGH



;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VSWPSR,11113

ENTRY SWPSER
SWPSER:

INTERN FT2REL,SQIN,SQOUT,ESQREQ
EXTERN CPOPJ,CPOPJ1,JBTCHK,TPOPJ,P2WLSH

;INTERNALS REQUIRED IN SWAP

INTERN SQREQ,SERA,SWPSPC,SQIN,SQOUT
EXTERN FINISH,GET4WD,GIV4WD,JBTSWP,JBYSUN,JBYLKN,SWPUNI,SWAPIO
EXTERN	DODELE
EXTERN UNISLB,UNIFKS,UNISWP,UNIPTR,UNYCFS,UNYK4S

;THIS CODE SERVES AS AN INTERFACE BETWEEN THE SWAPPER (SCHED1) AND
;I/O CODE FOR SWAPPING DEVICES (FILSER)

IFE FTVM,<
;HERE TO PUT A REQUEST IN THE SWAPPING QUEUE. ENTER AT SQIN FOR
;	INPUT, SQOUT FOR OUTPUT
;CALL:	MOVE T2,XWD -NUMBER OF WORDS,FIRST CORE LOCATION (IE IOWD+1)
;	HRRZ T1,DISK BLOCK NUMBER
;	PUSHJ P,SQIN/SQOUT
;	RETURN HERE ALWAYS
;	CONTENTS OF T1,T2,T3,T4,F,U,S LOST

SQIN:	TDZA	S,S		;CLEAR S, INCLUDING IO
SQOUT:	MOVSI	S,IO		;CLEAR S, SET IO
	MOVEM	T1,SERA		;STORE THE BLOCK NUMBER
	MOVEM	T2,SQREQ	;STORE THE IOWD
	MOVEM	T2,ESQREQ	;SAVE IN CASE OF DISK ERROR ON FRAGMENTED JOB
	HRRZ	T1,T2		;T1 = ADDRESS OF FIRST WORD SWAPPED
	CAMGE	T1,SYSSIZ##	;IS IT ABOVE MONITOR?
	STOPCD	.,STOP,S2L,	;SWAP TOO LOW
				;NO--WE ARE ABOUT TO SWAP THE MONITOR
				; STOP HERE TO PRESERVE STATE.
IFN FTPDBS,< ;IF WE SWAP PDB'S
	SKIPGE	SCREQ##		;IS THE SWAPPING CHANNEL FREE?
	JRST	SCGRAB		;YES--GO GET IT
	SKIPN	SCUSER##	;NO--DOES THE MOINTOR OWN IT?
	JRST	SQGO		;YES--FINE. KEEP GOING
SCGRAB:	SETZM	SCUSER##	;FLAG THAT MONITOR HAS THE RESOURCE
	AOSE	SCREQ##		;GO GET THE RESOURCE
	STOPCD	.,STOP,SIB,	;++SWAPPER IS BUSY
> ;END FTPDBS


ERATRY==3	;NUMBER OF TIMES TO READ AND WRITE ON ERRORS

;HERE TO START UP DEVICE WITH SWAPPING REQUEST. THIS ROUTINE
;IS CALLED FROM DISK INTERRUPT SERVICE, AS WELL AS FROM ABOVE.
;IF A SWAPPER REQUEST IS WAITING (SQREQ WILL BE NON-ZERO)

SQGO:	MOVEI	T2,ERATRY
	MOVEM	T2,SERACT
SQGO1:	SETZM	SQLEN		;ZERO AMOUNT TRANSFERRED SO FAR
	MOVE	T2,SQREQ	;*PUT IOWD INTO T2
	MOVSI	T1,200000	;*SET "SWAPPER I/O GOING" FLAG ON
	ORB	T1,SERA		;*
	TRZN	T1,FRGSEG	;*FRAGMENTED ?
	JRST	SQGO2		;*NO, READ IN ENTIRE (OR PART) OF SEG
FRAGIO:	MOVN	T3,SQLEN		;AMOUNT PREVIOUSLY TRANSFERRED
	SUB	T2,T3		;INCREASE CORE ADDRESS BY PREVIOUS WORD COUNT
FRGIO1:	HLRE	T3,(T1)		;NUMBER OF K IN THIS DISK CHUNK
	HRR	T1,(T1)		;SWAPPING ADDRESS FOR THIS DISK CHUNK
	JUMPGE	T3,FRGIO2	;POINTER TO NEW CORE LIST IF NEGATIVE
	MOVEI	T3,377777	;CLEAR OUT ADR (17 BITS)
	ANDCAM	T3,SERA		;
	ORM	T1,SERA		;INSERT NEW ADDRESS
	JRST	FRGIO1		;NOW RETRIEVE ADDRESS
FRGIO2:	LSH	T3,P2WLSH	;CONVERT FROM K TO WORDS
	ADDM	T3,SQLEN	;ADD TO PREVIOUSLY TRANSFERRED AMOUNT
	MOVNS	T3		;-N WORDS
	HLRO	T4,SQREQ
	CAMG	T3,T4		;COMPARE WITH - NUMBER WORDS FOR REST OF SEG
	HRL	T2,T4		;SWAPPER ONLY WANTS TO READ A PORTION OF SEG
				; NOT ALL OF IT (R,RUN,GET,KJOB COMMAND)
	HRLM	T3,T2		;IOWD IN T2
	MOVNS	T3		;+NUMBER OF WORDS FOR THIS NEXT TRANSFER
	HRLZS	T3
	ADDM	T3,SQREQ	;UPDATE LH OF IOWD FOR ENTIRE SEG, SO IT HAS
				; -NUMBER OF WORDS LEFT AFTER THIS TRANSFER IS DONE
	PUSHJ	P,SAVE1##	;P1 AND J MUST BE PRESERVED IN CALLS TO SWPINT
	PUSH	P,J
	PUSHJ	P,SQGO2		;REQUEST NEXT FRAGMENT TO BE TRANSFERRED
	PJRST	JPOPJ##

SQGO2:	MOVEI	F,SWPDDB##	;ADDR OF SWAPPING DDB
IFE FT2SWP,<
	HLRZ	U,SWPUNI
>
IFN FT2SWP,<
	LDB	U,UNZCFS##	;GET INDEX OF THIS UNIT
	MOVE	U,SWPTAB##(U)	;GET ADDR OF THIS UNIT
>
	LDB	T1,UNZFKS##	;GET 1ST LOGICAL K IN SWAPPING AREA
	ROT	T1,BLKSPP##	;CONVERT TO BLOCKS
	ADD	T1,UNISLB(U)	;AND TO LOGICAL BLOCK NUMBER
	TRZ	S,IODTER!IODERR!IOIMPM!IOBKTL!IOCHMP!IOCHNX	;MAKE SURE NO ERROR BITS.
	SOJA	T2,SWAPIO	;MAKE T2 AN IOWD AND PUT IN IO QUEUE
;HERE TO SERVICE A SWAPPING INTERRUPT
; S WILL HAVE IO+IOSMON+ERROR BITS SET UP
; U WILL CONTAIN THE ADDRESS OF THE UNIT
; P4 WILL CONTAIN THE NUMBER OF BLOCKS TRANSFERRED

EXTERNAL MBKLSH,UNIICT,UNIOCT
INTERNAL SWPINT

SWPINT:	TLNE	S,IO		;READING
	ADDM	P4,UNIOCT(U)	;NO, COUNT BLOCKS WRITTEN
	TLNN	S,IO		;READING
	ADDM	P4,UNIICT(U)	;YES, COUNT BLOCKS READ
	TRNE	S,IODTER!IODERR!IOIMPM	;ANY ERRORS?
	JRST	SWPDON		;YES, (MAY INCLUDE IOCHNX AND IOCHMP)
	MOVE	T2,P4		;NUMBER OF BLOCKS TRANSFERRED
	HRLS	T2
	LSH	T2,BLKLSH##	;CONVERT TO WORDS
	ADD	T2,SWPDMP##	;UPDATE IOWD
	JUMPGE	T2,SWPIN1	;FINISHED IF POSITIVE
	MOVE	T1,P4		;NOT THROUGH - STOPPED AT END OF CYLINDER
	ADDB	T1,SWPBLK##	;UPDATE BLOCK NUMBER (T2 HAS NEW IOWD)
	PJRST	SWAPIO		;GO QUEUE THE NEXT CHUNK

SWPIN1:	MOVE	T1,SERA		;* GET BITS+FRAGMENT POINTER
	TRZE	T1,FRGSEG	;*FRAGMENTED ?
	SKIPL	T2,SQREQ	;*YES, MORE IOWD TO GO ?
	JRST	SWPDON		;NO, ALL DONE SWAP IN OR OUT
	AOS	SERA		;YES, FRAGMENTED AND MORE TO GO
	SKIPE	1(T1)		;IS THIS THE END OF SWAP COMMAND LIST ?
	AOJA	T1,FRAGIO	;NO, BO DO NEXT PIECE OF FRAGMENTED SEG

SWPDON:	
IFN FTPDBS,< ;IF WE SWAP PDB'S
	SKIPE	SCUSER##	;MONITOR I/O
	JRST	[SETZM SQREQ	;NO--UUO CAUSED THIS SWAP
		 POPJ  P,]	;DISMISS INTERUPT
	MOVE	J,FINISH
> ; END FTPDBS
IFE FTPDBS,<
	MOVM	J,FINISH
>
	MOVE	T1,ESQREQ	;FIRST ADR SWAPPED IN OR OUT
IFN FTKI10!FTKL10,<
	PUSHJ	P,GETCHK##	;MAKE FIRST WORD OF THE SEGMENT ADDRESSABLE
				; ADDRESS RETURNED IN T1
>;END IFN FTKI10!FTKL10
	MOVE	T1,(T1)		;GET CONTENTS
	HLRE	T2,ESQREQ
	MOVNS	T2
	LSH	T2,MBKLSH	;CONVERT TO # OF BLOCKS
	TLNE	S,IO		;READING?
	JRST	[
		MOVEM	T1,JBTCHK(J)	;NO, SAVE CHECKSUM (WRITING)
		JRST	SWPCHK]		;FINISH, DO NOT RETRY ON SWAP OUT ERRS
				; (FILSER ALREADY HAS RETRIED ALL ERRS
				; SWAPPER WILL TRY IN NEW PLACE UNLESS
				; CHANNEL ERROR (IOCHNX!IOCHMP)
	CAMN	T1,JBTCHK(J)	;YES, CORRECT CHECKSUM ?
	JRST	SWPCHK		;YES. EXIT
	TRO	S,IOIMPM	;SET SOFTWARE CHECKSUM ERROR FLAG
	HLRZ	T1,JBTSWP(J)	;*SWAP LOC (DISK ADR OR TABLE ADR)
	HRRM	T1,SERA		;*RESTORE SERA
	MOVE	T1,ESQREQ	;*RESTORE FROM ESQREQ IN CASE OF FRAGMENTED JOB
	MOVEM	T1,SQREQ

;HERE TO CHECK FOR ERRORS BEFORE EXIT FROM INTERFACE
SWPCHK:	TRNE	S,IODTER!IODERR!IOIMPM	;ANY ERRORS?
	TRNE	S,IOCHNX!IOCHMP	;YES, DO NOT RETRY IF CHANNEL NXM OR
				; MEM PARITY (SINCE FILSER HAS ALREADY TRIED
				; AND APR SWEEP WILL CLEAR PARITY)
	JRST	SWPFIN		;NO, DO NOT RETRY
	SOSG	SERACT		;*TRIED ENOUGH ?
	JRST	SWPFIN		;*YES, ERROR
	MOVE	T1,ESQREQ	;*NO, RESET POINTERS (NEEDED IF FRAGMENTED)
	MOVEM	T1,SQREQ
	MOVE	T1,JBTSWP##(J)
	HLRZM	T1,SERA
	JRST	SQGO1		;*TRY AGAIN
SWPFIN:	HRRZM	S,SERA		;CLEAR I/O FLAG,SAVE ERROR BITS
	SETZM	SQREQ		;NO SWAP REQUEST
	PUSHJ	P,STOIOS##	;EXIT INTERRUPT
	PJRST	NJBTST##	;SEE IF THE NULL JOB IS RUNNING AND IF SO
				; CAUSE A CLOCK INTERRUPT

>	;END IFE FTVM
;HERE TO START PAGING/SWAPPING I/O IN A MONITOR WHICH INCLUDES VM
IFN FTVM,<

SQIN::SQOUT::
	MOVEI	F,SWPDDB##	;SWAPPING DDB
	AOS	DEVDMP##(F)	;INSURE DEVDMP NON-ZERO SO ERROR RECOVERY WILL HAPPEN
	DSKOFF			;NO INTERRUPTS HERE
	AOS	T1,SQREQ	;COUNT UP THE NUMBER OF PAGING/SWAPPING I/O REQUESTS
	SOJE	T1,SWAPIO##	;START SWAPPING/PAGING I/O IF NOT ALREADY GOING
	DSKON			;I/O IN PROGRESS, GO AWAY
	POPJ	P,

;HERE WHEN PAGING/SWAPPING I/O IS DONE IN A MONITOR WHICH INCLUDES VM
SWPINT::SOSGE	SQREQ		;COUNT DOWN THE NUMBER OF PAGING/SWAPPING I/O
				; REQUESTS OUTSTANDING
	STOPCD	CPOPJ,DEBUG,SWN,;++SQREQ WENT NEGATIVE
	PUSHJ	P,SAVE2##	;SAVE P1,P2
	MOVE	P2,(P1)		;P2 = THE SWPLST ENTRY
	SUBI	P1,SWPLST##	;P1 = RELATIVE ADDRESS INTO SWPLST OF ENTRY
	HRRZ	J,SW3LST##(P1)	;SEGMENT NUMBER SWAPPING/PAGING IS DONE FOR
	TLNE	P2,(SL.SIO)	;SWAPPING I/O?
	JRST	SWPIN1		;YES
	MOVE	T1,J		;PAGING I/O, JOB NUMBER TO T1 STPIOD
	PUSHJ	P,STPIOD##	;PUT JOB INTO PAGE I/O SATISFIED STATE
	TLNN	P2,(SL.DIO)	;PAGE OUT?
	JRST	[PUSHJ P,ZERSLE## ;NO, RETURN THE DISK SPACE
		JRST	SWPIN3]	;PROCEED
	PUSHJ	P,SVEUB##	;MAKE THE UPMP ADDRESSABLE
	SETOM	.UPMP+.UPPGB	;INDICATE PAGES OUT BUT NOT GIVEN BACK TO
				; FREE CORE YET
	JRST	SWPIN3		;PROCEED
SWPIN1:
	TLNN	P2,(SL.DIO)	;SWAP OUT?
	CAILE	J,JOBMAX##	;NO, HIGH SEGMENT SWAP IN?
	JRST	SWPIN2		;YES, PROCEED
	HRRZ	T2,JBTUPM##(J)	;ADDRESS OF THE PAGE ALLOCATED TO THE UPMP
	SKIPL	T1,SWPLST(P1)	;CANT BE THE UPMP IF FRAG'D
	LDB	T1,[POINT 13,SWPLST(P1),26]
	CAIE	T1,(T2)		;SWAPPING IN THE UPMP?
	JRST	SWPIN2		;NO
	TRO	T1,PM.ACC+PM.WRT+IFN FTKL10,<PM.CSH> ;YES, ACCESSABLE AND WRITABLE
	HLRZ	T2,JBTSWP##(J)	;FIRST PAGE OF THE JOB
	TRO	T2,PM.ACC+PM.WRT+IFN FTKL10,<PM.CSH> ;ALSO ACCESSABLE PLUS WRITABLE
	HRRM	T1,.EPMP##+.MECKS ;MAKE THE UPMP ADDRESSABLE
	CLRPGT	(0)		;FLUSH THE HARDWARE P.T.
	HRLM	T1,.ECKSM+.MUPMP ;MAKE THE UPMP P.T. ADDRESSABLE
	HRRM	T2,.ECKSM+.MJDAT ;AND PAGE 0
	JRST	SWPIN4
SWPIN2:	SKIPGE	JBTSWP##(J)	;RUN OUT OF CORE BLOCKS DURING FRAGMENTED SWAP IN?
	SKIPG	SWPLST##(P1)	;NOT IF NOT FRAGMENTED
	SKIPA	T1,JBTADR##(J)	;NO, ADDRESS OF THE SEGMENT
	JRST	SWPIN4		;YES, SWAP IN NEXT FRAGMENT
	SOSGE	SPRCNT##	;DECREMENT SWAP IN PROGRESS COUNT
	STOPCD	CPOPJ,DEBUG,SNI, ;++SWAPPING NOT IN PROGRESS
	TLNE	P2,(SL.ERR+SL.CHN) ;I/O ERROR?
	JRST	SWPIN3		;YES
	PUSHJ	P,GETCHK##	;MAKE THE CHECKSUM ADDRESSABLE
	MOVE	T1,(T1)		;GET THE CHECKSUM WORD
	TLNE	P2,(SL.DIO)	;SWAPPING OUT?
	JRST	[MOVEM T1,JBTCHK##(J) ;YES, STORE THE CHECKSUM WORD
		JRST SWPIN3]	;AND PROCEED
	MOVSI	T2,(SL.CHK)	;ASSUME AN ERROR OCCURED
	CAME	T1,JBTCHK##(J)	;CHECKSUM THE SAME AS ON THE WAY OUT?
	IORM	T2,SWPLST##(P1)	;NO, INDICATE AN ERROR
SWPIN3:	MOVE	S,DEVIOS(F)	;SWAPPING DDB STATUS
	SKIPN	SQREQ		;STILL MORE SWAPPING OR PAGING I/O TO DO?
	TRZ	S,IOACT		;NO, THE DDB IS NO LONGER I/O ACTIVE
	PUSHJ	P,STOIOS##	;REMEMBER THAT IN THE DDB
	PJRST	NJBTST##	;START THE SCHEDULAR IF THE NULL JOB IS RUNNING


SWPIN4:	PUSHJ	P,SVEUB##	;MAKE JOB ADDRESSABLE
	CAMN	J,.UPMP+.UPJOB	;RIGHT JOB?
	TDZA	P2,P2		;YES
	MOVSI	P2,(SL.CHK)	;NO, SWAP READ ERROR
	IORB	P2,SWPLST##(P1)	;RESTORE P2 WITH POSSIBLE ERROR BIT
	TLNE	P2,(SL.ERR+SL.CHN+SL.CHK) ;I/O ERRORS?
	SOSA	SPRCNT##	;YES, DECREMENT SWAPS IN PROGRESS
	SKIPA	T1,P2		;T1 = THE SWPLST ENTRY
	JRST	SWPIN3		;SET I/O DONE SO ERROR WILL BE NOTICED
	PUSHJ	P,RTNDSP##	;RETURN UPMP DISK SPACE
	PUSHJ	P,DLTSLE##	;DELETE THE SWPLST ENTRY
	PUSHJ	P,BISLST##	;SETUP MEMTAB FOR LOW SEGMENT SWAP IN
	AOS	SQREQ		;ONE MONE SWAPPING REQUEST TO DO
	POPJ	P,		;RETURN TO FILIO

>	;END IFN FTVM
;SUBROUTINE TO FIND SPACE ON SWAPPING DEVICE
;ARG	U=NUMBER 1K BLOCKS NEEDED
;CALL	MOVEI	U,1K BLOCKS NEEDED, PG.SLO=1 IF SWAP IN SLOW SWAP SPACE
;	PUSHJ	P,SWPSPC
;	ERROR RETURN - SPACE NOT AVAILABLE
;	OK RETURN - DEV ADDR STORED IN LH JBTSWP(J) AND IN T1

SWPSPC:	PUSHJ	P,SAVE4##	;SAVE GLOBAL ACS
	MOVE	P2,U		;P2=NUMBER 1K BLOCKS NEEDED
	HLRZ	U,SWPUNI	;GET ADDR OF FIRST UNIT FOR SWAPPING

IFN FTVM,<
	TLZE	P2,(PG.SLO)	;SLOW (DISK) SWAP SPACE WANTED?
	HLRZ	U,SWPUN2##	;YES, GET UNIT OF FIRST SLOW DISK IN ASL
>

IFN FT2SWP,<
;LOOP TO SCAN NEXT CLASS OF SWAPPING UNIT

GT0:	SETZB	P3,T3
	LDB	P1,UNYCFS	;GET CLASS FOR SWAPPING
	HRL	P1,U		;SAVE ADDR OF 1ST UNIT OF THIS CLASS

;LOOP TO SCAN NEXT UNIT IN ACTIVE SWAPPING LIST IN THIS CLASS

GT1:	LDB	T2,UNYCFS	;GET CLASS FOR SWAPPING OF THIS UNIT
	CAIE	T2,(P1)		;SKIP IF STILL SAME CLASS
	JRST	GT4		;NO
>	;END CONDITIONAL ON FT2SWP
	CAMLE	P2,UNIFKS(U)	;SKIP IF ENOUGH ROOM ON THIS UNIT
	JRST	GT3		;FORGET IT FOR NOW
	MOVE	T1,P2		;T1 = NUMBER 1K BLOCKS NEEDED
	PUSHJ	P,GXSAT		;SEE IF CONTIGUOUS SPACE AVAILABLE
	  JRST	GT2		;NO
	JRST	FOUND		;YES

IFN FT2SWP,<
;HERE IF ENOUGH ROOM ON THIS UNIT, BUT NOT CONTIGUOUS

GT2:	CAML	P3,UNIFKS(U)	;SKIP IF THIS UNIT HAS MOST ROOM
	JRST	GT3		;SOMEBODY BETTER IN THIS CLASS
	MOVE	P3,UNIFKS(U)	;REMEMBER SPACE ON BEST UNIT
	MOVE	T3,U		;AND ITS ADDR

;HERE TO CHECK NEXT UNIT IN THIS CLASS

GT3:	HLRZ	U,UNISWP(U)	;NEXT UNIT FOR SWAPPING
	JUMPN	U,GT1		;JUMP IF NOT LAST UNIT FOR SWAPPING

;HERE IF END OF THIS CLASS AND NO UNIT HAD CONTIGUOUS SPACE

GT4:	MOVE	U,T3		;SET U TO ADDR OF UNIT WITH MOST ROOM
	CAMG	P2,P3		;SKIP IF NOT ENOUGH ROOM ON UNIT WITH MOST ROOM
	  JRST	FOUND1		;WE HAVE A WINNER
>	;END CONDITIONAL ON FT2SWP
IFN FT2REL,<
IFN FT2SWP,<
	HLRZ	U,P1		;RESET ADDR OF 1ST UNIT THIS CLASS

;HERE TO SEE IF BY DELETING DORMANT SEGMENTS WE CAN CREATE ENOUGH
;SPACE ON A UNIT IN THE CURRENT CLASS

GT5:	LDB	T1,UNYCFS	;GET CLASS FOR SWAPPING OF THIS UNIT
	CAIE	T1,(P1)		;SEE IF STILL SAME CLASS
	JRST	GT0		;NO
	PUSHJ	P,IFDELE##	;FIND OUT IF BY DELETING DORMANT SEGS CAN DO IT
	  JRST	GT6		;NO
>	;END CONDITIONAL ON FT2SWP
IFE FT2SWP,<
GT3:
GT6==CPOPJ##
>
	PUSHJ	P,DODELE	;RIGHT ON!
	JRST	GT6		;THERE WAS JUST ROOM!

;HERE IF HAD TO DELETE DORMANT SEGMENTS - MAY NOW HAVE CONTIGUOUS SPACE

FOUND2:	MOVE	T1,P2		;T1=1K BLOCKS NEEDED
	PUSHJ	P,GXSAT		;SEE IF CONTIGUOUS SPACE AVAILABLE
	  JRST	FOUND1		;NO
	JRST	FOUND		;YES!

;HERE IF DELETING DORMANT SEGMENTS DOESN'T HELP THIS UNIT

IFN FT2SWP,<
GT6:	HLRZ	U,UNISWP(U)	;TRY NEXT
	JUMPN	U,GT5
>	;END CONDITIONAL ON FT2SWP
>	;END CONDITIONAL ON FT2REL
IFN FT2SWP,<
	HLRZ	U,SWPUNI	;NO GOOD, MUST FRAGMENT ACROSS UNITS
	PUSHJ	P,DODELE	;DELETE ALL DORMANT SEGS ON 1ST UNIT
	  JFCL			;PROBABLY WONT MAKE IT
	JRST	FOUND1		;GET AS MUCH AS POSSIBLE ON THIS UNIT.
				;FOUND1 WILL MOVE TO NEXT UNIT IF NECESSARY
>	;END CONDITIONAL ON FT2SWP
;HERE IF CONTIGUOUS SPACE AVAILABLE ON UNIT WHOSE ADDR IS IN U
;T2  = FIRST LOGICAL J NUMBER, P2=T1=NUMBER NEEDED

FOUND:
IFN FTVM,<
	CAILE	P2,777		;ONLY 9 BITS TO STORE # BLOCKS IN SWPLST
	JRST	FOUND1		;SO FRAGMENT REQUEST IF MORE NEEDED
>
	HRLM	T2,JBTSWP(J)	;STORE LOGICAL K NUMBER OF SWAPPING SPACE
IFE FT2SWP,<
	SETZ	T2,
>
IFN FT2SWP,<
	PUSHJ	P,FNDU		;FIND U IN SWPTAB
>	;END CONDITIONAL ON FT2SWP
	DPB	T2,JBYSUN	;STORE INDEX IN JBTSWP
	LDB	T2,JBYLKN	;T2=1ST LOGICAL K
	PUSHJ	P,MRKALC	;MARK AS ALLOCATED
	JRST	SPCEX		;SET T1 AND OK RETURN FROM SWPSER
;HERE IF ROOM BUT HAVE TO FRAGMENT

IFE FT2SWP,<
GT2:
>
FOUND1:	MOVEI	T2,1
	CAIE	P2,1		;DON'T FRAGMENT IF 1 PAGE
	PUSHJ	P,GET4WD	;GET 4 FREE LOCS
	  POPJ	P,		;CANT - ABORT
IFN FTVM,<
	SETZM	3(T1)		;ENSURE THAT THE LINK-WORD IS 0
>
	MOVE	P3,T1		;P3=ADDR OF CORE BLOCKS
	TRO	T1,FRGSEG	;LIGHT FRAGMENTED BIT
	HRLM	T1,JBTSWP(J)	;STORE POINTER IN JBTSWP
	HRLI	P3,-4		;KEEP POINTER TO FREE CORE
FND12:	MOVE	T3,P2		;T3=SPACE STILL NEEDED
	MOVE	T1,T3
IFN FTVM,<
	CAILE	T1,777		;ONLY GET 777 PAGES IN 1 REQUEST
	MOVEI	T1,777		; SINCE ONLY 9 BITS IN SWPLST
>
IFE FT2SWP,<
	SETZB	T2,P4
>
IFN FT2SWP,<
	PUSHJ	P,FNDU		;FIND U IN SWPTAB
	MOVE	P4,T2		;SAVE INDEX IN P4
>	;END CONDITIONAL ON FT2SWP
FND11:	PUSHJ	P,GXSAT
	  JRST	FND13		;DIDN'T MAKE IT, T1=SPACE AVAILABLE
FND14:	HRLM	T1,(P3)		;AMOUNT ALLOCATED
	HRRM	T2,(P3)		;FIRST LOGICAL K NUM
	PUSHJ	P,MRKALC	;MARK AS ALLOCATED
	DPB	P4,[POINT 3,(P3),22]
	PUSHJ	P,BMPAC3
	SUBB	T3,T1		;DECREMENT AMOUNT NEEDED, PUT IN T1
	JUMPG	T1,FND11	;STILL NEED MORE
	SETZM	(P3)		;END UP WITH A 0
SPCEX:	HLRZ	T1,JBTSWP(J)	;RESET T1 FOR EXIT
	JRST	CPOPJ1

FND13:	JUMPE	T1,NXUN		;JUMP IF NO MORE ROOM THIS UNIT
	PUSHJ	P,GXSAT		;GET THAT MUCH SPACE
	 STOPCD	.,STOP,SSD,	;++SWAP SPACE DISAPPEARED
	JRST	FND14
;HERE IF FILLED CURRENT UNIT AND NEED MORE SPACE
; (ONLY IF FORCED TO FRAGMENT OVER UNITS)

NXUN:
IFN FT2SWP,<
	HLRZ	U,UNISWP(U)	;NEXT SWAPPING UNIT
	SKIPN	U
>	;END CONDITIONAL ON FT2SWP
	STOPCD	.,STOP,SRO,	;STOP IF NO MORE UNITS - SPACE RAN OUT
IFN FT2SWP,<
	MOVE	P2,T3		;P2=NUMBER 1K BLOCKS STILL NEEDED
	PUSHJ	P,DODELE	;DELETE AS MUCH AS YOU CAN
	  JFCL			;MAY NOT BE ENOUGH YET
	JRST	FND12		;RIGHT ON

;SUBROUTINE TO FIND ADDR CONTAINED IN U IN SWPTAB
;ARGS	U=ADDRESS OF A UNIT DATA BLOCK
;CALL	MOVEI	U,ADDR
;	PUSHJ	P,FNDU
;	RETURN - T2 SET UP.  ADDR MUST BE IN THE TABLE
;VALUE	T2=INDEX IN SWPTAB OF UNIT IN U

FNDU:	SETZ	T2,
	CAME	U,SWPTAB##(T2)
	AOJA	T2,.-1
	POPJ	P,
>	;END CONDITIONAL ON FT2SWP
;SUBROUTINE TO MARK BLOCKS ALLOCATED IN A UNIT'S SWAPPING AREA
;ARGS	T1=HOW MANY TO ALLOCATE
;	T2=1ST TO ALLOCATE
;PRESERVES T3,T1

MRKALC:	PUSH	P,T1
	PUSH	P,T3
	SUBM	T1,UNIFKS(U)	;DECREMENT FREE J FOR SWAPPING
	MOVNS	UNIFKS(U)	;COMES OUT NEGATIVE THAT WAY
	IDIVI	T2,^D36		;T2=FULL WORDS, T3=BITS IN PARTIAL WORD
	HRRZ	T4,UNIPTR(U)
	ADD	T4,T2		;COMPUTE ADDR OF 1ST BIT
	MOVEI	T2,^D36
	SUB	T2,T3		;36-POSITION IN WORD=DESIRED QUANTITY
	HRL	T4,T2		; IN LH OF T4
	MOVE	T3,T1		;T3=HOW MANY
	PUSHJ	P,CSETOS	;MARK ONES
	POP	P,T3
	JRST	TPOPJ		;RESTORE T1 AND RETURN

;SUBROUTINE TO STEP P3 TO NEXT LOCATION OF TABLE BEING BUILT


BMPGET:	MOVEI	T2,1
	PUSHJ	P,GET4WD	;GET 4 MORE CELLS
	  JRST	UNDD		;ABORT
IFN FTVM,<
	SETZM	3(T1)		;CLEAR THE LINK-WORD
>
	HRLI	P3,-4
	CAIN	T1,(P3)		;ARE THEY CONTIGUOUS ?
	JRST	BMPACX		;YES, RETURN.
	MOVE	T2,-1(P3)	;NO, CONVERT LAST GOOD LOCATION
	HRROM	T1,-1(P3)	; TO A POINTER TO NEXT PART OF TABLE
	MOVEM	T2,(T1)		;STORE GOOD DATA IN FIRST WORD OF NEW PART
	HRR	P3,T1		;NEW TABLE LOC
	JRST	BMPACL
BMPAC3:	PUSH	P,T1
	PUSH	P,T3
BMPACL:	AOBJP	P3,BMPGET	;COUNT WORD AND RETURN
	JRST	BMPACX

UNDD:	HRRZ	T1,-1(P3)	;RETURN LAST CHUNK OF
	HLRE	U,-1(P3)	; DISK SPACE AND TURN
	SETZM	-1(P3)		; THAT POINTER INTO AN
	PUSHJ	P,FXSAT1	; END OF LIST MARKER
	HLRZ	T1,JBTSWP(J)	;CAN'T COMPLETE SWAP OUT
	PUSHJ	P,FXSAT		;RETURN SWAPPING SPACE
	POP	P,T1		;***THROW AWAY SO THAT EXIT EXITS SWAPPER
BMPACX:	POP	P,T3
	JRST	TPOPJ		;EXIT
INTERNAL GXSAT,FXSAT
EXTERNAL SETZRS,CSETOS,CLGETZ

;SUBROUTINE "GXSAT" IS CALLED TO FIND A SERIES OF CONSECUTIVE FREE BLOCKS ON 
; THE DISK TO SWAP SOME JOB OUT ONTO.  IT IS CALLED AT CLOCK LEVEL.

;ARGS	U=ADDRESS OF UNIT DATA BLOCK TO CHECK
;	T1=NUMBER 1K BLOCK NEEDED
;VALUES	T1=NUMBER 1K BLOCKS CAN ALLOCATE (BIGGEST HOLE IF LESS THAN REQUEST)
;	T2=1ST LOGICAL K NUM IF REQUEST CAN BE SATISFIED
;CALLING SEQUENCE ---
;	MOVEI	T1,1K BLOCKS NEEDED
;	MOVEI	U,ADDR
;	PUSHJ	P,GXSAT
;	ERROR EXIT -- THE DISK IS FULL, NO SWAPPING SPACE AVAILABLE.
;	NORMAL EXIT
;ACCUMULATORS T4, T1, T2 ARE DESTROYED BY THIS SUBROUTINE.

GXSAT:	PUSH	P,T3		;THIS ROUTINE SAVES AND RESTORES ACCUMULATOR "T3".
	MOVE	T3,T1
	MOVE	T1,UNIPTR(U)	;AOBJN POINTER TO SWAPPING SAT TABLES
	SETZ	T2,
IFN FTDHIA&FT2SWP,<
	MOVE	T4,UNIUST##(U)	;IF NO NEW ACCESSES FOR THIS UNIT,
	TLNE	T4,UNPNNA##
	JRST	GXSAT1		;CANT GET ANY SPACE ON IT
>
	PUSHJ	P,CLGETZ	;CALL ROUTINE IN FILSER TO SEARCH FOR 0 BITS
	  JRST	GXSAT1		;NOT ENOUGH
	AOS	-1(P)		;OK, SKIP RETURN
	HRRZ	T1,UNIPTR(U)	;COMPUTE LOGICAL K NUM FROM POSITION IN TABLE
	MOVEI	T2,1(T4)
	SUB	T2,T1		;FULL WORDS FROM BEGINNING OF TABLE+1
	IMULI	T2,^D36		;TIMES 36 BITS
	HLRZ	T1,T4
	SUB	T2,T1		;-POSITION IN WORD
	SKIPA	T1,T3
GXSAT1:	MOVE	T1,T2
	POP	P,T3		;RESTORE T3
	POPJ	P,
;SUBROUTINE "FXSAT" IS CALLED TO RETURN A SERIES OF CONSECUTIVE DISK BLOCKS TO
; THE FREE STORAGE POOL, THUS MAKING THEM AVAILABLE FOR RE-USE IN HANDLING
; FUTURE SWAPPING REQUESTS.  IT IS CALLED AT CLOCK LEVEL.
;CALLING SEQUENCE ---
;	PUSHJ	P,FXSAT
;	NORMAL EXIT
;ENTRY CONDITIONS ---
;	C(T1) = LOGICAL BLOCK NUMBER OF THE FIRST DISK BLOCK IN THE 
;		SERIES WHICH IS TO BE MADE AVAILABLE.
;	C(U) = NUMBER OF CONSECUTIVE 1K BLOCKS OF DISK SPACE WHICH 
;		ARE TO BE MADE AVAILABLE.
;EXIT CONDITIONS ---
;	THE REQUESTED BITS IN THE SWAPPING SPACE AVAILABILITY TABLE  
;		(NAMELY, SWPTAB) HAVE BEEN CLEARED TO ZERO.
;ACCUMULATORS U, T1, T2, ARE DESTROYED BY THIS SUBROUTINE.

EXTERNAL GIV4WD

FXSAT:	TRZN	T1,FRGSEG	;FRAGMENTED ?
	JRST	FXSAT1		;NO, NO HASSLE HERE
	PUSHJ	P,SAVE1##	;SAVE P1
FRAGBK:	HRRZ	P1,T1		;YES, LOC OF TABLE IN P1
FRGBK1:	HRRZ	T1,(P1)		;LOC OF NEXT DISK ADDRESS
	HLRE	U,(P1)		;NUMBER OF K
	JUMPLE	U,FRGBK2	;GIVE UP FREE CORE IF NOT REAL ADDRESS
	PUSHJ	P,FXSAT1	;GIVE UP THE DISK SPACE FOR THIS PART
	AOBJP	P1,FRGBK1	;COUNT WORD OF TABLE, GET NEXT
FRGBK2:	HRRZ	T2,P1		;LOC OF TABLE
	HLRZ	T1,P1		;T1=NUMBER OF WDS IN TABLE
	SUB	T2,T1		;T2=1ST WORD OF BLOCK
	LSH	T1,-2		;T1=NUMBER WORDS-1
	AOS	T1		;CONVERT TO NUMBER OF 4 WORD BLOCKS
	MOVE	P1,(P1)
	PUSHJ	P,GIV4WD	;GIVE UP FREE CORE
	SKIPE	T1,P1		;END OF TABLE ?
	JRST	FRAGBK		;NO, GO CHASE NEXT PART
	POPJ	P,		;YES, DONE

FXSAT1::
	MOVE	T2,U		;T2=NUMBER 1K BLOCKS TO RETURN
IFE FT2SWP,<
	HLRZ	U,SWPUNI	;GET ADDR OF UNIT DATA BLOCK
>
IFN FT2SWP,<
	LDB	U,UNZCFS##	;GET INDEX OF UNIT IN SWPTAB
	MOVE	U,SWPTAB##(U)	;GET ADDR OF UNIT DATA BLOCK
>
	EXCH	T1,T2		;T1=HOW MANY, T2=START LOC
	TRZ	T2,760000	;CLEAR OUT UNIT INDEX
;	PJRST	CSETZS		;CLEAR BITS AND INCREMENT UNIFKS
;SUBROUTINE TO MARK 0'S IN SWAPPING SAT TABLE
;ARGS	T1=HOW MANY
;	T2=1ST LOGICAL K NUMBER
;CLOBBERS T3,T4

CSETZS:
IFN FTDHIA&FT2SWP,<
	MOVE	T3,UNIUST##(U)	;IF NO NEW ACCESSES FOR THIS UNIT (GOING DOWN SOON),
	TLNN	T3,UNPNNA##	; DONT CHANGE UNIFKS (=0)
>
	ADDM	T1,UNIFKS(U)	;INCREMENT COUNT OF FREE K FOR SWAPPING
	IDIVI	T2,^D36		;GET FULL WORDS IN TABLE
	HRLS	T2		;BOTH HALVES
	ADD	T2,UNIPTR(U)	;POINTER TO FIRST WORD TO MODIFY
	PJRST	SETZRS
IFN FTCHECK+FTMONP, <
EXTERNAL SQREQ,SERA,SERACT
EXTERNAL BLKSPK
>

IFE FTCHECK+FTMONP, <


;DATA ASSOCIATED WITH THE SWPSER LOGIC ---

INTERNAL SQREQ,SERA,SERACT
	$LOW

SQREQ:	Z		;C(LH)=NEGATIVE OF SIZE OF READ/WRITE
			; C(RH)=LOCATION OF FIRST WORD TO READ/WRITE
ESQREQ:	Z		;COPY OF SQREQ IN CASE OF SWAP ERROR ON FRAGMENTED JOB.
SERA:	Z		;SIGN IS 1 IF A READ
			;BIT 1=1 IF SWAP IO IN PROGRESS
			;RH(BEFORE IO) BIT 18=1 IF JOB FRAGMENTED
			;BIT 19-35 ADDRESS OF FRAGMENT TABLE IF JOB FRAGMENTED
			;BIT 21-35 DSK SWAPPING AREA BLOCK# IF NOT FRAGMENTED
			;RH(AFTER IO)BITS 18-35 FROM RH OF S
SERACT:	0		;COUNTER FOR ERRORS
SQLEN:	0		;AMOUNT TRANSFERRED SO FAR FOR FRAGMENTED JOB

	$HIGH
>	;END OF FTMONP CONDITIONAL


	$LIT

SWPEND:	END