Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99q-bb - aprser.x23
There is 1 other file named aprser.x23 in the archive. Click here to see a list.
TITLE	APRSER - PROCESSOR DEPENDENT CODE -  V52
SUBTTL	JOSEPH A. DZIEDZIC /JAD 	7 MARCH 89

	SEARCH	F,S,DEVPRM
IFN FTKL10,<SEARCH DTEPRM>

	$RELOC
	$HIGH


;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.

.CPYRT<1973,1988>

;APRSER WAS CREATED FROM KLSER AND KSSER.  AUTHORS OF THOSE MODULES:
;KLSER - J.M. FLEMMING/JMF & D.A. LEWINE/DAL/EVS
;KSSER - DMCC/DBD


XP VAPRSR,52			;PUT VERSION NUMBER IN GLOB LISTING AND MAP

APRSER::ENTRY	APRSER		;LOAD APRSER IF LIBRARY SEARCH
	SUBTTL	TRAP HANDLING

;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	SAROV3		;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
SAROV1:	TLNE	T2,MXSECN	;IN A NON-ZERO SECTION?
	JRST	SAROV5		;CAN'T TRAP IT THIS WAY THEN
	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	SAROV2		;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
SAROV2:	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	SAROV4		;YES
	HRR	T2,.JDAT+JOBAPR## ;GET USER'S TRAP ADDRESS
	TLZ	T1,(XC.OVF+XC.FOV+XC.FUF+XC.NDV+IC.BIS+IFN FTKL10,<IC.AFI>)
	TLO	T1,(XC.USR+IFN FTKL10,<XC.PUB>) ;INSURE PUBLIC AND USER MODE SET
SAROV3:	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

SAROV4:	MOVEI	T3,XP.LTH	;STUCK IN LOOP BIT
SAROV5:	DMOVEM	T1,.CPAPC##	;SAVE OLD PC FOR ERROR MESSAGE
	HRRM	T3,.CPAEF##
	JRST	SEPDL2
;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
SEPDL2:	SETOM	.CPSCF##	;SET FORCED RESCHEDULING FLAG
	SETOM	.CPCKF##	;AND CLOCK FLAG
	CONO	PI,XI.RQC##	;REQUEST A CLOCK INTERRUPT
	JRST	.		;WAIT UNTIL CLOCK LEVEL HAPPENS AND THE JOB
				; IS STOPPED IN USER MODE.


;SEE IF WE CAN EXTEND THE JOB'S PDL

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::	SKIPE	.CPPFT##	;IS THERE A PRE-EMPTIVE FAULT HANDLER?
	XJRST	.CPPFT##	;YES, TRANSFER CONTROL TO IT
	CONI	PI,.CPTPI##	;SAVE THE PI STATE
IFN FTKL10,<
	CONSO	PI,PI.ON	;IS THE PI SYSTEM ON?
	JRST	SEIL2		;NO--PROCESS TRAP IMMEDIATELY
	CONSZ	PI,AP.ACO##	;APR CHANNEL ON?
	CONSZ	PI,AP.APP##	;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
>; END IFN FTKL10
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
	MAP	T1,.UPMP	;IS THE UPT ACCESSIBLE?
;WOULD BE NICE TO CALL FLTCHK HERE BUT WE DON'T HAVE A P
	TLNE	T1,(MP.BAD)	;BAD MAPPING?
	JRST	SEILUP		;YES
	TLNE	T1,(MP.WRT)	;MUST BE WRITABLE, TOO
	TLNN	T1,(MP.BTS)	;VALID MAPPING?
	JRST	SEILUP		;NO, REALLY BAD, QUIT NOW
	LDB	T1,[POINT 5,.USPFW,5] ;PICK UP PF CODE
IFN FTKL10,<CAIE T1,PF.ABF>	;IS THIS AN ADDRESS BREAK?
	CAIGE	T1,20		;IS THIS A REAL PAGE FAULT
	JRST	SEILMA		;YES--GO PROCESS IT

IFN FTKL10,<CAIL T1,PF.ARP>	;IS IT A PARITY TRAP?
IFN FTKS10,<CAIL T1,PF.PAR>	;IS IT A PARITY OR NXM TRAP?
	JRST	PRTRP		;YES--GO PROCESS
	CAIN	T1,PF.PTP	;IS IT PAGE TABLE PARITY?
	JRST	PTPAR		;YES--GO PROCESS
IFN FTKL10,<
	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
	CAIN	T1,PF.PRF	;IS IT A PAGE REFILL FAILURE?
	STOPCD	.,CPU,PRF	;++PAGE REFILL FAILURE
>; END IFN FTKL10
IFN FTKS10,<
	CAIN	T1,PF.IOP	;IS IT A UBA FAILURE?
	JRST	SEILMU		;YES, PROCESS
>; END IFN FTKS10
	STOPCD	.,CPU,IPC	;++ILLEGAL PAGE FAILURE TRAP CODE
;HERE ON A UNIBUS ADDRESSING FAILURE
;A USER MODE FAILURE CAN OCCUR IF THE USER HAS IOT, AND MAKES A
;STRAY REFERENCE.  WE DON'T WANT TO KILL THE SYSTEM.  ALLOW THE
;USER TO INTERCEPT (NOT APRENB, BUT PSI) SO CAN CHECK WHETHER A
;DEVICE IS PRESENT.

IFN FTKS10,<
SEILMU:	DMOVEM	T2,.CPST1##	;SAVE SOME MORE ACS
	DMOVE	T1,.USPFP	;FETCH THE PC THAT FAILED
	SKIPE	.USJOB##	;IF NULL JOB, IT'S EXEC MODE
	TLNN	T1,(XC.USR)	;USER MODE?
	STOPCD	.,STOP,UAF,DIEUAF ;++UNIBUS ADDRESSING FAILURE
	DMOVEM	T1,.CPAPC##	;USER MODE, CAN SIMPLY STOP JOB (USER HAS IOT)
	MOVE	T1,.USPFW	;GET THE ADDRESS THAT FAILED
	MOVEM	T1,.USMUP	;SAVE IT IN CASE NON-EXISTANT UBA
	TLZ	T1,^-17		;KEEP ONLY THE UBA NUMBER
	HRRI	T1,UNBSTW	;POINT TO THE UBA STATUS REGISTER
	XMOVEI	T3,UBNOGD	;GET PAGE FAIL HANDLER
	EXCH	T3,.CPPFT##	;IN CASE OF ILLEGAL UBA
	MOVEI	T2,UNBNED!UNBTMO ;NON-EXISTANT DEVICE AND TIMEOUT
	BCIO	T2,(T1)		;CLEAR THE BITS
	MOVEM	T3,.CPPFT##	;RESTORE THE USUAL PAGEFAIL HANDLER
	DMOVE	T2,.CPST1##	;AND THE EXTRA ACS
	MOVE	T1,.CPSTT##	;RESTORE T1
	EXCH	T1,.USMUP	;AND PUT IT WHERE SEPDL1 WANTS IT
	MOVEM	T1,.USPFW	;RESTORE ORIGINAL PFW IN CASE OF PSI TRAP
	MOVEI	T1,AP.ILM	;ILL MEM REF BIT
	WRPI	PI.ON		;RESTORE PI SYSTEM
	JRST	SEPDL1		;AND GIVE ?ILL MEM REF AT PC MUMBLE

DIEUAF:	PUSHJ	P,INLMES##	;ADD SOME TEXT
	ASCIZ	/UBA = /
	LDB	T1,[POINT 4,.USPFW,17] ;GET UBA NUMBER
	PUSHJ	P,PRTDI8##	;PRINT IT
	PUSHJ	P,INLMES##	;MORE TEXT
	ASCIZ	/, register address = /
	HRRZ	T1,.USPFW	;GET ADDRESS
	PJRST	PRTDI8##	;PRINT AND RETURN
>; END IFN FTKS10
;HERE ON AR OR ARX PARITY TRAP (PAGE FAIL CODE 36 OR 37)
PRTRP:	SKIPE	.CPPSP##	;CORE SWEEP IN PROGRESS?
	JRST	SWTRP		;YES, JUST SAVE LOCATION OF FAILURE AND DISMISS
IFN FTKL10,<
	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
>; END IFN FTKL10
	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
	DIELOK			;GRAB THE DIE INTERLOCK
	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
IFN FTKS10,<
	CAIN	T4,PF.NXM	;IS IT AN NXM?
	SKIPA	P4,[UE.NXM]	;YES, SET UP NXM FLAG
>; END IFN FTKS10
	MOVEI	P4,UE.PEF	;NO, SET UP PARITY ERROR FLAG
IFN FTKL10,<
	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
>; END IFN FTKL10
IFN FTKS10,<
	TRNE	P4,UE.NXM	;IS THIS AN NXM?
	JRST	PRTRP2		;YES--THEN THERE'S NO DATA TO PICK UP
	WRUBR	[SG.LAB+7B11]	;NO--SET PREVIOUS ACS TO BLOCK 7
	PXCT	PX.MEM,[MOVE T4,0] ;PICK UP BAD DATA WORD FROM BLOCK 7
>; END IFN FTKS10
	EXECAC			;RESTORE MONITOR AC SETTINGS
	MOVEM	T4,.CPTBD##	;SAVE BAD DATA FOR DAEMON
IFN FTKL10,<
	TLNE	T1,(XC.USR)	;IS THE TRAP FROM EXEC MODE?
	JRST	PRTRP2		;NO--CONTINUE
	SKIPE	.CPCHE##	;IS TRAP FROM CHANNEL ERROR REPORTING?
	JRST	PRTCHN		;YES--SPECIAL HANDLING
	TLZ	T2,-1-MXSECN	;GET JUST THE ADDRESS OF OFFENDING INSTRUCTION
	TLZ	T3,-1-MXSECN	;GET JUST THE ADDRESS OF OFFENDING REFERENCE
	CAMN	T2,T3		;IS AN INSTRUCTION FETCH AT FAULT?
	JRST	PRTRP2		;YES--CONTINUE
	MOVE	T1,(T2)		;NO--PICK UP THE OFFENDING INSTRUCTION
	TLNN	T1,740		;IS THE AC FIELD NON-ZERO?
	JRST	PRTRP2		;NO--CONTINUE
	LSH	T1,-^D27	;YES--GET JUST THE OP CODE
	CAIE	T1,(XCT_-^D9)	;IS THIS A PXCT THEN?
	JRST	PRTRP2		;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	PRTRP1		;NO, NONE OF THESE ARE BLTS ANYWAYS
 	LDB	T3,[POINT 9,(T1),8] ;GET OP-CODE OF PXCT'ED INSTRUCTION
	CAIE	T3,(BLT_-^D9)	;IS IT A BLT?
	JRST	PRTRP1		;NO
	TLNN	T1,PX.SRC*40	;BLT FROM USER TO EXEC?
	JRST	PRTRP2		;NO, EXEC TO USER
PRTRP1:	MOVSI	T3,(PF.USR)	;YES--GET THE USER REFERENCE BIT
	IORB	T3,.CPPFW##	; AND FIX THE PAGE FAIL WORD (HARDWARE IS WRONG)
	JRST	PRTRP4		;REFERENCE WAS VIRTUAL
>; END IFN FTKL10
PRTRP2:	MOVE	P1,.CPPFW##	;GET THE PAGE FAIL WORD
	MOVE	T3,.CPMAP##	;GET EPT ADDRESS FOR THIS CPU
	PUSH	P,.ERPIL/PAGSIZ(T3) ;SAVE MAPPING FOR TEMP SLOT

;THE CODE BETWEEN HERE AND PRTRP5 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

IFN FTKL10,<
;	TLNE	P1,(PF.PHY)	;A PHYSICAL REFERENCE?
;	JRST	PRTRP4		;NO, CALCULATE PHYSICAL FROM VIRTUAL ADDRESS
;HERE TO PRETEND PF.PHY WAS ON AND REFERENCE POSSIBLE PHYSICAL LOCATIONS
	TLZ	P1,(MP.NAD)	;ISOLATE PHYSICAL ADDRESS
	CAILE	P1,PG.BDY	;COULD THE REFERENCE HAVE BEEN TO A PAGE MAP?
	JRST	PRTRP3		;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,LG.UPT	;ISOLATE THE PAGE NUMBER
	LSH	P1,P2WLSH	;PHYSICAL ADDRESS OF THE MAP
	IOR	P1,.CPPFW##	;PHYSICAL ADDRESS OF REFERENCE
	TLZ	P1,(MP.NAD)	;CLEAR CRUFT
	PUSHJ	P,TRYREF	;TRY REFERENCING THE LOCATION IN THE MAP
	  JRST	PRTRP5		;FAILED, STORE IT
	JRST	PRTRP4		;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)

PRTRP3:	PUSHJ	P,TRYREF	;SEE IF BAD PARITY IN PHYSICAL LOCATION
	  JRST	PRTRP5		;YES, STORE PHYSICAL ADDRESS
>; END IFN FTKL10

;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

PRTRP4:	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
PRTRP5:	MOVEM	P1,.CPPBA##	;SAVE BAD PHYSICAL ADDR FOR DAEMON
	TLZ	P1,(MP.NAD)	;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
IFN FTKL10,<MOVEI T1,[ASCIZ . AR/ARX parity trap.]>
IFN FTKS10,<
	TRNE	P4,UE.NXM	;IS THIS AN NXM?
	SKIPA	T1,[[ASCIZ / non-existent memory trap/]] ;YES
	MOVEI	T1,[ASCIZ / parity trap/] ;NO
>; END IFN FTKS10
	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##
IFN FTKS10,<TRNN P4,UE.NXM>	;NO DATA TO PRINT ON NXM
	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
IFN FTKL10,<
	CONSO	PAG,LG.CSL	;IS THE CACHE ON?
	JRST	PRTRP6		;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
	CONO	APR,LP.CSF!LP.CSD+APRCHN## ;CLEAR CACHE SWEEP DONE
	CONSO	APR,LP.PAR	;MB PARITY DURING SWEEP?
	JRST	PRTRP6		;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
	CONO	APR,LP.CSF!LP.SBE!LP.PAR+APRCHN## ;CLEAR THE APR

;HERE TO START RETRIES-FIRST WITH CACHE OFF
PRTRP6:	MOVE	T1,.CPPBA##	;BAD PHYSICAL ADDRESS
	TLZ	T1,(MP.NAD)	;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
>; END IFN FTKL10
	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
IFN FTKL10,<
	TRNN	P2,PFCPF3	;WAS CACHE ON WHEN WE STARTED?
	JRST	PRTRP8		;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 PRTRP7] ;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
PRTRP7:	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
	CONO	APR,LP.CSF!LP.CSD+APRCHN## ;CLEAR CACHE SWEEP DONE
	CONO	PAG,@.CPEBR##	;TURN ON CACHE LOOK & LOAD
>; END IFN FTKL10
;HERE IF RETRIES WERE SUCCESFUL, LOG SOFT ERROR AND DISMISS
PRTRP8:
IFN FTKS10,<TRO P2,PFCPF0>	;INDICATE WE'RE A KS10
	HRLM	P2,.CPPTR##	;SAVE STATUS FLAGS FOR ERROR REPORTING
IFN FTKL10,<DPB	T3,[POINT 9,.CPPTR##,26]> ;PUT CACHE RETRY COUNT HERE
	MOVE	T3,.CPMAP##	;GET EPT ADDRESS FOR THIS CPU
	POP	P,.ERPIL/PAGSIZ(T3)
IFN FTKL10,<
	PUSHJ	P,CLRSBD##	;CLEAR MEMORY CONTROLLERS
	CONO	APR,LP.CSF!LP.SBE!LP.PAR+APRCHN## ;CLEAR ANY APR ERRORS
>; END IFN FTKL10
	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) ;PAGE NUMBER
	HRRI	P1,(<PM.DCD>B2+PM.WRT+PM.PUB) ;ACCESSIBLE AND WRITABLE
	HRLM	P1,.ERPIL/PAGSIZ(T3)
	CLRPT	.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
	XMOVEI	T2,TRYBAD	;GET TEST TRAP ADDRESS
	EXCH	T2,.CPPFT##	;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
IFN FTKS10,<WREBR @.CPEBR##>	;INVALIDATE CACHE
	MOVE	T1,0(P1)	;TRY THE REFERENCE
	TRZ	P2,PFCPF0	;CLEAR THE REFERENCE FLAG
	TRZN	P2,PFCPF2	;ERROR DURING REFERENCE?
	JRST	PRTY2		;NO--GIVE A GOOD RETURN
	CAIGE	T3,TRPTRY	;YES--RETRY COUNT EXHAUSTED?
	AOJA	T3,PRTY1	;NO--TRY AGAIN
	SKIPA			;YES--GIVE AN ERROR RETURN
PRTY2:	AOS	-2(P)		;SET FOR SKIP RETURN
	POP	P,.USPFP+1	;AND SECOND WORD
	POP	P,.USPFP	;RESTORE OLD CONTENTS
	MOVEM	T2,.CPPFT##	;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	.,STOP,UPF	;++UNEXPECTED PAGE FAIL
	LDB	T1,[POINT 5,.USPFW,5] ;GET PAGE FAIL CODE
IFN FTKL10,<CAIE T1,PF.ARP>	;AR PARITY ERROR?
IFN FTKS10,<CAIGE T1,PF.PAR>	;PARITY ERROR OR NXM?
	STOPCD	.,STOP,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

IFN FTKL10,<
PRHCF:	SWPIA			;INVALIDATE CACHE BUT DON'T TOUCH CORE
	CONSO	APR,LP.CSD	;SWEEP BUSY?
	JRST	.-1		;WAIT FOR DONE
	CONO	APR,LP.CSF!LP.CSD+APRCHN## ;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	PRTRP8		;NOW CLEAN UP AND RETURN TO USER

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

PRHMF:
IFN FTKS10,<TRNN P4,UE.NXM>	;DON'T ZERO IF NXM
	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 EPT ADDRESS FOR THIS CPU
	POP	P,.ERPIL/PAGSIZ(T1)
	AOS	.CPHPT##	;BUMP HARD (AR/ARX) PARITY TRAP COUNT
IFN FTKL10,<
	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
	CONO	APR,LP.CSF!LP.SBE!LP.PAR!LP.CSD+APRCHN## ;CLEAR THE APR
>; END IFN FTKL10
	TRO	P2,PFCPF1+IFN FTKS10,<PFCPF0> ;SAY HARD ERROR FOR ERROR REPORTING
	HRLM	P2,.CPPTR##	;SAVE FLAGS
	HRRM	T3,.CPPTR##	;SAVE RETRY COUNT FOR ERROR REPORTING
IFN FTKL10,<CONO PAG,@.CPEBR##>	;TURN THE CACHE BACK ON
IFN FTKS10,<
	TRNE	P4,UE.NXM	;IF THIS IS A NXM, MESSAGE IS DIFFERENT
	SKIPA	T1,[[ASCIZ /Retry unsuccessful./]]
>; END IFN FTKS10
	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	PRHMF2		;YES--GO KILL USER
	HRRZ	T1,.CPPFW##	;GET THE PROBLEM ADDRESS
	SKIPGE	.CPPFW##	;IS THIS A USER CONTEXT REFERENCE?
	JRST	PRHMF1		;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	PRHMF1		;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,[MP.NAD+PG.BDY] ;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

PRHMF1:	SETOM	.CPREP##	;SET PARITY MSG FLAG IN CASE THIS IS FATAL
IFN FTKS10,<
	TRNE	P4,UE.NXM	;IS THIS A NXM?
	SETZM	.CPREP##	;YES--SET FLAG PROPERLY
>; END IFN FTKS10
	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	PRHMF4		;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	PRHMF7		;TREAT AS FATAL USER ERROR
PRHMF2:	TDNN	P4,.CPCN1##	;IS USER ENABLED TO HANDLE THIS HIMSELF?
	JRST	PRHMF4		;NO--GO ON
	MOVE	T2,JBTSTS##(J)	;YES--GET JOB STATUS WORD
	TLNE	T2,JACCT	;IS JOB PRIVILEGED?
	JRST	PRHMF3		;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	PRHMF3		;YES--LET'S TRAP TO HIM AS REQUESTED
	JRST	PRHMF4		;NO--THEN WE IGNORE HIS TRAP REQUEST
PRHMF3:	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
	HRRZ	T3,P4		;PUT PARITY/NXM BIT HERE
	JRST	SAROV1		;GO TRAP TO USER
PRHMF4:	SETZ	P2,		;SET FLAG ASSUMING LOW SEG ERROR
	MOVE	J,.CPJOB##	;GET THE OFFENDING JOB #
	PUSH	P,P1		;SAVE P1
	MOVE	P1,.CPPFW##	;SECTION # IN RIGHT HALF
	TLZ	P1,-1^!MXSECN	;KEEP ONLY SECTION # IN LEFT HALF
	TDZA	T1,T1		;START AT THE BEGINNING
PRHMF5:	POP	P,T1		;LAST HIGH SEG LOOKED AT
	MOVSS	P1		;PUT SECTION # IN RIGHT HALF
	PUSHJ	P,NXSSP1##	;FIND A(NOTHER) SEGMENT IN THAT SECTION
	  JRST	PRHMF6		;NO MORE
	PUSH	P,T1		;SAVE HIGH SEG DATA BLOCK ADDR
	PUSHJ	P,HSVAD##	;GET LIMITS OF THAT HIGH SEG
	MOVSS	P1 		;SWAP HALVES AGAIN
	CAIG	T2,(P1)		;FAULT ADDR ABOVE BEGINNING OF HIGH SEG?
	CAIL	T1,(P1)		;AND BELOW TOP
	JRST	PRHMF5		;NO, CHECK NEXT
	POP	P,J		;HIGH SEG DATA BLOCK ADDR
	HRRZ	J,.HBSGN(J)	;GET SEGMENT #
	SETO	P2,		;SET FLAG INDICATING HIGH SEG ERROR
	PUSHJ	P,HGHPAR##	;GO PROCESS JOBS USING THIS SEGMENT
PRHMF6:	POP	P,P1		;RESTORE P1
PRHMF7:	JUMPN	P1,PRHMF8	;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	PRHMF8		;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
PRHMF8:	MOVEI	T1,EDELIM##	;GET END DELIMITER
	PUSHJ	P,PRMSG		;PRINT IT
	MOVE	J,.CPJOB##	;GET JOB NUMBER
	JUMPE	P2,PRHMF9	;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	PRHMF9		;YES--JUST GO STOP IT
	DIENLK			;RETURN THE DIE INTERLOCK
	CONO	PI,PI.ON	;TURN THE PI'S BACK ON
IFN FTKS10,<
	HLLZ	T1,.CPMPS##	;GET CPU REQUESTS MEMORY SCAN BITS
	HRRI	T1,(P4)		;SET PARITY OR NXM BIT
	IORM	T1,.CPAEF##	;SET REQUEST
>; END IFN FTKS10
	DMOVE	T1,.USPFP	;GET PC/FLAGS DOUBLEWORD
	DMOVEM	T1,.CPPC##	;SAVE PC FOR RESCHEDULE
	PJRST	CLKSPD##	;RESCHEDULE THIS JOB TO RE-RUN WITH NEW HI SEG

PRHMF9:	MOVSI	T1,JACCT	;CLEAR JACCT SO DAMAGED PROGRAM
	ANDCAM	T1,JBTSTS##(J)	; WON'T HAVE PRIVILEGES
	MOVEI	T1,JS.MPE	;ASSUME PARITY ERROR IN JOB
IFN FTKS10,<
	TRNE	P4,UE.NXM	;IS IT A NXM?
	MOVEI	T1,JS.NXM	;YES--GET NXM IN JOB STATE BIT
>; END IFN FTKS10
	IORM	T1,JBTSTS##(J)	;SET IN JOB STATUS WORD
IFN FTKL10,<MOVSI T1,(CP.PXX)>	;GET PRINT REQUEST BIT
IFN FTKS10,<HLLZ T1,.CPMPS##>	;GET CPU REQUESTS MEMORY SCAN BITS
	HRRI	T1,(P4)		;SET PARITY OR NXM BIT
	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,APRMPI	;BETTER MATCH THE SWEEP BLT ADDRESS
	STOPCD	.,STOP,NPI	;++NOT PARITY INSTRUCTION
	MOVE	T1,.USPFW	;GET THE PAGE FAIL WORD
	MOVEM	T1,.CPPFW##	;AND SAVE IT
IFN FTKL10,<
	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
>; END IFN FTKL10
IFN FTKS10,<
	WRUBR	[SG.LAB+07B11]	;SET PREVIOUS AC BLOCK TO 7
	PXCT	PX.MEM,[MOVE T1,0] ;GET BAD DATA WORD FOR DAEMON
>; END IFN FTKS10
	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
IFN FTKL10,<
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
>; END IFN FTKL10
;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
IFN FTKL10,<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,DATIME##	;PRINT DATE AND TIME
	PUSHJ	P,PCRLF##	;AND A CRLF
	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"
PRMPC1:	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
IFN FTKL10,<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	PRMPC1		;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
IFN FTKL10,<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	PRMPC1		;FINISH UP

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

DAELOG:	MOVEI	T1,.ERKPT	;CODE FOR DAEMON
IFN FTKS10,<
	TRNE	P4,UE.NXM	;IT IT AN NXM?
	MOVEI	T1,.ERKSN	;YES
>; END IFN FTKS10
	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:	CONO	PAG,@.CPEBR##	;CLEAR THE PAGE TABLE
	AOS	.CPPTP##	;COUNT A PAGE TABLE PARITY ERROR
	MOVE	T1,.CPSTT##	;RESTORE T1
	MOVEM	17,.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
	DIELOK			;GRAB THE DIE INTERLOCK
	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	PRHMF9		;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:	DIENLK			;RETURN THE DIE INTERLOCK
	MOVSI	17,.CPA00##	;BLT POINTER TO RESTORE ACS
	BLT	17,17		;RESTORE AC'S
PTXIT1:	DATAO	PAG,.CPTCX##	;RESTORE THE CONTEXT AT TIME OF TRAP
	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	.CPTPC##	;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
	MOVE	T2,.USPFW	;GET THE USER PAGE FAIL WORD
	MOVEM	T2,.CPPFW##	;SAVE PAGE FAULT WORD FOR CRASH
	TLNE	T1,(XC.USR)	;PAGE FAULT IN EXEC MODE?
	JRST	SEILM1		;NO, PROCEED
IFN FTKL10,<
	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	SEILM2		;YES, REMEMBER IT AND GO AWAY
>; END IFN FTKL10
	JRST	SEJLM1		;NO, EXEC ILL MEM REF, LOOK FOR ERJMP


;HERE ON EXEC MODE ADDRESS BREAK (ACS RESTORED)
IFN FTKL10,<
SEILMX:	DATAO	APR,[EXP 0]	;TURN OFF ADDRESS BREAK
	DMOVE	T1,.CPST1##	;RELOAD T1 & T2
	MOVEM	17,.CPA17##	;SAVE AC 17
	MOVEI	17,.CPA00##	;MAKE BLT POINTER
	BLT	17,.CPA17##-1	;SAVE AC'S IN CPU DATA BLOCK
	LDB	T1,[.CPABS##+S$PTRT] ;GET STOPCODE TYPE
	EXCH	T1,.CPST1##	;PUT IN A SAFE PLACE AND RESTORE T1
	SKIPE	.CPST1##	;ZERO MEANS NO STOPCODE
	XCT	.CPABS##	;CREATE SOME CHATTER
	MOVEM	T1,.CPST1##	;SAVE T1 AGAIN
	XCT	.CPABI##	;EXECUTE INSTRUCTION TO CALL SUBROUTINE
	  JFCL			;INCASE OF SKIP RETURN
	MOVSI	T1,(XC.AFI)	;ADDRESS FAILURE INHIBIT
	IORM	T1,.USPFP	;ALLOW INSTRUCTION TO BE EXECUTED
	SKIPL	.CPABW##	;WANT REPETITIVE ENABLE?
	PUSHJ	P,ABKCLM	;CLEAR ADDRESS BREAK CONDITIONS
	MOVE	T1,.CPABW##	;GET ADRESS BREAK CONDITIONS + ADDRESS
	TLZE	T1,(AB.REP)	;REPETITIVE ENABLE?
	DATAO	APR,T1		;YES
	MOVSI	17,.CPA00##	;SET UP BLT
	BLT	17,17		;RESTORE THE ACS
	XJEN	.USPFP		;AND PROCEED FROM ADDRESS BREAK
> ;END IFN FTKL10
;HERE IF USER PAGE FAULT

SEILM1:	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##]	;SETUP A PUSH DOWN LIST
	SKIPN	.USJOB		;NULL JOB?
	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
IFN FTKL10,<
	CAIN	T2,PF.ABF	;ADDRESS BREAK?
	JRST	SEILM2		;YES, GO PROCESS
>; END IFN FTKL10
	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
IFN FTKL10,<
	CAIN	T2,PF.ISN	;ILLEGAL SECTION?
	JRST	SEPDL1		;YES
	CAIN	T2,PF.PRV	;WAS IT A PROPRIETARY VIOLATION?
	JRST	[HRRI T1,AP.PPV	;INDICATE PROP VIO
		 JRST SEPDL1]
>; END IFN FTKL10
	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."
;HERE ON ADDRESS BREAK

IFN FTKL10,<
SEILM2:	SKIPGE	.CPABF##	;EXEC MODE ADDRESS BREAK ENABLED?
	SKIPN	.CPABW##	;AND AN ADDRESS SET?
	CAIA			;DO NORMAL USER STUFF
	JRST	SEILMX		;HANDLE ADDRESS BREAK
	DMOVE	T1,.USPFP	;GET FAULT DOUBLE WORD PC
	TLO	T1,(XC.AFI)	;INHIBIT ADDRESS BREAK WHEN INSTR 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,SEILM6       ;CONTINUATION PC
			        ;DON'T BREAK IF PROCEED COUNT .GT. 0
	MOVE	T2,JBTSTS##(J)	;IS THIS A JACCT
	TLNN	T2,JACCT	;JOB
	JRST	SEILM3		;NOT JACCT
	MOVE	T2,JBTPPN##(J)	;YES, BUT IS
	CAME	T2,FFAPPN##	; HE GOD?
	JRST	SEILM6		;NO-IGNORE BREAK
SEILM3:	EXCH	J,.CPJOB##	;UNDO LAST EXCH
	TLNN	T1,(XC.USR)	;PC IN USER MODE?
	JRST	SEILM5		;NO, REMEMBER BREAK AND GO AWAY
	MOVEM	T1,.JDAT+JOBPD1## ;SAVE FLAGS
	PUSH	P,.CPPC##+1	;AND PC
	MOVE	R,.CPADR##	;SETUP R
	MOVE	J,.CPJOB##	;JOB NUMBER FOR PSISER
	SIGNAL	C$ADRB		;SIGNAL THAT AN ADDRESS BREAK HAS OCCURED
	  SKIPA			;USER DOESN'T WANT TRAP
	JRST	SEILM8		;INTERRUPT TO THE USER

	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
	PUSHJ	P,PSIERR##	;PENDING INTERRUPT?
	  JFCL
	  PJRST	ERRGOU##	;YES, GIVE IT TO THE USER
				;FALL INTO SEILM4
SEILM4:	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##

SEILM5:	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	SEILM6		;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
SEILM6:	EXCH	J,.CPJOB##	;RESTORE J
>; END IFN FTKL10

SEILM7:	MOVE	T1,.CPPC##	;GET FLAGS OF PC
	TLNE	T1,(XC.USR)	;BREAK OUT OF USER MODE?
	JRST	SEILM8		;YES
	DMOVE	T1,.CPST1##	;RESTORE T1 AND T2
	XJRSTF	.CPPC##		;GO AWAY AND TELL THE USER ABOUT THE BREAK
				; AT UUO EXIT
SEILM8:	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

SEJLM1:	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	.CPTPC##	;NESTING?
	JRST	@[0,,SEJLM6]	;YES, IT'S AN IME
	.CREF	PF.USR		;NOTE BIT WE'RE TESTING
	SKIPL	T2,.CPPFW##	;GET PAGE FAULT WORD, SKIP IF USER REF
	JRST	SEJLM3		;NOT USER REFERENCE
	PUSHJ	P,UUOLVL##	;YES, AT UUO LEVEL?
	  JRST	SEJLM3		;NO
IFN FTPEEKSPY,<
	PUSHJ	P,SEJSPG	;SEE IF REFERENCE TO A SPY PAGE (PRESERVES ACS)
	  JRST	UADERR##	;YES, BLAME THE USER
>; END IFN FTPEEKSPY
	TLNN	T2,(PF.ACC)	;VALID MAPPING?
	JRST	SEJLM3		;NO, PROBABLY A REFERENCE TO A PAGE WITH AA OFF
	TLNE	T2,(PF.WRT)	;PAGE FAIL A WRITE VIOLATION?
	PUSHJ	P,[PUSHJ P,SAVT## ;SAVE VOLATILE ACS
		   MOVE T3,T2	;PAGE FAIL WORD - ARGUMENT TO WLPFLT
		   PJRST WLPFLT##] ;WRITE ENABLE THE PAGE IF POSSIBLE
	  JRST	SEJLM3		;SPY PAGE OR PAGE IN A WRITE LOCKED HI SEG
	DMOVE	T1,.CPST1##	;RESTORE ACS
	XJRSTF	.USPFP		;TRY AGAIN WITH PAGE WRITE ENABLED
;LOOK FOR "ERJMP" OR "ERCAL" FOLLOWING FAILED INSTRUCTION

SEJLM3:	DMOVE	T1,.USPFP	;GET PC DOUBLEWORD AT FAULT
	DMOVEM	T1,.CPTPC##	;SAVE "TOP LEVEL" FAULT ADDRESS FOR ERJMP RETRY
	MOVE	T1,.USPFW	;GET PAGE FAIL WORD AT FAULT
	MOVEM	T1,.CPTPF##	;SAVE "TOP LEVEL" PAGE FAIL WORD
IFN FTXMON,<
	TLNE	T2,-1		;FAULT OCCUR IN A NON-ZERO SECTION?
	XJRST	[MCSEC1+.+1]  	;YES, GO INTO SECTION 1
>; END IFN FTXMON
	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	SEJLM6		;NO, THEN WE HAVE AN IME
	MOVE	T2,1(T1)	;GET ENTIRE ERJMP EXPRESSION
	MOVEM	T2,.CPEJT##	;SAVE WHERE WE CAN FIND IT
IFN FTXMON,<
	TLNN	T1,-1		;NON ZERO SECTION?
	JRST	SEJLM4		;NO, DO SECTION 0 CALCULATION
	TLZ	T2,777740	;NON-ADDRESSING PART OF ERJMP
	TLO	T2,(IFIW)	;MAKE A USABLE INDIRECT
	MOVEM	T2,.CPEJT##	;SAVE WHERE WE CAN FIND IT
	DMOVE	T1,.CPST1##	;RESTORE T1&T2
	XMOVEI	T1,@.CPEJT##	;RESOLVE ADDRESS OF ERJMP
	JRST	SEJLM5		;JOIN COMMON CODE
>; END IFN FTXMON

SEJLM4:	DMOVE	T1,.CPST1##	;RESTORE T1&T2
	MOVEI	T1,@.CPEJT##	;RESOLVE ADDRESS OF ERJMP
				;IF THIS IMES .CPTPC/.CPTPF HAVE ORIGINAL
				; TRAP PC AND PAGE FAIL WORD
SEJLM5:	MOVEM	T1,.CPAPC##+1	;SET CONTINUATION ADDRESS
	MOVE	T1,.CPST1##	;RESTORE T1
	SETZM	.CPTPC##	;CLEAR NESTING FLAG
	DATAO	PAG,.CPTCX##	;RESTORE TRAP CONTEXT
	XJRSTF	.CPAPC##	;CONTINUE AT PC FROM "ERJMP"
;HERE ON NESTED IME, "RESTORE" THE FIRST IME AND STOPCD

SEJLM6:	DMOVE	T1,.CPTPC##	;PAGE FAULT PC DOUBLEWORD
	DMOVEM	T1,.USPFP	;RESTORE CONTEXT OF FIRST IME
	DMOVEM	T1,.CPAPC##	;SET TRUE ERROR PC
	MOVE	T2,.CPTPF##	;PAGE FAIL WORD
	MOVEM	T2,.CPPFW##	;SET TRUE PAGE FAULT WORD
	MOVEM	T2,.USPFW	;ALSO MAKE UPT LOOK RIGHT
SEILME:	SETZM	.CPTPC##	;CLEAR NESTING FLAG
	DMOVE	T1,.CPST1##	;RESTORE AC'S AT TRAP
	STOPCD	.,JOB,IME,DIEIME, ;++ILL MEM REF FROM EXEC
				;NEVER CONTINUES HERE

DIEIME:	PUSHJ	P,INLMES##	;ADD SOME TEXT
	ASCIZ	/Page fail word = /
	MOVE	T1,.USPFW	;GET PAGE FAIL WORD
	PUSHJ	P,HWDPNT##	;PRINT AS HALF-WORDS
	PUSHJ	P,INLMES##	;ADD SOME TEXT
	ASCIZ	/, page fail PC = /
	MOVE	T2,.USPFP+1	;GET PAGE FAIL PC
	PJRST	UDPCP##		;PRINT AND RETURN
;ROUTINE TO SEE IF A REFERENCE WAS TO A SPY PAGE
;CALL WITH PAGE FAIL WORD IN T2, NON-SKIP RETURN IF A SPY PAGE
;REFERENCE, SKIP RETURN IF NOT A SPY PAGE REFERENCE.
;PRESERVES T1-T4

IFN FTPEEKSPY,<
SEJSPG:	PUSHJ	P,SAVT##	;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?
	  AOS	(P)		;NO, SKIP RETURN
	POPJ	P,		;RETURN
>; END IFN FTPEEKSPY
;HERE IF AN EXEC BREAK OCCURED WHILE IN EXEC MODE.
;CALLED FROM USRRET IN UUOCON WITH T1 CONTAINING JS.ABP.

IFN FTKL10,<
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
	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
	PUSHJ	P,PSIERR##	;PENDING INTERRUPT?
	  JFCL
	  POPJ	P,		;YES

	POP	P,(P)		;POP OFF THE PUSHJ TO EXCABK
	JRST	SEILM4		;AND STOP THE JOB IN A CONTINUABLE STATE
>; END IFN FTKL10
;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	SAROV1		;FINISH UP

SUPDLO::DMOVE	T1,.USMUO	;GET FLAGS & PC
	MOVEI	T3,AP.POV	;SET POV BIT FOR USER
	JRST	SAROV1		;FINISH UP

;HERE FROM SEILM ON A PAGE FAULT WHEN THE UPT IS NOT ADDRESSABLE
;(ODD ERROR CONDITION).  DON'T LOOP FOREVER TRYING TO REFERENCE
;THE UPT WHICH WILL LEAD TO ANOTHER PAGE FAULT.

SEILUP:	EXCH	T1,.CPSTT##	;RESTORE T1, SAVE RESULTS OF MAP INSTRUCTION
	MOVEM	17,.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
	MOVE	T1,.CPSTT##	;GET RESULTS OF MAP INSTRUCTION BACK
	HRRZ	T2,JBTUPM##+0	;GET PAGE NUMBER OF NULL JOB'S UPT
	EXCH	T2,@.CPSPT##	;POINT SPT AT NULL JOB, SAVE OLD CONTENTS IN T2
	DATAO	PAG,NULDOP##	;MAKE SURE SOME UPT IS ADDRESSABLE
	STOPCD	.,STOP,UNA,	;++UPT NOT ADDRESSABLE
				;T1/ RESULTS OF MAP .UPMP
				;T2/ OLD CONTENTS OF @.CPSPT
SUBTTL	APR INTERRUPT PROCESSING -- KL10


IFN FTKL10,<

;APR CHANNEL INTERRUPT
APRINT::CONSO	APR,LP.CSD	;CACHE SWEEP DONE?
	JRST	APRIN1		;NO
	CONO	APR,LP.CSF+LP.CSD+APRCHN## ;YES, CLEAR SWEEP DONE FLAG
	AOS	.CPCSN##	;COUNT A CACHE SWEEP COMPLETED
	EXCH	T1,.CPSCS##	;SAVE T1, GET DOORBELL BIT
	IORM	T1,DOORBL##	;DING!
	EXCH	T1,.CPSCS##	;RESTORE T1
	XJEN	@.CPCHL##	;DISMISS INTERRUPT

APRIN1:	CONSZ	APR,LP.NXM!LP.CDP!LP.ADP!LP.SBE!LP.PAR!LP.PWF!LP.IOF
				;TIMER TIMEOUT, MEM PARITY, POWER FAIL,
				; ADDRESS BREAK, IO PAGE FAIL?
	JRST	APRUNS		;YES, GO PROCESS UNUSUAL INTERRUPTS
	PJRST	APRDDT		;GO CHECK FOR EDDT ENTRY AND DISMISS INTERRUPT

;STILL UNDER FTKL10
;STILL UNDER FTKL10

;PROCESS UNUSUAL INTERRUPTS
APRUNS:	CONSZ	APR,LP.PWF	;POWER FAIL?
	JRST	APRPWF		;YES
	CONSZ	APR,LP.ADP!LP.CDP ;ADDRESS OR CACHE DIRECTORY PARITY?
	JRST	APRNHT		;YES
	CONSZ	APR,LP.NXM	;NON-EXISTANT MEMORY
	JRST	APRNXM		;YES
	CONSZ	APR,LP.PAR	;MB PARITY ERROR?
	JRST	APRDDT		;YES (IGNORE)
	CONSZ	APR,LP.IOF	;IO PAGE FAILURE?
	JRST	APRIOP		;YES
	CONSZ	APR,LP.SBE	;SBUS ERROR?
	JRST	APRSBE		;YES
	JRST	APREXT		;NO, EXIT INTERRUPT


;NXM INTERRUPT
APRNXM:	CONO	APR,LP.CSF!LP.PAR!LP.SBE  ;CLEAR ALL BUT INTERESTING STUFF
	SWPUA			;SWEEP CACHE (NXM LEAVES BAD PARITY IN CACHE)
	CONSZ	APR,LP.CSB	;CACHE SWEEP DONE?
	JRST	.-1		;WAIT FOR IT TO FINISH
	JRST	APRDDT		;PROCESS LIKE A NXM (IGNORE)

;STILL UNDER FTKL10
;STILL UNDER FTKL10

;I/O PAGE FAILURE
APRIOP:	DATAI	PAG,.CPIPG##	;SAVE AC SET INFO
	DATAO	PAG,[LG.LAB+0B8+7B11] ;EXEC AC SET 0, USER AC SET 7
	MOVEM	P,.CPSP##	;PRESERVE P
	PXCT	PX.MEM,[MOVE P,2] ;GET AC 2, BLOCK 7 (API FUNCTION WORD)
	MOVEM	P,.CPIOP##	;SAVE FOR ANALYSIS
	EXECAC			;EXEC AC SET 0, USER AC SET 1
	CONO	APR,LP.CSF!LP.IOF ;CLEAR I/O PAGE FAILURE
	MOVE	P,.CPAPP##	;SET TO PD LIST FOR THIS CPU
	PUSHJ	P,IOPSTP	;ANALYZE THE FAILURE, SKIP RETURN IF RECOVERABLE
	  STOPCD .,CPU,IOP,	;++I/O PAGE FAILURE
	MOVE	P,.CPSP##	;RESTORE P
	DATAO	PAG,.CPIPG##	;RESTORE AC SETS
	JRST	APREXT		;DISMISS INTERRUPT

;STILL IN IFN FTKL10
;STILL IN IFN FTKL10

;ROUTINE TO ANALYZE I/O PAGE FAILURE AND TAKE APPROPRIATE ACTION.
;IF THE FAILURE WAS CAUSED BY A NON-MASTER DTE20 THE DTE IS SIMPLY
;RELOADED.  ANY OTHER CAUSE LEADS TO A FATAL STOPCODE.  THE API
;FUNCTION WORD HAS BEEN STORED BY THE INTERRUPT HANDLER AT .CPIOP.
;CALL:
;	PUSHJ	P,IOPSTP
;	  <NON-SKIP>		;RETURN IF NON-RECOVERABLE ERROR (MASTER FE)
;	<SKIP>			;RETURN IF RECOVERABLE ERROR (OTHER FE)
;
;ON AN I/O PAGE FAILURE AC BLOCK 7, AC 2 HAS THE FOLLOWING CONTENTS:
;0:2	ADDRESS SPACE:
;		0 = EPT RELATIVE
;		1 = EXECUTIVE VIRTUAL
;		4 = PHYSICAL
;3:5	FUNCTION:
;		0 = STANDARD (40+2N)
;		1 = STANDARD (40+2N)
;		2 = VECTOR (XCT INSTRUCTION AT ADDRESS 13:35)
;		3 = INCREMENT/DECREMENT (INTERLOCKED) (Q -- DECREMENT)
;		4 = DATAO (Q -- PROTECTED)
;		5 = DATAI (Q -- PROTECTED)
;		6 = BYTE (Q -- TO -10)
;		7 = PHYSICAL INCREMENT (INTERLOCKED)
;6:	QUALIFIER (SEE ABOVE)
;7:10	DEVICE NUMBER ON EBUS:
;		 0 - 7	= INTERNAL CHANNEL 0 - 7
;		10 - 13	= DTE20 0 - 3
;		14 - 16	= EXTERNAL DEVICE
;		17	= DIA20
;13:35	ADDRESS

IOPSTP:	PUSHJ	P,SAVT##	;PRESERVE FROM AC CORRUPTION
	LDB	T1,[POINT 4,.CPIOP##,10] ;GET DEVICE NUMBER
	CAIL	T1,10		;IS THIS A DTE20?
	CAILE	T1,13		;...
	POPJ	P,		;NO, THEN THIS IS A FATAL IOP STOP
	PUSH	P,F		;GETETD STEPS ON F
	MOVEI	F,-10(T1)	;GET DTE NUMBER
	HRL	F,.CPCPN##	;MAKE CPU NUMBER,,DTE NUMBER
	PUSHJ	P,GETETD##	;GET DTE CONTROL BLOCK ADDRESS
	  PJRST	FPOPJ##		;ERROR?  UNLIKELY, BUT ASSUME MASTER FE
	MOVSI	T1,(ED.DTM)	;IS THIS THE MASTER FE?
	TDNE	T1,ETDSTS(F)	;IF SO, NOTHING WE CAN DO
	PJRST	FPOPJ##		; SO NON-SKIP RETURN AND DIE
	STOPCD	.,INFO,DTEIOP,DIEIOP, ;++DTE20 I/O PAGE FAILURE
	MOVEI	T1,.+1		;GET A PC
	PUSHJ	P,DTERLD##	;RELOAD THE DTE
	PJRST	FPOPJ1##	;RESTORE F AND RETURN

;HERE FROM ERRCON ON THE DTEIOP STOPCD
DIEIOP:	PUSHJ	P,INLMES##
	ASCIZ	.I/O page failure for .
	PJRST	DTEPDI##	;PRINT DTE INFORMATION AND RETURN

;STILL UNDER FTKL10
;STILL UNDER FTKL10

;SBUS ERROR
APRSBE:	SKIPN	[M.MOS##]	;MOS MEMORY SUPPORT?
	JRST	APRNHT		;NO, COLLECT ERROR INFO AND HALT
	CONO	APR,LP.CSF+LP.SBE ;CLEAR SBUS ERROR EARLY IN CASE
	MOVEM	P,.CPSP##	; SINGLE BIT ERROR IN ERROR ANALYSIS CODE
	MOVE	P,.CPAPP##	;SET TO PD LIST FOR THIS CPU
	PUSHJ	P,SBERR##	;DO ERROR ANALYSIS AND RECORD ERRORS FOR THGA
	MOVE	P,.CPSP##	;RESTORE P
	JRST	APREXT		;EXIT INTERRUPT


;HALT ON APR ERROR CONDITION--DO SBDIAG AND RDERA FIRST
APRNHT:	MOVEM	P,.CPSP##	;GET A VALID PDL
	MOVE	P,.CPAPP##	;SET TO PD LIST FOR THIS CPU
	RDERA	.CPAER##	;READ ERA INTO CPU DATA BLOCK
	CONI	APR,.CPAEF##	;SAVE CONI APR,
	SBDIAG	.CPSB0##	;GET SBDIAG FUNCTIONS 1+2
	SBDIAG	.CPSB1##	; ...
	SWPUA			;CACHE SWEEPS SO WE CAN SEE DATA
	CONSZ	APR,LP.CSB	;SWEEP FINISHED?
	JRST	.-1		;WAIT FOR IT TO COMPLETE
	CONSZ	APR,LP.SBE	;SBUS ERROR?
	STOPCD	.,CPU,SBE,	;++SBUS ERROR
	CONSZ	APR,LP.CDP	;CACHE DIRECTORY OR ADDRESS PARITY?
	STOPCD	.,CPU,CDE,	;++CACHE DIRECTORY PARITY ERROR
	STOPCD	.,CPU,APE,	;++ADDR. PARITY ERROR

;STILL UNDER FTKL10
;STILL UNDER FTKL10

PWFPIS==0			;CONI PI,
PWFPAG==1			;DATAI PAG,
PWFMTR==2			;CONI MTR,
PWFLEN==:3			;NUMBER OF WORDS SAVED

;POWER FAIL
APRPWF:	CONI	PI,.CPPFD##+PWFPIS ;SAVE STATE OF PI SYS
	CONO	PI,PI.OFF	;TURN OFF INTERRUPTS
	MOVEM	P,.CPSP##	;SAVE P
	MOVE	P,.CPEBR##	;GET CURRENT EBR
	ANDI	P,-1-<LG.CSL!LG.CSW> ;TURN OFF CACHE
	CONO	PAG,(P)		;...
	SWPUA			;SWEEP CACHE
	CONSZ	APR,LP.CSB	;WAIT FOR SWEEP BUSY TO CLEAR
	JRST	.-1
	DATAI	PAG,.CPPFD##+PWFPAG ;SAVE UBR, CURRENT & PREVIOUS AC BLOCKS
	CONI	MTR,.CPPFD##+PWFMTR ;SAVE METER
	MOVE	P,.CPSP##	;RESTORE P
	JSR	.CPSVA##	;SAVE ALL AC SETS
	MOVSI	P,(JRST)	;ALLOW -20F TO RESTART US
IFE FTMP,<HLLM	P,ARSLOC##>
IFN FTMP,<HLLM	P,.CPRES##>
	MOVE	P,.CPAPP##	;SET TO PD LIST FOR THIS CPU
	PUSHJ	P,DTEPWF##	;TELL F.E. WE HAVE A POWER FAILURE
	MOVEI	17,700000	;GET A SHORT COUNT
	SOJG	17,.		;MAKE SURE POWER HAS FAILED
	PJRST	APRRES##	;IT HASN'T

;POWER FAIL RESTART
APRPFR::SWPIA			;CLEAR OUT CACHE
	CONSZ	APR,LP.CSB	;WAIT FOR SWEEP BUSY TO CLEAR
	JRST	.-1
	CONO	PAG,@.CPEBR##	;TURN ON CACHE, TRAP ENABLE
	MOVEM	P3,@.CPSPT##	;RESTORE SPT
	MOVE	P,.CPPFD##+PWFPIS ;GET CONI PI, WORD
	ANDI	P,377		;JUST SYS ON, OFF AND CHANNELS ON, OFF
	CONO	PI,PI.TNP(P)	;TURN ON CHANNELS AND SYS, IF IT WAS ON BEFORE
	MOVE	P,.CPPFD##+PWFPAG ;GET UPT INFO
	TRO	P,LG.IAM	;INHIBIT UPDATING OF ACCOUNTING METERS
	DATAO	PAG,P		;RESTORE UBR FOR METERS
	MOVE	P,.CPPFD##+PWFMTR ;GET METER INFO
	CONO	MTR,MO.LAC(P)	;LOAD ACCOUNTING CONTROL, PI
	MOVSI	P,(HALT)	;PREVENT -20F FROM RESTARTING US
IFN FTMP,<HLLM	P,.CPRES##>
IFE FTMP,<HLLM	P,ARSLOC##>
	MOVE	P,.CPAPP##	;SET TO PD LIST FOR THIS CPU
	PUSHJ	P,DTEPFC##	;RE-ESTABLISH PRIMARY PROTOCOL
	JSP	T4,ZAPICH##	;PUT INTERNAL CHANNELS BACK TOGETHER
	PUSHJ	P,DSKRCL##	;CAUSE HOME BLOCKS TO BE REREAD
	RESTOR	(0,.CPCAC##)	;RESTORE AC'S
	RESTOR	(1,.CPCA1##)
	RESTOR	(2,.CPCA2##)
	RESTOR	(3,.CPCA3##)
	RESTOR	(4,.CPCA4##)
	CONO	TIM,TO.CTD!TO.CIT!TO.SIT!^D1667 ;SET FOR FIRST CLOCK TICK
	DATAO	PAG,.CPPFD##+PWFPAG ;RESTORE UBR/AC SETS
	CONO	APR,APRNUL##	;CLEAR POWER FAIL, ENABLE FOR GOOD STUFF
	PJRST	APREXT		;DISMISS INTERRUPT

> ;END IFN FTKL10
SUBTTL	APR INTERRUPT PROCESSING -- KS10


IFN FTKS10,<

;APR CHANNEL INTERRUPT
APRINT::SKIPE	CRSHWD		;OPR DEPOSIT 30 NON-ZERO?
	JRST	SYSCRH##	;YES, TAKE CRASH DUMP
	CONSZ	APR,SP.NXM!SP.HMP!SP.PWF ;NXM, HARD PARITY OR POWER FAIL?
	JRST	APRUNS		;YES

APRIN2:	DMOVEM	P,.CPSP##	;SAVE ACS P & P+1
	CONSO	APR,SP.ITI	;CLOCK TICK?
	PJRST	CLKDDR		;NO
	JSP	P+1,TIMINT	;PROCESS TIMER INTERRUPT
	DMOVE	P,.CPSP##	;RESTORE ACS
	PJRST	APRDDT		;CHECK FOR EDDT ENTRY AND DISMISS INTERRUPT


;PROCESS UNUSUAL INTERRUPTS
APRUNS:	CONSZ	APR,SP.PWF	;POWER FAIL?
	JRST	APRPWF		;YES
	CONSZ	APR,SP.NXM!SP.HMP ;NXM OR PARITY ERROR?
	JRST	APRIN2		;YES--GO PROCESS IT
	JRST	APREXT		;DISMISS INTERRUPT

;STILL UNDER FTKS10
;STILL UNDER FTKS10

PWFPIS==0			;CONI PI,
PWFPAG==1			;DATAI PAG,
PWFMTR==2			;CONI MTR,
PWFLEN==:3			;NUMBER OF WORDS SAVED

;POWER FAIL
APRPWF:	RDPI	.CPPFD##+PWFPIS	;SAVE STATE OF PI SYS
	WRPI	PI.OFF		;TURN OFF PI'S
	RDUBR	.CPPFD##+PWFPAG	;SAVE UDB, CURRENT & PREVIOUS AC BLOCKS
	RDTIME	.CPPFD##+PWFMTR	;SAVE TIME BASE
	JSR	.CPSVA##	;SAVE ALL AC SETS
	MOVE	P,[JRST APRRES##] ;POWER FAIL AUTO RESTART INTSTRUCTION
	MOVEM	P,ARSLOC##	;SET IT UP
	HALT	.		;STOP
				;FE RESTARTS US AT 70 WHICH EVENTUALLY
				; GETS US HERE

;POWER FAIL RESTART
APRPFR::WRUBR	.CPPFD##+PWFPAG	;RESTORE UBR AND AC BLOCKS IN USE
	SETZ	0,		;CLEAR CURRENT AC BLOCK FOR USE
	MOVEI	17,1		;...
	BLT	17,17		;...
	MOVE	P,.CPAPP##	;SET TO PD LIST FOR THIS CPU
	PUSHJ	P,UBAPIS##	;RESET UBA'S
	MOVE	T1,.CPPFD##+PWFPIS ;GET CONI PI, WORD
	ANDI	T1,377		;JUST SYS ON, OFF AND CHANNELS
	WRPI	PI.TNP(T1)	;RESTORE PI SYSTEM
	MOVEI	T1,<^D16>B23	;RESTART INTERVAL TIMER
	WRINT	T1		;SET IT
	MOVE	T1,[HALT ARSLOC##] ;HALT AT 70 INSTRUCTION
	MOVEM	T1,ARSLOC##	;DISABLE 70 RESTART
	MOVE	U,OPRLDB##	;OPR'S LDB
	MOVEI	T1,[ASCIZ /
%Power fail restart
/]
	PUSHJ	P,CONMES##	;ANNOUNCE RESTART
	PUSHJ	P,ENAKAL	;ENABLE KEEP ALIVE FUNCTION
	PUSHJ	P,DSKRCL##	;CAUSE HOME BLOCKS TO BE REREAD
	RESTOR	(0,.CPCAC##)	;RESTORE AC'S
	RESTOR	(1,.CPCA1##)
	RESTOR	(2,.CPCA2##)
	RESTOR	(3,.CPCA3##)
	RESTOR	(4,.CPCA4##)
	ZERO	(5)		;CLEAN OUT REST OF AC BLOCKS
	ZERO	(6)
	ZERO	(7)
	WRUBR	.CPPFD##+PWFPAG	;RESTORE UBR AND AC BLOCKS IN USE
	WRTIME	.CPPFD##+PWFMTR	;RESTORE TIME BASE
	WRAPR	APRNUL##	;CLEAR POWER FAIL, ENABLE FOR GOOD STUFF
	PJRST	APREXT		;DISMISS INTERRUPT

> ;END IFN FTKS10
SUBTTL	APR INTERRUPT PROCESSING -- COMMON INTERRUPT EXIT


;CHECK FOR EDDT ENTRY
APRDDT:	DMOVEM	P,.CPSP##	;SAVE AC P
IFN FTMP,<
	MOVE	P,.CPCPN##	;GET OUR CPU NUMBER
	CAMN	P,BOOTCP##	;ARE WE THE BOOT CPU?
> ;END IFN FTMP
APRCLK:	SKIPN	CLKDDT		;AND IS 21 NON-ZERO
	JRST	CLKDDR		;NO--PRECEED
	MOVE	P,.CPSP##	;RELOAD P
	SETZM	CLKDDT		;CLEAR FLAG
	XCT	SYSDDT##	;GO TO EDDT IF POSSIBLE
CLKDDR::MOVE	P,.CPAPP##	;SET TO PD LIST FOR THIS CPU
	PUSHJ	P,APRSUB##	;GO PROCESS INTERRUPT
	DMOVE	P,.CPSP##	;RESTORE P


;EXIT FROM INTERRUPT
APREXT:	CONO	APR,APRCHN##	;SET APR PI
	XJEN	@.CPCHL##	;DISMISS INTERRUPT
SUBTTL	TIMER INTERRUPT PROCESSING -- KL10

;ENTERED VIA XPCW FROM EPT WHEN TIMER INTERRUPTS

IFN FTKL10,<

TIMINT::SKIPE	CRSHWD		;OPR DEPOSIT 30 NON-ZERO?
	JRST	SYSCRH##	;YES, TAKE CRASH DUMP
IFN FTMP,<
	SKIPN	CPNDDT		;ANY CPU HIT A BREAKPOINT?
	JRST	TIMIN2		;NO, SKIP OVER THIS
	MOVEM	P,.CPSP##	;YES, SAVE FOR A BIT
	SKIPE	BPTMSK##	;ANY CPU ALLOWED TO ENTER EDDT?
	JRST	TIMIN1		;YES, CONTINUE
	MOVEI	P,.CPKFP##-1	;SET UP A PDL
	STOPCD	.,EVENT,CPNDDN,DIECPN, ;++CPNDDT NON-ZERO
	SETZM	CPNDDT		;PREVENT HEARTBURN AND DEAD SYSTEMS
	MOVE	P,.CPSP##	;RESTORE P
	JRST	TIMIN2		;CONTINUE ONWARD

TIMIN1:	MOVE	P,.CPCPN##	;GET OUR CPU NUMBER
	MOVE	P,BITTBL##(P)	;GET CORRESPONDING BIT
	TDNN	P,CPNDDT	;IS THIS JUST A FLUKE DURING $X?
	SKIPA	P,.CPSP##	;NO, RESTORE AC
	SKIPA	P,.CPSP##	;YES, RESTORE AC
	JRST	CPNBPT##	;OTHER CPU IN A BREAKPOINT, WAIT FOR IT

APRABK::!
> ;END IFN FTMP

TIMIN2:	DMOVEM	P,.CPSP##	;SAVE P
	DMOVE	P,@.CPTMI##	;GET INTERRUPTING PC
	DMOVEM	P,@.CPCHL##	;SAVE AT APR PI CHANNEL XPCW
	MOVSI	P,(ST.CYC)	;BIT TO TEST
	TDNN	P,STATES##	;50HZ?
	JRST	TIMIN3		;NO
	MOVEI	P,^D2000	;SET UP 20000 MICROSECONDS FOR 50HZ
	JRST	TIMIN4		;AND CONTINUE

TIMIN3:	MOVEI	P,^D1666	;60HZ, SO ASSUME LEAP JIFFY
	AOSG	.CPTCT##	;COUNT TRIAD COUNTER (-1,0,1)
	AOJA	P,TIMIN4	;NOT LEAP TICK UNLESS TRIAD COUNT IS 1
	SETCMM	.CPTCT##	;COUNT REACHED 1, SET BACK TO -2

TIMIN4:	CONO	TIM,TO.CTD!TO.SIT(P) ;SET INTERVAL OF TIMER AGAIN
	SETOM	.CPTIM##	;SOFTWARE CLOCK FLAG FOR KL'S
	PJRST	APRCLK		;CHECK FOR EDDT ENTRY AND DISMISS INTERRUPT

IFN FTMP,<
DIECPN:	PUSHJ	P,INLMES##	;PRINT SOME GARBAGE
	ASCIZ	/CPNDDT non-zero; contents /
	MOVE	T1,CPNDDT	;GET IT
	PJRST	HWDPNT##	;PRINT IN HALF-WORDS
>; END IFN FTMP

> ;END IFN FTKL10
SUBTTL	TIMER INTERRUPT PROCESSING -- KS10

;ENTERED VIA JSP P+1, FROM APRINT

IFN FTKS10,<

TIMINT:	MOVSI	P,(ST.CYC)	;BIT TO TEST
	TDNN	P,STATES##	;50HZ CLOCK SIMULATION?
	JRST	TIMIN1		;NO
	MOVEI	P,^D20		;SET UP 20 MILLISECONDS FOR 50HZ
	JRST	TIMIN2		;GO SET INTERVAL

TIMIN1:	MOVEI	P,^D16		;60HZ, SO ASSUME LEAP JIFFY
	AOSG	.CPTCT##	;COUNT TRIAD COUNTER (-1,0,1)
	AOSA	P		;NOT LEAP TICK UNLESS TRIAD COUNT IS 1
	SETCMM	.CPTCT##	;COUNT REACHED 1, SET BACK TO -2

TIMIN2:	ADDM	P,.CPLMC##	;ADD THIS INTERVAL TO LEAP MSEC COUNT
	SKIPL	.CPLMC##	;IS IT STILL NEGATIVE?
	ADDI	P,1		;NO--IT'S TIME FOR A LEAP MSEC
	LSH	P,^D12		;SHIFT TO LOAD INTO TIMER REGISTER
	WRINT	P		;SET INTERVAL OF TIMER AGAIN
	WRAPR	SP.CSF!SP.ITI	;CLEAR INTERVAL TIMER INTERRUPT FLAG
	SETOM	.CPTIM##	;SET SOFTWARE CLOCK TICK FLAG
	SKIPGE	P,.CPLMC##	;IS THIS A LEAP MSEC?
	JRST	(P+1)		;NO--RETURN
	ADD	P,[-^D1024]	;YES--COMPUTE NEXT LEAP MSEC COUNT
	MOVEM	P,.CPLMC##	;RESET IT
	JRST	(P+1)		;RETURN

> ;END IFN FTKS10
SUBTTL	KEEP-ALIVE TRAP HANDLER


APRKAF::MOVEM	P,.CPSVP##	;SAVE P
	MOVEI	P,.CPKFP##-1	;SET UP STACK
	STOPCD	.,CPU,KAF,	;++KEEP ALIVE FAILURE
	SUBTTL	CONTEXT SWITCHING

;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::
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
	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,SETRL3	;DON'T CHANGE ANYTHING IF THERE ISN'T ONE
IFN FTKL10,<HRLI T1,(LG.LUB+LG.LPC+LG.KPM)> ;SET THE LOAD BIT, PCS = 0
IFN FTKS10,<HRLI T1,(SG.LUB)>	;SET THE LOAD BIT
IFN FTRTTRP,<MOVEM T1,.CPHRP##>	;SAVE FOR RTTRP INTERRUPT LEVEL USE

	CONO	PI,PI.OFF	;MAKE CHANGING ADDRESSABILITY ATOMIC
	HRRM	T1,@.CPSPT##
IFN FTKL10,<
	SKIPN	T2		;LAST JOB STILL HAVE CORE?
	DATAO	PAG,NULDOP##	;DUMP THE METERS
>; END IFN FTKL10
	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
	MOVSI	T3,REDOMP	;FORCING THE MAP TO BE REDONE?
	AND	T3,JBTSGN##(J)	;GET STATE OF BIT
	ANDCAM	T3,JBTSGN##(J)	;CLEAR IT (WE'LL REDO SEGMENT IN A MINUTE)
	SKIPE	T3		;WAS IT ON?
	PUSHJ	P,MAPHGH##	;YES, REDO THE HIGH SEGMENT PART OF THE MAP
SETRLZ:	PUSHJ	P,FNDPDS##	;SET UP W
IFN FTKL10,<
	MOVE	T3,JBTPDB##+0	;NULL JOB PDB
	SKIPE	T2,.PDABS##(W)	;DOES THE USER HAVE ADDRESS BREAK SETTINGS?
	TLNN	T2,(OC.ABE)	;YES, IS HE ENABLED FOR BREAKS
	JRST	SETRL2
	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			;
SETRL2:	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
>; END IFN FTKL10
SETRL3:	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
IFN FTKL10,<TLO T1,(LG.LUB+LG.KPM)> ;REQUEST LOADING OF UBR
IFN FTKS10,<TLO T1,(SG.LUB)>	;REQUEST LOADING OF UBR
IFN FTKL10,<TRNE T1,LG.UPT>	;IS THERE A UPT?
IFN FTKS10,<TRNE T1,SG.UPT>	;IS THERE A UPT?
	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##
>
	SUBTTL	KL ACCOUNTING METERS

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	KS ONCE A SECOND CODE

IFN FTKS10,<
KSSEC::	PUSHJ	P,MEMCHK	;CHECK FOR MEMORY ERRORS

	PUSHJ	P,UBACHK	;CHECK THAT UNIBUS ADAPTERS HAVE THEIR PIAS

;COUNT THE KEEP ALIVE COUNTER FOR THE 8080 FRONT END

	LDB	T1,BKPALV	;GET THE CURRENT COUNT
	AOS	T1		;INCREMENT IT
;NOT NECESSARY TO MASK SINCE DPB WILL DO THAT FOR US
;	ANDI	T1,377		;WE COUNT IT MODULO 8 BITS
	DPB	T1,BKPALV	;PUT IT IN ITS PROPER PLACE
	POPJ	P,		;RETURN

BKPALV:	POINT	8,RLWORD,27	;BYTE POINTER TO KEEP ALIVE COUNT

UBACHK:	PUSHJ	P,SAVE1##	;FREE UP AN AC
	MOVEI	P1,1		;START WITH FIRST ADAPTER
UBACK1:	MOVS	T1,P1		;GET ADAPTER NUMBER,,0
	HRRI	T1,UNBSTW	;ADDRESS OF STATUS REGISTER
	PUSHJ	P,UBGOOD	;IS UBA ALIVE?
	  JRST	UBACK2		;NO--THEN DON'T TRY TO ACCESS IT
	RDIO	T3,(T1)		;YES--GET UBA STATUS
	ANDI	T3,UNBDTR!77	;MASK OFF EXTRA BITS
	MOVE	T2,UBAPIT##-1(P1) ;GET PI ASSIGNMENT FOR THIS ADAPTER
	IORI	T2,UNBDTR	;SET DISABLE XFER BIT FOR COMPARE/SET
	CAMN	T3,T2		;ARE ALL THE BITS RIGHT ?
	JRST	UBACK2		;ALL OK
	STOPCD	.+1,DEBUG,ULP,DIEULP ;++UBA LOST ITS PI ASSIGNMENT
	WRIO	T2,(T1)		;REASSIGN LEVELS
UBACK2:	CAIGE	P1,MAXUBA	;DONE ALL ADAPTERS?
	AOJA	P1,UBACK1	;NO, DO NEXT
	POPJ	P,

DIEULP:	PUSHJ	P,INLMES##
	ASCIZ	/UBA #/
	MOVE	T1,P1		;COPY THE NUMBER
	PJRST	RADX10##	;PRINT AND RETURN

MEMCHK:	PUSHJ	P,SAVE1##	;SAVE P1
	MOVEI	P1,MEMSTS	;GET ADDRESS OF MEMORY STATUS REGISTER
	RDIO	T2,(P1)		;READ IT
	TLNN	T2,(MR.HLD)	;HOLDING ERROR INFORMATION?
	POPJ	P,		;NO
	HLLZ	T1,T2		;GET A COPY
	TLZ	T1,^-<(MR.HLD!MR.ECC!MR.PWF)> ;TURN OFF ALL ERROR BITS
	WRIO	T1,(P1)		;CLEAR ERROR BITS
	MOVE	P1,T2		;COPY STATUS BITS
	TLNN	P1,(MR.BAD!MR.REF!MR.PAR!MR.PWF) ;"HARD" ERROR?
	JRST	MEMCK1		;NO
	AOS	.CPHME##	;INCREMENT COUNT OF HARD ERRORS
	MOVEM	P1,.CPHMS##	;SAVE LAST HARD ERROR STATUS
	STOPCD	MEMCK2,INFO,KSHME,DIEKSH, ;++KS HARD MEMORY ERROR

MEMCK1:	AOS	.CPSME##	;INCREMENT COUNT OF SOFT ERRORS
	MOVEM	P1,.CPSMS##	;SAVE LAST SOFT ERROR STATUS
MEMCK2:	TLNN	P1,(MR.BAD!MR.REF!MR.PAR!MR.PWF) ;"HARD" ERROR?
	TDZA	T2,T2		;NO, PUT ZERO IN U
	MOVEI	T2,1		;REMEMBER IT WAS A HARD ERROR
	MOVEM	T2,.CPMFL##	;SAVE FLAG TO INDICATE LAST ERROR TYPE
	SETZ	T1,		;LET XFR ROUTINE ALLOCATE
	XMOVEI	T2,KSMTBL	;POINT TO TRANSFER TABLE
	PUSHJ	P,XFRSEB##	;COPY DATA
	  JFCL			;NO CORE
	POPJ	P,		;RETURN

KSMTBL:	SEBTBL	(.ERKSM,KSMEND,<EX.QUE!EX.SYE>)
	MOVE	.CPSME##	;(R00) NUMBER OF SOFT MEMORY ERRORS
	MOVE	.CPSMS##	;(R01) MEM STATUS REG AT LAST SOFT ERROR
	MOVE	.CPHME##	;(R02) NUMBER OF HARD MEMORY ERRORS
	MOVE	.CPHMS##	;(R03) MEM STATUS REG AT LAST HARD ERROR
	MOVE	.CPSMC##	;(R04) NUMBER OF SOFT ERRORS IN LAST MINUTE
	MOVE	.CPMFL##	;(R05) LAST MEMORY ERROR FLAG (0=SOFT, 1=HARD)
KSMEND:!			;END OF TABLE

DIEKSH:	PUSHJ	P,INLMES##	;START THE NOISE
	ASCIZ	/Hard memory error/
	MOVEI	T1,[ASCIZ / (Bad Data)/]
	TLNE	P1,(MR.BAD)	;BIT SET?
	PUSHJ	P,CONMES##	;YES
	MOVEI	T1,[ASCIZ / (Refresh Error)/]
	TLNE	P1,(MR.REF)	;BIT SET?
	PUSHJ	P,CONMES##	;YES
	MOVEI	T1,[ASCIZ / (Parity Error)/]
	TLNE	P1,(MR.PAR)	;BIT SET?
	PUSHJ	P,CONMES##	;YES
	MOVEI	T1,[ASCIZ | (Power/Battery Backup Failure)|]
	TLNE	T1,(MR.PWF)	;BIT SET?
	PUSHJ	P,CONMES##	;YES
	POPJ	P,		;RETURN
>; END IFN FTKS10
	SUBTTL	KS ONCE PER MINUTE CODE

IFN FTKS10,<
KSMIN::	MOVE	T1,.CPSME##	;GET NUMBER OF SOFT ERRORS DURING LAST MINUTE
	CAMG	T1,.CPSMC##	;ANY HAPPEN DURING THE LAST MINUTE?
	POPJ	P,		;NO, NOTHING TO DO
	MOVSI	T1,(ST%NSE)	;GET THE BIT
	TDNN	T1,CNFST2##	;WANT TO SUPPRESS MESSAGES?
	STOPCD	.+1,EVENT,KSSME,DIEKSS, ;++KS SOFT MEMORY ERROR
	MOVE	T1,.CPSME##	;GET CURRENT COUNT
	MOVEM	T1,.CPSMC##	;SAVE FOR NEXT MINUTE
	POPJ	P,		;RETURN

DIEKSS:	MOVE	P1,.CPSME##	;GET CURRENT COUNT
	SUB	P1,.CPSMC##	;SUBTRACT PREVIOUS TO GET NUMBER LAST MINUTE
	MOVE	T1,P1		;COPY HERE FOR RADX10
	PUSHJ	P,RADX10##	;PRINT THE TOTAL
	PUSHJ	P,INLMES##	;START THE NOISE
	ASCIZ	/ ECC correctable memory error/
	MOVEI	T1,[ASCIZ /s/]	;MAYBE PLURAL
	CAIE	P1,1		;BUT NOT IF ONE
	PUSHJ	P,CONMES##	;LET'S BE GRAMMATICAL OUT THERE
	PUSHJ	P,INLMES##	;PRINT ADDRESS
	ASCIZ	/ last minute
Last ERA = /
	LDB	T1,[POINT 22,.CPSMS##,35] ;GET ERA
	PUSHJ	P,PRT22A##	;PRINT IT
	PUSHJ	P,INLMES##	;MORE NOISE
	ASCIZ	/, correction code = /
	LDB	T1,[POINT 7,.CPSMS##,11] ;GET CORRECTION CODE
	PJRST	PRTDI8##	;PRINT IT AND RETURN (ERRCON ADDS CRLF)

;HERE FROM COMCON TO DISABLE SOFT MEMORY ERROR MESSAGES
MEMSIL::MOVSI	T1,(ST%NSE)	;GET THE BIT
	IORM	T1,CNFST2##	;SET IT
	JRST	CPOPJ1##	;SKIP RETURN
>; END IFN FTKS10
	SUBTTL	DTESER SIMULATION

;ROUTINES TO TURN KEEP ALIVE FUNCTION ON AND OFF WITH 8080 FRONT END

IFN FTKS10,<
	$LOW
SVPPC::	PUSH	P,T1		;SAVE T1
	MOVSI	T1,(KPACT)	;KEEP ALIVE ACTIVE BIT
	TDNN	T1,RLWORD	;ARE WE GOING TO GET KAF'ED?
	JRST	DISKA1		;NO, JUST BE A LONG NO-OP
	ANDCAM	T1,RLWORD	;YES, CLEAR THE BIT
	MOVE	T1,(P)		;RESTORE T1
	ADJSP	P,-2		;BALANCE STACK
	PUSHJ	P,@1(P)		;CALL OUR CALLER
	  JRST	ENAKAL		;PROPAGATE NON-SKIP
	AOS	(P)		;AND SKIP
;FALL INTO ENAKAL

ENAKAL::PUSH	P,T1		;SAVE T1
	MOVSI	T1,(KPACT)	;KEEP ALIVE ACTIVE BIT
	IORM	T1,RLWORD	;SET IT
	PJRST	DISKA1		;RETURN

DISKAL::PUSH	P,T1		;SAVE T1
	MOVSI	T1,(KPACT)	;KEEP ALIVE ACTIVE BIT
	ANDCAM	T1,RLWORD	;CLEAR IT
DISKA1:	POP	P,T1		;CAN'T USE TPOPJ SINCE
	POPJ	P,		;  WE MAY NOT BE MAPPED
	$HIGH
;ROUTINE TO GET DATE AND TIME FROM THE FRONT END
;
;IN OUR CASE, THIS (MIGHT BE) A TCU150 ON THE UNIBUS

SPCGDT::MOVE	T1,[EXP CLKCSR]	;GET IO ADDRESS OF CSR
	PUSHJ	P,UBGOOD	;SEE IF INSTALLED
	  POPJ	P,		;NOT INSTALLED, CAN'T HELP
	MOVE	T1,[EXP CLKCSR]	;RESTORE IO ADDRESS
	RDIO	T2,0(T1)	;GET DATE
	RDIO	T3,2(T1)	;GET TIME
	HRL	T2,T3		;SAVE TIME,,DATE
	RDIO	T3,4(T1)	;GET SECOND
	LDB	T1,[POINT 7,T2,26] ;GET YEARS SINCE 1900
	ADDI	T1,^D1900	;MAKE INTO REAL YEAR
	CAIGE	T1,^D1964	;BASIC SANITY CHECK
	POPJ	P,		;CLOCK IS BAD
	MOVEM	T1,LOCYER##	;SAVE YEAR
	LDB	T1,[POINT 4,T2,30]	;GET MONTH
	SKIPE	T1		;SANE?
	CAILE	T1,^D12		;...
	POPJ	P,		;NO
	MOVEM	T1,LOCMON##	;YES, SAVE MONTH
	SOJ	T1,		;MAKE INTO TABLE OFFSET
	LDB	T4,PMONTB##	;GET DAYS IN MONTH - 1
	AOJ	T4,		;MAKE ONE-BASED
	SOJN	T1,SPGDT1	;IF FEBRUARY
	MOVE	T1,LOCYER##	;GET YEAR
	TRNN	T1,3		;AND IF LEAP YEAR
	AOJ	T4,		;ALLOW FOR EXTRA DAY
SPGDT1:	LDB	T1,[POINT 5,T2,35] ;GET DAY OF MONTY
	SKIPE	T1		;CHECK FOR SANITY
	CAMLE	T1,T4		;...
	POPJ	P,		;BAD CLOCK
	MOVEM	T1,LOCDAY##	;SAVE DAY OF MONTH
	LDB	T1,[POINT 5,T2,9] ;GET HOUR
	CAILE	T1,^D24		;SEE IF MAKES SENSE
	POPJ	P,		;SIGH
	CAIN	T1,^D24		;MIDNIGHT?
	SETZ	T1,		;YES, USE OUR CONVENTION
	MOVEM	T1,LOCHOR##	;SAVE HOUR
	LDB	T1,[POINT 6,T2,17] ;GET MINUTE
	CAILE	T1,^D59		;MAKE SURE IT'S NOT JUNK
	POPJ	P,		;PARANOIA 1, CLOCK 0
	MOVEM	T1,LOCMIN##	;SET MINUTE
	LDB	T1,[POINT 6,T3,35] ;GET SECOND
	CAILE	T1,^D59		;FINAL CHECK
	POPJ	P,		;FAILED
	MOVEM	T1,LOCSEC##	;SET SECOND AND VALID FLAG
	JRST	CPOPJ1##	;SUCCESS
>; END IFN FTKS10
	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:
IFN FTKL10,<PUSHJ P,ABKCHK>	;CHECK & POSSIBLY SET EXEC MODE ADDRESS BREAK
	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
IFN FTKL10,<
	SKIPGE	.CPABF##	;EXEC MODE ADDRESS BREAK ENABLED?
	SKIPN	.CPABW##	;AND AN ADDRESS SET?
	CAIA			;DO NORMAL USER STUFF
	JRST	SSEU3		;YES
	DATAI	APR,-1(P)	;SAVE ORIGINAL BREAK CONDITIONS
				; THIS DOES NOT STORE BREAK ADDR
	DATAO	APR,[0]		;NO ADDRESS BREAKS
SSEU3:
>; END IFN FTKL10
	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
IFN FTKL10,<TLO T1,(LG.KPM)>	;"KEEP ME"
	DATAO	PAG,T1		;RESTORE THE UBR
SSEU2:	CONO	PI,PI.ON	;SAFE TO ALLOW INTERRUPTS
IFN FTKL10,<
	MOVSI	T1,777740	;EVERYTHING BUT THE ADDRESS
	ANDM	T1,(P)		;JUST USER BREAK CONDITIONS
	ANDCA	T1,.CPAPR##	;USER BREAK ADDRESS
	IOR	T1,(P)		;BREAK CONDITIONS + BREAK ADDRESS
	SKIPGE	.CPABF##	;EXEC MODE ADDRESS BREAK ENABLED?
	SKIPN	.CPABW##	;AND AN ADDRESS SET?
	DATAO	APR,T1		;NO, RE-ENABLE USER ADDRESS BREAK
>; END IFN FTKL10
	POP	P,(P)		;CLEAR JUNK
	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

IFN FTXMON,<
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,MXSECN	;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,MXSECN	;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
>; END IFN FTXMON
;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
;	MOVE	F,DDB ADDRESS
;	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
;*** BE CAREFUL!  DXFIX AND RH2FIX *KNOW* THE LAYOUT OF THE STACK.

IFN FTKL10,<
MAPIO::	TLNN	T2,-1		;0 OR CHANNEL JUMPS ARE ILLEGAL
	STOPCD	CPOPJ##,DEBUG,IEZ, ;++IOWD EQUALS ZERO
	PUSH	P,U		;SAVE U
	HLLZ	U,CHNTYP(P3)	;GET CHANNEL-TYPE WORD
	TLNE	U,CP.RH2!CP.KLP!CP.KNI ;INTERNAL CHANNEL DEVICE?
	TROA	U,2		;YES
	LDB	U,[POINT 1,U,1]	;NO, GET DF10/DX10 FLAG (0 OR 1)
	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	MAPIOX		;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
	TRNE	U,2		;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	MAPIO9		;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,V2PADR	;T3 = CURRENT ABSOLUTE ADDRESS
	  SKIPGE USRHCU##	;IF A SAVE IS IN PROGRESS,
	SKIPA			; THEN, THIS IS OK
	XCT	AAO		;ACCESS ALLOWED OFF
	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,PG.BDY	;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,MAPIO6	;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
	CAML	T1,[EXP -37777+PAGSIZ] ;OTHERWISE SET T3=CURRENT PAGE
	ADD	T4,T3		;T4 = CURRENT PHYSICAL ADDRESS WITHIN SEGMENT
	PUSHJ	P,V2PADR	;T3 = NEXT PHYSICAL ADDRESS WITHIN PAGE
	  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
	CAME	T2,[-600000]	;DON'T GENERATE IOWD WHOSE LH
	CAMN	T2,[-030000]	; LOOKS LIKE AN RH20 CHANNEL JUMP
	JRST	MAPIO5
MAPIO4:	CAMN	T4,T3		;ARE THE TWO PAGES ADJACENT IN PHYSICAL MEMORY?
	JRST	MAPIO3		;YES, CONTINUE ON CURRENT IOWD
MAPIO5:	POP	P,(P1)		;STORE THE IOWD ABSOLUTE ADDRESS
	HRRZ	T4,U		;GET CHANNEL TYPE INDEX
	PUSHJ	P,@[EXP DFFIX,DXFIX,RH2FIX](T4) ;ADJUST THE IOWD AS APPROPRIATE
	  JRST	MAPIO8		;NO SPACE
	JUMPL	U,MAPIO7	;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	MAPIO8		;WHOOPS! NONE AVAILABLE
	JRST	MAPIO2		;MAP THE REST OF THE IOWD
MAPIO6:	POP	P,(P1)		;STORE THE IOWD ABSOLUTE ADDRESS
	ADDB	P4,T1		;ADD THE RESIDUAL WORD COUNT TO THE ACCUMULATED
				; WORD COUNT
	HRRZ	T4,U		;GET CHANNEL TYPE INDEX
	PUSHJ	P,@[EXP DFFIX,DXFIX,RH2FIX](T4) ;ADJUST THE IOWD AS APPROPRIATE
	  JRST	MAPIO8		;OUT OF SPACE
MAPIO7:	AOBJN	P1,.+1		;BUMP THE POINTER TO THE NEXT FREE WORD
	SETZM	(P1)		;ZERO IT SO THE LIST IS TERMINATED
	AOS	-7(P)		;SET FOR SKIP (WIN) RETURN
MAPIO8: 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
MAPIO9:	SKIPGE	-3(P)		;IF WE WANT IT STORED,
	TRNE	U,3		;DF10-STYLE CHANNEL?
	JRST	MAPIOX		;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)
MAPIOX:	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::	PUSHJ	P,SAVU##	;PRESERVE U
	PUSH	P,T1
	MOVEI	U,2		;TELL THE WORLD IT AN RH20
	MOVEI	T3,BLKSIZ##-1
	ANDB	T3,CHNTCW(P3)	;NO SWEAT IF AN EVEN MULTIPLE OF 200 WORDS
	JUMPE	T3,RH2ND1
	TLNE	S,IOSUPR##	;SUPER I/O?
	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)	;COMPUTE NO OF WORDS TO 0-FILL
	ADDI	T3,BLKSIZ##+<(INSVL.(.CCFTH,CC.OPC)_-4)> ;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,(CC.HLT)	;LIGHT LAST-BIT IN IOWD
	IORB	T3,-1(P1)
	LDB	T2,[POINT 11,T3,13] ;GET WORDCOUNT
	TDNE	T3,[CC.ADR]	;ADR = 0 IS SPECIAL
	ADD	T3,T2		;ADDR + N
	TLZ	T3,(CC.WDC)	;WDCNT SHOULD GO TO 0
RH2ND2:	MOVEM	T3,CHNTCW(P3)	;SAVE EXPECTED TERM WORD
	PJRST	TPOPJ##		;AND RETURN TO CALLER
;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
;	  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
	MOVE	T2,P3		;COPY VIRTUAL ADDRESS
	ADD	T2,T1		;SECTION NUMBER FOR I/O
	HLRZ	T1,T2		;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)	;GET DEVICE TYPE BITS
	SKIPL	DEVSPL(F)	;SPOOLED DDBS ARE ALWAYS A DSK
	TLNE	T3,DVDSK	;IF A DSK
	CAIA			;SPOOLED DDB OR DSK
	SKIPN	T3		;MONITOR I/O IF REREADING HOME BLOCKS
	SKIPL	S		;MONITOR I/O?
	SKIPA	T3,[PXCT PX.MEM,[MAP T3,(T2)]] ;USER ADDRESS
	MOVSI	T3,(MAP T3,(T2)) ;EXEC ADDRESS
	SE1ENT			;SAVE CALLER'S SECTION, ENTER SECTION 1
	XCT	T3		;MAP OR PXCT OF A MAP
	TLNN	T3,(MP.BAD)	;BAD FAIL OR
	TLNN	T3,(MP.BTS)	; INACCESSIBLE?
	POPJ	P,		;YES TO EITHER, WILL FAULT
	TLZ	T3,(MP.NAD)	;CLEAR NON-ADDRESS 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:	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 DF10C-STYLE CHANNELS

DFFIX:	DPB	T1,WDCPNT##(U)	;STORE WORD COUNT
	JRST	CPOPJ1##	;SKIP RETURN

;ROUTINE TO HANDLE RH20 CHANNELS
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+<(INSVL.(.CCFDT,CC.OPC)_-4)>;ONLY CAN DO 11 BITS IN ONE IOWD
	DPB	T3,WDCPNT##(U)	;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,[CC.ADR]	;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,<(INSVL.(.CCFDT,CC.OPC)_-4)> ;INDICATE THIS IS A DATA-IOWD
	DPB	T1,WDCPNT##(U)	;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	T3=ICWA
;RETURNS WITH T1=IORB, THE LIST REVERSED
;RETURNS T2=ORIGINAL LH OF IOWD WHICH GOT CHANGED,,ITS ADDRESS

REVCCW::JUMPE	T2,CPOPJ##	;WORDCOUNT OF 0 WILL CAUSE A CRASH
	PUSHJ	P,SAVE4##
	SETZ	P1,
	PUSH	P,T3
REVCC1:	SKIPN	P2,(T3)		;GET A CCW
	SOJA	T3,REVCC5	;ZERO INDICATES END OF LIST
	TLNE	P2,(CC.WDC)	;WORDCOUNT EQUAL 0?
	AOJA	P1,REVCC2	;NO, CAN'T BE JUMP
	HRRZ	T3,P2		;GET JUMP ADDRESS
	JRST	REVCC1		;KEEP LOOKING
REVCC2:	LDB	T4,CNTPP2	;GET WORD COUNT
	CAMLE	T4,T2		;MORE THAN WHAT IS LEFT?
	JRST	REVCC3		;YES
	SUB	T2,T4		;SUBTRACT THAT AMOUNT
	JUMPE	T2,REVCC4	;DONE IF WORDCOUNT GOES TO ZERO
	TLNE	P2,(CC.HLT)	;THIS CCW HAVE THE HALT BIT SET?
	JRST	REVCC5		;YES, END
	AOJA	T3,REVCC1	;KEEP LOOKING
REVCC3:	DPB	T2,CNTPP2	;STORE WORD COUNT
REVCC4:	TLO	P2,(CC.HLT)	;SET HALT BIT IN LAST CCW
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,(CC.HLT)	;HALT BIT SET?
	TLO	P2,(CC.HLT)	;YES, PROPAGATE IT
	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,(CC.WDC)	;WORDCOUNT EQUAL 0?
	HRR	T2,T4
	MOVEI	P3,-1(P1)
	HRRZ	T3,T2
REVCC7:	AOSA	T3
REVCC8:	HRR	T3,T4
	MOVE	T4,(T3)
	TLNN	T4,(CC.WDC)	;WORDCOUNT EQUAL 0?
	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	;GET WORDCOUNT
	TLCE	P2,(CC.REV)	;COMPLEMENT REVERSE BIT, IS IT SET?
	JRST	[SUBI P2,-1(T4)
		 POPJ P,]
	ADDI	P2,-1(T4)
	POPJ	P,

CNTPP2:	POINT	11, P2, 13	;EXTRACT WORD COUNT FROM P2
;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,2 IF RH20/INTERNAL CHANNEL
;		  1 IF DX10
;		  0 IF DF10C-STYLE CHANNEL
;	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,2		;RH20?
	HRLI	T1,(INSVL.(.CCJMP,CC.OPC)) ;YES, MAKE RIGHT STYLE JUMP-WORD
	TRNE	U,1		;IF DX10 CHANNEL,
	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 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
>; END IFN FTKL10
;ROUTINE TO SET UP UNIBUS ADAPTER MAPPING REGISTERS FOR A GIVEN
;IOWD FOLLOWING THE PAGING OF A JOB.  PRESERVES T1-T4, P3, P4.
;
;CALL	MOVE	T2,IOWD
;	MOVEI	P1,0		;FIRST CALL
;	MOVE	P3,LOC OF CHANNEL DATA BLOCK
;	MOVE	P4,FRAME-COUNT,,CHARS/WD IF TU45
;	PUSHJ	P,MAPIO
;RETURN	CPOPJ	IF IOWD EXCEEDS AVAILABLE PAGING REGISTERS
;	CPOPJ1	P2=ADDRESS OF FIRST PAGING REGISTER USED
;		P1=ADDRESS OF NEXT PAGING REGISTER TO BE USED

IFN FTKS10,<
MAPIO::	TLNN	T2,-1		;0 OR CHANNEL JUMPS ARE ILLEGAL
	STOPCD	CPOPJ##,DEBUG,IEZ, ;++IOWD EQUALS ZERO
	PUSHJ	P,SVEUB		;SAVE AND SETUP UBR
	PUSHJ	P,SAVT##	;SAVE T REGS
	PUSH	P,U		;SAVE U
	MOVE	P1,CHNIMR(P3)	;UBA #,,1ST ASSIGNED PAGING REGISTER
	HRRZI	T4,-UBAEXP(P1)	;OFFSET FROM BASE OF UBA PAGING REGISTERS
	LSH	T4,P2WLSH	;CONVERT TO PAGES
	MOVE	U,T2		;SAVE IOWD IN U
	AOS	T2		;ACCOUNT FOR FACT THAT IOWD'S ARE ADDR-1
	ANDI	T2,PG.BDY	;GET LOW 9 BITS OF STARTING ADDRESS
	ADD	T4,T2		;FORM STARTING "DOUBLE-WORD" -11 ADDRESS
	LSH	T4,2		;TURN INTO BYTE ADDRESS
	MOVEM	T4,CHNIEA(P3)	;AND SAVE IN CHANNEL DATA BLOCK
	MOVE	T4,CHNMRC(P3)	;GET MAPPING REGISTER COUNT
	MOVE	T2,U		;T2 AND U = IOWD
	HLROS	U		;U = -WORD COUNT
	MOVEI	T2,1(T2)	;STARTING ADDRESS
	PUSHJ	P,V2PADR	;SEE WHAT KIND OF REFERENCE THIS IS
	  JFCL			;ILLEGAL, WE'LL CATCH IT LATER
	TLZE	P1,(1B0)	;EXEC?
	CAIE	T2,1		;YES, "NO DATA XFER" TYPE IOWD? (INCREMENTED)
	JRST	MAPIO1		;NO, CONTINUE
	MOVEI	T2,CHNDBF(P3)	;YES, POINT TO ADDRESS OF DUMMY BUFFER
	SETOM	CHNNXF(P3)	;SET FLAG FOR DEVICE DRIVER TO SET ADDRESS INH
MAPIO1:	MOVE	T1,T2		;ANOTHER ADDRESS (THIS BECOMES A FLAG)
MAPIO2:	PUSHJ	P,V2PADR	;GET PHYSICAL ADDRESS IN T3
	  SKIPGE USRHCU##	;IF SAVE IN PROGRESS
	SKIPA			;THEN, WE LET ERROR PASS
	STOPCD	.,JOB,AAO,	;++ACCESS ALLOWED OFF (BUT THE IOWD ADDRESS CHECKED)
	TLZ	P1,(1B0)	;CLEAR EXEC ADDRESS FLAG
	LSH	T3,W2PLSH	;GET PAGE NUMBER FOR UBA MAPPING
	PUSHJ	P,SETUBB	;GO SET PROPER UBA BITS IN T3
	WRIO	T3,(P1)		;AND LOAD THE PAGING RAM
	JUMPE	T1,MAPIO3	;IF NOT FIRST PAGE, DO WHOLE PAGE
	ANDI	T1,PG.BDY	;EXTRACT THE WORD NUMBER
	SUBI	T1,PAGSIZ	;CALCULATE THE NUMBER OF WORDS DONE IN FIRST PAGE
	CAIA			;SKIP PASS 2 CODE
MAPIO3:	MOVNI	T1,PAGSIZ	;(- # DONE)
	SUB	U,T1		;-#LEFT = -#LEFT --#DONE
	JUMPGE	U,MAPIO4	;JUMP IF THE ORIGIONAL WORD COUNT IS EXHAUSTED
	MOVEI	T1,0		;START NEXT PAGE AT ADDRESS 0
	ADDI	P1,1		;POINT TO NEXT MAPPING REGISTER
	ADDI	T2,PAGSIZ	;STEP TO NEXT PAGE
	SOJG	T4,MAPIO2	;CONTINUE IF THERE IS ROOM
	SETZ	P1,		;INDICATE NONE
	STOPCD	UPOPJ##,JOB,OMR	;++OUT OF MAPPING REGISTERS

;HERE WITH ENTIRE IOWD MAPPED
;U/ NUMBER OF WORDS OF LAST PAGE MAPPED BUT NOT USED

MAPIO4:	HRRZ	P2,P1		;GET LAST USED REGISTER ADDRESS
	MOVNS	U		;NEGATE U (NOW - XTRA WDS MAPPED)
	ANDI	U,PG.BDY	;WORDS INTO LAST PAGE TO TRANSFER
	SKIPN	U		;JUST CROSSED PAGE BOUNDARY?
	AOS	P2		;YES, ACCOUNT FOR IT
	LSH	U,2		;MAKE INTO AN ELEVEN STYLE ADDRESS
	HRRZI	P2,-UBAEXP(P2)	;GET OFFSET INTO MAPPING REGISTERS
	IMULI	P2,UBAMUL	;MAKE INTO 11 STYLE ADDRESSING
	ADDB	P2,U		;FORM ADDRESS OF LAST WORD TO TRANSFER
	SUB	U,CHNIEA(P3)	;MINUS STARTING ADDRESS
	TLNE	P4,-1		;USER FRAME COUNT?
	HLRZ	U,P4		;YES, BELIEVE USER
	MOVEM	U,CHNBTC(P3)	; AND SAVE THE TOTAL BYTE COUNT
	SKIPGE	CHNNXF(P3)	;IS THIS A NO-XFER REQUEST?
	MOVE	P2,CHNIEA(P3)	;YES--THEN ENDING ADDRESS WILL EQUAL STARTING ADDR
	SKIPGE	P3		;WANT TERMINATION EXPECTED?
	MOVEM	P2,CHNTCW(P3)	;STORE FOR LATER CHECKING
	MOVE	P2,CHNIMR(P3)	;GET ADDRESS OF INITIAL MAPPING REGISTER
	PJRST	UPOPJ1##	;SKIP RETURN
;ROUTINE TO SET THE PROPER BITS FOR A UBA PAGING RAM ENTRY WHICH IS IN T3.
;THE BIT SETTINGS DEPEND ON WHAT KIND OF A DEVICE IS BEING RUN THROUGH MAPIO.

SETUBB:	PUSHJ	P,SAVE1##	;SAVE P1
	SKIPN	P1,DEVMOD(F)	;PICK UP DEVICE CLASSES
	MOVEI	P1,DVDSK	;MUST BE READING HOME BLOCKS
	TRO	T3,UNBVBT	;ALWAYS SET VALID
	SKIPE	CHNRRV(P3)	;ARE WE DOING A READ REVERSE OPERATION?
	TRO	T3,UNBRRV	;YES--SET READ REVERSE
	SKIPL	DEVSPL(F)	;SPOOLED DDB'S ARE ALWAYS DISKS
	TLNE	P1,DVDSK	; OR IF A "REAL" DISK DDB
	TRO	T3,UNB36B	; SET FAST XFER MODE
	SKIPGE	DEVSPL(F)	;IF A SPOOLED DDB (I.E. DISK)
	POPJ	P,		; WE'RE DONE
	TLNE	P1,DVLPT!DVCDR	;IF AN LP20 OR CD20
	TRO	T3,UNBD18	; SET 18 BITS DISABLE (16 BIT MODE)
	POPJ	P,		;RETURN
;ROUTINE TO TURN A VIRTUAL ADDRESS INTO A PHYSICAL ONE.
;WORRIES ABOUT WHAT SORT OF VIRTUAL ADDRESS IT MIGHT BE (EXEC, USER...)
;
;CALL:	T2/ADDRESS TO MAP
;	F/DDB THAT WANTS IO
;	PUSHJ	P,V2PADR
;	 HERE WHEN PAGE ISN'T ACCESSIBLE (USUALLY RESULTS IN AN AAO)
;	HERE WHEN MAPS OK, T3 IS PHYSICAL ADDRESS.
;
;ONLY T3 IS TRASHED

V2PADR:	MOVE	T3,DEVMOD(F)	;GET DEVMOD
	SKIPL	DEVSPL(F)	;SPOOLED DDBS ARE ALWAYS A DSK
	TLNE	T3,DVDSK!DVLPT!DVCDR	;IF A DSK (OR LP20 OR CD20)
	CAIA			;MONITOR IO IS POSSIBLE
	SKIPN	T3		;IF MIGHT BE READING HOME BLOCK
	SKIPL	S		; SKIP IF MONITOR IO
	SKIPA	T3,[PXCT PX.MEM,[MAP T3,(T2)]] ;NOT MONITOR SPACE, MAP AS USER
	TLOA	P1,(1B0)	;REMEMBER THIS IS EXEC
	TLZA	P1,(1B0)	;THIS IS NOT
	MOVSI	T3,(MAP T3,(T2));MONITOR IO, MAP AS EXEC ADDRESS
IFN FTXMON,<			;SHOULD A KS EVER DO EXTENDED SECTIONS
	HRL	T2,DEVISN(F)	;SECTION NUMBER FOR IO
	SE1ENT			;SAVE CALLER'S SECTION, ENTER SECTION 1
>
	XCT	T3		;MAP EXEC OR USER, RESULT IN T3
	TLNN	T3,(1B8)	;PAGED REFERENCE? (OUGHTA BE 1)
	JRST	V2PAD1		;NO, WILL NOT FAULT
	TLNN	T3,(MP.BAD)	;HARD PAGE FAILURE?
	TLNN	T3,(MP.BTS)	;...
	POPJ	P,		;YES TO EITHER, ACCESS DENIED
V2PAD1:	TLZ	T3,(MP.NAD)	;ACCESS IS OK, CLEAR NON-ADDRESS BITS
	JRST	CPOPJ1##	;RETURN SUCCESS
>; END IFN FTKS10
;HERE TO CHECK FOR EXISTENCE OF UBA DEVICES
; CALL	MOVE	T1,<ADR> OF DEVICE TO CHECK
;	PUSHJ	P,UBGOOD
;	LOSE RETURN
;	WIN RETURN

IFN FTKS10,<
UBGOOD::PUSHJ	P,SAVT##	;RESPECT T REGS
	PUSH	P,.USPFW	;SAVE PAGE FAIL LOCATIONS SINCE A TRAP
	PUSH	P,.USPFP	; COULD CLOBBER THEM AND THEY COULD
	PUSH	P,.USPFP+1	; BE IMPORTANT (TIMFLT FOR INSTANCE)
	PUSH	P,.CPPFT##	;SAVE PRE-EMPTIVE FAULT HANDLER
	SETZ	T2,		;BITS FOR TIOE
	XMOVEI	T3,UBNOGD	;TEMP PAGE FAIL TRAP ADDR
	RDPI	T4		;SAVE STATE OF PI'S
	WRPI	PI.OFF		;DISABLE INTERRUPTS
	MOVEM	T3,.CPPFT##	;SET TEMPORARY PAGE FAIL TRAP ADR
	TIOE	T2,(T1)		;CHECK FOR DEVICE
	SKIPA			;FAILED
	AOS	-4(P)		;WIN, CAUSE SKIP RETURN
	MOVEI	T2,UNBNED!UNBTMO ;CLEAR NED IN UNIBUS ADAPTER
	HRRI	T1,UNBSTW	;GET BASIC ADDRESS OF UNIBUS
	BSIO	T2,(T1)		;CLEAR FLAGS
	TRNE	T4,PI.ON	;WERE PI'S ON?
	WRPI	PI.ON		;YES--THEN ENABLE THEM
	POP	P,.CPPFT##	;RESTORE PRE-EMPTIVE FAULT HANDLER
	POP	P,.USPFP+1	;RESTORE PAGE FAIL LOCATIONS
	POP	P,.USPFP	; ..
	POP	P,.USPFW	; ..
	POPJ	P,		;RETURN

;HERE WHEN ADDRESS IS BUM
UBNOGD:	AOS	.USPFP+1	;SKIP LOSING INSTRUCTION
	JRST	@.USPFP+1	;JUST RETURN (NONSKIP)
>; END IFN FTKS10
;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::
IFN FTKL10,<
	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
>; END IFN FTKL10
IFN FTKS10,<
	WREBR	@.CPEBR##	;CAUSE CACHE FLUSH
	AOS	.CPCSN##	;COUNT THE SWEEP
	POPJ	P,		;RETURN
>; END IFN FTKS10

IFN FTKL10&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,PG.BDY	;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,
>; END IFN FTKL10&FTMP
	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

APRMPS::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) ;GET MAP BITS, START WITH PAGE 0
	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,MPSLP3	;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
IFN FTKL10,<
	MOVEI	T1,@.CPEBR##	;GET EBR
	TRZ	T1,LG.CSL+LG.CSW ;TURN OFF LOOK AND LOAD
	CONO	PAG,(T1)	;DISABLE THE CACHE
>; END IFN FTKL10
	SETOM	.CPPSP##	;SET SWEEPING FLAG
APRMPI:	MOVE	P2,(P1)		;TEST NEXT LOCATION
MPSLP2:	SOJLE	T2,MPSLP1	;IF CURRENT PAGE DONE, MAP NEXT
	AOJA	P1,APRMPI	;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
MPSLP3:	SETZM	.CPPSP##	;CLEAR SWEEPING FLAG
IFN FTKL10,<CONO PAG,@.CPEBR##>	;TURN CACHE BACK ON
	PUSHJ	P,UNMAP##	;RESTORE EXEC MAP SLOT
	POPJ	P,		;AND RETURN
	SUBTTL	BACKGROUND KL10 PERFORMANCE ANALYSIS

IFN FTKL10,<
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	.EPPAC(T4)	;CLEAR HIGH ORDER PERF ANAL COUNT
	SETZM	.EPPAC+1(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,M.CPU##-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,M.CPU##
	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	.EPPAC(T1)	;CLEAR HI PERF COUNT
	SETZM	.EPPAC+1(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
>; END IFN FTKL10
	SUBTTL	SET KL 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.

IFN FTKL10,<
SETCSH::MOVE	T1,.CPSPF##	;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 CPU NUMBER 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
>; END IFN FTKL10
	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.

	@
IFN FTKL10,<

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

GFLTD:	IFIW	.DGFX		;DGFIX
	IFIW	.GFX		;GFIX
	IFIW	.DGFXR		;DGFIXR
	IFIW	.GFXR		;GFIXR
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
>; END IFN FTKL10
SUBTTL	EXEC MODE ADDRESS BREAK CONTROL


IFN FTKL10,<
;ADDRESS BREAK CONDITIONS
	AB.REP==:1B0		;REPETITIVE ENABLE
	AB.FET==:1B9		;FETCH
	AB.RED==:1B10		;READ
	AB.WRT==:1B11		;WRITE
	AB.USR==:1B12		;USER ADDRESS
	AB.ADR==:37,,777777	;ADDRESS MASK

ABKCHK::SKIPN	.CPABW##	;WANT TO SET ADDRESS BREAK ON THIS CPU?
	POPJ	P,		;NO
	SKIPLE	.CPABF##	;NEED TO INIT ADDRESS BREAK?
	PUSHJ	P,ABKINI	;YES--DO IT NOW
	PUSH	P,T1		;SAVE ALL ACS
	HLRZ	T1,.CPABF##	;GET STOPCODE TYPE
	DPB	T1,[.CPABS##+S$PTRT] ;UPDATE INCASE PATCH CHANGED IT
	MOVE	T1,.CPABW##	;GET ADDRESS BREAK WORD
	TLZ	T1,(AB.REP)	;CLEAR FAKE BIT
	DATAO	APR,T1		;ENABLE EXEC MODE ADDRESS BREAK
	JRST	TPOPJ##		;RESTORE & RETURN

	STOPCD	.,EVENT,ABK,ABKDIE ;++ ADDRESS BREAK

ABKDIE:	MOVEI	T1,[ASCIZ /Exec mode address break at PC /]
	PUSHJ	P,CONMES##	;PRINT TEXT
	DMOVE	T1,.USPFP	;GET PC DOUBLE-WORD
	PUSHJ	P,UDPCP##	;PRINT PC
	MOVEI	T1,[ASCIZ /, Conditions = /]
	PUSHJ	P,CONMES##	;PRINT TEXT
	LDB	T1,[POINT 3,.CPABW##,11] ;GET CONDITIONS
	MOVE	T1,ABKTBL-1(T1)	;AND ASSOCIATED TEXT
	PJRST	CONMES##	;PRINT TEXT AND RETURN

ABKTBL:	[ASCIZ	/Write/]
	[ASCIZ	/Read/]
	[ASCIZ	/Read + Write/]
	[ASCIZ	/Fetch/]
	[ASCIZ	/Fetch + Write/]
	[ASCIZ	/Fetch + Read/]
	[ASCIZ	/Fetch + Read + Write/]
;INITIAL ADDRESS BREAK ON OTHER CPUS
ABKINI:	
IFN FTMP,<
	SYSPIF			;INTERLOCK AGAINST RACES
	SKIPG	.CPABF##	;NEED TO SETUP OTHER CPUS?
	JRST	ONPOPJ##	;NO--RELEASE INTERLOCK AND RETURN
> ;END IFN FTMP
	PUSHJ	P,SAVT##	;SAVE SOME ACS
	HLRZ	T1,.CPABF##	;GET STOPCODE TYPE
	CAIE	T1,S$HALT	;NEVER GENERATE HALT STOPCODES
	CAILE	T1,S$MAXT	;RANGE CHECK
	MOVEI	T1,S$EVENT	;DEFAULT IT
	HRLM	T1,.CPABF##	;UPDATE
	SKIPN	T1,.CPABI##	;GET INSTRUCTION TO XCT
	MOVSI	T1,(CAIA)	;THE FOOL FORGOT TO GIVE ONE
	MOVEM	T1,.CPABI##	;UPDATE
	HRLZ	T1,S..ABK	;GET STOPCODE BLOCK ADDRESS
	HRRI	T1,.CPABS##	;WHERE TO PUT IT
	BLT	T1,.CPABS##+S$MAXL-1 ;COPY STOPCODE BLOCK
	HLRZ	T1,.CPABF##	;GET STOPCODE TYPE
	DPB	T1,[.CPABS##+S$PTRT] ;SET IT
	MOVSI	T1,(AB.USR)	;USER ADDRESS BIT
	ANDCAM	T1,.CPABW##	;NEVER TURN THIS ONE ON
	MOVSI	T1,400000	;GET A BIT
	IORM	T1,.CPABF##	;INDICATE STUFF ALL CHECKED OUT
IFN FTMP,<
	MOVE	T2,.CPCPN##	;GET OUR CPU NUMBER
	IMULI	T2,.CPLEN##	;LENGTH OF A CDB (MAKE OFFSET)
	HRROI	T1,ABKSCP	;SUBROUTINE TO DO THE DIRTY WORK
	PUSHJ	P,CPUAPP##	;SET UP OTHER CPUS
	SYSPIN			;RELEASE INTERLOCK
> ;END IFN FTMP
	POPJ	P,		;RETURN


;CLEAR ADDRESS BREAK ON OTHER CPUS
ABKCLM:	SKIPA	T2,.CPBIT##	;GET OUR CPU BIT
ABKCLR:	MOVEI	T2,-1		;ALL CPU MASK
	SYSPIF			;INTERLOCK AGAINST RACES
	HRRM	T2,.CPABF##	;STUFF MASK IN FLAG WORD
	MOVEI	T1,ABKCCP	;SUBROUTINE TO DO THE DIRTY WORK
	PUSHJ	P,CPUAPP##	;SET UP OTHER CPUS
	SYSPIN			;RELEASE INTERLOCK
	POPJ	P,		;RETURN
ABKCCP:	TDNN	T2,.CPBIT##-.CPCDB##(P1) ;WANT TO CLEAR ON THIS CPU?
	POPJ	P,		;NO
	SETZM	.CPABF##-.CPCDB##(P1) ;ZAP FLAGS
	SETZM	.CPABW##-.CPCDB##(P1) ;AND BREAK WORD
	SETZM	.CPABI##-.CPCDB##(P1) ;AND INSTRUCTION TO XCT
	POPJ	P,		;RETURN

IFN FTMP,<
ABKSCP:	MOVE	T3,.C0ABF##(T2)	;GET CPU MASK
	TDNN	T3,.CPBIT##-.CPCDB##(P1) ;WANT TO SET ON THIS CPU?
	POPJ	P,		;NO
	MOVEM	T3,.CPABF##-.CPCDB##(P1) ;SAVE FLAGS
	MOVSI	T3,.C0ABS##(T2) ;STOPCODE CODE
	HRRI	T3,.CPABS##-.CPCDB##(P1) ;DESTINATION
	BLT	T3,.CPABS##-.CPCDB##+S$MAXL-1(P1) ;COPY
	MOVE	T3,.C0ABI##(T2)	;GET BREAKPOINT INSTRUCTION
	MOVEM	T3,.CPABI##-.CPCDB##(P1) ;SET MINE
	MOVE	T3,.C0ABW##(T2)	;GET ADDRESS BREAK WORD
	MOVEM	T3,.CPABW##-.CPCDB##(P1) ;SET WORD FOR CPUN
	POPJ	P,		;RETURN

> ;END IFN FTMP
> ;END IFN FTKL10
	SUBTTL	THE END

APRLIT:	$LIT
APREND:	END