Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - kiser.mac
There are 6 other files named kiser.mac in the archive. Click here to see a list.
TITLE	KISER - KI10 PROCESSOR DEPENDENT CODE -V254
SUBTTL	J.M. FLEMMING/JMF/DAL  TS   08 FEB 77
	SEARCH	F,S
	$RELOC
	$HIGH
;***COPYRIGHT 1973,1974,1975,1976,1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VKISER,254
		; PUT VERSION NUMBER IN GLOB LISTING AND LOADER STORAGE MAP

	ENTRY	KISER		;LOAD KISER IF LIBRARY SEARCH
KISER:

SUBTTL	CLOCK1 - INTERFACE TO JOB STARTUP, STOP, AND CONTEXT SWITCHING ROUTINES
;HERE AT CLK INTERRUPT LEVEL

;THIS CODE IS DUPLICATED IN CP1SER FOR CPU1

CK0INT::SKIPN	.C0CKF##	;CLK INTERRUPT REQUEST?
	JRST	CK0INT		;NO, CHECK OTHER DEVICES
	CONO	PI,II.CCI##	;CLEAR SOFTWARE INITIATED CLOCK INTERRUPT FLAG
	MOVEM	17,.C0S17##	;SAVE AC 17
	MOVE	17,CK0CHL##	;IS CURRENT JOB IN USER MODE?
	TLNE	17,(XC.USR)
	JRST	CK0IN1		;YES, DON'T NEED TO SAVE THE ACS
	MOVE	17,.C0S17##	;IN EXEC MODE, ASSUME NOT FORCED RESCHEDULE
	SKIPN	.C0SCF##	;SKIP IF THE FORCED RESCHEDULING FLAG IS ON
	JEN	@CK0CHL##	;INTERRUPTED OUT OF A UUO, LEAVE CLOCK FLAG
				; SET AND DISMISS
	SKIPN	17,.C0ADR##	;CURRENT JOB DATA AREA, IS THERE ONE?
	MOVE	17,.C0NJD##	;NO, MUST BE KJOB OR CORE 0, RUNS AT UUO
				; LEVEL AND REQUESTS A CLOCK INTERRUPT TO STOP
	MOVEM	16,JOBD16##(17)	;SAVE AC 16 IN DUMP AREA OF JOB DATA AREA
	MOVEI	16,JOBDAC##(17)	;SOURCE = 0, DESTINATION = DUMP AC 0
	BLT	16,JOBD15##(17)	;SAVE ACS 0-15 IN DUMP AC AREA
	MOVE	T1,.C0S17##	;NOW SAVE 17 IN THE JOB DATA AREA
	MOVEM	T1,JOBD17##(17)	;ALONG WITH THE OTHER DUMP ACS
	MOVE	17,CK0CHL##	;RESTORE INTERRUPT PC
CK0IN1:	MOVEM	17,.C0PC##	;SAVE PC IN PROTECTED PART OF SYSTEM DATA
				; STORAGE FOR CURRENT JOB
CK0SPD::MOVE	P,.C0NPD##	;SETUP PUSH DOWN LIST IN NULL JOB DATA AREA
				;TURN ON USER IOT SO XCTP WORKS RIGHT
CK0IN2:	JRSTF	@[IC.UOU+CHKAPE##] ;CHECK FOR APR ERRORS, CALL THE COMMAND
				; DECODER, AND RESCHEDULE
CIP8B::	MOVE	T1,.C0PC##	;GET THE PC FOR THE CURRENT JOB
	TLNE	T1,(XC.USR)	;IS IT IN USER MODE?
	JEN	@.C0PC##	;YES, ACS ARE ALREADY SETUP
	MOVSI	17,JOBDAC##(R)	;NO, RESTORE EXEC MODE ACS
	BLT	17,17		; FROM THE DUMP AC AREA
	JEN	@.C0PC##	;RETURN TO THE INTERRUPTED EXEC MODE PROGRAM
;ROUTINE TO SAVE THE USER'S ACS IN AC BLOCK 1 IN THE SHADOW AC
; AREA IN THE JOB DATA AREA ON A CONTEXT SWITCH
;CALLING SEQUENCE:
;	SETUP THE USER BASE REGISTER TO POINT TO THE CURRENT JOB'S UPMP
;	PUSHJ	P,SAVUAC
;	ALWAYS RETURN HERE

SAVUAC::PUSH	P,J		;SAVE CURRENT JOB NUMBER
	MOVE	J,U		;J 2 JOB NUMBER OF THE LAST JOB RUN
	PUSHJ	P,SETUPR	;SETUP R TO POINT TO SHADOW AREA
	JRST	JPOPJ##		;NO CORE IN CORE
	MOVEI	T1,(R)		;SOURCE = USER AC 0,
				; DESTINATION = AC 0 IN SHADOW AREA
	EXCTUX	<BLT	T1,17(R)>
				;SAVE USER ACS 0-17
	JRST	JPOPJ##		;RETURN

;ROUTINE TO RESTORE THE USER'S ACS TO AC BLOCK 1 FROM THE SHADOW AC
; AREA IN THE JOB DATA AREA ON A CONTEXT SWITCH
;CALLING SEQUENCE:
;	SETUP THE USER BASE REGISTER TO POINT TO CURRENT JOB'S UPMP
;	PUSHJ	P,RESUAC
;	ALWAYS RETURN HERE

RESUAC::PUSHJ	P,SETUPR	;SETUP R TO POINT TO SHADOW AREA
	  POPJ	P,		;NO CORE IN CORE
	MOVSI	T1,(R)		;SOURCE = AC 0 IN THE SHADOW AREA,
				; DESTINATION = USER AC 0
	EXCTXU	<BLT	T1,17>	;RESTORE USER ACS 0-17
	POPJ	P,		;RETURN

;SUBROUTINE TO SETUP R TO POINT TO SHADOW AC AREA FOR THE CURRENT JOB
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER OF CURRENT JOB
;	PUSHJ	P,SETUPR
;	RETURN HERE IF NOT THE NULL JOB BUT HAS NO CORE (CORE 0,KJOB)
;	RETURN HERE - R POINTS TO THE CURRENT JOBS SHADOW ACS

SETUPR:	MOVEI	T1,JS.ASA	;DON'T SAVE ACS IF THE SHADOW AREA ISN'T FREE
	TDNE	T1,JBTSTS##(J)	;IS IT?
	POPJ	P,		;NO
SETRUP:	SKIPN	R,JBTADR##(J)	;SETUP R - DOES THE JOB HAVE CORE IN CORE?
	JUMPN	J,CPOPJ##	;NO, IF J IS NON-ZERO (I.E., NOT THE NULL
				; JOB) GIVE NON-SKIP RETURN (JOB HAS NO ACS)
	JUMPN	R,CPOPJ1##	;IS IT THE NULL JOB?
	MOVE	R,.CPNJD##(P4)	;YES, RETURN ADDRESS OF NULL JOBS SHADOW AREA
	ADDI	R,JOBDAC##	; ..
	JRST	CPOPJ1##	;GIVE SKIP (THERE IS A PLACE TO STORE ACS) RETURN
;ROUTINE TO ENABLE/DISABLE APR FOR TRAPPING TO USER AND EXEC
;CALL:	MOVEI T1, APR CONSO FLAGS FOR USER TRAPPING
;	PUSHJ P,SETAPR
;	RETURN WITH APR RESET AND INTERRUPT LOCATION CONSO'S SET

SETAPR::PUSH	P,P4		;SAVE P4
	MOVEI	P4,.C0CDB##	;SET UP CDB INDEX FOR CPU0
SETAP1::PUSHJ	P,SETRP		;SETUP THE TRAP LOCATIONS (PAGE FAULT,
				; ARITHMETIC, PDL OVF)
SETAP2:	PUSHJ	P,SETCNA	;SET USER ENABLES FOR NXM AND CLOCK AND
				; SET THE APR PIA
	POP	P,P4		;RESTORE P4
	POPJ	P,		;EXIT

;ROUTINE TO SETUP USER TRAP LOCATIONS AS SPECIFIED BY USER ENABLE BITS
; PAGE FAULT (ILL. MEM. REF.), ARITHMETIC (INTEGER OVERFLOW, FLOATING
; POINT OVERFLOW OR UNDERFLOW, AND DIVIDE CHECK), PUSH DOWN LIST OVERFLOW
; TRAP 3 IS ALWAYS IGNORED IN USER MODE.
;CALLING SEQUENCE:
;	MOVE	T1,USER ENABLE BITS
;	PUSHJ	P,SETRP
;	ALWAYS RETURN HERE
;T1 IS PRESERVED.

SETRP:	TRNE	T1,AP.AOV+AP.FOV;IS HE?
	TDZA	T2,T2		;YES, SET TO FIELD TRAPS
	MOVSI	T2,(JFCL)	;IGNORE ARITHMETIC TRAPS IF USER NOT ENABLED
IFN FTPI,<
	HRRI	T2,SAROVF	;SET DISPATCH ADDRESS
	MOVEM	T2,.UPMP+.UPAOT	;STORE IN UPT
>
IFE FTPI,<
	HLLM	T2,.UPMP+.UPAOT	;FIELD OR IGNORE USER AOF TRAPS
>
	MOVEI	T2,SEPDLO	;IF USER NOT ENABLED FOR POV HANDLE LIKE EXEC POV
	TRNE	T1,AP.POV	;IS HE ENABLED?
	MOVEI	T2,SUPDLO	;YES, HANDLE DIFFERENTLY
	HRRM	T2,.UPMP+.UPPDT	;YES, SET FOR SEPDLO OR SUPDLO TO HANDLE PDL OV
	MOVEI	T2,SEILM	;SAME PROCEDURE FOR ILM
	TRNE	T1,AP.ILM	;IS USER ENABLED FOR ILM?
	MOVEI	T2,SUILM	;YES, GIVE USER CONTROL ON ILM REFERENCE
	HRRM	T2,.UPMP+.UPPFT	;PAGE FAULT TRAP LOCATION IS SEILM OR SUILM
IFE FTPI,<
	POPJ	P,		;RETURN
>
IFN FTPI,<
	PJRST	APPSI##	;SETUP TRAP LOCATIONS FOR ANY INTERRUPTS THE
				; USER IS ENABLED FOR
>
;SUBROUTINE TO SETUP USER'S APR CONSO MASK AND THE APR PIA
;CALLING SEQUENCE:
;	MOVE	T1,USER'S APR ENABLE BITS
;	PUSHJ	P,SETCNA
;	ALWAYS RETURN HERE

SETCNA::HRL	T1,T1		;COPY ENABLE BITS TO LEFT HALF
	TLZ	T1,-1-XP.CLK-UE.PEF ;CLEAR ALL BITS EXCEPT CLOCK FLAG
				; AND USER ENABLED MEM PARITY
	TRNE	T1,AP.NXM	;DOES USER WANT NXM ENABLED?
	TLO	T1,IP.NXM	;YES, ENABLE THAT FOR HIM
	HRRI	T1,IP.TTO+IP.PAR+IP.PWF+XP.CLK+IP.ABK+IP.NXM+IP.IOF
				;SET MONITOR ENABLE BITS
	MOVEI	T2,IP.ECI	 ;ENABLE CLOCK INTERRUPT
	ADDI	T2,@.CPAPI##(P4) ;ADD IN APR PIA
	CONO	PI,PIOFF##	;DISALLOW INTERRUPTS WHILE CHANGING APR BITS
	HLRM	T1,.CPCN1##(P4)	;USER'S ENABLE BITS
	HRRM	T1,.CPCON##(P4)	;MONITOR'S ENABLE BITS
	CONO	APR,(T2)	;SET CLOCK ENABLE AND APR PIA
	CONO	PI,PION##	;RESTORE PI
	POPJ	P,		;RETURN
;ROUTINE TO CAUSE CLK ROUTINE TO RESCHEDULE
;CALLED AT ANY LEVEL
;CALL:	PUSHJ P,STOP2	
;	RETURN IMMEDIATELY EXCEPT IF AT UUO LEVEL
;	IF AT UUO LEVEL, RETURN WHEN JOB IS RUNABLE AGAIN

STOP2::	CONO	PI,PIOFF##	;PREVENT CLOCK INTERRUPT DURING STOP2 CODE
	SETOM	.C0CKF##	;SET FLAG TO INDICATE CLK INTERRUPT
				; EVEN THOUGH CLK INTERRUPT IS NOT A TIME INTERRUPT
	CONO	PI,PICLK##	;TURN PI BACK ON AND REQUEST INTERRUPT TO
				; CLK PI CHANNEL(LOWEST PRIORITY CHANNEL)
	CONSZ	PI,II.IPA	;AT INTERRUPT LEVEL?
	POPJ	P,		;YES, RETURN IMMEDIATELY

	PUSH	P,T1		;NO, AT UUO LEVEL
STOP3:	CONI	PI,T1		; MAKE SURE CLOCK LEVEL PROCESSING
	TLNE	T1,CLKBIT##	; HAPPENS BEFORE DOING ANYTHING ELSE
	JRST	STOP3		; SINCE MAY NOT HAVE ANY CORE
	JRST	TPOPJ##		;RETURN

TSTREL::MOVEI	T1,JS.ASA	;WHAT DOES REFERENCE TO USER 0-17 REALLY MEAN BIT
	TRNN	M,777760	;IS THIS REFERENCE TO USER 0-17?
	TDNN	T1,JBTSTS##(J)	;YES, IS IT TO USER'S ACS OR THE SHADOW ACS?
	AOS	(P)		;USER'S ACS
	POPJ	P,		;GIVE SHADOW ACS OR USER AC SET RETURN
SAROVF::MOVEI	P4,.C0CDB##	;ASSUME CPU0
IFN FTMS,<
	SKPCPU	(0)		;IS THIS CPU0?
	MOVEI	P4,.C1CDB##	;NO, POINT P4 AT CPU1'S CDB
>
	EXCH	R,.CPADR##(P4)	;GET ADDRESS OF USER'S JOB DATA AREA
	MOVEM	T1,.UPMP+.UPMUO	;SAVE A TEMPORARY
	HLLZ	T1,.UPMP+.UPMUP	;GET PC ERROR FLAGS
	HRR	T1,JOBENB##(R)	;GET USER'S ENABLE BITS
	TLZ	T1,3637		;CLEAR NON-EXISTANT KA10 BITS FOR COMPATABLITY
	TRNN	T1,AP.AOV	;OVERFLOW - IS THE USER ENABLED?
	TLNE	T1,(XC.FOV)	;TRAP CAUSED BY FOV?
	JRST	SAROV2		;YES, GO TRAP TO HIM
SAROV1:	MOVE	T1,.UPMP+.UPMUP	;USER IS NOT ENABLED FOR THIS EXCEPTION - RESTORE THE
	JRST	SAROV6		; TRAP PC AND DISMISS TO THE INTERRUPTED PROGRAM
SAROV2:	HRRI	T1,AP.AOV+AP.FOV;ASSUME FLOATING OVERFLOW
	TLNN	T1,(XC.FOV)	;WAS IT A FLOATING OVERFLOW TRAP?
	TRZ	T1,AP.FOV	;NO, INTEGER OVERFLOW
	HRRZM	T1,JOBCNI##(R)	;SIMULATE KA10 CONI APR,JOBCNI(R)
	HRR	T1,.UPMP+.UPMUP	;RESTORE TRAP PC
	MOVEM	T1,JOBTPC##(R)	;STORE IT FOR TRAP HANDLING ROUTINE
	JRST	SAROV4		;FINISH UP
SAROV3:	HRRZM	T1,JOBCNI##(R)	;LIKE CONI ON THE KA-10
SAROV4:	HRR	T1,JOBENB##(R)	;GET USER'S ENABLE BITS
	TRNE	T1,XP.DDU	;USER WANT TRAPS REENABLED?
	JRST	SAROV5		;YES, LEAVE AS IS
	HLLZS	JOBENB##(R)	;CLEAR USER'S ENABLE BITS SO MUST DO APRENB AGAIN
	HRRI	T1,SEILM	;NO
	HRRM	T1,.UPMP+.UPPFT	;EXEC WILL FIELD ILM
	HRRI	T1,(JFCL)
	HRLM	T1,.UPMP+.UPAOT	;IGNORE ARITHMETIC TRAPS
	HRRI	T1,SEPDLO
	HRRM	T1,.UPMP+.UPPDT	;EXEC WILL FIELD PDL OVERFLOWS
	SETZM	.CPCN1##(P4)	;CLEAR POSSIBLE NXM OR CLOCK ENABLES
SAROV5:	HRR	T1,.CPCN1##(P4)	;CLEAR CLOCK ENABLE SO THAT WON'T INTERRUPT HIM
	TRZ	T1,XP.CLK
	HRRZM	T1,.CPCN1##(P4)	;NEW USER ENABLE BITS
	HRR	T1,JOBAPR##(R)	;GET USER'S TRAP ADDRESS
SAROV6:	TLZ	T1,(XC.OVF+XC.FOV+XC.FUF+XC.NDV)
	TLO	T1,(XC.PUB)	;INSURE PUBLIC IS SET
	EXCH	T1,.UPMP+.UPMUO	;NEW PC WITH TRAP CAUSING BITS CLEARED
	EXCH	R,.CPADR##(P4)	;RESTORE R
	JEN	@.UPMP+.UPMUO	;EXIT TO THE USER'S TRAP HANDLER
SEPDLO::MOVEM	P4,.UPMP+.UPMUO	;SAVE P4
	MOVEI	P4,.C0CDB##	;ASSUME CPU0
IFN FTMS,<
	SKPCPU	(0)		;ON CPU1?
	MOVEI	P4,.C1CDB##	;YES, POINT P4 AT CPU1'S CDB
>
	EXCH	T1,.UPMP+.UPMUP	;GET THE PC
	MOVEM	T1,.CPAPC##(P4)	;SET AS ERROR PC FOR ERRCON
	HRRI	T1,AP.POV	;SET PUSH DOWN OVERFLOW FLAG
SEPDL1:	TLNN	T1,(XC.USR)	;WAS THE PDL OVF IN USER MODE?
	JRST	SEPDL2		;NO
	HRRZM	T1,.JDAT+JOBCNI## ;STORE THE PDL OVF BIT
	MOVE	T1,.CPAPC##(P4)	;GET THE USER'S PC
	MOVEM	T1,.JDAT+JOBTPC## ;STORE IT FOR LATER REPORTING
	MOVEI	T1,JS.APE	;APR ERROR IN JOB BIT
	EXCH	J,.CPJOB##(P4)	;GET THE CURRENT JOB'S JOB NUMBER
	IORM	T1,JBTSTS##(J)	;LIGHT APR ERROR BIT
IFN FTMS,<
	MOVE	P,[MJOBPD##,,.JDAT+JOBPDL##] ;SETUP A PUSH DOWN LIST
	PUSHJ	P,CP1APE##	;MAKE SURE THE JOB IS RUNNABLE ON CPU0
				; SO IT WILL GET STOPPED AND ERROR WILL BE REPORTED
>
	EXCH	J,.CPJOB##(P4)	;RESTORE J
	JRST	SEPDL3		;AND PROCEDE
SEPDL2:	HRRM	T1,.CPAEF##(P4)	;IN .CPAEF SO ERRCON WILL GET CALLED
SEPDL3:	MOVE	T1,.UPMP+.UPMUP	;RESTORE T1
	CONO	PI,PIOFF	;NO INTERRUPTS UNTIL P4 IS RESTORED
	SETOM	.CPSCF##(P4)	;SET FORCED RESCHEDULING FLAG
	SETOM	.CPCKF##(P4)	;AND CLOCK FLAG
	MOVE	P4,.UPMP+.UPMUO	;RESTORE P4
	CONO	PI,PICLK##	;REQUEST A CLOCK INTERRUPT AND TURN THE PI SYSTEM ON
	CONSZ	PI,II.IPA	;ANY PIS IN PROGRESS?
	STOPCD	.,STOP,PIP,	;++PI IN PROGRESS
	JRST	.		;WAIT UNTIL CLOCK LEVEL HAPPENS AND THE JOB
				; IS STOPPED IF IN USER MODE.  IF THE PC IS IN
				 ;EXEC MODE, ERRCON WILL CONTINUE AT
				; (.CPAPC(P4)) INSTEAD OF HERE
SEILM::	MOVEM	P4,.UPMP+.UPMUO	;SAVE P4
	MOVEI	P4,.C0CDB##	;ASSUME ON CPU0
IFN FTMS,<
	SKPCPU	(0)		;ARE WE?
	MOVEI	P4,.C1CDB##	;NO, POINT P4 AT CPU1'S CDB
>
	EXCH	T1,.UPMP+.UPMUP	;SAVE T1 AND GET THE PC
	MOVEM	T1,.CPAPC##(P4)	;STORE IT AS POTENTIAL ERROR PC
	EXCH	T2,.UPMP+.UPUPF	;GET THE USER PAGE FAIL WORD
	TLNN	T1,(XC.USR)	;DID THE PAGE FAULT OCCUR IN USER MODE?
	SKIPA	T2,.UPMP+.UPEPF	;NO, GET THE EXEC PAGE FAIL WORD
	MOVE	T3,T2		;USER PAGE FAULT, SAVE PC FOR POSSIBLE CALL TO USRFLT
	JUMPL	T2,SEILM4	;INSURE AGAINST HARDWARE STORING -1 A P.F. WORD
	ANDI	T2,37		;CLEAR ALL BUT THE PAGE FAIL CODE
	TLNE	T1,(XC.USR)	;PAGE FAULT IN EXEC MODE?
	JRST	SEILM0		;NO, PROCEED
	CAIE	T2,PF.ABF	;WAS THE PAGE FAULT AN ADDRESS BREAK?
	STOPCD	.+1,JOB,IME,	;++ILL MEM REF FROM EXEC
	JRST	SEILM1		;YES, REMEMBER IT AND GO AWAY
SEILM0:	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##] ;SETUP A PUSH DOWN LIST
	CAIN	T2,PF.ABF	;ADDRESS BREAK?
	JRST	SEILM1		;YES, GO PROCESS
IFN FTVM,<
	MOVE	T4,T1		;PC WORD INTO T4 FOR USRFLT
>
	HRRI	T1,AP.ILM	;ILLEGAL MEMORY REFERENCE
	CAIN	T2,PF.PRV	;WAS IT A PROPRIETARY VIOLATION?
IFE FTVM,<
	TRO	T1,AP.PPV	;YES, INDICATE THAT
>
IFN FTVM,<
	TROA	T1,AP.PPV	;INDICATE PROPRIETARY VIOLATION (AVOID CALL TO USRFLT)
	PUSHJ	P,USRFLT##	;SEE IF PAGE FAULT FOR A VM USER
				; WILL NOT RETURN IF SO (DISPATCH TO USER)
	MOVEM	T4,.CPAPC##(P4)	;STORE ERROR PC
>
	MOVE	T2,.UPMP+.UPUPF	;RESTORE T2
	JRST	SEPDL1		;GO SAY "ILL. MEM. REF."
SEILM1:	TLO	T1,(IC.AFI)	;INHIBIT ADDRESS BREAK WHEN INSTRUCTION IS
				; EXECUTED AGAIN
	EXCH	J,.CPJOB##(P4)	;GET JOB
	PUSH	P,W		;SAVE W IN CASE IN EXEC MODE
	PUSHJ	P,FNDPDS##	;FIND THE PDB
	LDB	T2,[POINT 9,.PDABS##(W),17]  ;GET THE PROCEED COUNT
	SOSL	T2		;DECREMENT
	DPB	T2,[POINT 9,.PDABS##(W),17]  ;STORE IT BACK IF POSITIVE
	POP	P,W		;RESTORE W
	JUMPG	T2,SEILM3	;DON'T BREAK IF PROCEED COUNT .GT. 0
	MOVE	T2,JBTSTS##(J)	;IS THIS A JACCT
	TLNE	T2,JACCT	;JOB
	JRST	SEILM3		;YES-IGNORE BREAK
	EXCH	J,.CPJOB##(P4)	;UNDO LAST EXCH
	TLNN	T1,(XC.USR)	;PC IN USER MODE?
	JRST	SEILM2		;NO, REMEMBER BREAK AND GO AWAY
	MOVE	R,.CPADR##(P4)	;SETUP R
	MOVEM	T1,.CPAPC##(P4)	;STORE THE PC WITH IFA ON
IFN FTPI,<
	MOVE	J,.CPJOB##(P4)	;JOB NUMBER FOR PSISER
	SIGNAL	C$ADRB		;SIGNAL THAT AN ADDRESS BREAK HAS OCCURED
	  JRSTF	@.CPAPC##(P4)	;THE USER IS ENABLED, INTERRUPT HIM
>	;END FTPI
	PUSH	P,.CPAPC##(P4)	;SAVE PC ON STACK
IFN FTMS,<
	PUSHJ	P,ONCPU0##	;MUST BE ON CPU0 TO REPORT THE BREAK
>
	PUSHJ	P,TTYFUW##	;FIND THE USER'S TTY
	PUSHJ	P,INLMES##	;REPORT THE ADDRESS BREAK
	ASCIZ	/
%Address break at user PC /
	HRRZ	T1,(P)		;GET THE USER'S PC
	PUSHJ	P,OCTPNT##	;TELL HIM WHERE THE BREAK OCCURED
IFN FTPI,<
	PUSHJ	P,PSIERR##	;PENDING INTERRUPT?
	  JFCL
	  PJRST	ERRGOU##	;YES, GIVE IT TO THE USER
>
	PJRST	HOLDW##		;STOP THE JOB IN A CONTINUABLE STATE
SEILM2:	MOVEI	T2,JS.ASA	;AC'S ARE IN THE SHADOW AREA BIT
	EXCH	J,.CPJOB##(P4)	;JOB NUMBER
	TDNE	T2,JBTSTS##(J)	;SAVE/GET IN PROGRESS?
	JRST	SEILM3		;YES, DON'T BOTHER THE USER WITH BREAKS ON THAT
	MOVEI	T2,JS.ABP	;ADDRESS BREAK HAPPENED DURING UUO PROCESSING BIT
	IORM	T2,JBTST2##(J)	;REMEMBER THAT THE BREAK HAPPENED
SEILM3:	EXCH	J,.CPJOB##(P4)	;RESTORE J
SEILM4:	EXCH	T1,.UPMP+.UPMUP	; AND T1
	MOVE	T2,.UPMP+.UPUPF	; AND T2
	MOVE	P4,.UPMP+.UPMUO	; AND P4
	JRSTF	@.UPMP+.UPMUP	;GO AWAY AND TELL THE USER ABOUT THE BREAK
				; AT UUO EXIT
EXCABK::ANDCAM	T1,JBTST2##(J)	;CLEAR BREAK HAPPENED IN EXEC MODE BIT
	PUSHJ	P,FNDPDS##	;FIND THIS JOB'S PDB
	MOVSI	T1,(OC.BCM)	;BREAK ON MUUO REFERENCES BIT
	TDNN	T1,.PDABS##(W)	;IS THE USER INTERESTED?
	 POPJ	P,		;NO, GO AWAY
IFN FTPI,<
	PUSHJ	P,CPUCDB##	;SETUP P4 TO POINT TO THE CURRENT CPU'S CDB
	MOVE	T2,JOBPD1##(R)	;GET UUO PC
	MOVEM	T2,.CPAPC##(P4)	;STORE IT WHERE PSISER EXPECTS IT
	SIGNAL	C$ADRB		;SIGNAL THAT AN ADDRESS BREAK OCCURED
	  POPJ	P,		;USER IS ENABLED, UUO EXIT WILL INTERRUPT TO HIM
>
IFN FTMS,<
	PUSHJ	P,ONCPU0##	;MUST BE ON CPU0 TO WRITE A MESSAGE
>
	PUSHJ	P,TTYFUW##	;FIND THE USER'S TTY
	PUSHJ	P,INLMES##	;REPORT THE ADDRESS BREAK
	ASCIZ	/
%Address break at exec PC /
	HRRZ	T1,.UPMP+.UPMUP	;GET THE PC WHERE THE LAST BREAK OCCURED
	PUSHJ	P,OCTPNT##	;TELL HIM THAT
	MOVEI	T1,[ASCIZ/; UUO/]
	PUSHJ	P,CONMES##
	MOVE	T2,JOBPD1##(R)	;GET THE UUO PC
	PUSHJ	P,PCP##		;REPORT IT SO HE WILL KNOW WHAT UUO BROKE
IFN FTPI,<
	PUSHJ	P,PSIERR##	;PENDING INTERRUPT?
	  JFCL
	 POPJ	P,		;YES
>
	POP	P,(P)		;POP OFF THE PUSHJ TO EXCABK
	PJRST	HOLDW##		;AND STOP THE JOB IN A CONTINUABLE STATE
SUILM:	MOVEI	P4,.C0CDB##	;ASSUME FAULT OCCURED ON CPU0
IFN FTMS,<
	SKPCPU	(0)		;DID IT?
	MOVEI	P4,.C1CDB##	;NO, ON CPU1
>
	MOVE	R,.CPADR##(P4)	;GET THE ADDRESS OF THE USER'S JOB DATA AREA
	MOVEM	T1,.UPMP+.UPMUO	;SAVE A TEMPORARY
	MOVE	T1,.UPMP+.UPMUP	;GET ILM PC
	MOVE	T2,.UPMP+.UPUPF	;GET THE PAGE FAIL WORD
	ANDI	T2,37		;PAGE FAIL CODE
	CAIN	T2,PF.ABF	;ADDRESS BREAK?
	JRST	SEILM0		;YES, GO PROCESS IT
IFN FTVM,<
	MOVE	T3,.UPMP+.UPUPF	;GET THE USER PAGE FAIL WORD
	MOVE	T4,T1		;MOVE THE PC TO T4 FOR USRFLT
	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##] ;SETUP A PUSH DOWN LIST
	PUSHJ	P,USRFLT##	;SEE IF PAGE FAULT FOR VM USER
				; WILL NOT RETURN IF SO (DISPATCH TO PFH)
>
	TLZ	T1,3637		;CLEAR NON-EXISTANT KA-10 BITS FOR COMPATABILITY
	MOVEM	T1,JOBTPC##(R)	;SAVE ERROR PC FOR USER
	HRRI	T1,AP.ILM	;SET ILM BIT FOR USER
	JRST	SAROV3		;FINISH UP
SUPDLO:	MOVEI	P4,.C0CDB##	;ASSUME ON CPU0
IFN FTMS,<
	SKPCPU	(0)		;ARE WE?
	MOVEI	P4,.C1CDB##	;NO, ON CPU1
>
	EXCH	R,.CPADR##(P4)	;GET ADDRESS OF USER'S JOB DATA AREA
	MOVEM	T1,.UPMP+.UPMUO	;SAVE A TEMPORARY
	MOVE	T1,.UPMP+.UPMUP	;GET ERROR PC
	TLZ	T1,3637
	MOVEM	T1,JOBTPC##(R)	;SAVE FOR USER TO LOOK AT
	HRRI	T1,AP.POV	;SET POV BIT FOR USER
	JRST	SAROV3		;FINISH UP
;ROUTINE TO SET HARDWARE AND SOFTWARE RELOCATION INFORMATION FOR CURRENT USER
;CALLING SEQUENCE:
;	PUSHJ	P,SETREL
;	...	RETURN HERE
;J = CURRENT JOB NUMBER
;R = PROTECTION,,RELOCATION FOR THE LOW SEGMENT

SETRLH::MOVE	J,.C0JOB##	;J=CURRENT JOB NUMBER
	MOVEI	T1,0
	DPB	T1,JBYHSS##	;FORCE MAP TO BE REDONE
SETREL::PUSH	P,P4		;SAVE P4
	MOVEI	P4,.C0CDB##	;SETUP P4 TO POINT TO CPU0 CDB
	SKIPA	J,.C0JOB##	;J = CURRENT JOB NUMBER
SETRL1::PUSH	P,P4		;SAVE P4
	MOVE	R,JBTADR##(J)	;R = XWD PROTECTION,,EXEC VIRTUAL ADDRESS
				; OF THE FIRST PAGE OF THE LOW SEGMENT
	MOVEM	R,.CPADR##(P4)	;SET .CPADR FOR QUICK ACCESS AT APR LEVEL
	HLRZM	R,.CPREL##(P4)	;SET .CPREL FOR ADDRESS CHECKING
IFN FTTRPSET,<
	SKIPE	.CPSTS##(P4)	;HAS TIME-SHARING BEEN STOPPED BY A TRPSET UUO?
	JRST	SETRLZ		;NO, DON'T CHANGE THE UBR
>
	SKIPE	J		;NULL JOB ALWAYS HAS A UPMP
	JUMPE	R,SETRLZ	;THERE IS NO UPMP IF THE JOB HAS NO CORE
	PUSHJ	P,STEUB		;NO, SET THE USER BASE REGISTER
	JUMPE	R,SETRLZ	;IF NULL JOB OR CORE 0, DON'T STORE IN
				; NON-EXISTANT JOB DATA AREA
	LDB	T1,JBYLSS##	;GET THE PREVIOUS SIZE OF THE LOW SEGMENT
	LDB	T2,[POINT 9,R,8];GET THE CURRENT SIZE
	CAIE	T1,(T2)		;IS IT THE SAME SIZE AS IT WAS THE LAST
				; TIME THIS JOB WAS RUN?
	PUSHJ	P,MAPLOW	;NO, REDO THE MAP
IFE FTVM,<
	HLRZM	R,JOBREL##(R)	;SET THE SIZE OF THE LOW SEGMENT FOR THE USER
>
IFN FTVM,<
	SKIPN	T1,.UPMP+.UPREL	;HOLEY PROGRAM?
	HLR	T1,R
	HRRZM	T1,JOBREL##(R)	;STORE HIGHEST CORE-UUO ADDRESS IN JOBREL
>
IFN FT2REL,<
	SKIPL	T1,JBTSGN##(J)	;JOB HAVE A REAL HIGH SEGMENT?
	SKIPA	T1,JBTADR##(T1)	;YES
	HRLZS	T1		;SIZE OF SPY SEGMENT OR ZERO IF NOT SPY SEGMENT
	LDB	T2,[POINT 9,T1,8];CURRENT SIZE -1 OF THE HIGH SEGMENT
	SKIPE	T1		;IS THERE A SPY OR HIGH SEGEMNT?
	ADDI	T2,1		;YES, ITS ACTUALLY ONE PAGE BIGGER
	LDB	T1,JBYHSS##
	CAIE	T1,(T2)		;HAS THE HIGH SEGMENT SIZE CHANGED SINCE THE
				; LAST TIME THIS JOB WAS RUN?
	PUSHJ	P,MAPHGH	;YES, REDO THE HIGH SEGMENT PART OF THE MAP
>
SETRLZ:
IFN FTSET,<
	PUSHJ	P,FDNJP		;FIND THE NULL JOB'S PDB
	MOVE	T3,T1		;SAVE THE ADDRESS OF THE NULL JOB'S PDB
	PUSHJ	P,FNDPDS	;FIND THE CURRENT JOB'S PDB
>
	HRRZ	T1,JBTUPM##(J)	;PAGE NUMBER OF THE CURRENT JOB'S UPMP
	JUMPE	T1,SETRL2	;DON'T CHANGE ANYTHING IF THERE ISN'T ONE
	MOVSI	T1,<(PG.LUB)>(T1)
IFN FTRTTRP,<
	MOVEM	T1,.CPDTO##(P4)	;SAVE FOR RTTRP INTERRUPT LEVEL USE
>
	TLO	T1,(PG.ACE+PG.AC1) ;USER ADDRESS COMPARE ENABLE AND USER AC SET 1
IFN FTSET,<
	.SKIPE	T2,.PDABS##(W)	;DOES THE USER HAVE ADDRESS BREAK SETTINGS?
	TLNN	T2,(OC.ABE)	;YES, IS HE ENABLED FOR BREAKS
	MOVE	T2,[EXP OC.FEP+CURJOB##] ;NO, DISPLAY JOB NUMBERS
>
	DATAO	PAG,T1		;SETUP THE UBR
IFN FTSET,<
	TLZ	T2,777(OC.BSU)	;CLEAR PROCEED COUNTER AND SET BY UUO
	.SKIPL	.PDABS(T3)	;CAN USERS USE ADDRESS BREAK?
	DATAO	PTR,T2		;YES, SETUP BREAK CONDITIONS AND BREAK ADDRESS
>
SETRL2:	SKIPN	R,JBTADR##(J)	;RESTORE R - JOB HAVE CORE IN CORE?
	TDZA	T1,T1		;NO, MUST BE THE NULL JOB OR CORE 0
	MOVE	T1,JOBENB##(R)	;JOB'S APR ENABLE BITS
	JRST	SETAP2		;SETUP APR ENABLE BITS FOR THE USER
				; NO ENABLES IF NULL JOB OR NO CORE IN CORE
;ROUTINE TO SETUP USER AND EXEC BASE REGISTERS FOR A JOB
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER
;	PUSHJ	P,STEUB

STEUB::	CAILE	J,JOBMAX##	;IS THIS A LOW SEGMENT?
	POPJ	P,		;NO, THE UBR MUST ALREADY BE SETUP
				; OR DOESN'T NEED TO BE (ADDRESSES WILL BE
				; MAPPED THROUGH THE EXEC MAP)
	PUSH	P,T1		;SAVE A TEMPORARY
	HRRZ	T1,JBTUPM##(J)	;T1 = THE PAGE NUMBER OF THE USER PAGE MAP PAGE
	TRNN	T1,17777	;IS THERE A UPMP
	JRST	TPOPJ##		;NO, DON'T CLOBBER UBR
	MOVSI	T1,<(PG.LUB+PG.AC1)>(T1)
	DATAO	PAG,T1		;SET FOR CURRENT USER AND CLEAR THE AM
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
SUBTTL	COMCON - INTERFACE TO COMMAND DECODER MODULE

;ROUTINE TO SETUP THE USER BASE REGISTER FOR COMMAND PROCESSING
;CALLING SEQUENCE:
;	PUSHJ	P,COMUBR
;	...	ALWAYS RETURN HERE - UBR POINTS TO THE UPMP OF THE
;		JOB THAT TYPED A COMMAND

COMUBR::MOVE	T1,.C0JOB##	;T1=JOB NUMBER OF CURRENTLY RUNNING JOB
	HRRZ	T2,JBTUPM##(T1)	;JOB HAVE A UPMP?  (NO, ONLY IF THE CURRENT
				; JOB DID  LOGOUT UUO GIVING BACK ALL
				; OF ITS CORE)?
	JUMPE	T2,STEUB	;NO, DON'T SAVE THE UBR SINCE IT POINTS
				; A UPMP WHICH HAS BEEN RETURNED
				; TO THE FREE CORE LIST - JUST POINT THE
				; UBR AT THE UPMP OF THE JOB THAT THE
				; COMMAND IS BEING DONE FOR
	JRST	SVEUB		;SAVE AND SETUP THE UBR
;HERE IF THE USER TYPED SET BREAK
IFN FTSET,<
SETBRK::PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSHJ	P,FNDPDS##	;FIND THE PDB FOR THIS USER
	PUSHJ	P,CTEXT##	;GET THE FIRST ARGUMENT
	JUMPE	T2,NOTENF##	;IF NONE, COMPLAIN
	PUSHJ	P,GETNUM	;SEE IF ARGUMENT TYPED IS A NUMBER
	  JRST	SETBR2		;NOT A NUMBER, LOOK FOR LEGAL TEXT
SETBR1:	CAIN	P1,-1		;DON'T ALLOW -1 FOR THE TIME BEING SINCE IT
				; CONFUSES THE HARDWARE
	JRST	COMERA##	;COMPLAIN
	.HRRM	P1,.PDABS##(W)	;STORE THE BREAK ADDRESS
	PUSHJ	P,CTEXT##	;GET THE NEXT ARGUMENT
	JUMPN	T2,SETBR2	;JUMP IF ONE WAS TYPED
	SKIPN	P2,P1		;BREAK ADDRESS ZERO?
	  JRST	SETB10		;YES, TREAT SET BREAK 0 WITH NO CONDITION LIKE NONE
	.HLLZ	P2,.PDABS##(W)	;GET PREVIOUS CONDITIONS IF ANY
SETB1A:	TLNN	P2,(OC.BCI+OC.BCD+OC.BCW+OC.BCM) ;WERE THERE ANY PREVIOUSLY?
	TLO	P2,(OC.BCI+OC.BCD+OC.BCW) ;NO, ASSUME ALL
	JRST	SETBR8		;ENABLE BREAK, STORE CONDITIONS, AND GO AWAY
SETBR2:	MOVE	T1,[-4,,BRKLS1]	;TABLE LENGTH,,ADDRESS OF THE TABLE
	PUSHJ	P,FNDNAM##	;RECOGNIZABLE TEXT ARGUMENT?
	  JRST	SETBR5		;NO, POSSIBLY IN ANOTHER CONTEXT
	MOVE	P2,T1		;INDEX INTO BRKTBL
	JUMPN	T1,SETBR3	;JUMP IF THE USER DIDN'T TYPE 'NONE'
;HERE WHEN THE USER TYPED 'NONE'
	JUMPGE	P1,COMERA##	;IF A NUMBER WAS TYPED WE SHOULDN'T BE HERE
	JRST	SETB10		;GO CLEAR BREAK CONDITIONS
SETBR3:	PUSHJ	P,CTEXT##	;GET THE NEXT TEXT ARGUMENT
	JUMPE	T2,NOTENF##	;IF WE'RE HERE THERE HAS TO BE ONE
	JRST	.(P2)		;DISPATCH TO THE APPROPRIATE PROCESSOR
	JRST	SETBR4		;USER TYPED 'AT'
	JRST	SETBR5		;USER TYPED 'ON'
	JRST	SETBR6		;USER TYPED 'NO'
;HERE WHEN THE USER TYPED 'AT'
SETBR4:	JUMPGE	P1,COMERA##	;NO PREVIOUS NUMBERS ALLOWED IF WE GET HERE
	PUSHJ	P,GETNUM	;CONVERT THE NUMBER FROM SIXBIT TO OCTAL
	  JRST	COMERA##	;IT MUST BE A NUMBER BUT ISN'T SO COMPLAIN
	JRST	SETBR1		;LOOK FOR THE NEXT TEXT ARGUMENT
;HERE WHEN THE USER TYPED 'ON'
SETBR5:	SKIPA	P1,[TDO P2,BRKTBL-1(T1)]
;HERE WHEN THE USER TYPED 'NO'
SETBR6:	MOVE	P1,[TDZ P2,BRKTBL-1(T1)]
	.HLLZ	P2,.PDABS##(W)	;GET CURRENT BREAK CONDITIONS
SETBR7:	MOVE	T1,[-7,,BRKLS2]	;TABLE LENGTH,,TABLE ADDRESS
	PUSHJ	P,FNDNAM##	;GET A BREAK CONDITION
	  JRST	COMERA##	;IT CAN'T BE ANYTHING ELSE
	JUMPE	T1,SETB11	;JUMP IF 'USERS'
	CAIN	T1,AFTERX
	JRST	SETB12
	XCT	P1		;SET OR CLEAR THE CONDITION
	PUSHJ	P,CTEXT##	;GET THE NEXT ARGUMENT
	JUMPN	T2,SETBR7	;LOOP BACK IF THERE WAS ONE
	TLZ	P2,(OC.ABE+OC.FUP)  ;ASSUME NO CONDITIONS
	TLNN	P2,(OC.BCI+OC.BCD+OC.BCW+OC.BCM) ;ANY CONDITIONS DESIRED?
	JRST	SETB10		;NO, DECREMENT NUMBER OF USERS USING ADDRESS BREAK
SETBR8:	PUSHJ	P,BRKAV		;SEE IF ADDRESS BREAK IS AVAILABLE AND INCREMENT
				; THE COUNT OF USERS USING IT IF SO
	  JRST	NOBRAK		;NOT AVAILABLE, COMPLAIN
SETBR9:	TLOA	P2,(OC.ABE+OC.FUP) ;ENABLE THE USER FOR ADDRESS BREAK
SETB10:	PUSHJ	P,BRKDEC	;DECREMENT THE COUNT OF USERS USING ADDRESS BREAK
	.HLLM	P2,.PDABS##(W)	;STORE THE NEW CONDITIONS
	POPJ	P,		;AND RETURN TO COMCON
;HERE WHEN THE USER TYPED 'USERS', MUST BE PRIVILEGED
SETB11:	PUSHJ	P,SETLGL##	;USER SUFFICIENTLY PRIVILEDGED TO MONOPOLIZE
				; ADDRESS BREAK?
	  JRST	COMERA##	;NO, COMPLAIN
	PUSHJ	P,FDNJP		;FIND THE NULL JOB'S PDB
	MOVSI	T2,400000	;SET TO TURN ON OR OFF ADDRESS BREAK
	CAME	P1,[TDZ P2,BRKTBL-1(T1)] ;WAS 'USERS' WITHOUT A 'NO' TYPED?
	JRST	[.ANCAM	T2,.PDABS##(T1) ;YES, ALLOW USERS TO USE ADDRESS BREAK
		POPJ	P,]	;RETURN
;HERE WHEN THE USER TYPED 'NO USERS'
	.SKPLE	.PDABS##(T1)	;IS ADDRESS BREAK CURRENTLY BEING USED?
	JRST	NOBRAK		;DON'T ALLOW HIM TO YANK IT OUT FROM UNDER THEM
	.IORM	T2,.PDABS##(T1)	;DON'T ALLOW USERS TO USE ADDRESS BRAEK
	POPJ	P,		;RETURN TO COMCON

;HERE WHEN THE USER TYPED 'AFTER'
SETB12:	PUSHJ	P,DECIN##	;GET THE NEXT ARGUMENT
	  PJRST	NOTENF##	;THERE MUST BE ONE
	  JRST	COMERA##	;NOTHING BUT A NUMBER IS LEGAL
	CAILE	T2,^D510	;IS IT TOO BIG?
	JRST	COMERA##	;YES
	ADDI	T2,1
	DPB	T2,[POINT 9,P2,17]  ;SAVE THE REPEAT COUNT
	JRST	SETB1A		;STORE IT AND GO AWAY
;HERE ON A SET ADDRESS BREAK UUO
SETABR::PUSHJ	P,SAVE2##	;SAVE P1,P2
	HRR	M,T2		;ADDRESS OF USER'S ARGUMENT
	PUSHJ	P,GETWDU##	;GET THE ARGUMENT
	HRRM	T1,.PDABS##(W)	;STORE THE BREAK ADDRESS
	MOVE	P2,T1		;P2 = BREAK CONDITIONS
	TLZ	P2,(OC.FEP)	;HE ISN'T ALLOWED TO SET FOLLOW EXEC PAGING
	TLO	P2,(OC.BSU)	;INDICATE SET BY UUO
	AOS	(P)		;PREPARE TO GIVE GOOD RETURN
	TLNN	P2,(OC.BCI+OC.BCD+OC.BCW+OC.BCM)
	JRST	[PUSHJ P,SETB10	;TURNING OFF BREAK
		 PJRST SETRL1]
	PUSHJ	P,BRKAV		;IS ADDRESS BREAK AVAILABLE?
	  SOSA	(P)		;NO, ERROR RETURN
	JRST	[PUSHJ P,SETBR9	;YES, SETUP BREAK CONDITIONS
		 PJRST SETRL1]
	POPJ	P,		;GIVE ERROR RETURN

;HERE ON RESET TO CLEAR BREAK ADDRESS AND CONDITIONS
; IF SET BY UUO
CLRBRK::SKIPE	T1,.PDABS##(W)	;BREAK IN USE AT ALL?
	TLNN	T1,(OC.BSU)	;AND SET BY UUO?
	POPJ	P,		;NO
	PUSHJ	P,BRKDEC	;YES, DECREMENT COUNT OF USERS
	SETZM	.PDABS##(W)	;CLEAR ADDRESS AND CONDITIONS
	POPJ	P,		;AND RETURN
;THE ORDER OF AND THE NUMBER OF ENTRIES
; IN THE FOLLOWING TABLES CANNOT BE CHANGED
; WITHOUT CHANGING THE CODE IN SETBRK

BRKLS1:	SIXBIT	/NONE/
	SIXBIT	/AT/
	SIXBIT	/ON/
	SIXBIT	/NO/
BRKLS2:	SIXBIT	/USERS/
	SIXBIT	/EXECUT/
	SIXBIT	/READ/
	SIXBIT	/WRITE/
	SIXBIT	/MUUO/
	SIXBIT	/ALL/
BRKLS3:	SIXBIT	/AFTER/
AFTERX==BRKLS3-BRKLS2
;THE ENTRIES IN THIS TABLE CORRESPOND IN ORDER
; TO THE ENTRIES IN THE ABOVE TABLE
BRKTBL:	EXP	OC.BCI
	EXP	OC.BCD
	EXP	OC.BCW
	EXP	OC.BCM
	EXP	OC.BCI+OC.BCD+OC.BCW

;SUBROUTINE TO DETERMINE IF THE SIXBIT STRING IN
; T2 IS A LEGAL OCTAL NUMBER
;CALLING SEQUENCE:
;
;	MOVE	T2,SIXBIT STRING
;	PUSHJ	P,GETNUM
;NON-SKIP RETURN IF T2 DOES NOT CONTAIN A
; NUMBER, P1.LT.0, AND T2 PRESERVED
;SKIP RETURN P1=NUMBER IF T2 CONTAINS A NUMBER
;NEVER RETURNS IF T2 CONTAINS A MALFORMED
; NUMBER
;N.B. P1 MUST BE SAVED BEFORE CALLING THIS
;SUBROUTINE

GETNUM:	MOVSI	P1,400000	;INDICATE NO NUMBER SEEN
	MOVEI	T3,0		;CLEAR RESULT SO FAR
	MOVE	T4,[POINT 6,T2]	;BYTE POINTER TO PICKUP CHARACTERS
GETNM1:	ILDB	T1,T4		;GET THE NEXT CHARACTER
	CAIL	T1,'0'		;IS THE CHARACTER .LT. ZERO?
	CAILE	T1,'7'		;OR G.GE. 7?
	JRST	GETNM2		;YES, ITS NOT AN OCTAL DIGIT
	LSH	P1,3		;MULTIPLY ACCUMULATED RESULT BY 8
	ADDI	P1,-'0'(T1)	;ADD IN THE CURRENT CHARACTER
	JRST	GETNM1		;AND GET THE NEXT DIGIT
GETNM2:	JUMPL	P1,CPOPJ##	;NON-SKIP RETURN IF NOT A NUMBER
	JUMPN	T1,COMERP##	;NUMBERS WHICH TERMINATE WITH NON-DIGITS ARE
				; NOT NUMBERS
	JRST	CPOPJ1##	;GIVE NUMBER FOUND RETURN
;SUBROUTINE TO DETERMINE WHETHER ADDRESS BREAK IS AVAILABLE TO USERS
;CALLING SEQUENCE:
;	PUSHJ	P,BRKAV
;NON-SKIP RETURN IF NOT AVAILABLE BECAUSE MEMORY
; INDICATORS ARE DISABLED OR ADDRESS BREAK IS BEING
; USED BY SYSTEM PROGRAMMERS FOR MONITOR DEBUGGING
;SKIP RETURN IF ADDRESS BREAK IS AVAILABLE TO USERS, COUNT OF THE NUMBER
;OF USERS USING ADDRESS BREAK HAS BEEN UPDATED
;PRESERVES T2

BRKAV:	PUSHJ	P,FDNJP		;FIND THE NULL JOB'S PDB
	MOVSI	T4,(IP.MID)	;MI PROG DIS
	PUSHJ	P,CP0RC##	;SEE IF THE JOB IS RUNNABLE ON CPU0
	  TLNE	P2,(OC.BCM)	;ITS NOT, BUT IF HE IS ENABLED FOR UUOS, SOME
				; MUST HAPPEN ON CPU0
	TDNN	T4,.C0APR##	;IS MI PROG DIS ON ON CPU0?
	SKIPGE	.PDABS##(T1)	;OR HAS ADDRESS BREAK BEEN DISABLED BY THE OPR?
	POPJ	P,		;YES, LOSE
IFN FTMS,<
	PUSHJ	P,CP1AC##	;IF RUNNABLE ON CPU1, MI PROG DIS MUST BE OFF ON CPU1
	  POPJ	P,		;HE IS AND IT ISN'T, SO LOSE

>
	.MOVE	T3,.PDABS##(W)	;GET HIS CURRENT ADDRESS BREAK SETTINGS
	TLNN	T3,(OC.ABE)	;IS HE ALREADY BREAKING?
	.AOS	.PDABS##(T1)	;NO, COUNT UP THE NUMBER OF USERS USING ADDRESS BREAK
	JRST	CPOPJ1##	;AND GIVE THE HAPPY RETURN

;SUBROUTINE TO DECREMENT THE COUNT OF THE NUMBER
; OF USERS USING ADDRESS BREAK

BRKDEC:	.MOVE	T1,.PDABS##(W)	;GET HIS CURRENT BREAK SETTINGS
	TLNN	T1,(OC.ABE)	;IS HE ENABLED FOR ADDRESS BREAK?
	POPJ	P,		;NO, NOTHING TO DO
	PUSHJ	P,FDNJP		;FIND THE PDB FOR THE NULL JOB
	.SOS	.PDABS##(T1)	;DECREMENT THE COUNT OF USERS USING ADDRESS BREAK
	POPJ	P,		;AND RETURN

NOBRAK:	PJSP	T1,CONMES##	;SORRY FOLKS!
	ASCIZ	/?Not available
/

;SUBROUTINE TO RETURN THE ADDRESS OF THE NULL JOB'S PDB IN T1
;PRESERVES T2-T4

FDNJP:	MOVEI	T1,0		;NULL JOB'S JOB NUMBER
	PUSHJ	P,FPDBT1##	;FIND THE NULL JOB'S PDB, RETURN ITS ADDRESS IN T1
	  JFCL			;IT MUST HAVE ONE
	POPJ	P,		;RETURN TO THE CALLER
>	;END IFN FTSET
SUBTTL	IOCSS - I/O SERVICE SUBROUTINES (UUOCON AND DEVICE ROUTINES)

;ROUTINE TO DETERMINE WHETHER A DEVICE NEEDS THE USER AREA
;REPRESENTED IN THE CURRENT I/O OPERATION TO BE
;MAPPED IN EXEC VIRTUAL MEMORY
;CALLING SEQUENCE:
;
;	MOVE	F,ADDRESSS OF DEVICE DATA BLOCK
;	PUSHJ	P,MAPDEV
;	RETURN HERE IF NO MAPPING REQUIRED
;	RETURN HERE IF BUFFERS OR IOWDS MUST BE MAPPED

MAPDEV::PUSH	P,T1		;SAVE P1
	MOVEI	T1,DEPEVM	;GET "DEVICE DOESN'T NEED EVM" BIT
	TDNN	T1,DEVTYP(F)	;SKIP IF MAPPING NOT REQUIRED
	PJRST	TPOPJ1##	;PTY, TTY, AND CHANNEL DEVICES ARE NOT
				; MAPPED IN EXEC VIRTUAL MEMORY
	PJRST	TPOPJ##		;ALL I/O BUS DEVICE REQUIRE MAPPING IN
				; EXEC VIRTUAL MEMORY
;ROUTINE TO SAVE AND OPTIONALLY SET UP THE USER BASE REGISTER
; AND RESTORE IT ON A CPOPJ OR CPOPJ1 RETURN
;CALLING SEQUENCE:
;	PUSHJ	P,SVEUB		;TO SAVE USER BASE REGISTER
;OR
;	PUSHJ	P,SVEUB		;TO SAVE USER BASE REGISTER AND SETUP
;				;USER BASE REGISTER FOR JOB IN J
;ALWAYS RETURN HERE

SVEUF::	PUSH	P,T1		;SAVE A TEMPORARY
	DATAI	PAG,T1		;GET THE USER AND EXEC BASE REGISTERS
	PUSH	P,J		;SAVE J
	LDB	J,PJOBN##	;GET THE JOB NUMBER OF JOB CURRENTLY USING
				; THIS DEVICE
	PUSHJ	P,STEUB		;SETUP THE UBR SO CURRENT JOB IS ADDRESSABLE
	POP	P,J		;RESTORE J
	JRST	SSEU1		;SAVE THE PREVIOUS CONTENTS OF THE UBR AND EBR
SVEUB::	PUSH	P,T1		;SAVE A TEMPORARY
	DATAI	PAG,T1		;GET THE CONTENTS OF THE USER AND EXEC BASE REGISTERS
	PUSHJ	P,STEUB		;SETUP THE UBR FOR THE JOB WHOSE JOB NUMBER
				; IS IN J
	JRST	SSEU1		;SAVE THE PREVIOUS CONTENTS OF THE UBR AND THE EBR
SSEUB:	PUSH	P,T1		;SAVE A TEMPORARY
	DATAI	PAG,T1		;GET THE CONTENTS OF THE USER AND EXEC BASE REGISTERS
SSEU1:	EXCH	T1,-1(P)	;GET THE CALLER'S PC AND SAVE THE CONTENTS
				; OF THE UBR AND EBR
	MOVEM	T1,1(P)		;SAVE THE CALLER'S PC IN A TEMPORARY LOCATION
				; ON THE STACK
	POP	P,T1		;RESTORE T1 TO ITS CONTENTS ON ENTRY
	PUSHJ	P,@2(P)		;RETURN TO THE CALLER LEAVING .+1 ON THE
				; STACK SO WHEN THE CALLER DOES A POPJ OR
				; A CPOPJ1, CAN RESTORE THE PREVIOUS CONTENTS
				; OF THE UBR AND THE EBR
	  CAIA			;CPOPJ RETURN
	AOS	-1(P)		;CPOPJ1 RETURN - BUMP RETURN PC
	EXCH	T1,(P)		;GET THE PREVIOUS CONTENTS OF THE UBR
	TDO	T1,[EXP PG.LUB+PG.LEB]
	DATAO	PAG,T1		;RESTORE THE UBR AND THE EBR
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
;ROUTINE TO MAP USER AREA IN THE EXEC MAP
;CALLING SEQUENCE:
;
;	MOVE	T1,PAGE NUMBER OF STARTING PAGE IN THE EXEC MAP
;	MOVE	T2,NUMBER OF PAGES
;	MOVE	T3,USER VIRTUAL ADDRESS
;	PUSHJ	P,MAPUEV
;OR
;	PUSHJ	P,MAPUEI IF AT INTERRUPT LEVEL SO EBR,UBR WILL BE
;		RESTORED SO DO NOT NEED TO PURGE ASSOCIATIVE MEMORY
;	RETURNS HERE - T1=PAGE NUMBER IN THE EXEC MAP, T3=EXEC VIRTUAL
;	ADDRESS WHICH CORRESPONDS TO USER VIRTUAL ADDRESS,
;	AND ASSOCIATIVE MEMORY IS PURGED

MAPUEV::PUSHJ	P,SAVE3##	;SAVE P1-P3
	PUSHJ	P,MAPUE1	;MAP THE USER IN EXEC VIRTUAL MEMORY
	CLRPGT	(0)	;RESET THE EXEC BASE REGISTER SO THAT
				; THE ASSOCIATIVE MEMORY WILL BE FLUSHED
				; AND THE NEW MAPPING WILL BE IN AFFECT
	POPJ	P,		;RETURN

MAPUEI::PUSHJ	P,SAVE3##	;SAVE P1-P3
MAPUE1:	MOVE	P1,T1		;P1 = THE PAGE NUMBER OF THE FIRST PAGE
				; IN THE EVM THAT BELONGS TO THIS JOB
	SUBI	P1,400		;MAPPED ADDRESSES START AT 128K
	ROT	P1,-1		;DIVIDE BY 2 AND PUT THE REMAINDER IN HIGH ORDER BIT
	MOVEI	P2,.EPPM##(P1)	;FORM A BYTE POINTER TO THE EXEC MAP
	TLO	P2,442200	;ASSUME AN EVEN PAGE
	SKIPGE	P1		;WAS IT EVEN?
	HRLI	P2,222200	;NO, START WITH THE RIGHT HALF WORD
	LDB	P1,[POINT 9,T3,26]
	ROT	P1,-1		;DIVIDE BY 2 AND PUT THE REMAINDER IN HIGH ORDER BIT
	MOVEI	P3,.UPMP(P1)	;FORM A BYTE POINTER TO THE USER'S MAP
	SKIPL	P1		;FIRST PAGE EVEN
	TLOA	P3,442200	;YES, THE FIRST PAGE IS MAPPED BY THE LEFT HALF WORD
	HRLI	P3,222200	;NO, MAPPED BY THE RIGHT HALF WORD
MAPUE2:	ILDB	P1,P3		;COPY A PORTION OF THE USER'S MAP TO
	TRZ	P1,760000	;CLEAR ALL ACCESS BITS
	TRO	P1,PM.ACC+PM.WRT	;ACCESS ALLOWED, CONCEALED,  AND WRITEABLE
	IDPB	P1,P2		; THE EXEC MAP
	SOJG	T2,MAPUE2	;COPY AS MANY PAGES AS ARE TO BE MAPPED IN EVM
	DPB	T1,[POINT 9,T3,26]
				;FORM AN EXEC VIRTUAL ADDRESS FROM THE EXEC
				; PAGE NUMBER AND THE USER VIRTUAL ADDRESS
	POPJ	P,		;RETURN
;ROUTINE TO MAP A USER BUFFER IN EXEC VIRTUAL MEMORY
;CALLING SEQUENCE:
;	MOVE	T1,BUFFER SIZE
;	MOVE	T3,USER VIRTUAL ADDRESS OF BUFFER
;	MOVE	F,ADDRESS OF THE DDB
;	PUSHJ	P,GTEVBF
;	RETURN HERE ONLY IF REQUEST COULD NEVER BE SATISFIED (THERE WILL
;	NEVER BE ENOUGH SLOTS AVAILABLE IN THE EXEC MAP)
;	RETURN HERE - T1=BYTE (18)0(9) EXEC VIRTUAL PAGE # (9) # OF EXEC PAGES
;	T3 = THE EXEC VIRTUAL ADDRESS OF THE BUFFER

GTEVBF::SUBI	T1,2		;COMPUTE THE UPPER BOUND ON THE NUMBER OF PAGES
	IDIVI	T1,PAGSIZ##+2	; OF EXEC VIRTUAL MEMORY WHICH MIGHT BE
	ADDI	T1,2		; REQUIRED TO COVER THIS BUFFER OR IOWD
	CAMLE	T1,EVBMAX##	;WILL THAT NUMBER OF PAGES EVER BE AVAILABLE?
	POPJ	P,		;NO, ERROR RETURN
	PUSH	P,T1		;SAVE NUMBER OF PAGES BEING REQUESTED
GTEVB1:	PUSH	P,T3		;SAVE THE USER VIRTUAL ADDRESS
	PUSHJ	P,GETEVM	;ATTEMPT TO GET ENOUGH PAGES TO SATISFY THE REQUEST
	  JRST	GTEVBW		;NOT ENOUGH AVAILABLE (WAIT FOR SOME TO BE FREED UP)
	POP	P,T3		;RESTORE THE USER'S VIRTUAL ADDRESS
	MOVE	T2,(P)		; AND THE NUMBER OF PAGES
	PUSHJ	P,MAPUEV	;MAP THE BUFFER OR IOWD IN THE EXEC MAP
	MOVE	T1,T3		;T1 = EXEC VIRTUAL ADDRESS OF THE BUFFER OR IOWD
	POP	P,T2		;MAKE T1 = EXEC VIRTUAL ADDRESS OF SAME
	DPB	T2,[POINT 9,T1,35]
	JRST	CPOPJ1##	;GIVE OK RETURN
GTEVBW:	POP	P,T3		;RESTORE T3
	PUSHJ	P,EVWAIT##	;WAIT UNTIL SOME EVM IS FREED UP
	MOVE	T1,(P)		;RESTORE THE NUMBER OF PAGES REQUIRED
	JRST	GTEVB1		;TRY AGAIN
;SUBROUTINE TO GET EXEC VIRTUAL MEMORY
;CALLING SEQUENCE:
;
;	MOVE	T1,NUMBER OF CONTIGOUS PAGES REQUIRED
;	PUSHJ	P,GETEVM
;	...	ERROR RETURN - NOT ENOUGH AVAILABLE, T1 = LARGEST NUMBER SEEN
;	...	OK RETURN - T1 = PAGE NUMBER OF FIRST AVAILABLE PAGE

GETEVM::MOVEI	T2,EVMPTR##	;POINT TO EXEC-MAP USAGE TABLE
	PUSHJ	P,GETBIT##	;GET, SET BITS IN THE TABLE FOR THESE PAGES
	  POPJ	P,		;NOT ENOUGH AVAILABLE, RETURN WITH T1= LARGEST HOLE
	MOVEI	T1,400(T1)	;MAKE RELATIVE LOCATION IN THE MAP INTO PAGE NUMBER
	JRST	CPOPJ1##	;AND GIVE SUCCESS RETURN



;ROUTINE TO GIVE BACK SLOTS IN THE EXEC MAP
;CALLING SEQUENCE:
;	MOVE	T1,NUMBER OF PAGES
;	MOVE	T2,EXEC VIRTUAL ADDRESS
;	PUSHJ	P,GIVEVM
;	ALWAYS RETURN HERE

GIVEVM::LDB	T2,[POINT 9,T2,26]
	SUBI	T2,400		;CHANGE PAGE NUMBER INTO BIT POSITION
	IDIVI	T2,^D36		;WHICH WORD
	HRLS	T2		;PUT WORD NUMBER IN THE LEFT HALF
	ADD	T2,EVMPTR##	;MAKE AOBJN POINTER POINT TO THE WORD CONTAINING
				; THE FIRST BIT TO CLEAR
	PUSH	P,T4		;SETZRS CLOBBER T4
	PUSHJ	P,SETZRS##	;GIVE BACK THE EVM
	PUSHJ	P,EVFREE##	;WAKE UP ALL WAITERS FOR EVM
	SETZM	EVREQ##		;SO NEXT CALLER TO EVWAIT WILL WAIT (IMMEDIATELY)
	JRST	T4POPJ##	;RETURN
;ROUTINE TO CONVERT AN IOWD TO ABSOLUTE IOWDS
;FOLLOWING THE PAGING OF A JOB
;CALLING SEQUENCE:
;	MOVE	T2,IOWD
;	MOVEI	P1,0		;FIRST CALL
;	MOVE	P3,LOC OF CHANNEL DATA BLOCK
;	LH(P3)=1 IF STORE EXPECTED CHAN TERM WORD
;	MOVE	P4,FRAME-COUNT,,CHARS/WD IF DX10 CHL
;	PUSHJ	P,MAPIOW
;	RETURN HERE IF NOT ENOUGH MONITOR FREE CORE
;	RETURN HERE - P2=ADDRESS OF FIRST IOWD
;	P1=WHERE NEXT IOWD WILL BE STORED

MAPIO::	TLNN	T2,-1		;0 OR CHANNEL JUMPS ARE ILLEGAL
	STOPCD	CPOPJ,DEBUG,IEZ,  ;++IOWD EQUALS ZERO
	PUSHJ	P,SVEUB		;SAVE AND SETUP UBR
	PUSH	P,U		;SAVE U
	LDB	U,[POINT 2,CHB22B##(P3),1]
IFN FT22BIT,<
				;GET CHL TYPE INFO
	HLL	U,P4		;PRESERVE FRAME-COUNT
>
	PUSH	P,T1		;SAVE ALL ACS THAT ARE USED SINCE THEY
	PUSH	P,P4		; ARE PROBABLY IMPORTANT TO THE CALLERS
	PUSH	P,P3		; OF MAPIOW
	PUSH	P,T2		; ..
	PUSH	P,T3		; ..
	PUSH	P,T4		; ..
	JUMPN	P1,MAPIO1	;P1 IS NON-ZERO IF NOT THE FIRST CALL
	PUSHJ	P,GCH4WD	; ..
	  JRST	MAPIO8		;NONE AVAILABLE
	MOVE	P1,T1		;ADDRESS OF THE FOUR WORD BLOCK
	MOVE	P2,T1		;ADDRESS OF THE IOWD LIST
	HRLI	P1,-3		;THE NUMBER OF WORDS LEFT IN THIS BLOCK
	SETZM	3(P1)		;ZERO THE LAST WORD OF THE BLOCK
MAPIO1:	PUSHJ	P,CHKMOR	;GET ANOTHER FOUR WORD BLOCK AND LINK IT
				; TO THE CURRENT BLOCK IF ABOUT TO USE
				; THE LAST WORD OF THE CURRENT BLOCK
	  JRST	MAPIO8		;NO MORE FOUR WORD BLOCKS
	MOVE	P4,-2(P)	;RESTORE THE IOWD TO P4
	HRRZ	T2,P4		;ADDRESS-1 WHERE I/O WILL START
	MOVE	T3,DEVMOD(F)
IFE FTSPL,<
	TLNN	T3,DVDSK	;IF A DSK
>
IFN FTSPL,<
	SKIPL	DEVSPL(F)	;SPOOLED DDBS ARE ALWAYS A DSK
	TLNE	T3,DVDSK		;IS A DSK
	CAIA
>
	JRST	MAPI1B
IFE FTVM<
	SKIPL	DEVSWP##(F)	;IF NOT THE SWAPPER
>
	JUMPL	S,MAPIO6	; DONT UNRELOCATE IF MONITOR IO
MAPI1B:	MOVE	R,JBTADR##(J)	;ADDRESS OF THE JOB DATA AREA
	PUSHJ	P,CHKHS		;SEE IF A HIGH SEGMENT SAVE IS IN PROGRESS
IFE FTVM,<
	CAIA
	SKIPLE	J,JBTSGN##(J)	;YES, J = HIGH SEGMENT NUMBER
	SKIPN	T1,JBTADR##(J)	;EXEC VIRTUAL ADDRESS OF THIS SEGMENT
				; (DEVICE ROUTINES THINK THEY ARE RELOCATING
				; THE IOWD BY ADDING THIS)
	STOPCD	.,JOB,IRE,	;++IOWD RELOCATION ERROR
	CAILE	J,JOBMAX##	;HIGH SEG?
	MOVEI	T1,342000	;YES, USE STD ADDR
	SUBI	T2,-1(T1)	;SUBTRACT OUT "RELOCATION" AND ACCOUNT
				; FOR THE FACT THAT IOWDS ARE ADDRESS-1
	HRRZS	T2		;IN CASE OF MORE THAN 437 PAGES
	LSH	T2,W2PLSH##	;CONVERT TO PAGE NUMBER
	PUSHJ	P,SNPAGS	;GET THE ABSOLUTE PAGE NUMBER OF THIS PAGE
	MOVE	P3,T1		;SAVE THAT IN P3
	MOVE	T2,P4		;T2 AND P4 = IOWD+1
	HLROS	P4		;P4 = -WORD COUNT
	ADDI	T2,1
MAPIO2:	SKIPN	T3,P3		;T3 = CURRENT ABSOLUTE PAGE NUMBER
	STOPCD	.,JOB,APE,	;++ABSOLUTE PAGE EXCEEDED
				; IOWD HAS BEEN ADDRESS CHECKED)
	MOVEI	T1,0		;T1 = AMOUNT ACCUMULATED SO FAR
	LSH	T3,P2WLSH##	;MOVE PAGE NUMBER TO THE HIGH ORDER THIRTEEN
				; BITS OF THE ADDRESS
	ANDI	T2,PG.BDY##	;GET THE STARTING WORD ADDRESS WITHIN THE PAGE
	ADD	T2,T3		;T2 = ABSOLUTE ADDRESS
	SUBI	T2,1		;MAKE T2 AN IOWD
	PUSH	P,T2		;SAVE THE ADDRESS
	ANDI	T2,PG.BDY##	;EXTRACT THE WORD NUMBER
	SUBI	T2,PAGSIZ##-1	;CALCULATE THE NUMBER OF WORDS TO DO INTO THIS PAGE
	SKIPN	T2		;IF ITS ZERO DO A WHOLE PAGE WORTH
MAPIO3:	MOVNI	T2,PAGSIZ##	; ..
	SUB	P4,T2		;ADD -NUMBER OF WORDS ON THIS PAGE TO 
				; IOWD WORD COUNT
	ADD	T1,T2		;ACCUMULATE IN TOTAL WORD COUNT
	JUMPGE	P4,MAPIO4	;JUMP IF THE ORIGIONAL WORD COUNT IS EXHAUSTED
IFN FT22BIT,<
	SETZ	T3,		;SET T3 SO TEST WILL FAIL IF 22-BIT CHAN AND
	SKIPE	U		; NO ROOM FOR ANOTHER PAGE IN THE IOWD
	CAML	T1,[EXP -37777+PAGSIZ##] ;OTHERWISE SET T3=CURRENT PAGE
>
	MOVE	T3,P3		;T3 = CURRENT PAGE NUMBER WITHIN SEGMENT
	HRRZ	P3,PAGTAB(P3)	;P3 = NEXT PAGE NUMBER WITHIN SEGMENT
	CAIN	P3,1(T3)	;ARE THE TWO PAGES ADJACENT IN PHYSICAL MEMORY?
>	;END FTVM
IFN FTVM,<
	  JRST	MAPI1C		;NO, GET VIRT ADR THE NORMAL WAY
	MOVE	T1,P4		;YES, IOWD TO T1
	SUBI	T1,(R)		;UNRELOCATE IT
	PUSHJ	P,UVACK		;COMPUTE STARTING ADR FOR THIS PART
	AOJA	T2,MAPI1D	;AND CONTINUE
MAPI1C:	SKIPN	T1,JBTADR##(J)	;EXEC VIRTUAL ADDRESS OF THIS SEGMENT
				; (DEVICE ROUTINES THINK THEY ARE RELOCATING
				; THE IOWD BY ADDING THIS)
	STOPCD	.,JOB,IRE,	;++IOWD RELOCATION ERROR
	SUBI	T2,-1(T1)	;SUBTRACT OUT "RELOCATION" AND ACCOUNT
				; FOR THE FACT THAT IOWDS ARE ADDRESS-1
	HRRZS	T2		;NEEDED IF SEG GTR THAN 437 PAGES
MAPI1D:	LSH	T2,W2PLSH##	;CONVERT TO PAGE NUMBER
	ROT	T2,-1		;SET UP A BYTE POINTER TO THE PAGE IN THE UPMP
	ADDI	T2,.UPMP
	TLZE	T2,400000
	TLOA	T2,(<POINT 18,0,35>)
	TLO	T2,(<POINT 18,0,17>)
	MOVE	P3,T2		;SAVE POINTER IN P3
	MOVE	T2,P4		;T2 AND P4 = IOWD
	HLROS	P4		;P4 = -WORD COUNT
	ADDI	T2,1		;POINT AT REAL ADR
MAPIO2:	LDB	T3,P3		;T3 = CURRENT ABSOLUTE PAGE NUMBER
	TRNN	T3,PM.ACC
IFN FTEXE,<
	SKIPGE	USRHCU##	;IF A SAVE IS IN PROGRESS,
	SKIPA			; THEN, THIS IS OK
>;END OF INF FTEXE
	JRST	S..AAO		;ACCESS ALLOWED OFF
				; IOWD HAS BEEN ADDRESS CHECKED)
	MOVEI	T1,0		;T1 = AMOUNT ACCUMULATED SO FAR
	LSH	T3,P2WLSH##	;MOVE PAGE NUMBER TO THE HIGH ORDER THIRTEEN
				; BITS OF THE ADDRESS
	ANDI	T2,PG.BDY##	;GET THE STARTING WORD ADDDESS WITHIN THE PAGE
	ADD	T2,T3		;T2 = ABSOLUTE ADDRESS (IOWD STYLE)
	SUBI	T2,1		;MAKE AN IOWD
	PUSH	P,T2		;SAVE THE ADDRESS
	ANDI	T2,PG.BDY##	;EXTRACT THE WORD NUMBER
	SUBI	T2,PAGSIZ##-1	;CALCULATE THE NUMBER OF WORDS TO DO INTO THIS PAGE
	SKIPN	T2		;IF ITS ZERO DO A WHOLE PAGE WORTH
MAPIO3:	MOVNI	T2,PAGSIZ##	; ..
	SUB	P4,T2		;ADD -NUMBER OF WORDS ON THIS PAGE TO 
				; IOWD WORD COUNT
	ADD	T1,T2		;ACCUMULATE IN TOTAL WORD COUNT
	JUMPGE	P4,MAPIO4	;JUMP IF THE ORIGIONAL WORD COUNT IS EXHAUSTED
IFN FT22BIT,<
	SETZ	T3,		;SET T3 SO TEST WILL FAIL IF 22-BIT CHAN AND
	SKIPE	U		; NO ROOM FOR ANOTHER PAGE IN IOWD
	CAML	T1,[EXP -37777+PAGSIZ##] ;OTHERWISE SET T3=CURRENT PAGE
>
	LDB	T3,P3		;T3 = CURRENT PAGE NUMBER WITHIN SEGMENT
	ILDB	T4,P3		;T4 = NEXT PAGE NUMBER WITHIN SEGMENT
	TRNN	T4,PM.ACC	;ACCESS ALLOWED ON?
	STOPCD	.,JOB,AAO,	;++ACCESS ALLOWED IS OFF
	TRZ	T3,760000	;CLEAR ACCESS BITS
	TRZ	T4,760000	;CLEAR OUT THE ACCESS BITS
	CAIN	T4,1(T3)	;ARE THE TWO PAGES ADJACENT IN PHYSICAL MEMORY?
>	;END IFN FTVM
	JRST	MAPIO3		;YES, CONTINUE ON CURRENT IOWD
	MOVEI	T2,0		;T2 = FIRST ADDRESS
	POP	P,(P1)		;STORE THE IOWD ABSOLUTE ADDRESS
IFE FT22BIT,<
	HRLM	T1,(P1)		;AND THE WORD COUNT (NUMBER OF WORDS MAPPED SO FAR)
>
IFN FT22BIT,<
	PUSHJ	P,DXFIX		;ADJUST IOWD IF A DX10
	  JRST	MAPIO8		;NO SPACE
	JUMPL	U,MAPIO7	;GO IF FRAMECOUNT EXHAUSTED
>
	AOBJN	P1,MAPIO2	;CONTINUE IF THERE IS ROOM IN THE FOUR WORD BLOCK
	PUSHJ	P,GETMOR	;GET ANOTHER FOUR WORD BLOCK
	  JRST	MAPIO8		;WHOOPS! NONE AVAILABLE
	MOVEI	T2,0		;START AT WORD NUMBER ZERO ON THIS PAGE
	JRST	MAPIO2		;MAP THE REST OF THE IOWD
MAPIO4:	POP	P,(P1)		;STORE THE IOWD ABSOLUTE ADDRESS
	ADD	P4,T1		;ADD THE RESIDUAL WORD COUNT TO THE ACCUMULATED
				; WORD COUNT
IFE FT22BIT,<
	HRLM	P4,(P1)		;STORE WORD COUNT IN IOWD
>
IFN FT22BIT,<
	MOVE	T1,P4		;PUT WD CNT INTO T1
	PUSHJ	P,DXFIX		;PERFORM FIXUPS FOR DX10
	  JRST	MAPIO8		;OUT OF SPACE
>
	JRST	MAPIO7		;AND GIVE THE WIN RETURN
MAPIO6:
IFE FT22BIT,<
	MOVEM	P4,(P1)		;THE I/O IS INTO A MONITOR BUFFER SO STORE
>
IFN FT22BIT,<
	MOVEM	T2,0(P1)	;STORE ADDRESS
	HLRE	T1,P4		;GET WORD COUNT
	PUSHJ	P,DXFIX		;FIDDLE WITH DX10 IOWDS
	  JRST	MAPIO8		;NO ROOM
>
				; THE ALREADY ABSOLUTE IOWD AND RETURN
				;AND FALL INTO MAPIO7
				;MAPIO6 FALLS INTO HERE
MAPIO7:	AOBJN	P1,.+1		;BUMP THE POINTER TO THE NEXT FREE WORD
	SETZM	(P1)		;ZERO IT SO THE LIST IS TERMINATED
	AOS	-7(P)		;SET FOR SKIP (WIN) RETURN
MAPIO8:
IFE FT22BIT,<
	HLRE	P4,-1(P1)	;GET NEG WORD CNT FROM LAST IOWD
	HRRZ	T1,-1(P1)	;GET START OF DATA FROM LAST IOWD
	SUB	T1,P4		;DETERMINE ENDING DATA ADDRESS
	HRL	T1,P1		;PUT ADDR OF END OF IOWD LIST
>
	SKIPGE	-3(P)		;IF WE WANT IT STORED,
	TRNE	U,1		;TYPE 0 OR 2 CONTROLLER?
	JRST	MAPIO9		;NO, DON'T DO NEXT
IFN FT22BIT,<
	HRRZS	U		;CLEAR POSSIBLE FRAMECOUNT
	LSH	U,-1
	MOVE	T3,P1		;GET ADDR OF LAST IOWD FOR BYTE PTR'S
	LDB	T1,ADRPT2##(U)	;GET ADDR FIELD FROM LAST IOWD
	HLRO	P4,-1(T3)	;WORD COUNT
	ASH	P4,@ASH22B##(U)	;4 BITS DON'T COUNT IF 22-BIT
	SUB	T1,P4		;DETERMINE ENDING DATA ADDRESS
	DPB	P1,ADRPT4##(U)	;PUT ADDR OF END OF IOWD LIST
>
	MOVE	P3,-3(P)
	MOVEM	T1,CHNTCW##(P3)
MAPIO9:	POP	P,T4		;RESTORE ACS
	POP	P,T3		; ..
	POP	P,T2		; ..
	POP	P,P3		; ..
	POP	P,P4		; ..
	POP	P,T1		; ..
	PJRST	UPOPJ##		;GIVE WIN OR LOSE RETURN
;SUBROUTINE TO CHECK TO SEE IF THE CURRENT FOUR WORD BLOCK IS EXHAUSTED
; AND IF SO GET ANOTHER ONE IF ANY ARE AVAILABLE.  IF THE NEXT FOUR WORD
; BLOCK IT OBTAINS IS ADJACENT TO THE CURRENT ONE, IT SIMPLY RETURNS.  IF
; IT IS NOT, A LINK WORD LINKING THE CURRENT FOUR WORD BLOCK TO THE
; NEW FOUR WORD BLOCK IS SETUP IN THE FOURTH WORD OF THE CURRENT BLOCK
;CALLING SEQUENCE:
;	MOVE	P1,AOBJN POINTER TO CURRENT BLOCK
;	PUSHJ	P,CHKMOR
;	...	RETURN HERE IF NO MORE FOUR WORD BLOCKS
;	...	RETURN HERE IF CURRENT FOUR WORD BLOCK NOT FILLED OR
;		NEXT FOUR WORD BLOCK OBTAINED 
;P1 = AOBJN POINTER TO CURRENT OR NEW BLOCK

CHKMOR::JUMPL	P1,CPOPJ1##	;CONTINUE IF ANY WORDS LEFT IN THIS BLOCK
GETMOR::PUSHJ	P,GCH4WD	;GET 1 CORE BLOCK
	  POPJ	P,		;NO MORE AVAILABLE
	CAIE	T1,1(P1)	;IS THIS BLOCK ADJACENT TO THE LAST BLOCK?
	JRST	GETMR1		;NO, ADD A LINK
	HRLI	P1,-4		;YES, FOUR WORDS LEFT TO GO (LAST WORD IN
				; THE LAST BLOCK AND THREE WORDS IN NEW BLOCK)
	JRST	CPOPJ1##	;RESTORE T2 AND GIVE OK RETURN
GETMR1:
IFN FT22BIT,<
	TRC	U,3
	TRCN	U,3		;CHECK CHL TYPE
	HRLI	T1,CCHJGO##	;DX10 STYLE CHL JUMP
>
	MOVEM	T1,0(P1)	;LINK TO THE NEW BLOCK
	MOVE	P1,T1		;P1 = POINTER TO NEW BLOCK
	HRLI	P1,-3		;NUMBER OF WORDS LEFT TO GO IN THE CURRENT BLOCK
	JRST	CPOPJ1##	;AND SKIP RETURN
IFN FT22BIT,<
;ROUTINE USED TO HANDLE 22-BIT CHNLS AND PERFORM IOWD TRANSFORMATIONS
;FOR THE DX10 TAPE CHL. CALLING SEQUENCE:
;	MOVE T1,-WDS TO XFER
;	MOVE P1,ADDRS OF CURRENT IOWD
;	CHARS/WD WAS FOUND IN THE ORIGINAL CALL TO MAPIO
;	PUSHJ P,DXFIX
;	  ...		;RETURN HERE IF NO MORE FREE SPACE
;	  ...		;RETURN HERE IF OK

DXFIX:	HRRZ	T4,U
	CAIE	T4,3		;CHECK CHL TYPE
	JRST	[DPB T1,WDCPNT##(U)
		 JRST CPOPJ1##]	;HANDLE NON-DX10 CHLS
	MOVE	T4,-5(P)	;RESTORE CHAR/WD
	IMULI	T1,0(T4)	;CONVERT TO BYTE COUNT
	AOS	0(P1)		;DX10 LIKES ADDRS RATHER THAN ADDRS-1
	HLRZ	T3,U		;FRAME-COUNT USER SET
	JUMPE	T3,DXFIX0	;NONE
	MOVNS	T3
	CAML	T3,T1		;MORE THAN HE WANTS?
	MOVE	T1,T3		;YES, GET WHAT WAS REQUESTED
	HRLZ	T3,T1		;FRAMECOUNT
	ADDB	T3,U		;UPDATE MAX LEFT
	TLNN	T3,-1		;ANY LEFT?
	HRROS	U		;NO, INDICATE WE'RE DONE
DXFIX0:	CAML	T1,[-17777]	;ROOM FOR THIS
	JRST	DXFIX2		;YES - JUST STORE AND EXIT
	MOVE	T3,MCHTAB(T4)	;MAX CHARS / XFER CMD
	SUB	T1,T3		;SUBTRACT MAX FOR THIS ONE
	DPB	T3,WDCPNT##(U)	;STORE IN IOWD
	PUSH	P,0(P1)		;SAVE PNTR
	AOBJN	P1,DXFIX1	;SEE IF ROOM FOR MORE
	PUSH	P,T1		;NO -SAVE COUNT
	PUSHJ	P,GETMOR	;GET MORE SPACE
	  JRST	DXFIX3		;RAN OUT OF SPACE
	MOVEI	T2,0		;RESTORE T2
	POP	P,T1		;RESTORE COUNT
DXFIX1:	POP	P,T3		;GET LAST POINTER
	MOVE	T4,-5(P)	;RESTORE T4 (CHARS/WD)
	ADD	T3,MWDTAB(T4)	;ADD MAX WORDS OFFSER
	MOVEM	T3,0(P1)	;NEW PARTIAL PNTR
	JRST	DXFIX0		;PROCEED

DXFIX2:	DPB	T1,WDCPNT##(U)	;STORE RESIDUE
	JRST	CPOPJ1##	;SUCCESS RETURN

DXFIX3:	POP	P,T1		;PRUNE PDL
	JRST	TPOPJ##		;PRUNE & EXIT (FAIL)
;THE BYTE PACKING MODES OF THE DX10 WILL ALLOW 4,5 & 6 BYTES / WORD
;THESE TABLES ARE USED TO TRANSLATE THIS INFO INTO 1) THE MAX CHARS
;THAT WILL EXACTLY FILL THE 2) MAX NO. OF WDS PER IOWD
;ALLOWING 2^13-1 BYTES / IOWD.
MCHTAB=.-4
	-<17777/4>*4		;4 BYTE/WD = 8188 BYTES
	-<17777/5>*5		;5 BYTE/WD = 8190 BYTES
	-<17777/6>*6		;6 BYTE/WD = 8190 BYTES

MWDTAB=.-4
	17777/4			;4 BYTE/WD = 2047 WDS
	17777/5			;5 BYTE/WD = 1638 WDS
	17777/6			;6 BYTE/WD = 1365 WDS

>	;END IFN FT22BIT
;ROUTINE TO RETURN FREE CORE USED FOR MAPPING IOWDS.
;CALLING SEQUENCE:
;	MOVE	T1,ADDRESS OF IOWD LIST
;	PUSHJ	P,RTNIOW
;	ALWAYS RETURN HERE

RTNIOW::PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,T1		;P1 = ADDRESS OF THE IOWD LIST
RTNIO1:	MOVEI	T1,1		;GIVE BACK ONE FOUR WORD BLOCK
	MOVE	T2,P1		;ADDRESS OF THE BLOCK
	MOVE	T3,3(P1)	;LAST WORD OF BLOCK
	TLNN	T3,-1		;AN IOWD?
	SKIPA	P1,T3		;NO, THEN THIS IS THE LAST BLOCK
				; OR A LINK TO THE NEXT BLOCK
	ADDI	P1,4		;ADDRESS OF THE NEXT BLOCK
				; (ITS ADJACENT TO THE CURRENT BLOCK)
	PUSHJ	P,RCH4WD	;RETURN BLOCK TO MONITOR FREE CORE
	JUMPE	P1,CPOPJ##	;JUMP IF THIS IS THE LAST BLOCK
	JRST	RTNIO1		;GIVE UP ALL THE BLOCKS


;ROUTINE TO OBTAIN A LOWER-CORE 4-WORD BLOCK
GCH4WD::MOVEI	T1,1		;JUST WANT 1 BLOCK
	MOVEI	T2,LOWPTR##	;POINT TO LOWER-CORE FREE-CORE TABLE
	PUSHJ	P,GETBIT##	;GET, SET THE BIT
	  POPJ	P,		;NONE AVAILABLE, LOSE
	LSH	T1,2		;CONVERT TO 4-WORD STYLE
	ADD	T1,LOWLOC##	;CONVERT TO ACTUAL ADDRESS
	SETZM	3(T1)		;ZERO THE LAST WORD OF THE CURRENT BLOCK
	PJRST	CPOPJ1##	;AND TAKE GOOD RETURN


;ROUTINE TO RETURN LOWER-CORE 4-WORD BLOCKS
RCH4WD::SUB	T2,LOWLOC##	;CONVERT TO RELATIVE ADDRESS
	LSH	T2,-2		;/4 TO CONVERT TO BITS
	IDIVI	T2,^D36		;COMPUTE WORD ADR, POSITION IN WORD
	HRLS	T2
	ADD	T2,LOWPTR##	;SET AOBJN POINTER FOR SETZRS
	PJRST	SETZRS##	;CLEAR THE BITS AND RETURN
;SUBROUTINE TO CHECK TO SEE IF THE CURRENT I/O OPERATION IS A
; HIGH SEGMENT SAVE
;CALLING SEQUENCE:
;	MOVE	F,DDB ADDRESS
;	MOVE	R,LOW SEGMENT ADDRESS
;	PUSHJ	P,CHKHS
;	RETURN HERE IF NORMAL I/O
;	RETURN HERE IF HIGH SEGMENT SAVE

CHKHS:	PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,DEVMOD(F)	;DEVICE DESCRIPTORS
	TLNE	P1,DVDSK	;DSK I/O?
	SKIPL	DEVSWP##(F)	;YES, SWAPPING I/O?
	SKIPL	P1,JOBHCU##(R)	;NO, IS A SAVE OR GET IN PROGRESS?
	POPJ	P,		;NOT SAVE/GET
	TLNE	P1,3		;DOING THE I/O TO SAVE A HIGH SEGMENT?
	POPJ	P,		;NO, NORMAL I/O
IFN FTEXE,<
	PUSH	P,J		;SAVE J
	LDB	J,PJOBN##	;GET CURRENT JOB NUMBER
	PUSHJ	P,CHKEXE##	;IS THIS AN EXE FILE SAVE?
	JRST	JPOPJ##		;YES, EXIT AND DO NOTHING
	POP	P,J		;NO, RESTORE J
>;END OF IFN FTEXE
	PJRST	CPOPJ1##	;YES, GIVE HIGH SEGMENT SAVE IN PROGRESS RETURN

;SUBROUTINE TO RETURN THE USER VIRTUAL ADDRESS OF THE
; CHECKSUM WORD
;CALLING SEQUENCE:
;	MOVE	T1,IOWD TO BE USED IN THE FILE TRANSFER (UNRELOCATED)
;	MOVE	R,LOW SEGMENT PROTECTION,, RELOCATION
;	PUSHJ	P,UVACKS
;	ALWAYS RETURN HERE - T2 = UVA OF THE CHECKSUM
;PRESERVES T1

UVACK:
UVACKS::HRRZ	T2,T1		;ADDRESS I/O WILL BE DONE FROM OR TO
	PUSHJ	P,CHKHS		;SEE IF SAVING A HIGH SEGMENT
	  POPJ	P,		;NO, NORMAL I/O RETURN
	SUBI	T2,.VJDT-.JDAT	;T2=ADDRESS WITHIN THE HIGH SEGMENT WHERE
				; OUTPUT WILL START
	PUSH	P,T2		;SAVE THAT
	PUSH	P,J		;SAVE J
	PUSH	P,T1		;AND T1
	LDB	J,PJOBN##	;GET JOB NUMBER
	PUSHJ	P,HSVAD##	;GET THE STARTING VIRTUAL ADDRESS OF THE
				; HIGH SEGMENT
	POP	P,T1		;RESTORE T1
	POP	P,J		;AND J
	ADDM	T2,(P)		;(P)=UVA OF FIRST WORD -1 TO BE OUTPUT
	JRST	T2POPJ##	;T2=UVA, AND RETURN
;SUBROUTINE TO GET EVM IF NEEDED FOR OUTPUT
;CALLING SEQUENCE:
;	MOVE	F,DDB ADDRESS
;	PUSHJ	P,GTOEVM
;	RETURN HERE
;NEVER RETURN IF TO MUCH EVM IS REQUIRED

GTOEVM::SKIPA	T3,PDVOAD##	;POINTER TO UVA OF THE BUFFER
;	PJRST	GTBEVM		;MAP THE BUFFER IN EVM


;SUBROUTINE TO GET EVM IF NEEDED FOR INPUT
;CALLING SEQUENCE:
;	MOVE	F,DDB ADDRESS
;	PUSHJ	P,GTIEVM
;	RETURN HERE
;NEVER RETURN IF TO MUCH EVM IS REQUIRED

GTIEVM::MOVE	T3,PDVIAD##	;POINTER TO UVA OF THE BUFFER
;	PJRST	GTBEVM		;MAP THE BUFFER IN EVM
;FALL INTO GTBEVM
;SUBROUTINE TO ACCOUNT FOR THE FACT THAT BUFFERS
; ARE TWO WORDS LONGER THAN THE NUMBER OF DATA
; WORDS IN THE BUFFER AND THE FACT THAT THE LINK
; WORD IS REALLY THE SECOND WORD OF THE BUFFER
;CALLING SEQUENCE:
;	MOVE	T3,POINTER TO THE CURRENT BUFFER (UVA)
;	PUSHJ	P,GTBEVM
;	RETURN HERE T1 = # OF PAGES + STARTING PAGE #, T3 = EVA OF BUFFER
;NEVER RETURN IF NOT ENOUGH EVM

GTBEVM:	PUSHJ	P,MAPDEV	;IS CURRENT DEVICE A PTY, TTY, OR ON A CHANNEL?
	POPJ	P,		;YES, DO NOT ALLOCATE ANY EVM
	PUSH	P,T3		;SAVE THE USER VIRTUAL ADDRESS OF THIS BUFFER
				; SO CAN RETURN EVM ON HUNG DEVICE, ETC.
	HRRZ	T3,@T3		;USER VIRTUAL ADDRESS OF THE BUFFER
	EXCTUX	<HLRZ T1,(T3)>	;SIZE OF THE BUFFER

	TRZ	T1,IOUSE	;T1 = NUMBER OF DATA WORDS - USE BIT
	SUBI	T3,1		;POINT TO ACTUAL FIRST WORD OF THE BUFFER
	ADDI	T1,2		;ACCOUNT FOR THE TWO OVERHEAD WORDS IN
				; THE BUFFER
	PUSHJ	P,GTEVBF	;MAP THE BUFFER IN EVM - WAIT UNTIL
				; SOME IS AVAILABLE IF NECESSARY
	  JRST	ADRERR##	;NEVER WILL BE ENOUGH EVM
	HRL	T1,@(P)		;SAVE USER VIRTUAL ADDRESS OF THE BUFFER
	ADDI	T3,1		;BUMP BUFFER ADDRESS TO THE LINK WORD
	CONO	PI,PI.OFF	;GUARD AGAINST INTERRUPTS
	MOVEM	T1,DEVEVM(F)	;SAVE THE STARTING PAGE NUMBER AND NUMBER
				; OF PAGES OF EVM FOR ADVANCING BUFFERS
				; AND RETURNING EVM
	DPB	T3,(P)		;STORE THE EVA OF THE BUFFER FOR THE DEVICE ROUTINE
	CONO	PI,PI.ON	;NOW, ALLOW INTERRUPTS AGAIN
	JRST	T2POPJ##	;RETURN

;SUBROUTINE TO RESTORE EVM AFTER GIVING IT
; UP ON A CALL TO THE SCHEDULER (CONTROL BUSY, HUNG DEVICE, ETC.)
;CALLING SEQUENCE:
;	MOVE	F,ADDRESS OF DEVICE DATA BLOCK
;	MOVE	S,DEVIOS(F)	;DEVICE STATUS
;	PUSHJ	P,RSTEVM
;	RETURN HERE IF NO ADDRESS CHECK WITH DEVEVM(F) SETUP

RSTEVM::LDB	T1,PIOMOD##	;GET DATA MODE
	CAIL	T1,SD		;DUMP MODE?
	PJRST	DMPEV		;YES, GET EVM DUMP MODE STYLE
	TLNE	S,IO		;BUFFERED MODE, INPUT OR OUTPUT?
	PJRST	GTOEVM		;OUTPUT, GET BUFFERED OUTPUT EVM
	PJRST	GTIEVM		;INPUT, GET BUFFERED INPUT EVM
;SUBROUTINE TO DETERMINE IF A DEVICE NEEDS EVM TO DO DUMP
; MODE I/O AND IF SO TO SCAN THE IOWD LIST TO FIND THE
; IOWD WHICH HAS THE LARGEST WORD COUNT AND ALLOCATE
; ENOUGH EVM TO COVER THAT IOWD.
;CALLING SEQUENCE:
;	MOVE	M,USER VIRTUAL ADDRESS OF IOWD LIST
;	MOVE	F,ADDRESS OF DEVICE DATA BLOCK
;	PUSHJ	P,DMPEV
;	RETURN HERE IF NO ADDRESS CHECK WITH DEVEVM(F) SETUP
;PRESERVES T1

DMPEV::
	PUSHJ	P,SAVE4##	;SAVE P1-P4
IFN FTVM,<
	PUSH	P,U		;SAVE U
	MOVEI	U,0		;ASSUME THE DEVICE DOES NOT REQUIRE EXEC VIRTUAL
				; MEMORY TO DO I/O (DSK, MTA, TTY, PTY)
>
	PUSHJ	P,MAPDEV	;NOT A KA10, NEED EVM TO DO I/O?
IFE FTVM,<
	  POPJ	P,		;EVM NOT REQUIRED (KA10, CHANNEL DEVICE, TTY, OR PTY)
>
IFN FTVM,<
	TLO	U,400000	;EVM NOT REQUIRED - SET U NEGATIVE
>
	PUSH	P,T1		;SAVE DISPATCH ADDRESS
	PUSH	P,M		;SAVE THE UUO FOR THE DEVICE ROUTINE
	SOS	M		;COMPENSATE FOR GETWD1
	MOVEI	P2,0		;LARGEST WORD COUNT SEEN SO FAR
	MOVEI	P3,10000	;GUARD AGAINST A LOOP (GOTO IOWDS)
DMPEV1:	PUSHJ	P,GETWD1##	;GET AN IOWD
	JUMPE	T1,DMPEV4	;JUMP IF LAST IOWD IN THE LIST
	HLRO	P1,T1		;THIS IOWD'S WORD COUNT
	TLNE	T1,-1		;A GOTO WORD?
	JRST	DMPEV2		;NO, A REAL IOWD
	HRRI	M,-1(T1)	;A GOTO WORD (POINTS TO THE NEXT IOWD)
	JRST	DMPEV3		;GET NEXT IOWD
DMPEV2:	MOVNS	P1		;P1 = POSITIVE WORD COUNT FOR THIS IOWD
	CAMLE	P1,P2		;GREATER THAN THE LARGEST WORD COUNT SEEN SO FAR?
	MOVE	P2,P1		;YES, REMEMBER IT AS LARGEST SEEN
IFN FTVM,<
	PUSHJ	P,CHKHS		;HIGH SEGMENT SAVE?
	  JRST	DMPE2A		;NO
	PUSH	P,T1		;YES, SAVE IOWD
	PUSHJ	P,HSVAD##	;GET START ADR OF HI SEG
	POP	P,T1		;RESTORE START ADR OF IOWD
	ADDI	T1,-1000(T2)	;POINT TO START OF HIGH SEG
DMPE2A:	MOVEI	T1,1(T1)	;START ADR OF THE IOWD
	MOVE	T2,P1		;TOP ADR OF THE IOWD
	ADDI	T2,-1(T1)
	PUSHJ	P,TRNGE##	;MAKE SURE THE REQUIRED PAGES ARE IN CORE
>
DMPEV3:	SOJG	P3,DMPEV1	;GET NEXT IOWD IN THE LIST
	JRST	ADRERR##	;TOO MANY IOWDS (PROBABLY A GOTO WORD LOOP,
				; STOP THE JOB AND REPORT THE ERROR)

DMPEV4:	POP	P,M		;RESTORE THE UUO AND THE POINTER TO THE FIRST
				; IOWD IN THE LIST
IFN FTVM,<
	JUMPL	U,DMPEV5	;DONT ACTUALLY NEED EVM IF U NEGATIVE
>
	PUSHJ	P,GETWDU##	;GET THE FIRST IOWD IN THE LIST AGAIN
	HRRZ	T3,T1		;USER VIRTUAL ADDRESS WHERE I/O WILL START
	MOVE	T1,P2		;NUMBER OF WORDS OF EXEC VIRTUAL MEMORY REQUIRED
				; TO COVER THE LARGEST IOWD FOUND IN THE IOWD
				; LIST
	PUSHJ	P,GTEVBF	;GET ENOUGH EVM TO COVER THE LARGEST WORD IN
				; THE LIST (WAIT UNTIL AVAILABLE IF NECESSARY)
	JRST	ADRERR##	;WHOOPS! NEVER WILL BE ENOUGH
	MOVEM	T1,DEVEVM(F)	;DEVEVM = BYTE (18)0(9)EV PAGE #(9)# OF PAGES
IFE FTVM,<
	PJRST	TPOPJ##		;RESTORE T1 AND RETURN
>
IFN FTVM,<
DMPEV5:	POP	P,T1		;RESTORE DISPATCH ADDRESS
	JRST	UPOPJ##		;RESTORE U AND RETURN
>
;ROUTINE TO RETURN ANY EVM A DEVICE MAY HAVE WHEN A SHARABLE RESOURCE
; WHICH CURRENTLY BELONGS TO THE JOB WHICH HAS THE DEVICE IS GIVEN UP.
;CALLING SEQUENCE:
;	MOVE	F,ADDRESS OF DEVICE DATA BLOCK OR 0 IF NONE
;	PUSHJ	P,RTEVM
;ALL ACS ARE RESPECTED.

RTEVM::	SKIPE	F		;IS THIS A RESOURCE ASSOCIATED WITH I/O?
				; I.E., IS THERE A DEVICE DATA BLOCK?
	SKIPN	DEVEVM(F)	;DOES THE JOB HAVE EVM?
	POPJ	P,		;NO, JUST RETURN
	PUSHJ	P,SAVT##	;IT IS THE TRADITION NOT TO CLOBBER ACS HERE
	PUSHJ	P,SVEUF		;SAVE THE UBR AND SET IT UP SO CAN ADDRESS CURRENT JOB
	PJRST	RTNEVM		;GIVE UP EVM FOR MAPPING I/O IF ANY

;HERE TO GIVE UP EVM THAT THIS DEVICE HAS FOR INPUT OPERATIONS

RTEVMI::HLRZ	T3,DEVEVM(F)	;USER VIRTUAL ADDRESS OF CURRENT BUFFER
	JUMPE	T3,CPOPJ##	;ZERO MEANS NO EVM REQUIRED FOR THE I/O

	HRLI	T3,R		;LITE R IN THE LEFT HALF TO SIGNAL USER
				; VIRTUAL ADDRESS
	PJRST	RTIEVM		;GIVE BACK THE EVM

;HERE TO GIVE UP EVM THAT THIS DEVICE HAS FOR OUTPUT OPERATIONS

RTEVMO::HLRZ	T3,DEVEVM(F)	;USER VIRTUAL ADDRESS OF CURRENT BUFFER
	JUMPE	T3,CPOPJ##	;ZERO MEANS NO EVM REQUIRED FOR THE I/O

	HRLI	T3,R		;LITE R IN THE LEFT HALF TO SIGNAL USER
				; VIRTUAL ADDRESS
	PJRST	RTOEVM		;GIVE BACK THE EVM
;ROUTINE TO RETURN SLOTS IN THE EXEC MAP USED TO MAP USER BUFFERS
;CALLING SEQUENCE:
;
;	MOVE	T3,USER VIRTUAL ADDRESS OF BUFFER
;	PUSHJ	P,RTNEVM
;	ALWAYS RETURN HERE

RTNEVM::MOVS	T3,DEVEVM(F)	;ANY EVM ALLOCATED TO THIS DEVICE?
	JUMPE	T3,CPOPJ##	;NO, JUST RETURN
	TRNN	T3,-1		;DUMP MODE I/O?
	JRST	RTNEV1		;YES, DON'T CLOBBER DEVXAD
	HRLI	T3,R		;LITE R IN THE LEFT HALF TO SIGNAL THAT
				; DEVIAD/DEVOAD NOW CONTAINS A USER VIRTUAL ADDRESS
	TLNN	S,IO		;OUTPUT?
	JRST	RTIEVM		;NO, GO RETURN INPUT EVM
RTOEVM::DPB	T3,PDVOAD##	;STORE UVA IN DEVOAD
	JRST	RTNEV1		;RETURN EVM
RTIEVM::DPB	T3,PDVIAD##	;STORE UVA IN DEVIAD
RTNEV1:	HRRZ	T2,DEVEVM(F)	;PAGE NUMBER AND NUMBER OF PAGES OF EVM
	LDB	T1,[POINT 9,T2,35]
	SETZM	DEVEVM(F)	;FLAG NO LONGER ANY EVM
	PJUMPN	T1,GIVEVM	;RETURN THE EVM TO THE FREE POOL AND TELL
				; THE SCHEDULAR THAT EVM IS AVAILABLE IF ANY
				; JOB IS WAITING FOR SOME
	POPJ	P,		;RETURN


;ROUTINE TO CALL THE SCHEDULER AND REMEMBER IF A JOB HAS EVM OR NOT.
; IF SO, RESTORE THE EVM WHEN THE JOB BECOMES RUNNABLE AGAIN.
;PRESERVES ALL ACS

RMEVM::	SKIPE	F		;IS THERE A DDB?
	SKIPN	DEVEVM(F)	;AND DOES IT HAVE EVM?
	PJRST	WSCHD1##	;NO--JUST RESCHEDULE
	TRNE	S,IOACT		;DON'T RETURN EVM IF THE DDB
	JRST	WSCHD1##	; IS I/O ACTIVE
	PUSHJ	P,RTEVM		;YES--RETURN THE EVM SINCE JOB MAY GET SWAPPED
	PUSHJ	P,WSCHD1##	;RESCHEDULE
	PUSHJ	P,SAVT##	;SAVE T2-T4
	PJRST	RSTEVM		;RESTORE THE EVM
;ROUTINE TO ADVANCE A BUFFER IN EXEC VIRTUAL MEMORY
;CALLING SEQUENCE:
;
;	MOVE	T3,XWD NEXT BUFFER SIZE,NEXT USER VIRTUAL BUFFER ADDRESS
;	RETURN HERE IF NOT ENOUGH PAGES ALLOCATED IN EXEC MAP TO ADVANCE BUFFER
;	RETURN HERE - BUFFER ADVANCED
;			T1 = EXEC VIRTUAL ADDRESS OF BUFFER
;			T3 = USER VIRTUAL ADDRESS OF BUFFER

ADVEVM::PUSH	P,T3		;SAVE BUFFER SIZE,,BUFFER ADDRESS
	HRRZ	T1,DEVEVM(F)	;BYTE (18)0(9) EXEC VIRTUAL PAGE #(9)# OF EXEC PAGES
	HRLM	T3,DEVEVM(F)	;STORE UVA OF NEXT BUFFER
	HLRZ	T2,T3		;GET BUFFER SIZE
;DON'T NEED TO SUBTRACT 2 SINCE THE BUFFER IS ACTUALLY
; TWO WORDS LONGER THAN THE NUMBER OF DATA WORDS IT CONTAINS
;	SUBI	T2,2		;COMPUTE THE UPPER BOUND ON THE NUMBER
	IDIVI	T2,PAGSIZ##+2	; OF PAGES WHICH MAY BE REQUIRED TO
	ADDI	T2,2		; MAP THIS BUFFER IN EXEC VIRTUAL MEMORY
	LDB	T3,[POINT 9,T1,35]
	CAMLE	T2,T3		;DOES THE DEVICE HAVE A ENOUGH EVM TO MAP THIS BUFFER?
	JRST	T3POPJ##	;NO, STOP THE I/O (ENOUGH PAGES WILL BE
				; AQUIRED THE NEXT TIME AROUND AT UUO LEVEL)
	LDB	T1,[POINT 9,T1,26]
	HRRZS	T3,(P)		;T3 = USER VIRTUAL ADDRESS OF THE NEXT BUFFER
	SOS	T3		;T3 = ADDRESS OF FIRST WORD OF THE BUFFER
	PUSHJ	P,MAPUEV	;MAP THE NEXT BUFFER IN THE EXEC MAP
	EXCH	T3,(P)		;RESTORE THE USER VIRTUAL ADDRESS OF THE
				; BUFFER IN CASE I/O MUST BE STOPPED FOR
				; SOME OTHER REASON
	AOS	(P)		;BUMP BUFFER POINTER TO THE LINK WORD
	PJRST	TPOPJ1##	;T1 = EXEC VIRTUAL ADDRESS OF THE BUFFER
SUBTTL	SEGCON - SEGMENT CONTROL MODULE

;ROUTINE TO SAVE THE ABSOLUTE ADDRESS OF A HIGH SEGMENT AND RETURN
; ITS VIRTUAL ADDRESS (CALLED FROM REMAP)
; J=HI SEG NUMBER
; T1=NEW HI SIZE
; T2=WHERE,, NEW LOW SIZE

NEWHGH::PUSHJ	P,SAVE3##	;SAVE P1-P3
	HRRZ	P2,T2		;SAVE WHERE,,NEW LOW SEGMENT SIZE
	HLRZS	T2		;WHERE TO PUT THE HIGH SEGMENT
	ANDI	T2,777000	;MAKE SURE ITS ON A PAGE BOUNDARY
	JUMPN	T2,NEWHG0	;JUMP IF HIGH SEGMENT STARTING ADDRESS SPECIFIED
	TRNE	P2,400000	;IS THE LOW SEGMENT BIGGER THAN 128K?
	SKIPA	T2,P2		;YES, HIGH SEGMENT ORIGIN IS FIRST PAGE ABOVE
				; THE LOW SEGMENT
	MOVEI	T2,377777	;NO, HIGH SEGMENT GOES AT 400000
	MOVEI	T2,1(T2)	;HIGH SEGMENT ORIGIN (ALSO CLEAR LEFT HALF OF T2)
NEWHG0:	MOVE	P3,.C0JOB##	;CURRENT JOB NUMBER
	MOVEM	R,JBTADR##(P3)	;STORE PREVIOUS PROTECTION,,JDAT IN CASE OF ERROR
IFN FTVM,<
	MOVEI	T3,1(T1)	;NUMBER OF WORDS IN NEW HIGH SEGMENT
	MOVEI	T1,1(P2)	;ADDRESS WHERE REMAP STARTS
	LSHC	T1,W2PLSH##	;T1=FROM PAGE, T2=TO PAGE
	LSH	T3,W2PLSH##	;NUMBER OF PAGES
	HLRZ	T4,SGAEXT##(R)	;FILE EXTENSION
	SUBI	T4,'SHR'	;T4=0 IF THE HIGH SEGMENT IS SHARABLE
	PJRST	NREMAP##	;REMAP IT
>
IFE FTVM,<
	JUMPLE	T2,CPOPJ##	;DON'T ALLOW HIGH SEGMENT AT PAGE ZERO
	HRRZ	P1,T1		;NEW HIGH SEGMENT SIZE
	ADDI	P1,(T2)		;HIGH SEGMENT SIZE PLUS WHERE IT STARTS
	TLNN	P1,-1		;WILL THE END OF THE HIGH SEGMENT BE OUTSIDE
				; OF THE USER'S ADDRESSING SPACE? (.GT. 256K)
	CAIG	T2,(P2)		;OR WILL THE LOW SEGMENT AND HIGH SEGMENT OVERLAP?
	POPJ	P,		;YES, LOSE
	HRLM	P2,JBTADR##(P3)	;STORE NEW HIGHEST ADDRESS IN THE LOW SEGMENT
	HRLI	T1,.VJDT	;EXEC VIRTUAL ADDRESS OF THE VESTIGUAL JOB
				; DATA AREA
	LSH	T2,W2PLSH##	;CONVERT HIGH SEGMENT ADDRESS TO PAGE NUMBER
	DPB	T2,JBYHSO##	;STORE ORIGIN OF THE HIGH SEGMENT
	ROT	P2,W2PLSH##-1	;CONVERT TO PAGE NUMBER AND ODD OR EVEN PAGE
				; IN THE HIGH ORDER BIT
	TRZ	P2,400000	;DON'T LET BIT 8 OF USER-SPECIFIED
				; HISEG ORIGIN SPILL OVER
	MOVEI	P1,.UPMP(P2)	;ADDRESS OF THE WORD IN THE MAP WHICH CONTAINS
				; THE ABSOLUTE PAGE NUMBER OF THE LAST PAGE
				; OF THE LOW SEGMENT
	HRLI	P1,222200	;ASSUME AN EVEN PAGE NUMBER (I.E., MAPPED BY THE
				; LEFT HALF WORD)

	SKIPGE	P2		;IS IT EVEN?
	HRLI	P1,002200	;NO, ODD - MAPPED BY THE RIGHT HALF WORD
	LDB	P2,P1		;GET ABSOLUTE PAGE NUMBER OF LAST PAGE IN
				; THE LOW SEGMENT
	TRZ	P2,760000	;CLEAR ACCESS BITS
	HLLZS	PAGTAB(P2)	;INDICATE LAST PAGE IN THE LOW SEGMENT IN PAGTAB
	ILDB	T2,P1		;GET THE ABSOLUTE PAGE NUMBER OF THE FIRST
				; PAGE IN THE HIGH SEGMENT
	DPB	T2,JBYHSA##	;STORE IT FOR MAPPING THIS HIGH SEGMENT INTO
				; FUTURE USER'S ADDRESSING SPACES
	TRO	T2,PM.ACC+PM.WRT;ACCESS ALLOWED AND WRITABLE
	HRLM	T2,.UPMP+.MVJDT	;MAP .VJDT IN THE PER-PROCESS MAP
	JRST	CPOPJ1##	;GIVE OK RETURN (HIGH SEGMENT WON'T OVERLAP
				; LOW SEGMENT
>
;ROUTINE TO MAKE ANY WORD OF ANY JOB ADDRESSABLE
; (IN FACT WRITABLE) BY MAPPING IT THROUGH THE
; PER PROCESS MAP OF THE CURRENT JOB
;CALLING SEQUENCE:
;	MOVE	T2,USER VIRTUAL ADDRESS TO BE MAPPED
;	MOVE	J,JOB NUMBER OF JOB CONTAINING THE WORD
;	PUSHJ	P,MAPWRD
;OR	PUSHJ	P,MAPHC		;TO MAP JOBHCU
;	...	RETURN HERE
;ON RETURN FROM CALL TO MAPWRD T2=EVA OF WORD
;ON RETURN FROM CALL TO MAPHC R=JOBHCU
;MAPHC PRESERVES T2

MAPHC::	PUSH	P,T2		;SAVE T2
IFE FTVM,<
	MOVEI	T2,0		;JOB DATA AREA STARTS AT USER 0
>
IFN FTVM,<
	MOVSI	T2,1		;UVA OF THE UPMP
>
	PUSHJ	P,MAPWRD	;MAKE THE JOB DATA AREA ADDRESSABLE
IFE FTVM,<
	HRR	R,T2		;RH(R)=EVA OF JOB DATA AREA
>
IFN FTVM,<
	HRRI	R,.JDAT-.UPMP(T2)
>
	JRST	T2POPJ##	;RESTORE T2 AND RETURN

MAPWRD::
	PUSHJ	P,SCPCDB##	;POINT P4 AT THIS CPUSCDB
	PUSH	P,T2		;SAVE UVA
	ROT	T2,W2PLSH##-1	;CONVERT TO PAGE #/2 - REMAINDER IN HIGH BIT
	MOVEI	T1,.TEMP(T2)	;T1=ADDRESS OF TEMP. PP SLOT
	HRLI	T1,222200	;ASSUME WORD IN EVEN PAGE
	SKIPGE	T2		;IS IT?
	HRLI	T1,002200	;NO - ODD PAGE
	HRRZ	T2,JBTUPM##(J)	;ADDRESS OF TARGET JOB'S UPMP
	TRO	T2,PM.ACC+PM.WRT;INSURE ACCESS ALLOWED
	HRRM	T2,.UPMP+.MTEMP	;MAKE THE TARGET JOB'S UPMP ADDRESSABLE
	CLRPGT	(P4)		;CLEAR THE AM SO NEW MAPPING
	     	      		; IS USED
	LDB	T2,T1		;GET MAPPING FOR PAGE CONTAINING WORD
	TRO	T2,PM.ACC+PM.WRT;MAKE SURE CAN WRITE
	HRRM	T2,.UPMP+.MTEMP	;MAKE THE WORD ADDRESSABLE
	CLRPGT	(P4)		;CLEAR THE AM SO NEW MAPPING
	     	      		; IS IN EFFECT
	MOVEI	T1,.TEMP/1000	;PAGE # IN EV ADDRESSING SPACE
	DPB	T1,[POINT 9,(P),26] ;EVA OF WORD
	JRST	T2POPJ##	;RESTORE EVA AND RETURN
;ROUTINE TO MAKE AVAILABLE A PAGE MAP SLOT IN EVA SPACE
;MAY ONLY BE CALLED AT INTERUPT LEVEL
;CALLING SEQUENCE:
;	MOVE	P4,ADR OF CPU DATA BLOCK
;	PUSHJ	P,MAPLOC
;	RETURN HERE
;   C(T1) := BYTE PNTR TO EPMP SLOT
;   C(T3) := RELATIVE PAGE # IN EPMP

MAPLOC::CONI	PI,T1		;GET PIS IN PROGRESS
	ANDI	T1,II.IPA	;CLEAR ALL BITS EXCEPT PIS IN PROGRESS
	JFFO	T1,.+2		;FIND OUT THE HIGHEST PI IN PROGRESS, I.E.,
				; THE ONE THAT THIS CODE IS BEING EXECUTED AT
	STOPCD	.,STOP,NPP,	;++NO PI IN PROGRESS
				; NO PAGE IN THE EXEC MAP FOR MAPPING THE SCAN
	SUBI	T2,25		;T2=0-6 FOR PI 1-7 IN PROGRESS
	MOVE	T3,T2		;CALCULATE THE EXEC VIRTUAL ADDRESS FOR
	LSH	T3,P2WLSH##	; USE IN THE SWEEP RELATIVE TO PI TEMPORARIES.
	ROT	T2,-1		;DIVIDE BY 2 AND PUT THE REMAINDER IN HIGH ORDER BIT
	MOVEI	T1,.MERPL(T2)
	ADD	T1,.CPTOS##(P4)	;T1=ADDRESS IN THE MAP OF SLOT USED FOR SCAN
	HRLI	T1,(<POINT 18,0,17>) ;ASSUME LEFT HALF WORD
	SKIPGE	T2		;IS IT AN ODD PAGE?
	HRLI	T1,(<POINT 18,0,35>) ;YES, THEN ITS THE RIGHT HALF WORD
	POPJ	P,		;RETURN
SUBTTL	ERRCON - ERROR HANDLING MODULE

;SUBROUTINE TO SWEEP MEMORY TO FIND ADDRESS AND CONTENTS OF BAD WORDS
;IT CALLS CPU INDEPENDENT SUB.(PARERR##) TO RECORD DATA ON EACH BAD WORD
;CALL:	MOVE	P4,ADR OF CPU DATA BLOCK
;	PUSHJ	P,@.CPMPS##(P4)
;	ALWAYS RETURN WHEN SWEEP OVER (EVEN IF SERIOUS ERROR)
;SWEEP CORE IN ASCENDING ADDRESSES EVEN THOUGH SLOWER, SO DATA STORED ASCENDING
; FOR ERROR REPORTING WITH DAEMON

IFN FTMEMPAR,<			;MEMORY PARITY ANALYSIS
	XP	PARDLY,5	;NO. OF SOJ INSTR. TO DELAY SO PARITY CAN BE TESTED

CPIMPS::PUSHJ	P,SAVE4##	;SAVE P1-P4 FOR BAD ADR. CONTENTS AND WORKING ACS
	PUSHJ	P,MAPLOC	;GET EXEC MAP SLOT
	PUSH	P,T1		;SAVE BYTE POINTER TO EXEC MAP SLOT
	MOVEI	P1,0		;SCAN ALL OF MEMORY STARTING WITH FAST ACS
				; FOR CONVENIENCE (KI10 ALWAYS HAS FAST ACS)
	MOVEI	P3,PM.ACC+PM.WRT
				;START AT PAGE 0. PAGE ATTRIBUTES TO ALLOW
				; ACCESS AND WRITING (TO ATTEMPT REPAIR BELOW)
	LDB	T4,[POINT 14,MEMSIZ##,26]
				;T4=NUMBER OF PAGES TO SCAN (AVOID NXM)
	SKIPA	U,[POINT 1,NXMTAB##] ;BYTE POINTER TO TABLE REFLECTING EXISTANT MEMORY
MPSLP1:	AOS	P3		;STEP TO NEXT PAGE
	SOJL	T4,TPOPJ##	;RESTORE T1 AND RETURN IF SCANNED ALL OF MEMORY
	ILDB	T1,U		;DOES THIS PAGE EXIST?
	JUMPN	T1,MPSLP1	;JUMP IF NOT TO AVOID REFERENCING NON-EXISTANT
				; PAGE
	MOVEI	P1,.ERPIL(T3)	;START AT THE BEGINNING OF THE PAGE
	DPB	P3,(P)		;MAP THE CURRENT PAGE
	CLRPGT	(P4)		;CLEAR THE ASSOCIATIVE SO THE NEW
				; WILL BE USED
	MOVEI	T2,PAGSIZ##	;NO. OF WORDS TO SCAN BEFORE REMAPPING

IFN FTMONL,<
	SKIPE	MOFLPG##	;SETTING MEMORY ON-LINE IN PROGRESS?
	MOVEI	T2,MEMITL##	;YES, ONLY REFERENCE ENOUGH TO BE SURE
				; INTERLEAVING IS RIGHT
>
MPSLP2:	CONSZ	PI,@.CPAPP##(P4)  ;APR PI IN PROGRESS (I.E. SCANNING
				; AT APR INTERRUPT LEVEL?
	TDZA	T1,T1		;YES, DON'T WAIT AT THE SOJG.
	MOVEI	T1,PARDLY	;NO. OF SOJ TO INSURE PARITY FLAG INT. OR ON
;SPECIAL INSTRUCTION ADDRESS - REFERENCE MEMORY TO SEE IF BAD
	XP	CPIMPI,MPI+1	;PC VALUE WHEN APR GETS PARITY INT.
				;USED BY APR PI ROUTINE TO MAKE INSTR. SKIP
MPI:	SKIP	P2,(P1)		;DOES THIS LOC HAVE BAD PARITY (PICKUP IN P2)?
	SOJG	T1,.		;DELAY HERE SO APR INT. WILL OCCUR WITH
				; PC AT A KNOWN PLACE IN MONITOR
	JRST	[IFN FTMEMNXM,<
		TRNN S,UE.PEF
		JRST	[CONSO APR,IP.NXM
			JRST MPSLP4
			CONO APR,IP.CNM
			JRST MPSLP3]>
		CONSO APR,IP.PAR
		JRST MPSLP4
		CONO PI,XI.CPE
		JRST	.+1]

;HERE ON BAD WORD FOUND (NXM OR PARITY) - APR OR PI 7 (APR INTERRUPT ADDED 2 TO PC)

IFN FTMEMNXM,<
	TRNE	S,UE.PEF	;A PARITY ERROR?
>
	MOVEM	P2,(P1)		;FIX UP BAD PARITY SO THAT NUMBER OF BAD
				; PARITY WORDS IN MEMORY IS MINIMIZED.  THIS
				; DECREASES CHANCES OF NOT DETECTING
				; READ-PAUSE-WRITE SITUATION (0 ERRORS)
				; BECAUSE ANOTHER BAD WORD IS PRESENT
MPSLP3:	MAP	T1,(P1)		;GET THE PAGE NUMBER OF THE PAGE WHICH
				; CORRESPONDS TO THE EXEC VIRTUAL ADDRESS IN P1
	PUSH	P,T2
	PUSH	P,T3		;SAVE THE POSITION IN THE MAP
	PUSH	P,T4		;SAVE # OF PAGES TO SCAN
	PUSH	P,P1		;SAVE THE EVA
	DPB	T1,[POINT 13,P1,26]
				; P1=ABSOLUTE ADDRESS OF THE WORD WITH BAD PARITY
	PUSHJ	P,CPIASN	;CONVERT TO SEG NUMBER, (J), REL ADR (T1)
	  SETOM	T1		;FLAG ABS. ADR NEITHER IN MONITOR NOR A SEGMENT.
	PUSHJ	P,PARRBD##	;RECORD BAD DATA (T1=REL ADR, P1=BAD ADR,P2=
				; BAD CONTENTS)
	POP	P,P1		;RESTORE P1
	POP	P,T4		; AND T4
	POP	P,T3		; AND T3
	POP	P,T2		; AND T2
MPSLP4:	SOJLE	T2,MPSLP1	;IF CURRENT PAGE IS FINISHED, MAP THE NEXT PAGE
	AOJA	P1,MPSLP2	;STEP TO NEXT ABSOLUTE ADDRESS

>	;STILL IN FTMEMPAR CONDITIONAL
IFN FTMEMPAR!FTLOCK!FTMEMNXM,<
;SUBROUTINE - ABSOLUTE (ADDRESS TO) SEGMENT NUMBER
;CALL:	MOVE	P1,ABS.ADR(18 BIT FOR KA-10, 22 BIT FOR KI10)
;	TLO	P1,400000	;IF VIRTUAL ADDRESS IS NOT REQUIRED
;	PUSHJ	P,@CP.ASN(P4)
;	  ERROR RETURN IF NOT IN MONITOR OR A HIGH OR LOW SEGMENT,
;	OK RETURN J=0 IF IN MONITOR, OR HIGH OR LOW SEG, T1=REL. ADR
;CAN BE CALLED AT APR PI OR CLK PI(7).  CANNOT BE CALLED AT UUO LEVEL
;NOTE:  REL ADR. IS NOT VIRTUAL ADR ON HIGH SEGS
; SINCE THAT IS JOB DEPENDENT IF LOW SEG GR 400000

CPIASN::SETZB	T2,J		;ASSUME IN MONITOR (JOB 0 NOT A LEGAL JOB #)
	LDB	T1,[POINT 13,P1,26]  ;SET REL. ADR. FROM ABS. ADR IN MONITOR
	MOVE	T1,PAGTAB(T1)
	TLNE	T1,MONTRB	;IS THIS A MONITOR PAGE?
	JRST	CPOPJ1##	;YES, GIVE OK RETURN WITH J=0
	MOVE	T3,P1		;SET T3=ABSOLUTE ADDRESS OF ERROR WORD
	LSH	T3,W2PLSH##	;T3=ABSOLUTE PAGE NUMBER OF PAGE CONTAING BAD WORD
	MOVEI	T2,JOBMAX##	;SCAN TO SEE IF BAD ADDRESS IS IN A UPMP
AUPLOP:	HRRZ	T1,JBTUPM##(T2)	;T1=PAGE NUMBER OF THE UPMP
	CAIE	T1,(T3)		;BAD WORD IN THIS UPMP?
	SOJG	T2,AUPLOP	;NO, SCAN ALL USER PAGE MAP PAGES
	JUMPG	T2,CPOPJ1##	;JUMP IF THE PARITY ERROR WAS IN A UPMP
	PUSHJ	P,SSEUB
;LOOP - SCAN ALL HIGH AND LOW SEGS
ASNLOP:	MOVEI	T1,0		;ASSUME PARITY ERROR IS IN PAGE 0 OF THIS SEGMENT
IFN FTVM,<
	MOVSI	T2,SHRSEG	;SHARABLE SEGMENT BIT
	CAILE	J,JOBMAX##	;A LOW SEGMENT?
	TDNE	T2,JBTSTS##(J)	;NO, IS IT SHARABLE
>
	SKIPN	JBTADR##(J)	;IS THIS JOB OR HIGH SEG IN CORE?
	JRST	ASNAOJ		;NO, LOOK AT THE NEXT SEGMENT
	LDB	T2,JBYHSA##	;ASSUME ITS A HIGH SEGMENT
				; GET ITS STARTING PAGE NUMBER
	CAILE	J,JOBMAX##	;IS IT A HIGH SEGMENT?
	JRST	ASNHGH		;YES
	PUSHJ	P,STEUB		;NO, MAKE ITS FIRST PHYSICAL PAGE NUMBER ADDRESSABLE
				; LOW SEGMENT ADDRESS IN THE UPMP IS
				; VALID SINCE PARITY ERROR IS NOT IN A
				; UPMP (VERIFIED ABOVE)
	LDB	T2,JBYLSA##	;STARTING PAGE NUMBER OF LOW SEGMENT
ASNHGH:	CAIN	T2,(T3)		;IS THIS PAGE THE SAME PAGE WHICH CONTAINED AN ERROR?
	JRST	ASNFND		;YES, COMPUTE THE RELATIVE ADDRESS OF THE
				; WORD WITHIN THE SEGMENT WHICH CONTAINS THE ERROR
	HRRZ	T2,PAGTAB(T2)	;T2=PAGE NO. OF NEXT PAGE IN THIS SEGMENT
	SKIPE	T2		;IS IT THE LAST PAGE IN THIS SEGMENT?
	AOJA	T1,ASNHGH	;NO, LOOK AT ALL THE PAGES IN THIS SEGMENT
ASNAOJ:	CAIG	J,JBTMAX##	;LOOKED AT ALL SEGMENTS?
	AOJA	J,ASNLOP	;NO, LOOK AT NEXT SEGMENT
	POPJ	P,		;NOT IN MONITOR OR ANY JOB
;HERE TO COMPUTE RELATIVE ADDRESS OF PARITY ERROR BY CONCATINATING RELATE
; PAGE NUMBER AND WORD NUMBER WITHIN THE PAGE
ASNFND:	JUMPL	P1,CPOPJ1##	;RETURN IF NOT INTERESTED IN VIRTUAL ADR
IFN FTVM,<
	CAIG	J,JOBMAX##	;A SHARABLE HIGH SEGMENT?
	PUSHJ	P,PHYPVP##	;NO, CONVERT FROM PHYSICAL TO VIRTUAL PAGE NUMBER
>
	LSH	T1,P2WLSH##	;MOVE PAGE NUMBER TO PAGE NUMBER FIELD
	DPB	P1,[POINT 9,T1,35]
				; AND WORD NUMBER
	JRST	CPOPJ1##	;AND GIVE OKAY RETURN
>	;END IFN FTMEMPAR!FTLOCK!FTMEMNXM
IFN FTMEMNXM,<

;SUBROUTINE TO FIX CORE ALLOCATION TABLES AFTER NON-EXISTANT MEMORY
; IS ENCOUNTERED
;CALLING SEQUENCE:
;	MAKE NXMTAB REFLECT CURRENT STATE OF MEMORY, GIVE BACK CORE
;	BELONGING TO ALL SEGMENTS WHICH OVERLAP NXM, AND
;	PUSHJ	P,CPINXF	;FIX UP RELEVANT TABLES AND VARIABLES
;RETURNS CPOPJ IF NEW VALUE OF CORMAX .LE. OLD VALUE OF CORMAX (SOME
; JOB MAY BE TOO BIG TO SWAP IN), CPOPJ1 IF ALL IS OK.

CPINXF::PUSHJ	P,SAVE2##	;SAVE WORKING ACS
	SETZB	T1,T2		;INITIALIZE INDEXS INTO PAGTAB AND NXMTAB
	MOVSI	T3,400000	;FIRST BIT TO LOOK AT IN NXMTAB
	LDB	T4,[POINT 14,MEMSIZ##,26]
	MOVSI	P1,NXMBIT	;LOOK FOR NON-EXISTANT PAGES
	HRROI	P2,MPGSIZ##	;DECREASE MAXMAX BY 1 PAGE FOR EACH NON-EXISTANT PAGE SEEN
CPINX1:	TDNN	P1,PAGTAB(T1)	;PAGE ALREADY MARKED AS NON-EXISTANT?
	TDNN	T3,NXMTAB##(T2)	;NO, IS IT NON-EXISTANT NOW?
	JRST	CPINX2		;NO, FORGE AHEAD
	SKIPL	PAGTAB(T1)	;IS THIS NON-EXISTANT PAGE ON THE FREE CORE LIST?
	STOPCD	.,STOP,NPN,	;++NON-EXISTANT PAGE NOT FREE
	ADDM	P2,MAXMAX##	;DECREASE MAXMAX BY 1 PAGE
	HLLM	P1,PAGTAB(T1)	;AND MARK THIS PAGE AS NOW NON-EXISTANT
CPINX2:	ADDI	T1,1		;NEXT PAGE
	ROT	T3,-1		;NEXT BIT POSITION IN NXMTAB
	SKIPG	T3		;CROSSED A WORD BOUNDARY?
	ADDI	T2,1		;YES, BUMP TO NEXT WORD IN NXMTAB
	SOJG	T4,CPINX1	;LOOP OVER ALL PAGES
CPINX3:	MOVE	T1,PAGPTR##	;POINTER TO THE FREE CORE LIST
	JUMPE	T1,CPINX5	;JUMP IF THERE ARE CURRENTLY NO PAGES ON THE FREE LIST
	TDNN	P1,PAGTAB(T1)	;IS THIS PAGE NOW NON-EXISTANT?
	JRST	CPINX5		;NO
	MOVE	T2,PAGTAB(T1)	;YES, LINK FREE CORE LIST AROUND THE PAGE
	HRRZM	T2,PAGPTR##	;STORE NEW FIRST PAGE ON THE FREE CORE LIST
	SOS	CORTAL##	;DECREMENT COUNT OF POTENTIALLY FREE PAGES
	SOS	BIGHOL##	;DECREMENT COUNT OF FREE PAGES
	JRST	CPINX3		;CONTINUE TO LOOK AT PAGES AT THE BEGINNING
				; OF THE FREE CORE LIST
CPINX4:	MOVE	T1,T2		;CURRENT INDEX INTO PAGTAB
CPINX5:	HRRZ	T2,PAGTAB(T1)	;NEXT PAGE IN PAGTAB
	JUMPE	T2,CPINX6	;JUMP IF THIS IS THE END OF THE FREE CORE LIST
	TDNN	P1,PAGTAB(T2)	;IS THIS PAGE NOW NON-EXISTANT?
	JRST	CPINX4		;NO
	HRRZ	T2,PAGTAB(T2)	;YES, LINK THE FREE CORE LIST AROUND IT
	HRRM	T2,PAGTAB(T1)	; ..
	SOS	CORTAL##	;DECREMENT THE COUNT OF POTENTIALLY FREE PAGES
	SOS	BIGHOL##	;AND THE COUNT OF FREE PAGES
	JRST	CPINX5		;LOOP OVER THE ENTIRE FREE CORE LIST

; STILL IN FTMEMNXM
CPINX6:	MOVEI	T1,0		;INITIALIZE COUNT OF EXISTANT UNLOCKED PAGES
	MOVE	T2,MEMSIZ##	;PREVIOUS HIGHEST ADDRESS + 1
	SUB	T2,SYSSIZ##	;RANGE OF USERS CORE
	LSH	T2,W2PLSH##	;NUMBER OF PAGES FROM TOP OF THE MONITOR
				; TO THE PREVIOUS TOP OF MEMORY
	MOVE	T3,SYSSIZ##	;WHERE TO START LOOKING FOR UNLOCKED EXISTANT PAGES
	LSH	T3,W2PLSH##	;PAGE NUMBER TO START AT
CPINX7:	MOVE	P1,PAGTAB(T3)	;PAGE DESCRIPTOR BITS FROM PAGTAB
	TLNE	P1,LKBITS-MONTRB;IS THIS PAGE LOCKED OR NON-EXISTANT?
	JRST	CPINX8		;YES, DON'T CONSIDER IT IN COMPUTING NEW CORMAX
	MOVEI	T4,1(T3)	;HIGHEST EXISTANT PAGE + 1 THAT WAS SEEN
	TLNN	P1,MONTRB	;IS THIS A MONITOR PAGE?
	ADDI	T1,PAGSIZ##	;NO, INCREASE NEW CORMAX BY ONE PAGE
CPINX8:	ADDI	T3,1		;NEXT PAGE IN PAGTAB
	SOJG	T2,CPINX7	;LOOP OVER ALL PAGES
	MOVEI	T2,PAGTAB-1(T4)	;BYTE POINTER TO HIGHEST PAGE
	HRRM	T2,CORLST##	;STORE THAT FOR CHKTAL
	LSH	T4,P2WLSH##	;HIGHEST EXISTANT ADDRESS + 1
	MOVEM	T4,MEMSIZ##	;STORE THAT AS THE SIZE OF MEMORY
	CAML	T1,CORMAX##	;NEW CORMAX LESS THAN THE OLD CORMAX?
	AOSA	(P)		;NO, INDICATE ALL JOBS CAN STILL RUN
	MOVEM	T1,CORMAX##	;YES, STORE NEW VALUE OF CORMAX AND GIVE
				; A NON-SKIP RETURN TO INDICATE THAT SOME
				; JOBS MAY BE TO LARGE TO BE SWAPPED IN
	POPJ	P,		;RETURN

> ;END FTMEMNXM
IFN FTMONL,<

,;HERE TO SET MEMORY ON LINE, T1 = FIRST PAGE TO SET ON LINE, T2 = LAST
; PAGE + 1
MEMONL::HRLZ	S,T1		;STARTING PAGE TO SET ON LINE
	HRR	S,T2		;HIGHEST PAGE TO SET ON LINE
	PUSH	P,S		;SAVE THAT
	SKIPN	JBTADR##(J)	;DOES THIS JOB HAVE CORE?
	PUSHJ	P,GETMIN##	;NO, GET A MINIMUM AMOUNT FOR PDL, ETC.
	JUMPE	R,[POP	P,(P)	;COULDN'T GET IT THIS TICK
		   JRST	DLYCM##];GO AWAY AND TRY AGAIN NEXT TIME
	POP	P,S		;RESTORE RANGE OF ADDRESSES TO SET ON LINE
	PUSHJ	P,SAVCTX##	;SAVE THE JOB'S CONTEXT AND RETURN AT UUO LEVEL
				; (THE JOB'S CONTEXT MUST BE SAVED BECAUSE
				; IF SETTING THE MEMORY ON LINE CAUSES
				; A NXM, THE JOB'S CONTEXT WILL BE DESTROYED)
	HLRZ	T1,S		;RESTORE THE STARTING PAGE TO SET ON LINE
	HRRZ	T2,S		;AND THE HIGHEST PAGE TO SET ON LINE
	CAIG	T2,1000		;TRYING TO SET MEMORY ON LINE ABOVE 256K?
	JRST	MEMON5		;NO, CAN DO THAT WITHOUT CHECKING
IFN FT22BIT,<;HERE IF SETTING MEMORY ON LINE ABOVE 256K TO SEE IF ANY CHANNEL IS IN
; 18 BIT MODE
	HLRZ	T3,SYSUNI##	;ADDRESS OF THE FIRST UDB IN THE SYSTEM
MEMON1:	HRRZ	T4,UNICHN##(T3)	;ADDRESS OF THE CHANNEL DATA BLOCK FOR THIS UNIT
	SKIPL	CHB22B##(T4)	;IS THE CHANNEL IN 22 BIT MODE?
	JRST	MEMON4		;NO, CAN ONLY SET UP TO 256K ON LINE
	HLRZ	T3,UNISYS##(T3)	;ADDRESS OF THE NEXT UNIT DATA BLOCK
	JUMPN	T3,MEMON1	;JUMP IF NOT THE LAST
	SKIPN	T3,CNFMTA##	;ANY MAGTAPES?
	JRST	MEMON5		;NO
MEMON2:	HLRZ	U,TDVUDB##(T3)	;ADDRESS OF THE UDB FOR THIS DDB
	HRRZ	T4,TDVKDB##(T3)	;ADDRESS OF THE CONTROLLER DB FOR THIS UNIT
	HRRZ	T4,TKBCDB##(T4)	;ADDRESS OF THE CHANNEL DB FOR THIS CONTROLLER
	JUMPE	T4,MEMON3	;JUMP IF NOT A CHANNEL DEVICE
	SKIPL	CHB22B##(T4)	;IS IT IN 22 BIT MODE?
	JRST	MEMON4		;NO, CAN ONLY SET UP TO 256K ON LINE
MEMON3:	HLRZ	T3,DEVSER(T3)	;ADDRESS OF THE NEXT DDB
	JUMPE	T3,MEMON5	;ALL DONE IF THIS IS THE LAST DDB
	MOVE	T4,DEVMOD(T3)	;DEVICE CHARACTERISTICS
	TLNE	T4,DVMTA	;IS THIS A MTA DDB?
	JRST	MEMON2		;YES, MAKE SURE ALL CHANNELS ARE IN 22 BIT MODE
	JRST	MEMON5		;NO, ALL DONE
> ;END FT22BIT
MEMON4:	MOVEI	T2,1000		;REDUCE THE HIGHEST PAGE TO SET ON LINE
				; TO 256K SINCE SOME CHANNEL IS IN 18 BIT MODE

;STILL IN FTMONL
;HERE WHEN OPR IS REQUESTING .LE. 256K OR IF .GT. 256K, NO DF10 IN
; 18 BIT MODE WAS FOUND
MEMON5:	MOVE	T3,MEMSIZ##	;CURRENT HIGHEST ADDRESS IN THE MACHINE
	MOVE	T4,NWCORE##	;HIGHEST ADDRESS THAT CAN BE SET ON LINE
				; (CANNOT MAKE PAGTAB AND MEMTAB BIGGER)
	LSHC	T3,W2PLSH##	;CONVERT TO PAGES
	CAMG	T3,T4		;PICK THE BIGGER OF THE TWO AS THE
	MOVE	T3,T4		; HIGHEST ADDRESS THAT CAN BE SET ON LINE
	TRZE	T3,PG.BDY##	;ROUND UP TO A 256K BOUNDARY (IF NOT 
	ADDI	T3,PAGSIZ##	; ALREADY ON A 256K BOUNDARY
	CAMG	T3,T2		;IF ASKING FOR MEMORY ON LINE ABOVE THE
				; HIGHEST WHICH CAN BE DONE,
	MOVE	T2,T3		; SET ON UP TO THE HIGHEST THAT CAN BE DONE
	CAML	T1,T2		;LOWEST PAGE ABOVE THE HIGHEST PAGE?
	POPJ	P,		;YES, NOTHING TO SET ON LINE
	MOVE	P1,T1		;LOWEST PAGE TO SET ON LINE
	IDIVI	P1,^D36		;COMPUTE BIT POSITION AND WORD NUMBER WITHIN NXMTAB
	MOVNI	P2,-^D35(P2)	;BIT POSITION BYTE POINTER STYLE
	HRLI	P1,(POINT 1,0,0);FORM A 1 BIT BYTE POINTER TO NXMTAB
	DPB	P2,[POINT 6,P1,5]
	ADDI	P1,NXMTAB##	;BYTE POINTER TO BIT CORRESPONDING TO FIRST PAGE TO SET ON
	MOVSI	T3,NXMBIT	;BIT INDICATING NON-EXISTANT PAGE
	SETZB	T4,P2		;INITIALIZE FIRST AND HIGHEST NON-EXISTANT PAGES SEEN
	MOVEI	P3,PAGSIZ##	;TO UPDATE MAXMAX ON EACH PAGE SET ON LINE
MEMON6:	TDNN	T3,PAGTAB(T1)	;IS THIS PAGE NON-EXISTANT?
	JRST	MEMON8		;NO, ITS ALREADY ON LINE
	ADDM	P3,MAXMAX##	;INCREASE THE MAXIMUM VALUE FOR CORMAX
	DPB	T3,P1		;INDICATE THAT THIS PAGE EXISTS IN NXMTAB
	SKIPN	P2		;SKIP IF NOT THE FIRST PAGE SET ON LINE
	MOVE	P2,T1		;REMEMBER THE FIRST PAGE SET ON LINE
	JUMPE	T4,MEMON7	;JUMP IF FIRST PAGE
	HRRZM	T1,PAGTAB(T4)	;LINK PAGES BEING SET ON LINE TOGETHER
MEMON7:	MOVE	T4,T1		;REMEMBER LAST PAGE
MEMON8:	IBP	P1		;BUMP BYTE POINTER TO NEXT PAGE IN NXMTAB
	CAIE	T1,-1(T2)	;LOOKED AT THE ENTIRE RANGE OF PAGES TO SET ON LINE?
	AOJA	T1,MEMON6	;NO, LOOK AT THE NEXT PAGE
	JUMPE	P2,CPOPJ##	;RETURN DOING NOTHING IF ALL PAGES WERE ALREADY
				; ON LINE
	SETZM	PAGTAB(T4)	;INDICATE END OF THE LIST OF PAGES SET ON LINE

; STILL IN FTMONL
;HERE WHEN MEMORY HAS BEEN MARKED ON LINE TO ADD ALL PAGES WHICH
; WERE OFF LINE TO THE FREE CORE LIST
	MOVE	T1,P2		;FIRST PAGE IN THE LIST OF PAGES SET ON LINE
	MOVE	P1,T4		;LAST PAGE FREED
	LSH	T4,P2WLSH##	;HIGHEST ADDRESS SET ON LINE
	ADDI	T4,PAGSIZ##	;ADDRESS OF PAGE FOLLOWING HIGHEST SET ON LINE
	CAMLE	T4,MEMSIZ##	;IS THAT GREATER THAN CURRENT MEMORY SIZE?
	MOVEM	T4,MEMSIZ##	;YES, SAVE NEW HIGHEST ADDRESS IN MEMORY + 1
	MOVE	T4,MEMSIZ##	;HIGHEST ADDRESS IN MEMORY + 1
	LSH	T4,W2PLSH##	;CONVERT TO HIGHEST PAGE
	MOVEI	T4,PAGTAB-1(T4)	;BYTE POINTER TO HIGHEST PAGE IN MEMORY
	HRRM	T4,CORLST##	;STORE THAT FOR CHKTAL
	PUSHJ	P,GVPAGS	;ADD THE PAGES SET ON LINE TO THE FREE CORE LIST
;HERE TO REFERENCE PAGES ADDED TO THE FREE CORE LIST SO IF THEY ARE
; OFF LINE, IT WILL BE DETECTED BEFORE THEY ARE ATTEMPTED TO BE USED
MEMON9:	HRRZ	T1,P2		;FIRST PAGE SET ON LINE
	IDIVI	T1,^D36		;COMPUTE WORD AND BIT POSITION WITHIN NXMTAB
	MOVE	T2,BITTBL##(T2)	;MASK CORRESPONDING TO THAT BIT POSITION
	TDNE	T2,NXMTAB##(T1)	;IS THIS PAGE NOW ON LINE?
	JRST	MEMO11		;NO, FORGET IT
	HRRZ	T3,P2		;YES, GET PAGE NUMBER
	TRO	T3,PM.ACC+PM.WRT;ACCESS ALLOWED AND WRITEABLE
	HRLM	T3,.EPMP##+.MEUPM
	CLRPGT	(0,.EUPMP)	;FLUSH PAGE TABLE SO NEW MAPPING IS IN EFFECT
;WORRY ABOUT INTERLEAVED MEMORY
	XP	NXMDLY,PARDLY	;TIME TO WAIT FOR NXM FLAG TO COME UP
	MOVEI	T3,MEMITL##	;NUMBER OF WAYS MEMORY CAN BE INTERLEAVED
	MOVEI	T4,NXMDLY	;TIME TO WAIT FOR NXM FLAG TO CAUSE AN IRP.
	MOVEM	J,MOFLPG##	;FLAG THAT MEMORY BEING SET ON LINE
				; NXM AT THIS POINT ISN'T A SERIOUS ERROR
MEMO10:	MOVES	.EUPMP-1(T3)	;REFRENCE THE PAGE TO MAKE SURE ITS REALLY THERE
	SOJG	T4,.		;WAIT LONG ENOUGH FOR NXM INTERRUPT TO HAPPEN
				; IN CASE IT ISN'T THERE
	TDNN	T2,NXMTAB##(T1)	;IS THE PAGE STILL ON LINE?
	SOJG	T3,MEMO10	;YES, CHECK NEXT WORD OF THE PAGE
				; TO INSURE THAT THERE ISN'T AN INTERLEAVING PROBLEM
	SETZM	MOFLPG##	;NO LONGER CHECKING FOR OFF LINE PAGES
MEMO11:	CAIN	P2,(P1)		;REFERENCED ALL PAGES IN THE RANGE SET ON LINE?
IFN FTDAEM,<
	JRST	[MOVE T1,[10,,.ERCSC]
		 PJRST DAEEIM##];YES, TELL DAEMON CONFIGURATION HAS CHANGED AND RETURN
>
IFE FTDAEM,<
	POPJ	P,		;IF NO DAEMON, JUST RETURN
>
	HRRZ	P2,PAGTAB(P2)	;NO, GET THE NEXT PAGE SET ON LINE
	JRST	MEMON9		;AND REFERENCE IT TO MAKE SURE ITS THERE

> ;END FTMEMONL
SUBTTL	CORE1 - CORE ALLOCATION MODULE

;ROUTINE TO ALLOCATE PHYSICAL CORE IN CORE OR ON THE DISK
;CALLING SEQUENCE:
;	MOVE	R,XWD PROTECTION,RELOCATION
;	MOVE	T1,HIGHEST RELATIVE ADDRESS REQUESTED
;	PUSHJ	P,CORE1A
;ALWAYS SKIP RETURN - R = NEW PROTECTION,,RELOCATION
; R = 0 IF CORE IS ASSIGNED ON THE SWAPPING SPACE

CORE1A::JUMPE	R,CORGT0	;JUMP IF SEGMENT HAS NO CORE IN CORE
	HLRZ	T3,R		;T3 = CURRENT HIGHEST RELATIVE ADDRESS IN THE SEGMENT
	SKIPN	T1		;IS ZERO CORE BEING REQUESTED?
	MOVNI	T1,1		;YES, PRETEND -1 AND DEPEND ON BUG IN ASH
				; WHICH MAKES -1 = -1 WHEN SHIFTED
	SUB	T3,T1		;T3 = NUMBER OF WORDS OF INCREASE OR DECREASE IN
				; SEGMENT SIZE
	ASH	T3,W2PLSH##	;CONVERT TO NUMBER OF PAGES OF INCREASE OR DECREASE
	JUMPG	T3,CORE1B	;JUMP IF SEGMENT IS GETTING SMALLER
	MOVMS	T3		;T3 = NUMBER OF PAGES OF INCREASE
	PUSHJ	P,FRDCR##	;ARE THERE THAT MANY FREE PAGES AVAILABLE IN CORE?
	  JRST	CORGT7		;NO, MARK THE SEGMENT AS EXPANDING AND ALLOCATE
				; THE REQUIRED NUMBER OF PAGES ON SWAP-IN
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES OF INCREASE
	PUSHJ	P,SCPAGS	;FIND THE LAST PAGE WHICH IS CURRENTLY
				; ALLOCATED TO THE SEGMENT
	MOVE	T2,(P)		;T2 = NUMBER OF PAGES TO ADD TO THE SEGMENT
IFN FTVM,<
	ADDM	T2,JBTSWP##(J)	;INCREASE IMGIN BY THAT NUMBER OF PAGES
>
	PUSHJ	P,ADPAGS	;ALLOCATE ENOUGH PAGES TO SATISFY THE REQUEST
	POP	P,T2		;RESTORE THE NUMBER OF PAGES OF INCREASE
	LSH	T2,^D18+P2WLSH##;CONVERT TO NUMBER OF WORDS OF INCREASE IN
				; POSITION TO UPDATE CURRENT RELOCATION
	ADD	R,T2		;R = NEW PROTECTION,,RELOCATION
	JRST	CORGT2		;STORE NEW PROTECTION,,RELOCATION AND CLEAR
				; PAGES JUST ADDED TO INSURE SECURITY
CORE1B:	JUMPG	T1,CORE1C	;REQUESTING 0K CORE IN CORE?
	PUSHJ	P,SVEUB		;YES, MAY BE FROM THE SWAPPER AND THE UPMP
				; IS NOT NECESSARILY ADDRESSABLE SO MAKE SURE IT IS
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES OF DECREASE
	MOVEI	T2,0		;FIND THE FIRST PAGE OF THE SEGMENT
	PUSHJ	P,SNPAGS	;T1 = FIRST PAGE TO RETURN TO FREE CORE LIST
	JRST	CORE1D		;GO RETURN PAGES
CORE1C:	LDB	T2,[POINT 9,R,8];T2 = THE CURRENT SIZE OF THE SEGMENT IN
				; PAGES - 1
	SUBI	T2,(T3)		;COMPUTE THE RELATIVE PAGE NUMBER OF THE FIRST
				; PAGE TO RETURN TO THE FREE CORE LIST
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES OF DECREASE
	PUSHJ	P,SNPAGS	;FIND THE ABSOLUTE PAGE NUMBER OF THE FIRST PAGE
				; TO RETURN TO THE FREE CORE LIST
	HRRZ	T2,PAGTAB(T1)	;T2 = THE LINK TO THE FIRST PAGE TO FREE
	HLLZS	PAGTAB(T1)	;INDICATE THAT THIS IS NOW THE LAST PAGE
				; OF THE SEGMENT
	MOVE	T1,T2		;T1 = THE ABSOLUTE PAGE NUMBER OF FIRST PAGE TO FREE
CORE1D:	PUSHJ	P,GVPAGS	;RETURN FREED PAGES TO THE FREE CORE LIST
IFN FTVM,<
	LDB	T2,IMGOUT##	;SWAPPER DEALLOCATION?
	JUMPN	T2,CORE1E	;JUMP IF YES
	MOVN	T2,(P)		;NUMBER OF PAGES BEING DEALLOCATED
	ADDM	T2,JBTSWP##(J)	;UPDATE IMGIN TO REFLECT NUMBER OF PAGES ALLOCATED
CORE1E:>
	POP	P,T2		;RESTORE THE NUMBER OF PAGES OF DECREASE
	LSH	T2,^D18+P2WLSH##;CONVERT TO NUMBER OF WORDS OF DECREASE AND
				; POSITION TO UPDATE CURRENT RELOCATION
	SUB	R,T2		;R = NEW PROTECTION,,RELOCATION
	TLC	R,-1		;WERE ALL OF THE PAGES BELONGING TO THE SEGMENT
	TLCN	R,-1		; RETURNED TO FREE CORE
	SETZB	T1,R		;YES, INDICATE SEGMENT HAS NO CORE IN CORE
	CAILE	J,JOBMAX##	;IS THIS SEGMENT A HIGH SEGMENT?
	JUMPE	R,CORGT1	;YES, AND DOES IT STILL HAVE CORE IN CORE?
	JUMPN	R,CORGT2	;NO, DOES LOW SEGMENT HAVE CORE IN CORE?
	HRRZ	T1,JBTUPM##(J)	;NO, RETURN UPMP TO THE FREE CORE LIST
	SETZ	R,		;INDICATE NO UPMP OR CORE IN CORE
	HLLZS	JBTUPM##(J)
	PUSHJ	P,GVPAGS	;GIVE UP THE PAGE ALLOCATED TO THE UPMP
	JRST	CORGT6		;STORE R AND RETURN
;HERE WHEN THE SEGMENT IS EXPANDING FROM ZERO (CALLED BY THE SWAPPER AND ABOVE)
CORGET::PUSHJ	P,SVEUB		;SAVE UBR ON CALL FROM THE SWAPPER
CORGT0:	JUMPE	T1,CPOPJ1##	;RETURN IF MULTIPLE CALLS TO RETURN CORE
	AOS	T2,T1		;T2 = NUMBER OF WORDS OF CORE REQUIRED TO
				; SATISFY REQUEST
	LSH	T2,W2PLSH##	;T2 = NUMBER OF PAGES REQUIRED
	CAIG	J,JOBMAX##	;IS THIS A LOW SEGMENT?
	CAMGE	T2,BIGHOL##	;YES, MUST ALLOCATE A UPMP ALSO
	CAMLE	T2,BIGHOL##	;NO, IS THERE ENOUGH FREE CORE IN CORE TO
				; ACCOMODATE THE REQUEST?
	SOJA	T1,CORGT7	;NO, MARK THE SEGMENT AS EXPANDING AND ALLOCATE
				; THE REQUIRED NUMBER OF PAGES ON SWAP-IN
IFN FTVM,<
	DPB	T2,IMGIN##	;STORE THE NUMBER OF PAGES ALLOCATED IN CORE
>
	HRLI	R,-1(T1)	;R = NEW PROTECTION,,?
	PUSHJ	P,GTPAGS	;ALLOCATE THE PAGES TO SATIFY THE REQUEST
	MOVEI	T1,PM.ACC+PM.WRT(T1)
	CAILE	J,JOBMAX##	;IS THIS A LOW SEGMENT
	JRST	CORGT1		;NO, UPMP HAS ALREADY BEEN ALLOCATED
	PUSH	P,T1		;SAVE THE PAGE NUMBER OF FIRST PAGE OF THE LOW SEGMENT
	MOVEI	T2,1		;ALLOCATE ONE PAGE FOR THE UPMP
	PUSHJ	P,GTPAGS	;GET ONE PAGE OFF THE FREE CORE LIST
	HRRM	T1,JBTUPM##(J)	;STORE IT AS THE ADDRESS OF THE UPMP
	MOVEI	T1,PM.ACC+PM.WRT(T1)
	HRLM	T1,.EPMP##+.MEUPM
	CLRPGT	(0,.EUPMP)	;THE UPMP IS NOW MAPPED THROUGH THE EXEC
	     	      		; MAP. CLEAR THE AM SO THE NEW MAPPING
				; WILL BE IN AFFECT
	SETZM	.EUPMP
	MOVE	T2,[.EUPMP,,.EUPMP+1]
	BLT	T2,.EUPMP+PG.BDY## ;ZERO THE ENTIRE UPMP
	MOVSI	T2,NLUPMP##+.MUPMP ;NOW SETUP THE REST OF THE MAP FROM THE
	HRRI	T2,.EUPMP+.MUPMP ; PROTOTYPE MAP (NULL JOB'S UPMP)
	BLT	T2,.EUPMP+NUPMPL##-1
	HRLM	T1,.EUPMP+.MUPMP;MAP THE UPMP IN THE PER-PROCESS MAP
	POP	P,T1		;RESTORE THE MAPPING FOR THE FIRST PAGE OF THE
				; LOW SEGMENT
	PUSHJ	P,STEUB		;MAKE THE UPMP ADDRESSABLE (SET THE UBR TO
				; PONIT TO THIS PAGE)
	HRLM	T1,.UPMP	;STORE THE MAPPING FOR THE FIRST PAGE OF
				; THE LOW SEGMENT
	HRRM	T1,.UPMP+.MJDAT	;AND MAKE THE JOB DATA AREA ADDRESSABLE THROUGH
				; THE PER PROCESS MAP
	JRST	CORGT2		;CLEAR THE PAGES JUST ALLOCATED
CORGT1:	DPB	T1,JBYHSA##	;STORE THE STARTING PAGE NUMBER OF THE HIGH SEGMENT
CORGT2:	JUMPE	R,CORGT6	;ALL DONE IF THE SEGMENT HAS NO CORE AT THIS POINT
	HLRZ	T1,R		;T1 = HIGHEST RELATIVE ADDRESS SEGMENT CURRENTLY HAS
	HLRZ	T2,JBTADR##(J)	;T2 = HIGHEST RELATIVE ADDRESS SEGMENT PREVIOUSLY HAD
	JUMPN	T2,CORGT3	;JUMP IF SEGMENT HAD CORE IN CORE
	LDB	T2,IMGOUT##	;T2 = AMOUNT OF CORE SEGMENT HAD WHEN LAST IN CORE
	LSH	T2,P2WLSH##	;CONVERT TO NUMBER OF WORDS
	SOS	T2		;HIGHEST RELATIVE ADDRESS
CORGT3:	CAMG	T1,T2		;CURRENT SEGMENT SIZE GREATER THAN PREVIOUS SIZE?
	JRST	CORGT5		;NO, NOTHING TO CLEAR
	SUB	T1,T2		;T1 = NUMBER OF WORDS OF INCREASE
	ADDI	T2,1		;T2 = NUMBER OF WORDS PREVIOUSLY ALLOCATED THE SEGMENT
	LSH	T2,W2PLSH##	;CONVERT TO PAGE NUMBER OF LAST PAGE
				; PREVIOUSLY ALLOCATED TO THE SEGMENT
IFN FTVM,<
	PUSHJ	P,ZERHGH##	;IF JOB HAS A NON-SHARABLE HI-SEG
	  JRST	CORGT5		; ZERO THE CORE DIFFERENTLY
>
IFN FTTIME,<
	ADDM	T1,CLRWRD##	;INCREASE COUNT OF NUMBER OF WORDS CLEARED
>
	PUSHJ	P,SNPAGS	;GET THE ABSOLUTE PAGE NUMBER OF THE FIRST
				; NEW PAGE (PAGE TO BE CLEARED)
CORGT4:	MOVEI	T1,PM.ACC+PM.WRT(T1)
	HRLM	T1,.EPMP##+.MEUPM
	CLRPGT	(0,.EUPMP)	;THE PAGE IS ADDRESSABLE THROUGH THE EXEC MAP
	     	      		; CLEAR THE AM SO THE MAPPING WILL BE IN AFFECT
	MOVEI	T2,.EUPMP+1	;MAKE A BLT POINTER
	HRLI	T2,.EUPMP	;SET TO ZERO THE PAGE
	SETZM	.EUPMP		;ZERO THE FIRST WORD OF THE PAGE
	BLT	T2,.EUPMP+PAGSIZ##-1
				;ZERO THE PAGE
	TRZ	T1,PM.ACC+PM.WRT;CLEAR THE ACCESS BITS
	HRRZ	T1,PAGTAB(T1)	;GET THE ABSOLUTE PAGE NUMBER OF THE
				; NEXT PAGE OF THE SEGMENT
	JUMPN	T1,CORGT4	;IF NOT THE LAST PAGE ZERO IT
CORGT5:	HRRI	R,.VJDT		;ASSUME A HIGH SEGMENT,.I.E., RH(R) = EVA
				; OF THE VESTIGUAL JOB DATA AREA
	CAILE	J,JOBMAX##	;IS IT A HIGH SEGMENT?
	JRST	CORGT6		;NO
	HRRI	R,.JDAT		;LOW SEGMENT, RH(R) = EVA OF JOB DATA AREA
IFN FTVM,<
	MOVEM	J,.UPMP+.UPJOB	;SAVE THE JOB NUMBER FOR DEBUGGING AND
				; VIRCHK (FOR GIVING BACK HIGH SEG CORE)
>
	HLRZM	R,JOBREL##(R)	;STORE THE NEW SIZE OF THE LOW SEGMENT FOR THE
				; USER SO HE WON'T GET CONFUSED ON EXAMINE COMMAND
CORGT6:	MOVEM	R,JBTADR##(J)	;STORE NEW PROTECTION,,RELOCATION
IFN FTTRACK,<
	MOVEM	J,LASCOR##	;STORE SEGMENT NUMBER OF LAST SEGMENT CORE
				; ALLOCATION WAS DONE FOR FOR DEBUGGING
>
IFN FTVM,<
	LDB	T1,IMGOUT##	;CORE ALLOCATION FOR THE SWAPPER?
 	JUMPN	T1,CPOPJ1##	;YES, ALL DONE
>
	CAMN	J,.C0JOB##	;IS THIS THE CURRENT JOB (CORE UUO)?
	PUSHJ	P,SETREL	;YES, SETUP THE MAP AND SOFTWARE RELOCTATION INFO.
	AOS	(P)		;GIVE SKIP (OK) RETURN
	CAILE	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	PJRST	CURHGH##	;YES SEE IF CORE WAS ALLOCATED FOR THE HIGH
				; SEGMENT WHICH THE CURRENT JOB MIGHT BE SHARING
IFE FTVM,<
	CAME	J,.C0JOB##	;IS THIS THE CURRENT JOB?
	>
IFN FTVM,<
	CAMN	J,.C0JOB##	;CURRENT JOB?
	TLNN	R,MPGSIZ##	; OR ONLY ONE PAGE ALLOCATED TO THE CURRENT JOB?
				; IF ONLY 1 PAGE SETREL MIGHT NOT CALL MAPLOW
>
	PJRST	MAPLOW		;NO, SETUP THE MAP FOR E AND D COMMANDS
	POPJ	P,		;YES, MAP IS ALREADY SETUP
;HERE IF NOT ENOUGH FREE PAGES AVAILABLE IN CORE TO SATISFY REQUEST
; INDICATE JOB IS EXPANDING AND THE REQUIRED NUMBER OF PAGES WILL BE
; ALLOCATED WHEN THE SEGMENT IS NEXT SWAPPED IN
CORGT7:
	AOS	(P)		;SET FOR SKIP RETURN
	PJRST	XPAND##		;AND MARK THE JOB AS EXPANDING
;ROUTINE TO SETUP THE PORTION OF THE MAP WHICH MAPS THE
; LOW SEGMENT
;CALLING SEQUENCE:
;	MOVE	R,LOW SEGMENT PROTECTION,,RELOCATION
;	PUSHJ	P,MAPLOW
;	...	ALWAYS RETURN HERE

MAPLOW:
IFN FTVM,<
	LDB	T1,JBYLSS##	;HIGHEST PAGE IN THE LOW SEGMENT
	ADDI	T1,1		;LOW SEGMENT SIZE
	PUSHJ	P,CLRWS##	;CLEAR WORKING SET BITS
	LDB	T1,[POINT 9,R,8];NEW HIGHEST PAGE IN THE LOW SEGMENT
	ADDI	T1,1		;NEW LOW SEGMENT SIZE
	PUSHJ	P,ADJWS##	;SET WORKING SET BITS FOR NEW SIZE
>	;END FTVM
	MOVE	T1,[POINT 18,.UPMP] ;START AT PAGE ZERO
	MOVEI	T2,PM.ACC+PM.WRT+PM.PUB ;ACCESSABLE, WRITABLE, AND PUBLIC
	LDB	T3,JBYLSA##	;FIRST PHYSICAL PAGE IN THE LOW SEGMENT
	PUSHJ	P,REMAP		;SETUP THE MAP FOR THE LOW SEGMENT
	LDB	T3,JBYLSS##	;PREVIOUS SIZE
	PUSHJ	P,ZERMAP	;CLEAR MAP SLOTS NO LONGER A PART OF THE LOW SEGMENT
	DPB	T2,JBYLSS##	;STORE NEW LOW SEGMENT SIZE
	POPJ	P,		;AND RETURN
;ROUTINE TO SETUP THE PORTION OF THE MAP WHICH MAPS THE HIGH SEGMENT
;CALLING SEQUENCE:
;	PUSHJ	P,MAPHGH
;	...	ALWAYS RETURN HERE - R = PROTECTION,,RELOCATION OF LOW SEGMENT

SETMAP::SKIPA	J,.C0JOB##	;CURRENT JOB NUMBER
REMHGH::TDZA	T3,T3		;NO HIGH SEGMENT NUMBER
MAPHGH::MOVE	T3,JBTSGN##(J)	;HIGH SEGMENT NUMBER
	PUSHJ	P,SVEUB		;MAKE SURE THE JOB IS ADDRESSABLE
	PUSHJ	P,HSVAD##	;COMPUTE HIGH SEGMENT STARTING AND ENDING ADDRESSES
	MOVE	T4,T2		;STARTING ADDRESS
	SKIPL	R,T3		;SPY SEGMENT?
	HLRZ	R,JBTADR##(T3)	;NO, SIZE OF THE REAL HIGH SEGMENT
	HRLZS	R		;HIGH SEGMENT SIZE,,0
	SKIPL	JOBHCU##+.JDAT	;SAVE IN PROGRESS?
	HRRM	T1,JOBHRL##+.JDAT ;YES, DON'T CLOBBER IOWD IN COMPRESSED LOW SEGMENT
IFN FTVM,<
	TLNN	T3,SHRSEG+SPYSEG ;HIGH SEGMENT SHARABLE?
	JUMPN	T3,SCWEXO##	;NO, THE MAP IS RIGHT EXCEPT FOR W.E. AND PUBLIC BITS
>
	ROT	T4,W2PLSH##-1	;CONVERT STARTING ADDRESS TO PAGE NUMBER/2
	MOVEI	T1,.UPMP(T4)	;WORD IN THE UPMP WHERE HIGH SEGMENT MAPPING STARTS
	HRLI	T1,442200	;ASSUME HIGH SEGMENT STARTS AT AN EVEN PAGE NUMBER
	SKIPGE	T4		;DOES IT?
	HRLI	T1,222200	;NO, IT STARTS AT AN ODD PAGE NUMBER
	MOVEI	T2,PM.ACC+PM.WRT;ACCESS ALLOWED PLUS WRITABLE
	TLNN	T3,GTSSEG	;SEGMENT GETSEGED?
	JRST	SETM0A		;NO, ALWAYS PUBLIC
IFN FTFDAE,<
	MOVSI	T4,(JS.FXO)	;FILE DAEMON MADE IT EXECUTE ONLY BIT
	TDNE	T4,JBTST2##(J)	;IS IT EXECUTE ONLY?
	JRST	SETM0B		;YES, LEAVE IT CONCEALED
>
	MOVE	T4,JBTSTS##(J)	;JOB STATUS
	TRNE	T4,JS.XO	;EXECUTE ONLY?
	TLNE	T4,JACCT	;IF ALSO JACCT, FORGET ABOUT X.O.
SETM0A:	TRO	T2,PM.PUB	;JACCT OR NOT EXECUTE ONLY, SO MAKE PAGES PUBLIC
SETM0B:	TLNN	T3,UWPOFF	;USER WRITE PROTECT OFF?
	TRZ	T2,PM.WRT	;YES, MAKE THE SEGMENT WRITABLE
	JUMPL	T3,SETMP1	;JUMP IF A SPY SEGMENT
	LDB	T3,[POINT 13,JBTHSA##(T3),35] ;FIRST PHYSICAL PAGE OF THE HIGH SEGMENT
	MOVEI	T4,PM.ACC+PM.WRT(T3) ;ACCESS ALLOWED PLUS WRITABLE
	HRLM	T4,.UPMP+.MVJDT	;MAKE THE HIGH SEGMENT VESTIGUAL JOB DATA AREA
				; ADDRESSABLE VIA THE PER-PROCESS MAP
	PUSHJ	P,REMAP		;MAP THE HIGH SEGMENT INTO THE USER'S ADDRESS SPACE
	JRST	SETMP3		;CONTINUE
SETMP1:	LDB	T3,[POINT 9,R,8];SIZE OF THE SPY SEGMENT
	TRO	T2,PM.PUB	;EXECUTE ONLY SPY SEG DOESN'T WORK
SETMP2:	IDPB	T2,T1		;MAP MONITOR ADDRESSES INTO USER'S ADDRESS SPACE
	AOS	T2		;STEP TO NEXT MONITOR PAGE
	SOJGE	T3,SETMP2	;MAP AS MANY PAGES AS THE USER REQUESTED
SETMP3:	LDB	T3,JBYHSS##	;PREVIOUS HIGH SEGMENT SIZE
	TLNE	R,-1		;IF THE HIGH SEGMENT SIZE ISN'T 0,
	SUBI	T3,1		;HIGHEST PAGE IN THE HIGH SEGMENT
	PUSHJ	P,ZERMAP	;ZERO MAP SLOTS NO LONGER A PART OF THE HIGH SEGMENT
	TLNE	R,-1		;IF THERE STILL IS A HIGH SEGMENT
	ADDI	T2,1		;COMPUTE NEW NUMBER OF PAGES IN THE HIGH SEGMENT
	DPB	T2,JBYHSS##	;STORE NEW NUMBER OF PAGES IN THE HIGH SEGMENT
	MOVE	R,JBTADR##(J)	;LOW SEGMENT SIZE,,VIRTUAL ADDRESS
	POPJ	P,		;AND RETURN TO THE CALLER
;SUBROUTINE TO SETUP THE USER PAGE MAP PAGE TO REFLECT THE LOCATION
; OF THE PAGES OF A SEGMENT IN PHYSICAL MEMORY
;CALLING SEQUENCE:
;	MOVE	T1,BYTE POINTER TO THE MAP
;	MOVE	T2,PAGE ATTRIBUTES
;	MOVE	T3,ABSOLUTE PAGE NUMBER OF FIRST PAGE OF THE SEGMENT
;	PUSHJ	P,REMAP
;	...	ALWAYS RETURN HERE

REMAP:	HLRZ	T4,R		;LENGTH - 1 OF THE SEGMENT
	JUMPE	T4,CPOPJ##	;IF THE SEGMENT IS ZERO LENGTH RETURN
	LSH	T4,W2PLSH##	;CONVERT TO NUMBER OF PAGES - 1
REMAP1:	TRO	T3,(T2)		;ABSOLUTE PAGE NUMBER PLUS ACCESS BITS
	IDPB	T3,T1		;STORE PHYSICAL LOCATION OF THE PAGE AND
				; THE ACCESS BITS IN THE MAP
	TRZ	T3,(T2)		;CLEAR ACCESS BITS
	MOVE	T3,PAGTAB(T3)	;GET THE ABSOLUTE PAGE NUMBER OF THE NEXT
				; PAGE IN THE SEGMENT
	SOJL	T4,CPOPJ##	;RETURN IF ALL THE PAGES IN THE SEGMENT
				; HAVE BEEN MAPPED
	JUMPG	T3,REMAP1	;MAP ALL THE PAGES IN THE SEGMENT
	STOPCD	.,STOP,PMU,	;++PAGTAB MESSED UP

;ROUTINE TO DETERMINE IF THE SIZE OF A SEGMENT HAS CHANGED SINCE THE LAST
; TIME THE JOB WHOSE ADDRESSING SPACE CONTAINS THIS SEGMENT WAS RUN.  IF THE
; SEGMENT IS SMALLER THAN THE IT PREVIOUSLY WAS, THE ROUTINE
; ZEROES THE LOCATIONS IN THE MAP WHICH CORRESPOND TO THE PAGES REMOVED FROM
; THE SEGMENT (OR ALL THE LOCATIONS IF THE SEGMENT WAS REMOVED) SO THE JOB
; WILL PAGE FAIL ON AN ILLEGAL MEMORY REFERENCE
;CALLING SEQUENCE:
;	MOVE	T3,PREVIOUS SEGMENT SIZE IN PAGES - 1
;	MOVE	R,JBTADR##(J)
;	PUSHJ	P,ZERMAP
;	...	ALWAYS RETURN HERE - T2 = CURRENT SEGMENT SIZE IN PAGES - 1

ZERMAP:	LDB	T2,[POINT 9,R,8];CURRENT SIZE OF THE SEGMENT - 1 IN PAGES
	SUBI	T3,(T2)		;NEW SIZE MINUS OLD SIZE
	JUMPLE	T3,CPOPJ##	;RETURN IF THE SEGMENT IS THE SAME
				; SIZE OR BIGGER THAN IT WAS THE LAST TIME
				; THE JOB WAS RUN
	MOVEI	T4,0		;ZERO THE MAP TO REFLECT THE NEW SMALLER
ZRMAP1:	IDPB	T4,T1		; SEGMENT SIZE SO JOB WILL PAGE FAIL ON AN
	SOJG	T3,ZRMAP1	; ILLEGAL MEMORY REFERENCE
	POPJ	P,		;RETURN
;SUBROUTINE TO RETURN PAGES TO THE LINKED LIST OF FREE PAGES AND UPDATE
; BIGHOL (THE TOTAL NUMBER OF FREE PAGES) AND CORTAL (THE TOTAL NUMBER
; OF FREE PAGES PLUS THE NUMBER OF PAGES OCCUPIED BY
; DORMANT OR IDLE SEGMENTS)
;CALLING SEQUENCE:
;	MOVE	T1,FIRST PAGE TO RETURN TO THE FREE CORE LIST
;	PUSHJ	P,GVPAGS
;	ALWAYS RETURN HERE

GVPAGS::HRRZS	T2,T1		;T2 = FIRST PAGE TO RETURN (CLEAR ANY JUNK IN LH)
	EXCH	T1,PAGPTR##	;STORE FIRST PAGE TO FREE AS FIRST PAGE ON THE
				; FREE CORE LIST AND GET FIRST PAGE ON CURRENT LIST
	MOVEI	T3,1		;AT LEAST ONE PAGE IS BEING RETURNED
GVPAG1:	MOVSI	T4,FREPAG	;THIS PAGE IS ON THE FREE CORE LIST BIT
	TDNE	T4,PAGTAB(T2)	;PAGE MUST NOT BE FREE ALREADY
	STOPCD	.,STOP,ARF,	;++ATTEMPT TO RETURN FREE PAGE
	IORB	T4,PAGTAB(T2)	;MARK THIS PAGE AS BEING ON THE FREE CORE LIST
				; AND GET THE NEXT PAGE TO BE RETURNED
	TRNN	T4,-1		;LAST PAGE TO BE RETURNED?
	JRST	GVPAG2		;YES, UPDATE BIGHOL AND CORTAL AND RETURN
	HRRZ	T2,T4		;INDEX TO NEXT PAGE TO FREE
	AOJA	T3,GVPAG1	;COUNT NUMBER OF PAGES FREED AND RETURN NEXT PAGE
GVPAG2:	HRRM	T1,PAGTAB(T2)	;LINK THE REST OF THE FREE CORE LIST TO THE PAGES
				; FREED
	ADDM	T3,BIGHOL##	;UPDATE THE AMOUNT OF FREE CORE BY THE NUMBER
				; OF PAGES FREED
	ADDM	T3,CORTAL##	;ALSO, UPDATE THE AMOUNT OF POTENTIALLY FREE CORE
	POPJ	P,		;AND RETURN
;SUBROUTINE TO FIND THE NTH PAGE FOR N.LT.THE NUMBER OF PAGES
; ASSIGNED TO THE JOB OR THE JOBS LAST PAGE
;CALLING SEQUENCE:
;	PUSHJ	P,SCPAGS	;TO FIND THE LAST PAGE OF THE JOB
;OR
;	PUSHJ	P,SNPAGS	;TO FIND THE NTH PAGE OF A JOB
;	RETURN HERE - T1 = PAGE NUMBER OF THE NTH PAGE

SCPAGS::MOVEI	T2,^D511	;STOP AFTER SCANNING 512 PAGES
SNPAGS::LDB	T3,JBYHSA##	;PHYSICAL PAGE NUMBER OF PAGE 0 IN THE LOW SEGMENT
	CAIG	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	LDB	T3,JBYLSA##	;YES, PHYSICAL PAGE NUMBER OF FIRST PAGE OF
				; THE HIGH SEGMENT
SNPAG1:	HRRZ	T1,T3		;CURRENT PAGE WITHIN THE SEGMENT
	SKIPGE	T3,PAGTAB(T1)	;GET NEXT PAGE IN THE SEGMENT
	STOPCD	.,STOP,PSF,	;++PAGE IN SEGMENT FREE
	TRNE	T3,-1		;IS THIS THE LAST PAGE IN THE SEGMENT?
	SOJGE	T2,SNPAG1	;NO, IS THIS THE NTH PAGE WITHIN THE SEGMENT?
	POPJ	P,		;YES, RETURN WITH T1 = NTH OR LAST PAGE
;SUBROUTINE TO GET PAGES FROM THE LINKED LIST OF FREE PAGES AND
; UPDATE CORTAL AND BIGHOL
;CALLING SEQUENCE:
;	MOVE	T1,WHERE TO BEGIN ALLOCATION IF ADDING PAGES
;	MOVE	T2,NUMBER OF PAGES TO ALLOCATE
;	PUSHJ	P,ADPAGS	;OR
;	PUSHJ	P,GTPAGS	;IF NO PAGES ARE CURRENTLY ALLOCATED
;	ALWAYS RETURN HERE - T1 = PAGE NUMBER OF FIRST PAGE ALLOCATED

ADPAGS::MOVE	T4,PAGPTR##	;FIRST FREE PAGE
	HRRM	T4,PAGTAB(T1)	;LINK IT TO THE PAGES CONTAINED IN THIS SEGMENT
GTPAGS:	SKIPN	T1,PAGPTR##	;GET FIRST FREE PAGE
	STOPCD	.,STOP,PEZ,	;++PAGPTR=0
	MOVNS	T2		;MINUS NUMBER OF PAGES BEING ALLOCATED
	ADDM	T2,BIGHOL##	;DECREASE THE NUMBER OF FREE PAGES BY THAT AMOUNT
	ADDM	T2,CORTAL##	;AND THE NUMBER OF POTENTIALLY FREE PAGES
	MOVE	T3,T1		;FIRST PAGE TO ADD OR GET
GTPAG1:	HRRZ	T4,T3		;ALLOCATE THIS PAGE
	MOVSI	T3,FREPAG	;PREPARE TO MARK THIS PAGE AS IN-USE
	SKIPN	T4		;END OF THE FREE CORE LIST?
	STOPCD	.,STOP,FPI,	;++FREE PAGE INUSE
	ANDCAB	T3,PAGTAB(T4)	;CLEAR THE BIT INDICATING A FREE PAGE AND GET
				; THE NEXT PAGE ON THE FREE CORE LIST
	AOJL	T2,GTPAG1	;LOOP UNTIL ALL PAGES REQUESTED ARE ALLOCATED
	HRRZM	T3,PAGPTR##	;STORE THE NEW FIRST PAGE IN THE FREE CORE LIST
	HLLZS	PAGTAB(T4)	;INDICATE THAT THIS IS THE LAST PAGE ALLOCATED
				; TO THIS SEGMENT
	POPJ	P,		;AND RETURN TO THE CALLER
SUBTTL	SWAP - USER PROGRAM SWAPPING ROUTINES

;SUBROUTINE TO SETUP THE MAP FOR A JOB WHICH WAS JUST SWAPPED IN
; THIS INCLUDES THE TRAP LOCATIONS AS WELL AS THE MAP ITSELF
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER OF JOB JUST SWAPPED IN
;	MOVE	R,XWD LOW SEGMENT SIZE, EVA OF THE JOB DATA AREA
;	SETUP THE USER BASE REGISTER TO POINT TO THIS JOB'S UPMP
;	PUSHJ	P,MAPUSR
;	ALWAYS RETURN HERE

MAPUSR::PUSHJ	P,SVEUB		;MAKE THE MAP ADDRESSABLE
	MOVE	R,JBTADR##(J)	;R=WXD LOW SEGMENT SIZE, ADDRESS OF JOB DATA AREA
	MOVE	T1,JOBPC##(R)	;JOBS PC
	TLNN	T1,(XC.USR)	;JOB IN EXEC MODE?
	MOVEM	R,JOBDPG##(R)	;YES, STORE POSSIBLY UPDATED R IN THE DUMP ACS
IFE FTVM,<
	PUSHJ	P,MAPLOW	;MAP THE LOW SEGMENT
>
	PUSHJ	P,MAPHGH	;MAP THE HIGH SEGMENT
	MOVE	T1,JOBENB##(R)	;GET THE JOBS ENABLE BITS
	PJRST	SETRP		;SETUP THE TRAP LOCATIONS
SUBTTL	SWPSER - SWAPPING SERVICE ROUTINE

;SUBROUTINE TO MAKE THE FIRST WORD OF A SEGMENT ADDRESSABLE FOR JBTCHK
; CALLING SEQUENCE:
;	MOVE	T1,IOWD USED FOR SWAPPING
;	MOVE	J,SEGMENT NUMBER OF SEGMENT SWAPPED IN OR OUT
;	PUSHJ	P,GETCHK
;	ALWAYS RETURN HERE
;T1 = EXEC VIRTUAL ADDRESS OF WORD 0 OF THE SEGMENT.  IF THIS IS A LOW
; SEGMENT, JUST SETUP THE UBR SINCE T1 CONTAINS THE ADDRESS OF WORD 0
; OF THE SEGMENT MAPPED THROUGH THE PER PROCESS MAP.  IF THIS IS A HIGH
; SEGMENT, MAP WORD 0 THROUGH THE EXEC MAP SINCE THE SEGMENT MAY BE
; DORMANT OR IDLE AND THUS NOT APPEAR IN ANY USERS MAP.

GETCHK::CAIG	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	JRST	SVEUB		;NO, JUST SETUP THE UBR SINCE THE LOW SEGMENT
				; IS ADDRESSABLE VIA THE PER PROCESS MAP
	LDB	T1,JBYHSA##	;GET THE ABSOLUTE PAGE NUMBER OF THE FIRST
				; PAGE OF THE HIGH SEGMENT
	TRO	T1,PM.ACC+PM.WRT;SET ACCESS BITS
	HRRM	T1,.EPMP##+.MECKS
				;MAP WORD 0 IN THE EXEC MAP
	CLRPGT	(0,.ECKSM)	;FLUSH THE ASSOCIATIVE MEMORY SO THE NEW MAPPING
	     	      		; WILL BE IN EFFECT
	MOVEI	T1,.ECKSM	;T1 = EXEC VIRTUAL ADDRESS OF WORD 0 OF THE
				; HIGH SEGMENT
	POPJ	P,		;RETURN
SUBTTL	UUOCON - UUO HANDLING ROUTINES

IFN FTDAEM,<
;SUBROUTINE TO DO PROCESSOR DEPENDANT PORTION OF JOB PEEK UUO
;CALLING SEQUENCE:
;	HRRI	T4,0 IF SOURCE SEGMENT IS A SPY SEGMENT
;	MOVE	P1,FLAGS,,JOB NUMBER (FLAGS BIT0=0 IF READ, 1 IF WRITE)
;	MOVE	P2,NUMBER OF WORDS TO TRANSFER
;	PUSHJ	P,JOBPKD
;	ALWAYS RETURN HERE

JOBPKD::PUSHJ	P,GETWDU##	;GET SOURCE AND DESTINATION ADDRESSES
	MOVSI	T2,(XCT 3,)	;ASSUME SOURCE AND TARGET ADDRESSES ARE IN JOB DOING
	CAIN	J,(P1)		; THE JOBPEK (IF SO BOTH ARE ADDRESSABLE). ARE THEY?
	JRST	JOBPK3		;YES, BLT FROM USER TO USER
	MOVSI	T2,(XCT 2,)	;ASSUME THE SOURCE SEGMENT IS A SPY SEGMENT
	TRNN	T4,-1		; I.E., THE MONITOR. IS IT?
	JRST	JOBPK3		;YES, BLT FROM MONITOR TO USER
	HRRZ	T2,JBTUPM##(P1)	;ADDRESS OF THE TARGET JOB'S UPMP
	TRO	T2,PM.ACC+PM.WRT;ALLOW ACCESS AND WRITING
	HRRM	T2,.UPMP+.MTEMP	;MAKE THE TARGET JOB'S UPMP ADDRESSABLE
	CLRPGT	(0,.JBPK)	;CLEAR THE A.M. SO NEW MAPPING IS IN AFFECT
	HRRZ	T3,T1		;DESTINATION ADDRESS IF WRITING
	TLNN	P1,400000	;WRITING?
	HLRZ	T3,T1		;NO, READING. GET SOURCE ADDRESS
	TLNE	P1,200000	;READING THE UPMP?
	MOVSI	T3,1		;YES, VIRTUAL PAGE NUMBER 1000
	MOVE	T2,T3		;GET ADDRESS IN TARGET JOB
	ANDI	T2,PG.BDY##	;KEEP ONLY REL WD IN PAGE
	ADDI	T2,PG.BDY##(P2)	;ADD AND ROUND NO. WDS TO TRANSFER
	LSH	T2,W2PLSH##	;MAKE NO. OF PAGES
	LSH	T3,W2PLSH##	;CONVERT TO VIRTUAL PAGE NUMBER
	MOVNS	T2		;MINUS NUMBER OF PAGES TO MAKE ADDRESSABLE
	HRL	T2,T3		;STARTING VIRTUAL PAGE NUMBER IN TARGET JOB
	MOVSS	T2		;MAKE AN AOBJN POINTER
	ROT	T3,-1		;INDEX INTO TARGET JOB'S MAP (REMAINDER IN HIGH BIT)
	MOVEI	T4,.TEMP(T3)	;FORM A BYTE POINTER TO THE TARGET JOB'S MAP
	HRLI	T4,442200	;ASSUME AN EVEN STARTING PAGE
	SKIPGE	T3		;IS IT AN EVEN PAGE?
	HRLI	T4,222200	;NO, ODD
	MOVEI	T3,.UPMP+.MJBPK	;ADDRESS OF JOBPEK TEMPORARY SLOTS IN THE
				; PER-PROCESS MAP
	HRLI	T3,442200	;STARTING IN THE LEFT HALF WORD
JOBPK0:	ILDB	P3,T4		;GET THE ENTRY FROM THE TARGET JOB'S MAP
IFN	FTVM,<
	TRNE	P3,PM.ACC	;ACCESS ALLOWED?
	JRST	JOBPK1		;YES, ZOOM ON
	JUMPE	P3,CPOPJ##	;ERROR RETURN IF PAGE DOESN'T EXIST
	CAIN	P3,PM.ZER	;ALLOCATED BUT ZERO PAGE?
	POPJ	P,		;YES, PAGE NOT IN CORE RETURN
	HRRZ	P3,T2		;VIRTUAL PAGE WHICH HAS ACCESS ALLOWED OFF
	IDIVI	P3,^D36		;WORD IN WSBTAB WHICH CONTAINS BIT FOR THIS PAGE
	MOVE	P4,BITTBL##(P4)	;BIT POSITION WITHIN THE WORD
	TDNN	P4,WSBTAB-.UPMP+.TEMP(P3) ;PAGE IN CORE WITH ACCESS ALLOWED OFF?
	POPJ	P,		;NO, JUST GIVE PAGE NOT IN CORE RETURN
	LDB	P3,T4		;GET MAP ENTRY AGAIN
JOBPK1:	TRO	P3,PM.ACC!PM.WRT  ;ALLOW ACCESS
>
	IDPB	P3,T3		;STORE IT IN THIS JOB'S PER-PROCESS MAP
	AOBJN	T2,JOBPK0	;MAP ENOUGH PAGES TO ALLOW THE TRANSFER
	CLRPGT	(0,.JBPK)	;CLEAR THE A.M. SO THAT THE NEW MAPPING IS IN AFFECT
	MOVEI	T2,.JBPK/1000	;PAGE NUMBER IN THE EXEC VIRTUAL ADDRESS SPACE
	TLNE	P1,400000	;READ OR WRITE?
	JRST	JOBPK2		;WRITE
	DPB	T2,[POINT 9,T1,8] ;READ, MAKE SOURCE ADDRESS AN EXEC VIRTUAL ADDRESS
	MOVSI	T2,(XCT 2,)	;READ FROM EXEC, WRITE TO USER
	JRST	JOBPK3		;GO DO THE BLT
JOBPK2:	DPB	T2,[POINT 9,T1,26] ;WRITING, MAKE DESTINATION AN EXEC VIRTUAL ADDRESS
	MOVSI	T2,(XCT 1,)	;READ FROM USER, WRITE TO EXEC
JOBPK3:	ADDI	P2,(T1)		;ENDING ADDRESS EQUALS NUMBER OF WORDS PLUS
				; STARTING ADDRESS
	HRRI	T2,[BLT T1,-1(P2)] ;XCT 1, 2, OR 3 OF A BLT
	XCT	T2		;MOVE THE DATA
IFN FTVM,<
	AOS	(P)		;INDICATE ALL PAGES WERE IN CORE AND THE DATA
				; WAS TRANSFERED
>
	POPJ	P,		;RETURN
>
	$LIT
KIEND:	END