Google
 

Trailing-Edge - PDP-10 Archives - tops10_704_monitoranf_bb-x140c-sb - 10,7/mon/datman.mac
There are 9 other files named datman.mac in the archive. Click here to see a list.
TITLE DATMAN - DATA BASE MANAGER  V177
SUBTTL D BLACK/DAL/JBS  21-JUNE-88
	SEARCH	F,S
	$RELOC
	$CSUB			;ENTIRE MODULE IN COMMON PSECT


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


XP VDATMN,177

	ENTRY	DATMAN

DATMAN::		;CAUSE DATMAN TO LOAD IF IN LIBRARY FILE

XP LISTSN,1		;CAUSE S.MAC AND F.MAC TO BE LISTED HERE
			; (USED TO BE IN COMMON WHICH IS NOW TOO BIG).


REPEAT 0,<
The DATA BASE MANAGER contains both subroutines to manipulate
monitor's data base and formats of various components of the data base.
The DATA BASE MANAGER should be the only module which modifies the data base;
all other modules should call DATMAN.
This scheme has a number of advantages:

1. It provides a good chance for comments.
2. It provides good conventions for future growth.
3. It provides good locality.
4. It helps reentrancy by having only one module maintain impure code.

DATMAN will also control writing in users' core too.
PROCESS and SEGMENT are important components in the data base
being introduced at this time.
A SEGMENT is one logical collection of data, either program data
or code, and is the building block of a program. Segments are really
the same as previously.
A PROCESS is a virtual machine;
it has a hardware state associated with it: a virtual memory, a processor,
typically one PC, a stack, etc. A process's virtual memory will
contain a number of segments. Several processes may run either
serially or in parallel as one overall program or user.
Monitor data will be organized on a per segment and a per process basis.
Part of per segment and part of per process data must be resident,
other parts could be swappable; the data breaks up
into four components. The following abbreviations and definitions will be used:

PRB	Process Resident Block - the resident process information.
	This will be very small, about 8 or 12 words.

PDB	Process Data Block - the not necessarily resident (swappable) process data.
	This will be most of the process data and may grow to fill a page or more.

SRB	Segment Resident Block - the resident segment information.
	This will be very small, about 8 or 12 words.

SDB	Segment Data Block - the not necessarily resident segment data.
	This may grow to fill a page or more.
Conventions about symbols:

symbols will consist of a three letter prefix and a three letter suffix.
The prefix will determine to what type of data base component the entry belongs,
and the particular usage of the entry.
For example, a word entry in the PDB would be .PDxxx.
The suffix is a three letter mnemonic describing the entry. Thus
the PDB entry SIZ containing the size of the PDB
would be .PDSIZ.
DATMAN is organized in the following manner:

First are the definitions of the various data base components.
These will be in alphabetical order so they can be found easily.

Second are subroutines for manipulating the data base,
grouped by function. Code should go down the page,
as in 5 series monitor conventions, until concern for locality
becomes more important.
>	;END REPEAT 0
	SUBTTL	PDB LOGIC


;SUBROUTINE TO FIND A PDB OR HALT
;CALL WITH:
;	MOVE	J,PROCESS-NUMBER
;	PUSHJ	P,FNPDBS
;	RETURN HERE WITH W POINTING TO A PDB
;
FNDPDS::JUMPL	J,NPJSTP
	HRRZ	W,JBTPDB##(J)	;GET PDB
	CAIG	J,JOBMAX##	;LEGAL JOB #
	JUMPN	W,CPOPJ##	;RETURN IF PDB EXISTS
NPJSTP::STOPCD	.,STOP,NPJ,	;++NO PDB FOR JOB


;SUBROUTINE TO FIND PDB FOR PROCESS IN T1
;	PUSHJ 	P,FPDBT1
;	  HERE IF NO PDB
;	HERE WITH T1 POINTING TO PDB
;RETURNS WITH T1 UNCHANGED IF NO PDB

FPDBT1::PUSH	P,J		;SAVE J AND W
	PUSH	P,W		; ..
	HRRZ	J,T1		;COPY PDB HANDLE
	PUSHJ	P,FNDPDB	;FIND THE PDB
	  SOSA	-2(P)		;CAUSE NON-SKIP RETURN
	MOVE	T1,W		;COPY CORE ADDRESS
	POP	P,W		;RESTORE AC'S
	JRST	JPOPJ1##	;RETURN
;SUBROUTINE TO FIND A PDB
;CALL WITH:
;	MOVE	J,PROCESS-NUMBER
;	PUSHJ	P,FNDPDB
;	  RETURN HERE IF NO PDB (W = 0)
;	RETURN HERE WITH W POINTING TO PDB

FNDPDB::PUSH	P,T1		;SAVE T1
	PUSHJ	P,LGJPR1	;SEE IF A LEGAL PROCESS (INCLUDING ZERO)
	  JRST	TPOPJ##		;NOT, LOSE
	HRRZ	W,JBTPDB##(J)	;GET PDB ADDRESS
	JUMPN	W,TPOPJ1##	;IF W IS NON-ZERO GIVE THE SKIP RETURN
	JRST	TPOPJ##		; ELSE FAIL
SUBTTL	CX RESOURCE ROUTINES

;ROUTINES TO MANIPULATE THE CX RESOURCE FOR A JOB.  THE CX RESOURCE IS USED
;TO INTERLOCK PDB OR CONTEXT BLOCK REFERENCES.

;UPCX TO GET THE CX RESOURCE FOR THE JOB IN T1 (.CPJOB CONTAINS OUR JOB)
;UPCX WILL BLOCK IF THE REQUESTED CX RESOURCE ISN'T AVAILABLE

UPCX::	PUSH	P,T2		;SAVE EVERYTHING
	PUSH	P,J		;SAVE J
	MOVE	J,.CPJOB##
	SKIPN	T2,T1		;WHO WE WANT
	SOS	T2		;IF JOB 0, SAY -1
	HRLM	T2,JBTCX##(J)	;FLAG WHO WE WANT/OWN
	JUMPE	T1,UPCXR	;NO REAL INTERLOCKING FOR JOB 0
	SYSPIF			;GUARD RACES
	HRRZ	T2,JBTCX(T1)	;GET THE OWNER OF HIS CX RESOURCE
	JUMPN	T2,CXWAIT	;WAIT IF IT ISN'T AVAILABLE
	HRRM	J,JBTCX##(T1)	;WE OWN HIS CX
	SYSPIN
UPCXR:	POP	P,J
	JRST	T2POPJ##	;RETURN

CXWAIT:	SYSPIN
	MOVEI	T2,CXQ##	;THE QUEUE
	DPB	T2,PJBSTS##	;SAY IN CX WAIT
	POP	P,J		;RESTORE J
	POP	P,T2		;RESTORE T2
	PJRST	WSCHED##	;WAIT FOR RESOURCE

;HERE TO TRY AND GET CX RESOURCE AT INTERRUPT LEVEL.  RETURN CPOPJ1
;IF WE HAVE IT, CPOPJ OTHERWISE.  CALLER'S RESPONSIBILITY TO WAIT

GETCX::	PUSH	P,T1		;SAVE T1
	SYSPIF
	HRRZ	T1,JBTCX##(J)	;GET OWNER OF CX RESOURCE WE DESIRE
	JUMPN	T1,GETCXR	;OWNED BY SOMEONE ELSE
	MOVEM	J,.CPCXJ##	;SAVE WE OWN IT
	SKIPN	J		;JOB 0?
	SOSA	.CPCXJ		;YES, FLAG OWN NUL JOB
	HLLOS	JBTCX##(J)	;SAY A CPU OWNS IT
	AOS	-1(P)		;GIVE GOOD RETURN
GETCXR:	SYSPIN
	JRST	TPOPJ##

;COROUTINE TO GET AND GIVE THE CX RESOURCE (UUO LEVEL)

GGVCX::	PUSHJ	P,UPCX		;GET CX RESOURCE
	POP	P,(P)
	PUSHJ	P,@1(P)		;CALL BACK
	  CAIA
	AOS	(P)
;	PJRST	DWNCX		;(FALL INTO DWNCX)

;HERE TO RELEASE THE CX RESOURCE WE (THE JOB IN J) OWNS
;CALL GIVCX FOR INTERRUPT LEVEL (OWNED BY CPU), OR
;DWNCX *FOR UUO LEVEL ONLY* (OWNED BY JOB IN .CPJOB)

DWNCX::	PUSH	P,J		;SAVE J
	PUSH	P,F		;SAVE F
	MOVE	J,.CPJOB##	;GET JOB WHO IS RUNNING
	SYSPIF			;INTERLOCK
	HLRE	F,JBTCX##(J)	;GET WHO WE OWN
	HRRZS	JBTCX##(J)	;WE NO LONGER OWN HIM
DWNCX1:	SKIPL	F		;IF OWNED NUL JOB
	HLLZS	JBTCX##(F)	;HE IS NO LONGER OWNED
	SYSPIN
	JUMPL	F,DWNCXR	;RETURN IF NUL
	SETZ	F,		;**NO EVM**
	PUSHJ	P,[PUSH	P,T1	;SAVE T1
		   PUSH P,J	;AND J
		   PJRST SRFRCX##]
DWNCXR:	POP	P,F
	POP	P,J
	POPJ	P,

GIVCX::	PUSH	P,J		;SAVE J
	PUSH	P,F		;SAVE F
	SETZB	F,J		;GET & CLEAR
	SYSPIF
	EXCH	F,.CPCXJ##	;GET JOB
	JRST	DWNCX1

;HERE TO UNWIND CX RESOURCE AT SCHEDULAR LEVEL
;CALL WITH JOB WHOSE CX WE WANT IN J, RETURN WITH OWNER (IF ANY) IN T3

UNWCX::	HLRE	T3,JBTCX##(J)	;WHO WE WANT
	SKIPLE	T3		;HUH?
	HRRE	T3,JBTCX##(T3)	;OWNER
	POPJ	P,

;HERE TO GRANT CX TO A JOB AT SCHEDULAR LEVEL

SCDCX::	HLRE	T3,JBTCX##(J)	;GET THE CX WE WANT
	JUMPLE	T3,CPOPJ1##	;HUH?
	SYSPIF			;GUARD RACES
	HRL	T3,JBTCX##(T3)	;MAKE SURE IT'S STILL FREE
	TLNE	T3,-1		;SOMEONE SNEAK IN?
	JRST	ONPOPJ##	;YES, LOSE
	HRRM	J,JBTCX##(T3)	;WE OWN HIS
	AOS	(P)
	JRST	ONPOPJ##	;WIN

;SUBROUTINE FOR CLOCK1 TO CALL TO SEE IF JOB IN J OWNS ANY CX RESOURCES
;SKIP RETURN IF OWN SOME CX, NON-SKIP OTHERWISE

OWNCX::	PUSH	P,T1		;SAVE T1
	HLRZ	T1,JBTCX##(J)	;OWN ANYTHING?
	JUMPN	T1,TPOPJ1##
	JRST	TPOPJ##

;ROUTINE TO SEE IF WE OWN THE CX.  NON-SKIP IF WE DON'T, SKIP
;IF WE DO.  CX DESIRED IN T1

CXOWN::	CAMN	T1,.CPCXJ##	;OWNED BY CPU?
	JRST	CPOPJ1##	;YES
	PUSH	P,T2
	HRRZ	T2,JBTCX##(T1)	;SEE WHO OWNS HIS CX
	CAMN	T2,.CPJOB##	;US?
	AOS	-1(P)		;YES
	JRST	T2POPJ##
	SUBTTL	ROUTINES TO REFERENCE USER CORE

;GETTAC  --  RE-LOAD AC T1 FROM USER'S AC ON A CALLI OR
;THE LIKE, IN CASES WHERE T1 HAS BEEN DESTROYED.
;CALL:
;
;	MOVE J,JOB NUMBER
;	PUSHJ P,GETTAC
;	RETURN
;
;ON RETURN THE USER'S AC IS IN T1. USES M, PRESERVES ALL OTHER ACS.
;CALL GETSAC FOR THE SAME RESULTS, EXCEPT GETWSU IS CALLED INSTEAD OF GETWDU

GETTAC::LDB	T1,PUUOAC##	;GET USER'S AC NUMBER
	HRR	M,T1		;PROVIDE AS ADDRESS TO READ
	PJRST	GETWDU		;GO READ THE AC

GETSAC::LDB	T1,PUUOAC##	;GET USER'S AC NUMBER
	HRR	M,T1
	PJRST	GETWSU



;GETWDU  --  READ 1 WORD FROM USER VIRTUAL ADDRESS SPACE
;GETWD1  --  READ NEXT WORD FROM USER VIRTUAL ADDRESS SPACE
;CALL IS:
;
;	MOVEI	M,<ADR>
;	PUSHJ	P,GETWDU
;	RETURN
;
;WHERE <ADR> IS USER VIRTUAL ADDRESS TO BE READ.
;
;DISPATCHES TO PAGE FAULT HANDLER ON A USER PAGE FAULT, OR PRINTS ILL
;ADR IN UUO IF NO SUCH ADDRESS.
;
;ON SUCCESSFUL RETURN THE USER WORD IS IN T1 AND, IF CALL WAS TO
;GETWD1 M IS UPDATED TO NEW USER VIRTUAL ADDRESS <ADR>+1. J IS SET
;TO THE USER'S JOB NUMBER. ALL OTHER ACS PRESERVED.

GETWD1::HRRI	M,1(M)		;INCREMENT M BEFORE PICKING UP WORD
GTWST2::
GETWDU::MOVE	J,.CPJOB##	;MAKE SURE J CORRECT
	PUSHJ	P,GETWRD	;GET THE WORD AND CHECK IF LEGAL
	  JRST	@[MCSEC0+UADERR##] ;ADDRESS NOT ACCESSIBLE, PRINT ERROR
	POPJ	P,		;OK RETURN, T1=WORD
;GETWSU -- READ 1 WORD FROM USER VIRTUAL ADDRESS SPACE
;GETWS1 -- READ NEXT WORD FROM USER VIRTUAL ADDRESS SPACE
;SAME CALL AND RETURN AS GETWRD/GETWR1, BUT STOPCODES IF
;THE ADDRESS IS NOT AVAILABLE, AND DOES NOT LOAD J FROM .CPJOB

GETWS1::HRRI	M,1(M)
GETWSU::PUSHJ	P,GETWRD
	  CAIA			;SEE IF MUST STOP
	POPJ	P,
	PUSHJ	P,INTLVL##	;AT INTERRUPT LEVEL?
	  JRST	@[MCSEC0+UADERR##] ;NO, ADDRESS CHECK
	STOPCD	.,STOP,GNA	;++GETWRD NOT AVAILABLE
;GETXWD  --  READ 1 WORD FROM ANYWHERE IN EXTENDED USER VIRTUAL ADDRESS SPACE
;PUTXWD  --  WRITE 1 WORD TO ANYWHERE IN EXTENDED USER VIRTUAL ADDRESS SPACE
;CALL IS:
;
;	XMOVEI	M,<ADR>	-OR-	MOVE	M,[IFIW <ADR>]
;	PUSHJ	P,GETXWD/PUTXWD
;	  ERROR
;	NORMAL
;
;USED FOR ONE-SHOT READ/WRITE TO RANDOM LOCATIONS IN THE USER'S ADDRESS SPACE
;OTHERWISE LIKE GETEWD/PUTEWD

IFN FTXMON,<

GETXWD::JUMPL	M,GETWRD	;DO IT THE OLD WAY FOR IFIW FORMAT
	TDNN	M,[^-<(IFIW!<1,,0>)>,,^-17] ;AN AC REFERENCE?
	JRST	GETWRA		;YES, GO HANDLE AC REFERENCE
	PUSHJ	P,SGPXWD	;SETUP FOR PXCT OF XBLT
	XBLTUX	P1,		;READ THE WORD FROM THE USER
	  ERJMP	GETWRY		;ATTEMPT ERROR RECOVERY
	JRST	CPOPJ1##	;SUCCEED

PUTXWD::JUMPL	M,PUTWRD	;IFIW CAN BE DONE MORE EASILY
	TDNN	M,[^-<(IFIW!<1,,0>)>,,^-17] ;AN AC REFERENCE?
	JRST	PUTWRD		;YES, HANDLE THAT THE OLD WAY
	PUSHJ	P,SGPXWD	;SETUP FOR PXCT OF XBLT
	EXCH	P2,P3		;GOING THE OTHER WAY
	XBLTXU	P1,		;WRITE THE WORD FOR THE USER
	  ERJMP	PUTWRZ		;ATTEMPT ERROR RECOVERY
	JRST	CPOPJ1##	;SUCCEED

SGPXWD:	ADJSP	P,2		;MAKE SOME STORAGE ROOM
	DMOVEM	P2,-1(P)	;SAVE THESE ACS
	EXCH	P1,-2(P)	;SAVE P1 & GET RETURN PC
	MOVEM	P1,1(P)		;USUAL CO-RETURN STORAGE PLACE
	MOVEI	P1,1		;GOING TO XBLT 1 WORD
	MOVE	P2,M		;GLOBAL ADDRESS FROM M
	XMOVEI	P3,T1		;INTO T1
	PUSHJ	P,@1(P)		;CALL THE CALLER
	  CAIA			;ERROR
	AOS	-3(P)		;OR SKIP
	MOVE	P1,-2(P)	;RECOVER AN AC
	DMOVE	P2,-1(P)	;AND THE REST
	ADJSP	P,-3		;BALANCE THE STACK
	POPJ	P,		;PROPAGATE RETURN
> ;END OF IFN FTXMON
;GETWRD  --  READ 1 WORD FROM USER VIRTUAL ADDRESS SPACE
;GETWR1  --  READ NEXT WORD FROM USER VIRTUAL ADDRESS SPACE
;CALL IS:
;
;	MOVX	J,<JOB>
;	MOVX	M,<ADR>
;	PUSHJ	P,GETWRD
;	  ERROR
;	NORMAL
;
;WHERE <JOB> IS USER JOB NUMBER AND <ADR> IS USER VIRTUAL ADDRESS.
;CAN BE CALLED AT CLOCK OR UUO LEVEL.
;
;DISPATCHES TO PAGE FAULT HANDLER ON A USER PAGE FAULT, OTHERWISE
;RETURNS CPOPJ0 IF USER ADDRESS IS INACCESSIBLE.
;
;SUCCESSFUL RETURN IS CPOPJ1 WITH USER WORD IN T1 AND, IF CALL WAS
;TO GETWR1, WITH M INCREMENTED TO NEW USER VIRTUAL ADDRESS <ADR>+1.
;ALL OTHER ACS ARE PRESERVED.

IFN FTXMON,<
GETEW1::JUMPL	M,GETWR1	;SKIP OVERHEAD FOR IFIW FORMS
	AOS	T1,M		;INCREMENT GLOBAL ADDRESS
	TRNE	T1,-1		;DID IT CROSS A SECTION BOUNDARY?
	JRST	GETEWD		;NO, DON'T BOTHER WITH THIS
	PUSHJ	P,SXPCS		;YES, BUMP PCS TO KEEP IT CONSISTENT
	  POPJ	P,		;PROPAGATE FAILURES
GETEWD::JUMPL	M,GETWRD	;SKIP OVERHEAD FOR IFIW FORMS
	TDNN	M,[^-<(IFIW!<1,,0>)>,,^-17] ;AN AC REFERENCE?
	JRST	GETWRA		;YES, GO HANDLE AC REFERENCE
	SE1ENT			;MUST BE IN SECTION 1 FOR EACALC TO WORK
	UMOVE	T1,@M		;NOT AN AC, FETCH FROM USER SPACE
	  ERJMP	GETWRY		;HANDLE ERRORS
	JRST	CPOPJ1##	;RETURN GOODNESS

GETMWD::LDB	T1,[POINT 5,M,17] ;WHAT WE WANT PCS TO BE
	PUSHJ	P,SVPCS##	;SAVE AND SETUP PCS
	PJRST	GETWRD		;GET THE WORD
> ;END OF IFN FTXMON

IFE FTXMON,<
GETEW1::!
>
GETWR1::HRRI	M,1(M)		;INCREMENT M BEFORE PICKING UP WORD
IFE FTXMON,<
GETXWD::!
GETEWD::!
GETMWD::!
> ;END OF IFE FTXMON
GETWRD::TRNN	M,777760	;REFERENCE TO A USER AC?
	JRST	GETWRA		;YES, HANDLE DIFFERENTLY
GETWRU:	MOVE	T1,M
IFN FTXMON,<
	TLZ	T1,-1-MXSECN
	TRNN	T1,777760	;AC REFERENCE?
	TLZ	T1,MXSECN	;YES, CLEAR POSSIBLE SECTION NUMBER
>
	UMOVE	T1,(T1)
	  ERJMP	GETWRY		;IF FAILED CHECK FOR PAGE FAULT ETC.
	JRST	CPOPJ1##	;TAKE SKIP RETURN

GETWRA::MOVE	T1,J		;JOB NUMBER OR JCH
	ANDI	T1,JOBMSK##	;JUST JOB NUMBER
	MOVE	T1,JBTSTS##(T1)	;JOB STATUS FOR THIS JOB
	TRNN	T1,JS.ASA	;REAL OR FAKE ACS?
	JRST	GETWRU		;REAL, HANDLE NORMALLY AFTER ALL
	HRRZ	T1,M		;CLEAR LEFT HALF JUNK
	MOVE	T1,.JDAT(T1)	;FAKE, READ FROM SHADOW ACS AREA
	JRST	CPOPJ1##	;SUCCESSFUL RETURN

GETWRY:	MOVE	R,.CPADR##	;SET UP RELOCATION FOR VMSER
	PUSHJ	P,FLTSY##	;CHECK FOR PAGE FAULT
	  POPJ	P,		;BAD ADDRESS-ERROR RETURN
	POPJ	P,		;IT'S STILL BAD, FLTSY NOTWITHSTANDING

;STOTAC  --  STORE WORD INTO USER AC
;STOTC1  --  STORE WORD INTO USER AC AND SKIP RETURN
;CALL IS:
;
;	MOVX	T1,<WRD>
;	PUSHJ	P,STOTAC
;	RETURN (STOTAC)
;	RETURN (STOTC1)
;
;WHERE <WRD> IS THE WORD TO BE WRITTEN INTO THE USER AC.
;
;PRESERVES ALL ACS.

STOTC1::AOSA	(P)		;SKIP RETURN
RTM2::	MOVNI	T1,2		;RETURN -2 TO USER
STOTAC::PUSH	P,M		;SAVE M
	MOVS	M,.USMUO	;GET MUUO OPCODE,AC IN LH
	LDB	M,PUUOAC##	;GET USER'S AC
	PUSHJ	P,PUTWDU	;STORE T1 IN USER'S AC
	JRST	MPOPJ##		;RESTORE M AND RETURN
;PUTWDU  --  WRITE 1 WORD INTO USER VIRTUAL ADDRESS SPACE
;PUTWD1  --  WRITE NEXT WORD INTO USER VIRTUAL ADDRESS SPACE
;CALL IS:
;
;	MOVX	M,<ADR>
;	MOVX	T1,<WRD>
;	PUSHJ	P,PUTWDU
;	RETURN
;
;WHERE <WRD> IS THE WORD TO BE WRITTEN INTO USER VIRTUAL ADDRESS <ADR>
;
;DISPATCHES TO PAGE FAULT HANDLER ON A USER PAGE FAULT, OR PRINTS ILL
;ADR IN UUO IF NO SUCH ADDRESS.
;
;ON SUCCESSFUL RETURN THE USER WORD IS IN T1 AND, IF CALL WAS TO
;PUTWD1 M IS UPDATED TO NEW USER VIRTUAL ADDRESS <ADR>+1.
;PRESERVES ALL OTHER ACS.

IFN FTXMON,<
PUTEW1::JUMPL	M,PUTWR1	;DO OLD WAY IF IFIW FORM
	AOS	M		;INCREMENT GLOBAL ADDRESS
	TRNE	M,-1		;CROSSING A SECTION BOUNDARY?
	JRST	PUTEWD		;NO, SKIP THIS
	PUSHJ	P,SMPCS		;BUMP PCS FOR THIS FETCH
	  POPJ	P,		;PROPAGATE FAILURES
PUTEWD::JUMPL	M,PUTWRD	;DO OLD WAY IF IFIW FORM
	TDNN	M,[^-<(IFIW!<1,,0>)>,,^-17] ;AN AC REFERENCE?
	JRST	PUTWRD		;YES, DO IT THE OLD WAY
	SE1ENT			;MUST BE IN SECTION 1 FOR EACALC TO WORK
	UMOVEM	T1,@M		;NOT AN AC, STORE TO USER SPACE
	  ERJMP	PUTWRZ		;HANDLE ERRORS
	JRST	CPOPJ1##	;RETURN GOODNESS

PUTMWD::PUSHJ	P,SSPCS##	;PRESERVE PCS
	PUSH	P,T1		;SAVE WORD TO STORE
	LDB	T1,[POINT 5,M,17] ;WHAT WE WANT PCS TO BE
	PUSHJ	P,STPCS##	;SAVE AND SETUP PCS
	POP	P,T1		;RESTORE DATA WORD
	PJRST	PUTWRD		;STORE THE WORD
> ;END OF IFN FTXMON

PUTWD1::HRRI	M,1(M)		;INCREMENT M BEFORE STORING WORD
PUTWDU::PUSH	P,J		;SAVE J
	MOVE	J,.CPJOB##	;SET UP J FOR THIS CPU'S JOB
	PUSHJ	P,PUTWRD	;STORE THE WORD
	  JRST	@[MCSEC0+UADERR##] ;A LOSER
	JRST	JPOPJ##		;A WINNER, RESTORE J AND RETURN
;PUTWSU -- WRITE 1 WORD INTO USER VIRTUAL ADDR SPACE
;PUTWS1 -- WRITE NEXT WORD
;CALL AND RETURN SAME AS PUTWDU/PUTWD1, BUT STOPCODES IF THE WORD ISN'T
;ADDRESSABLE AND DOES NOT LOAD J FROM .CPJOB

PUTWS1::HRRI	M,1(M)
PUTWSU::PUSHJ	P,PUTWRD
	  CAIA			;SEE IF MUST STOP
	POPJ	P,
	PUSHJ	P,INTLVL##	;AT INTERRUPT LEVEL?
	  JRST	@[MCSEC0+UADERR##] ;NO, ADDRESS CHECK
	STOPCD	.,STOP,PNA	;++PUTWRD NOT AVAILABLE
;PUTWRD  --  WRITE 1 WORD INTO USER VIRTUAL ADDRESS SPACE
;PUTWR1  --  WRITE NEXT WORD INTO USER VIRTUAL ADDRESS SPACE
;CALL IS:
;
;	MOVX	J,<JOB>
;	MOVX	M,<ADR>
;	MOVX	T1,<WRD>
;	PUSHJ	P,GETWRD
;	  ERROR
;	NORMAL
;
;WHERE <JOB> IS USER JOB NUMBER; <ADR> IS USER VIRTUAL ADDRESS;
;AND <WRD> IS THE WORD TO BE WRITTEN INTO THE USER ADDRESS <ADR>.
;CAN BE CALLED AT CLOCK OR UUO LEVEL.
;
;DISPATCHES TO PAGE FAULT HANDLER ON A USER PAGE FAULT, OTHERWISE
;RETURNS CPOPJ0 IF USER ADDRESS IS UNWRITEABLE.
;
;SUCCESSFUL RETURN IS CPOPJ1 WITH USER WORD IN T1 AND, IF CALL WAS
;TO PUTWR1, WITH M INCREMENTED TO NEW USER VIRTUAL ADDRESS <ADR>+1.
;ALL OTHER ACS PRESERVED.

IFE FTXMON,<
PUTEW1::!
>
PUTWR1::HRRI	M,1(M)		;INCREMENT BEFORE STORING WORD

IFE FTXMON,<
PUTEWD::!
PUTMWD::!
>
PUTWRD::PUSH	P,T1		;NEED A SCRATCH AC MOMENTARILY
	TRNN	M,777760	;REFERENCE TO USER AC?
	JRST	PUTWRA		;YES, HANDLE DIFFERENTLY
	HRRZ	T1,M		;GET USER VIRTUAL ADDRESS
	CAIG	T1,JOBPFI##	;IN PROTECTED JOB DATA AREA?
	JRST	TPOPJ##		;YES, TAKE FAILURE RETURN
PUTWRU:	POP	P,T1		;RESTORE VALUE TO BE DEPOSITED
IFN FTXMON,<
	PUSH	P,M
	TLZ	M,-1-MXSECN
	TRNN	M,777760	;AN AC REFERENCE?
	TLZ	M,MXSECN	;YES, CLEAR POSSIBLE SECTION NUMBER
>
	UMOVEM	T1,(M)		;STORE WORD IN USER ADDRESS SPACE
	  ERJMP	PUTWRY		;CHECK ON FAILURE
IFN FTXMON,<
	POP	P,M
>
	JRST	CPOPJ1##	;TAKE SUCCESSFUL RETURN

PUTWRA:	MOVE	T1,J		;JOB NUMBER OR JCH
	ANDI	T1,JOBMSK##	;JUST JOB NUMBER
	MOVE	T1,JBTSTS##(T1)	;JOB STATUS FOR THIS JOB
	TRNN	T1,JS.ASA	;REAL OR FAKE ACS?
	JRST	PUTWRU		;REAL, TREAT NORMALLY AFTER ALL
	POP	P,T1		;FAKE ACS, RESTORE T1
	PUSH	P,M
	TLZ	M,-1-MXSECN	;CLEAR POSSIBLE JUNK
	MOVEM	T1,.JDAT(M)	;AND WRITE INTO SHADOW ACS
	POP	P,M
	JRST	CPOPJ1##	;ALWAYS SUCCEEDS

PUTWRY:
IFN FTXMON,<
	POP	P,M		;RESTORE ORIGINAL CONTENTS
>
PUTWRZ:	PUSH	P,.USPFW	;SAVE PAGE FAIL WORD
	PUSHJ	P,FLTSY##	;CHECK FOR PAGE FAULT
	  JRST	[POP	P,(P)	;FIX STACK
		 POPJ	P,   ]	;BAD ADDRESS
	EXCH	T1,(P)		;SAVE T1, GET ADDRESS
	PUSH	P,T2		;SAVE T2
	PUSH	P,S		;PROTECT AGAINST
	PUSH	P,P2		;  HGHDEP
	MOVE	S,-3(P)		;HGHDEP WANTS WORD IN S
	MOVE	T2,T1		;AND ADDRESS IN T2
	PUSH	P,M		;MORE AC PROTECTION
	SNCALL	(HGHDEP##,MCSEC0) ;TRY STUFFING INTO HIGH SEGMENT
	  SOS	-5(P)		;NOPE
	POP	P,M		;RESTORE M
	POP	P,P2		;RESTORE
	POP	P,S		; ACS
	POP	P,T2		;  FROM
	JRST	TPOPJ1##	;   HGHDEP

;WARNING:  ANY CHANGES MADE TO TSTREL SHOULD ALSO BE REFLECTED IN GETWRD & PUTWRD

TSTREL::MOVEI	T1,JS.ASA	;WHAT DOES REFERENCE TO USER 0-17 REALLY MEAN BIT
	TRNN	M,777760	;IS THIS REFERENCE TO USER 0-17?
	TDNN	T1,JBTSTS##(J)	;YES, IS IT TO USER'S ACS OR THE SHADOW ACS?
	AOS	(P)		;USER'S ACS
	POPJ	P,		;GIVE SHADOW ACS OR USER AC SET RETURN
	SUBTTL	USER ARGUMENT SECTION ROUTINE

;ROUTINE TO SETUP FOR FETCHING USER ARGUMENTS FROM ARBITRARY SECTIONS
;RESPECTS BOTH 30-BIT ADDRESS (REALLY ONLY 23-BIT) AND IFIW FORMS,
;BUT WITH NEITHER INDEXING NOR INDIRECTION.
;CALLING SEQUENCE:
;	MOVE	T1,[USER ADDRESS ARGUMENT, EITHER 30-BIT OR IFIW]
;	PUSHJ	P,SXPCS
;	  RETURN NON-SKIP ON ANY SORT OF ADDRESSING ERROR
;	SKIP RETURN WITH PCS SETUP APPROPRIATELY IF EVERYTHING IS OK
;RESPECTS ALL ACS

SMPCS::	EXCH	T1,M			;SAME CALL, WITH ADDRESS IN M
	PUSHJ	P,SXPCS			;DO THE DIRTY WORK
	  CAIA				;NON-SKIP
	AOS	(P)			;OR SKIP
	EXCH	T1,M			;RESTORE ACS
	POPJ	P,			;PROPAGATE RETURN

SXPCS::	SKIPGE	T1			;IF AN IFIW,
	TLNN	T1,^-<(IFIW)>		;CHECK IF
	TLNE	T1,^-<(IFIW!<MXSECN,,0>)> ;ANY ATTEMPT AT INDEXING OR INDIRECTION?
	POPJ	P,			;YES, RETURN FAILURE
IFN FTXMON,<
	JUMPL	T1,CPOPJ1##		;IF IFIW, PCS IS ALREADY CORRECT
	PUSH	P,T1			;SAVE T1 FOR CALLER
	HLRZS	T1			;ISOLATE SECTION NUMBER IN RH
	PUSHJ	P,STPCS##		;SETUP PCS AS DESIRED
	JRST	TPOPJ1##		;RETURN AS ADVERTISED
>
IFE FTXMON,<JRST CPOPJ1##>		;RETURN GOODNESS IF NO XMON
;SUBROUTINE TO CHECK IF SEGMENT # IN J IS A LEGAL SEG #
;ARGS	J=SEG#
;SKIP RETURN IF LEGAL SEGMENT #, NON-SKIP IF NOT

LGJSEG::HRRZ	T1,J
LGLSEG::CAILE	T1,JOBMAX##	;SKIP IF BELOW 1ST LEGAL SEG #
	CAIL	T1,JBTMAX##	;NO, SKIP IF LEGAL SEG #
	POPJ	P,
	JRST	CPOPJ1##

LGJPRC::SKIPA	T1,J		;FROM J, EXCLUDE ZERO
LGJPR1::SKIPA	T1,J		;FROM J, ALLOW ZERO
LGLPRC::JUMPLE	T1,CPOPJ##	;JUMP IF LE 0
LGLPR1::CAIG 	T1,JOBMAX##
	JUMPGE	T1,CPOPJ1##	;0 WAS ALREADY CHECKED
	POPJ	P,		;-N ALWAYS ILLEGAL
;SUBROUTINE TO CREATE A PDB
;ARG	J=JOB NUMBER

	$HIGH

CREPDB::HRRZ	W,JBTPDB##(J)	;SEE IF ALREADY ONE THERE
	JUMPE	W,CREPD1	;NONE
	PUSHJ	P,SAVE4##	;SAVE COMCON FROM CTXSER'S DESTRUCTIVENESS
	PUSHJ	P,CTXKIL##	;KILL OFF CONTEXT BLOCKS
	JRST	CREPD2		;ZERO OUT THE PDB
CREPD1:	MOVEI	T2,.PDLEN##	;NUMBER OF WORDS NEEDED FOR A PDB
	PUSHJ	P,GETWDS##	;GET CORE FOR PDB
	  POPJ	P,		;CAN'T GET THRU
	HRRZ	W,T1		;COPY ADDRESS TO STANDARD AC
	HRRM	W,JBTPDB##(J)	;SAVE PDB ADDRESS
CREPD2:	SETZM	(W)		;CLEAR ALL PDB
	MOVSI	T1,(W)		;MAKE BLT PTR
	HRRI	T1,1(W)
	BLT	T1,.PDLEN##-1(W)
	MOVE	T1,STNPRT##	;INITIALIZE DEAFULT
	MOVEM	T1,.PDDFL##(W)	;TO STANDARD FILE PROTECTION
	MOVSI	T1,(PD.LGN)	;GET THE LOGIN BIT
	IORM	T1,.PDDFL##(W)	;SET IT IN THE WORD
	PUSHJ	P,CTXBLK##	;CREATE AN INITIAL CONTEXT BLOCK
	  JRST	KILPDB		;NOT ENOUGH CORE
	PUSHJ	P,ENQJBI##	;INIT QUEUE LIST HEADER
	JRST	CPOPJ1##	;RETURN

;SUBROUTINE TO DEALLOCATE A PDB
;ARGS	J=JOB NUMBER

KILPDB::JUMPE	J,CPOPJ##	;NEVER DELETE THE NULL JOB'S PDB
IFN FTMP,<
	PUSHJ	P,INTLVL##	;INTERRUPT LEVEL?
	  JRST	[EXCH	T1,J	;UPCX WANTS ARG IN T1
		 PUSHJ	P,UPCX	;NO, WAIT UUO LEVEL STYLE
		 EXCH	T1,J
		 JRST	KILPD1	]
	PUSHJ	P,GETCX
	  JRST	.-1		;INTERRUPT LEVEL STYLE
KILPD1:
> ;END IFN FTMP
	HRRZ	W,JBTPDB##(J)	;GET PDB ADDRESS
	JUMPE	W,KILPD2	;MUST HAVE ONE TO DELETE IT
	PUSHJ	P,CTXKIL##	;GO CLEAN UP OLD CONTEXT BLOCKS
	MOVEI	T1,.PDLEN##	;NUMBER OF WORDS FOR A PDB
	HRRZ	T2,JBTPDB##(J)	;ADDR OF PDB
	PUSHJ	P,GIVWDS##	;DEALLOCATE PDB
KILPD2:	HLLZS	W,JBTPDB##(J)	;CLEAR ADDR OF PDB
IFN FTMP,<
	PUSHJ	P,INTLVL##	;INTERRUPT LEVEL?
	  PJRST	DWNCX		;GIVE IT UP UUO LEVEL STYLE
	PJRST	GIVCX		;RETURN CX RESOURCE
> ;END IFN FTMP
IFE FTMP,<POPJ	P,>		;RETURN

	$CSUB
SUBTTL	UUO ARGUMENT BLOCK CHECKING ROUTINES -- ARNGE - ADDRESS CHECKING


; ROUTINE TO PERFORM ADDRESS CHECKING ON UUO ARGUMENT BLOCKS.
; THIS HANDLES ALL CASES OF 30-BIT ADDRESSES AND IFIW WORDS.
; IT MAY ONLY BE CALLED AT UUO LEVEL.
;
; IF THE RANGE OF ADDRESSES CROSSES A SECTION BOUNDRY AND THE
; TARGET GIVEN WAS AN IFIW, THEN ADDRESS CHECK ERROR WILL BE
; RETURNED.  OTHERWISE, A GLOBAL RANGE OF ADDRESSES WHICH CROSSES
; SECTION BOUNDRIES WILL BE CONSIDERED LEGAL.
;
; THE RANGE OF ADDRESSES IS CONSIDERED ILLEGAL FOR I/O IF ANY
; PAGE IN THE RANGE IS NOT MARKED AS WRITEABLE IN A PAGE MAP.
; ALSO, IF ANY PAGE IN THE RANGE IS MAPPED TO SECTION ZERO
; PAGE ZERO AND ANY ADDRESS RELATIVE TO THAT PAGE IS LESS THAN
; JOBPFI, THE RANGE WILL BE CONSIDERED ILLEGAL FOR I/O.
;
; CALL:	MOVE	T1, STARTING ADDRESS
;	MOVE	T2, LENGTH OF BLOCK
;	PUSHJ	P,ARNGE
;	  <RETURN 1>		;ADDRESS CHECK
;	<RETURN 2>		;ADDRESS OK BUT ILLEGAL FOR I/O
;	<RETURN 3>		;ADDRESS OK
;
; PCS AND ALL ACS ARE PRESERVED

ARNGE::	PUSH	P,T1		;SAVE T1
	PUSH	P,T2		;SAVE T2
	PUSH	P,T3		;SAVE T3
	PUSH	P,T4		;SAVE T4
	PUSHJ	P,ARNGE1	;DO SOME WORK
	  JRST	ARNGEX		;ADDRESS CHECK ERROR
	AOS	-4(P)		;ALL PAGES CHECKED OUT OK
	SKIPN	T1		;ANY PAGES ILLEGAL FOR I/O?
	AOS	-4(P)		;YES
ARNGEX:	POP	P,T4		;RESTORE T4
	POP	P,T3		;RESTORE T3
	POP	P,T2		;RESTORE T2
	POP	P,T1		;RESTORE T1
	POPJ	P,		;RETURN
ARNGE1:	SE1ENT			;ENTER SECTION 1
IFN FTXMON,<PUSHJ P,SSPCS##>	;SAVE PCS
	PUSHJ	P,SXPCS  	;SET NEW PCS
	  POPJ	P,		;BAD ARGUMENTS--ADDRESS CHECK ERROR
	PUSH	P,T1		;SAVE ADDRESS (WITH POSSIBLE IFIW)
	XSFM	T3		;GET PCS
	ANDI	T3,MXSECN	;STRIP OFF JUNK
	HRL	T1,T3		;REPLACE POSSIBLE IFIW WITH REAL SECTION NUMBER
	ADD	T2,T1		;COMPUTE END ADDRESS +1
	SUBI	T2,1		;LAST ADDRESS TO CHECK
	HLRZ	T3,T1		;GET STARTING SECTION NUMBER
	HLRZ	T4,T2		;AND ENDING SECTION NUMBER
	EXCH	T1,(P)		;GET POSSIBLE IFIW BACK
	CAIE	T3,(T4)		;CROSS SECTION ?
	JUMPE	T3,TPOPJ##	;ILLEGAL FROM SECTION 0
	CAIE	T3,(T4)		;CROSS SECTION BOUNDRY?
	JUMPL	T1,TPOPJ##	;YES--ADDRESS CHECK ERROR IF AN IFIW GIVEN
	MOVEI	T1,0		;CLEAR ILLEGAL I/O FLAG
	EXCH	T1,(P)		;SAVE AND RETRIEVE FULL 30-BIT ADDRESS
	PUSHJ	P,INTLVL##	;ARE WE AT UUO LEVEL?
	  TDNE	T2,[^-1,,^-17]	;AND IS ENDING ADDRESS AN AC?
	JRST	ARNGE2		;NO, SKIP THE SPECIAL CASE
	CAMGE	T2,T1		;DO ADDRESSES GO BACKWARDS?
	JRST	TPOPJ##		;YES, FATAL
	CAIN	T3,(T4)		;IS ENTIRE RANGE IN THE ACS IN ONE SECTION?
	JRST	TPOPJ1##	;YES, THIS IS ALWAYS LEGAL EVEN FOR I/O
	MOVEI	T2,-1		;NO, ONLY CHECK TO END OF S0 WHEN CROSSING

ARNGE2:	HLRZ	T3,T1		;GET SECTION NUMBER
	CAIG	T3,MXSECN	;HAVE A REASONABLE SECTION NUMBER?
	SKIPN	.UPMP+SECTAB(T3);AND DOES THE SECTION EXIST?
	JRST	TPOPJ##		;NO--ADDRESS CHECK ERROR
	MOVE	T3,T1		;COPY TARGET ADDRESS
	LSH	T3,W2PLSH	;CONVERT TO A PAGE NUMBER
	HRRZ	T4,T1		;GET RELATIVE ADDRESS WITHIN SECTION
	CAILE	T4,JOBPFI##	;IN PROTECTED JOBDAT?
	JRST	ARNGE3		;NO
	MOVE	T4,@[IW MS.MAP,UMAPS(T3)] ;POINTER FOR PAGE 0 OF PCS SECTION
	CAMN	T4,@[IW MS.MAP,UMAPS] ;SAME AS POINTER FOR PAGE 0 OF SECTION 0?
	AOS	(P)		;ADDRESS ILLEGAL FOR I/O

ARNGE3:	SKIPN	T4,@[IW MS.MAP,UMAPS(T3)] ;GET POINTER FOR THIS PAGE
	JRST	TPOPJ##		;NON-EXISTANT--ADDRESS CHECK ERROR

ARNGE4:	TLNE	T4,(PM.NIA!PM.SPY) ;I/O LEGAL?
	AOS	(P)		;NO--SAY ILLEGAL FOR I/O
	LDB	T3,[POINT 3,T4,2] ;GET POINTER TYPE
	JUMPE	T3,ARNGE6	;PAGED OUT, AA OFF, OR ABZ--PAGE FAULT
	CAIN	T3,PM.DCD	;ELSE IS IT A DIRECT POINTER?
	JRST	ARNGE5		;YES
	CAIE	T3,PM.ICD	;INDIRECT POINTER?
	JRST	[HRRZS	T4	;NO, SHARED, GET SPT INDEX
		 SKIPN	T4,SPTTAB##(T4) ;GET POINTER
		 JRST	TPOPJ##	;ADDRESS CHECK ERROR IF NONE
		 JRST	ARNGE4]	;LOOP OVER POINTERS
	LDB	T3,[POINT 9,T4,17] ;GET INDEX INTO SECONDARY PAGE MAP
	HRRZS	T4		;GET SPT INDEX
	HRRZ	T4,SPTTAB##(T4)	;GET POINTER TO USE FROM SPT
	JUMPE	T4,TPOPJ##	;FAIL IF SPT SLOT NOT SETUP
	TLO	T4,(<PM.DCD>B2)	;MAKE VALID MAPPING ENTRY
	PUSH	P,.UPMP+.UMTMP	;SAVE TEMPORARY MAPPING SLOT
	MOVEM	T4,.UPMP+.UMTMP	;STORE MAP POINTER
	TRO	T3,.TEMP	;MAKE FULL ADDRESS FOR FETCH
	CLRPT	.TEMP		;CLEAR PAGING MEMORY SO NEW MAPPING IS USED
	MOVE	T4,@T3		;GET MAP ENTRY
	POP	P,.UPMP+.UMTMP	;RESTORE TEMPORARY MAPPING SLOT
	CLRPT	.TEMP		;CLEAR PAGING MEMORY SO OLD MAPPING IS USED
	JUMPN	T4,ARNGE4	;CHASE DOWN MAP POINTER
	JRST	TPOPJ##		;FAIL IF NEXT SLOT IN CHAIN IS ZERO

ARNGE6:	PUSHJ	P,INTLVL##	;AT INTERRUPT LEVEL?
	  JRST	@[MCSEC0+UUOFLT##] ;NO, LET PFH HAVE IT
	AOS	(P)		;YES, CONSIDER IT ILLEGAL FOR I/O
;	JRST	ARNGE5		;KEEP ON TRUCKING AT INTERRUPT LEVEL

ARNGE5:	TRO	T1,PG.BDY	;ROUND UP TO TOP OF PAGE
	CAML	T1,T2		;PAST THE END OF THE BLOCK
	JRST	TPOPJ1##	;YES--ALL ADDRESSES CHECK OUT OK
	ADDI	T1,PAGSIZ	;ON TO THE NEXT PAGE
	JRST	ARNGE2		;LOOP BACK
SUBTTL	UUO ARGUMENT BLOCK CHECKING ROUTINES -- PRNGE - BYTE POINTER


; CHECK A RANGE OF ADDRESSES GIVEN A BYTE POINTER
; CALL:	MOVE	T1, BYTE POINTER
;	MOVE	T2, BYTE COUNT
;	PUSHJ	P,PRNGE
;	  <RETURN 1>		;ADDRESS CHECK
;	<RETURN 2>		;ADDRESS OK BUT ILLEGAL FOR I/O
;	<RETURN 3>		;ADDRESS OK
;
; PCS AND ALL ACS EXCEPT T1-T3 ARE PRESERVED

PRNGE::	IBP	T1		;POINT TO FIRST REAL BYTE
	SOJ	T2,		;OFFSET FOR IBP ABOVE
	ADJBP	T2,T1		;POINT AT END
	LDB	T3,[POINT 6,T1,5] ;GET BYTE POSITION
	CAILE	T3,^D36		;OWGBP?
	TLZA	T1,(77B5)	;YES
	HRLI	T1,(IFIW)	;OR NO
	CAILE	T3,^D36		;AGAIN?
	TLZA	T2,(77B5)	;GLOBAL
	HRLI	T2,(IFIW)	;OR LOCAL ADDRESS
	SUB	T2,T1		;FINALLY, MAKE A COUNT FOR ARNGE
	AOJA	T2,ARNGE	;GO RANGE CHECK THE BLOCK
SUBTTL	UUO ARGUMENT BLOCK CHECKING ROUTINES -- QRNGE - BYTE POINTER


; CHECK A RANGE OF ADDRESSES GIVEN A BYTE POINTER
; CALL:	MOVE	T1, BYTE POINTER WORD 1
;	MOVE	T2, BYTE POINTER WORD 2
;	MOVE	T3, BYTE COUNT
;	MOVE	M, ADDRESS OF SCRATCH LOCATION FOR PUTEWD
;	PUSHJ	P,QRNGE
;	  <RETURN 1>		;ADDRESS CHECK
;	<RETURN 2>		;ADDRESS OK BUT ILLEGAL FOR I/O
;	<RETURN 3>		;ADDRESS OK
;
; PCS AND ALL ACS EXCEPT T1-T4 ARE PRESERVED
; T1 & T2 HAVE A RESOLVED BYTE POINTER IN THEM ON RETURNS 2 & 3
;
;NOTE THAT THE SCRATCH LOCATION REQUIRED IS USUALLY THE ADDRESS FROM WHICH
;THE SECOND WORD OF THE BYTE POINTER WAS FETCHED.
;
;NOTE ALSO THAT THE RESOLVED BYTE POINTER RETURNED WILL HAVE CONVERTED A
;OWGBP INTO A TWO-WORD GLOBAL, EVEN IF PCS IS ZERO.  IF YOU WANT TO USE
;THE BYTE POINTER DIRECTLY IN A PXCT, CALL ORNGE INSTEAD.
;
;ORNGE REQUIRES THAT RETURNS 2 & 3 LEAVE T3 NON-NEGATIVE.

QRNGE::	LDB	T4,[POINT 6,T1,5]	;PICK UP P OR P&S FIELD
IFE FTXMON,<
	CAIG	T4,44		;IS THIS A OWGBP?
	JRST	QRNGE2		;NO, MUST BE LOCAL-SECTION
>
IFN FTXMON,<
	CAILE	T4,44		;IS THIS A OWGBP?
	JRST	QRNGE1		;YEP--GO BREAK IT DOWN
	XSFM	T4		;GET PCS
	SKIPN	T4		;IF FROM SECTION ZERO,
	TLZA	T1,(1B12)	;CAN'T BE TWO-WORD FORMAT
	TLNN	T1,(1B12)	;IS IT IN TWO-WORD FORMAT?
	JRST	QRNGE2		;NO--MUST CONVERT
	TLNE	T1,37		;IS THE RESERVED FIELD IN USE?
	POPJ	P,		;YES--THIS IS ILLEGAL
	JRST	QRNGE3		;GO EVALUATE ADDRESS
> ;END OF IFN FTXMON
QRNGE1:	CAIL	T4,77		;IS IT LEGAL EVEN FOR A OWGBP?
	POPJ	P,		;NO--CRY FOUL
	MOVE	T2,T1		;COPY BYTE POINTER (FOR ADDRESS)
	MOVE	T1,OWGBPT-45(T4);GET LH OF EQUIVALENT BYTE POINTER
	TLZ	T2,(77B5)	;ISOLATE ADDRESS
	JRST	QRNGE4		;GO CHECK OUT ADDRESS
QRNGE2:	MOVE	T2,T1		;COPY BYTE POINTER (FOR ADDRESS)
	TLZ	T2,^-37		;GET RID OF P & S FIELDS
	TLO	T2,(IFIW)	;MAKE SECTION LOCAL
	TLZ	T1,77		;KEEP ONLY P & S FIELDS IN FIRST WORD
QRNGE3:	EXCH	T1,T2		;SWAP WORDS FOR A BIT
	PUSHJ	P,PUTEWD	;STUFF ADDRESS WORD
	  JRST	[EXCH	T1,T2	;SWAP BACK
		 POPJ	P,]	;GIVE ERROR RETURN
	HRRZ	T1,M		;GET ADDRESS POINER FOR EACALC
	PUSHJ	P,EACALC	;GET EFFECTIVE ADDRESS FROM BYTE POINTER VALUE
	  JRST	[EXCH	T1,T2	;SWAP BACK
		 POPJ	P,]	;PROPAGATE ERROR
	EXCH	T1,T2		;SWAP B.P. VALUES BACK AGAIN
	HLLZS	T1		;CLEAR POSSIBLE JUNK
QRNGE4:	TLNN	T1,(1B12)	;IS THIS A TWO-WORD POINTER?
	HRR	T1,T2		;NO, KEEP A VALID ONE-WORD FORM FOR DECNET
	PUSH	P,T1		;SAVE THE BYTE POINTER
	PUSH	P,T2		;AS A DOUBLE-WORD
	LDB	T4,[POINT 6,T1,11]	;GET S FIELD
	CAILE	T4,44		;IS IT REASONABLE?
	JRST	TTPOPJ##	;NO--AVOID IME
	JUMPE	T4,TTPOPJ##	;DISALLOW ZERO-SIZED BYTES
	MOVEI	T1,^D36		;YES, GET WORD SIZE
	IDIVI	T1,(T4)		;SEE HOW MANY BYTES FIT IN A WORD
	LDB	T2,[POINT 6,-1(P),5]	;GET P FIELD
	EXCH	T2,T3		;MOVE FOR SAFETY
	IDIVI	T3,(T4)		;SEE HOW MANY BYTES IN FIRST WORD
	SUB	T2,T3		;COUNT OF BYTES BEYOND FIRST WORD
	MOVE	T4,T3		;SAVE FIRST WORD COUNT
	IDIVI	T2,(T1)		;COUNT OF ADDITIONAL WORDS REFERENCED
	SKIPE	T3		;IF ANY REMAINDER,
	AOS	T2		;REFERENCE ANOTHER WORD
	SKIPE	T4		;IF ANY IN FIRST WORD,
	AOS	T2		;REFERENCE IT TOO
	SKIPE	T4		;IF ANY IN FIRST WORD,
	TDZA	T1,T1		;THEN START THERE
	MOVEI	T1,1		;ELSE START ONE AFTER IT
	ADD	T1,(P)		;FORM BEGINNING ADDRESS TO CHECK
	PUSHJ	P,ARNGE		;CHECK THE WORDS
	  JRST	TTPOPJ##	;ILLEGAL ADDRESS IN RANGE
	  TRNA			;READ ONLY
	AOS	-2(P)		;PROPAGATE SKIPNESS
	AOS	-2(P)		;SINGLE OR DOUBLE
	JRST	TTPOPJ##	;AND RETURN MUNGED BYTE POINTER WORDS

OWGBPT:
DEFINE	X(SIZ),<
IRP SIZ,<
	.ZZ==-1
	REPEAT ^D<36/<SIZ>>+1,<
		<POINT <SIZ>,,.ZZ>!IFN FTXMON,<1B12>
		.ZZ==.ZZ+^D<SIZ>
		>
	>
>
X<6,8,7,9,18>

OWGTLN==.-OWGBPT	;LENGTH OF THIS TABLE

IF2,<PURGE .ZZ>
SUBTTL	UUO ARGUMENT BLOCK CHECKING ROUTINES -- ORNGE - BYTE POINTER


; CHECK A RANGE OF ADDRESSES GIVEN A BYTE POINTER
; CALLING SEQUENCE IS IDENTIAL TO THAT OF QRNGE, WHICH IS CALLED.
;
; ON RETURNS 2 & 3, A RESOLVED BYTE POINTER WILL BE RETURNED.  THIS BYTE
; POINTER WILL BE IN ONE-WORD FORMAT IF POSSIBLE.  IT WILL BE A ONE-WORD
; GLOBAL IFF T3 IS NEGATIVE.

ORNGE::	PUSHJ	P,QRNGE		;RESOLVE THE BYTE POINTER
	  POPJ	P,		;PROPAGATE FAILURE
	  TRNA			;ILLEGAL FOR I/O RETURN
	AOS	(P)		;PROPAGATE SKIPNESS
	AOS	(P)		;SINGLE OR DOUBLE
IFN FTXMON,<
	TLNN	T1,(1B12)	;TWO-WORD FORMAT?
	JRST	ORNGE3		;NO, RETURN ONE-WORD LOCAL
	JUMPL	T2,ORNGE2	;CONVERT TWO-WORD LOCAL TO ONE-WORD LOCAL
	XSFM	T3		;GET PCS (AMONG OTHER THINGS)
	TSC	T3,T2		;XOR SWAPPED
	TRNN	T3,MXSECN	;GLOBAL ADDRESS IN CURRENT SECTION?
	JRST	ORNGE2		;YES, CONVERT TO ONE-WORD LOCAL
	MOVSI	T3,-OWGTLN	;GET AOBJN POINTER TO OWGBPT CONVERSION TABLE
ORNGE1:	CAME	T1,OWGBPT(T3)	;IS THIS A MATCH?
	AOBJN	T3,ORNGE1	;NO, KEEP LOOKING
	JUMPGE	T3,CPOPJ##	;OH, WELL, WE'RE STUCK WITH A TWO-WORD GLOBAL
	HRRZI	T1,45(T3)	;GOT A MATCH, CONVERT TO P&S BYTE
	LSH	T1,^D30		;POSITION IT
	IOR	T1,T2		;GET ONE-WORD FORM
	POPJ	P,		;RETURN

ORNGE2:	TLZ	T1,(1B12)	;NOT REALLY GLOBAL AFTER ALL
> ;END OF IFN FTXMON

ORNGE3:	HRR	T1,T2		;MAKE ONE-WORD LOCAL
	POPJ	P,		;RETURN
SUBTTL	UUO ARGUMENT CHECKING - DECNET-STYLE STRING BLOCK

;
; CHKSTB - CHECK A STRING BLOCK FOR ADDRESSABILITY
;
;CALL:	M/ ADDRESS OF STRING BLOCK
;
;RETURN:	+1 NOT WRITEABLE OR READABLE
;		+2 SUCCESS.  MAX BYTE COUNT IN T4
;
;SIDE-EFFECTS:
;	THE BYTE-COUNT IN THE STRING BLOCK IS ZEROED, FOR CONVENIENCE
;	IN DEALING WITH ERRORS.

IFN FTNET,<
CHKSTB::MOVE	T1,M		;GET ADDRESS OF BLOCK
IFN FTXMON,<PUSHJ P,SSPCS##>	;PRESERVE PCS FOR CALLER
	PUSHJ	P,SXPCS		;VALIDATE POINTER TO STRING BLOCK
	  POPJ	P,		;NO GO
	PUSHJ	P,GETEWD	;GET FIRST WORD OF STRING BLOCK
	  POPJ	P,		;NOT THERE
	HRRZ	T2,T1		;SAVE LENGTH (IN WORDS)
	MOVE	T1,M		;GET ADDRESS OF BLOCK
	PUSHJ	P,ARNGE		;CHECK IT
	  POPJ	P,		;NOT ADDRESSABLE
	  POPJ	P,		;NOT WRITEABLE
	MOVE	T1,T2		;GET LENGTH IN RIGHT AC
	PUSHJ	P,PUTEWD	;AND STUFF IT BACK WITH A 0 LH
	  POPJ	P,		;NOT WRITABLE?
	SOS	T4,T1		;ONE LESS THAN THIS AVAILABLE FOR BYTES
	LSH	T4,2		;4 BYTES PER WORD
	JRST	CPOPJ1##	;OK
> ;END IF IFN FTNET
SUBTTL	UUO ARGUMENT BLOCK CHECKING ROUTINES -- EACALC - EFFECTIVE ADDR CALC


; ROUTINE TO DO EFFECTIVE ADDRESS CALCULATION ON A UUO ARGUMENT.
; CALL:	MOVE	T1, SECTION RELATIVE UVA CONTAINING WORD FOR EACALC
;	PUSHJ	P,EACALC
;	  <NON-SKIP>		;ILLEGAL ADDRESS REFERENCED
;	<SKIP>			;T1 HAS RESOLVED ADDRESS
;
; THE WORD MAY BE EFIW OR IFIW AND OPTIONALLY CONTAIN LOCAL OR
; GLOBAL INDEXING AND INDIRECTION.  ON RETURN, T1 WILL CONTAIN
; THE RESOLVED USER VIRTUAL ADDRESS.  NO LEGALITY CHECKS ARE MADE
; ON THE ADDRESS.  PRESEUMABLY, SOME FLAVOR OF GETWRD/PUTWRD WILL
; TAKE CARE OF ADDRESS CHECKING.  ALL ACS ARE PRESERVED.

EACACC::MOVE	T1,JBTSTS##(J)	;GET JOB STATUS
	SNCALL	(USCHD1##,MCSEC0) ;LET USER CONTROL-C OUT
	SKIPA	T1,(P)		;GET UVA BACK
EACALC::PUSH	P,T1		;SAVE UVA
	HRLI	T1,(XMOVEI T1,@);FORM INSTRUCTION

; HERE TO DO ACTUAL EFFECTIVE ADDRESS CALCULATION.  KAF STOPCODES ARE
; AVOIDED BY HAVING CLOCK1 (CLKINT) CHECK THE INTERRUPTING PC.  IF IT
; IS EACAPC, THEN THE SCHEDULER WILL RUN.  INFINITE LOOPS IN EXEC MODE
; WHERE THE USER CAN'T CONTROL-C OUT ARE AVOIDED BY CHECKING CNTRLC IN
; JBTSTS AND ALTERING THE INTERRUPTING PC TO BE EACACC, THUS ALLOWING
; THE USER TO REACH MONITOR LEVEL THE NEXT TIME THE JOB IS SCHEDULED.

EACAPC::PXCT	PX.EAC,T1	;LET HARDWARE DO EFFECTIVE ADDRESS CALCULATION
	ERJMP	.+2		;NON-SKIP FOR ILLEGAL ADDRESS REFERENCE
	AOS	-1(P)		;ADDRESS OK
	POP	P,(P)		;PRUNE STACK
	POPJ	P,		;AND RETURN
	SUBTTL	SUBROUTINES TO REFERENCE PHYSICAL MEMORY

;ROUTINE TO FETCH THE CONTENTS OF A GIVEN PHYSICAL ADDRESS.
;CALL:
;	T2/ PHYSICAL ADDRESS
;	PUSHJ	P,PHMOV
;RETURN:
;	CPOPJ ALWAYS WITH:
;	T2/ CONTENTS
;MUST PRESERVE T1 AND T3.

	$CSENT	(PHMOV::)
	SKIPE	.CPPMV##	;INSTRUCTION IMPLEMENTED?
	JRST	[PMOVE	T2,T2	;YES, FETCH THE CONTENTS
		 POPJ	P,]	;RETURN
	PUSHJ	P,SAVE3##	;SAVE P1-P3
	DMOVE	P1,T1		;COPY T1 AND T2
	MOVE	P3,T3		;AND T3
	PUSHJ	P,MAPLOC##	;GET A MAP SLOT TO USE
	DPB	P2,[POINT 9,T3,35] ;SET LINE IN PAGE
	LSH	P2,W2PLSH	;CONVERT TO PAGE NUMBER
	HRLI	P2,(<PM.DCD>B2)	;MAKE IT ACCESSIBLE
	DPB	P2,T1		;STORE MAPPING IN EXEC PAGE MAP
	CLRPT	.ERPIL		;MAKE THE NEW MAPPING VISIBLE
	MOVE	T2,0(T3)	;FETCH THE CONTENTS
	PUSHJ	P,UNMAP##	;GIVE UP THE MAP SLOT
	MOVE	T1,P1		;RESTORE T1
	MOVE	T3,P3		;AND T3
	POPJ	P,		;RETURN


;ROUTINE TO STORE DATA INTO A GIVEN PHYSICAL ADDRESS.
;CALL:
;	T2/ PHYSICAL ADDRESS
;	T3/ DATA TO STORE
;	PUSHJ	P,PHMOVM
;RETURN:
;	CPOPJ ALWAYS
;MUST PRESERVE T1 AND T3.

	$CSENT	(PHMOVM::)
	SKIPE	.CPPMV##	;INSTRUCTION IMPLEMENTED?
	JRST	[PMOVEM	T3,T2	;YES, STORE THE CONTENTS
		 POPJ	P,]	;RETURN
	PUSHJ	P,SAVE3##	;SAVE P1 - P3
	DMOVE	P1,T1		;COPY T1 AND T2
	MOVE	P3,T3		;COPY DATA TO STORE
	PUSHJ	P,MAPLOC##	;GET A MAP SLOT TO USE
	DPB	P2,[POINT 9,T3,35] ;SET LINE IN PAGE
	LSH	P2,W2PLSH	;CONVERT TO PAGE NUMBER
	HRLI	P2,(<PM.DCD>B2!PM.WRT) ;MAKE IT ACCESSIBLE AND WRITABLE
	DPB	P2,T1		;STORE MAPPING IN EXEC PAGE MAP
	CLRPT	.ERPIL		;MAKE THE NEW MAPPING VISIBLE
	MOVEM	P3,0(T3)	;STORE THE DATA
	PUSHJ	P,UNMAP##	;GIVE UP THE MAP SLOT
	MOVE	T1,P1		;RESTORE T1
	MOVE	T3,P3		;AND T3
	POPJ	P,		;RETURN
	$LIT

DATEND:	END