Google
 

Trailing-Edge - PDP-10 Archives - tops10_703a_sys_ap115_bb-ju01b-bb - klser.x15
There are 2 other files named klser.x15 in the archive. Click here to see a list.
TITLE	KLSER - KL10 PROCESSOR DEPENDENT CODE - FROM KISER V176 -V563
SUBTTL  J.M. FLEMMING/JMF & D.A. LEWINE/DAL/EVS 30 JUL 86

	SEARCH	F,S,DTEPRM
	$RELOC
	$HIGH



;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1973,1986>
;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.


;
XP VKLSER,563		; PUT VERSION NUMBER IN GLOB LISTING AND LOADER STORAGE MAP

ENTRY	KLSER		;LOAD KLSER IF LIBRARY SEARCH
KLSER::
SUBTTL	TRAP HANDLING AND CONTEXT SWITCHING

;HERE TO PROCESS USER ARITHMETIC OVERFLOW TRAPS
SAROVF::
	DMOVE	T1,.USMUO	;GET PC DBL WRD
	MOVE	T3,.JDAT+JOBENB## ;GET USER'S ENABLE BITS
	TRNN	T3,AP.AOV	;OVERFLOW - IS THE USER ENABLED?
	TLNE	T1,(XC.FOV)	;TRAP CAUSED BY FOV?
	CAIA			;YES,
	JRST	SAROV6		;NOT ENABLED, IGNORE IT
	HRRI	T3,AP.AOV+AP.FOV;ASSUME FLOATING OVERFLOW
	TLNN	T1,(XC.FOV)	;WAS IT A FLOATING OVERFLOW TRAP?
	TRZ	T3,AP.FOV	;NO, INTEGER OVERFLOW
;HERE WITH T1,T2=PC, T3=APRENB BITS
SAROV3:	TLNE	T2,MXSECN	;IN A NON-ZERO SECTION?
	JRST	SAROV9		;CAN'T TRAP IT THIS WAY THEN
REPEAT 0,<
	TLZ	T1,637		;CLEAR NON-EX BITS (KA COMPATABILITY)
>
	HLLM	T1,.JDAT+JOBTPC## ;SAVE OLD PC
	HRRM	T2,.JDAT+JOBTPC## ;..
	MOVEM	T3,.JDAT+JOBCNI## ;LIKE CONI ON THE KA-10
	MOVE	T3,.JDAT+JOBENB## ;GET USER'S ENABLE BITS
	TRNE	T3,XP.DDU	;USER WANT TRAPS REENABLED?
	JRST	SAROV5		;YES, LEAVE AS IS
	HLLZS	.JDAT+JOBENB##	;CLEAR USER'S ENABLE BITS SO MUST DO APRENB AGAIN
	MOVSI	T3,(JFCL)	;NOP
	MOVEM	T3,.USAOT	;IGNORE ARITHMETIC TRAPS
	MOVEI	T3,UP.PDT
	MOVEM	T3,.USPDT	;EXEC WILL FIELD PDL OVERFLOWS
	SETZM	.CPCN1##	;CLEAR POSSIBLE NXM OR CLOCK ENABLES
SAROV5:	MOVEI	T3,XP.CLK	;ALWAYS DISABLE CLOCK
	ANDCAM	T3,.CPCN1##
	HRRZ	T3,.JDAT+JOBAPR## ;PC IN TRAP ROUTINE?
	CAIE	T3,0(T2)
	CAIN	T3,-1(T2)
	JRST	SAROV7		;YES
	HRR	T2,.JDAT+JOBAPR## ;GET USER'S TRAP ADDRESS
	TLZ	T1,(XC.OVF+XC.FOV+XC.FUF+XC.NDV+IC.BIS+IC.AFI)
	TLO	T1,(XC.PUB!XC.USR) ;INSURE PUBLIC AND USER MODE IS SET
SAROV6:	DMOVEM	T1,.USMUO	;NEW PC WITH TRAP CAUSING BITS CLEARED
	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##] ;SET UP A STACK
	PUSHJ	P,SCDCHK##	;CHECK IF WE SHOULD RESCHEDULE
	USERAC			;SET USER AC BLOCK
	XJRSTF	.USMUO		;EXIT TO THE USER'S TRAP HANDLER
SAROV7:	MOVEI	T3,XP.LTH	;STUCK IN LOOP BIT
SAROV9:	DMOVEM	T1,.CPAPC##	;SAVE OLD PC FOR ERROR MESSAGE
	HRRM	T3,.CPAEF##
	JRST	SEPDL3
;HERE TO PROCESS EXEC STACK OVERFLOW TRAPS

SEPDLO::EXCH	T1,.USMUP	;GET THE PC
	MOVEM	T1,.CPAPC##+1	;STORE PC
	HLLZ	T1,.USMUO	;FLAGS
	MOVEM	T1,.CPAPC##	;SET AS ERROR FLAGS FOR ERRCON
	TLNN	T1,(XC.USR)	;WAS THIS IN USER MODE?
	JRST	DOPDL		;NOPE, EXEC, SOMETHING'S WRONG, CRASH
	HRRI	T1,AP.POV	;SET PUSH DOWN OVERFLOW FLAG
SEPDL1:	HRRM	T1,.CPAEF##	;IN .CPAEF SO ERRCON WILL GET CALLED
	MOVE	T1,.USMUP	;RESTORE T1
SEPDL3:	SETOM	.CPSCF##	;SET FORCED RESCHEDULING FLAG
	SETOM	.CPCKF##	;AND CLOCK FLAG
	CONO	PI,CLKBIT##+PI.IIO ;REQUEST A CLOCK INTERRUPT
	JRST	.		;WAIT UNTIL CLOCK LEVEL HAPPENS AND THE JOB
				; IS STOPPED IN USER MODE.


DOPDL::	EXCH	T1,.USMUP	;SAVE PC AND RESTORE T1
	MOVEM	P,@.CPEPL##	;SAVE OLD P
	HRRZS	P		;SEE IF
	CAMLE	P,SYSSIZ##	;UUO OR INTERRUPT LEVEL
	XJRST	[MCSEC1+EXTPDL##] ;UUO, TRY TO EXTEND THE PDL
	JRST	EPOSTP##	;CAN'T RECOVER ON INTERRUPT LEVEL

;HERE TO PROCESS PAGE FAILURE TRAPS

SEILM::	CONI	PI,.CPTPI##	;SAVE THE PI STATE
	CONSO	PI,PI.ON	;IS THE PI SYSTEM ON?
	JRST	SEIL2		;NO--PROCESS TRAP IMMEDIATELY
	CONSZ	PI,@.CPACO##	;APR CHANNEL ON?
	CONSZ	PI,@.CPAPP##	;YES--DID THIS TRAP HAPPEN AT CPU PI LEVEL?
	JRST	SEIL1		;YES--PROCESS TRAP IMMEDIATELY
	CONSZ	APR,LP.PAR!LP.NXM ;NO--IS AN MB PARITY OR NXM INTERRUPT COMING?
	JRST	.-1		;YES--LET IT RUN AND THEN CONTINUE THE TRAP
SEIL1::	CONO	PI,PI.OFF	;NOW INSURE THAT PI'S ARE OFF
SEIL2:	DATAI	PAG,.CPTCX##	;SAVE THE TRAP CONTEXT
	EXECAC			;WANT MONITOR'S AC BLOCK
	JRSTF	@[IC.UOU+.+1]	;INSURE USRIOT IS ON SO PXCT WORKS

	MOVEM	T1,.CPSTT##	;SAVE T1 TEMPORARILY
	LDB	T1,[POINT 5,.USPFW,5] ;PICK UP PF CODE
	CAIL	T1,20		;IS THIS A REAL PAGE FAULT
	CAIN	T1,PF.ABF	; OR AN ADDRESS BREAK?
	JRST	SEILMA		;YES--GO PROCESS IT
	CAIN	T1,PF.IID	;IS IT AN ILLEGAL INDIRECT ADDRESS?
	JRST	SEILMA		;YES--GO PROCESS IT

	CAIE	T1,PF.ISN	;IS IT AN ILLEGAL SECTION NUMBER?
	CAIN	T1,PF.PRV	;IS IT A PROPRIETARY VIOLATION?
	JRST	SEILMA		;YES--GO PROCESS
	CAIL	T1,PF.ARP	;IS IT A PARITY TRAP?
	JRST	PRTRP		;YES--GO PROCESS
	CAIN	T1,PF.PTP	;IS IT PAGE TABLE PARITY?
	JRST	PTPAR		;YES--GO PROCESS
	CAIN	T1,PF.PRF	;IS IT A PAGE REFILL FAILURE?
	STOPCD	(.,CPU,PRF)	;++PAGE REFILL FAILURE
	STOPCD	(.,CPU,IPC)	;++ILLEGAL PAGE FAILURE TRAP CODE
;HERE ON AR OR ARX PARITY TRAP (PAGE FAIL CODE 36 OR 37)
PRTRP:	DIELOK			;GRAB THE DIE INTERLOCK
	SKIPE	.CPPSP##	;CORE SWEEP IN PROGRESS?
	JRST	SWTRP		;YES, JUST SAVE LOCATION OF FAILURE AND DISMISS
	MOVEI	T1,@.CPEBR##	;NORMAL EBR
	TRZ	T1,LG.CSW	;TURN OFF CACHE LOAD BIT
	CONO	PAG,(T1)	;TURN OFF CACHE LOAD AND CLEAR PAGE TABLE
	MOVE	T1,.CPSTT##	;RESTORE T1
	MOVEM	17,.CPA17##	;SAVE AC 17
	MOVEI	17,.CPA00##	;MAKE BLT POINTER
	BLT	17,.CPA17##-1	;SAVE AC'S IN CPU DATA BLOCK
	MOVE	P,.CPEPD##	;SET UP ERROR STACK
	PUSHJ	P,CPUSTS##	;READ CPU STATUS
	PUSHJ	P,DVCSTS##	; AND DEVICE STATUS
	MOVE	J,.CPJOB##	;SET UP J WITH CURRENT JOB RUNNING
	MOVE	T1,JBTPPN##(J)	;GET ITS PPN
	MOVEM	T1,.CPEJN##	; AND SAVE IT
	MOVE	T1,JBTNAM##(J)	;GET ITS PROGRAM NAME
	MOVEM	T1,.CPEPN##	; AND SAVE IT
	AOS	.CPNPT##	;COUNT TOTAL NUMBER OF AR/ARX PARITY TRAPS
	DMOVE	T1,.USPFP	;GET THE PAGE FAIL PC
	DMOVEM	T1,.CPMDP##	;FOR ERROR IN JOB MESSAGES
	DMOVEM	T1,.CPPPD##	;STORE TROUBLE PC
	TDZ	T1,[7777,,-1]	;HOKEY IT UP
	IOR	T1,T2		;SINCE A ONE WORD GETTAB
	MOVEM	T1,.CPPPC##	;SAVE THE PC FOR DAEMON
	MOVEM	T1,.CPMPP##	;ALSO OLD PLACE
	MOVE	T3,.USPFW	;GET THE PAGE FAIL WORD
	MOVEM	T3,.CPPFW##	;SAVE THE PAGE FAIL WORD FOR DAEMON
	LDB	T4,[POINT 5,T3,5] ;GET THE PAGE FAIL CODE
	SUBI	T4,PF.ARP	;CONVERT TO INDEX INTO AC BLOCK 7
	DATAO	PAG,[LG.LAB+7B11] ;SET PREVIOUS ACS TO BLOCK 7
	PXCT	PX.MEM,[MOVE T4,(T4)] ;PICK UP BAD DATA WORD FROM BLOCK 7
	EXECAC			;RESTORE MONITOR AC SETTINGS
	MOVEM	T4,.CPTBD##	;SAVE BAD DATA FOR DAEMON
	TLNE	T1,(XC.USR)	;IS THE TRAP FROM EXEC MODE?
	JRST	PRTRPC		;NO--CONTINUE
	SKIPE	.CPCHE##	;IS TRAP FROM CHANNEL ERROR REPORTING?
	JRST	PRTCHN		;YES--SPECIAL HANDLING
	TLZ	T2,777740	;GET JUST THE ADDRESS OF OFFENDING INSTRUCTION
	TLZ	T3,777740	;GET JUST THE ADDRESS OF OFFENDING REFERENCE
	CAMN	T2,T3		;IS AN INSTRUCTION FETCH AT FAULT?
	JRST	PRTRPC		;YES--CONTINUE
	MOVE	T1,(T2)		;NO--PICK UP THE OFFENDING INSTRUCTION
	TLNN	T1,740		;IS THE AC FIELD NON-ZERO?
	JRST	PRTRPC		;NO--CONTINUE
	LSH	T1,-^D27	;YES--GET JUST THE OP CODE
	CAIE	T1,256		;IS THIS A PXCT THEN?
	JRST	PRTRPC		;NO--CONTINUE
	MOVE	T1,(T2)		;YES, GET THE PXCT BACK
	TLZ	T2,-1		;ONLY 18 BITS
	TLNN	T1,37		;SAFE TO FETCH THE OPERAND?
	CAIN	T2,(T1)
	JRST	PRTRP9		;NO, NONE OF THESE ARE BLTS ANYWAYS
 	LDB	T3,[POINT 9,(T1),8] ;GET OP-CODE OF PXCT'ED INSTRUCTION
	CAIE	T3,(BLT/1000)	;IS IT A BLT?
	JRST	PRTRP9		;NO
	TLNN	T1,PX.SRC*40	;BLT FROM USER TO EXEC?
	JRST	PRTRPC		;NO, EXEC TO USER
PRTRP9:	MOVSI	T3,(PF.USR)	;YES--GET THE USER REFERENCE BIT
	IORB	T3,.CPPFW##	; AND FIX THE PAGE FAIL WORD (HARDWARE IS WRONG)
	JRST	PRTRP1		;REFERENCE WAS VIRTUAL
;THE CODE BETWEEN HERE AND PRTRP2 IS AN ELABORATE NOOP SINCE THE MICROCODE
; DOES NOT INDICATE A PHYSICAL REFERENCE IN THE PAGE FAIL WORD EVEN IF THE
; PARITY ERROR OCCURRED AS A RESULT OF THE MICROCODE MAKING A PHYSICAL REFERENCE.
; IT'S INCLUDED IN CASE THE MICROCODE GETS FIXED
; ACTUALLY, THE MICROCODE SHOULDN'T BE BLAMED SINCE ITS A HARDWARE BUG
PRTRPC:	MOVE	P1,.CPPFW##	;GET THE PAGE FAIL WORD
	MOVE	T3,.CPMAP##	;GET .EPMP FOR THIS CPU
	PUSH	P,.ERPIL/PAGSIZ##(T3)

;	TLNE	P1,(PF.PHY)	;A PHYSICAL REFERENCE?
;	JRST	PRTRP1		;NO, CALCULATE PHYSICAL FROM VIRTUAL ADDRESS
;HERE TO PRETEND PF.PHY WAS ON AND REFERENCE POSSIBLE PHYSICAL LOCATIONS
	TLZ	P1,777760	;ISOLATE PHYSICAL ADDRESS
	CAILE	P1,777		;COULD THE REFERENCE HAVE BEEN TO A PAGE MAP?
	JRST	PRTRP0		;NO, THEN P1 IS THE REAL PHYSICAL ADDRESS
;IF THE PAGE FAIL WORD IS LESS THAN 777, THE REFERENCE COULD HAVE BEEN
; AN EPT OR UPT RELATIVE PHYSICAL REFERENCE MADE BY THE MICROCODE. TRY
; REFERENCING THAT LOCATION IN THE APPROPRIATE MAP TO SEE IF BAD PARITY
	SKIPL	.CPPFW##	;REFERENCE TO THE EXEC ADDRESS SPACE?
	CONI	PAG,P1		;YES, GET THE PAGE NUMBER OF THE EPT
	SKIPGE	.CPPFW##	;OR A REFERENCE TO USER ADDRESS SPACE?
	DATAI	PAG,P1		;YES, GET THE PAGE NUMBER OF THE UPT
	ANDI	P1,17777	;ISOLATE THE PAGE NUMBER
	LSH	P1,P2WLSH##	;PHYSICAL ADDRESS OF THE MAP
	IOR	P1,.CPPFW##	;PHYSICAL ADDRESS OF REFERENCE
	TLZ	P1,777760	;CLEAR CRUFT
	PUSHJ	P,TRYREF	;TRY REFERENCING THE LOCATION IN THE MAP
	  JRST	PRTRP2		;FAILED, STORE IT
	JRST	PRTRP1		;DIDN'T FAIL, ASSUME REFERENCE TO USER OR EXEC
				; PAGE 0
;EVEN THOUGH NOT A REFERENCE TO PAGE 0, STILL COULD BE A PHYSICAL REFERENCE (SPT,CST)
PRTRP0:	PUSHJ	P,TRYREF	;SEE IF BAD PARITY IN PHYSICAL LOCATION
	  JRST	PRTRP2		;YES, STORE PHYSICAL ADDRESS
;HERE IF WE BELIEVE THAT THE ADDRESS IN THE PAGE FAIL WORD IS REALLY A
; VIRTUAL ADDRESS. MUST BE TRUE OR THE PARITY ERROR WAS SPURIOUS
PRTRP1:	MOVE	T4,[PXCT PX.MEM,[MAP P1,(P1)]] ;SET UP PXCT OF MAP INSTRUCTION
	SKIPL	.CPPFW##	;IS THIS A USER CONTEXT REFERENCE?
	TLZ	T4,(PX.MEM,)	;NO--THEN PXCT BECOMES REGULAR XCT
	MOVE	P1,.CPPFW##	;NOT PHYSICAL REFERENCE, GET VIRTUAL ADDRESS
	XCT	T4		;DO A MAP TO TURN PF WORD INTO PHYS ADDR IN P1
PRTRP2:	MOVEM	P1,.CPPBA##	;SAVE BAD PHYSICAL ADDR FOR DAEMON
	TLZ	P1,777760	;GET RID OF LEFT HALF STUFF
	ROT	P1,W2PLSH##	;TURN RH OF P1 INTO PAGE NUMBER OF BAD LOC
	PUSHJ	P,MAPREF	;SETUP MAPPING FOR RETRY REFERENCES
	LSH	P1,-^D27	;TURN P1 INTO WORD NUMBER WITHIN PAGE
	ADDI	P1,.ERPIL	;AND GET PAGE NUMBER CORRESPONDING TO MAP SLOT
	MOVEI	T1,[ASCIZ . AR/ARX parity trap.]
	PUSHJ	P,PRMPC		;ANNOUNCE ERROR
	MOVEI	T1,[ASCIZ /Page fail word = /]
	MOVE	T2,.CPPFW##
	PUSHJ	P,PRMHW		;PRINT THE PAGE FAIL WORD
	MOVEI	T1,[ASCIZ /Mapped page fail address = /]
	MOVE	T2,.CPPBA##
	PUSHJ	P,PRMHW		;PRINT THE MAP WORD (PHYS. ADDRESS)
	MOVEI	T1,[ASCIZ /Incorrect contents = /]
	MOVE	T2,.CPTBD##
	PUSHJ	P,PRMHW		;PRINT THE BAD DATA
	MOVEI	T1,[ASCIZ /CONI PI, = /]
	MOVE	T2,.CPTPI##
	PUSHJ	P,PRMHW		;PRINT THE CONI PI BITS
	SETZ	P2,		;CLEAR FLAG REGISTER
	CONSO	PAG,LG.CSL	;IS THE CACHE ON?
	JRST	PRTRP3		;NO
	TRO	P2,PFCPF3	;REMEMBER IT'S IN USE
	SWPVA			;SWEEP WRITTEN ENTRIES BACK TO MEMORY
	CONSO	APR,LP.CSD	;SWEEP BUSY?
	JRST	.-1		;WAIT FOR DONE
	MOVE	T1,.CPAPI##	;GET APR PIA
	CONO	APR,LP.CSF!LP.CSD(T1) ;CLEAR CACHE SWEEP DONE
	CONSO	APR,LP.PAR	;MB PARITY DURING SWEEP?
	JRST	PRTRP3		;NO--START RETRIES
	TRO	P2,PFCPF4	;YES--REMEMBER THIS PROBLEM
	MOVEI	T1,[ASCIZ /MB parity error occurred during cache sweep prior to retry attempt.
ERA = /]
	RDERA	T2		;PICK UP THE ERA
	PUSHJ	P,PRMHW		;PRINT MESSAGE AND ERA
	PUSHJ	P,CLRSBD##	;CLEAR MEMORY CONTROLLERS
	MOVE	T1,.CPAPI##	;GET APR PIA
	CONO	APR,LP.CSF!LP.SBE!LP.PAR(T1) ;CLEAR THE APR
;HERE TO START RETRIES-FIRST WITH CACHE OFF
PRTRP3:	MOVE	T1,.CPPBA##	;BAD PHYSICAL ADDRESS
	TLZ	T1,777760	;CLEAR LEFT HALF JUNK
	LSH	T1,W2PLSH##	;CONVERT TO PAGE NUMBER
	IDIVI	T1,^D36		;INDEX INTO NXM TABLE
	MOVE	T2,BITTBL##(T2)	;BIT IN NXM TABLE
	TDNE	T2,NXMTAB##(T1)	;PAGE ALREADY KNOWN TO BE IN NON-EXISTANT MEMORY?
	JRST	[SETZ	P1,
		 JRST	PRHMX]	;DON'T REFERENCE NON-EXISTANT MEMORY
	MOVEI	T1,@.CPEBR##	;GET NORMAL CONO PAG, BITS
	TRZ	T1,LG.CSW!LG.CSL ;TURN OFF LOOK AND LOAD
	CONO	PAG,(T1)	;MAKE SURE CACHE IS OFF
	PUSHJ	P,PRTRY		;REFERENCE LOCATION WITHOUT CACHE
	  JRST	PRHMF		;RETRIES FAILED! HARD MEMORY FAILURE
;HERE WE KNOW WE CAN RECOVER THE USER
	MOVEM	T1,.CPTGD##	;SAVE THE GOOD DATA FOR ERROR REPORTING
	AOS	.CPSAR##	;UPDATE COUNTER OF SOFT AR/ARX PARITY ERRORS
	HRRM	T3,.CPPTR##	;STORE RETRY COUNT
	TRNN	P2,PFCPF3	;WAS CACHE ON WHEN WE STARTED?
	JRST	PRTRP5		;NO--GO FINISH UP
;HERE RESTORE GOOD DATA TO THE CACHE LOCATION
	MOVEI	W,@.CPEBR##	;GET NORMAL EBR
	MOVE	U,W		;2ND COPY
	TRZ	U,LG.CSW	;TURN OFF LOAD IN THIS ONE
	MOVE	S,T1		;SETUP GOOD DATA TO WRITE TO CACHE
	MOVE	T1,[CONO PAG,(W)] ;TURN ON CACHE LOOK & LOAD
	MOVE	T2,[MOVEM S,(P1)] ;REWRITE GOOD DATA TO CACHE
	MOVE	T3,[CONO PAG,(U)] ;TURN OFF CACHE LOAD
	MOVE	T4,[JRST PRTRP4] ;GET BACK TO THIS CODE
	JRST	T1		;EXECUTE THE INSTRUCTIONS IN THE AC'S
				;SO THEY DON'T GET INTO POSSIBLY BAD CACHE

;NOW RETRY REFERENCE WITH CACHE ON, CACHE STILL HAS LOOK BIT ON BUT LOAD OFF
PRTRP4:	PUSHJ	P,PRTRY		;REFERENCE LOCATION
	  JRST	PRHCF		;RETRIES FAILED! HARD CACHE FAILURE
	SWPIA			;INVALIDATE CACHE BUT DON'T TOUCH CORE
	CONSO	APR,LP.CSD	;SWEEP BUSY?
	JRST	.-1		;WAIT FOR DONE
	MOVE	T1,.CPAPI##	;GET APR PIA
	CONO	APR,LP.CSF!LP.CSD(T1) ;CLEAR CACHE SWEEP DONE
	CONO	PAG,@.CPEBR##	;TURN ON CACHE LOOK & LOAD
;HERE IF RETRIES WERE SUCCESFUL, LOG SOFT ERROR AND DISMISS
PRTRP5:	HRLM	P2,.CPPTR##	;SAVE STATUS FLAGS FOR ERROR REPORTING
	DPB	T3,[POINT 9,.CPPTR##,26] ;PUT CACHE RETRY COUNT HERE
	MOVE	T3,.CPMAP##	;GET .EPMP FOR THIS CPU
	POP	P,.ERPIL/PAGSIZ##(T3)
	PUSHJ	P,CLRSBD##	;CLEAR MEMORY CONTROLLERS
	MOVE	T1,.CPAPI##	;GET APR PIA
	CONO	APR,LP.CSF!LP.SBE!LP.PAR(T1) ;CLEAR ANY APR ERRORS
	MOVEI	T1,[ASCIZ /Retry successful! Correct contents = /]
	MOVE	T2,.CPTGD
	PUSHJ	P,PRMHW		;PRINT SUCCESS AND GOOD DATA
	MOVEI	T1,EDELIM##	;GET ADDRESS OF TEXT
	PUSHJ	P,PRMSG		;PRINT END DELIMITER
	PUSHJ	P,DAELOG	;LOG THE ERROR
	JRST	PTXIT		;EXIT THE TRAP
	;LOCAL ROUTINE TO SETUP A MAP SLOT TO MAKE PHYSICAL REFERENCES
	;RETURNS +1 ALWAYS
	;PRESERVES LEFT HALF OF P1, CLOBBERS RIGHT HALF

MAPREF:	MOVE	T3,.CPMAP##	;GET PAGE NUMBER OF EPMP FOR THIS CPU
	HRRM	P1,.ERPIL/PAGSIZ##(T3)
	HRRI	P1,(<PM.DCD>B2+PM.WRT+PM.PUB)
	HRLM	P1,.ERPIL/PAGSIZ##(T3)
	CLRPGT	(0,.ERPIL)	;CLEAR OUT OLD ENTRY FOR .ERPIL
	POPJ	P,		;RETURN

	;LOCAL ROUTINE TO REFERENCE A PHYSICAL ADDRESS
	;ENTER WITH P1 = PHYSICAL ADDRESS TO BE REFERENCED
	;RETURNS +1 IF LOCATION CONTAINS BAD PARITY
	;RETURNS +2 IF CONTENTS OK

TRYREF:	PUSHJ	P,SAVE1##	;SAVE PHYSICAL ADDRESS
	LSH	P1,W2PLSH##	;PAGE TO MAP
	PUSHJ	P,MAPREF	;SETUP MAPPING TO REFERENCE PHYSICAL ADDRESS
	MOVE	P1,-1(P)	;GET BACK PHYSICAL ADDRESS
	ANDI	P1,PG.BDY##	;WORD NUMBER WITHIN THE PAGE
	ADDI	P1,.ERPIL	;VIRTUAL ADDRESS OF WORD TO TRY
;	PJRST	PRTRY		;REFERENCE THE WORD AND SEE IF IT CONTAINS BAD PARITY
	;LOCAL RETRY ROUTINE
	;RETURNS +1 IF RETRIES FAIL
	;RETRUNS +2 IF ANY RETRY WINS
	;   T1/GOOD DATA
	;   T3/RETRY WHICH SUCCEEDED (FIRST =1)

PRTRY:	MOVEI	T3,1		;INIT RETRY COUNTER
	MOVEI	T2,TRYBAD	;GET TEST TRAP ADDRESS
	EXCH	T2,.USPFN+1	;EXCHANGE WITH WHAT'S THERE NOW
	PUSH	P,.USPFP	;IF A TRAP HAPPENS, HOW WE GOT HERE IS LOST
	PUSH	P,.USPFP+1	;SECOND HALF
PRTY1:	TRO	P2,PFCPF0	;NOTE THIS IS TEST REFERENCE
	MOVE	T1,0(P1)	;TRY THE REFERENCE
	  TRZ	P2,PFCPF0	;CLEAR THE REFERENCE FLAG
	TRZN	P2,PFCPF2	;ERROR DURING REFERENCE?
	JRST	PRTY3		;NO--GIVE A GOOD RETURN
	CAIGE	T3,TRPTRY	;YES--RETRY COUNT EXHAUSTED?
	AOJA	T3,PRTY1	;NO--TRY AGAIN
	SKIPA			;YES--GIVE AN ERROR RETURN
PRTY3:	AOS	-2(P)		 ;SET FOR SKIP RETURN
	POP	P,.USPFP+1	;AND SECOND WORD
	POP	P,.USPFP	;RESTORE OLD CONTENTS
	EXCH	T2,.USPFN+1	;RESTORE STANDARD TRAP ADDRESS
	POPJ	P,		;EXIT

;HERE ON TRAPS OCCURING DURING RECOVERY ATTEMPTS
TRYBAD:	TRNN	P2,PFCPF0	;ARE WE HERE BECAUSE OF TEST REFERENCE?
	STOPCD	(.,HALT,UPF)	;++UNEXPECTED PAGE FAIL
	LDB	T1,[POINT 5,.USPFW,5] ;GET PAGE FAIL CODE
	CAIE	T1,PF.ARP	;AR PARITY ERROR?
	STOPCD	(.,HALT,WPT)	;++WRONG PARITY TRAP
	TRO	P2,PFCPF2	;YES--INDICATE ERROR
	AOS	.USPFP+1	;RETURN TO TEST REFERENCE + 1
	XJRSTF	.USPFP		;RETURN


;CACHE HAS LOOK ON BUT NOT LOAD
;HERE IF CACHE RETRIES FAIL  WE MAY TURN OFF CACHE NOW

PRHCF:	SWPIA			;INVALIDATE CACHE BUT DON'T TOUCH CORE
	CONSO	APR,LP.CSD	;SWEEP BUSY?
	JRST	.-1		;WAIT FOR DONE
	MOVE	T1,.CPAPI##	;GET APR PIA
	CONO	APR,LP.CSF!LP.CSD(T1) ;CLEAR CACHE SWEEP DONE
	MOVEI	T1,@.CPEBR##	;INITIAL EBR
	TRZ	T1,LG.CSL!LG.CSW ;TURN OFF THE LOOK BIT FOR SAFETY
	CONO	PAG,(T1)	;MAY LEAVE IT OFF
	TRO	P2,PFCPF2	;SET THE CACHE FAILED BIT FOR ERROR REPORTING
	AOS	T1,.CPCEC##	;COUNT THIS FAILURE
	CAIGE	T1,CCHEMX	;EXCEEDED ALLOWABLE?
	JRST	PRHC1		;NO-TURN IT BACK ON
	MOVEI	T1,[ASCIZ /Three non-recoverable cache parity errors
  have occurred since processor started.
CACHE HAS BEEN TURNED OFF./]
	PUSHJ	P,PRMSG		;ANNOUNCE CACHE DESELECT
	MOVEI	T1,LG.CSL!LG.CSW;TURN OFF LOOK & LOAD BITS
	ANDCAM	T1,.CPEBR##	;BITS NOW CLEARED SO OTHERS
				;CAN'T TURN IT ON BY ACCIDENT
	TRO	P2,PFCPF5	;SET CACHE DESELECTED FLAG FOR ERROR REPORTING
	JRST	PRTRP5		;NOW CLEAN UP AND RETURN TO USER

;HERE TO TURN THE CACHE BACK ON
PRHC1:	CONO	PAG,@.CPEBR##	;TURN IT ON
	JRST	PRTRP5		;AND RETURN TO USER
;HERE WHEN RETRIES FROM MEMORY FAIL

PRHMF:	SETZM	(P1)		;ZERO (AND RE-WRITE) THE ROTTEN LOCATION ALSO
	PUSH	P,P2		;SAVE P2
	PUSH	P,T3		;SAVE T3
	PUSHJ	P,PRTRY		;NOW SEE IF IT'S REALLY HARD (MEMORY BROKEN)
	  TDZA	P1,P1		;IT IS, SET P1 = 0
	SETO	P1,		;IT'S NOT, SET P1 = -1
	POP	P,T3		;RESTORE T3
	POP	P,P2		;RESTORE P2
PRHMX:	SETZM	.CPTGD##	;ZERO "GOOD DATA" SINCE WE DIDN'T GET ANY
	MOVE	T1,.CPMAP##	;GET .EPMP FOR THIS CPU
	POP	P,.ERPIL/PAGSIZ##(T1)
	AOS	.CPHPT##	;BUMP HARD (AR/ARX) PARITY TRAP COUNT
	SWPIA			;INVALIDATE CACHE BUT DON'T TOUCH CORE
	CONSO	APR,LP.CSD	;SWEEP BUSY?
	JRST	.-1		;WAIT FOR DONE
	PUSHJ	P,CLRSBD##	;CLEAR MEMORY CONTROLLERS
	MOVE	T1,.CPAPI##	;GET APR PIA
	CONO	APR,LP.CSF!LP.SBE!LP.PAR!LP.CSD(T1) ;CLEAR THE APR
	TRO	P2,PFCPF1	;SAY HARD ERROR FOR ERROR REPORTING
	HRLM	P2,.CPPTR##	;SAVE FLAGS
	HRRM	T3,.CPPTR##	;SAVE RETRY COUNT FOR ERROR REPORTING
	CONO	PAG,@.CPEBR##	;TURN THE CACHE BACK ON
	MOVEI	T1,[ASCIZ /Retries unsuccessful. Offending location zeroed./]
	PUSHJ	P,PRMSG		;ANNOUNCE FAILURE
	PUSHJ	P,DAELOG	;CALL DAEMON TO LOG THE ERROR
	MOVE	T1,.CPPPC##	;GET THE TRAP PC
	TLNE	T1,(XC.USR)	;IS THE TRAP FROM USER MODE?
	JRST	PRHMF1		;YES--GO KILL USER
	HRRZ	T1,.CPPFW##	;GET THE PROBLEM ADDRESS
	SKIPGE	.CPPFW##	;IS THIS A USER CONTEXT REFERENCE?
	JRST	PRHMF0		;YES--GO CHECK IF AT SCHED OR PI LEVEL
	MOVE	T2,SYSLEN##	;NO--GET LENGTH OF MONITOR'S HIGH SEG
	ADDI	T2,MONORG##-1	;FORM EVA OF THE TOP OF THE HIGH SEG
	CAIL	T1,MONORG##	;IS THE ERROR IN THE
	CAILE	T1,(T2)		; MONITOR'S HIGH SEGMENT?
	JRST	PRHMF0		;NO--GO CHECK OTHER THINGS
	LSH	T1,W2PLSH##	;YES--FORM THE EXEC VIRTUAL PAGE NUMBER
	MOVE	T2,.CPPBA##	;GET THE MAPPED PHYSICAL ADDRESS
	TDZ	T2,[777760,,777] ;ONLY WANT BASE ADDRESS OF PAGE
	PUSHJ	P,PAGRPL##	;TRY TO REPLACE THIS CODE PAGE
	  JRST	PARHLT##	;IT DIDN'T WORK
	MOVEI	T1,[ASCIZ /Replaced monitor code page from disk./] ;GET TEXT
	PUSHJ	P,PRMSG		;PRINT IT
	MOVEI	T1,EDELIM##	;GET END DELIMITER
	PUSHJ	P,PRMSG		;PRINT IT
	PJRST	PTXIT		;EXIT THE TRAP
PRHMF0:	SETOM	.CPREP##	;SET PARITY MSG FLAG IN CASE THIS IS FATAL
	SKIPN	.CPISF##	;ARE WE IN THE SCHEDULER
	CONSZ	PI,PI.IPA	; OR ARE WE AT INTERRUPT LEVEL?
	JRST	PARHLT##	;YES--SORRY BUT WE CAN'T DO A THING
	SKIPGE	.CPPFW##	;WAS THIS A MONITOR REF TO USER SPACE AT UUO LVL?
	JRST	PRHMF2		;YES--TREAT AS USER ERROR
	CAIL	T1,FYSORG	;NO--IS THE ERROR IN THE
	CAILE	T1,.LPPP-1	; USER PER PROCESS AREA?
	JRST	PARHLT##	;NO--IT'S IN THE MONITOR DATA BASE, FATAL!
	SETZ	P2,		;YES, CALL IT A LOWSEG ERROR
	JRST	PRHMF3		;TREAT AS FATAL USER ERROR
PRHMF1:	MOVEI	T1,UE.PEF	;GET PARITY ERROR BIT
	TDNN	T1,.CPCN1##	;IS USER ENABLED TO HANDLE THIS HIMSELF?
	JRST	PRHMF2		;NO--GO ON
	MOVE	T2,JBTSTS##(J)	;YES--GET JOB STATUS WORD
	TLNE	T2,JACCT	;IS JOB PRIVILEGED?
	JRST	PRHF1A		;YES--TRAP TO HIM
	MOVE	T2,JBTPPN##(J)	;NO--GET HIS PPN
	CAME	T2,FFAPPN##	;IS IT THE OPERATOR PPN
	CAMN	T2,UMDPPN##	; OR THE USER MODE DIAG PPN?
	JRST	PRHF1A		;YES--LET'S TRAP TO HIM AS REQUESTED
	JRST	PRHMF2		;NO--THEN WE IGNORE HIS TRAP REQUEST
PRHF1A:	MOVEI	T1,EDELIM##	;GET END DELIMITER
	PUSHJ	P,PRMSG		;PRINT IT
	DIENLK			;RETURN THE DIE INTERLOCK
	CONO	PI,PI.ON	;TURN PI'S BACK ON
	DMOVE	T1,.CPPPD##	;GET THE PROBLEM PC
	MOVEI	T3,UE.PEF	;PARITY ERROR
	JRST	SAROV3		;GO TRAP TO USER
PRHMF2:	SETZ	P2,		;SET FLAG ASSUMING LOW SEG ERROR
	MOVE	J,.CPJOB##	;GET THE OFFENDING JOB #
	SKIPG	J,JBTSGN##(J)	;DOES THIS JOB HAVE A HIGH SEG?
	JRST	PRHMF3		;NO--GO ON
	HRRZ	T1,.CPPFW##	;GET THE PROBLEM ADDRESS
	CAML	T1,.USHSS	;IS ADDRESS IN THE USER HIGH SEGMENT?
	CAMLE	T1,.USHSE
	JRST	PRHMF3		;NO--GO ON
	SETO	P2,		;YES--SET FLAG INDICATING HIGH SEG ERROR
	PUSHJ	P,HGHPAR##	;GO PROCESS JOBS USING THIS SEGMENT
PRHMF3:	JUMPN	P1,PRHMF4	;IF MEMORY IS OK, DON'T MARK OUT PAGE
	LDB	T1,[POINT 13,.CPPBA##,26] ;GET THE PAGE NUMBER TO MARK OFF-LINE
	PUSH	P,T1		;SAVE PAGE NUMBER
	IDIVI	T1,^D36		;COMPUTE NXMTAB INDEX AND BITTBL INDEX
	MOVE	T2,BITTBL##(T2)	;GET CORRECT BIT TO SET
	TDNE	T2,NXMTAB##(T1)	;ALREADY A NON-EXISTANT PAGE?
	JRST	PRHMF4		;YES, COULD HAPPEN IF REFERENCE TO A NON-EXISTANT ADDRESS
	IORM	T2,NXMTAB##(T1)	;MARK OUT PAGE IN NXMTAB
	MOVEI	T1,[ASCIZ /Location still bad after zeroing.
Setting off-line physical page /] ;GET TEXT
	POP	P,T2		; AND PAGE NUMBER
	PUSHJ	P,PRMOC		;TELL HIM WHAT WE DID
	MOVE	T1,[.CSCPO,,.ERCSC]
	PUSHJ	P,DAEDIE##	;LOG CONFIGURATION CHANGE
PRHMF4:	MOVEI	T1,EDELIM##	;GET END DELIMITER
	PUSHJ	P,PRMSG		;PRINT IT
	MOVE	J,.CPJOB##	;GET JOB NUMBER
	JUMPE	P2,PRHMF5	;GO STOP THIS JOB IF LOW SEG ERROR
	MOVEI	T1,JS.MPE	;DID HGHPAR SAY THAT THIS JOB
	TDNE	T1,JBTSTS##(J)	; COULDN'T BE SAVED?
	JRST	PRHMF5		;YES--JUST GO STOP IT
	DIENLK			;RETURN THE DIE INTERLOCK
	CONO	PI,PI.ON	;TURN THE PI'S BACK ON
	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##] ;DUMMY STACK FOR WSCHED
	PUSH	P,.USPFP	;STACK RETURN USER ADDRESS FOR WSCHED
	PUSH	P,.USPFP+1	;SECOND HALF AS WELL

	PJRST	WSCHED##	;RESCHEDULE THIS JOB TO RE-RUN WITH NEW HI SEG

PRHMF5:	PUSHJ	P,PARJB1##	;CLEAR JACCT AND SET JS.MPE
	MOVSI	T1,(CP.PXX)	;GET PRINT REQUEST BIT
	TRO	T1,UE.PEF	;ALSO FLAG PARITY ERROR
	IORM	T1,.CPAEF##	;SET REQUEST FOR PI 7
	SETOM	.CPSCF##	;FORCE RESCHEDULE
	SETOM	.CPCKF##	;SET FLAG FOR PI 7 INTERRUPT
	DIENLK			;RETURN THE DIE INTERLOCK
	CONO	PI,XI.RQC##	;REQUEST PI 7
	CONO	PI,PI.ON	;ALLOW INTERRUPTS NOW (MAINLY PI 7)
	PJRST	ESTOP##		;GO STOP THIS JOB
;HERE ON TRAP DURING PARITY SWEEP
SWTRP:	EXCH	T1,.CPSTT##	;RESTORE T1, SAVE TRAP CODE
	PUSH	P,T1		;SAVE T1
	HRRZ	T1,.USPFP+1	;GET PC OF TRAP
	CAIE	T1,CPLMPI	;BETTER MATCH THE SWEEP BLT ADDRESS
	STOPCD	(.,HALT,NPI)	;++NOT PARITY INSTRUCTION
	MOVE	T1,.USPFW	;GET THE PAGE FAIL WORD
	MOVEM	T1,.CPPFW##	;AND SAVE IT
	MOVE	T1,.CPAER##	;GET ERA FROM INTERRUPT THAT SHOULD HAVE HAPPENED
	MOVEM	T1,.CPSTE##	;SAVE AS ERA CORRESPONDING TO THIS SWEEP TRAP
	MOVE	T1,.CPSTT##	;GET PAGE FAIL CODE
	SUBI	T1,PF.ARP	;CONVERT TO INDEX INTO AC BLOCK 7
	DATAO	PAG,[LG.LAB+07B11] ;SET PREVIOUS AC BLOCK TO 7
	PXCT	PX.MEM,[MOVE T1,(T1)] ;GET BAD DATA WORD FOR DAEMON
	EXECAC			;RESTORE MONITOR'S AC BLOCK
	MOVEM 	T1,.CPTBD##	;SAVE BAD DATA
	SETOM	.CPPTH##	;INDICATE ERROR ON SWEEP
	MOVEI	T1,3		;BUMP RETURN PC BY 3 TO
	ADDM	T1,.USPFP+1	; INDICATE A TRAP HAPPENED
	POP	P,T1		;RESTORE T1
	JRST	PTXIT1		;EXIT BACK TO SWEEP ROUTINE

;HERE ON TRAPS FROM CHANNEL ERROR REPORTING CODE
;NOTE: P3 IS THE AC USED IN THE CHANNEL ERROR CODE TO ACCESS DATA IN CORE
PRTCHN:	CONO	PAG,@.CPEBR##	;RESTORE CACHE SETTINGS
	DATAO	PAG,.CPTCX##	;SET AC BLOCK TO ONE IN USE AT TIME OF TRAP
	MOVE	P3,.CPTBD##	;PUT ACCESSED DATA (THOUGH BAD) IN P3
	EXECAC			;BACK TO MONITOR AC SETTINGS
	AOS	.USPFP+1	;BUMP RETURN PC OVER MOVE INSTRUCTION
	JRST	PTXIT		;EXIT THE TRAP
;ROUTINE TO PRINT A MESSAGE PREFIXED BY "CPUx" AND
;FOLLOWED BY "AT EXEC(USER) PC XXXXXX"
;  T1=MESSAGE ADDRESS

PRMPC:	PUSHJ	P,SAVE1##	;SAVE P1 TO REMEMBER ADDRESS OF MESSAGE
	MOVE	P1,T1		;SAVE
	PUSHJ	P,SVPPC##	;SWITCH TO SECONDARY PROTOCOL
	PUSH	P,.CPTOA##	;SAVE COMMAND OUTPUT ADDRESS
	MOVEI	T2,CTYWAT##	;GET ONE THAT DOESN'T USE PI SYS
	MOVEM	T2,.CPTOA##
	MOVEI	T1,SDELIM##	;GET ADDRESS OF TEXT
	PUSHJ	P,CONMES##	;PRINT START DELIMITER
	MOVE	T2,.CPLOG##	;GET THIS CPU'S NAME
	PUSHJ	P,PRNAME##	;PRINT IT
	MOVE	T1,P1		;GET ADDRESS OF MESSAGE IN T1
	PUSHJ	P,CONMES##	;PRINT MESSAGE
	DMOVE	T1,.CPPPD##	;GET SAVED PC
	PUSHJ	P,DPCP##	;PRINT "AT EXEC/USER XXXXXX"
	MOVEI	T1,[ASCIZ / on /] ;SEPARATE FROM DATE/TIME
	PUSHJ	P,CONMES##	;PRINT IT
	PUSHJ	P,DAYTIM##	;PRINT DATE AND TIME
	MOVEI	T1,[ASCIZ /Job/];TELL THEM WHO WAS RUNNING
	PUSHJ	P,CONMES##	;PRINT "JOB"
	PUSHJ	P,PRJBNM##	;PRINT JOB INFO
	MOVEI	T1,[ASCIZ / was running
/]
	PUSHJ	P,CONMES##	;PRINT "WAS RUNNING"
PRMPC2:	POP	P,.CPTOA##	;RESTORE SCNSER ADDRESS
	POPJ	P,		;RETURN

;ROUTINES TO PRINT A MESSAGE FOLLOWED BY NUMBER IN HALFWORD OR OCTAL FORMAT
;  T1=MESSAGE ADDRESS, T2=NUMBER
PRMOC:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVEI	P3,OCTPNT##	;GET ADDRESS OF OCTAL PRINT ROUTINE
	JRST	PRMHW1		;GO TO COMMON CODE
PRMHW:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVEI	P3,HWDPNT##	;GET ADDRESS OF HALFWORD PRINT ROUTINE
PRMHW1:	MOVE	P1,T1		;SAVE
	MOVE	P2,T2		;SAVE
	PUSHJ	P,SVPPC##	;SWITCH TO SECONDARY PROTOCOL
	PUSH	P,.CPTOA##	;SAVE COMMAND OUTPUT ADDRESS
	MOVEI	T2,CTYWAT##	;GET ONE THAT DOESN'T USE PI SYS
	MOVEM	T2,.CPTOA##
	MOVE	T1,P1		;GET ADDRESS OF MESSAGE IN T1
	PUSHJ	P,CONMES##	;PRINT MESSAGE
	MOVE	T1,P2		;GET NUMBER TO PRINT (IF ANY)
	PUSHJ	P,(P3)		;PRINT NUMBER IN DESIRED FORMAT
	PUSHJ	P,CRLF##	;END WITH CRLF
	PJRST	PRMPC2		;FINISH UP
;ROUTINE TO PRINT A MESSAGE
;  T1=MESSAGE ADDRESS

PRMSG:	PUSHJ	P,SAVE2##	;SAVE P1,P2 TO REMEMBER ADDRESS OF MESSAGE
	MOVE	P1,T1		;SAVE
	PUSHJ	P,SVPPC##	;SWITCH TO SECONDARY PROTOCOL
	PUSH	P,.CPTOA##	;SAVE COMMAND OUTPUT ADDRESS
	MOVEI	T2,CTYWAT##	;GET ONE THAT DOESN'T USE PI SYS
	MOVEM	T2,.CPTOA##
	MOVE	T1,P1		;GET ADDRESS OF MESSAGE IN T1
	PUSHJ	P,CONMES##	;PRINT MESSAGE
	PUSHJ	P,CRLF##	;END WITH CRLF
	PJRST	PRMPC2		;FINISH UP

;ROUTINE TO LOG AN ERROR + CPU AND DEVICE STATUS BLOCKS

DAELOG:	MOVEI	T1,.ERKPT	;CODE FOR DAEMON
	HRL	T1,.CPSLF##	;THIS CPU'S CDB ADDRESS
	PUSHJ	P,DAEDIE##	;PUT THE ENTRY IN THE QUEUE
	PJRST	RCDSTD##	;ALSO, QUEUE ENTRY FOR CPU AND DEVICE STATUS BLOCK
;HERE ON PAGE TABLE PARITY TRAP (PF CODE 25)
PTPAR:	DIELOK			;GRAB THE DIE INTERLOCK
	CONO	PAG,@.CPEBR##	;CLEAR THE PAGE TABLE
	AOS	.CPPTP##	;COUNT A PAGE TABLE PARITY ERROR
	MOVE	T1,.CPSTT##	;RESTORE T1
	MOVEM	T1,.CPA17##	;SAVE 17
	MOVEI	17,.CPA00##	;MAKE BLT POINTER
	BLT	17,.CPA17##-1	;SAVE ACS IN CPU DATA BLOCK
	MOVE	P,.CPEPD##	;SET UP ERROR STACK
	SKIPGE	T1,.CPPTF##	;PICK UP COUNT OF PAGE TABLE FAILURES
	MOVEI	T1,^D4		;NONE YET, INITIALIZE FOR 3 RETRIES
	SOJG	T1,PTPAR1	;IF COUNT HASN'T EXPIRED, JUST RETRY.
				; COUNTER IS RESET ON EVERY CLOCK TICK.
	MOVE	J,.CPJOB##	;CURRENT JOB
	MOVE	T1,.CPPPD##	;PC
	TLNE	T1,(XC.USR)	;IN USER MODE?
	JRST	PRHMF5		;YES, JUST ZAP THE JOB
	DIENLK			;UNLOCK SO CAN CALL DIE
	STOPCD	.,CPU,PGTPAR,	;++PAGE TABLE PARITY
PTPAR1:	MOVEM	T1,.CPPTF##	;REMEMBER COUNTER
	DMOVE	T1,.USPFP	;GET PAGE FAIL PC
	DMOVEM	T1,.CPPPD##	;SAVE FOR PRINT ROUTINE

	MOVE	J,.CPJOB##	;SET UP J WITH CURRENTLY RUNNING JOB
	MOVEI	T1,[ASCIZ / page table parity trap/]
	PUSHJ	P,PRMPC		;ANNOUNCE ERROR
	MOVEI	T1,[ASCIZ /Page fail word = /]
	MOVE	T2,.USPFW
	MOVEM	T2,.CPPFW##	;FOR CRASH
	PUSHJ	P,PRMHW		;PRINT THE PAGE FAIL WORD
	MOVEI	T1,[ASCIZ /CONI PI, = /]
	MOVE	T2,.CPTPI##
	PUSHJ	P,PRMHW		;PRINT THE CONI PI BITS
	MOVEI	T1,EDELIM##	;GET ADDRESS OF TEXT
	PUSHJ	P,PRMSG		;PRINT END DELIMITER
PTXIT:	MOVSI	17,.CPA00##	;BLT POINTER TO RESTORE ACS
	BLT	17,16		;RESTORE ACS
	MOVE	17,.CPA17##	;AC 17 ALSO
PTXIT1:	DATAO	PAG,.CPTCX##	;RESTORE THE CONTEXT AT TIME OF TRAP
	DIENLK			;RETURN THE DIE INTERLOCK
	EXCH	T1,.CPTPI##	;GET PI'S AT TRAP ENTRY, SAVE T1
	TRNE	T1,PI.ON	;WERE THE PI'S ON?
	CONO	PI,PI.ON	;YES--TURN PI'S BACK ON
	EXCH	T1,.CPTPI##	;RESTORE T1
	XJRSTF	.USPFP		;RESTORE FLAGS AND RETURN

;HERE ON REAL PAGE FAULTS OR ADDRESS BREAKS

SEILMA:	MOVE	T1,.CPSTT##	;RESTORE T1
	CONO	PI,PI.ON	;TURN PI SYSTEM BACK ON
	SKIPN	.CPEJ1##	;SKIP NEXT IF EXEC PAGE FAULT IN PROGRESS
	DMOVEM	T1,.CPST1##	;SAVE T1 AND T2 IN CASE OF CRASH
	DMOVE	T1,.USPFP	;GET THE PAGE FAIL PC
	DMOVEM	T1,.CPAPC##	;STORE IT AS POTENTIAL ERROR PC
	DMOVEM	T1,.USMUP	;STORE WHERE KI WOULD PUT IT
	HRR	T1,T2		;GET PC INTO T1 AS A ONE WORD PC

	MOVE	T2,.USPFW	;GET THE USER PAGE FAIL WORD
	MOVEM	T2,.CPPFW##	;SAVE PAGE FAULT WORD FOR CRASH
SEILMB:	TLNE	T1,(XC.USR)	;PAGE FAULT IN EXEC MODE?
	JRST	SEILM0		;NO, PROCEED
	LDB	T2,[POINT 5,T2,5] ;CLEAR ALL BUT THE PAGE FAIL CODE
	CAIN	T2,PF.ABF	;WAS THE PAGE FAULT AN ADDRESS BREAK?
	JRST	SEILM1		;YES, REMEMBER IT AND GO AWAY
	JRST	SEILM7		;NO, EXEC ILL MEM REF, LOOK FOR ERJMP
SEILM0:	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##]	;SETUP A PUSH DOWN LIST
	SKIPN	.USJOB
	STOPCD	.,CPU,PFN	;++PAGE FAULT IN NULL JOB
	PUSH	P,.USPFP+1	;SAVE USER'S PC
	MOVE	T3,T2		;FAULT WAS IN USER MODE, SAVE PFC FOR
				; POSSIBLE CALL TO USRFLT
	LDB	T2,[POINT 5,T2,5] ;CLEAR ALL BUT THE PAGE FAIL CODE
	CAIN	T2,PF.ABF	;ADDRESS BREAK?
	JRST	SEILM1		;YES, GO PROCESS
	MOVE	T4,.JDAT+JOBENB## ;GET APR ENABLE BITS
	TRNE	T4,AP.ILM	;IS USER ENABLED?
	JRST	SUILM		;YES--DO SUILM INSTEAD
	HRRI	T1,AP.ILM	;ILLEGAL MEMORY REFERENCE
	CAIN	T2,PF.ISN	;ILLEGAL SECTION?
	JRST	SEPDL1		;YES
	CAIN	T2,PF.PRV	;WAS IT A PROPRIETARY VIOLATION?
	JRST	[TRO  T1,AP.PPV	;INDICATE PROP VIO
		 JRST SEPDL1]
	DMOVE	T1,.USPFP	;GET DOUBLE WORD PC
	PUSHJ	P,USRFLT##	;SEE IF PAGE FAULT FOR A VM USER
				; WILL NOT RETURN IF SO (DISPATCH TO USER)
	HRRI	T1,AP.ILM	;COULDN'T HANDLE IT - USER GETS ILL MEM REF
	JRST	SEPDL1		;GO SAY "ILL. MEM. REF."
SEILM1:	DMOVE	T1,.USPFP	;GET FAULT DOUBLE WORD PC
	TLO	T1,(IC.AFI)	;INHIBIT ADDRESS BREAK WHEN INSTRUCTION IS EXECUTED
	DMOVEM	T1,.CPPC##	;STASH WHERE PSISER CAN FIND IT
	EXCH	J,.CPJOB##	;GET JOB
	PUSH	P,W		;SAVE W IN CASE IN EXEC MODE
	PUSHJ	P,FNDPDS##	;FIND THE PDB
	LDB	T2,[POINT 9,.PDTMI##(W),17]	;GET THE PROCEED COUNT
	SOSL	T2		;DECREMENT
	DPB	T2,[POINT 9,.PDTMI##(W),17]	;STORE IT BACK IF POSITIVE
	POP	P,W		;RESTORE W
	JUMPG	T2,SEILM3       ;CONTINUATION PC
			        ;DON'T BREAK IF PROCEED COUNT .GT. 0
	MOVE	T2,JBTSTS##(J)	;IS THIS A JACCT
	TLNN	T2,JACCT	;JOB
	JRST	SEILM6		;NOT JACCT
	MOVE	T2,JBTPPN##(J)	;YES, BUT IS
	CAME	T2,FFAPPN##	; HE GOD?
	JRST	SEILM3		;NO-IGNORE BREAK
SEILM6:	EXCH	J,.CPJOB##	;UNDO LAST EXCH
	TLNN	T1,(XC.USR)	;PC IN USER MODE?
	JRST	SEILM2		;NO, REMEMBER BREAK AND GO AWAY
	MOVEM	T1,.JDAT+JOBPD1## ;SAVE FLAGS
	PUSH	P,.CPPC##+1	;AND PC
	MOVE	R,.CPADR##	;SETUP R
IFN FTPI,<
	MOVE	J,.CPJOB##	;JOB NUMBER FOR PSISER
	SIGNAL	C$ADRB		;SIGNAL THAT AN ADDRESS BREAK HAS OCCURED
	  JRST	.+2		;USER DOESN'T WANT TRAP
	JRST	SEILM5		;INTERRUPT TO THE USER
>	;END FTPI

	PUSHJ	P,TTYFUW##	;FIND THE USER'S TTY
	PUSHJ	P,INLMES##	;REPORT THE ADDRESS BREAK
	ASCIZ	/
%Address break/
	DMOVE	T1,.JDAT+JOBPD1## ;GET THE USER'S PC
	PUSHJ	P,DPCP##	;TELL HIM WHERE THE BREAK OCCURED
IFN FTPI,<
	PUSHJ	P,PSIERR##	;PENDING INTERRUPT?
	  JFCL
	  PJRST	ERRGOU##	;YES, GIVE IT TO THE USER
>
SEILMD:	DMOVE	T1,.JDAT+JOBPD1## ;GET USERS PC
	DMOVEM	T1,.CPPC##	;COULD HAVE CHANGED IF WE HAD TO WAIT
	PUSHJ	P,HOLD0##	;STOP THE JOB IN A CONTINUABLE STATE
	PJRST	WSCHD3##

SEILM2:	MOVEI	T2,JS.ASA	;AC'S ARE IN THE SHADOW AREA BIT
	EXCH	J,.CPJOB##	;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##	;RESTORE J
SEILM4:	MOVE	T1,.CPPC##	;GET FLAGS OF PC
	TLNE	T1,(XC.USR)	;BREAK OUT OF USER MODE?
	JRST	SEILM5		;YES
	DMOVE	T1,.CPST1##	;RESTORE T1 AND T2
	XJRSTF	.CPPC##		;GO AWAY AND TELL THE USER ABOUT THE BREAK
				; AT UUO EXIT
SEILM5:	USERAC			;USER'S AC BLOCK
	XJRSTF	.CPPC##		;EXIT TO USER
;HERE IF AN ILL MEM REF OCCURED IN EXEC MODE, CHECK FOR ERJMP OR
;ERCAL BEFORE CALLING IT AN IME

SEILM7:	CONSO	PI,PI.IPA	;AT INTERRUPT LEVEL?
	JRST	SEJLM2		;NO, UUO LEVEL, OK
	CONSO	PI,PI.IPA-PI.IP7 ;YES - LEVEL 7?
	SKIPN	.CPISF##	;YES, FROM SCHEDULER?
	JRST	SEILME 		;PI1 - PI6 OR NON-SCHEDULER PI7

SEJLM2:	SKIPE	.CPEJ1##	;NESTING?
	JRST	@[0,,SEILM8]	;YES, IT'S AN IME
	MOVE	T2,.CPPFW##	;GET FULL PAGE FAULT WORD
IFN FTPEEKSPY,<
	JUMPG	T2,SEJL2A	;JUMP IF NOT USER REF
	PUSHJ	P,INTLVL##	;YES, AT UUO LEVEL?
	  PUSHJ	P,[PUSHJ P,SAVT## ;YES, SAVE VOLATILE ACS
		   MOVE	 T1,T2	;VIRTUAL ADDRESS
		   LSH	 T1,W2PLSH## ;PAGE NUMBER
		   ANDI  T1,HLGPGS
		   MOVE  T4,T1	;PAGE #
		   LSH   T4,P2SLSH## ;ISOLATE SECTION #
		   SKIPE .UPMP+SECTAB(T4) ;IF SECTION NXS, NOT SPY
	           PUSHJ P,TSSPT## ;FAULT ON A SPY PAGE?
		     POPJ P,	;NO
		   PJRST UADERR##] ;YES, BLAME THE USER
SEJL2A:>
	DMOVEM	T1,.CPEJ1##	;"TOP LEVEL", REMEMBER IN CASE WE NEST
	DMOVEM	T1,.CPEJ3##	;ALSO SAVE HERE FOR PSYCHOPATHIC CASES
	MOVE	T2,.USPFP+1	;GET PC FAULT OCCURRED AT
	TLNE	T2,-1		;NON-ZERO SECTION?
	XJRST	[MCSEC1+.+1]  	;GO INTO SECTION 1
	LDB	T1,[POINT 22,T2,35] ;GET ADDRESS PART OF PAGE FAIL WORD

	SKIP	(T1)		;TOUCH PAGE FAULT PC LOCATION AND
	LDB	T2,[POINT 13,1(T1),12]  ;GET INSTRUCTION FOLLOWING
				; IF THE PC JUMPED OFF INTO THE BOONIES
				; THEN THIS WILL PAGE FAULT AND WE WILL
				; KNOW WE HAVE A REAL IME
	CAIE	T2,<ERJMP>_-^D23	;IS IT AN ERJMP?
	JRST	SEILM8		;NO, THEN WE HAVE AN IME
	MOVE	T2,1(T1)	;GET ENTIRE ERJMP EXPRESSION
	MOVEM	T2,.CPEJ4##	;SAVE WHERE WE CAN FIND IT
	TLNN	T1,-1		;NON ZERO SECTION?
	 JRST	SEJLM3		;NO, DO SECTION 0 CALCULATION
	TLZ	T2,777740	;NON-ADDRESSING PART OF ERJMP
	TLO	T2,(IFIW)	;MAKE A USABLE INDIRECT
	XMOVEI	T1,@T2		;RESOLVE ADDRESS OF ERJMP
	SKIPA			;JOIN COMMON CODE
SEJLM3:	MOVEI	T1,@.CPEJ4##	;RESOLVE ADDRESS OF ERJMP
				; IF THIS IME'S (NOTE .CPEJ1 STILL
				; NON-ZERO) THEN .CPEJ3 HAS ORIGINAL
				; TRAP PC WHICH STARTED THIS MESS.
	MOVEM	T1,.CPAPC##+1	;SET CONTINUATION ADDRESS
	DMOVE	T1,.CPST1##	;RESTORE T1&T2
	SETZM	.CPEJ1##	;CLEAR NESTING FLAG
	DATAO	PAG,.CPTCX##	;RESTORE TRAP CONTEXT
	XJRSTF	.CPAPC##	;....

;HERE ON NESTED IME, "RESTORE" THE FIRST IME AND STOPCD

SEILM8:	DMOVE	T1,.CPEJ1##	;PAGE FAULT PC AND REASON WORDS
	MOVEM	T1,.CPAPC##	;SET TRUE ERROR PC
	MOVEM	T1,.USPFP	;ALSO MAKE UPMP LOOK RIGHT
	MOVEM	T2,.CPPFW##	;SET TRUE PAGE FAULT WORD
	MOVEM	T2,.USPFW	;ALSO MAKE UPMP LOOK RIGHT
SEILME:	SETZM	.CPEJ1##	;CLEAR NESTING FLAG
	STOPCD	.+1,JOB,IME,DIEIME, ;++ILL MEM REF FROM EXEC
	DMOVE	T1,.USPFW	;GET PAGE FAULT WORD
	DMOVEM	T1,.CPPC##	;STASH AS CONTINUATION ADDRESS
	JRST	SEILM4		;AND CONTINUE

DIEIME:	PUSHJ	P,INLMES##	;ADD SOME TEXT
	ASCIZ	/Page fail word = /
	MOVE	T1,.USPFW	;GET PAGE FAIL WORD
	PJRST	HWDPNT##	;PRINT AS HALF-WORDS AND RETURN
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,<
	DMOVE	T1,.JDAT+JOBPD1## ;GET UUO PC
	DMOVEM	T1,.CPPC##	;STORE IT WHERE PSISER EXPECTS IT
	SIGNAL	C$ADRB		;SIGNAL THAT AN ADDRESS BREAK OCCURED
	  SKIPA			;USER DOESN'T WANT TRAP
	POPJ	P,		;USER IS ENABLED, UUO EXIT WILL INTERRUPT TO HIM
>
	PUSHJ	P,TTYFUW##	;FIND THE USER'S TTY
	PUSHJ	P,INLMES##	;REPORT THE ADDRESS BREAK
	ASCIZ	/
%Address break/
	DMOVE	T1,.CPAPC##
	PUSHJ	P,DPCP##	;TELL HIM THAT
	MOVEI	T1,[ASCIZ/; UUO/]
	PUSHJ	P,CONMES##
	DMOVE	T1,.JDAT+JOBPD1## ;GET THE UUO PC
	PUSHJ	P,DPCP##	;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
	JRST	SEILMD		;AND STOP THE JOB IN A CONTINUABLE STATE
;HERE FROM SEILM IF PAGE FAULT IS IN USER MODE AND APRENB DONE
;T3=PAGE FAULT WORD
SUILMX::
	DMOVE	T1,.USMUO	;GET PC FROM "UUO"
	JRST	SUILM1
SUILM:	DMOVE	T1,.USPFP	;GET DOUBLE WORD PC
SUILM1:	MOVE	R,.CPADR##	;GET THE ADDRESS OF THE USER'S JOB DATA AREA
	PUSHJ	P,USRFLT##	;SEE IF PAGE FAULT FOR VM USER
				; WILL NOT RETURN IF SO (DISPATCH TO PFH)
	MOVEI	T3,AP.ILM	;SET ILM BIT FOR USER
	JRST	SAROV3		;FINISH UP
SUPDLO::
	DMOVE	T1,.USMUO	;GET FLAGS & PC
	MOVEI	T3,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,.CPJOB##	;J=CURRENT JOB NUMBER
	MOVEI	T1,0
	DPB	T1,JBYHSS##	;FORCE MAP TO BE REDONE
SETREL::MOVE	J,.CPJOB##	;J = CURRENT JOB NUMBER
SETRL1::MOVE	R,JBTADR##(J)	;R = XWD PROTECTION,,EXEC VIRTUAL ADDRESS
				; OF THE FIRST PAGE OF THE LOW SEGMENT
	MOVE	T2,.CPADR##	;PREVIOUS JOB'S CORE, 0 IF NONE
	MOVEM	R,.CPADR##	;SET .CPADR FOR QUICK ACCESS AT APR LEVEL
	HLRZM	R,.CPREL##	;SET .CPREL FOR ADDRESS CHECKING
IFN FTTRPSET,<
	SKIPE	T1,.CPSTS##	;HAS TIMESHARING BEEN STOPPED VIA TRPSET?
	CAIE	T1,(J)		;YES, WAS IT THIS JOB?
	JUMPN	T1,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
	HRRZ	T1,JBTUPM##(J)	;PAGE NUMBER OF THE CURRENT JOB'S UPMP
	JUMPE	T1,SETRL2	;DON'T CHANGE ANYTHING IF THERE ISN'T ONE
	HRLI	T1,(LG.LUB+LG.LPC+LG.KPM) ;SET THE LOAD BIT, PCS = 0
IFN FTRTTRP,<
	MOVEM	T1,.CPDTO##	;SAVE FOR RTTRP INTERRUPT LEVEL USE
>
	CONO	PI,PI.OFF	;MAKE CHANGING ADDRESSABILITY ATOMIC
	HRRM	T1,@.CPSPT##

	SKIPN	T2		;LAST JOB STILL HAVE CORE?
	DATAO	PAG,NULDOP##	;DUMP THE METERS
	DATAO	PAG,T1		;SETUP THE UBR, UPDATE METERS
	CONO	PI,PI.ON	;CONTEXT SWITCH NOW DONE

	JUMPE	R,SETRLZ	;DONE IF NULL JOB
	HLRZM	R,.USHVA	;SET .UPHVA FOR ADDRESS CHECKING AT IRP LEVEL
	SKIPN	T1,.USREL	;HOLEY PROGRAM?
	HLR	T1,R
	HRRZM	T1,.JDAT+JOBREL## ;STORE HIGHEST CORE-UUO ADDRESS IN JOBREL
	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##
	MOVSI	T3,REDOMP!SEGMB	;FORCING THE MAP TO BE REDONE?
	TDNN	T3,JBTSGN##(J)
	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
	MOVSI	T1,REDOMP!SEGMB	;INDICATE MAP HAS BEEN REDONE NOW
	ANDCAM	T1,JBTSGN##(J)

SETRLZ:	MOVE	T3,JBTPDB##+0	;NULL JOB PDB
	PUSHJ	P,FNDPDS##	;SET UP W
	.SKIPE	T2,.PDABS##(W)	;DOES THE USER HAVE ADDRESS BREAK SETTINGS?
	TLNN	T2,(OC.ABE)	;YES, IS HE ENABLED FOR BREAKS
	JRST	SETRL3
	TLZ	T2,(OC.BSU)	;CLEAR SET BY UUO
	TLZE	T2,(1B0)	;CHANGE NEW HARDWARE INTO
	TLO	T2,(1B9)	; OLD. OR CHANGE OLD
	TLZE	T2,(1B1)	; SOFTWARE INTO NEW
	TLO	T2,(1B10)	; ..
	TLZE	T2,(1B2)	; ..
	TLO	T2,(1B11)	; ..
	TLZE	T2,(1B6)	; ..
	TLO	T2,(1B12)	; ..
	CAIA			;
SETRL3:	SETZ	T2,
	.SKIPL	.PDABS##(T3)	;CAN USERS USE ADDRESS BREAK?
	DATAO	APR,T2		;YES, SETUP BREAK CONDITIONS AND BREAK ADDRESS
	MOVEM	T2,.CPAPR##	;STORE BREAK CONDITIONS FOR SSEUB
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,.JDAT+JOBENB##	;JOB'S APR ENABLE BITS
	PJRST	SETCNA##	;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
;ENTER AT MKADD TO JUST MAKE THE JOB ADDRESSABLE

MKADD::	CAME	J,.USJOB	;GO AWAY IF ALREADY ADDRESSABLE
STEUB::	CAILE	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	POPJ	P,		;YES, 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
	CONO	PI,PI.OFF	;NO INTERRUPTS WHILE CHANGING UBR/SPT
	SKIPE	T1		;IF NOT ZERO,
	HRRM	T1,@.CPSPT##	; SETUP NEW SPT
	TDO	T1,[LG.LUB+LG.KPM+LG.IAM] ;REQUEST LOADING OF UBR
	TRNE	T1,17777	;IS THERE A UPMP
	DATAO	PAG,T1		;SET FOR CURRENT USER AND CLEAR THE AM
	CONO	PI,PI.ON	;BOTH THE SPT AND UBR HAVE BEEN CHANGED
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

IFN FTXMON,<
;ROUTINES TO SETUP PCS FROM DEVISN.
;CALLING SEQUENCE:
;	MOVE	F,DDB ADDRESS
;	PUSHJ	P,SPCS
;ROUTINES CALLING THIS ROUTINE SHOULD CALL SVEU? SO THAT PCS WILL BE
; RESTORED ON A POPJ FROM THE CALLING ROUTINE

SPCS::	PUSH	P,T1		;SAVE A TEMP
	HRRZ	T1,DEVISN(F)	;GET SECTION NUMBER FOR I/O
	MOVSI	T1,<(LG.LPC)>(T1) ;LOAD PREVIOUS CONTEXT SECTION
	DATAO	PAG,T1		;PREVIOS CONTEXT IS ADDRESSABLE
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
>
IFE FTXMON,<
SPCSB==:SVEUB
SPCSF==:SVEUF
SPCS==:CPOPJ##
>
IFN FTEMRT,<
;ROUTINES TO HANDLE ACCOUNTING METERS

;RETURN EBOX COUNTS FROM CURRENT UPT IN T1 AND T2

GETEBT::RDEACT	T1		;READ EBOX COUNTS INTO T1,T2
	POPJ	P,		;RETURN

GETMBT::RDMACT	T1		;SAME FOR MBOX COUNTS
	POPJ	P,

;ROUTINE TO TURN ACCOUNTING METERS ON AND OFF
; CALLED BY CLOCK1 TO EXCLUDE MONITOR OVERHEAD FROM USER RUNTIME
; ACCMON AND ACCMOF PRESERVE ALL ACS

ACCMON::PUSH	P,T1
	PUSH	P,T2		;SAVE T1,T2
	CONI	MTR,T1		;GET PI ASSIGNMENT, TIME BASE ON/OFF
	TRO	T1,MO.LAC!MO.AEN!MO.AIP!MO.AO	;MAKE SURE LOAD ACCT, EXEC NO PI
				; PI, ACCT METER ON
	MOVE	T2,CNFST2##	;GET CNFST2
	TRNE	T2,ST%XPI	;EXCLUDE PI FROM USER RUNTIME?
	TRZ	T1,MO.AIP	;YES, THEN DON'T INCLUDE
	CONO	PI,PI.OFF	;TURN OFF PI'S SO ACCOUNTING METER AND PERF METER
				; WILL STAY IN SYNC
	CONO	MTR,(T1)	;SET STUFF, TURN METER ON
	SKIPE	.CPAPS##	;IF ACCT/PERF METER SYNC,
	PUSHJ	P,SCDPMR	;GO TURN PERFORMANCE METER ON IF NECESSARY
	CONO	PI,PI.ON	;BACK ON
	POP	P,T2		;RESTORE T2
	JRST	TPOPJ##		;T1 AND RETURN

;TURN OFF ACCOUNTING METER

ACCMOF::PUSH	P,T1		;SAVE AN AC
	CONI	MTR,T1		;GET PI ASSIGNMENT, OTHER STUFF
	ANDI	T1,7		;ONLY PI ASSIGNMENT
	TRO	T1,MO.LAC	;LOAD ACCOUNTING ENABLES - ZILCH
	CONO	PI,PI.OFF	;TURN OFF PI'S
	CONO	MTR,(T1)	;STOP THE CLOCK
	SKIPE	.CPAPS##	;ACCOUNTING/PERF SYNC?
	PUSHJ	P,STPPMR	;YES, TURN OFF PERFORMANCE METER
	CONO	PI,PI.ON	;PI BACK ON AGAIN
	PJRST	TPOPJ##		;RESTORE T1 AND RETURN

;STILL IN FTEMRT CONDITIONAL
;CLEAR EBOX, MBOX COUNT FOR CURRENT UPT
; THESE ROUTINES PRESERVE ALL AC'S

CLREMB::DATAI	PAG,1(P)		;WRITE OUT ALL THE BITS
	DATAO	PAG,1(P)
	SETZM	.UPMP+.LMEBL	;LOW ORDER BITS FIRST SO NO OVERFLOW
	SETZM	.UPMP+.LMEBH	;THEN HIGH ORDER
	SETZM	.UPMP+.LMMBL	;LOW ORDER FIRST
	SETZM	.UPMP+.LMMBH	;THEN HIGH
	POPJ	P,		;RETURN

>;END IFN FTEMRT
SUBTTL	IOCSS - I/O SERVICE SUBROUTINES (UUOCON AND DEVICE ROUTINES)

;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
	PUSH	P,@.CPSPT##
	DATAI	PAG,T1		;GET THE USER BASE REGISTER
	PUSH	P,J		;SAVE J
	LDB	J,PJOBN##	;GET THE JOB NUMBER OF JOB CURRENTLY USING
				; THIS DEVICE
	PUSHJ	P,MKADD		;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
	PUSH	P,@.CPSPT##
	DATAI	PAG,T1		;GET THE CONTENTS OF THE USER BASE REGISTER
	PUSHJ	P,MKADD		;SETUP THE UBR FOR THE JOB WHOSE JOB NUMBER
				; IS IN J
	JRST	SSEU1		;SAVE THE PREVIOUS CONTENTS OF THE UBR
SSEUB::	PUSH	P,T1		;SAVE A TEMPORARY
	PUSH	P,@.CPSPT##
	DATAI	PAG,T1		;GET THE CONTENTS OF THE USER BASE REGISTER
SSEU1:	EXCH	T1,-2(P)	;GET THE CALLER'S PC AND SAVE THE CONTENTS
				; OF THE UBR
	MOVEM	T1,1(P)		;SAVE THE CALLER'S PC IN A TEMPORARY LOCATION
				; ON THE STACK
	MOVE	T1,-1(P)	;RESTORE T1 TO ITS CONTENTS ON ENTRY
	DATAI	APR,-1(P)	;SAVE ORIGINAL BREAK CONDITIONS
				; THIS DOES NOT STORE BREAK ADDR
	DATAO	APR,[0]		;NO ADDRESS BREAKS
	PUSHJ	P,@1(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
	  CAIA			;CPOPJ RETURN
	AOS	-3(P)		;CPOPJ1 RETURN - BUMP RETURN PC
	CONO	PI,PI.OFF	;DON'T ALLOW INTERRUPTS UNTIL UBR/SPT AGREE
	POP	P,@.CPSPT##
	EXCH	T1,-1(P)	;GET THE PREVIOUS CONTENTS OF THE UBR
	DATAI	PAG,1(P)	;READ INTO A TEMP
	CAMN	T1,1(P)		;GOING TO CHANGE IT TO WHAT IT IS?
	JRST	SSEU2		;YES, DON'T CLEAR THE PAGING MEMORY
	TDO	T1,[LG.KPM+LG.IAM] ;DON'T UPDATE METERS
	DATAO	PAG,T1		;RESTORE THE UBR
SSEU2:	CONO	PI,PI.ON	;SAFE TO ALLOW INTERRUPTS
	POP	P,T1		;RESTORE BREAK CONDITIONS
	HRR	T1,.CPAPR##	;GET BREAK ADDRESS
	DATAO	APR,T1		;RE-ENABLE ADDRESS BREAK
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

;SUBROUTINE TO SAVE CURRENT PCS, SET IT TO (T1) AND RESTORE IT TO PREVIOUS
; VALUE ON CPOPJ OR CPOPJ1 RETURN

SVPCS::	PUSH	P,(P)		;COPY AS SECOND WORD OF PC
	XSFM	-1(P)		;READ FLAGS AND PCS
	PUSH	P,-1(P)		;COPY OLD FLAGS AND PCS TO TOP OF THE STACK
	HRRM	T1,-2(P)	;STORE DESIRED (NEW) PCS
	PUSH	P,T1		;SAVE ARGUMENT
	HRLOI	T1,37		;IN CASE IN SECTION 0,
	ANDM	T1,-2(P)	; IN PC SO WE DON'T XJRSTF INTO THE BOONIES
	POP	P,T1		;RESTORE ARGUMENT
	PUSHJ	P,[XJRSTF -3(P)];CALL CALLER AS A COROUTINE WITH NEW PCS SETUP
	  CAIA			;NON-SKIP RETURN
	AOS	-3(P)		;SKIP RETURN, PROPAGATE IT
	PUSH	P,-3(P)		;COPY RETURN PC TO THE TOP OF THE STACK
	PUSH	P,T1		;SAVE T1 AS RETURNED FROM SUBROUTINE CALL
	HRLOI	T1,37		;CLEAR FLAGS
	ANDM	T1,-1(P)	; IN CASE IN SECTION 0
	POP	P,T1		;RESTORE T1
	ADJSP	P,-5		;RESET STACK
	XJRSTF	4(P)		;RESTORE OLD PCS AND RETURN
;COROUTINE TO SAVE THE CALLER'S PCS, AND RESTORE IT UPON THE CORETURN.
;CALLING SEQUENCE:
;	PUSHJ	P,SSPCS
;	ALWAYS RETURNS HERE
;RESTORES PCS ON RETURN

SSPCS::	EXCH	T1,(P)		;SAVE CALLER'S T1, GET RETURN PC
	MOVEM	T1,1(P)		;PUT IT WHERE COROUTINES DO
	XSFM	T1		;GET CURRENT PCS
	ANDI	T1,MXSECN	;KEEP ONLY SECTION NUMBER
	EXCH	T1,(P)		;SAVE FOR CORETURN AND RESTORE CALLER'S T1
	PUSHJ	P,@1(P)		;CALL CALLER
	  CAIA			;PROPAGATE NON-SKIP
	AOS	-1(P)		; VS SKIP RETURN
	EXCH	T1,(P)		;SAVE T1 AND GET ORIGINAL PCS
	MOVSI	T1,<(LG.LPC)>(T1) ;LOAD PREVIOUS CONTEXT SECTION
	DATAO	PAG,T1		;SET UP PCS
	JRST	TPOPJ##		;RESTORE T1 AND RETURN TO CALLER'S CALLER


;ROUTINE TO SETUP PCS AS DESIRED BY THE CALLER
;CALLING SEQUENCE:
;	MOVEI	T1, SECTION #
;	PUSHJ	P,STPCS
;	ALWAYS RETURN HERE WITH PCS SETUP
;PRESERVES ALL REGISTERS

STPCS::	PUSH	P,T1		;IN CASE OF BITS
	ANDI	T1,MXSECN	;MASK DOWN TO JUST SECTION NUMBER
	MOVSI	T1,<(LG.LPC)>(T1) ;LOAD PREVIOUS CONTEXT SECTION
	DATAO	PAG,T1		;SETUP PCS AS DESIRED
	JRST	TPOPJ##		;RESTORE T1 AND 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
;	MOVE	P4,FRAME-COUNT,,CHARS/WD
;	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
;	P2=LOC OF IOWD WE JUST STORED, IF A DX10

MAPIO::	TLNN	T2,-1		;0 OR CHANNEL JUMPS ARE ILLEGAL
	STOPCD	CPOPJ##,DEBUG,IEZ,	;++IOWD EQUALS ZERO
	PUSH	P,U		;SAVE U
	HLLZ	U,CHB22B##(P3)	;GET CHANNEL-TYPE WORD
	TLNE	U,CP.RH2##!CP.KLP##!CP.KNI## ;INTERNAL CHANNEL DEVICE?
	TROA	U,4		;YES
	LDB	U,[POINT 2,U,1]	;NO, GET CHAN TYPE ELSEWHERE
	HLL	U,P4		;PRESERVE FRAMECOUNT
	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
	TRNE	U,4		;INTERNAL CHANNEL DEVICE?
	SETZM	CHNTCW##(P3)	;ACCUMULATE WORD-COUNT IN CHNTCW (FOR RH20)
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	MAPIO7		;NO MORE FOUR WORD BLOCKS
	MOVE	P4,-2(P)	;RESTORE THE IOWD TO P4
	MOVE	T2,P4		;T2 AND P4 = IOWD
	HLROS	P4		;P4 = -WORD COUNT
	ADDI	T2,1		;POINT AT REAL ADR
	LDB	P3,DEYISN##	;GET RUNNING SECTION FOR I/O
	ADDM	P3,DEVISN(F)	;UPDATE DEVISN FOR THIS I/O OPERATION
	SETZ	P3,		;NO RUNNING TOTAL NOW
	DPB	P3,DEYISN##	;ZAP REMEMBERANCE OF CROSSING SECTION BOUNDARIES
	HRRZ	P3,T2		;VIRTUAL ADDRESS WITHIN SECTION
MAPIO2:	PUSHJ	P,[PUSH P,P3	;T3 = CURRENT ABSOLUTE ADDRESS
		   PUSHJ P,V2PADR;GET IT
		     JRST P3POPJ## ;ILLEGAL PAGE(S)
		   AOS -1(P)	;PROPAGATE SKIP
		   JRST P3POPJ##] ;GOOD RETURN
	  SKIPGE	USRHCU## ;IF A SAVE IS IN PROGRESS,
	SKIPA			; THEN, THIS IS OK
	JRST	S..AAO		;ACCESS ALLOWED OFF
				; IOWD HAS BEEN ADDRESS CHECKED)
	MOVEI	T1,0		;T1 = AMOUNT ACCUMULATED SO FAR
	MOVE	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,MAPIO5	;JUMP IF THE ORIGIONAL WORD COUNT IS EXHAUSTED
	SUB	P3,T2		;UPDATE VIRTUAL ADDRESS BY AMOUNT DONE
	MOVN	T4,T2		;SET T4 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
	ADD	T4,T3		;T4 = CURRENT PHYSICAL ADDRESS WITHIN SEGMENT
	PUSHJ	P,[PUSH P,P3	;T3 = NEXT PHYSICAL ADDRESS WITHIN PAGE
		   PUSHJ P,V2PADR;GET IT
		     JRST P3POPJ## ;ILLEGAL PAGE(S)
		   AOS -1(P)	;PROPAGATE SKIP
		   JRST P3POPJ##] ;GOOD RETURN
	  STOPCD	.,JOB,AAO,	;++ACCESS ALLOWED IS OFF
	MOVNI	T2,PAGSIZ##	;ASSUME WILL DO ANOTHER WHOLE PAGE
	CAMLE	P4,[-PAGSIZ##]	;LESS THAN A PAGE LEFT IN USER IOWD
	MOVE	T2,P4		;YES, WILL JUST DO THAT MUCH
	ADD	T2,T1		;GET UPDATED WORD COUNT
	TRNN	U,4		;INTERNAL CHANNEL DEVICE?
	JRST	MAPI3A		;NO
	CAME	T2,[-600000]	;DON'T GENERATE IOWD WHOSE LH
	CAMN	T2,[-030000]	; LOOKS LIKE AN RH20 CHANNEL JUMP
	JRST	MAPIO4
MAPI3A:	CAMN	T4,T3		;ARE THE TWO PAGES ADJACENT IN PHYSICAL MEMORY?
	JRST	MAPIO3		;YES, CONTINUE ON CURRENT IOWD
MAPIO4:	POP	P,(P1)		;STORE THE IOWD ABSOLUTE ADDRESS
	PUSHJ	P,DXFIX		;ADJUST IOWD IF A DX10
	  JRST	MAPI6A		;NO SPACE
	JUMPL	U,MAPIO6	;DONE 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	MAPI6A		;WHOOPS! NONE AVAILABLE
	JRST	MAPIO2		;MAP THE REST OF THE IOWD
MAPIO5:	POP	P,(P1)		;STORE THE IOWD ABSOLUTE ADDRESS
	ADDB	P4,T1		;ADD THE RESIDUAL WORD COUNT TO THE ACCUMULATED
				; WORD COUNT
	PUSHJ	P,DXFIX		;PERFORM FIXUPS FOR DX10
	  JRST	MAPI6A		;OUT OF SPACE
				; THE ALREADY ABSOLUTE IOWD AND RETURN
MAPIO6:	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
MAPI6A: HLRZS	P3		;CURRENT SECTION OFFSET FROM DEVISN
	HLRE	T1,-2(P)	;GET WORD COUNT
	MOVNI	T1,-1(T1)	;POSITIVE WORD COUNT + 1
	ADD	T1,-2(P)	;+ STARTING ADDRESS - 1
	TRNN	T1,-1		;I/O END AT A SECTION BOUNDARY?
	ADDI	P3,1		;YES, THEN START NEXT OP IN NEXT SECTION
	DPB	P3,DEYISN##	;SAVE THAT FOR NEXT TIME
MAPIO7:	SKIPGE	-3(P)		;IF WE WANT IT STORED,
	TRNE	U,5		;TYPE 0 OR 2 OR 4 CONTROLLER?
	JRST	MAPIO8		;NO, DON'T DO NEXT
	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	T4,-3(P)
	MOVEM	T1,CHNTCW##(T4)
MAPIO8:	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
;ROUTINE TO FINISH UP AN RH20 IO LIST
;PRESEVES T1
RH2ND::	PUSH	P,T1
	PUSH	P,U
	MOVEI	U,4		;TELL THE WORLD IT AN RH20
	MOVEI	T3,177
	ANDB	T3,CHNTCW##(P3)	;NO SWEAT IF AN EVEN MULTIPLE OF 200 WORDS
	JUMPE	T3,RH2ND1
	TLNE	S,IOSUPR##
	TRNN	S,UDSX##	;ASSUME USER KNOWS IF HE'S FORMATTING
	PUSHJ	P,CHKMOR	;NOT EVEN MULTIPLE, HAVE TO INSERT A THROW-AWAY WORD
	  JRST	RH2ND1		;NO MORE ROOM, LET IT GO ANYWAY
	MOVN	T3,CHNTCW##(P3)	;COMMPUTE NO OF WORDS TO 0-FILL
	ADDI	T3,200+RH2TLS##	;NO OF WORDS AND LAST+TRA
	LSH	T3,^D22		;POSITION IT
	MOVEM	T3,(P1)		;STORE THE THROW-AWAY IOWD
	TLZ	T3,077777	;JUST LAST+TRA
	AOBJN	P1,RH2ND2	;STORE TCW AND EXIT (AOBJN ALWAYS JUMPS)
RH2ND1:	MOVSI	T3,RH2LST##	;LIGHT LAST-BIT IN IOWD
	IORB	T3,-1(P1)
	LDB	T2,[POINT 11,T3,13]	;GET WORDCOUNT
	TDNE	T3,[17,,-1]	;ADR = 0 IS SPECIAL
	ADD	T3,T2		;ADDR + N
	TLZ	T3,077760	;WDCNT SHOULD GO TO 0
RH2ND2:	MOVEM	T3,CHNTCW##(P3)	;SAVE EXPECTED TERM WORD
	POP	P,U
	PJRST	TPOPJ##		;AND RETURN TO CALLER
;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
;	MOVEI	U,4 IF RH20
;		  3 IF DX10
;		  0 IF NOT RH20 OR DX10
;	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:
	TRNE	U,4		;RH20?
	HRLI	T1,RH2JMP##	;YES, MAKE RIGHT STYLE JUMP-WORD
	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
;ROUTINE TO CONVERT A VIRTUAL ADDRESS (USER OR EXEC) TO A PHYSICAL
; ADDRESS
;CALLING SEQUENCE:
;	MOVE	F,ADDRESS OF DDB WITH DEVISC (SECTION NUMBER FOR I/O)
;		  SETUP IN IT
;	MOVE	P3,VIRTUAL ADDRESS
;	PUSHJ	P,V2PADR	;GET PHYSICAL ADDRESS WHICH CORRESPONDS TO VIRTUAL ADDRESS
;	  RETURNS HERE IF PAGE NOT ACCESSIBLE
;	RETURNS HERE, T3 = PHYSICAL ADDRESS CORRESPONDING TO C(DEVISN)B18+(P3)
;

V2PADR:	SKIPL	DEVISN(F)	;IOWD ALLOWED TO CROSS A SECTION BOUNDARY?
	TLNN	P3,-1		;NO, DOES IT?
	SKIPA	T3,T1		;IOWD IS OK, SAVE T1
	POPJ	P,		;IOWD CROSSES SECTION BOUNDARY WHEN IT SHOULDN'T
	HRLZ	T1,DEVISN(F)	;SECTION NUMBER WHERE ORIGINAL IOWD STARTED
	ADD	P3,T1		;SECTION NUMBER FOR I/O
	HLRZ	T1,P3		;PCS SECTION
	PUSHJ	P,SVPCS		;SAVE PCS AND SET IT TO SECTION NUMBER FOR I/O
	MOVE	T1,T3		;RESTORE T1
	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	;IF A DSK
	CAIA
>
	SKIPN	T3
	SKIPL	S
	SKIPA	T3,[XCT 4,[MAP T3,(P3)]]
	MOVSI	T3,(MAP T3,(P3))
	SE1ENT			;SAVE CALLER'S SECTION, ENTER SECTION 1
	XCT	T3		;MAP OR PXCT OF A MAP
	TLNN	T3,(1B1)	;BAD FAIL OR
	TLNN	T3,(17B5)
	POPJ	P,		;YES TO EITHER, WILL FAULT
V2PAD1:	TLZ	T3,777760	;CLEAR ACCESS BITS
	JRST	CPOPJ1##	;REF OK. WIN.
;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:	TRNE	U,4		;RH20?
	JRST	RH2FIX		;YES, DO DIFFERENTLY
	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		;ROOM FOR MORE?
	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
	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		;5ROCEED

DXFIX2:	DPB	T1,WDCPNT##(U)	;STORE RESIDUE
	HRL	P2,P1		;LOC OF THE IOWD
	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


;ROUTINE TO HANDLE RH20 DEVICES
RH2FIX:	SKIPE	(P1)		;UNLESS THROW-AWAY IOWD
	AOS	(P1)		;RH20 LIKES ADDRESS
	MOVNS	T1		; AND POSITIVE WRDCNT
	HLRZ	T3,U		;GET FRAME COUNT
	JUMPE	T3,RH2FX0	;DO WE HAVE FC?
	MOVE	T4,-5(P)	;YES, RESTORE CHAR/WD
	IDIVI	T3,(T4)		;FC TO WC
	SKIPE	T4		;EXTRA FRAMES?
	ADDI	T3,1		;YES, ADD A WORD
	CAMLE	T1,T3		;TAKE SMALLER
	MOVE	T1,T3
RH2FX0:	MOVE	T3,-4(P)
	ADDM	T1,CHNTCW##(T3)	;ACCUMULATE WDCNT
RH2FX1:	CAIG	T1,3600		;IF LESS THAN 12 BITS,
	JRST	RH2FX3		; DONT HAVE TO FIDDLE WITH IT
	MOVEI	T3,3600+RH2TRX##	;ONLY CAN DO 11 BITS IN ONE IOWD
	DPB	T3,WDCPNT##+3	;SAVE THIS IOWD
	SUBI	T1,3600		;ACCUMULATE WHAT WE'VE DONE SO FAR
	PUSH	P,(P1)		;SAVE PARTIAL IOWD
	AOBJN	P1,RH2FX2	;GO IF ROOM FOR ANOTHER IOWD
	PUSH	P,T1		;SAVE WDCNT
	PUSHJ	P,GETMOR	;GET ANOTHER 4-WORD BLOCK
	  JRST	DXFIX3		;NO MORE - GIVE LOSE RETURN
	MOVEI	T2,0		;RESET T2 TO BEGINNING OF PAGE
	POP	P,T1		;RESTORE COUNT
RH2FX2:	POP	P,T3		;RESTORE PARTIAL IOWD
	TDNE	T3,[17,,-1]	;IF NOT A SKIP-IOWD
	ADDI	T3,3600		;UPDATE ADDR
	MOVEM	T3,(P1)		;SAVE NEW IOWD (ONLY ADR USED)
	JRST	RH2FX1		;AND SET WDCNT FOR NEXT PIECE
RH2FX3:	TRO	T1,RH2TRX##	;INDICATE THIS IS A DATA-IOWD
	DPB	T1,WDCPNT##+3	;STORE WDCNT AND TRA-BIT
	JRST	CPOPJ1##	;INDICATE WE WON
;SUBROUTINE TO REVERSE THE IOWDS FOR A READ-OPPOSITE
;WORKS ONLY FOR AN RH20 DEVICE
;CALL WITH T1=IORB   T2=WORDCOUNT
;RETURNS WITH T1=IORB, THE LIST REVERSED
;RETURNS T2=ORIGINAL LH OF IOWD WHICH GOT CHANGED,,ITS ADDRESS
REVCCW::HRRZ	T3,TRBXCW(T1)
				;FALL INTO REVCC

;SUBROUTINE TO REVERSE IOWDS
;CALL WITH T2=WRDCNT, T3=ADDR OF IO LIST
;RETURNS WITH IO LIST REVERSED
;PRESERVES T1
REVCCD::			;(DOESNT GUARANTEE T1)
REVCC:	JUMPE	T2,CPOPJ##	;WORDCOUNT OF 0 WILL CAUSE A CRASH
	PUSHJ	P,SAVE4##
	SETZ	P1,
	PUSH	P,T3
REVCC1:	SKIPN	P2,(T3)
	SOJA	T3,REVCC5
	TLNE	P2,JMPRH2##
	AOJA	P1,REVCC2
	HRRZ	T3,P2
	JRST	REVCC1
REVCC2:	LDB	T4,CNTPP2##
	CAMLE	T4,T2
	JRST	REVCC3
	SUB	T2,T4
	JUMPE	T2,REVCC4
	TLNE	P2,RH2LST##
	JRST	REVCC5
	AOJA	T3,REVCC1
REVCC3:	DPB	T2,CNTPP2##
REVCC4:	TLO	P2,RH2LST##
REVCC5:	MOVE	P4,T3
	HLL	P4,(P4)
	MOVEM	P2,(T3)
	POP	P,T2

;HERE WITH P1= # OF IOWDS, T2 POINTS AT 1ST IOWD, T3 POINTS AT LAST IOWD
REVCC6:	SOJLE	P1,REVCC9
	MOVE	P3,(T3)
	MOVE	P2,(T2)
	TLZE	P3,RH2LST##
	TLO	P2,RH2LST##
	PUSHJ	P,REVIOW
	MOVEM	P2,(T3)
	MOVE	P2,P3
	PUSHJ	P,REVIOW
	MOVEM	P2,(T2)
	SOJLE	P1,REVCCA
	ADDI	T2,1
	MOVE	T4,(T2)
	TLNN	T4,JMPRH2##
	HRR	T2,T4
	MOVEI	P3,-1(P1)
	HRRZ	T3,T2
REVCC7:	AOSA	T3
REVCC8:	HRR	T3,T4
	MOVE	T4,(T3)
	TLNN	T4,JMPRH2##
	JRST	REVCC8
	SOJG	P3,REVCC7
	JRST	REVCC6
REVCC9:	JUMPL	P1,REVCCA
	MOVE	P2,(T2)
	PUSHJ	P,REVIOW
	MOVEM	P2,(T2)
REVCCA:	MOVE	T2,P4
	POPJ	P,

REVIOW:	LDB	T4,CNTPP2##
	TLCE	P2,RH2REV##
	JRST	[SUBI P2,-1(T4)
		 POPJ P,]
	ADDI	P2,-1(T4)
	POPJ	P,
;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
	HRRZ	P1,T1		;P1 = ADDRESS OF THE IOWD LIST
RTNIO1:	MOVEI	T1,1		;GIVE BACK ONE FOUR WORD BLOCK
	HRRZ	T2,P1		;ADDRESS OF THE BLOCK
	MOVE	T3,3(P1)	;LAST WORD OF BLOCK
	TLNN	T3,577777	;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::MOVE	T1,NOIOWD##	;IF WE ARE LOW ON IOWD SPACE
	CAMGE	T1,NUMKON##	; ONLY GIVE AN IOWD
	JUMPN	P1,CPOPJ##	; FOR THE INITIAL IOWDS
	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
	SOS	NOIOWD##	;1 LESS IOWD BLOCK
	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
	ADDM	T1,NOIOWD##	;1 MORE IOWD BLOCK
	PJRST	SETZRS##	;CLEAR THE BITS AND RETURN
;ROUTINE TO INVALIDATE ENTIRE CACHE AND VALIDATE CORE
; ALWAYS RETURN CPOPJ, RESPECTS ALL ACS
; LOOP IN ACS WHILE WAITING FOR FLUSH COMPLETION TO MINIMIZE
; MEMORY INTERFERENCE.

CSDMP::	SWPUA			;SWEEP - UPDATE ALL PAGES, INVALIDATE CACHE
	PUSHJ	P,SAVE3##	;SAVE E3 ACCUMULATORS
	DMOVE	P1,CSHWAT	;CACHE WAITING INSTRUCTIONS
	MOVE	P3,CPOPJ##
	PJRST	P1		;WAIT IN ACS


CSHWAT:	CONSZ	APR,LP.CSB	;WAIT FOR CACHE SWEEP TO HAPPEN
	JRST	P1

IFN FTMP,<
;SUBROUTINE TO CHASE A LINE OUT OF THE CACHE
;ENTER T1=ADDRESS
;EXIT WITH THAT LOCATION NOT IN THE CACHE
;PRESERVES T2-T4
OUCHE::	ANDI	T1,777		;GET LINE NUMBER
	SKIP	@OUCHTB##
	SKIP	@OUCHTB##+1
	SKIP	@OUCHTB##+2
	SKIP	@OUCHTB##+3
	SKIP	@OUCHTB##+4
	SKIP	@OUCHTB##+5
	SKIP	@OUCHTB##+6
	SKIP	@OUCHTB##+7
	POPJ	P,
>

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:	PUSHJ	P,@.CPMPS##
;	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

CPLMPS::PUSHJ	P,MAPLOC##	;GET EXEC MAP SLOT
	MOVE	W,T1		;SAVE BYTE POINTER TO EXEC MAP SLOT
	MOVSI	P3,(<PM.DCD>B2+PM.WRT+PM.PUB)

	LDB	T4,[POINT 14,NWCORE##,26] ;T4=NUMBER OF PAGES TO SCAN
	SKIPA	P4,[POINT 1,NXMTAB##] ;BYTE POINTER TO NXM TABLE
MPSLP1:	AOS	P3		;STEP TO NEXT PAGE
	SOJL	T4,MPSLP5	;RESTORE T1 AND RETURN IF SCANNED ALL OF MEMORY
	ILDB	T1,P4		;DOES THIS PAGE EXIST?
	JUMPN	T1,MPSLP1	;IF NOT, GO BACK FOR NEXT
	DPB	P3,W		;MAP THE CURRENT PAGE
	MOVE	P1,T3		;EVA FOR BEGINNING OF PAGE
	CLRPT	(P1)		;CLEAR HDW PAGE TABLE FOR NEW MAPPING
	MOVEI	T2,PAGSIZ##	;NO. OF WORDS/PAGE TO SCAN
	PUSHJ	P,CSDMP		;SWEEP CACHE
	MOVEI	T1,@.CPEBR##	;GET EBR
	TRZ	T1,LG.CSL+LG.CSW;TURN OFF LOOK AND LOAD
	CONO	PAG,(T1)	;DISABLE THE CACHE
	SETOM	.CPPSP##	;SET SWEEPING FLAG
CPLMPI::MOVE	P2,(P1)		;TEST NEXT LOCATION
MPSLP2:	SOJLE	T2,MPSLP1	;IF CURRENT PAGE DONE, MAP NEXT
	AOJA	P1,CPLMPI	;GO TEST NEXT WORD IN PAGE

;HERE ON BAD WORD FOUND (NXM OR PARITY) - TRAP HAPPENED AND ADDED 3 TO PC
	MAP	T1,(P1)		;GET THE PHYSICAL ADDRESS OF BAD WORD
	PUSH	P,P1		;SAVE THE EVA
	PUSH	P,T2		;SAVE THE WORD NUMBER IN CURRENT PAGE
	PUSH	P,T3		;SAVE THE POSITION IN THE MAP
	PUSH	P,T4		;SAVE # OF PAGES TO SCAN
	LDB	P1,[POINT 22,T1,35] ;GET JUST THE PHYSICAL ADDRESS OF BAD WORD
	PUSHJ	P,CPIASN##	;CONVERT TO SEG NUMBER IN J
	  TDZA	T1,T1		;INDICATE NO ERROR IN MONITOR OR A JOB
	SETO	T1,		;INDICATE AN ERROR IN MONITOR OR A JOB
	MOVE	P2,.CPTBD##	;GET BAD DATA WORD STORED BY THE TRAP ROUTINE
	PUSHJ	P,PARRBD##	;RECORD BAD DATA
	POP	P,T4		;RESTORE T4
	POP	P,T3		; AND T3
	POP	P,T2		; AND T2
	POP	P,P1		; AND P1
	SETZM	.CPPTH##	;CLEAR FLAG THAT TRAP HAPPENED
	JRST	MPSLP2		;GO CONTINUE THE SWEEP

MPSLP5:	SETZM	.CPPSP##	;CLEAR SWEEPING FLAG
	CONO	PAG,@.CPEBR##	;TURN CACHE BACK ON
	PUSHJ	P,UNMAP##	;RESTORE EXEC MAP SLOT
	POPJ	P,		;AND RETURN
	SUBTTL	BACKGROUND KL10 PERFORMANCE ANALYSIS

IFN	FTRSP,<

;BPAUPD  --  UPDATE BACKGROUND PERFORMANCE ANALYSIS COUNTS
;CALLED BY CLOCK1 AT CLOCK INTERUPT LEVEL
;
;PRESERVES ALL ACS.

BPAUPD::SKIPE	.CPPJB##	;PERFORMANCE METER IN USE BY PERF.?
	POPJ	P,		;YES, WE CAN'T USE IT THEN
	PUSHJ	P,SAVT##	;SAVE THE T AC'S
	SKIPN	T1,.CPBPI##	;PICK UP WHERE WE LAST LEFT OFF
	JRST	BPAUP5		;NEVER BEEN HERE, INITIALIZE FIRST
	HRRZ	T2,T1		;GET PACTAB INDEX
	LSH	T2,2		;AND MAKE INTO 4-WORD .CPBPV INDEX

;NOW SEE HOW MUCH TIME HAS ELAPSED SINCE WE STARTED THIS ITEM COUNTING

	CONO	PI,PI.OFF	;VALID TIMINGS
	RDTIME	T3		;GET TOTAL ELAPSED TIME
	DSUB	T3,.CPBPT##	;T3:=INCREMENTAL SINCE STARTED
	DADD	T3,.CPBPV##(T2)	;T3:=TOTAL ITEM ELAPSED TIME
	DMOVEM	T3,.CPBPV##(T2)	;STORE FOR INTERESTED PARTIES

;NOW READ THE PERFORMANCE METER COUNT AND SAVE IT AWAY

	RDPERF	T3		;T3:=INCREMENTAL PERFORMANCE COUNTER
	CONO	PI,PI.ON	;LET SYSTEM GO AGAIN
	DADD	T3,.CPBPV##+2(T2)  ;T3:=TOTAL PERFORMANCE COUNT FOR THIS ITEM
	DMOVEM	T3,.CPBPV##+2(T2)  ;SAVE IT FOR INTERESTED READERS

;NOW SELECT NEXT CONDITION TO WATCH

	AOBJN	T1,.+2		;NEXT ITEM IN BPATAB
BPAUP5:	MOVSI	T1,-BPATLN##	;INITIALIZE AT START OF BPATAB
	WRPAE	[PE.CLR]	;ZAP THE COUNTER
	MOVE	T4,.CPEPT##	;GET ADDRESS OF EPT FOR THIS CPU
	SETZM	.E0HPA##-.E0MP##(T4)  ;CLEAR HIGH ORDER PERF ANAL COUNT
	SETZM	.E0LPA##-.E0MP##(T4)  ;CLEAR LOW ORDER PERF ANAL COUNT
	CONO	PI,PI.OFF	;AGAIN, NO INTERRUPTS
	RDTIME	.CPBPT##	;REMEMBER WHEN THIS CONDITION SELECTED
	WRPAE	BPATAB##(T1)	;TURN ON PERFORMANCE METER
	CONO	PI,PI.ON	;AND ONCE AGAIN LET SYSTEM GO
	MOVEM	T1,.CPBPI##	;REMEMBER WHERE IN BPATAB WE ARE
	MOVN	T4,.CPBPC##	;TICK COUNT BETWEEN SAMPLES
	MOVEM	T4,.CPBPF##	;SET SAMPLING INTERVAL
	SETZM	.CPMJ1##	;NO NEED TO STOP METER ANYMORE!
	POPJ	P,		;BACK TO CLOCK1
> ;END OF IFN FTRSP
SUBTTL PERF. UUO FUNCTIONS TO HANDLE KL10 PERFORMANCE METER

COMMENT &
THE KL10 PERFORMANCE METER IS ASSUMED TO BE AN INTEGRAL PART OF
THE KL10 PROCESSOR, AND THUS ITS DATA BASE IS FOUND IN THE
CDB. FOR THE PURPOSES OF DOCUMENTATION AND IN THE EVENT THAT
A FUTURE CPU CAN HAVE MORE THAN ONE TYPE OF PERFORMANCE METER,
A LIST OF THE CDB LOCATIONS USED FOR THE PERFORMANCE METER
FOLLOWS:

	.CPPJB - JOB WHICH OWNS PERFORMANCE METER ON THIS CPU, 0 IF FREE
	.CPMJB - JOB ENABLE CONDITION, SET BY UUO. -2 = NULL JOB, 0 = DONT CARE
	.CPMJ1 - JOB ENABLE CONDITION, ONLY SET IF METER IS RUNNING.
		  THIS IS THE VARIABLE WHICH CLOCK1 USES TO TURN THE
		  METER ON AND OFF TO SIMULATE A JOB ENABLE CONDITION.
		  THIS VARIABLE IS NEEDED BECAUSE THE METER CAN BE
		  STOPPED AND THEN STARTED WITH THE SAME JOB ENABLE

	.CPPMR - SET NONZERO WHENEVER THE PERFORMANCE METER IS RUNNING
		  USED IN CHECKING FOR STARTING METER TWICE

	.CPPAE - USED TO STORE THE PERFORMANCE ANALYSIS ENABLES FOR METER
	.CPPRQ - SEMAPHORE USED IN TESTING AND GIVING METER AWAY

	.CPAPS - FLAG THAT CAUSES THE PERFORMANCE METER TO BE TURNED
		  ON AND OFF WITH THE ACCOUNTING METER

	.CPMM0
	.CPMM1 - DOUBLE WORD LOCATION THAT CONTAINS THE NUMBER OF
		  MBOX REFERENCES WHILE METER WAS ON AND ENABLED
		  JOB CONDITION TERM WAS TRUE. USEFUL FOR MEASURING
		  CACHE HIT RATE.


THE FORMAT OF THESE METER FUNCTIONS WAS SETUP TO ACCOMODATE FUTURE
METERS IF NECESSARY:  EVERY ENABLE CONDITION IS A SEPARATE WORD.
THE ORDER OF THE ENABLES WERE SPECIALLY CHOSEN SUCH THAT THE
MOST FREQUENTLY USED ENABLES ARE FIRST.  SINCE UNSPECIFIED ARGUMENTS
ALWAYS DEFAULT TO ZERO, THIS SAVES SPACE IN THE USER PERFORMANCE
PROGRAM.
INSTEAD	OF CHECKING FOR TERMINATION OF THE ARGUMENT LIST EVERY TIME
A WORD IS FETCHED OR STORED IN THESE ROUTINES, THE SPECIAL ROUTINES
PF?WDU, PF?WD1 (?=G, GET OR P,PUT) ARE USED, WHICH RETURN 0 (DONT CARE)
ON GETTING AFTER ARGS ARE EXHAUSTED OR ARE NOOPS WHEN AN ATTEMPT IS MADE
BY THE FUNCTION ROUTINES TO PLACE A VALUE BEYOND THE LIMIT OF WHAT
THE CALLER ASKED FOR.
&;END OF COMMENT
;THE FOLLOWING PERF. UUO FUNCTIONS ARE IN KLSER:

;THE FOLLOWING ERROR ROUTINES ARE CALLED BY PERF. UUO FUNCTIONS
; IN KLSER, AND ARE FOUND IN UUOCON
;FUNCION 1 - GET METER AND SETUP METER CONDITIONS
;
;FORMAT OF ARGUMENT BLOCK:
;
;ADDR:		;NUMBER OF WORDS FOLLOWING
;ADDR+1:		;CPU TYPES (1B0=PDP6,1B1=KA10,ETC.)
;ADDR+2:		;CPU NUMBER,,MODE
;ADDR+3:		;CACHE ENABLES
;ADDR+4:		;PI CHANNEL ENABLES
;ADDR+5:		;PC ENABLES
;ADDR+6:		;MICROCODE ENABLES
;ADDR+7:		;PROBE ENABLES
;ADDR+10:		;JOB
;ADDR+11:		;RH20 CHANNEL ENABLES
;ZERO ALWAYS INDICATES DON'T CARE.  FOR DETAILS ON WHAT THE
; ENABLE BITS ARE, REFER TO KL10 INTERNAL CLOCK SUPPORT FUNCTIONAL SPEC.

PMRSET::PUSHJ	P,CHKPMS	;CHECK CPU TYPE STUFF AND SETUP P4
	  POPJ	P,		;ERROR OF SOME SORT (SEE CHKPMS)
	PUSHJ	P,GETPMR	;GET METER
	  JRST	PREMIU##	;**METER BUSY**
;	PUSHJ	P,ONCPP4	;RESCHEDULE TO CPU IN P4
	PUSHJ	P,STPPMJ	;STOP METER
	TRZE	T4,1B35		;T4 HAS EVENT/DURATION STATE.
				;TEST BORROWED BIT (CLEAR/DON'T CLEAR)
	PUSHJ	P,CLRPMR	;ZERO OUT PERFORMANCE COUNT

;CACHE ENABLES
	PUSHJ	P,PFGWD1	;GET CACHE ENABLES FROM USER
	SKIPN	T1		;DON'T CARE??
	TLO	T4,(PE.CCI)	;YES, SET CACHE DON'T CARE
	TLZE	T1,(1B4)	;ACCOUNTING METER/PERFORMANCE METER SYNC BIT?
	SETOM	.CPAPS##	;YES, SET THE FLAG
	LSH	T1,<-<^L<PE.CCR>>-<^D18>>	;SHIFT INTO POSITION
	TRC	T1,(PE.CCR!PE.CCF!PE.EWB!PE.SWB)	;ACCOUNT FOR THE FACT
				; THAT THESE BITS ARE ZERO WHEN THE
				;CONDITION IS ENABLED!
	ANDI	T1,(PE.CCR!PE.CCF!PE.EWB!PE.SWB)	;PREVENT OTHER BITS FROM SETTING
	TSO	T4,T1		;SET DESIRED BITS

;PI ENABLES
	PUSHJ	P,PFGWD1	;GET PI ENABLES
	SKIPN	T1		;DON'T CARE??
	TRO	T4,PE.PPI	;PI IGNORE IF ZERO ARG
	LSH	T1,<-<^L<PE.PP0>>>	;SHIFT INTO POSITION
	ANDI	T1,PE.PPI	;CLEAR OUT ERRONEOUS BITS
	TDO	T4,T1		;AND SET THEM IN T4

;PC ENABLES
	PUSHJ	P,PFGWD1	;GET THEM
	TLCE	T1,(1B0!1B1)	;IF ALL BITS ARE ZERO OR
	TLNN	T1,(1B0!1B1)	;IF BOTH ARE SET
	TRO	T4,PE.PCI	;SET PC IGNORE
	TLNN	T1,(1B0)	;IN ANY CASE, WANT USER PC?
	TRO	T4,PE.PCU	;YES,SET PC USER (NN BECAUSE BITS ARE COMP.)
;MICROCODE ENABLES
	PUSHJ	P,PFGWD1	;GET UCODE ENABLES
	TLNN	T1,(1B0)	;SKIP IF UCODE STATE ENABLED
	TLO	T4,(PE.UCI)	;NOT ENABLED, SET UCODE IGNORE BIT

;PROBE ENABLES
	PUSHJ	P,PFGWD1	;GET THEM
	TLCE	T1,(1B0!1B1)	;IF BOTH OFF OR
	TLNN	T1,(1B0!1B1)	;BOTH ON
	TLO	T4,(PE.PRI)	;IGNORE PROBE
	TLNN	T1,(1B0)	;IN ANY CASE, WANT PROBE LOW? (COMP)
	TLO	T4,(PE.PRL)	;YES, ENABLE PROBE LOW

;JOB ENABLE
	PUSHJ	P,PFGWD1	;JOB ENABLE
	JUMPE	T1,PMRST1	;IGNORE IS OK
	CAMN	T1,[-1]		;SELF?
	MOVE	T1,J		;YES
	CAMN	T1,[-2]		;NULL JOB?
	JRST	PMRST1		;YES, DON'T CALL LGLPRC
	PUSHJ	P,LGLPRC##	;IS THIS A LEGAL NUMBER?
	  JRST	PREBJN##	;BAD JOB NUMBER
PMRST1:	MOVEM	T1,.CPMJB##	;EVERYTHING'S OK, STORE JOB ENABLE

;NOW FOR CHANNEL ENABLES
	PUSHJ	P,PFGWD1	;GET THEM
	SKIPN	T1		;DON'T CARE?
	TLO	T4,(PE.CPI)	;YES, SET ALL BITS FOR DON'T CARE
	LSH	T1,<-<^L<PE.CP0>>-<^D18>>	;POSITION (IN RH)
	ANDI	T1,PE.PPI	;CLEAR UNWANTED BITS
	TSO	T4,T1		;AND SET THE BITS

;ADD FURTHER ENABLE LOGIC HERE

	MOVEM	T4,.CPPAE##	;AT LAST
	JRST	CPOPJ1##	;BYE.
;FUNCTION 2 - START METER
;
;THE METER MUST BE OWNED BY THE CALLING JOB (CHECKED BY PRFCPU).
; SPECIAL CARE IS TAKEN NOT TO START THE METER IF THE CALLING JOB DOES NOT
;SATISFY THE JOB ENABLE CONDTION.  AFTER THE METER IS STARTED,
; THE FUNCTION RETURNS THE DOUBLE WORD TIME BASE AND PERFORMANCE COUNT
; IN THE ARGUMENT BLOCK, WHICH HAS THE FOLLOWING FORMAT:
;
;ADDR:			;COUNT OF WORDS FOLLOWING
;ADDR+1:		;CPU NUMBER
;ADDR+2:		;HIGH ORDER TIME BASE RETURNED HERE
;ADDR+3:		;LOW ORDER TIME BASE RETURNED HERE
;ADDR+4:		;HIGH ORDER PERFORMANCE METER VALUE
;ADDR+5:		;LOW ORDER "			"
;ADDR+6:		;HIGH ORDER MBOX REFERENCE COUNT
;ADDR+7:		;LOW ORDER MBOX REFERENCE COUNT

PMRSTR::PUSHJ	P,PRFCPU	;CHECK CPU SPEC, SETUP P4, MAKE SURE METER IS OWNED
	  POPJ	P,		;SORRY, SOMETHING WENT WRONG
	SKIPE	.CPPMR##	;SKIP IF METER IS NOT STARTED ALREADY
	JRST	PREMAS##	;**METER ALREADY STARTED**
;	PUSHJ	P,ONCPP4	;MUST RESCHEDULE ON THE RIGHT CPU TO START METER
	CONO	PI,PI.OFF	;TURN OFF PI SO WE CAN START AND READ
				;METER WITHOUT INTERRUPTIONS
	PUSHJ	P,STRPMJ	;START METER IF WE'RE SUPPOSED TO

;FALL INTO STORPT

STORPT:	PUSHJ	P,REDPMT	;READ TIME BASE AND PERF METER INTO T1-T4
	PUSH	P,.CPMM1##	;ALSO SAVE MEMORY REFERENCE COUNT BEFORE
	PUSH	P,.CPMM0##	; PI SYSTEM IS TURNED BACK ON
	CONO	PI,PI.ON	;TURN PI BACK ON
	PUSHJ	P,PFPWD1	;STORE HIGH ORDER TIME BASE
	MOVE	T1,T2
	PUSHJ	P,PFPWD1	;STORE LOW ORDER TIME BASE
	MOVE	T1,T3
	PUSHJ	P,PFPWD1	;STORE HIGH ORDER PERFORMANCE COUNT
	MOVE	T1,T4
	PUSHJ	P,PFPWD1	;STORE LOW ORDER PERF COUNT
	POP	P,T1		;GET HIGH ORDER MEMORY REFERENCE COUNT BACK
	PUSHJ	P,PFPWD1	;GIVE THAT TO USER
	POP	P,T1		;NOW GET LOW ORDER MEM REF COUNT
	AOS	(P)		;GIVE SKIP RETURN
	PJRST	PFPWD1		;STORE LOW ORDER MBOX COUNT AND RETURN
;FUNCTION 3 - READ PERFORMANCE METER
;
;FORMAT OF ARGUMENT LIST SAME AS FUNCTION 2, START METER

PMRRED::PUSHJ	P,PRFCPU	;CHECK AND SETUP CPU STUFF, METER OWNER
	  POPJ	P,		;SOMETHING WENT WRONG
;	PUSHJ	P,ONCPP4	;RESCHEDULE ONTO PROPER CPU FOR THIS METER
	PJRST	STORPT		;STORE TIME BASE, PERF COUNT AND RETURN


;FUNCTION 4 - STOP METER
;
;FORMAT OF ARG LIST SAME AS START AND READ FUNCTIONS
;

PMRSTP::PUSHJ	P,PRFCPU	;SETUP P4, CHECK METER OWNERSHIP
	  POPJ	P,		;OOOPS
;	PUSHJ	P,ONCPP4	;PUT OURSELVES ONTO PROPER CPU
	SKIPN	.CPPMR##	;IS METER RUNNING?
	JRST	PREMNR##	;**METER NOT RUNNING** (SO WHY STOP IT?)
	PUSHJ	P,STPPMJ	;STOP METER
	PJRST	STORPT		;STORE GOOD STUFF AND RETURN
;FUNCTION 5 - RELEASE METER

;FORMAT OF ARGUMENT BLOCK:
;
;ADDR:			;NUMBER OF WORDS FOLLOWING
;ADDR+1:		;CPU NUMBER OF METER TO RELEASE


PMRREL::PUSHJ	P,PRFCPU	;GOOD CPU? THEN SETUP P4 AFTER WE KNOW WE OWN METER
	  POPJ	P,		;SORRY CHARLIE
;	PUSHJ	P,ONCPP4	;RESCHEDULE ONTO PROPER CPU
	PUSHJ	P,STPPMJ	;STOP METER
	MOVE	T1,.CPSLF##	;POINT T1 AT THIS CPU'S CDB
	AOS	(P)		;SET FOR SKIP RETURN
	PJRST	RELPMR		;AND RELEASE, RETURN
;FUNCTION 6 - TURN OFF BACKGROUND PERFORMANCE ANALYSIS
;FUNCTION 7 - TURN ON  BACKGROUND PERFORMANCE ANALYSIS

;FORMAT OF ARGUMENT BLOCK:
;
;ADDR:			;NUMBER OF WORDS FOLLOWING
;ADDR+1:		;CPU TYPES
;ADDR+2:		;CPU NUMBER,,MODE (1B19 = CLEAR COUNTS)
;ADDR+3:		;SAMPLING INTERVAL (CLOCK TICKS PER SAMPLE ITEM)

IFN	FTRSP,<			;ONLY IF RESPONSE NUMBERS WANTED

PMRBPF::PUSHJ	P,CHKPMS	;VERIFY AND GET TO CPU DESIRED
	  POPJ	P,		;SOMETHING DIDN'T MAKE IT
	SETZM	.CPBPF##	;CLEAR CLOCK-LEVEL COUNTER
	JRST	CPOPJ1##	;SUCCESSFUL RETURN


PMRBPN::PUSHJ	P,CHKPMS	;VERIFY AND GET TO CPU DESIRED
	  POPJ	P,		;SOMETHING DIDN'T MAKE IT
	SETZM	.CPBPF##	;AVOID CLOCK-LEVEL RACE
	TRNN	T4,1B35		;USER WANT TO "CLEAR" THE COUNTER(S)?
	JRST	PMBPN2		;NO, ACCUMULATE SYSTEM TOTALS
	SETZM	.CPBPV##	;YES, CLEAR FIRST WORD OF BPA BLOCK
	MOVE	T1,[.CPBPV##,,.CPBPV##+1]  ;BLT POINTER TO
	BLT	T1,.CPBPV##+<BPATLN##*4>-1 ;CLEAR OUT ALL OF THE BPA BLOCK
PMBPN2:	PUSHJ	P,PFGWD1	;GET SAMPLING INTERVAL
	CAIG	T1,0		;USEFUL NUMBER SUPPLIED?
	MOVE	T1,.CPBPC##	;NO, USE LAST SPECIFIED FOR THIS CPU
	CAIG	T1,0		;USEFUL NUMBER YET?
	MOVEI	T1,3		;NO, SET INTERVAL TO 3 TICKS
	MOVEM	T1,.CPBPC##	;TELL BPAUPD HOW LONG TO SAMPLE EACH ITEM
	SETZM	.CPBPI##	;TELL BPAUPD TO RE-INITIALIZE ITSELF
	SETOM	.CPBPF##	;TELL CLOCK-LEVEL TO START UP BPAUPD
	JRST	CPOPJ1##	;RETURN SUCCESSFULLY

> ;END OF IFN FTRSP
;ROUTINE TO CHECK INITAL CPU/METER SPECIFICATION
; CALL WITH M SETUP TO POINT TO ADDRESS BEFORE CPU TYPE WORD.
; SMASHES T1-T3, RETURNS T4 WITH EVENT MODE BIT EITHER SET OR CLEAR
; DEPENDING ON THE MODE ARGUMENT THE CALLER SUPPLIES.
; THIS ROUTINE ALSO BORROWS BIT 35 TO INDICATE WHETHER OR NOT THE
; PERFORMANCE METER COUNT SHOULD BE CLEARED OR NOT.  THIS BIT
; SHOULD BE CLEARED IMMEDIATELY AFTER CHECKING, SINCE IT MIGHT
; BE USED BY THE HARDWARE
;
;AN ERROR RETURN IS GIVEN FROM THIS ROUTINE IF THE CPU SPECIFICATION
; IS INCORRECT OR A CPU NUMBER CORRESPONDING TO A NON-EXISTANT CPU IS GIVEN.
; THE CALLER MUST ACTUALLY GET CONTROL OF THE METER.

CHKPMS:	PUSHJ	P,PFGWD1	;GET CPU TYPES ACCEPTABLE
	MOVE	T3,T1		;SAVE IN T3
	PUSHJ	P,PFGWD1	;GET CPU NUMBER,,MODE
	TLNN	T3,(1B3)	;CPU TYPE MUST BE KL10 FOR THIS FUNCTION
	JRST	PREICT##	;**IMPROPER CPU TYPE**
	SETZ	T4,		;START WITH ZERO FOR PERFORMANCE ENABLE WORD
	TRNN	T1,1B18		;SKIP IF NOT EVENT MODE
	MOVEI	T4,PE.EVM	;IS EVENT MODE, SET THE BIT
	TRNE	T1,1B19		;CLEAR METER COUNT?
	TRO	T4,1B35		;YES, BORROW A BIT TO TELL ABOUT IT
	HLRZS	T1
	CAILE	T1,CPUN##-1
	JRST	PRENXC##
IFN FTMP,<
	PUSHJ	P,ONCPUS##
	  JRST	PRENXC##
>
	PJRST	CPOPJ1##	;AND GIVE SKIP RETURN
;THIS ROUTINE IS USED IN THE START, READ, STOP, AND RELEASE ROUTINES.
; IT CHECKS THE CPU NUMBER FOR LEGALITY, AND GIVES ERROR RETURN IF
; CPU NUMBER IS BAD.  IT ALSO GIVES AN ERROR RETURN IF
; THE CALLER (WHOSE JOB IS IN AC J) DOES NOT OWN THE METER.
; THIS ROUTINE DISTINGUISHES BETWEEN THE CASES OF METER IN USE
; AND METER NOT SETUP WHEN IT DISCOVERS THAT THE CALLER DOES NOT
; OWN THE METER.  M SHOULD BE SETUP TO POINT TO THE ITEM COUNT
; OF THE ARG BLOCK. AC'S T3-T4 ARE PRESERVED. P4 IS SETUP TO BE
; THE CPU DATA BLOCK OF THE SPECIFIED CPU.

PRFCPU:	PUSHJ	P,PFGWD1	;GET CPU NUMBER
	MOVEI	T2,CPUN##
	CAIGE	T2,1(T1)
	JRST	PRENXC##
IFN FTMP,<
	PUSHJ	P,ONCPUS##
	  JRST	PRENXC##
>
	CAMN	J,.CPPJB##
	JRST	CPOPJ1##	;YES, RETURN
	SKIPE	.CPPJB##	;IS METER OWNED BY SOMEONE ELSE??
	JRST	PREMIU##	;**METER IN USE**
	JRST	PREMNS##	;**METER NOT SETUP**

;SPECIAL ROUTINES TO PICK UP ARGUMENTS FOR PERFORMANCE METER FUNCTIONS.
; IF THE COUNT GIVEN BY THE CALLER (IN P2) IS EXHAUSTED, THE PUTTER
; ROUTINE DOES NOTHING AND THE GETTER ROUTINE RETURNS A ZERO
; (DON'T CARE).  THIS SAVES SOME CHECKING ELSEWHERE.

PFPWD1:	SOJL	P2,CPOPJ##	;IF COUNT IS GONE, DO NOTHING
	PJRST	PUTWD1##	;ELSE DO PUTWD1

PFGWD1:	SETZ	T1,		;CLEAR T1 IN CASE COUNT IS GONE
	SOJL	P2,CPOPJ##	;RETURN ZERO IF COUNT EXHAUSTED
	PJRST	GETWD1##	;ELSE DO GETWD1

;ROUTINE TO READ IN TIME BASE AND PERFORMANCE METER COUNT AT THE
; SAME TIME, MAKING SURE NO INTERRUPTS INTERFERE.
;
;RETURNS TIME BASE HI AND LO IN T1,T2 AND PERF COUNT IN T3,T4
;
;MUST BE ON CPU OF TARGET METER - CALLER'S RESPONSIBILITY
;
;PRESERVES P AC'S, T1-T4 ARE DESTROYED

REDPMT::CONSO	PI,PI.IPA	;PI OFF ALREADY?
	JRST	REDPM2		;YES, DON'T TURN IT ON AGAIN
	PUSHJ	P,REDPM1	;NO, TURN IT ON AFTER WERE THROUGH
	PJRST	ONPOPJ##

REDPM1:	SYSPIF			;TURN OFF PI
REDPM2:	RDTIME	T1		;HI AND LO INTO T1,T2
	RDPERF	T3		;HI AND LO PERF INTO T3,T4
	POPJ	P,		;RETURN

;ROUTINE TO START PERFORMANCE METER USED BY PERF. UUO
; SETS UP JOB CONDITION FOR CLOCK1 AND THEN USES SCDPR1
; TO START THE METER IF THE JOB ENABLE CONDITION IS SATISFIED.
; PRESERVES ALL AC'S EXECPT T1. MUST BE CALLED ON CPU OF DESIRED METER,
; PRESERVES STATE OF PI SYSTEM (ON,OFF)

STRPMJ::PUSH	P,.CPMJB##	;PUT METER ENABLE INTO
	POP	P,.CPMJ1##	;PROPER WORD
	SETOM	.CPPMR##	;SAY THAT METER IS RUNNING
	PJRST	SCDPR1		;START METER IF WE'RE SUPPOSED TO AND RETURN
;ROUTINE TO START PERFORMANCE METER USED BY CLOCK1, CALLED BY STRPMJ.
; THIS ROUTINE ACTUALLY STARTS THE PERFORMANCE METER ACCORDING TO
; THE CONDITIONS IN .CPPAE. PRESERVES ALL AC'S, STATE OF PI SYSTEM.
; CALL WITH P4 = CPU DATA BLOCK, MUST BE ON CPU OF TARGET METER.

STRPMR::WRPAE	.CPPAE##	;THIS IS ALL THAT'S NECESSARY
	POPJ	P,		;THERE, THAT WAS EASY

;ROUTINE TO STOP METER USED BY PERF UUO.
; STOPS METER AND CLEARS JOB ENABLE FLAG FOR CLOCK1 SO IT DOESN'T
; TURN THE METER ON. USES ACS T1,T2. PRESERVES STATE OF PI SYSTEM.
; CALL ON CPU OF TARGET METER WITH P4 = CPU DATA BLOCK

STPPMJ::PUSHJ	P,CHKPMJ	;WERE WE PART OF THE JOB ENABLE CONDITION?
	  JRST	STPPJ1		;NO, DON'T UPDATE MBOX REFERENCE COUNT
	PUSHJ	P,GETMBT	;GET MBOX REFERENCES IN T1,T2
	DADD	T1,.CPMM0##	;UPDATE COUNT
	DMOVEM	T1,.CPMM0##
STPPJ1:	SETZM	.CPMJ1##	;CLEAR JOB ENABLE THAT CLOCK1 LOOKS AT
	SETZM	.CPPMR##	;AND SAY THAT METER IS NOW STOPPED
;	PJRST	STPPMR		;STOP METER AND RETURN

;ROUTINE TO STOP PERF METER.  DOESN'T TOUCH JOB ENABLE, SO CLOCK1
; CAN CALL IT TO START AND STOP METER FOR JOB ENABLE LOGIC.
; PRESERVES ALL AC'S, STATE OF PI SYSTEM. CALL ON CPU OF TARGET METER
; WITH P4 SETUP ACCORDINGLY.

STPPMR::WRPAE	[0]		;ZERO STOPS THE METER
	POPJ	P,		;ANOTHER COMPLICATED ROUTINE
;ROUTINE TO GET THE PERFORMANCE METER USED BY PERF. UUO
; CALL WITH JOB NUMBER OF CALLER IN J, ADDRESS OF CPU DATA
; BLOCK OF CPU OF TARGET METER IN P4. MUST BE ON THE
; CPU OF TARGET METER.  NON-SKIP RETURN IF METER IS ALREADY IN
; USE, SKIP RETURN IF ALREADY OWN METER OR METER WAS FREE.

GETPMR:	CAMN	J,.CPPJB##	;ALREADY OWN IT?
	JRST	CPOPJ1##	;YES, GOOD RETURN
	AOSE	.CPPRQ##	;AVAILABLE?
	POPJ	P,		;NO, NOT NOW.
	MOVEM	J,.CPPJB##	;YES, PUT OUR NAME ON THE METER
				; NOTE THIS WILL ALSO TURN OFF ANY
				; BACKGROUND PERF ANALYSIS PENDING
	JRST	CPOPJ1##	;GOOD RETURN


;ROUTINE TO RELEASE PERFORMANCE METER USED BY PERF. UUO AND
; EMERGENCY ROUTINES (RESET, SWAP READ ERROR, ETC.)
; CALL WITH P4 = CPU DATA BLOCK OF TARGET PERF METER. NEED NOT
; BE RUNNING ON TARGET CPU (SO SWAPPER CAN CALL, RESET, ETC.)
; CLEARS ALL METER VARIABLES FOR SPECIFIED CPU.
; ALL AC'S PRESERVED.

RELPMR:	SETZM	.CPAPS##-.CPCDB##(T1) ;CLEAR PERF/ACC METER SYNC FLAG
	SETZM	.CPMJB##-.CPCDB##(T1) ;CLEAR MEASURED JOB
	SETOM	.CPMJ1##-.CPCDB##(T1) ;-1 IS FLAG FOR CLOCK1 TO STOP METER
	SETZM	.CPPJB##-.CPCDB##(T1) ;CLEAR OWNING JOB
	SETZM	.CPPAE##-.CPCDB##(T1) ;AND PERFORMANCE ENABLES
	SETOM	.CPPRQ##-.CPCDB##(T1) ;NOW MAKE METER AVAILABLE
	SETZM	.CPBPI##-.CPCDB##(T1) ;TELL BACKGROUND UPDPAC TO REINIT
	SKIPLE	.CPBPC##-.CPCDB##(T1) ;BACKGROUND PERF ANAL ON FOR CPU?
	SETOM	.CPBPF##-.CPCDB##(T1) ;YES, RESTART AT NEXT CLOCK TICK
	POPJ	P,		;ONLY RETURN
				;(ALWAYS SUCCEEDS!)


;ROUTINE TO CLEAR PERFORMANCE METER COUNT
; USED BY PERF. UUO AT METER SETUP TIME. CALLER SHOULD
; MAKE SURE THAT IT OWNS THE METER INVOLVED.
; CALLER MUST MAKE SURE HE IS RUNNING ON CPU OF TARGET
; METER. CALLER SHOULD ALSO MAKE SURE METER IS STOPPED.

CLRPMR:	WRPAE	[PE.CLR]	;CLEAR HARDWARE COUNTER
	MOVE	T1,.CPEPT##
	SETZM	.E0HPA##-.E0MP##(T1) ;CLEAR HI PERF COUNT
	SETZM	.E0LPA##-.E0MP##(T1) ;AND LO
	SETZM	.CPMM0##	;CLEAR OUT MBOX COUNT ALSO
	SETZM	.CPMM1##	;HIGH AND LOW ORDERS
	POPJ	P,		;RETURN
;ROUTINE CALLED AFTER SCHEDULER IN CLOCK1 TO IMPLEMENT JOB ENABLE CONDITION.
; .CPMJ1 CONTAINS THE ENABLE CONDITION. -2 IS NULL JOB, -1 IS A SPECIAL
; CODE MEANING STOP THE METER (USED IF A RESET IS DONE BEFORE METER
; IS RELEASED), 0 MEANS THE JOB ENABLE IS DON'T CARE, AND NON-ZERO
; MEANS LEAVE THE METER RUNNING IF AND ONLY IF THE JOB NUMBER
; IN .CPMJ1 IS ABOUT TO BE RUN.  ALL ACS PRESERVED.


SCDPMR::PUSH	P,T1		;SAVE T1
	PUSHJ	P,SCDPR1	;CALL THE ROUTINE
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

SCDPR1:	MOVE	T1,.CPMJ1##	;GET JOB ENABLE CONDITION
	AOJE	T1,STPPMJ	;IT WAS A REQUEST TO STOP METER, DO IT.
	SKIPN	.CPPJB##	;METER OWNED BY ANYONE?
	POPJ	P,		;NO, LEAVE THE METER ALONE
	PUSHJ	P,CHKPMJ	;CHECK THE JOB ENABLE CONDITION.
	PJRST	STPPMR		;NOT SATISFIED, STOP THE CLOCK
	PJRST	STRPMR		;IS SATISFIED, START UP THE CLOCK, EVEN
				;THOUGH IT MAY BE STARTED ALREADY (SO WHAT)

;ROUTINE TO CHECK ON THE JOB ENABLE CONDITION.
; CALL WITH JOB NUMBER TO BE TESTED IN J, CPU DATA BLOCK ADDR IN P4.
; GIVES SKIP RETURN IF THE JOB IN J CAUSES THE CPU ENABLE CONDITION
; FOR THE PERFORMANCE METER TO BE SATISFIED, NON-SKIP IF THE CONDITION
; IS NOT SATISFIED OR SOMEONE IS TRYING TO STOP THE METER (-1 IN .CPMJ1).
;USES T1.

CHKPMJ::SKIPN	T1,.CPMJ1##	;GET JOB ENABLE. IS IT ZERO?
	JRST	CPOPJ1##	;YES, CONDITION IS DON'T CARE, GIVE SKIP RETURN
	CAMN	J,T1		;NO, DOES .CPMJ1 CONTAIN JOB NUMBER WHICH
				; IS IN J?
	JRST	CPOPJ1##	;YES, GIVE SKIP RETURN
	AOJGE	T1,CPOPJ##	;IF T1 = -1, SOMEONE WANTS METER STOPPED.
				; CALLER'S RESPONSIBILITY TO STOP IT
				; IF T1 WAS .GT. ZERO, CONDITION FOR JOB IS NOT MET, SO
				; GIVE NON-SKIP RETURN
	PJUMPE	J,CPOPJ1##	;JOB ENABLE MUST HAVE BEEN NULL JOB.
				; IF J .EQ. 0, ENABLE CONDITION IS SATISFIED.
	POPJ	P,		;SORRY, CONDITION NOT SATISFIED

;ROUTINE TO GIVE UP THE PERFORMANCE METER ON THE CPU'S THIS JOB OWNS IT ON
GIVPMR::MOVEI	T1,.C0CDB##	;START WITH CPU0
GIVPM1:	CAMN	J,.CPPJB##-.CPCDB##(T1) ;OWN THE PERFORMANCE METER ON THIS CPU?
	PUSHJ	P,RELPMR	;YES, RELEASE IT
	HLRZ	T1,.CPCDB##-.CPCDB##(T1) ;NEXT CPU
	JUMPN	T1,GIVPM1	;JUMP IF ALL CPU'S HAVEN'T BEEN CHECKED
	POPJ	P,		;RETURN
SUBTTL	SET CACHE STRATEGY

;ROUTINE CALLED TO SET KL CACHE STRATEGY AS SPECIFIED TO KLI.
;SETS/CLEARS LG.CSL!LG.CSW IN .CPEBR AS APPROPRIATE, PRINTS A
;WARNING MESSAGE ON THE CTY IF CACHE WAS DISABLED.

SETCSH::PUSHJ	P,SPCGSF##	;GET SECONDARY PROTOCOL FLAG WORD
	TRNN	T1,DF.CSH	;DID OPERATOR SPECIFY TO ENABLE CACHE?
	SKIPA	T1,[ANDCAB T2,.CPEBR##] ;NO, GET CLEAR INSTRUCTION
	MOVE	T1,[IORB T2,.CPEBR##] ;YES, GET SET INSTRUCTION
	MOVEI	T2,LG.CSL!LG.CSW ;GET THE CACHE STRATEGY BITS
	XCT	T1		;SET/CLEAR IN .CPEBR AS APPROPRIATE
	TRNE	T2,LG.CSL!LG.CSW ;CACHE STRATEGY OFF?
	POPJ	P,		;NO, NOTHING TO WARN
	PUSHJ	P,CTYERM##	;SET FOR OUTPUT TO CTY
	MOVEI	T1,[ASCIZ /
%% Cache is disabled/]
	PUSHJ	P,CONMES##	;START MESSAGE
	MOVEI	T1,M.CPU##	;GET NUMBER OF CPUS IN THIS MONITOR
	SOJE	T1,PCRLF##	;DON'T PRINT CPUN IF THERE'S ONLY ONE
	MOVEI	T1,[ASCIZ / on /] ;SEPARATOR
	PUSHJ	P,CONMES##	;PRINT IT
	MOVE	T2,.CPLOG##	;GET THE CPU NAME
	PUSHJ	P,PRNAME##	;PRINT IT
	PJRST	PCRLF##		;PRINT CR-LF AND RETURN
SUBTTL OINKSR - KL10 MODULE TO SUPPORT G-FLOATING INSTRUCTIONS

Comment	@

This module simulates some G-floating conversion instructions which
the KL-10 uCode does not presently handle. At one time, the uCode
did handle these, but we reclaimed the uCode space for other fixes.

The instructions currently handled are:
	DGFIX
	GFIX
	DGFIXR
	GFIXR
which are all EXTEND opcodes.



This code is ripped off from the TOPS-20 module APRSRV, and should be kept
in sync; If this code is changed, Please change the tops-20 code also.

	@

	OPDEF CALL [PUSHJ P,0]	;CALL
	OPDEF RET [POPJ P,0]	;RETURN
	.NODDT CALL,RET

	GFLT%O==1B1		;GFLOAT OVERFLOW FLAG
	GFLT%2==1B2		;GFLOAT TWO AC STORE FLAG
	PC%TP1==1B10		;TRAP 1. USED ONLY BY GFLOAT

OPDEF DGFIX	[023000,,0]	;GFLT TO DOUBLE INTEGER
OPDEF GFIX	[024000,,0]	;GFLT TO INTEGER
OPDEF DGFIXR	[025000,,0]	;GFLT TO DOUBLE INTEGER ROUNDED
OPDEF GFIXR	[026000,,0]	;GFLT TO INTEGER ROUNDED

OINKSR::			;[TOPS10]
GFLT0:				;HERE TO CHECK FOR GFLT'S
	MOVE	M,.USMUE	;GET GLOBAL ADDRESS
	PUSHJ	P,GETEWD##	;FETCH THE EXTEND SUB-OPCODE
	  JRST	UADERR##	;ILLEGAL ADDRESS
	LDB	T3,[POINT 9,T1,8];GET THE EXTENDED OPCODE
	CAIL	T3,<<DGFIX>_-^D27>;IS IT A GFLT INSTRUCTION?
	CAILE	T3,<<GFIXR>_-^D27>
	JRST	ILLIN1##	;NO, GIVE HIM AN ILL UUO
	SUBI	T3,<<DGFIX>_-^D27>;CONVERT TO GFLTD OFFSET
	PUSHJ	P,GFLTXX	;DISPATCH TO WORKER ROUTINES
	TLNE	T4,(GFLT%O)	;DID IT OVERFLOW
	JRST	GFLT1		;YES...GO HANDLE IT
	LDB	T3,[POINT 4,.USMUO,30] ;GET THE AC THE USER USED
	UMOVEM	T1,(T3)		;SAVE THE FIRST AC
	TLNN	T4,(GFLT%2)	;IS IT A TWO AC RESULT?
	JRST	USRXIT##	;NO...SO WE ARE DONE
	ADDI	T3,1		;YES...SO BUMP THE AC VALUE
	ANDI	T3,17		;MAKE ADDITION MODULO 16
	UMOVEM	T2,(T3)		;SAVE THE SECOND AC RESULT
	JRST	USRXIT##	;RETURN TO USER
GFLT1:
	MOVSI	T1,(XC.OVF!PC%TP1);CAUSE AN OVERLOW TRAP.
	IORM	T1,.JDAT+JOBPD1##;BY CHANGING THE USER FLAGS.
	JRST	USRXIT##	;AND RETURN

GFLTD:	IFIW	.DGFX		;DGFIX
	IFIW	.GFX		;GFIX
	IFIW	.DGFXR		;DGFIXR
	IFIW	.GFXR		;GFIXR

GFLTXX:	HLRZ	T2,.USMUE	;GET DEFAULT SECTION-OF-REFERENCE
	MOVE	T4,.USMUE	;GET UUO EFFECTIVE ADDRESS
	TDNN	T4,[^-1,,^-17]	;IF AN AC
	TLNN	T4,-1		;AND NOT FROM S0
	JRST	GFLTX1		;NO, IT'S OK
	MOVE	M,.USMUP	;YES, HAVE TO GET SECTION OF REFERENCE
	HRRI	M,-1(M)		;BACK OFF TO PC OF EXTEND INSTRUCTION
	PUSHJ	P,GETMWD##	;FETCH ORIGINAL INSTRUCTION WORD
	  JRST	UADERR##	;HOW CAN THIS HAPPEN?
	PUSHJ	P,CHKINS##	;GET EA AND SECTION-NESS
	  JRST	UADERR##	;SHOULD NEVER FAIL
	CAME	T1,.USMUE	;BETTER MATCH
	JRST	UADERR##	;BLAME USER IF NOT
	MOVE	M,T1		;YES, GET FOR FETCH ROUTINE
	PUSHJ	P,GETXWD##	;RESTORE EXTEND SUB-OPCODE
	  JRST	UADERR##	;SOMETHING BAD HAPPENED
GFLTX1:	PUSHJ	P,CHKINX##	;DO AN EA-CALC WITH THE SECTION FROM T2
	  JRST	UADERR##	;EA-CALC FAILURE
	HRLI	T1,(T2)		;MAKE SURE OF GLOBAL ADDRESS
	PUSHJ	P,SXPCS##	;SETUP FOR ARG FETCHING
	  JRST	UADERR##	;BAD ADDRESS
	SKIPL	T2		;IF LOCAL REFERENCE,
	HRLI	T1,(IFIW)	;SETUP FOR FETCH ROUTINES
	MOVE	M,T1		;COPY POINTER
	PUSHJ	P,GETEWD##	;GET FIRST WORD OF PAIR
	  JRST	UADERR##	;INVALID ADDRESS
	MOVE	T2,T1		;SAVE IT
	PUSHJ	P,GETEW1##	;GET SECOND WORD OF PAIR
	  JRST	UADERR##	;ILLEGAL ADDRESS
	EXCH	T1,T2		;SWAP THEM BACK AROUND
	SETZ	T4,		;CLEAR ALL FLAGS.
	PJRST	@GFLTD(T3)	;DISPATCH TO WORKER ROUTINE
COMMENT @
		***********************************
		***** N   N  OOO  TTTTT EEEEE *****
		***** NN  N O   O   T   E     *****
		***** N N N O   O   T   EEE   *****
		***** N  NN O   O   T   E     *****
		***** N   N  OOO    T   EEEEE *****
		***********************************

The following routines are copied verbatim from TOPS20 APRSRV. If either
changes, please update the other.
	@


.DGFXR:				;GFLT TO DOUBLE INTEGER ROUNDED
	MOVSI	T4,(GFLT%2)	;SET THE DOUBLE AC FLAG
	CALL	DGFXR0		;GO TO COMMON CODE
	JUMPG	T3,DGFXR1	;IF SHIFT POSITIVE THEN SHIFT LEFT
	CAMG	T3,[-^D70]	;SHIFT INSTS ARE MOD 256 SO REDUCE
	MOVNI	T3,^D70		;EXPONENT IF ITS TOO LARGE
	ASHC	T1,1(T3)	;SHIFT ROUNDING BIT INTO RIGHTMOST OF T2
	DADD	T1,[EXP 0,1]	;ROUND
	ASHC	T1,-1		;SHIFT ROUNDING BIT OUT
	RET			;RETURN	TO CALLER
DGFXR1:	CAILE	T3,^D11		;CHECK EXPONENT SIZE
	JRST	DGFXR3		;TOO BIG THEN OVERFLOW
DGFXR2:	ASHC	T1,(T3)		;SHIFT LEFT NO ROUNDING
	RET			;RETURN	TO CALLER
DGFXR3:	CAIN	T3,^D12		;CHECK FOR LARGEST NEGATIVE INTEGER
	JUMPL T1,[CAMN T1,[777740000000]
		 JUMPE T2,DGFXR2 ;LET THAT ONE THROUGH
		 JRST .+1]	;OVERFLOW ON ALL OTHERS
DGFXR4:	TLO	T4,(GFLT%O)	;SET THE OVERFLOW FLAG
	RET			;AND RETURN TO CALLER

DGFXR0:				;COMMON CODE FOR DGFIXR AND DFIXR
	LDB	T3,[POINT 11,T1,11];GET THE EXPONENT
	TLNE	T1,(1B0)	;PROPAGATE SIGN THROUGH EXPONENT BITS
	TLOA	T1,777700	;NEGATIVE SET TO ONES
	TLZA	T1,777700	;POSITIVE SET TO ZEROES
	TRC	T3,3777		;UNCOMPLEMENT EXPONENT IF NEGATIVE
	SUBI	T3,2000+^D59	;GET SHIFT VALUE TO ALIGN INTEGER PART
	RET			;RETURN TO CALLER

.GFXR:				;GFLOAT TO SINGLE INTEGER ROUNDED
	SETZ	T4,		;RESET FLAG AC
	CALL	DGFXR0		;GO TO COMMON CODE
	JUMPG	T3,DFXR1	;IF SHIFT COUNT POSITIVE GO SHIFT LEFT
	CAMG	T3,[-^D70]	;SHIFT INSTS ARE MOD 256 SO REDUCE
	MOVNI	T3,^D70		;NEW EXPONENT IF IT WAS TOO LARGE
	ASHC	T1,1(T3)	;SHIFT ROUNDING BIT INTO T2
	DADD	T1,[EXP 0,1]	;ROUND
	ASHC	T1,-1		;SHIFT ROUNDING BIT OUT
	JRST	DFXR3		;GO CONVERT TO SINGLE INTEGER
DFXR1:	CAILE	T3,^D11		;CHECK EXPONENT SIZE
	JRST	DGFXR4		;GO DO OVERFLOW STUFF
DFXR2:	ASHC	T1,(T3)		;SHIFT LEFT NO ROUNDING NEEDED
DFXR3:	CAME	T1,[-1]		;HIGH WORD MUST BE ALL SIGN BITS
	JUMPN	T1,DGFXR4	;IF IT ISNT THEN OVERFLOW
	MOVE	T1,T2		;GET WORD INTO CORRECT AC
	RET			;RETURN	TO CALLER

.GFX:				;GFLOAT TO SINGLE INTEGER
	SETZ	T4,		;RESET FLAG AC
	PUSH	P,T1		;SAVE ORIGINAL SIGN
	SKIPGE	T1		;IS NUMBER POSITIVE?
	DMOVN	T1,T1		;NO...GET ABSOLUTE VALUE
	LDB	T3,[POINT 11,T1,11];GET THE EXPONENT
	TLZ	T1,777700	;CLEAR EXPONENT FROM NUMBE
	SUBI	T3,2000+^D59	;GET SHIFT AMOUNT TO ALIGN INTEGER PART
	CAMG	T3,[-^D70]	;SHIFT INSTS ARE MOD 256 SO REDUCE
	MOVNI	T3,^D70		;EXPONENT IF ITS LARGE
	CAILE	T3,^D11		;CHECK EXPONENT SIZE
	JRST	GFX2		;TOO BIG...OVERFLOW
	ASHC	T1,(T3)		;SHIFT FRACTION OFF
	SKIPGE	0(P)		;CHECK ORIGINAL SIGN
	DMOVN	T1,T1		;IF NEGATIVE COMPLEMENT RESULT
	TLNE	T1,(1B0)	;COPY HIGH SIGN INTO LOW WORD
	TLO	T2,(1B0)
	CAME	T1,[-1]		;HIGH WORD MUST BE ALL SIGN  BITS
	JUMPN	T1,GFX2		;ELSE OVERFLOW
	MOVE	T1,T2		;PUT RESULT INTO PROPER AC FOR RETURN
GFX1:	ADJSP	P,-1		;FIX STACK
	RET			;AND RETURN TO CALLER
GFX2:	TLO	T4,(GFLT%O)	;HERE ON OVERFLOW...SET THE FLAG
	JRST	GFX1		;AND RETURN TO USER

.DGFX:				;GFLOAT TO DOUBLE INTEGER
	MOVSI	T4,(GFLT%2)	;SET THE TWO ACS FLAG
	PUSH	P,T1		;SAVE THE ORIGINAL SIGN
	JUMPGE	T1,DGFX1	;IS NUMBER POSITIVE?
	DMOVN	T1,T1		;NO...SO GET ABSOLUTE VALUE
	CAMN	T1,[210740000000];CHECK FOR -2^70
	JUMPE	T2,DGFX5	;IT IS SPECIAL SO HANDLE IT
DGFX1:	LDB	T3,[POINT 11,T1,11];GET THE EXPONENT
	TLZ	T1,777700	;CLEAR THE EXPONENT FIELD
	SUBI	T3,2000+^D59	;GET SHIFT AMOUNT TO ALIGN INTEGER PART
	CAMG	T3,[-^D70]	;SHIFT INSTS ARE MOD 256
	MOVNI	T3,^D70		;REDUCE EXPONENT IF IT IS LARGE
	CAILE	T3,^D11		;CHECK EXPONENT SIZE
	JRST	DGFX4		;TOO BIG SO OVERFLOW
	ASHC	T1,(T3)		;SHIFT FRACTION OFF
	SKIPGE	0(P)		;CHECK ORIGINAL SIGN
	DMOVN	T1,T1		;IF NEGATIVE THEN COMPLEMENT
	TLNE	T1,(1B0)	;COPY HIGH SIGN INTO LOW WORD
	TLO	T2,(1B0)
DGFX2:	ADJSP	P,-1		;FIX UP THE STACK
	RET			;AND RETURN TO CALLER
DGFX4:	TLO	T4,(GFLT%O)	;SET THE OVERFLOW FLAG
	JRST	DGFX2		;AND RETURN
DGFX5:	MOVSI	T1,(1B0)	;-2^70 SPECIAL CASE
	MOVE	T2,T1
	JRST	DGFX2		;AND GO RETURN

KLLIT:	$LIT
KLEND:	END