Google
 

Trailing-Edge - PDP-10 Archives - BB-F494Z-DD_1986 - 10,7/lnkxit.mac
Click 10,7/lnkxit.mac to see without markup as text/plain
There are 19 other files named lnkxit.mac in the archive. Click here to see a list.
TITLE LNKXIT - EXIT MODULE FOR LINK
SUBTTL	D.M.NIXON/DMN/JLd/RKH/JBC/JNG/MCHC/DZN/MFB/PAH/PY/HD/JBS 10-Dec-85


;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1974,1985,1986. ALL RIGHTS RESERVED.
;
;
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
;ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH LICENSE AND WITH THE
;INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR ANY  OTHER
;COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
;OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF THE  SOFTWARE  IS  HEREBY
;TRANSFERRED.
;
;
;THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT  NOTICE
;AND  SHOULD  NOT  BE  CONSTRUED  AS A COMMITMENT BY DIGITAL EQUIPMENT
;CORPORATION.
;
;DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY  OF  ITS
;SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.



SEARCH	LNKPAR,LNKLOW,OVRPAR,MACTEN,UUOSYM
IFN TOPS20,<SEARCH MACSYM, MONSYM>
SALL

ENTRY	LNKXIT
EXTERN	LNKCOR,LNKLOG,LNKFIO
EXTERN	.JB41


CUSTVR==0		;CUSTOMER VERSION
DECVER==6		;DEC VERSION
DECMVR==0		;DEC MINOR VERSION
DECEVR==2374		;DEC EDIT VERSION

VERSION


SEGMENT


;LOCAL ACC DEFINITION
R==R1
SUBTTL	REVISION HISTORY


;START OF VERSION 1A
;50	HANDLE PAGING DURING LOCAL SYMBOL OUTPUT CORRECTLY
;51	FIX BUG IF UNDEF SYMBOLS BUT DON'T WANT TO KEEP LOCAL SYMS
;53	FIX RETURNS FROM DVMOV. ROUTINE
;54	ADD KIONLY D.P. INST.
;55	STORE VERSION NUMBER (.JBVER) IN .RBVER OF SAVE FILE
;56	FIX LOOP AT JBEX2A IF CORE IMAGE IS MULTIPLE OF 2000
;57	SETUP VESTIGIAL JOB DATA AREA EVEN IF NOT A SAVE FILE
;63	REMOVE MULTIPLY-DEFINED SYMBOLS FROM SYMBOL TABLE (IN CORE)
;65	TENEX SPEEDUPS
;66	SAVE JOB DATA AREA ON /SAVE IF DDT, SYMBOLS AND ALL CODE IN HIGH SEG
;67	PUT ADDITIVE GLOBAL REQUESTS IN UNDEF TABLE
;70	FIX ADDRESS CHECK PROBLEM
;71	MAKE ALL INFO MESSAGES STANDARD FORM
;73	(11314) PREVENT EXECUTION IF UNDEF SYMBOLS
;100	FIX ILL MEM REL ON /SAVE IF LAST BLOCK FILLS ALL OF CORE
;104	OUTPUT FAIL BLOCK HEADER IN LOCAL SYMBOL TABLE
;106	REMOVE HIORG, REPLACE BY LL.S2
;115	MAKE /NOSYMBOLS WORK CORRECTLY

;START OF VERSION 2
;135	ADD OVERLAY FACILITY
;136	FIX VARIOUS BUGS
;140	(12617) FIX ?IO TO UNASSIGNED CHANNEL ON /SYMBOL:TRIPLET FILE
;154	(12991) ONLY LOOK AT RIGHT HALF OF .JBERR TO DELETE EXECUTION
;155	(12988) FIX TEST FOR COBDDT AT RUN UUO TIME
;166	MAKE RADIX50 SYMBOL FILE TYPE 776
;177	FIX ADDRESS CHECK BUG IF PAGING SYMBOLS
;211	FIX ZEROS IN MONITOR SYMBOL TABLE
;213	(12531) LOW SEG OF TWOSEG CORE IMAGE  BAD
;221	GET PROTECTION CODE RIGHT ON XPN FILE

;START OF VERSION 2A
;244	DATE75 FIX TO MAKE LOW SEG FILE HAVE CORRECT DATE
;START OF VERSION 2B
;224	PUT SECOND SYMBOL FOR COMMON BLOCK IN RADIX50 SYMBOL TABLE
;226	FIX UNDEFINED SYMBOL BUG (117 NOT SET UP)
;234	FIX VARIOUS BUGS IF HIGH FILE IS MADE RATHER THAN RENAMED
;235	(13845) FIX ZERO COMPRESSOR IF PAGED AND READING ZEROS
;241	USE LARGER OF ABS OR LOW REL BREAK FOR .JBFF
;242	HANDLE USER PAGE FAULT HANDLER CORRECTLY
;244	DATE75 FIX TO MAKE LOW SEG FILE HAVE CORRECT DATE
;247	Change all references to DEBUGSW. Now lh is -1 if set,
;	rh is table index  for either /DEBUG or /TEST
;266	Correct problems with loading symbols when LS area
;	overflows to the DSK.
;267	Get symbol table offest right when core window
;	changes.
;270	Use the correct initialization routine when high
;	core overflows to the disk during this phase.
;322	Get LSYM and other core management variables right
;	so LNKCOR doesn't fail
;324	Don't release the symbol channel if still needed,
;	when loading symbols into root of an overlay program.
;330	Release the correct channel when done with symbols
;	being loaded into the root of an overlay program.
;335	Keep LSYM from being clobbered when loading symbols
;	into root of overlay program.  Don't confuse LNKCOR
;336	Fix /RUN switch to work properly
;337	Insert check for no core to zero before BLT and
;	prevent possible ILL MEM REF
;353	REMOVE EDIT 225
;357	LABEL EDITS 224,226,234,235,241,242
;360	REMOVE EDIT 336
;401	Remove 5.06 compatability hack setting up vestigial jobdat.
;403	Fix HALT if generating new style symbol file.
;423	Fix ?ILL ADDR IN UUO when the zero compressor tried to use
;	the LS area after it had done a CORE UUO to get rid of it.
;433	Support the /RUN switch.
;START OF VERSION 2C
;442	Fix the DVMOV. routine to either RENAME or copy,
;	and delete copy routines called if DVMOV. fails.
;443	Don't lose part of local symbols if overflowing to disk.
;467	Correct RT.PT check at SYMO1
;471	Add code for ALGOL debugging system.
;476	Insert missing FTOVERLAY conditional.
;517	Make first word of ALGOL symbol file be 1044,,count.
;524	Check for symseg area reduced to one page & don't zero rest.
;530	Get triplet flag definitions right.
;544	SOUP in LINK version 3 stuff for TOPS-20.
;547	Make LINK assemble with MACRO 51.
;555	Don't round .RBSIZ up to block bound for symbol files.
;557	Clean up the listing for release.

;START OF VERSION 3
;446	CHANGES FOR TENEX

;START OF VERSION 3A
;560	Release on both TOPS-10 and TOPS-20 as LINK version 3A(560)
;START OF VERSION 4
;570	Don't lose local symbols when undefined globals exist.
;575	On /EXECUTE/SAVE to a two segment program, always run xxx.LOW
;606	Get the protection of .HGH and .XPN files right.
;616	Give appropriate error messages when RENAMEs fail
;621	/SAVE AND /SSAVE GENERATE EXE FILE.  
;	/SAVE AND /SSAVE NO LONGER TAKES ANY ARGUMENT.  IF THE CORE
;	SIZE IS SPECIFIED, LINK WILL IGNORE IT.
;	THE CODE TO GENERATE .HGH/.SHR/.LOW FILES ARE UNDER THE 
;	CONDITIONAL ASSEMBLY SWITCH FTEXE==0.
;622	Don't set up vestigal JOBDAT unless there's a high segment.
;641	IF HIGH SEG IS PAGED, WRITE OUT WHAT'S IN CORE BEFORE UPDATING
;	VESTIGAL JOBDAT AND DUMP TO EXE FILE.
;642	EXE FILE EXTENSION FOR DISK FILE GENERATED FOR NOT HAVING
;	ENOUGH CORE
;643	FIX BUG WITH SWITCH SETTING FOR P4 IN XCMPRL.
;644	DON'T DO JSYS 147(RESET) IF WE DO EXIT.
;645	Loop back topage lc if not more core in LSREQ.
;646	Don't touch a high seg page again after high seg is removed
;	in %LOW.
;647	Don't zero unneeded memory (better VM performance).
;650	Use VM on TOPS-10 if available.
;652	Avoid bad .SAV file when paging to disk.
;704	Don't write EXE-directory entries for psect gaps.
;713	Fix bug with sparse EXE-directory.
;715	Modify SYMSEG to take psect name.
;724	Check for symbol table range in INGAP.
;725	Fix bug with incrementing process page in XCMPOV.
;726	Fix bug in INGAP routine.
;727	Give Insufficient space error message when symbol table truncated.
;731	SEARCH MACTEN,UUOSYM instead of C.
;732	Use LOWLOC and fix bugs related to page 777.
;733	Fix bug with allocated high seg pages causing bad EXE format.
;742	Don't BLT JOBDAT if process page 0 not the first page.
;744	Fix bug with calculation of EXE file size.
;754	Don't page LS area when doing symbol table output, if paging is needed for the first time for LC(or HC).
;762	Page in the LOWLOC page before generating EXE file.
;764	Update LOWLOC in GETSST incase symbol table is lower than code.
;	Also, corrects a bug in updating upper window in XCMPRS routine.
;765	Release on both TOPS-10 and TOPS-20 as LINK version 4(765)
;START OF VERSION 4A
;770	Add code to allow first-time paging in und-symbol table routine.
;772	Adjust symbol table pointer to after undefined symbol table.
;773	Fix GSDLT in case the GS area is already gone.
;774	Fix bad calculation of UW in EXE file writer.
;776	Fix /SAVE of small program with no data in pages 0 or 1.
;1110	Output PSECT name as part of error message in GETSST.
;1111	Fix core management bug introduced by edit 772.
;1113	See that LINK doesn't shrink on TOPS-20 until really necessary.
;1121	Fix edit 772 so symbol table and undefined table don't overlap.
;1125	Don't try to do a RUN UUO to the hiseg file when generating an EXE file.
;1127	Set up the module length for PAT.. in the runtime symbol table.
;1132	Teach the EXE file writer about PSECTs above the high segment.
;1144	Zap PA1050 but not DDT on /EXECUTE, /DEBUG when running from .EXE file.
;1145	Set up symbol table pointers on TOPS-20 if no .EXE file written; broken by 1144.
;1146	Force writing an .EXE file more often, especially with PSECTs.
;1147	Adjust LC.LB when adjusting LW.S1 in JBEXE.  Broken by 732.
;1152	Set RC.HL for .LOW. during initialization when loading overlays.
;1160	Don't put junk in the undefined table when symbol used in Polish.
;1170	Fix core management problems when not writing an EXE file.
;1171	Fix edit 1146 to say LNKPCL if bad PSECT properties, even on TOPS-10.
;1172	Fix many problems with runtime symbol table generator.
;1174	Label and clean up all error messages.
;1202	Fix problems introduced by edits 1172 and 1174.
;1212	Use E$$SOE label instead of ZCMP7E, broken by 1174 (in off conditional).
;1214	Fix unmatched angle bracket bug in .EXE file code.
;1216	Preserve P acs in SYMOUT.
;1217	Clean up the listings for release.
;1220	Release on both TOPS-10 and TOPS-20 as version 4A(1220).
;1235	Clear LOGSUB to avoid possible IO TO UNASSIGNED CHANNEL.
;1242	Make High Segs above 700000 generate .EXE file on TOPS-20
;1244	Kill PA1050 if executing user program, replace CORE UUO with PMAP JSYS
;1257	Put Root node location in RC.HL in .ABS. if overlaid.
;1261	Restore P1 if /SAVE scan block built because of complex program
;1267	Add ALGDDT to KEYMAC definition.
;1272	Fix Edit 1244 to remove PA1050 if low seg ends at end of page.
;1273	Fix RC.HL in .LOW. and .HIGH. to agree with HP.S1 and HP.S2.
;1300	Check BADCORE, issue LNKCFS if non-zero.
;1301	Make .OERR. Messages use verbosity bits.
;1302	Fix bug in 1273, don't use HP.S if RC.HL() is greater.
;1305	Remove edits 1273, 1302, move code into LNKOLD
;1314	Fix bug if more than 400 contiguous non-zero pages of .EXE file.
;1317	Correctly calculate .JBCOR if program ends on page boundary.
;1321	Make SIMDDT start at .JBREN like ALGDDT.
;1323	Check for high seg when simulating CORE UUO with PMAP% JSYS.
;1325	Output secondary fixup chains in undefined symbol table.
;1326	Use new PA1050 suicide COMPT. instead of PMAP%

;START OF VERSION 5
;1400	Use OVRPAR.MAC.
;1401	Performance improvements to overflow and EXE file i/o.
;1415	Write out ALGOL .SYM files on channel TC.
;1423	Support Program Data Vectors
;1425	FTFRK2 Extended addressing support.
;1427	Put ERJMPs after PDVOP%s for pre-Tops-20 Release 5.
;1437	Defer destroying LC file under TOPS-20 until the last minute.
;1442	Don't go thru the SSINI code unless nonzero sections have been
;	loaded.
;
;1450   Use PRGFRK, fix some FTFRK2 bugs, insert ERJMP after failing SEVEC.
;1454	Calculate default SYMLIM correctly.
;1455	Fix infinite loop caused by bad test in TTLLUP.
;1460	Clean up SSINI code and kill UUO simulation for xaddr programs.
;1464	Get the right window for the PDV in nonzero sections.

;Start of Version 5.1
;1500-1677	Maintenance edits.
;1506	Conditionalize remaining UUOs in the overlay-writing code.
;1516	Fix bad test at CHKRS0+3
;1521	Get all of overlay links symbol table in .EXE file.
;1522	Make JBGCM/JBGCMV unmap and remap paged areas on the -20.
;1524	Add an entry for PASDDT in STLOCN.
;1531	Handle address before current window in EXE writer
;1532	Test JOBPTR, not LW.S1, to decide if XCMPRS should write the JOBDAT.
;1534	Make sure LC/HC.PT is right following calls to LNKCOR from SYMOU2.
;1536	Handle multi-section LS area without catastrophic failures.
;1757	Correct 1432.  PDV address was too large by one
;1760	Keep the section number of the last word of the PDV
;1762 	Don't return the PDV prematurely so that start address for programs
;	in non-zero sections is set correctly.
;1764	Make use specified entry vectors work in non-zero sections.
;1773	Set up t3 for XSVEC in JBEX1A
;2000	Don't return nonexistent PDV storage at SSINIG+9.
;2006	Fix PDVs over page boundary, use 1 not JRST, use SEVEC in section 0
;2016	Fix /PVBLOCK:HIGH, and set HL.S0(R) and HC.S0(R) if needed.
;2021	Make pages from overflow file private if not writing .EXE file.
;2023	If PMAP fails while writing .EXE because Quota exceeded try expunge.
;2024	Fix edit 2023
;2026	Update copywrite and strip edit banners.
;2027	Conditionalize PMAP error handling.
;2032	Allocate space with LC.IN before reading area from .OVL file.
;2034	Remove Edit 1531.
;2035	Don't map in non-existant pages at JBGMV0.
;2040	Be careful of page boundary when mapping out at SYMINI.
;2043   Don't call BLTJDA if JOBPTR is zero at JBEXE1.
;2052	Don't die when making EXE file if directory is protected.
;2054	Keep the LS overflow area on TOPS-20 if it is still mapped.
;2055	Put the count in T2 before calling DY.GET.
;2056	Print LNKXCT message when executing prog in non-zero section.
;2060	Save the PPN and PATH info for the RUN UUO in RUNEX2.
;2061	Fix typo in 2060.
;2066	Fix 2060 to get PPN from right place and check for default [0,0].

;Start of Version 6
;2202	Use 30 bit addresses for xx.IN and xx.OUT, remove NONZER and FTFRK2.
;2206	Set read-only attributes correctly for non-zero section psects.
;2211	Implement /NOJOBDAT, change the way JOBDAT is automatically suppressed.
;2220	Handle long psect names.
;2232	Don't set .JBREL during exit if user said /NOJOBDAT.
;2237	Implement PDV memory maps.
;2241	Setup P1 and P2 even if /NOJOBDAT.
;2245	Implement the PDV symbol table vector.
;2247	Use an inferior fork for program on TOPS-20.
;2250	Allocate PDV space more efficiently, fix various other bugs.
;2256	Use new-style LS segment triplets to generate the module headers.
;2260	Fix several things with old edits (see LNKHST).
;2261	Fix off-by-one in page attribute setting code.
;2265	Don't set page attributes of null read-only psects.
;2274	Fix some error messages, don't SSAVE% beyond highest section.
;2277	Add new /DEBUG code for loading DDT into non-zero sections.
;2301	Fix error messages for TOPS-20 native files.
;2304	Change DDT error messages, don't check undef sym ptr if def is there.
;2306	Add long PDV name, default PDV, move symbol vector to symbol psect.
;2311	Fix PDVs in high segment, default bit 0 for symbol vector pointer.
;2312	Store the default PDV memory map address in the PDV.
;2314	Allow /DEBUG when SPLFK% fails, remove LINK's PDV and PSI table addrs.
;2317	Fix 2247 to save copy-on-write page attributes correctly.
;2320	Create empty read-only pages when necessary.
;2330	Fix conditionals and add label needed under TOPS-10.
;2335	Fix problems with memory map, TOPS-10 conditionals, add default name.
;2336	Produce symbol vector properly if no default map requested.
;2346	Don't try to GET% EXE file if not on disk.
;2347	Fix arguments to COMPT. to remove PA1050.
;2350	Map non-existant pages properly.
;2352	Don't map too large an area in STUFDD.
;2353	Remove unreachable code, bad AC names, move SPLFK% symbols to LNKPAR.
;2355	Handle pre-emptive debugger starting addresses properly.
;2356	Remove unnecessary TOPS20 conditionals, fix overflow in exe writer.
;2357	Set up DC channel for exe file if splice fork fails.
;2360	Fix problem in edit 2355, don't change STADDR.
;2361	Add the PDV map overhead word before storing the map length.
;2362	Save the DDT start address in EXECSW as well as in STADDR.
;2363	Check which debugger starts, don't assume DDT.
;2364	Use HL.S1 to get highest location loaded for SSAVE.
;2366	Add symbol and entry vectors on TOPS-10.
;2370	Fix off-by-one if segment ends with allocated but zero pages.
;2370   Fix long sym support for DDT symbol tables.
SUBTTL	ENTER HERE


LNKXIT:	JFCL	.+1		;IN CASE CCL ENTRY
E$$EXS::.ERR.	(MS,0,V%L,L%I,S%I,EXS,<EXIT segment>) ;[1174]
	SKIPN	BADCORE		;[1300] CORE IMAGE ALL FIXED UP?
	JRST	LNKX0I		;[1300] YES
E$$CFS::.ERR.	(MS,0,V%L,L%F,S%C,CFS,<Chained fixups have been suppressed>);[1300] NO
LNKX0I:	ZAPTMP			;[1300] CLEAR ALL TEMP SPACE
	MOVE	T1,HC.S0	;GET ABS BREAK
	CAMLE	T1,HC.S1	;LARGER THAN LOW SEG?
	MOVEM	T1,HC.S1	;USE LARGER
	MOVE	T1,HL.S0	;GET ABS BREAK
	CAMLE	T1,HL.S1	;LARGER THAN LOW SEG?
	MOVEM	T1,HL.S1	;USE LARGER
	HRRZS	LL.S2		;[2247] CLEAR LH IN CASE /REDIRECT
IFN FTOVERLAY,<
	SKIPGE	LNKMAX		;DID WE LOAD ANY OVERLAYS?
	JRST	LNKX1		;NO
	MOVE	T1,PH+PH.OVL	;[1400] GET START OF CODE FOR ROOT
	USETI	OC,(T1)		;POSITION ON THE BLOCK
	MOVE	P2,PH+PH.LLN	;[1400] LENGTH WE NEED
	ADD	P2,LC.LB
	SUB	P2,LC.AB	;SEE IF ENOUGH
	JUMPLE	P2,LNKX0A	;YES
	MOVEI	P1,LC.IX
	PUSHJ	P,LNKCOR##	;MUST EXPAND
	  JRST	LNKX0C		;DO IT THE HARD WAY
LNKX0A:				;[2247]
IFN TOPS20,<			;[2247]
	MOVE	T2,LC.AB	;[2247] GET THE TOP OF THE LC AREA
	SUB	T2,LC.LB	;[2247] MINUS THE BOTTOM IS THE SIZE
	MOVEM	T2,UW.LC	;[2247] UPPER WINDOW BOUND
	SETZB	T1,LW.LC	;[2247] START AT ZERO
	PUSHJ	P,LC.IN##	;[2247] MAP IT IN
>;[2247] IFN TOPS20
	MOVE	T1,LC.LB	;[2247] READ INTO LC AREA
	SUBI	T1,1
	HLL	T1,PH+PH.OVL	;[1400] SETUP IOWD
	SETZ	T2,
	IN	OC,T1		;READ BACK CORE
LNKX0B:	  SKIPA	T1,OV.S1	;CORE BOUNDS
	PUSHJ	P,E$$IOV##	;[1174] INPUT ERROR
	HRRZM	T1,HL.S1
	HLRZM	T1,HC.S1
	MOVEI	R,1		;[1152] LOW SEGMENT
	MOVE	R,@RC.TB	;[1152] POINTER TO RC BLOCK FOR LC AREA
	HRRZM	T1,RC.CV(R)	;[1152] SAVE AS CURRENT VALUE OF RELOC COUNTER
	HRRZM	T1,RC.HL(R)	;[1152] AND FIRST FREE BEYOND ROOT
	JRST	LNKX0G		;[1257]

;NOW TO READ BACK FIRST FEW BLOCK
LNKX0F:	SETZB	T1,LW.S1	;[2202] STARTS AT ZERO
	MOVE	T2,LC.UB	;[2202] GET MAX SIZE
	MOVEM	T2,LC.AB	;[2202] USE IT ALL AGAIN
	SUB	T2,LC.LB	;[2202] GET UPPER BOUND
	MOVEM	T2,UW.S1	;[2202] REMEMBER IT
	PUSHJ	P,LC.IN##	;READ IT BACK
	JRST	LNKX0B		;FIXUP VARIOUS POINTERS
LNKX0C:	SETZM	LW.S1		;SET BACK TO START
	MOVE	T1,PH+PH.OVL	;[1400]
	USETI	OC,(T1)		;SET ON BLOCK
	MOVE	T1,LC.UB
	MOVEM	T1,LC.AB	;USE ALL AVAILABLE SPACE
	SUB	T1,LC.LB	;GET SIZE OF WINDOW
	MOVEM	T1,UW.S1	;UPPER WINDOW
	ADDI	T1,1
LNKX0D:				;[2032]
IFN TOPS20,<			;[2032]
	PUSH	P,T1		;[2032] SAVE THE AC
	MOVE	T1,LW.LC	;[2202] GET THE LOWER BOUND
	MOVE	T2,UW.LC	;[2202] GET THE UPPER BOUND
	PUSHJ	P,LC.IN##	;[2032] MAP IN THE WINDOW
	POP	P,T1		;[2032] RESTORE THE AC
>;[2032] IFN TOPS20
	MOVN	T1,T1		;[2032]
	HRLZ	T1,T1
	HRR	T1,LC.LB	;IOWD
	SUBI	T1,1		;AT LAST
	SETZ	T2,
	IN	OC,T1
	  SKIPA	T1,LC.AB
	PUSHJ	P,E$$IOV##	;[1174]
	SUB	T1,LC.LB
	ADD	T1,LW.S1	;ADD BASE
IFE	TOPS20,<		;[2032] DON'T BLT ON THE -20
	CAMG	T1,PH+PH.LLN	;[1400] REACHED END YET?
	JRST	LNKX0E		;NO
	MOVE	T1,PH+PH.LLN	;[1400] YES, GET WHAT WE REALLY NEED
	IORI	T1,.IPM
	MOVE	T2,T1
	SUB	T2,LW.S1
	ADD	T2,LC.LB
	CAMN	T2,LC.UB	;ARE WE IN LAST BLOCK
	JRST	LNKX0E		;YES, NO CHANGE
	MOVEM	T2,LC.AB	;RESET UPPER BOUND IN USE
	SETZM	1(T2)		;ZERO FIRST WORD
	HRLI	T2,1(T2)
	HRRI	T2,2(T2)
	BLT	T2,@LC.UB	;AND THROUGH REST
>;[2032] END IFE TOPS20
LNKX0E:	MOVE	T2,T1		;[2202] END OF WINDOW
	MOVE	T1,LW.S1	;[2202] ORIGIN
	PUSHJ	P,LC.OUT##	;WRITE OUT THIS MUCH
	MOVE	T1,LC.AB
	SUB	T1,LC.LB	;GET SIZE OF WINDOW
	MOVE	T2,T1
	ADD	T2,LW.S1
	CAML	T2,PH+PH.LLN	;[1400] MORE TO DO?
	JRST	LNKX0F		;NO
	AOS	T2,T1		;PUT COPY IN T2
	ADDM	T1,LW.S1	;NEW WINDOW BASE
	ADDB	T2,UW.S1	;GET NEXT UPPER BOUND
	CAMG	T2,PH+PH.LLN	;[1400] DO WE NEED TO READ IT ALL IN?
	JRST	LNKX0D		;YES
	MOVE	T1,PH+PH.LLN	;[1400] NO, GET HIGHEST WE NEED
	ADDI	T1,.DBM		;[650] UP TO NEXT BLOCK
	ANDCMI	T1,.DBM		;[650] INCASE WAS ALREADY THERE
	SUB	T1,LW.S1	;NO. OF WORDS
	JRST	LNKX0D		;TO INPUT
LNKX0GA:	MOVEI	R,0		;[1257] SET UP TO POINT TO PSECT
	MOVE	R,@RC.TB	;[1257] GET POINTER TO .ABS. PSECT BLOCK
	MOVE	T1,ROOTAB	;[1257] PICK UP ADDRESS IN ROOT NODE
	MOVEM	T1,RC.HL(R)	;[1257] PUT IN .ABS.

>;END OF IFN FTOVERLAY

LNKX1:				;[2366]
IFN TOPS20,<			;[2366]
;Here to determine whether a JOBDAT should be produced.  The rule is:
;	If the user said /NOJOBDAT, he won't get one.
;	If the user has non-zero sections he won't get one.
;	If the user has a psect which starts below 140 he won't get one.
;	Otherwise he will.

	SKIPE	NOJBDA		;[2247] User already said /NOJOBDAT?
	 JRST	LNKX1B		;[2247] Yes, user already made decision
	MOVE	T1,FXSBIT	;[2247] Get the section bits
	TXNE	T1,^-1B0	;[2247] Non-zero sections?
	 JRST	LNKX1A		;[2247] Yes, no JOBDAT for this program
	MOVEI	R,2		;[2247] Get index to lowest psect
	CAMLE	R,RC.NO		;[2247] Is there one?
	 JRST	LNKX1B		;[2247] No, it's single segment and gets JOBDAT
	MOVE	T1,@RC.TB	;[2247] Point to the RC block
	MOVE	T1,RC.IV(T1)	;[2247] Get the initial value
	CAIG	T1,140		;[2247] Check psect before 140
LNKX1A:	SETOM	NOJBDA		;[2247] Remember no JOBDAT

;[2306] Here to determine whether a PDV should be produced.  The rule is:
;[2306] If the user program has overlays, he won't get one.
;[2306]	If the user said /PVBLOCK:NONE, he won't get one.
;[2306]	If the user said /PVBLOCK:LOW, /PVBLOCK:HIGH, or /PVBLOCK:PSECT:
;[2306]	   he will get one.
;[2306]	If the user said /PVBLOCK:DEFAULT, or did not say anything, he
;[2306]	   will get one if he will not get a JOBDAT, or if he specified
;[2306]	   a /PVDATA of any type.  The type he will get will be identical
;[2306]	   to /PVBLOCK:LOW.

LNKX1B:
	HLRZ	T1,PRGPDV	;[2306] Get the keyword
IFN FTOVERLAY,<			;[2306]
	SKIPN	OVERLW		;[2306] Using overlays?
>;[2306] IFN FTOVERLAY
	CAIN	T1,$SSGNONE	;[2306] /PVBLOCK:NONE?
	 JRST	LNKX1D		;[2306] Yes, toss block and exit
	JUMPE	T1,LNKXIC	;[2306] Never set?
	CAIE	T1,$SSGDEFAULT	;[2306] Or /PVBLOCK:DEFAULT?
	 JRST	LNKX1G		;[2306] No, it's specified - must build one

;[2306] Here on /PVBLOCK:DEFAULT - Check for /PVDATA or no JOBDAT
LNKXIC:	HRRZ	T1,PRGPDV	;[2306] Get the PDV block address
	SKIPN	T1		;[2306] Block set up (/PVDATA already seen)?
	SKIPE	NOJBDA		;[2306] Or no jobdat?
	 JRST	LNKX1F		;[2306] Yes, create the PDV

;[2306] Here if a PDV not wanted - Return the block if there is one
LNKX1D:	HRRZ	T1,PRGPDV	;[2306] Get the PDV block address
	JUMPE	T1,LNKX1E	;[2306] No block, don't return it
	MOVEI	T2,PV.LEN	;[2306] And the length
	PUSHJ	P,DY.RET##	;[2306] Return it
LNKX1E:	SETZM	PRGPDV		;[2306] Remember there isn't one
	JRST	LNKX1H		;[2306] Done

;[2306] Here if a default PDV wanted -  Set to /PVBLOCK:LOW and continue
LNKX1F:	MOVEI	T1,$SSGLOW	;[2306] Get the token
	HRLM	T1,PRGPDV	;[2306] Set it

;[2306] Here if a PDV is wanted - Create the block if there isn't one yet.
LNKX1G:	HRRZ	T1,PRGPDV	;[2306] Get the block address
	SKIPN	T1		;[2306] Is there one?
	PUSHJ	P,PVFIX##	;[2306] No, set up the block
LNKX1H:
;[2247] Here to determine whether or not to include .LOW. in the map
	MOVE	T1,SG.TB+1	;[2247] Get pointer to .LOW.
	SKIPE	NOJBDA		;[2247] Need a JOBDAT?
	SKIPL	RC.AT(T1)	;[2247] Or user program put anything in .LOW.?
	 JRST	LNKX1I		;[2306] Yes, allow for .LOW. in the PDV map
	MOVE	T1,RC.NO	;[2247] Get number of psects
	CAIE	T1,1		;[2247] Are there any other than .LOW.?
	 SETOM	NOLOW		;[2247] Yes, don't put .LOW. in the map
>;[2330] IFN TOPS20
LNKX1I:	MOVE	R,SG.TB+1	;[2306] Get the low segment RC block
IFN FTOVERLAY,<
	SKIPL	LNKMAX		;IF LOADING OVERLAYS
	SETZM	USYM		;IGNORE UNDEFINED SYMBOLS TIL RUN TIME
>
	MOVEI	T1,PATSP.	;IF NOT ALREADY
	SKIPN	PATSPC		;SETUP PATCHING SIZE
	MOVEM	T1,PATSPC	;IN CASE REQUIRED
	SETZM	FRECOR		;NO NEED NOW
	SKIPN	FS.SS		;THESE ARE THE ONLY FIXUPS WE CAN DO NOW
	SKIPE	USYM		;BUT MAY HAVE GLOBAL REQUESTS
	CAIA
	PUSHJ	P,FX.ZAP	;NONE, SO GET RID OF AREA
IFE TOPS20,<			;[2054]
				;NOW TEST FOR CASE INWHICH SYMBOL FILE WAS
				;OPENED BUT NOT USED (NOT VERY LIKELY)
	SKIPE	UW.LS		;NEVER OPENED
	SKIPE	LW.LS		;NEVER USED IF STILL ZERO
	JRST	CLSMAP		;STILL IN USE, OR NEVER WAS
IFN FTOVERLAY,<
	SKIPL	LNKMAX		;IF LOADING OVERLAYS
	SKIPN	UW.LS		; AND PAGING SYMBOLS
	CAIA			;NO
	JRST	CLSMAP		;KEEP FILE OPEN RATHER THAN READ IN
>
	SETZM	UW.LS		;CLEAR UNWANTED POINTER
	MOVEI	T1,SC		;SYMBOL FILE CHAN #
	PUSHJ	P,DVDEL.##	;DELETE FILE AND REMOVE ALL TRACES
	  JFCL
	SETZM	IO.PTR+SC	;AND FORGET ABOUT IT
> ;[2054] IFE TOPS20
CLSMAP:	SKIPN	IO.PTR+MC	;AN OPEN MAP?
	JRST	RDJBDA		;NO
	MOVEI	T1,MC		;SET CHAN#
	MOVEM	T1,IO.CHN	;IN ACTIVE STATE
	PUSHJ	P,DVRLS.##	;CLOSE FILL AND DO POSITIONING
	PUSHJ	P,DVZAP.##	;RETURN BUFFERS AND DATA BLOCK
RDJBDA:
IFN TOPS20,<
	SKIPE	PRGPDV		;[2306] PROGRAM DATA VECTOR?
	PUSHJ	P,PDVBLD	;[2306] GO ALLOCATE THE SPACE
	SKIPE	NOJBDA		;[2306] JOBDAT NOT WANTED?
	 JRST	RBJBDX		;[2211] YES, NO JOBDAT
> ;[1423] IFN TOPS20
	SKIPE	PAG.S2		;HIGH SEG PAGING?
	PUSHJ	P,RDJBH		;YES, READ IN .JBHDA
	SKIPE	PAG.S1		;LOW SEG PAGING?
	PUSHJ	P,RDJBL		;YES
RBJBDX:				;[1460]
	HRRZ	T1,.JBERR	;GET ERRORS FOR THIS PROCESS
	ADD	T1,USYM		;EACH UNDEF COUNTS ONE
	HRRM	T1,.JBERR	;WILL STOP EXECUTION IF NON-ZERO
	JRST	CHKRST		;[1172] NOW GO DO RUNTIME SYMBOL TABLE
IFN TOPS20,<
;PDVBLD - ROUTINE TO ALLOCATE SPACE FOR THE PDV
;

PDVBLD:	HRRZ	P1,PRGPDV	;[2306] GET THE PDV BLOCK
	SKIPE	.PVNAM(P1)	;[2306] ASCIZ NAME ALREADY SET?
	 JRST	PVBLD1		;[2306] YES
	SKIPE	T3,RUNAME	;[2306] GET PROGNAM
	 JRST	.+3		;[2306] SET
	SKIPN	T3,SSNAME	;[2306] IF NOT TRY SAVE FILE NAME
	MOVE	T3,LODNAM	;[2306] USE DEFAULT IF NOT SET
	HLLZ	T2,JOBNUM	;[2335] SIXBIT JOBNUMBER
	HRRI	T2,'LNK'	;[2335] REST OF PDV NAME
	SKIPN	T3		;[2335] HAVE A NAME
	MOVE	T3,T2		;[2335] NO, USE NNNLNK AS NAME
	MOVEI	T2,1		;[2306] NEED ONE WORD FOR ASCIZ NAME
	TRNE	T3,7777		;[2306] NAME 5 OR 6 CHARACTERS LONG?
	MOVEI	T2,2		;[2306] YES, NEED 2 WORDS FOR ASCIZ NAME
	PUSH	P,T3		;[2306] SAVE THE SIXBIT NAME
	PUSHJ	P,DY.GET##	;[2306] GET SPACE FOR ASCIZ NAME
	POP	P,T3		;[2306] GET THE SIXBIT NAME BACK
	MOVEM	T1,.PVNAM(P1)	;[2306] STORE THE ADDRESS
	HRLM	T2,.PVNAM(P1)	;[2306] AND THE COUNT
	MOVE	T4,T1		;[2306] GET THE ADDRESS	
	HRLI	T4,(POINT 7,)	;[2306] MAKE A BYTE POINTER
	PUSHJ	P,DVDPB.##	;[2306] SIXBIT TO ASCIZ
PVBLD1:	PUSHJ	P,GETPVS	;[2306] FIND OUT WHERE TO PUT IT
	MOVE	T1,RC.HL(P4)	;[1423] PICK UP THE DESTINATION ADDRESS
	MOVEM	T1,PDVADR	;[1423] AND SAVE IT UNTIL LATER
;[2237] Calculate length of memory map here.  Repeated calls to PDVMAP will
;[2237] let us compute the maximum length of the memory map.  Note that the
;[2306] map may actually be slightly larger than we calculate, if the symbol
;[2306] table goes in an empty psect.
	SETZ	W3,		;[2306] INIT. MEMORY MAP LENGTH COUNTER
	SKIPE	NOPDMP		;[2306] DOING A MAP?
	 JRST	PDGTNM		;[2306] NO
	MOVEI	R,1		;[2237] START WITH PSECT 1 (.LOW.)
	SKIPE	NOLOW		;[2247] NEED TO COUNT .LOW.?
	 MOVEI	R,2		;[2247] NO, START WITH SECOND PSECT
PDLOOP:	PUSHJ	P,PDVMAP	;[2237] GO FIND A CONTIGUOUS MEMORY BLOCK
	 JRST	PDGTLN		;[2237] NO MORE, WE HAVE THE LENGTH NOW
	ADDI	W3,MM.SLN	;[2306] FOUND ANOTHER BLOCK, ACCOUNT FOR IT
	JRST	PDLOOP		;[2237] KEEP COUNTING MEMORY MAP ENTRIES

PDGTLN:	SKIPE	R		;[2237] DON'T PUT NULL LAST PSECT INTO MAP
	 ADDI	W3,MM.SLN	;[2306] ACCOUNT FOR LAST CALL TO PDVMAP
	MOVE	T4,RC.IV(P4)	;[2250] GET INITIAL PSECT VALUE
	CAMN	T4,RC.HL(P4)	;[2250] IS THIS CURRENTLY AN EMPTY PSECT?
	 ADDI	W3,MM.SLN	;[2250] YES, IT WON'T BE ONCE PDV IS IN IT
	ADDI	W3,1		;[2361] ACCOUNT FOR MAP LENGTH
	MOVEM	W3,PDMPLN	;[2237] STORE MAP LENGTH FOR USE IN PDVSET
PDGTNM:	HLRZ	T1,.PVNAM(P1)	;[2306] GET THE LENGTH OF THE NAME
	ADD	W3,T1		;[2306] ADD IT TO LENGTH OF MAP 	
	ADDI	W3,PV.LEN	;[2306] ADD LENGTH OF THE PDV AND MAP HEADER
	ADDM	W3,RC.HL(P4)	;[2306] ACCOUNT FOR PDV+NAME+MAP LENGTH
	MOVEM	P4,PVPSEG	;[1423] KEEP TRACK OF THE RELOC COUNTER
	POPJ	P,		;[2237]

;SUBROUTINE TO FIND CONTIGUOUS BLOCKS OF MEMORY WITH THE SAME ATTRIBUTES.
;USED IN BUILDING THE PDV MEMORY MAP, AND TO DETERMINE THE MAP'S LENGTH.
;IF OVERLAPPING PSECTS HAVE CONFLICTING ATTRIBUTES, THEY ARE CONSIDERED TO
;BOTH BE READ-ONLY.
;
;	CALL:	R/	PSECT # TO START SCANNING IT (MUST BE VALID # OR
;			YOU'LL BE SORRY!)
;
;	RETURN:	+1	NO MORE PSECTS, ACS SAME AS +2 RETURN EXCEPT R
;			IS LAST PSECT #+1, OR 0 IF LAST PSECT WAS EMPTY.
;
;		+2	T2/ LOW BLOCK ADDR.
;			T3/ HIGH BLOCK ADDR.
;			T4/ BLOCK ATTRIBUTES (EITHER AT.RO OR 0)
;			R/  NEXT PSECT # THAT'S NOT CONTIGUOUS OR HAS
;			    DIFFERENT ATTRIBUTES AND IS NOT OVERLAPPING
;
;	USED ACS: T2, T3, T4, R, W1, W2
;
PDVMAP:	MOVE	W2,@RC.TB	;[2237] GET PSECT TABLE ADDR.
	MOVE	T2,RC.IV(W2)	;[2237] GET BLOCK (AND THIS PSECT'S) START ADDR
	MOVE	T4,RC.AT(W2)	;[2237] GET ATTRIBUTES
	TXZ	T4,^-AT.RO	;[2237] CLEAR EVERYTHING BUT READ-ONLY BIT
	MOVE	T3,RC.HL(W2)	;[2237] REMEMBER WHERE THIS PSECT ENDS
	CAMLE	T3,T2		;[2237] EMPTY PSECT (START ADDR .LE. END ADDR)?
	 JRST	PDMAP2		;[2237] NOT NULL, JUMP AHEAD
	ADDI	R,1		;[2237] INCREMENT TO NEXT PSECT
	CAMG	R,RC.NO		;[2237] ALL DONE WITH PSECTS?
	 JRST	PDVMAP		;[2237] NO, USE NEXT PSECT AS BLOCK START
	SETZ	R,		;[2237] YES, LAST PSECT IS NULL, CLEAR R
	POPJ	P,		;[2237] TAKE +1 RETURN 

PDMAP1:	MOVE	T3,RC.HL(W2)	;[2237] YES, MAKE IT NEW HIGHEST ADDR. OF BLOCK
PDMAP2:	SUBI	T3,1		;[2237] END ADDR. IS CURRENT ADDR. -1
PDMAP3:	ADDI	R,1		;[2237] INCREMENT TO NEXT PSECT
	CAMLE	R,RC.NO		;[2237] ALL DONE WITH PSECTS?
	 POPJ	P,		;[2237] YES, TAKE +1 RETURN
	MOVE	W2,@RC.TB	;[2237] NO, GET NEXT PSECT TABLE ADDR.
	MOVE	W1,RC.IV(W2)	;[2237] GET NEXT PSECT START ADDR.
	SUBI	W1,1		;[2237] NO, MAKE ADJACENT ADDRESSES EQUAL
	CAMLE	W1,T3		;[2237] IS PSECT ADJACENT OR OVERLAPPING?
	 JRST	CPOPJ1		;[2237] NO, END OF THIS MEMORY MAP ENTRY
	CAML	W1,T3		;[2237] YES, DO THEY OVERLAP?
	 JRST	PDVADJ		;[2237] NO, THEY'RE ADJACENT
	MOVE	W1,RC.AT(W2)	;[2237] YES, GET NEW PSECT'S ATTRIBUTES
	TXZ	W1,^-AT.RO	;[2237] CLEAR EVERYTHING BUT READ-ONLY BIT
	CAME	W1,T4		;[2237] SAME ATTRIBUTES AS LAST PSECT?
	 MOVX	T4,AT.RO	;[2237] NO, MUST BE A CONFLICT - SET BLOCK R.O.
	JRST	PDVCOM		;[2237] JOIN COMMON CODE

PDVADJ:	MOVE	W1,RC.AT(W2)	;[2237] YES, GET NEW PSECT'S ATTRIBUTES
	TXZ	W1,^-AT.RO	;[2237] CLEAR EVERYTHING BUT READ-ONLY BIT
	CAME	W1,T4		;[2237] SAME ATTRIBUTES AS LAST PSECT?
	 JRST	CPOPJ1		;[2237] NO, END OF THIS MEMORY MAP ENTRY
PDVCOM:	CAMGE	T3,RC.HL(W2)	;[2237] YES, IS END ADDR. HIGHER THAN BEFORE?
	 JRST	PDMAP1		;[2237] YES, GO LOAD NEW END ADDR. AND CONTINUE
	JRST	PDMAP3		;[2237] NO, CONTINUE LOOPING THROUGH ALL PSECTS
;GETPVS - ROUTINE TO FIGURE OUT WHERE THE PROGRAM DATA VECTOR GOES.
;RETURNS WITH:
;
;	PVPNAM/		NAME (SIXBIT) OF PSECT TO APPEND PDV TO
;	R/		AREA PSECT IS IN, LC.IX OR HC.IX
;	P4/		POINTER TO RC BLOCK OF PSECT NAMED IN PVPNAM
;	RC.HL(P4)/	FIRST ADDRESS TO STORE THE PDV IN
;	PVPLIM/		LAST ADDRESS TO STORE THE PDV IN
;
;ALSO UPDATES LOWLOC IF NECESSARY.
;CLOSE RESEMBLENCE TO GETSST IS NO COINCIDENCE.

GETPVS:	HLRZ	R,PRGPDV	;[1423] PICK UP DESTINATION
	CAIN	R,-1		;[1423] PSECT?
	JRST	GETP10		;[1423] YES, GO FIND IT
GETP02:	CAIN	R,2		;[1423] /PVBLOCK:HIGH?
	JRST	GETP08		;[1423] YES, TREAT LIKE /PVBLOCK:PSECT:.HIGH.
	CAIN	R,1		;[1423] /PVBLOCK:LOW?
	JRST	GETP03		;[1423] YES
	SKIPE	LL.S2		;[1423] DEFAULT -- IS THERE A HIGH SEG?
	JRST	GETP08		;[1423] YES, PUT THE PDV THERE

;HERE IF /PVBLOCK:LOW
; APPEND THE PROGRAM DATA VECTOR TO THE LAST PSECT IN THE IMAGE.
; OUR FIRST MISSION IS TO FIND THAT PSECT...

GETP03:	SETZB	R,T3		;[1423] INIT HIGHEST ADDR AND PSECT IDX
GETP04:	MOVE	T1,@RC.TB	;[1423] GET POINTER TO RC BLOCK OF NEXT PSECT
	MOVE	T2,RC.SG(T1)	;[1423] GET THE SEGMENT THAT THIS PSECT IS IN
	CAIE	T2,1		;[1423] IN THE LOW SEGMENT?
	JRST	GETP06		;[1423] NO, IT DOESN'T COUNT FOR /PVBLOCK:LOW
	MOVE	T2,RC.HL(T1)	;[1423] GET THE FIRST FREE AFTER THIS PSECT
	CAMG	T2,T3		;[1423] HIGHEST SO FAR?
	JRST	GETP06		;[1423] NO, CONTINUE
	MOVE	T3,T2		;[1423] SAVE NEW BEST
	MOVE	T4,R		;[1423] AND WHAT PSECT IT WAS
	MOVE	T2,RC.NM(T1)	;[1423] GET THE WINNER'S NAME
	MOVEM	T2,PVPNAM	;[1423] STORE FOR ERROR MESSAGES
GETP06:	CAMGE	R,RC.NO		;[1423] ALL DONE?
	AOJA	R,GETP04	;[1423] NO, LOOP
	MOVE	R,T4		;[1423] YES, SAVE PSECT INDEX OF LAST ONE
	JRST	GETP14		;[1423] GO UPDATE THAT PSECT
;HERE ON /PVBLOCK:HIGH.  FAKE /PVBLOCK:PSECT:.HIGH. AND FALL INTO PSECT CODE.

GETP08:	MOVE	T1,['.HIGH.']	;[1423] /PVBLOCK:HIGH IS JUST LIKE A PSECT
	MOVEM	T1,PVPNAM	;[1423] STORE

;HERE ON /PVBLOCK:PSECT:xxxxxx.  FIND THE PSECT IN THE RC TABLES.

GETP10:	SETZ	R,		;[1423] YES, HAVE PSECT NAME
	MOVE	W2,PVPNAM	;[2220] GET THE PDV NAME
GETP12:	MOVE	T1,@RC.TB	;[1423]
	MOVE	T2,RC.NM(T1)	;[2220] GET PSECT NAME
	PUSHJ	P,NAMCMP##	;[2220] IS THIS THE ONE?
	JRST	GETP14		;[1423] YES,
	ADDI	R,1		;[1423] NEXT ONE
	CAMG	R,RC.NO		;[1423] ANY MORE?
	JRST	GETP12		;[1423] YES, LOOP
E$$NPP::.ERR.	(MS,.EC,V%L,L%W,S%W,NPP,<Non-existent psect >)	;[1423]
	.ETC.	(SBX,.EC!.EP,,,,PVPNAM)	;[1423]
	.ETC.	(STR,,,,,,< specified for program data vector>) ;[1423]
	MOVEI	R,1		;[1423] SET TO LOW
	HRLM	R,PRGPDV	;[1423]
	JRST	GETP02		;[1423] AND LOOP BACK
;HERE WITH THE PSECT INDEX TO USE IN R, AND ITS NAME IN PVPNAM.
;NOW CALCULATE THE UPPER BOUND POSSIBLE FOR THE PDV.


;THE NEXT PSECT ORIGIN WE WOULD CROSS, OR STOP AT 777777 IF NO MORE PSECTS.

GETP14:	MOVE	P4,@RC.TB	;[1423] POINTER TO THIS PSECT'S RC BLOCK
	MOVX	T1,AT.RP	;[2247] GET THE RELOCATABLE BIT
	ANDCAM	T1,RC.AT(P4)	;[2247] INDICATE IT EXISTS (IN CASE .LOW.)
	MOVE	T4,RC.HL(P4)	;[1423] ADDR OF FIRST FREE LOCATION
	ADDI	R,1		;[1423] START THE SEARCH AT THE NEXT PSECT
;LOOP BACK HERE ON EACH NEW PSECT, LOOKING FOR ONE WHOSE ORIGIN
;IS .GE. C(T4).
GETP16:	CAMLE	R,RC.NO		;[1423] CHECKED THEM ALL YET?
          JRST	GETP18		;[1423] YES, GO USE 777777
	MOVE	T1,@RC.TB	;[1423] GET PSECT'S RC BLOCK
	MOVE	T2,RC.IV(T1)	;[1423] GET ORIGIN OF THIS PSECT
	CAMGE	T2,T4		;[1423] START ABOVE THE PDV PSECT?
	AOJA	R,GETP16	;[1423] NO, MUST HAVE BEEN OVERLAPPING PSECT
	MOVE	T3,RC.HL(T1)	;[1423] YES, CHECK FOR ZERO-LENGTH PSECT
	CAMG	T3,T2		;[1423] WOULD WE OVERWRITE ANYTHING?
	AOJA	R,GETP16	;[1423] NO, IGNORE THIS PSECT
	SOSA	T2		;[1423] YES, LAST ADDR TO USE IS ONE LESS
GETP18:	HLLO	T2,RC.HL(P4)	;[1450] ROUND UP TO SECTION BOUNDARY
	MOVEM	T2,PVPLIM	;[1423] STORE NEWLY CALCULATED LIMIT

;NOW SET UP SOME FINAL THINGS FOR THE REST OF LINK, THEN RETURN.

GETP20:	MOVE	R,RC.SG(P4)	;[1423] FETCH SEGMENT INDEX FOR PSECTS
	MOVE	T1,RC.HL(P4)	;[1423] START OF PROGRAM DATA VECTOR
	POPJ	P,		;[1423] END OF GETPVS

> ;[1423] IFN TOPS20
;HERE TO READ IN FIRST 10 WORDS OF HIGH SEGMENT

;[2247] Under TOPS-20 just map the first high segment page into the DY area.
;[2247] It is never returned, as there is plenty of memory available,
;[2247] and by the time it could be there won't be anyone who needs it.

RDJBH:
IFE TOPS20,<			;[2247]
	MOVEI	T2,.JBHDA	;NO OF WORDS WE NEED
	PUSHJ	P,DY.GET	;GET THEM
	MOVEM	T1,JBHPTR	;STORE LOCATION
	SUBI	T1,1		;IOWD IS 1 LESS
	HRLI	T1,-10		;SHOULD BE -.JBHDA BUT MACRO 50 NOT YET OUT
	SETZ	T2,		;TERMINATE LIST
	USETI	HC,1		;SET ON BLOCK 1
	IN	HC,T1		;READ FIRST 10 WORDS ONLY
	  POPJ	P,		;OK
	PUSHJ	P,E$$IHC##	;[1174] DIE WITH ERROR
>  ;[1401] IFE TOPS20
IFN TOPS20,<
	MOVEI	T2,2*.IPS	;[2055] 2*.IPS INSURES ONE FULL PAGE
	PUSHJ	P,DY.GET	;[1401]
	IORI	T1,.IPM		;[2247] END OF THIS PAGE
	ADDI	T1,1		;[2247] SET ON PAGE BOUNDARY	
	MOVEM	T1,JBHPTR	;[2247] STORE LOCATION
	LSH	T1,-9		;[1401]
	HRLI	T1,.FHSLF	;[1401] PROCESS IS SELF
	MOVE	T2,T1		;[1401]
	MOVE	T1,LL.S2	;[2247] GET THE HIGH SEGMENT ORIGIN
	LSH	T1,-9		;[2247] IN PAGES
	HRL	T1,HC.JF	;[2247] FORK HANDLE
	MOVE	T3,[PM%RWX]	;[1401] MOVE ONE PAGE FOR READING
	PMAP%			;[1401]
	 ERCAL	E$$IHC##	;[2247] CAN'T DO IT
	POPJ	P,		;[1401] AND RETURN
> ;[1401]  IFN TOPS20

;HERE IF LOWSEG PAGED, WE NEED BOTH ENDS OF FILE AT ONCE
;THEREFORE PUT JOBDAT (0-137) IN DY AREA, POINTER IS JOBPTR
;AND TOP OF FILE IN LC AREA

;[2247] Under TOPS-20 just map the first page into the DY area.
;[2247] It is never returned, as there is plenty of memory available,
;[2247] and by the time it could be there won't be anyone who needs it.

RDJBL:
IFE TOPS20,<
	MOVEI	T2,.JBDA	;NEED ONE BLOCK
	PUSHJ	P,DY.GET
	MOVEM	T1,JOBPTR	;HOLD OFFSET IN CORE SO WE CAN FIXUP
				; REFERENCES TO JOBDAT SYMBOLS
	SKIPN	LW.S1		;HOWEVER IF 1ST PAGE IS IN CORE
	JRST	BLTJBL		;JUST MOVE IT
	SUBI	T1,1		;IOWD IS ONE LESS
	HRLI	T1,-140		;WORD COUNT
	SETZ	T2,		;TERMINATE LIST
	USETI	LC,1		;READ BLOCK 1
	IN	LC,T1		;AT LEAST FIRST 140 WORDS
	  POPJ	P,		;NONE
	PUSHJ	P,E$$ILC##	;[1174] DIE WITH ERROR
> ;[1401] IFE TOPS20
IFN TOPS20,<
	MOVEI	T2,2*.IPS	;[2247] 2*.IPS INSURES ONE FULL PAGE
	PUSHJ	P,DY.GET	;[1401]
	IORI	T1,.IPM		;[2247] END OF THIS PAGE
	ADDI	T1,1		;[2247] SET ON PAGE BOUNDARY	
	MOVEM	T1,JOBPTR	;[2247] HOLD OFFSET IN CORE
	LSH	T1,-9		;[1401]
	HRLI	T1,.FHSLF	;[1401] PROCESS IS SELF
	MOVE	T2,T1		;[1401]
	HRLZ	T1,LC.JF	;[1401] FILEJFN,,PAGE 0
	MOVE	T3,[PM%RWX]	;[1401] MOVE ONE PAGE FOR READING
	PMAP%			;[1401]
	 ERCAL	E$$ILC##	;[2247] CAN'T DO IT
	POPJ	P,		;[2247] RETURN
> ;[1401] IFN TOPS20

IFE TOPS20,<			;[2247]
;HERE TO JUST BLT JOBDAT AREA TO SAFE PLACE
BLTJBL:	HRL	T1,LC.LB	;FROM HERE
	HRRI	T2,.JBDA(T1)	;TO HERE
	BLT	T1,-1(T2)	;WELL ALMOST THERE
	POPJ	P,
SUBTTL	RUNTIME SYMBOL TABLE GENERATION
>;[2247] IFE TOPS20

;HERE TO DECIDE IF WE WANT TO PUT A RUNTIME SYMBOL TABLE INTO THE
;IMAGE, AND IF SO, TO DO IT.  WE WANT A RUNTIME SYMBOL TABLE IF ANY
;OF THE FOLLOWING CONDITIONS ARE TRUE:
;
; 1.	C(.JBDDT) IS NONZERO
; 2.	USER SAID /SYMSEG
; 3.	USER SAID /SYFILE:RADIX50
;
;IF THE USER SAID /NOSYMBOLS, WE NEVER WANT A RUNTIME SYMBOL TABLE.

CHKRST:
IFN TOPS20,<			;[2202]
	SKIPE	NOJBDA		;[2306] JOBDAT NOT WANTED?
	 JRST	CHKRS0		;[2211] YES, NO JOBDAT
	MOVE	T1,JOBPTR	;[2306] POINT TO JOBDAT
> ;IFN TOPS20 [2202]
IFE TOPS20,<			;[2306]
	SKIPE	PAG.S1		;[1172] FIND JOBDAT
	SKIPA	T1,JOBPTR	;[1172] IN DY IF PAGING
	MOVE	T1,LC.LB	;[1172] IN LC AREA IF NOT
>;[2306] IFE TOPS20
	SKIPN	T2,VERNUM	;[1202] /VERSION? (CHECK NOW FOR OLDSYM)
	SKIPA	T2,.JBVER(T1)	;[1202] NO, FETCH FROM .JBVER
	MOVEM	T2,.JBVER(T1)	;[1202] OVERRIDE IF /VERSION
	MOVEM	T2,VERNUM	;[1202] STORE FOR SYMBOL FILES
	SETZM	.JBSYM(T1)	;[1172] ASSUME NO SYMBOLS
	SETZM	.JBUSY(T1)	;[1172]   ..
CHKRS0:	SKIPE	NOSYMS		;[1460] /NOSYMBOLS?
	JRST	NORST		;[1172] YES, FORGET IT
IFN TOPS20,<			;[2202]
	SKIPN	NOJBDA		;[2306] DOES JOBDAT EXIST?
> ;[2202] IFN TOPS20
	SKIPN	.JBDDT(T1)	;[1172] C(.JBDDT) <> 0?
CHKRS1:	SKIPE	SYMSEG		;[2211] OR USER SAY /SYMSEG?
	 JRST	DORST		;[1172] YES, GO DO IT!
	SKIPL	SYMFRM		;[1172] /SYFILE:RADIX50?
	 JRST	NORST		;[1172] NOPE, NO SYMBOL TABLE
;HERE TO GENERATE A RUNTIME SYMBOL TABLE.
;FIRST, MAKE SURE THE AREA (LC/HC) THAT THE SYMBOLS ARE GOING
;INTO IS BIG ENOUGH, OR IS PAGING AND THE RIGHT PAGE IS IN.

DORST:
IFN FTOVERLAY,<
	SKIPL	LNKMAX		;[1172] LOADING OVERLAYS?
	JRST	OVLRST		;[1172] YES, THINGS ARE DIFFERENT
> ;END IFN FTOVERLAY

E$$SST::.ERR.	(MS,0,V%L,L%I,S%I,SST,<Sorting symbol table>) ;[1174]
	PUSHJ	P,GETSST	;[1172] FIND BASE OF SYMBOLS, SET R AND P4
IFE TOPS20,<			;[2335]
	SKIPE	PAG.S0(R)	;[2335] SYMBOL SEGMENT PAGING?
> ;[2335] IFE TOPS20
	JRST	DORST2		;[1172] YES, GO GET THE RIGHT PAGE INTO MEMORY
	MOVE	P2,RC.HL(P4)	;[1172] GET FIRST WORD OF TABLE
	SUB	P2,LL.S0(R)	;[1172] CONVERT TO OFFSET IN SEGMENT
	SUB	P2,LW.S0(R)	;[1172] THENCE TO OFFSET IN WINDOW
	ADD	P2,TAB.LB(R)	;[1172] FIRST ADDRESS WE'RE GOING TO STORE INTO
	CAMG	P2,TAB.AB(R)	;[1172] IS THE AREA BIG ENOUGH?
	JRST	DORST4		;[1172] YES, GO FILL IT IN
	MOVE	P1,R		;[1172] WHICH AREA TO EXPAND
	SUB	P2,TAB.AB(R)	;[1172] HOW MUCH WE NEED
	PUSHJ	P,LNKCOR	;[1172] EXPAND THE AREA
	  JRST	DORST2		;[1172] FINE, JUST START PAGING
	JRST	DORST3		;[1172] GO CHECK PAGING FOR THE FIRST TIME
;HERE IF PAGING TO BRING THE RIGHT LC/HC PAGE INTO MEMORY.

DORST2:	PUSHJ	P,LSYP		;[1172] NOW PAGING, GET RIGHT PAGE IN MEMORY
DORST3:	PUSHJ	P,CHKPAG	;[1172] SEE IF WE JUST STARTED PAGING
DORST4:	MOVE	T1,RC.HL(P4)	;[1172] NOW TO SET UP XX.PT
	SUB	T1,LL.S0(R)	;[1172] FIRST ADDRESS TO STORE INTO
	SUB	T1,LW.S0(R)	;[1172] CONVERT TO OFFSET IN AREA
	ADD	T1,TAB.LB(R)	;[1172] ADDRESS IN AREA
	MOVEM	T1,TAB.PT(R)	;[1172] STORE FOR SYMOUT


;OK, EVERYTHING IS INITIALIZED.  NOW WRITE OUT THE SYMBOL TABLE(S).

	SKIPE	USYM		;[1172] ANY UNDEFINED SYMBOLS?
	PUSHJ	P,DOUDFS	;[1172] YES, WRITE THEM OUT
	PUSHJ	P,GSDLT		;[1172] DELETE THE GS AREA
	SKIPN	SYMFUL		;[1172] IF ANY ROOM LEFT
	PUSHJ	P,DOLOCS	;[1172] WRITE THE LOCAL SYMBOLS OUT


;THE SYMBOLS HAVE BEEN WRITTEN.  NOW UPDATE THE HL/HC WORDS, THEN GO CLEAN UP.

	MOVE	T1,TAB.PT(R)	;[1172] NEXT FREE WORD
	SUB	T1,TAB.LB(R)	;[1172] OFFSET IN WINDOW
	ADD	T1,LW.S0(R)	;[1172] OFFSET IN SEGMENT
	CAMLE	T1,HL.S0(R)	;[1172] BIGGEST WE'VE SEEN?
	MOVEM	T1,HL.S0(R)	;[1172] YES, STORE IT
	CAMLE	T1,HC.S0(R)	;[1172] BIGGEST LOADED LOC?
	MOVEM	T1,HC.S0(R)	;[1172] YES, STORE IT
	ADD	T1,LL.S0(R)	;[1172] FORM VIRTUAL ADDRESS
	CAMLE	T1,RC.HL(P4)	;[1172] BIGGEST YET FOR THIS PSECT?
	MOVEM	T1,RC.HL(P4)	;[1172] YES, REMEMBER IT

;[2306] Here to set up the symbol vector

IFN TOPS20,<			;[2366]
	SKIPN	T2,PRGPDV	;[2306] Get the pointer to the PDV
	JRST	SYMVNO		;[2306] No PDV, so no symbol vector
	MOVE	W1,.PVSYM(T2)	;[2306] Get the symbol table vector address
>;[2366] IFN TOPS20
IFE TOPS20,<			;[2366]
	SKIPN	W1,SYMVEC	;[2366] Building a symbol vector?
	 JRST	SYMVNO		;[2366] No
>;[2366] IFE TOPS20
	SUB	W1,LL.S0(R)	;[2311] Subtract the segment base
	MOVE	W2,W1		;[2306] Get the address
	ADDI	W2,SV.LEN-1	;[2306] Last address needed
	CAMG	W2,TAB.UW(R)	;[2306] Is it above the window?
	CAMGE	W1,TAB.LW(R)	;[2306] Is it below the window?
	 CAIA			;[2306] Must move window
	 JRST	SYMVST		;[2306] No, no need to move window
	MOVE	T1,TAB.LW(R)	;[2306] Get current lower bound
	MOVE	T2,TAB.UW(R)	;[2306] And upper bound
	PUSHJ	P,@[LC.OUT##	;[2306] Remove it
		    HC.OUT##]-1(R) ;[2306] From the window
	MOVE	T1,W1		;[2306] Get the bottom address
	TRZ	T1,.IPM		;[2306] Put it on a page bound
	MOVEM	T1,TAB.LW(R)	;[2306] Set the bottom of the window
	TRO	W2,.IPM		;[2306] Set to top of page
	MOVE	T2,W2		;[2306] Get the high address
	SUB	T2,T1		;[2306] Get the size
	ADD	T2,TAB.LB(R)	;[2306] Get the high address in memory
	CAMG	T2,TAB.AB(R)	;[2306] Will it fit?
	 JRST	SYMVGT		;[2306] Yes, just go get it
	PUSH	P,T2		;[2306] Save the upper bound
	SUB	T2,TAB.AB(R)	;[2306] How much is needed
	MOVE	P1,R		;[2306] Get the index
	MOVE	P2,T2		;[2306] And the amound needed
	PUSHJ	P,LNKCOR##	;[2306] Try and get it
	 PUSHJ	P,E$$MEF##	;[2306] Only wanted a maximum 2 pages
	POP	P,T2		;[2306] Restore the upper bound
SYMVGT:	MOVEM	T2,TAB.AB(R)	;[2306] Save the upper bound
	MOVEM	W2,TAB.UW(R)	;[2306] And the size
	MOVE	T1,TAB.LW(R)	;[2306] Get the lower bound
	MOVE	T2,TAB.UW(R)	;[2306] And the upper bound
	PUSHJ	P,@[LC.IN##	;[2306] Get it
		    HC.IN##]-1(R) ;[2306] Into window
SYMVST:	SUB	W1,TAB.LW(R)	;[2306] Get the offset into the window
	ADD	W1,TAB.LB(R)	;[2306] Unrelocate
	MOVEI	T1,SV.LEN	;[2306] Get the symbol vector length
	MOVEM	T1,(W1)		;[2306] Store it
	MOVE	T1,DSTADR	;[2366] Get the address of the defined symbols
IFN TOPS20,<			;[2366]
	MOVE	T2,FXSBIT	;[2306] Get the section bits
	TXNN	T2,^-1B0	;[2306] Any non-zero sections?
	 HRLI	T1,(IFIW)	;[2306] No, make it an IFIW
>;[2366] IFN TOPS20
	MOVEM	T1,2(W1)	;[2306] Store the defined address
	SKIPN	USTADR		;[2306] Any undefined symbols?
	 JRST	SYMVS1		;[2306] No
	MOVE	T1,USTADR	;[2306] Yes, get the undefined symbol address
IFN TOPS20,<			;[2366]
	TXNN	T2,^-1B0	;[2306] Any non-zero sections?
	 HRLI	T1,(IFIW)	;[2306] No, make it an IFIW
>;[2366] IFN TOPS20
SYMVS1:	MOVEM	T1,SV.SLN+2(W1)	;[2306] Store the undefined address
	MOVE	T1,DSYCNT	;[2306] Get the defined symbol count
	TXO	T1,FLD(.R50D,ST%TYP) ;[2306] Set Radix 50 defined type
	MOVEM	T1,1(W1)	;[2306] Store the count and zero third word
	MOVE	T1,USYCNT	;[2306] Get the undefined symbol count
	TXO	T1,FLD(.R50U,ST%TYP) ;[2306] Set Radix 50 undefined type
	MOVEM	T1,SV.SLN+1(W1)	;[2306] Store it
	SETZM	3(W1)		;[2306] Zero the defined table third word
	SETZM	SV.SLN+3(W1)	;[2306] Zero the undefined table third word
SYMVNO:
	SKIPGE	SYMFRM		;[1172] OLD STYLE SYMBOL FILE WANTED?
	PUSHJ	P,OLDSYM	;[1172] YES, WRITE IT OUT
E$$STC::.ERR.	(MS,0,V%L,L%I,S%I,STC,<Symbol table completed>) ;[1174]
	JRST	FINRST		;[1172] GO JOIN COMMON CLEAN UP CODE
;HERE WHEN LOADING OVERLAYS.

IFN FTOVERLAY,<
OVLRST:	HLRE	T2,PH+PH.RDX	;[1400] GET - NO. OF SYMBOLS
	MOVM	T3,T2		;[1172] +
	ADD	T3,HL.S1	;[1172] HIGHEST LOCATION
	ADD	T3,SPACE	;[1172] PLUS BUFFER SPACE
	IOR.	T3,.PGSIZ	;[1172] UP TO PAGE BOUND
	ADDI	T3,1		;[1172] NEXT FREE
	ADD	T3,T2		;[1172] START OF SYMBOLS
	HLL	T3,PH+PH.RDX	;[1400] - COUNT
	MOVEM	T3,JOB116	;[1172] STORE IN INTERNAL PTR
	MOVEM	T3,.JBSYM(T1)	;[1172] STORE SYMBOL TABLE PTR

IFN TOPS20,<			;[2247] Read symbols now on TOPS-20
	MOVM	P1,T2		;[2247] Get count of symbols
	HRRZ	P2,T3		;[2247] Save the base address
	MOVE	P3,LS.LB	;[2247] Get the start of the symbols
OVLRS1:	MOVE	T1,LW.LC	;[2247] Get the lower bound
	MOVE	T2,UW.LC	;[2247] And the upper bound
	PUSHJ	P,LC.OUT##	;[2247] Remove it from memory
	HRRZ	T1,P2		;[2247] Get base address
	TRZ	T1,.IPM		;[2247] Put it on a page boundary
	HRRZ	T2,P1		;[2247] Get the size wanted
	MOVE	T3,LC.AB	;[2247] Get the top
	SUB	T3,LC.LB	;[2247] Get the size available
	CAMLE	T2,T3		;[2247] We need less than we have?	
	MOVE	T2,T3		;[2247] No, use what we have
	ADD	T2,T1		;[2247] Get the max address
	IORX	T2,.IPM		;[2247] Set at end of a page boundary
	MOVEM	T1,LW.LC	;[2247] Store the new lower bound
	MOVEM	T2,UW.LC	;[2247] And the new upper
	PUSHJ	P,LC.IN##	;[2247] Get it
	MOVE	T3,P2		;[2247] Get the base address
	SUB	T3,LW.LC	;[2247] Minus the window
	ADD	T3,LC.LB	;[2247] Locate in memory
	HRRZ	T1,T3		;[2247] Destination for BLT
	HRL	T1,P3		;[2247] Source for BLT
	ADDI	T3,-1(P1)	;[2247] How far we want to go
	MOVE	T2,T3		;[2247] Use as last to load
	CAMLE	T2,LC.AB	;[2247] More than we have
	MOVE	T2,LC.AB	;[2247] Yes, do what we can
	BLT	T1,(T2)		;[2247] Copy it
	MOVE	T2,UW.LC	;[2247] No, Get highest location done
	SUBI	T2,-1(P2)	;[2247] Figure out how much was done
	SUB	P1,T2		;[2247] Reduce the count by that much
	JUMPLE	P1,NORST	;[2247] Check for none left (done)
	ADD	P2,T2		;[2247] Where to copy to next
	ADD	P3,T2		;[2247] Where to copy from next
	JRST	OVLRS1		;[2247] Copy some more
>;[2247] IFN TOPS20
> ;END IFN FTOVERLAY


;HERE IF NOT WRITING A RUNTIME SYMBOL TABLE.  JUST DELETE LINK'S TABLES.

NORST:	PUSHJ	P,GSDLT		;[1172] GET RID OF THE GS AREA

;ALL PATHS REJOIN HERE.  DELETE TABLES, SET UP JOBDAT, AND EXIT.

FINRST:	SKIPLE	T1,SYMFRM	;[1172] WANT NEW STYLE SYMBOL FILE?
	PUSHJ	P,SAVSYM	;[1172] YES, WRITE IT OUT
	PUSHJ	P,AS.ZAP	;[1172] DONE WITH AS AREA
	MOVEI	T1,AC		;[1172] ALGOL SYMS CHANNEL
	SKIPE	PAG.AS		;[1172] AREA PAGING?
	PUSHJ	P,DVDEL.##	;[1172] YES, DELETE OVERFLOW FILE
	  JFCL			;[1172] DON'T CARE
	PUSHJ	P,FX.ZAP	;[1172] DONE WITH FX AREA

IFN FTOVERLAY,<
	SKIPL	LNKMAX		;[1172] LOADING OVERLAYS?
	JRST	FINRS2		;[1172] YES, SAVE LS AREA
> ;END IFN FTOVERLAY

	PUSHJ	P,LS.ZAP	;[1172] KILL OFF THE LS AREA
	MOVEI	T1,SC		;[1172] LS OVERFLOW CHANNEL
	SKIPE	PAG.LS		;[1172] LS AREA PAGING?
	PUSHJ	P,DVDEL.##	;[1172] YES, DELETE OVERFLOW FILE
	  JFCL			;[1172] WASN'T PAGING


;NOW UPDATE JOBDAT, THEN EXIT VIA SAVTST.

FINRS2:
IFN TOPS20,<
	SKIPE	PRGPDV		;[1423] CREATE A PDV?
	PUSHJ	P,PDVSET	;[1423] YES
> ;[2260]
	SKIPE	PAG.S1		;[2241] LC AREA PAGING?
	SKIPA	P1,JOBPTR	;[2241] YES, JOBDAT IS IN DY
	MOVE	P1,LC.LB	;[2241] NO, IT'S IN LC
	SKIPE	PAG.S2		;[2241] HC AREA?
	SKIPA	P2,JBHPTR	;[2241] YES, FETCH DY PTR
	MOVE	P2,HC.LB	;[2241] NO, FETCH HC PTR (OR 0)

;COMPUTE ADDRESS AT WHICH TO START PROGRAM. IF A DEBUGGER IS LOADED, THIS IS
;NOT NECESSARILY THE MAIN PROGRAM'S START ADDRESS, BUT DEPENDS ON THE DEBUGGER.

	SETZ	T1,		;[2211] ASSUME WE DON'T START PROGRAM
	SKIPE	EXECSW		;[2211] GO INTO EXECUTION?
	MOVE	T1,STADDR	;[2211] YES, ASSUME .JBSA
	HRRZ	T2,DEBUGSW	;[2211] IF DEBUGGING, DEBUGGER'S START ADDRESS
	SKIPGE	DEBUGSW		;[2211]   TAKES PRIORITY SO
	MOVE	T1,@STLOCN(T2)	;[2211]   FIND IT
	HRRM	T1,EXECSW	;[2211] IN ANY CASE STORE BACK IN EXECSW

IFN	TOPS20,<		;[2366]
	MOVE	T1,FXSBIT	;[2211] GET SECTION BITS
	SKIPE	NOJBDA		;[2306] JOBDAT NOT WANTED
	 JRST	JOBST9		;[2260] YES, DON'T BOTHER WITH JOBDAT
>;[2366] IFN TOPS20
;SUBTTL SET UP JOBDAT AREA
;HERE TO SET UP THE REST OF THE JOBDAT AREA. ENTER WITH P1 POINTING TO JOBDAT
;AREA AND P2 TO VESTIGIAL JOBDAT (0 IF NO HIGH SEGMENT).

IFE TOPS20,<			;[2366]

;[2366] If this is an extended addressing program, then the values must
;[2366] reflect section zero only.  It is necessary to figure out what
;[2366] those values are.

	MOVE	T1,HL.S1	;[2366] Get the highest loaded
	MOVE	T2,HC.S1	;[2366] And the highest code
	TLNN	T1,-1		;[2366] Extended addressing?
	 JRST	FINRS3		;[2366] No, no problem
	MOVEI	R,1		;[2366] Start at first psect (ignore .abs.)
	SETZ	T1,		;[2366] Init highest loaded
	MOVEI	T3,777777	;[2366] Highest location were psect can start
	MOVEI	T4,2		;[2366] Index for high segment

FNDSZP:	MOVE	W1,@RC.TB	;[2366] Get pointer to next psect
	CAMN	T4,RC.SG(W1)	;[2366] High segment?			
	 JRST	FNDSZ1		;[2366] Yes, ignore it
	CAMGE	T3,RC.IV(W1)	;[2366] Start outside section zero?
	 JRST	FNDSZ1		;[2366] Yes, ignore
	CAMGE	T1,RC.HL(W1)	;[2366] Higher than what we have?
	 MOVE	T1,RC.HL(W1)	;[2366] Yes, new highest
FNDSZ1:	CAMGE	R,RC.NO		;[2366] Looked at all psects?
	AOJA	R,FNDSZP	;[2366] No, look at next
	CAILE	T1,777777	;[2366] High psect cross section?
	 MOVEI	T1,777777	;[2366] Yes UGLY, but only want section zero 
	MOVE	T2,T1		;[2366] Use highest loaded as highest code

FINRS3:	PUSH	P,HL.S1		;[2366] Keep the actual values
	PUSH	P,HC.S1		;[2366] of high loaded and high code
	MOVEM	T1,HL.S1	;[2366] Set up only section zero numbers
	MOVEM	T2,HC.S1	;[2366] For JOBDAT
>;[2366] IFE TOPS20

	SKIPE	T2,HC.S1	;[2211] GET HIGHEST DATA LOCATION LOADED
	SUBI	T2,1		;[2211] MAKE IT HIGHEST LOC LOADED
IFN FTOVERLAY,<			;[2211] 
	SKIPL	LNKMAX		;[2211] LOADED ANY OVERLAYS?
	SKIPN	T1,JOB116	;[2211] AND SAVED SYMBOLS?
	JRST	.+4		;[2211] NO
	HLRE	T2,T1		;[2211] -LENGTH
	MOVM	T2,T2		;[2211] 
	ADDI	T2,-1(T1)	;[2211] HIGHEST LOCATION
>				;[2211] 
	HRLZM	T2,.JBCOR(P1)	;[2211] PUT  HIGHEST LOC IN LEFT HALF
	HRRZ	T2,HL.S1	;[2211] GET HIGHEST LOC REQUIRED
	HRL	T2,STADDR	;[2211] GET STARTING ADDRESS
	MOVSM	T2,.JBSA(P1)	;[2211] SET .JBSA AND .JBFF
	HRRZM	T2,.JBFF(P1)	;[2211] INCASE RESET NOT DONE FIRST
	IOR.	T2,.PGSIZ	;[2211] INCLUDE ALL OF THIS PAGE
	HRRZM	T2,.JBREL(P1)	;[2211] SET .JBREL
	MOVSI	T2,(HALT)	;[2211] PUT A HALT IN .JB41
	SKIPN	.JB41(P1)	;[2211] UNLESS ALREADY SETUP
	MOVEM	T2,.JB41(P1)	;[2211] 
	MOVE	T2,.JBSYM(P1)	;[2211] GET SYMBOL TABLE POINTER
	HRRZ	T1,T2		;[2211] GET POINTER
	JUMPE	P2,JOBST0	;[2211] NO HIGH SEG POSSIBLE
	CAML	T1,LL.S2	;[2211] SEE IF IN HIGH SEG
	MOVEM	T2,.JBHSM(P2)	;[2211] STORE IN HIGH SEG DATA AREA
	SKIPE	T1,HL.S2	;[2211] GET HIGHEST LOC +1
	SUBI	T1,1		;[2211] HIGHEST LEGAL ADDRESS
	ADD	T1,LL.S2	;[2211] PLUS ORIGIN
	IOR.	T1,.PGSIZ	;[2211] PUT ON PAGE BOUND
	SKIPN	T2,HL.S2	;[2211] LENGTH TO SAVE
	JRST	JOBST1		;[2211] NONE?
	SKIPN	.JBDDT##(P1)	;[2211] DDT LOADED?
	JRST	JOBST1		;[2211] NO, NUMBER IS OK
	SUBI	T2,1		;[2211] YES, BE LIKE MONITOR
	IOR.	T2,.PGSIZ	;[2211] ROUND UP TO TOP OF PAGE
	ADDI	T2,1		;[2211] THENCE TO BOTTOM OF NEXT
JOBST1:	HRL	T1,T2		;[2211] LENGTH TO SAVE,,HIGHEST ADDR
	MOVEM	T1,.JBHRL(P1)	;[2211] LENGTH,,HIGHEST ADDRESS
JOBST0:	MOVE	T1,.JBERR	;[2211] GET  NO OF PREVIOUS ERRORS
	MOVEM	T1,.JBERR(P1)	;[2211] COUNT AS EXECUTION ERRORS
	HRRZM	T1,ERRNO	;[2070] PROHIBIT EXECUTION IF NON-ZERO
	PUSHJ	P,HJBSET	;[1172] VESTIGAL JOBDAT

IFE TOPS20,<			;[2366]
	POP	P,HC.S1		;[2366] Restore actual highest code
	POP	P,HL.S1		;[2366] And highest loaded
>;[2366] IFE TOPS20

	JRST	SAVTST		;[1172] DONE WITH CHKRST, GO CHECK /SAVE

IFN TOPS20,<			;[2366]
JOBST9:	MOVE	T1,.JBERR	;[2260] GET # OF PREVIOUS ERRORS
	HRRZM	T1,ERRNO	;[2260] PROHIBIT EXECUTION IF NON-ZERO
	JRST	SAVTST		;[2260]
>;[2366] IFN TOPS20

;TABLE OF WHERE TO START FOR EACH DEBUGGER

DEFINE KEYMAC(A,B)<
  XALL					;;[2211] GIVE A GOOD LISTING
  IFIDN <A><DEB>,<			;;[2211] SELECT ONLY DEBUGGING KEYWORDS
    %%1==-1				;;[2211] SKIP DUMMY ENTRY
    IRP B,<				;;[2211] CHECK EACH KEYWORD
      IFGE %%1,<			;;[2211]   THAT IS NOT THE DUMMY
        IFN <%%1&1>,<			;;[2211]   AND IS A DEBUGGER NAME
          %%2==0			;;[2211] ASSUME WON'T FIND A DEBUGGER
          IFN TOPS20,<			;;[2211] TOPS-20 UDDT IS SPECIAL
            IFIDN <B><DDT>,<		;;[2211] CHECK FOR DDT DEBUGGER
	[770000]		;UDDT STARTS AT 770000
	DEB$DDT==%%1_<-1>	;[2363] SET UP A SYMBOLIC NAME
              %%2==1			;;[2211] REMEMBER WE FOUND A DEBUGGER
            >
          >
          IFIDN <B><FORDDT>,<		;;[2211] FORDDT IS SPECIAL
	STADDR			;FORDDT FORCES START ADDRESS TO ITSELF
            %%2==1			;;[2211] REMEMBER WE FOUND A DEBUGGER
          >
          IFIDN <B><COBDDT>,<		;;[2211] COBDDT IS SPECIAL
	STADDR			;COBDDT GETS CONTROL FROM COBOL PROGRAM
            %%2==1			;;[2211] REMEMBER WE FOUND A DEBUGGER
          >
	  IFIDN <B><ALGDDT>,<		;;[2211] ALGDDT IS SPECIAL
	.JBREN(P1)		;[2211] ALGDDT STARTS FROM REENTER ADDRESS
	    %%2==1			;;[2211] REMEMBER WE FOUND A DEBUGGER
	  >
	  IFIDN <B><SIMDDT>,<		;;[2211] SIMDDT IS SPECIAL
	.JBREN(P1)		;[2211] SIMDDT STARTS FROM REENTER ADDRESS
	    %%2==1			;;[2211] REMEMBER WE FOUND A DEBUGGER
	  >
          IFIDN <B><PASDDT>,<		;;[2211] PASDDT IS SPECIAL
	STADDR			;[2211] PASDDT FORCES START ADDRESS TO ITSELF
            %%2==1			;;[2211] REMEMBER WE FOUND A DEBUGGER
          >
          IFE %%2,<			;;[2211] IF IT WASN'T ABOVE DEBUGGERS
	.JBDDT(P1)		;OTHER DEBUGGERS SET .JBDDT
          >
        >
      >
      %%1==%%1+1			;;[2211] ADVANCE TO NEXT ENTRY
    >
  >
  PURGE %%1,%%2				;;[2211] CLEAN UP AFTERWARD
  SALL					;;[2211]   ..
>

STLOCN:	KEYWORDS
;GETSST - ROUTINE TO FIGURE OUT WHERE THE SYMBOL TABLE GOES
;CALLED ONLY WHEN A RUNTIME SYMBOL TABLE IS DEFINITELY NEEDED.
;RETURNS WITH:
;
;	SSGNAM/		NAME (SIXBIT) OF PSECT TO APPEND SYMBOLS TO
;	R/		AREA PSECT IS IN, LC.IX OR HC.IX
;	P4/		POINTER TO RC BLOCK OF PSECT NAMED IN SSGNAM
;	RC.HL(P4)/	FIRST ADDRESS TO STORE A SYMBOL IN
;	SYMLIM/		LAST ADDRESS TO STORE A SYMBOL IN
;
;ALSO UPDATES LOWLOC IF NECESSARY.

GETSST:	SKIPGE	R,SYMSEG	;[1172] /SYMSEG TO A PSECT?
	JRST	GETS10		;[1132] YES, GO FIND IT
GETS2:	CAIN	R,2		;[1172] /SYMSEG:HIGH?
	JRST	GETS8		;[1172] YES, TREAT IT LIKE /SYMSEG:PSECT:.HIGH.


;HERE IF /SYMSEG:LOW OR NO /SYMSEG (E.G., C(.JBDDT<>0).
;WE WANT TO APPEND PAT.. AND THE SYMBOL TABLE TO THE LAST PSECT IN THE IMAGE.
;OUR FIRST MISSION IS TO FIND THAT PSECT...

	SETZB	R,T3		;[1172] INIT HIGHEST ADDR AND PSECT IDX
GETS4:	MOVE	T1,@RC.TB	;[1172] GET POINTER TO RC BLOCK OF NEXT PSECT
	MOVE	T2,RC.SG(T1)	;[1172] GET THE SEGMENT THAT THIS PSECT IS IN
	CAIE	T2,1		;[1172] IN THE LOW SEGMENT?
	JRST	GETS6		;[1172] NO, IT DOESN'T COUNT FOR /SYMSEG:LOW
	MOVE	T2,RC.HL(T1)	;[1172] GET THE FIRST FREE AFTER THIS PSECT
	CAMG	T2,T3		;[1132] HIGHEST SO FAR?
	JRST	GETS6		;[1132] NO, CONTINUE
	MOVE	T3,T2		;[1132] SAVE NEW BEST
	MOVE	T4,R		;[1132] AND WHAT PSECT IT WAS
	MOVE	T2,RC.NM(T1)	;[1172] GET THE WINNER'S NAME
	MOVEM	T2,SSGNAM	;[1172] STORE FOR ERROR MESSAGES
GETS6:	CAMGE	R,RC.NO		;[1132] ALL DONE?
	AOJA	R,GETS4		;[1132] NO, LOOP
	MOVE	R,T4		;[1132] YES, SAVE PSECT INDEX OF LAST ONE
	JRST	GETS14		;[1132] GO UPDATE THAT PSECT
;HERE ON /SYMSEG:HIGH.  FAKE /SYMSEG:PSECT:.HIGH. AND FALL INTO PSECT CODE.

GETS8:	MOVE	T1,['.HIGH.']	;[1132] /SYMSEG:HIGH IS JUST LIKE A PSECT
	MOVEM	T1,SSGNAM	;[1132] STORE


;HERE ON /SYMSEG:PSECT:xxxxxx.  FIND THE PSECT IN THE RC TABLES.

GETS10:	SETZ	R,		;[727] YES, HAVE PSECT NAME
	MOVE	W2,SSGNAM	;[2220] GET THE SYMBOL TABLE PSECT NAME
GETS12:	MOVE	T1,@RC.TB	;[1132]
	MOVE	T2,RC.NM(T1)	;[2220] GET PSECT NAME
	PUSHJ	P,NAMCMP##	;[2220] IS THIS THE ONE?
	JRST	GETS14		;[1132] YES,
	ADDI	R,1		;[715] NEXT ONE
	CAMG	R,RC.NO		;[715] ANY MORE?
	JRST	GETS12		;[1132] YES, LOOP
E$$NPS::.ERR.	(MS,.EC,V%L,L%W,S%W,NPS,<Non-existent psect >)	;[1110] ;[1174]
	.ETC.	(SBX,.EC!.EP,,,,SSGNAM)	;[1174] OUTPUT PSECT NAME
	.ETC.	(STR,,,,,,< specified for symbol table>) ;[1174]
	MOVEI	R,1		;[1132] SET TO LOW
	MOVEM	R,SYMSEG	;[1132]
	JRST	GETS2		;[1132] AND LOOP BACK
;HERE WITH THE PSECT INDEX TO USE IN R, AND ITS NAME IN SSGNAM.
;WE NOW WANT TO CALCULATE HOW FAR THE SYMBOL TABLE IS ALLOWED TO EXTEND.
;BELIEVE THE USER'S /UPTO SWITCH IF HE GAVE ONE, OTHERWISE STOP ONE BELOW
;THE NEXT PSECT ORIGIN WE WOULD CROSS, OR STOP AT 777777 IF NO MORE PSECTS.

GETS14:
	MOVE	P4,@RC.TB	;[1172] POINTER TO THIS PSECT'S RC BLOCK
	MOVX	T1,AT.RP	;[2247] GET THE RELOCATABLE BIT
	ANDCAM	T1,RC.AT(P4)	;[2247] INDICATE IT EXISTS (IN CASE .LOW.)
	SKIPE	SYMLIM		;[1172] USER TYPE /UPTO?
	JRST	GETS20		;[1172] YES, BELIEVE IT
	MOVE	T4,RC.HL(P4)	;[1172] ADDR OF START OF PATCH AREA
	ADDI	R,1		;[1172] START THE SEARCH AT THE NEXT PSECT


;LOOP BACK HERE ON EACH NEW PSECT, LOOKING FOR ONE WHOSE ORIGIN
;IS .GE. C(T4).

GETS16:	CAMLE	R,RC.NO		;[1172] CHECKED THEM ALL YET?
	JRST	GETS18		;[1172] YES, GO USE 777777
	MOVE	T1,@RC.TB	;[1172] GET PSECT'S RC BLOCK
	MOVE	T2,RC.IV(T1)	;[1172] GET ORIGIN OF THIS PSECT
	CAMGE	T2,T4		;[1172] START ABOVE THE SYMSEG PSECT?
	AOJA	R,GETS16	;[1172] NO, MUST HAVE BEEN OVERLAPPING PSECT
	MOVE	T3,RC.HL(T1)	;[1172] YES, CHECK FOR ZERO-LENGTH PSECT
	CAMG	T3,T2		;[1172] WOULD WE OVERWRITE ANYTHING?
	AOJA	R,GETS16	;[1172] NO, IGNORE THIS PSECT
	SOSA	T2		;[1172] YES, LAST ADDR TO USE IS ONE LESS
GETS18:
	SOS	T2,RC.LM(P4)	;[1454] ROUND UP TO SECTION BOUNDARY
	MOVEM	T2,SYMLIM	;[1172] STORE NEWLY CALCULATED LIMIT


;NOW SET UP SOME FINAL THINGS FOR THE REST OF LINK, THEN RETURN.

GETS20:	MOVE	R,RC.SG(P4)	;[1172] FETCH SEGMENT INDEX FOR PSECTS
	MOVE	T1,RC.HL(P4)	;[1172] START OF PATCH AREA
IFN TOPS20,<			;[2306]
	SKIPN	T2,PRGPDV	;[2306] WANT A PDV?
	 JRST	GETS22		;[2335] NO, DON'T HAVE TO ALLOW FOR SIZE
	MOVEM	T1,.PVSYM(T2)	;[2306] YES, REMEMBER IT'S ADDRESS
>;[2366] IFN TOPS20
IFE TOPS20,<			;[2366]
	SETZM	SYMVEC		;[2366] NOT BUILDING A SYMBOL VECTOR (YET)
	MOVE	T2,HL.S1	;[2366] GET THE HIGHEST LOADED
	TLNN	T2,-1		;[2366] LOADED OUTSIDE SECTION ZERO?
	 JRST	GETS22		;[2366] NO, DON'T HAVE SYMBOL VECTOR
	MOVEM	T1,SYMVEC	;[2366] YES, REMEMBER IT'S ADDRESS
>;[2366] IFE TOPS20
IFN TOPS20,<			;[2366]
	MOVEI	T2,MM.SLN	;[2306] GET THE SIZE OF A PSECT
	SKIPN	NOPDMP		;[2336] WANT DEFAULT MAP?
	CAMLE	T1,RC.IV(P4)	;[2306] EMPTY PSECT?
	 JRST	GETS21		;[2306] NO, NO PROBLEM
	MOVEI	T2,MM.SLN	;[2306] YES, GET THE SIZE OF A MAP ENTRY
	 ADDM	T2,PDMPLN	;[2306] ADD TO SIZE OF MAP
	MOVE	T1,PVPSEG	;[2306] GET THE RC POINTER FOR THE PDV PSECT
	 ADDM	T2,RC.HL(T1)	;[2306] ACCOUNT FOR ANOTHER PSECT
>;[2366] IFN TOPS20
GETS21:	MOVEI	T1,SV.LEN	;[2306] SIZE OF SYMBOL VECTOR
	ADDB	T1,RC.HL(P4)	;[2306] UPDATE SIZE OF PSECT
GETS22:	MOVEM	T1,PATLOC	;[2366] REMEMBER FOR RST
	ADD	T1,PATSPC	;[1172] START OF REAL SYMBOL TABLE
	MOVEM	T1,RC.HL(P4)	;[1172] UPDATE SIZE OF PSECT
IFE TOPS20,<			;[2247]
	TRZ	T1,777		;[1172] ROUND DOWN TO PAGE BOUND
	CAMGE	T1,LOWLOC	;[1172] LOWEST LOCATION YET LOADED?
	MOVEM	T1,LOWLOC	;[1172] YES, SAVE FOR EXE FILE WRITER.
>;[2247] IFE TOPS20
	POPJ	P,		;[1172] END OF GETSST
;HERE IF PAGING TO SETUP LC/HC AREA TO INSERT SYMBOLS INTO.
;WRITE OUT ENTIRE WINDOW, THEN SET UP LAST PAGE ONLY.
;AREA WILL EXPAND AS REQUIRED IN SYMOUT.

LSYP:	MOVE	T1,LW.S0(R)	;[2202] BOTTOM OF WINDOW
	MOVE	T2,UW.S0(R)	;[2202] TOP
	PUSHJ	P,@TB.OUT##(R)	;[1172] WRITE ENTIRE WINDOW TO DISK
IFE TOPS20,<
	MOVE	T1,TAB.AB(R)	;[1172] REDUCE WINDOW TO ONE PAGE
	ANDCMI	T1,.IPM		;[1172] NEW BOTTOM OF AREA
	SUBI	T1,1		;[1172] FIRST WORD BELOW NEW BASE
	CAML	T1,TAB.LB(R)	;[1172] AREA ALREADY ONE PAGE?
	PUSHJ	P,GBCK.L##	;[1172] NO, SHRINK IT DOWN
> ;[1401] IFE TOPS20
IFN TOPS20,<
	MOVE	T1,TAB.LB(R)	;[1401] SHRINK WINDOW TO ONE PAGE
	ADDI	T1,.IPS-1	;[1401]
	MOVEM	T1,TAB.AB(R)	;[1401]
> ;[1401] IFN TOPS20
	MOVE	T2,RC.HL(P4)	;[2202] GET FIRST ADDR TO STORE A SYMBOL IN
	SUB	T2,LL.S0(R)	;[2202] RELATIVE TO SEGMENT START
	ANDCMI	T2,.IPM		;[2202] NEW BOTTOM OF WINDOW
	MOVEM	T2,LW.S0(R)	;[2202] STORE
	IORI	T2,.IPM		;[2202] NEW TOP OF WINDOW
IFE TOPS20,<
	CAMN	T2,UW.S0(R)	;[2202] WHERE IT WAS ALREADY?
	POPJ	P,		;[2202] YES, DONE
> ;[1401] IFE TOPS20
	MOVEM	T2,UW.S0(R)	;[2202] NO, MUST READ IN THE DATA
	MOVE	T1,LW.S0(R)	;[2202] GET THE UPPER BOUND
	PJRST	@TB.IN(R)	;[1172] READ IN DATA AND RETURN
;HERE TO WRITE THE UNDEFINED SYMBOL TABLE.  THE TABLE IS GENERATED
;BY SCANNING THE GLOBAL SYMBOL TABLE LOOKING FOR UNDEFINED SYMBOLS.
;WE GENERATE ONE RADIX50 PAIR FOR EACH UNDEFINED SYMBOL, AND ADDITIONAL
;PAIRS IF ANY ADDITIVE FIXUPS ARE ENCOUNTERED.
;
;THE ONLY FIXUP TYPES HANDLED ARE ADDITIVE AND RIGHT AND LEFT HALF CHAINED.
;OTHER TYPES, SUCH AS SYMBOL FIXUPS AND POLISH, ARE DISCARDED HERE.  THIS
;IS DUE TO LACK OF A SYMBOL TABLE FORMAT SPEC, AND LACK OF DDT SUPPORT.
;
;ENTERED WITH:
;
;	P4/	POINTER TO RC BLOCK OF /SYMSEG PSECT
;	R/	INDEX TO /SYMSEG AREA, LC OR HC


DOUDFS:	MOVE	T1,TAB.PT(R)	;[1172] LINK'S ADDRESS OF NEXT WORD
	SUB	T1,TAB.LB(R)	;[1172] FIND OFFSET IN WINDOW
	ADD	T1,LW.S0(R)	;[1172] FIND OFFSET IN SEGMENT
	ADD	T1,LL.S0(R)	;[1172] FORM ABSOLUTE ADDRESS
	MOVEM	T1,USTADR	;[2245] SAVE ADDR FOR PDV SYM TABLE VECTOR
	HRLZM	T1,JOB117	;[1172] STORE IN LH(JOB117) FOR A WHILE
	SETZM	SYMDEW		;[1172] DON'T NEED EXTRA ROOM FROM SYMOUT
	MOVE	P2,HT.PRM	;GET HASH SIZE
	SKIPE	T1,@HT.PTR	;GET POINTER IF NON-ZERO
	JRST	UDFTRY		;SEE IF A REQUEST
UDFNXT:	SOJGE	P2,.-2		;MORE?
	JRST	UDFDN		;NO

UDFTRY:	ADD	T1,GS.LB	;ADD IN BASE
	MOVE	W1,(T1)		;GET FLAGS
	TXNN	W1,PS.REQ	;GLOBAL REQUEST
	JRST	UDFNXT		;NO, TRY NEXT SYMBOL
	DMOVE	W2,1(T1)	;GET SIXBIT SYMBOL & VALUE (REQUEST POINTER)
	TLNN	W2,770000	;[2373] IS IT A LONG SYMBOL?
	 PUSHJ	P,LUNDF		;[2373] YES - GO GET 1ST SXI CHARACTERS
	PUSHJ	P,SXBR50	;CONVERT TO SIXBIT
	TXO	W2,R5.GLB	;MAKE GLOBAL DEFINITION
	PUSHJ	P,SYMOUT	;[1172] STORE W2/W3 IN IMAGE
	  JRST	UDFDN		;[1172] NO MORE ROOM, CLOSE UP SHOP
	AOS	USYCNT		;[2306] ANOTHER ONE STORED, BUMP COUNT
	TXNE	W1,PS.FXP	;ANY ADDITIVE GLOBAL FIXUPS
	JRST	UDFGB		;YES, RECREATE THE REQUESTS
	JRST	UDFNXT		;[1172] NO, LOOK FOR ANOTHER SYMBOL

LUNDF:	HRRZ	T1,W2		;[2373] GET THE GS OFFSET TO LONG NAME
	ADD	T1,GS.LB	;[2373] ADD IN GS BASE
	MOVE	W2,(T1)		;[2373] 1ST 6 CHARACTERS TO W2
	POPJ	P,		;[2373] RETURN

;THE LOOP BELOW FINDS THE S.FXP TRIPLET IN THE GS AREA, THEN CHASES
;THE CHAIN OF FIXUPS DEPENDING ON THIS SYMBOL THROUGH THE FX AREA,
;WRITING UNDEFINED SYMBOL TABLE ENTRIES FOR APPLICABLE FIXUPS AS IT GOES.
;
;ENTER AT UDFGB.

UDFGB0:	TXNE	W1,S.LST	;IS THIS THE LAST BLOCK
	JRST	UDFNXT		;[1172] YES
	ADDI	T1,.L		;NO, GET NEXT TRIPLET
UDFGB:	HRRZ	T1,@HT.PTR	;GET POINTER AGAIN
	ADD	T1,GS.LB	;ADD IN BASE
	SKIPG	W1,.L(T1)	;GET NEXT FLAG WORD
	JRST	UDFERR		;MUST HAVE SIGN BIT ON
	TXNN	W1,S.FXP	;AND A FIXUP
	JRST	UDFGB0		;NOT YET
	MOVE	T1,.L+2(T1)	;[1172] GET VALUE
UDFGB1:	ADD	T1,FX.LB	;RELOCATE IN FIXUP TABLE
	SKIPL	W1,0(T1)	;GET FLAGS
	JRST	UDFERR		;JUST INCASE
	TXNE	W1,FP.SYM	;[1160] FIXUP BASED ON UNDEFINED SYMBOL?
	TXNN	W1,FS.FXR!FS.FXL!FS.FXC ;[1325] CHECK FOR CHAINED OR ADDITIVE
	JRST	UDFGB2		;[1160] CAN'T OUTPUT POLISH, SYM FIXUPS, ETC.
	DMOVE	W2,1(T1)	;GET DATA WORDS
	PUSHJ	P,SXBR50	;CONVERT TO RADIX-50
	TXO	W2,R5.GLB	;MAKE INTO A GLOBAL DEFINITION
	TXNN	W1,FS.FXC	;[1325] IS IT A SECONDARY CHAINED FIXUP?
	TXO	W3,R5.FXA	;AND TURN ON ADDITIVE BIT
	TXNE	W1,FS.FXL	;LEFT HALF?
	TXO	W3,R5.FXL	;YES
	PUSHJ	P,SYMOUT	;[1172] WRITE W2/W3 INTO THE IMAGE
	  JRST	UDFDN		;[1172] SPACE EXCEEDED, STOP
	AOS	USYCNT		;[2306] OK, WROTE ANOTHER ONE
UDFGB2:	HRRZ	T1,W1		;GET POINTER
	JUMPE	T1,UDFNXT	;[1172] ALL DONE IF ZERO
	JRST	UDFGB1		;GET NEXT BLOCK


;HERE WHEN AN UNDEFINED SYMBOL WITH PS.FXP SET IS NOT FOLLOWED BY A
;SECONDARY TRIPLET WITH S.FXP SET.

UDFERR:	JRST	UDFNXT		;[1172] SYMBOL TABLE FOULED UP
;HERE WHEN FINISHED WRITING THE UNDEFINED SYMBOL TABLE.
;SET UP .JBUSY AND RETURN.

UDFDN:	SKIPE	PAG.S1		;[1172] PAGING?
	SKIPA	T1,JOBPTR	;[1172] YES, LOAD CORRECT OFFSET
	MOVE	T1,LC.LB	;[1172] CODE OFFSET
	MOVE	T2,USYCNT	;[2306] GET NUMBER OF UNDEFINED SYMBOLS
	ADD	T2,T2		;[2306] TWO WORDS PER SYMBOL
	MOVEM	T2,USYCNT	;[2245] SAVE FOR PDV SYM TABLE VECTOR
	MOVNS	T2		;[2306] WANT -LENGTH OF TABLE
	HRRM	T2,JOB117	;[1172] FORM ADDR,,-LEN
	MOVSS	T2,JOB117	;[1172] FORM -LEN,,ADDR
IFN TOPS20,<			;[2366]
	SKIPE	NOJBDA		;[2211] JOBDAT WANTED?
	 POPJ	P,		;[2211] NO
>;[2366] IFN TOPS20
	 MOVEM	T2,.JBUSY(T1)	;NO, STORE IN IMAGE
	POPJ	P,		;[1172] DONE WITH UNDEFINED TABLE, RETURN
;SUBROUTINE TO DELETE THE GS AREA, AND CUT BACK MEMORY IF POSSIBLE.

GSDLT:
IFE TOPS20,<			;[1113] DON'T SHRINK BACK ON TOPS-20
	SKIPN	.JBDDT(T1)	;SEE IF WE NEED LOCAL SYMBOLS
	SKIPE	SYMSEG		;EITHER FOR /DEB OR /SYMSEG
	JRST	GSNRED		;YES, DON'T CUT BACK CORE YET
	MOVEI	T1,GS.IX-1	;START AT AREA JUST LOWER
	SKIPN	TAB.LB(T1)	;FIND HIGHEST AREA IN USE
	SOJA	T1,.-1		;WILL GET THERE EVENTUALLY
	MOVE	T2,TAB.AB(T1)	;GET HIGHEST LOC IN USE IN IT
	IORI	T2,1777		;K BOUND
	ADDI	T2,2000		;EXTRA K FOR SAFETY
	CAML	T2,.JBREL	;ANYTHING TO GIVE BACK?
	JRST	GSNRED		;NO, REDUCED ALREADY
	CORE	T2,		;DELETE TOP PART
	  JRST	GSNRED		;NEVER CAN HAPPEN
	MOVE	T2,.JBREL	;GET NEW TOP
	SKIPN	GS.LB		;[773] GS AREA ALREADY GONE?
	JRST	GSDLT1		;[773] YES, DON'T RECREATE IT
	MOVEM	T2,GS.AB	;RESET TABLE
	MOVEM	T2,GS.UB
	CAMLE	T2,GS.LB	;INCASE WE REDUCED IT ALL
	JRST	E$$RED		;[1174] NO, ALL IS WELL
GSDLT1:	MOVEM	T2,TAB.UB(T1)	;[773] RESET HIGHEST FREE LOC AGAIN
	SETZM	GS.LB		;SO XX.ZAP CAN WORK
E$$RED::.ERR.	(MS,.EC,V%L,L%I,S%I,RED,<Reducing low segment to >) ;[1174]
	.ETC.	(COR,.EP,,,,.JBREL)
> ;END OF IFE TOPS20
GSNRED:	PUSHJ	P,GS.ZAP	;GET RID OF GS
	POPJ	P,		;[1172] END OF GSDLT
;HERE TO WRITE THE DEFINED SYMBOLS INTO THE IMAGE.

DOLOCS:	SKIPE	PAG.LS		;[1172] PAGING?
	PUSHJ	P,SYMINI	;[1172] YES, SET WINDOW TO END OF LS AREA
	MOVEI	T1,2		;[1172] NEED ENOUGH WARNING TO PUT A TITLE OUT
	MOVEM	T1,SYMDEW	;[1172] STORE FOR SYMOUT
	MOVE	T1,TAB.PT(R)	;[1172] COMPUTE START OF THIS TABLE
	SUB	T1,TAB.LB(R)	;[1172] OFFSET IN WINDOW TO FIRST AFTER USY
	ADD	T1,LW.S0(R)	;[1172] OFFSET IN SEGMENT
	ADD	T1,LL.S0(R)	;[1172] FORM ABSOLUTE ADDRESS FOR RH(.JBSYM)
	MOVEM	T1,DSTADR	;[2245] SAVE FOR PDV SYM TABLE VECTOR
	HRLZM	T1,JOB116	;[1172] STORE IN LH(JOB116) A WHILE
	PUSHJ	P,PATOUT	;[1172] WRITE THE PAT.. SYMBOL AND MODULE
	SKIPN	SYMFUL		;[1172] ANY ROOM LEFT?
	PUSHJ	P,LSLOOP	;[1172] DO THE WORK


;HERE WHEN THE SYMBOLS HAVE BEEN INSERTED INTO THE IMAGE.  UPDATE .JBSYM.

	SKIPE	PAG.S1		;[1172] PAGING?
	SKIPA	T1,JOBPTR	;[1172] YES, JOBDAT'S IN DY
	MOVE	T1,LC.LB	;[1172] NO, IT'S IN LC
	MOVE	T2,DSYCNT	;[2306] GET HOW MANY SYMBOLS
	ADD	T2,T2		;[2306] TWO WORDS PER SYMBOL
	MOVEM	T2,DSYCNT	;[2245] SAVE FOR PDV SYMBOL TABLE VECTOR
	MOVNS	T2		;[2306] WANT -COUNT
	HRRM	T2,JOB116	;[1172] ADDR,,-LEN
	MOVSS	T2,JOB116	;[1172] -LEN,,ADDR
IFN TOPS20,<			;[2366]
	SKIPE	NOJBDA		;[2211] JOBDAT WANTED?
	 POPJ	P,		;[2211] NO
>;[2366] IFN TOPS20
IFE TOPS20,<			;[2366]
	SKIPE	SYMVEC		;[2366] BUILDING A SYMBOL VECTOR
	 MOVE	T2,SYMVEC	;[2366] YES, GET THE VECTOR ADDRESS
>;[2366] IFE TOPS20
	 MOVEM	T2,.JBSYM(T1)	;[2211] NO, STORE IN JOBDAT
	POPJ	P,		;[1172] DONE WITH DOLOCS
;HERE TO MOVE SYMBOLS TO TOP OF CORE
;IF SORTING PUT SORT BUFFER IN AREA GS

SYMINI:	SKIPL	UW.LS		;[1172] IF -1 THEN SYMBOL TABLE NOT OUTPUT YET
	JRST	RDSYM		;JUST READ IT BACK IN
	MOVE	T2,LSYM		;[2202] ADDRESS OF LAST SYMBOL STORED +1
	SUBI	T2,1		;[2202] HIGHESE ADDRESS STORED TO
	IORI	T2,.IPM		;[2202] BLOCK BOUND
	MOVEM	T2,UW.LS	;[2202] REMEMBER WHAT'S THERE
IFN TOPS20,<
	CAMG	T2,LW.LS	;[2202] Check for current page never used
	 ADDI	T2,.IPS		;[2202] Must write out one page anyways
> ;[1536]
	MOVE	T1,LW.LS	;[2202] FORM  BLT WORD
	PUSHJ	P,LS.OUT##	;AND OUTPUT IT
				;FALL INTO RDSYM TO READ IT BACK

RDSYM:	PUSHJ	P,FR.CNT##	;[1172] SEE HOW MUCH IS FREE
	LSH	T1,-1		;[1172] TAKE HALF OF IT FOR LS WINDOW
	ANDCMI	T1,.IPM		;[1172] KEEP ON A PAGE BOUND
	CAIGE	T1,2*.IPS	;[1172] BUT NEED AT LEAST TWO PAGES
	MOVEI	T1,2*.IPS	;[1172] SO FORCE AT LEAST THAT MANY
	MOVE	T2,LS.AB	;[1172] CALCULATE CURRENT SIZE OF LS AREA
	SUB	T2,LS.LB	;[1172] LAST - FIRST
	ADDI	T2,1		;[1172] PLUS 1
	CAML	T2,T1		;[1172] HAVE LESS THAN WE WANT?
	JRST	RDSYM2		;[1172] ALREADY BIG ENOUGH
	SUB	T1,T2		;[1172] HOW MUCH MORE WE NEED
	MOVEI	P1,LS.IX	;[1172] ARRANGE TO GET IT
	MOVE	P2,T1		;[1172] HOW MUCH TO GET
	PUSHJ	P,LNKCOR##	;[1172] SHUFFLE
	  PUSHJ	P,E$$MMF##	;[2202] CANNOT HAPPEN
	PUSHJ	P,LS.FXR##	;[1401] DO ANY SYMBOL TABLE FIXUPS REMAINING

;NOW READ THE LAST PAGE OF SYMBOLS INTO THE FIRST PAGE OF THE LS AREA.
;LSLOOP WILL QUICKLY FALL OFF THE BOTTOM (READING BACKWARDS), AND
;FILL THE ENTIRE WINDOW WITH THE NEXT LOWER PIECE.

RDSYM2:
	MOVE	T1,LSYM		;[1172] LAST WORD OF SYMBOLS + 1
	SUBI	T1,1		;[1172] LAST WORD IN USE
	ANDCMI	T1,.IPM		;[1172] BOTTOM OF NEW WINDOW
	MOVEM	T1,LW.LS	;[1172] SET FOR PAGING ROUTINES
	ADD	T1,LS.AB	;[1172] ADD WINDOW SIZE
	SUB	T1,LS.LB	;[1172] TO GET TOP OF WINDOW
	MOVEM	T1,UW.LS	;[1172] STORE FOR PAGING ROUTINES
	MOVE	T1,LSYM		;[1172] FIRST UNUSED WORD AGAIN
	SUB	T1,LW.LS	;[1172] HOW FAR INTO WINDOW IT IS
	ADD	T1,LS.LB	;[1172] FIX IN MEMORY
	MOVEM	T1,LS.PT	;[1172] SAVE FOR GETSYM
	MOVE	T1,LW.LS	;[2202] NOW FILL BOTTOM PAGE
	MOVE	T2,LW.LS	;[2202] REST WILL BE FILLED BY PAGSYM
	IORI	T2,.IPM		;[2202] ROUND UP TO TOP OF PAGE
	PJRST	LS.IN##		;[1172] FILL THE WINDOW AND RETURN

;LNKOV2 FILLS THE LS AREA WITH SYMBOL TRIPLETS, ZEROES THE LC AREA,
;AND THEN PUSHJ'S DIRECTLY TO LSLOOP TO CONVERT THE SYMBOLS TO
;RADIX50 AND PUT A RUNTIME SYMBOL TABLE INTO THE LC AREA.  IT
;THEN WRITES THE LC AREA TO THE APPROPRIATE PLACE IN THE OVERLAY FILE.
;
;THIS IS AN INITIALIZATION ROUTINE CALLED BY LNKOV2 TO SET THINGS UP
;BEFORE CALLING LSLOOP.

IFN FTOVERLAY,<

LSOVX::	MOVX	T1,.INFIN	;[1172] DON'T STOP FOR A SYMBOL LIMIT
	MOVEM	T1,SYMLIM	;[1172] SINCE NOT REALLY LOADING INTO MEMORY
	SETZM	SYMDEW		;[1172] DON'T NEED ANY WARNING
	SETZM	SYMFUL		;[1172] HAVE LOTS OF ROOM FOR SYMBOLS
	SETZM	DSYCNT		;[2306] LSLOOP AOSES THIS FOR EVERY SYMBOL
	SKIPN	LNKNO.		;[1172] IS THIS THE ROOT?
	PJRST	PATOUT		;[1172] YES, WRITE PAT.. AND RETURN
	MOVNI	T1,2		;[1172] NO, INIT TTLPTR
	MOVEM	T1,TTLPTR	;[1172] SO FIRST MODULE WILL BE RIGHT
	POPJ	P,		;[1172] RETURN TO LNKOV2
> ;END IFN FTOVERLAY
;HERE TO WRITE THE PAT.. SYMBOL AND MODULE TO THE SYMBOL TABLE.

PATOUT:	MOVE	W2,[RADIX50 04,PAT..]	;[1172] NAME
	MOVE	W3,PATLOC	;[1172] VALUE
	PUSHJ	P,SYMOUT	;[1172] WRITE IT OUT
	  JRST	[HRLI W3,-2	;[1172] SYMBOL WON'T FIT, JUST WRITE NAME
		SETZM SYMDEW	;[1172] IF IT WILL FIT
		JRST PATOU2]	;[1172] RE-JOIN COMMON CODE
	AOS	DSYCNT		;[2306] A SYMBOL PAIR SUCCESSFULLY WRITTEN
	HRLI	W3,-4		;[1172] FOUR WORDS IN THIS MODULE
PATOU2:	MOVE	T1,TAB.PT(R)	;[1172] BEFORE WRITING THE TITLE,
	SUB	T1,TAB.LB(R)	;[1172] FIGURE OUT WHERE IT GOES
	ADD	T1,LW.S0(R)	;[1172] AS AN OFFSET INTO THE SEGMENT
	MOVEM	T1,TTLPTR	;[1172] SAVE FOR LTITLE
	TLZ	W2,740000	;[1172] MAKE 0,PAT.. BE THE TITLE
	PUSHJ	P,SYMOUT	;[1172] WRITE THE TITLE
	  CAIA			;[1172] OOPS! SEE WHAT WENT WRONG
	JRST	PATOU4		;[1172] OK, NOW GO WRITE THE REAL SYMBOLS
	SKIPN	SYMDEW		;[1172] 4,PAT.. FAILED ABOVE? (DON'T USE SYMFUL)
	JRST	[SETZM JOB116	;[1172] YES, THERE WON'T BE A SYMBOL TABLE
		POPJ P,]	;[1172] JUST RETURN
	SETZM	SYMDEW		;[1172] USE OUR RESERVE FOR PAT..'S TITLE
	PUSHJ	P,SYMOUT	;[1172] WRITE IT
	  JFCL			;[1172] CAN'T HAPPEN
PATOU4:	AOS	DSYCNT		;[2306] ANOTHER SYMBOL WRITTEN
	POPJ	P,		;[1172] DONE
LSLOOP::PUSHJ	P,GETSYM	;GET SYMBOL IN W1,W2,W3
	  POPJ	P,		;ALL DONE
	JUMPGE	W1,LSLOOP	;IGNORE ALL EXTENDED BLOCK
	TXNE	W1,PT.TTL	;SPECIAL IF TITLE BLOCK
	JRST	LTITLE		;NEED TO KEEP POINTERS ETC
	SKIPE	SYMFUL		;[1172] SKIPPING FOR LAST MODULE NAME?
	JRST	LSLOOP		;[1172] YES, REJECT ALL OTHER RANDOM SYMBOLS
	TXNE	W1,PT.SYM	;ONLY WANT REAL SYMBOLS
	TXNE	W1,PS.MDF	;BUT NOT MULTIPLE DEFINITION
	JRST	LSLOOP		;MUST BE SOME THING ELSE
	PUSHJ	P,SXBR50	;CONVERT TO RADIX-50
	TXNE	W1,PS.GLB	;GLOBAL?
	TXO	W2,R5.GLB	;YES
	TXNE	W1,PS.COM	;COMMON?
	JRST	LSLUPC		;YES, NEEDS TWO SYMBOLS
	TXNE	W1,PS.LCL	;THEN LOCAL?
	TXO	W2,R5.LCL	;YES
	TXNE	W1,PS.DDT	;NO DDT OUTPUT?
	TXO	W2,R5.DDT	;YES SET BIT
LSLUP1:	PUSHJ	P,SYMOUT	;PUT SYMBOL IN CORE
	  JRST	[SETZM SYMDEW	;[1172] GO INTO FIND MODULE NAME MODE
		JRST LSLOOP]	;[1172] START THE HUNT
	AOS	DSYCNT		;[2306] ANOTHER SYMBOL STORED
	JRST	LSLOOP		;AND BACK FOR MORE

LSLUPC:	MOVEI	T1,4		;[1172] NEED FOUR WORDS OR NOTHING
	MOVEM	T1,SYMDEW	;[1172] SO BUMP WARNING LEVEL
	PUSHJ	P,SYMOUT	;OUTPUT IT
	  JRST	[SETZM SYMDEW	;[1172] WON'T BOTH FIT
		JRST LSLOOP]	;[1172] CLOSE OFF TABLE AND STOP
	AOS	DSYCNT		;[2306] ANOTHER PAIR OUT
	MOVEI	T1,2		;[1172] PUT SYMOUT CUTOFF BACK
	MOVEM	T1,SYMDEW	;[1172] NEXT PAIR GUARANTEED TO FIT
	PUSH	P,W3		;SAVE ADDRESS
	MOVX	T1,S.COM	;PART WE WANT
	PUSHJ	P,GETAST	;GET REST OF SYMBOL
	  JRST	[POP	P,W3		;TOO BAD
		JRST	LSLOOP]		;JUST IGNORE
	PUSHJ	P,SXBR50	;IN RADIX50
	TXO	W2,R5.DDT!R5.GLB	;CODE 44
	POP	P,T1		;GET ADDRESS
	HRL	T1,W3		;LENGTH ,, ADDRESS
	MOVE	W3,T1		;...
	JRST	LSLUP1		;OUTPUT IT
;HERE ON A TITLE IN THE LS AREA.

LTITLE:	TXNE	W1,PT.PSC	;[1132] JUST A PSECT DEFINITION?
	JRST	LSLOOP		;[1132] YES, DON'T PUT IN SYMBOL TABLE
	PUSHJ	P,SXBR50	;CONVERT TO RADIX-50
	TXNE	W1,PT.BLK	;ONLY A FAIL BLOCK HEADER?
	JRST	BTITLE		;YES
	MOVE	T2,TTLPTR	;GET ADDRESS OF LAST PROG
	HRRZ	T1,TAB.PT(R)	;GET THIS ADDRESS
	SUB	T1,TAB.LB(R)	;MINUS OFFSET
	ADD	T1,TAB.LW(R)	;PLUS BASE OF WINDOW
	MOVEM	T1,TTLPTR	;SAVE FOR NEXT
	SUB	T1,T2		;GET DIFFERENCE
	MOVN	T1,T1		;NEGATE
	HRL	W3,T1		;FIXUP POINTER
	PUSH	P,W2		;SAVE SYMBOLS
	PUSH	P,W3
TTLLUP:	MOVX	T1,S.TTL!S.SEG	;FLAGS
	PUSHJ	P,GETAST	;GET EXTENSION TRIPLET
	 SETZ	W2,		;[2256] ONLY HERE IF DEFINED BY /SWITCH
	PUSH	P,W2		;[2256] SAVE THE LOW SEG ORIGIN
	MOVX	T1,S.TTL!S.SEG!S.SHI	;[2256] FLAGS
	PUSHJ	P,GETAST	;[2256] GET EXTENSION TRIPLET
	 SETZ	W2,	   	;[2256] THERE ISN'T ONE
	MOVE	W3,W2		;[2256] HIGH SEG BREAK IN W3
	POP	P,W2		;[2256] GET BACK LOW SEG BREAK	
	SKIPE	W3		;IF ANY HIGH SEG STUFF
	MOVE	W2,W3		;USE IT
	POP	P,W3		;GET W3 BACK
	HRR	W3,W2		;[2256] FIX IT UP
	POP	P,W2
	PUSHJ	P,SYMOUT	;OUTPUT PSEUDO SYMBOL
	  JRST	[
		SKIPN SYMDEW	;[1455] ALREADY EXHAUSED RESERVE?
		POPJ P,		;[1455] DON'T KEEP TRYING
		SETZM SYMDEW	;[1172] USE THE RESERVE TO STORE THIS TITLE
		JRST .-1]	;[1172] TRY AGAIN
	AOS	DSYCNT		;[2306] COUNT ANOTHER SYMBOL PAIR
	SKIPE	SYMFUL		;[1172] WAS THIS OUR LAST TITLE?
	POPJ	P,		;[1172] YES, QUIT, SINCE NO MORE ROOM
	JRST	LSLOOP		;RETURN



BTITLE:	SKIPE	SYMFUL		;[1172] ROOM FOR THIS?
	JRST	LSLOOP		;[1172] NO, DON'T STORE IT
	TXO	W2,R5.LCL!R5.GLB	;MAKE RADIX50 14,SYM
	HRRZ	W3,W3		;BLOCK LEVEL ONLY
	JRST	LSLUP1		;AND TREAT AS LOCAL SYMBOL
;HERE TO GET NEXT SYMBOL BLOCK
;CALLED BY
;	PUSHJ	P,GETSYM
;RETURNS
;W1, W2, W3 WITH SYMBOL INFO
;USES T1
;READS SYMBOL TABLE IN REVERSE ORDER

GTSYM1:	PUSHJ	P,PAGSYM	;SEE IF PAGING
	  POPJ	P,		;NO, ALL DONE
				;FALL INTO GETSYM


GETSYM:	MOVNI	T1,3		;BACKUP POINTET TO
	ADD	T1,LS.PT	;GET NEXT TRIPLET
	CAMGE	T1,LS.LB	;DON'T GO TOO FAR
	JRST	GTSYM1		;SEE IF PAGING
	MOVEM	T1,LS.PT	;SAFE TO STORE NOW
	TMOVE	W1,0(T1)	;FLAGS, SYMBOL, VALUE
	JRST	CPOPJ1		;SKIP RETURN
;HERE TO READ MORE SYMBOLS IF THEY ARE ON DSK

PAGSYM:	SKIPE	UW.LS		;NEVER WERE
	SKIPN	LW.LS		;WERE BUT ALL DONE
	POPJ	P,		;IN EITHER CASE JUST RETURN CPOPJ
IFE TOPS20,<
	HRLZ	T1,LS.LB	;[1172] MOVE FIRST BLOCK OF SYMBOLS
	HRR	T1,LS.AB	;[1172]   UP TO LAST BLOCK OF LS AREA
	ANDCMI	T1,.IPM		;[1172] NOW HAVE SRC,,DEST
	BLT	T1,@LS.AB	;[1172] MOVE THE DATA
	MOVE	T1,LS.AB	;[1172] CHECK TO SEE IF LAST TIME
	ANDCMI	T1,.IPM		;[1172] ACCOUNT FOR PAGE WE KEPT
	MOVEI	T2,.IPM		;[1172] MASK FOR PAGE OFFSET
	ANDM	T2,LS.PT	;[1172] OFFSET TO CURRENT SYMBOL
	ADDM	T1,LS.PT	;[1172] MOVE POINTER TO LAST PAGE OF AREA
	SUB	T1,LW.LS	;[1172] BOTTOM ADDR IF WE FINISHED THIS TIME
	SUBI	T1,1		;[1172] GET LOCATION BELOW FIRST USED
	CAML	T1,LS.LB	;[1172] LS AREA TOO BIG (LAST TIME)?
	PUSHJ	P,GBCK.L##	;[1172] YES, GET RID OF BOTTOM PART
	MOVE	T1,LW.LS	;[1172] GET OLD LOWER WINDOW ADDRESS
	IORI	T1,.IPM		;[1172] THE END OF THAT PAGE
	MOVEM	T1,UW.LS	;[1172] FORM NEW UPPER WINDOW
	ADD	T1,LS.LB	;[1172] SUBTRACT LENGTH OF AREA
	SUB	T1,LS.AB	;[1172] TO FORM LOWER WINDOW
	MOVEM	T1,LW.LS	;[1172] STORE FOR PAGING ROUTINES
	MOVE	T2,UW.LS	;[2202] TRANSFER WORD TO WHOLE AREA
	SUBI	T2,.IPS		;[2202] BUT WE ALREADY HAVE LAST PAGE
	PUSHJ	P,LS.IN		;[1172] FILL UP THE AREA
	JRST	CPOPJ1		;[1172] SKIP RETURN
> ;[1401] IFE TOPS20
IFN TOPS20,<
	MOVE	T2,LS.PT	;[1510]
	SUB	T2,LS.LB	;[1510]
	ADD	T2,LW.LS	;[1510]
	MOVEM	T2,LS.PT	;[1510] SAVE LS.PT AS VIRTUAL ADDR
	MOVE	T1,LW.LS	;[2202] SEND OUT CURRENT PAGES
	MOVE	T2,UW.LS	;[2202] ALL OF THEM
	PUSHJ	P,LS.OUT	;[1401] DO IT
	MOVE	T1,LS.AB	;[2202] WHAT'S AVAILABLE?
	SUB	T1,LS.LB	;[2202] SIZE OF LS AREA
	MOVE	T2,LW.LS	;[2202] WHAT'S LEFT?
	ADDI	T2,.IPS-1	;[2202] SYMBOLS FROM HERE BACK TO 0
	SUBM	T2,T1		;[2202] GET THE LOWER BOUND IN T1
	SKIPGE	T1		;[2202] GREATER THAN ZERO?
	SETZ	T1,		;[2202] NO, EVERYTHING UP TO HERE WILL FIT
	MOVEM	T1,LW.LS	;[2202] NEW LOWER BOUND
	MOVEM	T2,UW.LS	;[2202] NEW UPPER BOUND
	PUSHJ	P,LS.IN		;[1401] DO IT
	MOVE	T1,UW.LS	;[2202] GET THE UPPER BOUND
	SUB	T1,LW.LS	;[2202] GET THE SIZE
	ADD	T1,LS.LB	;[2202] ADD THE BASE
	MOVEM	T1,LS.AB	;[2202] CURRENT BOUND
	MOVE	T2,LS.PT	;[1510]
	SUB	T2,LW.LS	;[1510]
	ADD	T2,LS.LB	;[1510]
	MOVEM	T2,LS.PT	;[1510]
	JRST	CPOPJ1		;[1401] SKIP RETURN
>  ;[1401] IFN TOPS20
;HERE TO GET ASSOCIATED SECONDARY TRIPLET
;CALLED BY
;	MOVE	T1,FLAGS
;	PUSHJ	P,GETAST
;RETURNS
;+1	FAILED
;+2	SUCCESS
;USES T1, T2, T3
;SETS UP W1, W2, W3

GETAST:	MOVE	T2,LS.PT	;GET POINTER
GETNAS:	ADDI	T2,.L		;ENTER HERE WITH T2 SETUP
	CAMLE	T2,LS.AB	;STILL IN CORE?
	JRST	FNDNIC		;NOT IN CORE
	SKIPGE	T3,(T2)		;GET FLAGS
	POPJ	P,		;FOUND A PRIMARY (FAILED)
	XOR	T3,T1		;IFF ALL BITS MATCH
	TXZ	T3,S.LST	;IGNORE THIS BIT HOWEVER
	JUMPN	T3,GETNAS	;TRY AGAIN
	TMOVE	W1,(T2)		;FLAGS, SYMBOL, VALUE
CPOPJ1:	AOS	(P)
CPOPJ:	POPJ	P,


FNDNIC:	SKIPN	UW.LS
	POPJ	P,		;ALL DONE
E03CNW::.ERR.	(MS,.EC,V%L,L%F,S%F,CNW) ;[1174]
	.ETC.	(STR,,,,,,<FNDNIC>)
;SXBR50 -- SUBROUTINE TO CONVERT SIXBIT TO RADIX-50
;CALLED BY
;	MOVE	W2,SIXBIT WORD
;	PUSHJ	P,SXBR50
;RETURN
;	RADIX-50 IN W2
;USES T1, T2

SXBR50:	MOVE	T2,W2		;GET SIXBIT SYMBOL
	SETZ	W2,		;WHERE TO STORE RADIX50 SYMBOL
	SETZ	T1,		;CLEAR RECEIVING ACC
	LSHC	T1,6		;GET NEXT CHAR
	IMULI	W2,50		;MULTIPLE BY 50
	ADD	W2,SXBTAB(T1)	;ADD IN NEW CHAR
	JUMPN	T2,.-4		;NOT DONE YET
	POPJ	P,

DEFINE SXBCHR (CHR)<
 IRPC CHR,<
  RADIX50 0,CHR
>>


	XALL
SXBTAB:	SXBCHR (....$%..........0123456789.......ABCDEFGHIJKLMNOPQRSTUVWXYZ.....)				;[2373] substitute . for non-sixbit characters
	SALL
;HERE TO WRITE THE RADIX-50 SYMBOL IN W2/W3 TO THE IMAGE.
;RETURNS NON-SKIP, MESSAGE PRINTED, IF SYMBOL WON'T FIT BELOW SYMLIM.
;SYMBOL WON'T FIT IF IT IS WITHIN C(SYMDEW) WORDS OF PASSING SYMLIM.

SYMOUT:	MOVE	T1,TAB.PT(R)	;[1172] ADDRESS TO STORE INTO NEXT
	AOS	T2,T1		;[1172] LAST ADDRESS THIS SYMBOL WILL USE
	SUB	T2,TAB.LB(R)	;[1172] CONVERT TO OFFSET IN SEGMENT
	ADD	T2,TAB.LW(R)	;[1172] (USUALLY SAME AS VIRTUAL ADDRESS)
	ADD	T2,LL.S0(R)	;[1172] MAKE SURE IT'S A VIRTUAL ADDRESS
	ADD	T2,SYMDEW	;[1172] RESPECT DISTANT EARLY WARNING FACTOR
	CAMG	T2,SYMLIM	;[1172] WOULD WE STORE BEYOND LEGAL BOUNDS?
	JRST	SYMOU2		;[1172] NO, CONTINUE
	SKIPE	SYMFUL		;[1172] ALREADY ISSUED A MESSAGE?
	POPJ	P,		;[1172] YES, DONT SAY IT AGAIN
	SETOM	SYMFUL		;[1172] REMEMBER FOR NEXT TIME & CALLERS
E$$ISS::.ERR.	(MS,.EC,V%L,L%W,S%W,ISS,<Insufficient space for symbol table after psect >) ;[1174]
	.ETC.	(SBX,.EP!.EC,,,,SSGNAM)
	.ETC.	(STR,,,,,,< -- table truncated>)
	POPJ	P,		;[1172] ERROR RETURN
;HERE IF NOT PAST SYMLIM.  CHECK TO SEE IF THE AREA/WINDOW IS BIG ENOUGH.

SYMOU2:	CAMG	T1,TAB.AB(R)	;[1172] STILL ROOM IN THE AREA?
	AOJA	T1,SYMOU8	;[1172] YES, GO STORE THE SYMBOL
	SETOM	LS.PP		;[1172] DON'T SHRINK THE LS AREA
	SPUSH	<P1,P2>		;[1216] PRESERVE OVER LNKCOR
	MOVE	T1,TAB.PT(R)	;[1534] RENDER TAB.PT VIRTUAL
	SUB	T1,TAB.LB(R)	;[1534] TAKE OFF AREA BASE
	ADD	T1,TAB.LW(R)	;[1534] ADD IN WINDOW OFFSET
	PUSH	P,T1		;[1534] AND KEEP IT
	MOVE	P1,R		;[1172] SEGMENT TO EXPAND
	MOVEI	P2,.IPS		;[1172] BY ONE PAGE
	PUSHJ	P,LNKCOR##	;[1172] EXPAND
	  PUSHJ	P,E$$MEF##	;[1174] SHOULD NEVER GET HERE
	POP	P,T1		;[1534] GET VIRT TAB.PT
	SUB	T1,TAB.LW(R)	;[1534] AND FIX IN MEMORY AGAIN
	ADD	T1,TAB.LB(R)	;[1534]	IN CASE THINGS MOVED
	MOVEM	T1,TAB.PT(R)	;[1534]
	SPOP	<P2,P1>		;[1216] RESTORE SACRED COWS
	SETZM	LS.PP		;[1172] RESTORE

IFE TOPS20,<			;[2247]
IFN FTOVERLAY,<
	SKIPL	LNKMAX		;[1172] LSLOOP CALLED FROM LNKOV2?
	SKIPN	PAG.S0(R)	;[1172] AND LNKCOR STARTED AREA PAGING?
	CAIA			;[1172] NO
	PUSHJ	P,E$$MEF##	;[1174] YES, LNKOV2 CAN'T HANDLE THAT
> ;END IFN FTOVERLAY
>;[2247] IFE TOPS20

	PUSHJ	P,CHKPAG	;[1172] FIX JOBDAT IF JUST STARTED PAGING
	SKIPN	TAB.PG(R)	;[1172] AREA NOW PAGING?
	JRST	SYMOUT		;[1172] NO, GO TRY AGAIN
	MOVE	T1,LW.S0(R)	;[1172] YES, MUST UPDATE UW
	ADD	T1,TAB.AB(R)	;[1172] LNKCOR SOMETIMES DOES
	SUB	T1,TAB.LB(R)	;[1172] BUT SOMETIMES IT DOESN'T
	MOVEM	T1,UW.S0(R)	;[1172] SO MAKE SURE IT'S RIGHT
IFE TOPS20,<
	ANDCMI	T1,.IPM		;[1172] FIRST ADDRESS IN PAGE WE JUST ADDED
	CAML	T1,HC.S0(R)	;[1172] ANY DATA FURTHER ON IN OVERFLOW FILE?
	JRST	SYMOUT		;[1172] NO, JUST LEAVE NEW PAGE ZERO
	MOVE	T2,UW.S0(R)	;[2202] OTHERWISE WE LOSE DATA
	PUSHJ	P,@TB.IN(R)	;[1172] DO THE I/O
>  ;[1401] IFE TOPS20
	JRST	SYMOUT		;[1172] AND TRY AGAIN


;HERE WHEN ALL IS OK TO STORE THE NEW SYMBOL.

SYMOU8:	DMOVEM	W2,-2(T1)	;[1172] DO THE STORE
	MOVEM	T1,TAB.PT(R)	;[1172] UPDATE THE PT FOR NEXT TIME

IFN FTOVERLAY,<
	SKIPE	T1,RT.PT	;RELOCATABLE?
	CAMN	T1,RT.LB	;MAYBE, IS IT?
	JRST	CPOPJ1		;[715] NO, SKIP RETURN
	IBP	RT.PT		;SYMBOL IS NOT
	TXNN	W1,PS.REL	;IS IT RELOCATABLE?
	TDZA	T1,T1		;NO
	MOVEI	T1,1		;YES
	IDPB	T1,RT.PT	;SET BIT
>
	JRST	CPOPJ1		;[715] SKIP RETURN
;HERE FOR OLD FORM SYMBOLS (RADIX-50)
;IF IN CORE WRITE THEM OUT WITH THREE INFORMATION WORDS AT FRONT
;HEADER, .JBSYM (116) AND .JBUSY (117)
;HEADER IS 776(TYPE) ,, LENGTH
;OTHER TWO WORDS ARE RELATIVE TO ZERO
;.JBSYM MUST HAVE A NEGATIVE LEFT HALF
;.JBUSY IS ZERO IF NO UNDEFINED SYMBOLS

OLDSYM:	MOVEI	T1,MC		;USE MAP CHAN INCASE PAGING LC
	MOVEM	T1,IO.CHN
	MOVE	T1,IO.PTR+%SC	;POINT TO CORRECT DATA
	MOVEM	T1,IO.PTR+MC
	PUSHJ	P,DVCHN.##
	MOVSI	T2,(Z MC,)	;RESET CHAN #
	MOVEM	T2,I.CHN(T1)	;SINCE %SC IS THERE CURRENTLY
	HLRO	T2,JOB116	;NUMBER OF SYMBOLS
	MOVM	T2,T2
	LSH	T2,-.DBS2W	;[650] INTO BLOCKS (ASSUME FEW UNDEFS)
	MOVEM	T2,I.EST(T1)
	MOVE	T2,VERNUM	;GET VERSION OF CORE IMAGE
	SKIPN	I.VER(T1)	;SKIP IF SET BY SWITCH
	MOVEM	T2,I.VER(T1)	;NO, SO SET IT
	PUSHJ	P,DVNAM.##	;MAKE SURE NAME SETUP
	PUSHJ	P,DVOPN.##	;INIT DEV
	PUSHJ	P,DVENT.##	;DO ENTER
				;NOW TO STORE THREE INFO WORDS
	HLRE	T1,JOB116	;NO. OF DEFINED SYMBOLS
	HLRE	T2,JOB117	;NO. OF UNDEFS
	MOVM	T1,T1		;+
	MOVM	T2,T2
	ADDI	T2,2(T1)	;PLUS TWO EXTRA WORDS
	HRLI	T2,776		;BLOCK TYPE FOR LINK
	SKIPN	T1,JOB117	;.JBUSY IF NON-ZERO
	MOVE	T1,JOB116	;OTHERWISE .JBSYM
	HRRZ	T1,T1		;REMOVE NEG LEFT HALF
	SUB	T1,LL.S0(R)	;REMOVE ORIGIN
	SUB	T1,LW.S0(R)	;INCASE PAGING
	ADD	T1,TAB.LB(R)	;FIX IN CORE
;NOW PUT HEADER WORDS IN CORE IMAGE SO WE CAN DUMP IT ALL WITH
;ONE IOWD. PUSH REAL CONTENTS OF THOSE LOCATIONS (USUALLY 0) FIRST,
;THEN RESTORE THEM LATER

	SUBI	T1,3		;BACKUP 3
	PUSH	P,0(T1)		;SAVE WORDS INCASE NOT ZERO
	PUSH	P,1(T1)
	PUSH	P,2(T1)
	MOVEM	T2,0(T1)	;SAVE HEADER
	HLLZ	T2,JOB117	;COPY  INFO WORDS
	MOVEM	T2,2(T1)	;TO NEXT 2 LOCS
	HLRE	T2,T2		;GET - LENGTH (OR 0)
	MOVM	T2,T2		;+
	HLL	T2,JOB116	;-LENGTH,,OFFSET
	MOVEM	T2,1(T1)	;FIRST INFO WORD
	HLRE	T2,JOB116	;FIND TOTAL LENGTH TO OUTPUT
	HLRE	T3,JOB117	;.JBSYM+.JBUSY
	ADD	T2,T3
	SUBI	T2,3		;+3 INFO WORDS
	HRLZ	T2,T2		;-LENGTH
	HRRI	T2,-1(T1)	;IOWD LENGTH,ADDRESS
	SETZ	T3,		;TERMINATE
	OUT	MC,T2		;DUMP IT
	  JRST	[POP	P,2(T1)		;RESTORE DATA
		POP	P,1(T1)
		POP	P,0(T1)
		PJRST	DVRLS.##]	;CLOSE FILE
	POP	P,2(T1)		;RESTORE DATA
	POP	P,1(T1)
	POP	P,0(T1)
E$$OES::PUSH	P,[MC]		;[1174]
	.ERR.	(ST,,V%L,L%W,S%W,OES,<Output error on symbol file, file closed, load continuing>)
	POPJ	P,
;HERE TO SAVE NEW FORM SYMBOL TABLE
;IF ALL IN CORE JUST OPEN AND WRITE OUT
;IF ON DSK EITHER RENAME OR COPY THEM

SAVSYM:	PUSHJ	P,.SAVE1##	;NEED AN AC
	CAIN	T1,1		;SIXBIT SYM FILE WANTED?
	MOVEI	P1,LS.IX	;YES, STORED IN LS AREA
	CAIN	T1,2		;HOW ABOUT ALGOL .SYM FILE?
	MOVEI	P1,AS.IX	;YES, USE AS AREA INSTEAD
	SKIPN	TAB.UW(P1)	;PAGING?
	JRST	WRTSYM		;NO
	MOVE	T1,TAB.AB(P1)	;MAKE SURE UW.XX IS OK
	SUB	T1,TAB.LB(P1)	;MIGHT BE -1 IF LS AREA
	ADD	T1,TAB.LW(P1)	;NOW HAVE HIGHEST LOC IN CORE
	MOVEM	T1,TAB.UW(P1)	;UPDATE UW.XX
	SETCM	T2,TAB.LB(P1)	;[2202] ALSO MAKE SURE DISK FILE IS OK
	ADD	T2,TAB.PT(P1)	;[2202] IN CASE NEVER OUTPUT BEFORE
	JUMPE	T2,.+4		;[2202] FORGET IT IF NOTHING TO OUTPUT
	ADD	T2,TAB.LW(P1)	;[2202] NOTE WE'RE GETTING EXACT WORD CNT
	MOVE	T1,TAB.LW(P1)	;[2202] ALGOL 7 NEEDS .RBSIZ EXACT
	PUSHJ	P,@TB.OUT##(P1)	;SO USE XX.PT INSTEAD OF XX.AB
	MOVE	T2,TAB.AB(P1)	;[2202] NOW READ IN FRONT OF FILE
	SUB	T2,TAB.LB(P1)	;[2202] SO CAN SET UP 10??,,COUNT
	SETZB	T1,TAB.LW(P1)	;[2366] ?W.?S MUST BE UP TO DATE
	MOVEM	T2,TAB.UW(P1)	;[2202] FOR FOLLOWING CALL
	PUSHJ	P,@TB.IN##(P1)	;AS FIRST WORD OF FILE
	CAIE	P1,AS.IX	;ALGOL?
	  JRST	SAVSY0		;NO, DO IT FOR LS AREA
	MOVE	T3,ASYM		;YES, GET SYMBOL COUNT
	HRLI	T3,1044		;AND BLOCK TYPE
	JRST	SAVSY1		;AND CONTINUE
SAVSY0:	MOVE	T3,LSYM		;COUNT FOR LS AREA
	HRLI	T3,1700		;AND BLOCK TYPE
SAVSY1:	SUBI	T3,1		;WORDS FOLLOWING IS 1 LESS
	MOVEM	T3,@TAB.LB(P1)	;STORE COUNT WORD
	SETZ	T1,		;[2366] GET LOWER WINDOW (ALWAYS ZERO)
	MOVE	T2,TAB.UW(P1)	;[2366] AND UPPER WINDOW
	PUSHJ	P,@TB.OUT##(P1)	;AND UPDATE FILE
	MOVEI	T1,SC		;FROM CHAN#
	CAIN	P1,AS.IX	;UNLESS AS AREA
	MOVEI	T1,AC		;IN WHICH CASE ALGOL CHANNEL
	MOVE	T2,IO.PTR+%SC	;TO CHANNEL
	PUSHJ	P,DVPRO.	;GET PROTECTION RIGHT
	MOVEI	T2,%SC		;TO CHAN#
	MOVE	T3,IO.PTR+%SC	;GET POINTER TO NEW FILE
	MOVE	T4,VERNUM	;GET VERSION OF PROGRAM
	SKIPN	I.VER(T3)	;UNLESS ALREADY SET BY SWITCH...
	MOVEM	T4,I.VER(T3)	;SAVE FOR ENTER
	PJRST	DVMOV.		;GO COPY PAGED FILE TO SYMBOL FILE
WRTSYM:
	MOVEI	T1,TC		;[1415] USE TEMPORARY CHANNEL
	MOVEM	T1,IO.CHN
	MOVE	T1,IO.PTR+%SC	;HIDE DATA BLOCK HERE
	MOVEM	T1,IO.PTR+TC	;[1415] NOW USE IT
	PUSHJ	P,DVCHN.##	;PUT ADDRESS OF BLOCK IN T1
	MOVSI	T2,(Z TC,)	;[1415] RESET CHANNEL NUMBER IN I/O FIELD
	MOVEM	T2,I.CHN(T1)	;SINCE %SC IS THERE CURRENTLY
	CAIE	P1,AS.IX	;ALGOL?
	  JRST	WRTSY0		;NO, SETUP 1ST WORD FOR LS
	MOVE	T3,ASYM		;YES, SETUP COUNT WORD
	HRLI	T3,1044		;AND BLOCK TYPE
	JRST	WRTSY1		;CONTINUE
WRTSY0:	MOVE	T3,LSYM		;LS AREA COUNT
	HRLI	T3,1700		;BLOCK TYPE FOR TRIPLET SYMBOLS
WRTSY1:	HRRZ	T2,T3		;SAVE COUNT FOR ESTIMATE
	SUBI	T3,1		;WORDS FOLLOWING IS 1 LESS
	MOVEM	T3,@TAB.LB(P1)	;SAVE WORD COUNT IN AREA
	LSH	T2,-.DBS2W	;[650] INTO BLOCKS
	MOVEM	T2,I.EST(T1)	;WE NEED THIS MUCH
	MOVE	T2,VERNUM	;GET VERSION OF CORE IMAGE
	SKIPN	I.VER(T1)	;SKIP IF SET BY SWITCH
	MOVEM	T2,I.VER(T1)	;NO, SO SET IT
	PUSHJ	P,DVNAM.##	;MAKE SURE NAME IS SET UP
	PUSHJ	P,DVOPN.##	;INIT DEVICE
	PUSHJ	P,DVENT.##	;ENTER FILE
				;NOW FOR OUTPUT
WRTSY2:	MOVE	T1,TAB.LB(P1)	;GET BOTTOM ADDR IN CORE
	SUB	T1,TAB.PT(P1)	;-LENGTH
	HRLZ	T1,T1		;-LENGTH,,0
	HRR	T1,TAB.LB(P1)	;FIRST ADDR OF BUFFER
	HRRI	T1,-1(T1)	;-LENGTH,,ADDR-1
	SETZ	T2,
	OUT	TC,T1		;[1415] WRITE IT
	PJRST	DVRLS.##	;PAGING NO LONGER HANDLED HERE
E01OES::
	PUSH	P,[TC]		;[1415] 
	.ERR.	(ST,,V%L,L%W,S%W,OES)
	POPJ	P,
SUBTTL  SET UP PROGRAM DATA VECTOR

; PDVSET  - ROUTINE TO SET UP THE PROGRAM DATA VECTOR
; THE COPY IS INITIALIZED AND READ INTO THE PROGRAM IMAGE.

IFN TOPS20,<
PDVSET:
	HRRZ	P1,PRGPDV	;[2306] GET THE PDV BLOCK
	HLRZ	W3,.PVNAM(P1)	;[2306] GET THE LENGTH OF THE NAME
	ADDI	W3,PV.LEN	;[2306] ADD THE PDV BLOCK SIZE
	ADDM	W3,PDMPLN	;[2306] SAVE THE MAXIMUM PDV SIZE
	SOS	T1,PDMPLN	;[2306] MAX OFFSET IS ONE LESS
	ADD	T1,PDVADR	;[2306] ADD THE ADDRESS
	CAMLE	T1,PVPLIM	;[2306] TOO MUCH?
	 JRST	E$$NPD		;[2306] YES, COMPLAIN
	ADD	W3,PDVADR	;[2306] ADD THE PDV ORIGIN
	MOVE	T1,W3		;[2306] GET THE START OF THE MEMORY MAP
	SKIPE	NOPDMP		;[2306] NO DEFAULT MAP?
	 SKIPA	T1,.PVMEM(P1)	;[2312] GET USER SUPPLIED VALUE 
	 MOVEM	T1,.PVMEM(P1)	;[2312] PUT IT IN THE PDV
	MOVE	T2,FXSBIT	;[2306] GET THE SECTION BITS
	JUMPE	T1,PDVST1	;[2306] DON'T BOTHER IF ZERO
	TLNN	T1,-1		;[2306] ANYTHING IN LEFT HALF?
	 HRLI	T1,(IFIW)	;[2237] NO, USE IFIW FORMAT
	TXNN	T2,^-1B0	;[2237] ANY NON-ZERO SECTIONS EXIST?
	MOVEM	T1,.PVMEM(P1)	;[2306] NO, PUT IFIW IN THE PDV
PDVST1:	SKIPN	T1,.PVSTR(P1)	;[2306] GET THE START/EXPORT ADDRESS, IF ANY
	 JRST	PDVST2		;[2306] NONE FOUND
	TLNN	T1,-1		;[2306] ANYTHING IN LEFT HALF?
	HRLI	T1,(IFIW)	;[2306] NO, SET AS AN IFIW
	TXNN	T2,^-1B0	;[2306] SECTION ZERO ONLY?
	 MOVEM	T1,.PVSTR(P1)	;[2306] YES, STORE AS IFIW
PDVST2:	SKIPN	T1,.PVCST(P1)	;[2306] GET THE CUSTOMER BLOCK ADDRESS, IF ANY
	 JRST	PDVST3		;[2306] NONE FOUND
	TLNN	T1,-1		;[2306] ANYTHING IN LEFT HALF?
	HRLI	T1,(IFIW)	;[2306] NO, SET AS AN IFIW
	TXNN	T2,^-1B0	;[2306] SECTION ZERO ONLY?
	 MOVEM	T1,.PVCST(P1)	;[2306] YES, STORE AS IFIW
PDVST3:	SKIPN	T1,.PVPRG(P1)	;[2306] GET THE PROGRAM BLOCK ADDRESS, IF ANY
	 JRST	PDVST4		;[2306] NONE FOUND
	TLNN	T1,-1		;[2306] ANYTHING IN LEFT HALF?
	HRLI	T1,(IFIW)	;[2306] NO, SET AS AN IFIW
	TXNN	T2,^-1B0	;[2306] SECTION ZERO ONLY?
	 MOVEM	T1,.PVPRG(P1)	;[2306] YES, STORE AS IFIW
PDVST4:	SKIPN	T1,.PVSYM(P1)	;[2311] GET THE SYMBOL VECTOR ADDRESS, IF ANY
	 JRST	PDVST5		;[2311] NONE FOUND
	TLNN	T1,-1		;[2311] ANYTHING IN LEFT HALF?
	HRLI	T1,(IFIW)	;[2311] NO, SET AS AN IFIW
	TXNN	T2,^-1B0	;[2311] SECTION ZERO ONLY?
	 MOVEM	T1,.PVSYM(P1)	;[2311] YES, STORE AS IFIW
PDVST5:	MOVE	T1,VERNUM	;[2311] SET VERSION NUMBER
	SKIPN	.PVVER(P1)	;[1423] UNLESS EXPLICITLY SET
	MOVEM	T1,.PVVER(P1)	;[1423]
	MOVE	T1,COMPDT	;[1423] SET COMPILATION TIME
	MOVEM	T1,.PVCTM(P1)	;[1423]
;[1423] WHEN COMPILERS BEGIN INCLUDING VERSION NUMBERS ADD HERE TWO LINES TO
;[1423] SET .PVCVR(P1) ALSO.
	PUSHJ	P,PDVGET	;[2306] GET THE USER'S PDV ADDRESSES IN MEMORY
	PUSHJ	P,PDVNAM	;[2306] STORE THE NAME
	SKIPN	NOPDMP		;[2306] USER SUPPLY MAP?
	 PUSHJ	P,PDVMMP	;[2306] NO, BUILD THE MEMORY MAP
	PJRST	PDVSTO		;[2306] STORE THE PDV ITSELF

;[2306] Store the PDV name, and set the PDV pointer to it
;[2306] Return first address after name in W3
PDVNAM:	HRRZ	P1,PRGPDV	;[2306] GET THE PDV ADDRESS AGAIN
	MOVE	T1,PDVADR	;[2306] DESTINATION IN IMAGE MEMORY
	ADDI	T1,PV.LEN	;[2306] AT END OF PDV BLOCK
	MOVE	W3,T1		;[2306] HOLD ONTO THIS ADDRESS
	SUB	T1,TAB.LW(R)	;[2306] SUBTRACT THE OFFSET
	ADD	T1,TAB.LB(R)	;[2306] FIXED IN LINK'S MEMORY
	HLRZ	T2,.PVNAM(P1)	;[2306] GET THE LENGTH OF THE NAME
	ADDI	T2,-1(T1)	;[2306] NAME END IN LINK'S MEMORY
	HRL	T1,.PVNAM(P1)	;[2306] BASE OF NAME
	BLT	T1,(T2)		;[2306] COPY IN THE NAME
	HLRZ	T2,.PVNAM(P1)	;[2306] GET THE SIZE OF THE NAME
	HRRZ	T1,.PVNAM(P1)	;[2306] AND THE ADDRESS
	PUSHJ	P,DY.RET##	;[2306] RETURN THE SPACE
	MOVE	T1,W3		;[2306] GET BACK THE ADDRESS
	ADD	W3,T2		;[2306] ADD LENGTH, POINT TO NEXT AFTER NAME
	ADD	T1,LL.S0(R)	;[2311] MAKE THE ADDRESS ABSOLUTE
	MOVE	T2,FXSBIT	;[2306] GET THE SECTION BITS
	TXNN	T2,^-1B0	;[2306] ANY NON-ZERO SECTIONS EXIST?
	 HRLI	T1,(IFIW)	;[2306] NO, USE IFIW FORMAT
	MOVEM	T1,.PVNAM(P1)	;[2306] SAVE THE POINTER
	POPJ	P,		;[2306] RETURN

;[2237] Build memory map.  The map length must be recalculated, since it
;[2237] could have changed since we allocated space for the PDV, etc.
;[2335] Expects the address of the map in W3.
PDVMMP:	SUB	W3,TAB.LW(R)	;[2306] SUBTRACT THE OFFSET
	ADD	W3,TAB.LB(R)	;[2306] FIXED IN LINK'S MEMORY
	PUSH	P,R		;[2306] KEEP THE SEGMENT INFO
	PUSH	P,W3		;[2306] AND KEEP THE FIRST WORD OF THE MAP
	ADDI	W3,1		;[2306] THE FIRST WORD IS THE COUNT
	PUSH	P,[0]		;[2237] INIT. MEMORY MAP LENGTH COUNTER
	MOVEI	R,1		;[2237] START WITH PSECT 1 (.LOW.)
	SKIPE	NOLOW		;[2247] NEED TO COUNT .LOW.?
	 MOVEI	R,2		;[2247] NO, START WITH SECOND PSECT
PDSLOP:	PUSHJ	P,PDVMAP	;[2237] GO FIND A CONTIGUOUS MEMORY BLOCK
	 JRST	PDSTLN		;[2237] NO MORE, ALL DONE SCANNING PSECTS
	PUSHJ	P,MAKXFW	;[2237] CONVERT TO XFIW'S AND STORE ADDRS.
	AOS	(P)		;[2237] FOUND ANOTHER BLOCK, ACCOUNT FOR IT
	JRST	PDSLOP		;[2237] KEEP COUNTING MEMORY MAP ENTRIES

PDSTLN:	JUMPE	R,PDVNUL	;[2237] DON'T PUT NULL LAST PSECT INTO MAP
	AOS	(P)		;[2237] ACCOUNT FOR LAST CALL TO PDVMAP
	PUSHJ	P,MAKXFW	;[2237] CONVERT TO XFIW'S AND STORE ADDRS.
PDVNUL:	POP	P,T1		;[2237] RESTORE # OF MEMORY MAP ENTRIES
	IMULI	T1,MM.SLN	;[2250] NUMBER OF WORDS PER SUB-TABLE
	ADDI	T1,1		;[2237] ACCOUNT FOR LENGTH WORD (+MISC. WORDS)
;[2237] T1 contains memory map length now.
	POP	P,W3		;[2306] GET THE POINTER TO THE FIRST WORD
	MOVEM	T1,.MMLEN(W3)	;[2306] STORE MAP LENGTH WORD IN MAP
	POP	P,R		;[2306] RESTORE THE SEGMENT
	POPJ	P,		;[2306] DONE

;[1423] VERIFY THAT THE NEEDED PAGES ARE CURRENTLY MAPPED IN
;[2306] USES T1-T4, P1, P2
PDVGET:	MOVE	P2,PVPSEG	;[1423] PICK UP RELOC COUNTER
	MOVE	R,RC.SG(P2)	;[2006] GET THE SEGMENT NUMBER
	MOVN	T1,LL.S0(R)	;[2016] GET THE SEGMENT BASE
	ADDB	T1,PDVADR	;[2016] T1 IS (OFFSET) UPPER BOUND
	MOVE	P2,T1		;[1760] T2 IS UPPER BOUND
	ADD	P2,PDMPLN	;[2237] COMPUTE LAST ADDRESS
	CAMLE	P2,HC.S0(R)	;[2016] HIGHER THAN HIGHEST CODE?
	 MOVEM	P2,HC.S0(R)	;[2016] YES, MAKE IT HIGHEST
	CAMLE	P2,HL.S0(R)	;[2016] HIGHER THAN HIGHEST LOADED?
	 MOVEM	P2,HL.S0(R)	;[2016] YES, MAKE IT HIGHEST
	SUB	P2,TAB.LW(R)	;[2006] SUBTRACT OFFSET
	ADD	P2,TAB.LB(R)	;[2006] ADD LOWER BOUND
	IORI	P2,.PGSIZ	;[2006] SET TO END OF PAGE
	CAML	T1,TAB.LW(R)	;[2006] T1 ABOVE WINDOW BOTTOM?
	CAMLE	P2,TAB.AB(R)	;[2006] AND T2 BELOW WINDOW TOP?
	 TRNA			;[2237] NO, REMAP WINDOW
	POPJ	P,		;[2306] YES

;[1423] CHANGE THE WINDOW MAP TO INCLUDE THE ALLOCATED PDV STORAGE.
	SKIPN	T2,TAB.UW(R)	;[2202] CHECK FOR PAGING
	 JRST	PDVSNP		;[2006] NOT PAGING - SPECIAL CASE
	MOVE	T1,TAB.LW(R)	;[2202] MAP OUT CURRENT WINDOW
	PUSHJ	P,@[LC.OUT##
		HC.OUT##]-1(R)	;[1423] AND UNMAP PAGES
	MOVE	T1,PDVADR	;[2237] GET PDV ADDRESS
	ANDCMI	T1,.PGSIZ	;[2006] SET TO BEGINNING OF PAGE
	MOVEM	T1,TAB.LW(R)	;[2006] START AT BEGINNING OF PAGE
	MOVE	P2,PDVADR	;[2006] GET BACK THE PDV ADDRESS
	ADD	P2,PDMPLN	;[2237] COMPUTE LAST ADDRESS
	IORI	P2,.PGSIZ	;[2006] SET TO END OF PAGE
	MOVE	T2,T1		;[2006] GET THE BASE
	ADD	T2,TAB.AB(R)	;[2006] ADD THE UPPER BOUND
	SUB	T2,TAB.LB(R)	;[2006] MINUS LOWER GIVES MAX SIZE
	CAMLE	T2,P2		;[2006] MORE THAN NEEDED?
	 MOVE	T2,P2		;[2006] NO, USE SMALLER AMOUNT
	MOVEM	T2,TAB.UW(R)	;[2006] NEW UPPER WINDOW
	SUB	T2,TAB.LW(R)	;[2006] GET SIZE
	ADD	T2,TAB.LB(R)	;[2006] GET NEW UPPER BOUND
	MOVEM	T2,TAB.AB(R)	;[2006] REMEMBER THE NEW BOUND
	MOVE	T2,TAB.UW(R)	;[2202] GET UPPER WINDOW
	PUSHJ	P,@[LC.IN##
		HC.IN##]-1(R)	;[1423] AND REMAP PAGES
	CAMG	P2,TAB.UW(R)	;[2006] WILL IT FIT?
	 POPJ	P,		;[2306] YES
	SUB	P2,TAB.LW(R)	;[2006] REMOVE THE OFFSET
	ADD	P2,TAB.LB(R)	;[2006] FIND OUT WHERE IT SHOULD GO
PDVSNP:	SUB	P2,TAB.AB(R)	;[2006] GET THE DIFFERENCE
	MOVE	P1,R		;[2006] GET THE SEGMENT
	PUSHJ	P,LNKCOR##	;[2006] EXPAND MEMORY
	 JRST	E$$MEF##	;[2006] NOT EXPECTED TO FAIL	
	POPJ	P,		;[2306] DONE

;[2306] Here to store the actual PDV.
PDVSTO:	MOVE	T1,PDVADR	;[2006] DESTINATION IN IMAGE MEMORY
	SUB	T1,TAB.LW(R)	;[2006] SUBTRACT THE OFFSET
	ADD	T1,TAB.LB(R)	;[2006] FIXED IN LINK'S MEMORY
	MOVEI	T2,PV.LEN	;[2306] GET THE PDV LENGTH
	ADDI	T2,-1(T1)	;[2237] PDV END IN LINK'S MEMORY
	HRL	T1,PRGPDV	;[2006] BASE OF STORED PDV
	BLT	T1,(T2)		;[1423] COPY IN THE PDV
	MOVE	T1,LL.S0(R)	;[2016] GET BACK THE OFFSET
	ADDM	T1,PDVADR	;[2016] ADJUST THE PDV ADDRESS
	POPJ	P,		;[1423] RETURN

;SUBROUTINE TO CONVERT ADDRESSES TO XFIW'S FOR MEMORY MAP.
;
;	CALL:	W3/ PDV MEMORY MAP ADDR. TO STORE SUB-TABLE ENTRY INTO
;
;	DATA AS RETURNED BY PDVMAP IS STORED IN PROPER FORMAT INTO MEMORY MAP.
;	THIS SUBROUTINE ASSUMES THE MAP SUB-TABLES ARE 3 WORDS LONG.
;
;	USED ACS: W1, AND T2 AND T3 IF THEY ARE CONVERTED TO IFIW'S
;	W3 IS LEFT POINTING TO THE NEXT SUB-TABLE ADDR.
;
MAKXFW:	MOVEI	W1,MM.SLN	;[2250] INIT. TO R.O., DEFAULT LENGTH
	TXNN	T4,AT.RO	;[2237] IS BLOCK READ-ONLY?
	 TXO	W1,PM%WR	;[2237] NO, SET "WRITABLE" BIT
	MOVEM	W1,.MMDAT(W3)	;[2245] STORE ATTRIBUTES,,SUB-TABLE LENGTH
	MOVE	W1,FXSBIT	;[2237] GET SECTION BITS
	TXNE	W1,^-1B0	;[2237] ANY NON-ZERO SECTIONS?
	 JRST	MAKEFW		;[2237] YES, USE EFIW FORMAT
	HRLI	T2,(IFIW)	;[2237] NO, USE IFIW FORMAT
	HRLI	T3,(IFIW)	;[2237]
MAKEFW:	MOVEM	T2,.MMLOW(W3)	;[2245] STORE BLOCK START ADDR.
	MOVEM	T3,.MMHGH(W3)	;[2245] STORE BLOCK END ADDR.
	ADDI	W3,MM.SLN	;[2250] STEP TO NEXT SUB-TABLE
	POPJ	P,		;[2237]

E$$NPD::.ERR.	(MS,.EC,V%L,L%W,S%W,NPD,<No space for program data vector in psect >) ;[2306]
	.ETC.	(SBX,.EP,,,,PVPNAM) ;[2306]
> ;[1423] IFN TOPS20
;HERE TO SETUP REST OF VESTIGIAL JOBDAT AREA
;ENTER WITH  P1 POINTING TO JOBDAT AREA

HJBSET:	JUMPE	P2,CPOPJ	;DON'T NEED TO DO THIS IF NO HIGH SEG
	HRRZ	T1,HL.S2	;GET HIGHEST HIGH SEG LOCATION+1
	SKIPE	.JBDDT(P1)	;IF DDT LOADED
	SOJA	T1,[IOR. T1,.PGSIZ	;INCLUDE ALL OF THIS PAGE
		AOJA	T1,.+1]		;IN LENGTH
	HRL	T1,.JBREN(P1)	;GET .JBREN
	MOVSM	T1,JOBHRN(P2)	;SET BOTH HALVES OF JOBHRN
	MOVE	T1,.JBSA(P1)	;PUT .JBSA
	MOVEM	T1,JOBHSA(P2)	;IN HIGH SEG
	MOVE	T1,.JB41(P1)
	MOVEM	T1,JOBH41(P2)
	MOVS	T1,.JBCOR(P1)
	SKIPN	.JBDDT(P1)	;TEST FOR RARE CASE OF DDT, SYMBOLS AND CODE
	JRST	.+3		; ALL IN HIGH SEGMENT
	TRNN	T1,-140		;TRUE IF HIGHEST LOC IS 137 OR LESS
	ADDI	T1,1		;IF SO MAKE IT 140 IN HIGH SEG
	MOVSM	T1,.JBHCR(P2)	; SO WE LOAD LOW
	MOVE	T1,.JBVER(P1)
	MOVEM	T1,.JBHVR(P2)
	SKIPE	T1,RUNAME	;GET PROGNAM
	JRST	.+3		;SET
	SKIPN	T1,SSNAME	;IF NOT TRY SAVE FILE NAME
	MOVE	T1,LODNAM	;USE DEFAULT IF NOT SET
	MOVEM	T1,.JBHNM(P2)	;INTO HIGH SEG
	MOVE	T1,HL.S1	;HIGHEST LOC +1 IN LOW SEG
	SUBI	T1,1
	IOR.	T1,.PGSIZ	;ROUND UP TO PAGE BOUNDARY
	ADDI	T1,1		;NEXT PAGE
	CAMGE	T1,LL.S2	;GREATER THAN HI-ORG?
	MOVE	T1,LL.S2	;NO
	LSH	T1,-9		;PAGE #
	HRLZM	T1,JOBHSO(P2)	;STORE IN HIGH
	HRRZM	T1,.JBHSO(P1)	;AND STORE
	POPJ	P,
;HERE TO SEE IF WE JUST STARTED PAGING AND IF SO, COPY
;JOBDAT OR VESTIGAL JOBDAT INTO DY AREA, SO WE CAN ALWAYS
;REFERENCE THEM EVEN IF THEY ARE PAGED OUT.

CHKPAG:
IFN TOPS20,<			;[2366]
	SKIPE	NOJBDA		;[2247] /NOJOBDAT OR NON-ZERO SECTIONS?
	 POPJ	P,		;[2247] YES
>;[2366] IFN TOPS20
	SKIPE	PAG.S1		;IF WE ARE PAGING
	SKIPE	JOBPTR		;FOR FIRST TIME
	CAIA			;NO
	PUSHJ	P,RDJBL		;MUST SETUP JOB DATA AREA
	SKIPE	PAG.S2		;SAME FOR HIGH SEG
	SKIPE	JBHPTR
	POPJ	P,		;[1172] DONE
	PUSHJ	P,RDJBH		;SET UP JOBDAT IN HIGH
	POPJ	P,

;HERE TO GET RID OF VARIOUS AREAS

GS.ZAP:	MOVEI	T1,GS.IX	;GET AREA
	PJRST	XX.ZAP##	;GENERAL ROUTINE

FX.ZAP:	MOVEI	T1,FX.IX
	PJRST	XX.ZAP##

LS.ZAP:	MOVEI	T1,LS.IX
	PJRST	XX.ZAP##

AS.ZAP:	MOVEI	T1,AS.IX
	PJRST	XX.ZAP##
SUBTTL PROGRAM LOAD IN NONZERO SECTIONS

IFN TOPS20,<			;[2202]

;[2247] Note that P1 points to the user's low segment JOBDAT
;[2247] and P2 points to the user's high segment JOBDAT.
SAVTST:	SKIPE	NOJBDA		;[2247] Suppressing JOBDAT?
	 JRST	SSINI		;[2247] Yes, don't bother with this
	HLRZ	T1,.JBSA(P1)	;[2247] Setup right half of .JBCOR
	SUBI	T1,1		;[2247] Point at last word used
IFN FTOVERLAY,<			;[2247] 
	SKIPL	LNKMAX		;[2247] Seen any?
	SKIPN	JOB116		;[2247] Yes, and want symbols?
	CAIA			;[2247] No
	HLRZ	T1,.JBCOR(P1)	;[2247] Include symbols
> ;[2247] IFN FTOVERLAY
	IOR.	T1,.PGSIZ	;[2247] To highest loc required
	HRRM	T1,.JBCOR(P1)	;[2247] So save get works
	PUSHJ	P,HJBSET	;[2247] And update the vestigial jobdat area

;Now, step through RC.TB checking each PSECT's attributes.  If any are
;read-only, set the page access accordingly.  If two PSECTS with conflicting
;read/write attributes are on the same page, set the page read-only.

SSINI:	MOVEI	R,2		;[2247] START WITH PSECT 2 (.LOW. ALWAYS R/W)
STACC1:	CAMLE	R,RC.NO		;[2206] YES, FINISHED CHECKING ALL PSECTS?
	 JRST	STDONE		;[2206] YES, EXIT ROUTINE
	MOVE	W2,@RC.TB	;[2206] NO, GET NEXT PSECT TABLE ADDR.
	MOVE	T1,RC.AT(W2)	;[2206] GET PSECT ATTRIBUTES
	TXNN	T1,AT.RO	;[2206] READ-ONLY?
	 AOJA	R,STACC1	;[2206] NO, STEP TO NEXT PSECT

;A read-only psect has been found.  Determine the start page and repeat
;count for setting all the psect pages to read/execute access.  Assume
;all psect pages are contiguous, but allow non-existent pages within it.

	MOVE	T1,RC.IV(W2)	;[2206] YES, GET PSECT INITIAL VALUE
	LSH	T1,-^D9		;[2206] TURN INTO PAGE NUMBER
	MOVE	T3,RC.HL(W2)	;[2206] GET HIGHEST PSECT ADDR. LOADED
	SUBI	T3,1		;[2261] GO BACK TO LAST ADDR. ACTUALLY LOADED
	LSH	T3,-^D9		;[2206] TURN INTO PAGE NUMBER
	SUB	T3,T1		;[2261] MAKE REPEAT COUNT-1 IN T3
	JUMPL	T3,STACC4	;[2265] DON'T SET ATTRIBUTES OF NULL PSECTS
	HRL	T1,LC.JF	;[2206] GET PROCESS DESIGNATOR
STACC2:	RPACS%			;[2206] GET PAGE ACCESSIBILITY
	 ERNAM	RPACS%		;[2261] CATCH FATAL ERRORS
	TXNE	T2,PA%PEX	;[2320] DOES PAGE EXIST?
	 JRST	STACC5		;[2320] YES, GO DEAL WITH IT
	HRRZ	P1,T1		;[2350] GET THE PAGE NUMBER
	LSH	P1,^D9		;[2350] MAKE IT AN ADDRESS
	MOVE	P2,RC.SG(W2)	;[2350] GET THE SEGMENT
	PUSHJ	P,QMAP		;[2350] MAP IT IN
	SETZM	(P1)		;[2350] TOUCH THE PAGE

STACC5:	MOVX	T2,PA%RD+PA%EX	;[2320] SET ACCESS TO READ AND EXECUTE
	SPACS%			;[2206] DO IT
	 ERNAM	SPACS%		;[2260] CATCH FATAL ERRORS
STACC3:	ADDI	T1,1		;[2206] INCREMENT TO NEXT PAGE
	SOJGE	T3,STACC2	;[2261] DECREMENT PAGE CTR. AND CONTINUE
STACC4:	AOJA	R,STACC1	;[2265] DONE WITH THIS PSECT, GO TO NEXT ONE

;[2350] Routine to get an address into memory.
;[2350] On entry, P1 contains the address and P2 contains the segment
;[2350] (1=low, 2=high).  On return, P1 points to the addressed word
;[2350] in memory.

QMAP:	CAMLE	P1,TAB.LW(P2)	;[2350] Is it already within the window?
	CAML	P1,TAB.UW(P2)	;[2350] (between lower and upper limits?)
	 CAIA			;[2350] No
	JRST	QMAP1		;[2350] Yes, simple case

	SPUSH	<T1,T2,T3,T4>	;[2350] No, get some ACs
	MOVE	T1,TAB.LW(P2)	;[2350] Get the lower window
	MOVE	T2,TAB.UW(P2)	;[2350] And the upper
	PUSHJ	P,@[LC.OUT##	;[2350]
		   HC.OUT##]-1(P2) ;[2350] Unmap the window

	MOVE	T1,TAB.LB(P2)	;[2350] Get the area bottom
	TRO	T1,.IPM		;[2350] Need one page
	MOVEM	T1,TAB.AB(P2)	;[2350] Set it (always available)

	MOVE	T1,P1		;[2350] Get the address
	TRZ	T1,.IPM		;[2350] Bottom of a page
	MOVE	T2,T1		;[2350] Get it again
	TRO	T2,.IPM		;[2350] Top of page
	MOVEM	T1,TAB.LW(P2)	;[2350] Set the	bottom of the window
	MOVEM	T2,TAB.UW(P2)	;[2350] And the top
	PUSHJ	P,@[LC.IN##	;[2350]
		   HC.IN##]-1(P2) ;[2350] Map the window
	SPOP	<T4,T3,T2,T1>	;[2350] Restore the ACs

QMAP1:	SUB	P1,TAB.LW(P2)	;[2350] Get the offset into the window
	ADD	P1,TAB.LB(P2)	;[2350] Add the base
	POPJ	P,

STDONE:				;[2206] ALL DONE, FALL THROUGH

; If there is a Program Data Vector, use the PDVOP% JSYS to
; declare its existence.
	SETOM	XJFLG		;[2277] Assume that extended JSYSes are OK
	SKIPN	T3,STADDR	;[2247] Address
	 JRST	SSINIG		;[2247] None continue on
	SKIPE	T2,ENTLEN	;[2247] Entry vector length specified?
	 JRST	SSINIA		;[2247] Yes, don't default it
	MOVEI	T2,1		;[2247] Default one word vector
	SKIPN	NOJBDA		;[2247] Doing a JOBDAT?
	MOVEI	T2,(JRST)	;[2247] Yes, default TOPS-10 entry vector
SSINIA:	MOVE	T1,LC.JF	;[2247] Pick up fork handle
	XSVEC%			;[1764] Set entry vector
	 ERCAL	[TLNE T3,-1	;[2247] A section zero address?
		 JRST [MOVX P2,'XSVEC%' ;[2274] No, a JSYS failure
		       PJRST E$$UMF##]  ;[2274] Go report it
		 HRL T2,T3	;[2247] Put args in T2
		 MOVSS T2	;[2247] As length,,address
		 SEVEC%		;[2247] Try the old way
		 ERNAM (SEVEC%)	;[2247] Catch errors
		 SETZM XJFLG	;[2277] Extended JSYSes are not OK now
		 POPJ	P,]	;[2247] Success
	JRST	SSINIB		;[2277] Don't check extended JSYSes again
SSINIG:	MOVX	T1,.FHSLF	;[2277] Point to LINK
	XGVEC%			;[2277] Try fake extended JSYS
	 ERJMP	[SETZM	XJFLG		;[2277] Simple case failed, can't do
		JRST	SSINIB]		;[2277] extended JSYSes any more
SSINIB:	SKIPN	PRGPDV		;[2277] Is there a PDV?
	 JRST	JBFORK		;[2247] No, don't set it up
	MOVEI	T1,.POADD	;[2247] Set up PDV
	MOVEI	T2,P1		;[2247] Point to argument block
	MOVEI	P1,4		;[2247] Four arguments
	MOVE	P2,LC.JF	;[2247] Get fork handle
	MOVEI	P3,1		;[2247] One PDV to set
	MOVEI	P4,PDVADR	;[2247] Point to the address
	PDVOP%			;[1425] [1423]
	 ERJMP	.+1		;[1427]
	HRRZ	T1,PRGPDV	;[1762] POINT TO PRIVATE COPY OF PDV
	MOVEI	T2,PV.LEN	;[2306] GET ITS LENGTH
	 PUSHJ	P,DY.RET##	;[1762] RETURN IT
; At this point three courses are open:
;	1.  Remove linker and leave program fork in place.
;	2.  Remove linker and start program fork.
;	3.  Remove linker, load and start debugger in the program fork.
;

; Set the name of the program fork to be the jobwide program name.
JBFORK:	SKIPE	IO.PTR+%VC		;[2247] .EXE requested?
	 PUSHJ	P,SAVEXE		;[2247] Yes, do it
MAPDDT:	SKIPN	GETDDT		;[2277] NEED TO GET DDT?
	 JRST	NODDT		;[2277] NO
	SETZM	UDDFLG		;[2277] YES, CLEAR "UDDT LOADED" FLAG
	MOVEI	T3,0		;[2277] SAY DDT IS IN SECTION 0 FOR NOW
	MOVE	T1,LC.JF	;[2277] GET FORK JFN
	GEVEC%			;[2277] GET LENGTH (DON'T NEED 30 BIT ADDR)
	 ERNAM	GEVEC%		;[2277] CATCH ERRORS
	MOVEM	T2,EVLEN	;[2277] SAVE IN CASE NEEDED LATER FOR KS
	SKIPN	XJFLG		;[2277] ARE EXTENDED JSYSES ALLOWED?
	 JRST	TRYUDD		;[2277] NO, ALWAYS USE UDDT
	MOVE	T4,FXSBIT	;[2277] YES, GET SECTION BITS
	TXNE	T4,^-1B0	;[2277] ANY NON-ZERO SECTIONS EXIST?
	 JRST	DOXDDT		;[2277] YES, USE EXTENDED DDT
	HLRZS	T2		;[2277] NO, PUT LENGTH ONLY IN RIGHT HALF
	CAIN	T2,(JRST)	;[2277] TOPS-10 ENTRY VECTOR?
	 JRST	TRYUDD		;[2277] YES, USE UDDT
DOXDDT:	MOVX	T1,GJ%OLD!GJ%SHT ;[2277] NO, USE XDDT FOR TOPS-20 ENTRY VECTOR
	HRROI	T2,[ASCIZ/SYS:XDDT.EXE/] ;[2277]
	MOVEM	T2,DDTASC	;[2314] SAVE ASCIZ DDT FILESPEC
	GTJFN%			;[2277] FIND XDDT
	 ERJMP	TRYUDD		;[2277] FAILED, TRY UDDT
	MOVEM	T1,DDTJFN	;[2277] SAVE JFN
	SETCA	T4,T4		;[2277] FIND HIGHEST FREE SECTION FOR XDDT
	TRZ	T4,17		;[2277] CLEAR BITS FOR SECTIONS 32-35
	MOVN	T3,T4		;[2277] TURN THE BITS UPSIDE-DOWN
	AND	T3,T4		;[2277] LEAVES A BIT POINTING TO 1ST FREE SEC.
	JFFO	T3,.+1		;[2277] TURN INTO SECTION #
	JUMPE	T4,E$$NFS	;[2277] 0=NO FREE SECT. FOR XDDT (CAN'T USE 0)
	HRL	T3,T4		;[2277] T3 HAS DESIRED (1ST FREE) SECTION # NOW
	JRST	DDTCOM		;[2277] JOIN COMMON CODE

TRYUDD:	MOVX	T1,GJ%OLD!GJ%SHT ;[2277] SHORT FORM, FILE MUST EXIST
	HRROI	T2,[ASCIZ/SYS:UDDT.EXE/] ;[2277]
	MOVEM	T2,DDTASC	;[2314] SAVE ASCIZ DDT FILESPEC
	GTJFN%			;[2277] TRY TO FIND UDDT
	 ERJMP	E$$DNA		;[2277] FAILED, DEBUGGER NOT AVAILABLE
	MOVEM	T1,DDTJFN	;[2277] SAVE JFN
	SETOM	UDDFLG		;[2277] FLAG THAT UDDT PTRS. MUST BE STUFFED
DDTCOM:	MOVE	T1,LC.JF	;[2277] GET PROGRAM FORK HANDLE
	SKIPN	XJFLG		;[2277] HAVE TO DO NON-EXTENDED CODE?
	 JRST	GVEC0		;[2277] YES, GO DO IT (FOR KS)
GOTXDD:	SKIPN	UDDFLG		;[2277] NO, UDDT OR XDDT?
	 PUSH	P,T3		;[2277] XDDT, SAVE DESIRED SECTION #
	XGVEC%			;[2277] GET ENTRY VECTOR
	 ERNAM	XGVEC%		;[2277] TRAP ERRORS
	DMOVEM	T2,EVLEN	;[2277] REMEMBER ENTRY VECTOR LENGTH & ADDR.
	SKIPN	UDDFLG		;[2277] UDDT OR XDDT?
	 POP	P,T3		;[2277] XDDT, RESTORE DDT'S SECTION #
	HRR	T1,DDTJFN	;[2277] GET DDT JFN
	HRL	T1,LC.JF	;[2277] GET FORK HANDLE
	TXO	T1,GT%NOV!GT%ARG ;[2277] DON'T OVERLAY, USE ARG BLOCK
	MOVX	T2,GT%BAS	;[2277] WE WANT TO SPECIFIY SECTION
	MOVEM	T2,GETBLK+.GFLAG ;[2277] SET FLAG BITS
	HLRZM	T3,GETBLK+.GBASE ;[2277] SPECIFY SECTION TO LOAD INTO
	MOVEI	T2,GETBLK	;[2277] POINT TO ARG BLOCK
	GET%			;[2277] NOW BRING IN DDT
	 ERJMP	E$$CLD		;[2277] CANNOT LOAD DDT
	HLRZS	T3		;[2314] PUT SECTION # IN T3 RIGHT
	MOVNS	T3		;[2314] AND MAKE IT NEGATIVE
	MOVX	T1,1B0		;[2314] SECTION # BIT
	LSH	T1,(T3)		;[2314] SET APPROPRIATE BIT FOR THE SECTION #
	IORM	T1,FXSBIT	;[2314] DECLARE SECTION TO EXIST
	MOVE	T1,LC.JF	;[2277] GET PROGRAM FORK HANDLE
	SKIPE	DEBUGSW		;[2277] WANT TO EXECUTE DDT?
	SKIPN	EXECSW		;[2277] (ONLY WITH /DEBUG)
	 JRST	NOEXDD		;[2277] NO
	HRRZ	T4,DEBUGSW	;[2363] WHICH DEBUGGER STARTS PROGRAM?
	CAIE	T4,DEB$DDT	;[2363] IS IT DDT?
	 JRST	NOEXDD		;[2363] NO, /TEST:DDT ONLY
	XGVEC%			;[2277] YES, PICKUP DDT'S ENTRY VECTOR
	 ERNAM	XGVEC%		;[2277] CATCH ERRORS
	MOVEM	T3,STADDR	;[2277] START ADDR. IS DDT NOW
	HRRM	T3,EXECSW	;[2362] STORE IN BOTH PLACES
NOEXDD:	DMOVE	T2,EVLEN	;[2277] RESTORE VECTOR LENGTH & ADDR.
	XSVEC%			;[2277] SET IT AGAIN
	 ERNAM	XSVEC%		;[2277] TRAP ERRORS
	JRST	STUFDD		;[2277] ALL DONE, CONTINUE LINK

;Section 0 style load.  This is necessary for KS processors which don't
;have the extended JSYSes.  This code is identical in function to the
;above code.
GVEC0:	HRR	T1,DDTJFN	;[2277] GET DDT JFN
	HRL	T1,LC.JF	;[2277] GET FORK HANDLE
	TXO	T1,GT%NOV	;[2277] DON'T OVERLAY
	GET%			;[2277] NOW BRING IN DDT
	 ERJMP	E$$CLD		;[2277] CANNOT LOAD DDT
	MOVX	T1,1B0		;[2314] SAY THAT SECTION 0 NOW EXISTS
	IORM	T1,FXSBIT	;[2314] DO IT
	MOVE	T1,LC.JF	;[2277] GET PROGRAM FORK HANDLE
	SKIPE	DEBUGSW		;[2277] WANT TO EXECUTE DDT?
	SKIPN	EXECSW		;[2277] (ONLY WITH /DEBUG)
	 JRST	NOEXS0		;[2277] NO
	GEVEC%			;[2277] YES, GET DDT'S START ADDR.
	 ERNAM	GEVEC%		;[2277] CATCH ERRORS
	HRRZM	T2,STADDR	;[2277] START PROGRAM AT 0,,ADDR
	HRRM	T2,EXECSW	;[2362] STORE IT IN BOTH PLACES
NOEXS0:	MOVE	T2,EVLEN	;[2277] RECOVER OLD ENTRY VECTOR
	SEVEC%			;[2277] SET IT (DDT CHANGED IT WHEN GET%'ING)
	 ERNAM	SEVEC%		;[2277] CATCH ERRORS
STUFDD:	SKIPN	UDDFLG		;[2277] NEED TO STUFF UDDT SYMBOL TABLE PTRS?
	 JRST	NODDT		;[2277] NO, SKIP THIS
	MOVEI	P2,LC.IX	;[2352] DDT IS ALWAYS IN THE LOW SEGMENT
	HLLZ	P1,T3		;[2352] GET DDT'S SECTION #
	HRRI	P1,DDTSA+1	;[2352] NEED WORD AFTER DDT START ADDRESS
	PUSHJ	P,QMAP		;[2352] MAP IT
	MOVE	P1,(P1)		;[2352] GET SYMBOL TABLE POINTER ADDR
	HLL	P1,T3		;[2352] GET THE SECTION NUMBER
	PUSH	P,P1		;[2352] REMEMBER THIS ADDRESS
	PUSHJ	P,QMAP		;[2352] MAP IT IN
	MOVE	T1,JOB116	;[2352] GET DEFINED SYM TABLE PTR
	MOVEM	T1,(P1)		;[2352] STUFF DDT'S SYMBOL TABLE PTR
	 ERCAL	E$$CSP		;[2277] CANNOT SET UDDT'S POINTERS?
	POP	P,P1		;[2352] GET ADDRESS BACK
	ADDI	P1,1		;[2352] NEXT ADDRESS FOR UNDEFINED 
	PUSHJ	P,QMAP		;[2352] MAP IT IN
	MOVE	T1,JOB117	;[2352] GET UNDEFINED SYM TABLE PTR
	MOVEM	T1,(P1)		;[2352] STUFF DDT'S SYMBOL TABLE PTR
	 ERCAL	E$$CSP		;[2277] CANNOT SET UDDT'S POINTERS?

NODDT:	PUSHJ	P,ENDEXE		;[2277] Finish up, close log file
	SETZM	F.EDIT			;[2247] Keep LNKSCN happy
	SKIPN	EXECSW			;[2247] execute preempts run switch
	SKIPN	N.ZER##			;[2247] Run switch pending?
	 CAIA				;[2247] No
	JRST	LNKSCN##		;[2247] Yes, go do the run switch

;[2247] Here to build the SPLFK% Argument block

	MOVEI	T1,6			;[2247] Six arguments
	MOVEM	T1,ARGBLK+.SFLEN	;[2247] Store in arg block
	MOVEI	T1,.SFUNS		;[2247] Get function code
	MOVEM	T1,ARGBLK+.SFCOD	;[2247] Store in arg block
	MOVE	T1,LC.JF		;[2247] Get the fork handle
	MOVEM	T1,ARGBLK+.SFUIN	;[2247] Store in arg block
	SETZM	ARGBLK+.SFUA1		;[2247] No PC flags
	MOVE	T1,STADDR		;[2247] Get the start address
	HRR	T1,EXECSW		;[2355] Debugger may change address
	MOVEM	T1,ARGBLK+.SFUA2	;[2247] Store in arg block

	PUSHJ	P,DOXMES		;[2247] Type the execute message

	MOVX	T1,SF%ADR		;[2247] Get the "start" bit
	SKIPN	EXECSW			;[2247] Want to execute this?
	SETZ	T1,			;[2247] No
	MOVEM	T1,ARGBLK+.SFUFL	;[2247] Set the flag

	MOVEI	T1,[KILPAT]		;[2347] Tell PA1050 To go away
	COMPT.	T1,			;[1460]
	 JFCL				;[1460] Error return not possible

	SKIPE	T1,RUNAME		;[1425]  Get program name
	JRST	.+3			;[1425]  Got a name
	SKIPN	T1,SSNAME		;[1425]  If not try save file name
	MOVE	T1,LODNAM		;[1425]  Use default if not set
	SETNM%				;[1425]  Set it

	MOVX	T1,<SF%EXT!ARGBLK>	;[2247] Get the splice fork arg
	SPLFK%				;[2247] Go for the user's program
	 ERJMP	JBNONE			;[2247] Failure!

;[2247] The splice fork failed, probably because the monitor
;[2247] does not have the extended code.  Tell the user, and
;[2247] Save the program if it has not already been.  Then get
;[2247] and optionally start the user's program.

;[2247] Since this code is not expected to be used, it was
;[2247] designed to be small rather than efficient.  In
;[2247] particular, the routine it calls to get the JFN on
;[2247] the .EXE file also opens the file, which them must
;[2247] be closed.  This is done to prevent having to write
;[2247] a new routine which would get the JFN without opening
;[2247] the file.

JBNONE:	MOVEI	T1,DC			;[2357] Set up channel
	MOVEM	T1,IO.CHN		;[2357] For EXE file
	SKIPE	R,IO.PTR+%VC		;[2357] .EXE requested?
	 JRST	E$$SPF			;[2247] Yes
	MOVEI	T2,F.LEN		;[2247] Set up file spec
	PUSHJ	P,DY.GET##		;[2247] As though we had seen /SAVE
	MOVE	P1,T1			;[2247] Store pointer to "scan" block
	HLLZ	T2,JOBNUM		;[2247] Sixbit jobnumber
	HRRI	T2,'LNK'		;[2247] Rest of name
	MOVEM	T2,F.NAME(T1)		;[2247] In the scan block
	MOVEM	T2,SSNAME		;[2247] Here also
	MOVSI	T2,'EXE'		;[2247] Get extension
	MOVEM	T2,F.EXT(T1)		;[2247] Store it in scan block
	MOVEM	T2,SSEXT		;[2247] For save file
	MOVSI	T2,'DSK'		;[2247] Make sure it goes on DSK
	MOVEM	T2,F.DEV(T1)		;[2247] Incase defaults screwed up
	PUSHJ	P,DVOUT.##		;[2247] Setup data block
	  %VC,,.IODPR			;[2247] On fake chan in dump mode
	SETZ	R,			;[2247] In case DVOUT. set it

E$$SPF::.ERR.	(MS,.EC,V%L,L%F,S%W,SPF,<Splice fork failed>) ;[2247]
	.ETC.	(XCT,.EC,,,,<[SKIPE R]>) ;[2247] Already had save file?
	.ETC.	(JMP,.EC,,,,JBNON1) ;[2247] Yes, don't say "saving on..."
	.ETC.	(STR,.EC,,,,,<, saving on file >) ;[2247]
	.ETC.	(FSP,.EC,,,,%VC)	;[2247] Type the filespec
JBNON1:	.ETC.	(NOP)			;[2247] End
;Remove DDT from the user's core image before creating the .EXE file.
	SETZM	UDPTRS		;[2314] CLEAR "POKE UDDT IN SEC. 0" FLAG 
	SKIPN	GETDDT		;[2314] DID USER HAVE DDT IN MEMORY?
	 JRST	JBNON3		;[2314] NO
	SETO	T1,		;[2314] YES, PREPARE TO DELETE PAGES/SECTION
	SKIPE	UDDFLG		;[2314] XDDT (ITS OWN SECTION) OR UDDT?
	 JRST	JBNONU		;[2314] UDDT, GO UNMAP JUST UDDT'S PAGES
	HRL	T2,LC.JF	;[2314] XDDT, GET FORK HANDLE
	HRR	T2,GETBLK+.GBASE ;[2314] GET SECTION NUMBER
	MOVEI	T3,1		;[2314] DELETE 1 SECTION
	SMAP%			;[2314] BLOW AWAY XDDT AND ITS SECTION
	 ERNAM	SMAP%		;[2314] CATCH ERRORS
	JRST	JBNON3		;[2314] DONE
JBNONU:	HRR	T2,GETBLK+.GBASE ;[2314] GET SECTION #
	LSH	T2,^D9		;[2314] MOVE IT OVER
	TXO	T2,DDTPAG	;[2314] BEGIN UNMAPPING UDDT AT THIS PAGE
	HRL	T2,LC.JF	;[2314] GET FORK HANDLE
	MOVX	T3,PM%CNT+1000-DDTPAG ;[2314] # OF PAGES TO REMOVE FROM PROCESS
	PMAP%			;[2314] BLOW AWAY UDDT
	 ERNAM	PMAP%		;[2314] CATCH ERRORS

JBNON3:	SKIPN	R		;[2314] ALREADY GOT AN .EXE FILE?
	 PUSHJ	P,SAVEXE	;[2314] NO, GO MAKE ONE
	SKIPN	GETDDT		;[2314] YES, NEED TO LOAD A DDT?
	 JRST	JBNON2		;[2314] NO
	SKIPN	UDDFLG		;[2314] YES, UDDT OR XDDT?
	 JRST	JBNONX		;[2314] XDDT, GO DO IT
	SKIPE	T3,GETBLK+.GBASE ;[2314] UDDT, GET SECTION # TO LOAD IT INTO
	 JRST	JBNONX		;[2314] NON-ZERO, NO CONFLICT WITH LINK & DDT
	MOVX	T1,<.FHSLF,,770> ;[2314] PREPARE TO SEE IF WE'RE DDT'ING LINK
	RPACS%			;[2314] SEE IF UDDT'S FIRST PAGE IS THERE
	 ERNAM	RPACS%		;[2314] CATCH ERRORS
	TXNN	T2,PA%PEX	;[2314] DOES PAGE EXIST?
	 JRST	JBNONX		;[2314] NO, NO CONFLICT POSSIBLE
	MOVE	T2,770000	;[2314] YES, GET FIRST WORD OF PAGE 770
	CAMN	T2,[JRST 770002] ;[2314] DOES IT LOOK LIKE UDDT?
	 JRST	JBNON4		;[2314] YES, SPECIAL CASE - DON'T GET% UDDT
JBNONX:	MOVX	T1,GJ%OLD!GJ%SHT ;[2314] GET GTJFN% BITS
	MOVE	T2,DDTASC	;[2314] GET ASCIZ DDT FILESPEC
	GTJFN%			;[2314] FIND X/UDDT (WE FOUND IT BEFORE)
	 ERNAM	GTJFN%		;[2314] THIS WORKED BEFORE, SHOULD'VE HERE TOO!
	HRLI	T1,.FHSLF	;[2314] GET FORK HANDLE (LINK)
	SKIPN	XJFLG		;[2314] EXTENDED JSYSES ALLOWED?
	 JRST	JBNONZ		;[2314] NO, DO IT THE SIMPLE WAY
	TXO	T1,GT%NOV!GT%ARG ;[2314] YES, DON'T OVERLAY, USE ARG BLOCK
	MOVEI	T2,GETBLK	;[2314] POINT TO ARG BLOCK
	GET%			;[2314] NOW BRING X/UDDT INTO PROPER SECTION
	 ERNAM	GET%		;[2314] THIS WORKED BEFORE, SHOULD'VE HERE TOO!
	JRST	JBNON2		;[2314] DDT LOADED, START ADDRS. ALREADY SET

;Here when DDT is loaded with LINK and we want UDDT in section 0.
JBNON4:	DMOVE	T1,JOB116	;[2314] GET SYMBOL TABLE PTRS.
	DMOVEM	T1,UDPTRS	;[2314] SAVE THEM AND REMEMBER TO POKE LATER
	JRST	JBNON2		;[2314]

;Here for non-extended (KS) case.
JBNONZ:	TXO	T1,GT%NOV	;[2314] DON'T OVERLAY
	GET%			;[2314] NOW BRING UDDT INTO SECTION 0
	 ERNAM	GET%		;[2314] THIS WORKED BEFORE, SHOULD'VE HERE TOO!

JBNON2:	MOVE	T1,LC.JF	;[2314] Get the inferior
	KFORK%				;[2247] Kill it
	 ERNAM	(KFORK%)		;[2274] Should not fail

	PUSHJ	P,DVLKP.##		;[2247] Open the exe file
	 PUSHJ	P,E$$EOI		;[2357] Unexpected failure
	MOVX	T1,CO%NRJ		;[2247] Don't want to lose the JFN
	HRR	T1,DC.JF		;[2247] Get the JFN
	CLOSF%				;[2247] Close it
	 ERNAM	(CLOSF%)		;[2274] Should not fail

	MOVE	T1,[R%ACS,,ACS]		;[2247] Copy run code to writable place
	BLT	T1,ACS+R%17		;[2247]
	MOVE	T1,DC.JF		;[2247] Get the EXE file JFN
	HRRM	T1,ACS+R%16		;[2247] Put JFN in get JSYS argument
	MOVE	T1,STADDR		;[2247] Get the start address
	HRR	T1,EXECSW		;[2360] Debugger may change address
	SKIPE	EXECSW			;[2247] Want to execute?
	MOVEM	T1,ACS+R%12		;[2247] Yes, store address
	MOVE	T2,[JRST @R%12]		;[2247] Get the short JRST
	TLNN	T1,-1			;[2247] Doing extended addressing?
	MOVEM	T2,ACS+R%10		;[2247] No, use JRST (in case KS10)
	MOVX	T1,.POREM	;[2314] PREPARE TO REMOVE LINK'S PDV ADDR.
	MOVEI	T2,[.POADE+1	;[2353] LENGTH OF ARG BLOCK
		    .FHSLF	;[2353] DO IT TO OUR FORK (LINK)
		    0		;[2353] NO RETURNED VALUES EXPECTED
		    0           ;[2353] NO BLOCK FOR RETURNED VALUES
		    20		;[2353] START ADDR. TO REMOVE PDV ADDR. FROM
	            <DDTPAG*1000>-1] ;[2353] END ADDR. IS JUST BELOW UDDT
	PDVOP%			;[2314] REMOVE LINK'S PDV
	 ERNAM	PDVOP%		;[2314] CATCH ERRORS
	MOVEI	T1,.FHSLF	;[2314] POINT TO OUT PROCESS
	SETO	T2,		;[2314] PREPARE TO DISABLE ALL PSI CHANNELS
	DIC%			;[2314]  TO PREVENT PROBLEMS WHEN ZEROING
	 ERNAM	DIC%		;[2314]  TABLE ADDRESSES OUT
	MOVEI	T2,0		;[2314] PREPARE TO CLEAR PSI TABLE ADDRS.
	SIR%			;[2314] DO IT (RESET% DOESN'T CLEAR ADDRS.)
	 ERNAM	SIR%		;[2314] CATCH ERRORS
	DMOVE	T1,UDPTRS	;[2314] GET FLAG/PTRS. TO POKE UDDT
	SKIPE	T1		;[2314] HAVE TO POKE SECTION 0 UDDT?
	 DMOVEM	T1,@770001	;[2314] YES, DO IT (CAN'T SEE LINK SYMS. NOW)
	MOVE	R%17,[ACS,,R%0]		;[2247] Copy poked code to ACS
	BLT	R%17,R%17		;[2247]   ..
	JRST	R%4			;[2247] Go start program

;[2247] Final suicide code for running a program

R%ACS:	PHASE	0		;[2247] Get into the ACS
R%0:!	0			;[2247] Unused
R%1:!	-1			;[2247] PMAP% arguments to unmap all of memory
R%2:!	.FHSLF,,0		;[2247]   ..
R%3:!	PM%CNT+DDTPAG		;[2314] Don't unmap DDT (if debugging LINK)
R%4:!	PMAP%			;[2247] Beginning of suicide code--unmap pages
R%5:!	MOVE	R%1,R%16	;[2247] Load GET% argument
R%6:!	GET%			;[2247] Bring in program
R%7:!	RESET%			;[2247] Do RESET JSYS to clear PSI, etc.
R%10:!	XJRSTF	R%11		;[2247] Start the program
R%11:!	0			;[2247] PC Flags
R%12:!	R%13			;[2247] Where to start program
R%13:!	HALTF%			;[2247] Start of program if no /EXECUTE
R%14:!	JRST R%13		;[2247] Not a continuable halt
R%15:!	0			;[2247] Unused
R%16:!	.FHSLF,,.-.		;[2247] Poked with GET% JSYS argument
R%17:!	0			;[2247] Unused
	DEPHASE

SAVEXE:
E$$CSF::.ERR.	(MS,0,V%L,L%I,S%I,CSF,<Creating saved file>) ;[2247]
	PUSHJ	P,EXEINI		;[2247] Get a JFN
	MOVE	T1,T3			;[2247] Fetch spare JFN
	HRL	T1,LC.JF		;[2247] Get the fork handle
	MOVE	T3,HL.S1		;[2364] Get the highest loaded
	IORI	T3,777777		;[2274] Set to top of section
	ADDI	T3,1			;[2274] Number of words to transfer
	LSH	T3,-^D9			;[2274] Convert it to pages
	MOVNS	T3			;[2274] Negate it
	MOVX	T2,<SS%UCA!SS%CPY!SS%RD!SS%WR!SS%EXE!SS%EPN> ;[2317] Get flags
	HRL	T2,T3			;[2274] Save all pages
	SETZ	T3,			;[2247] Starting with page zero
	SSAVE%				;Save the pages
	 ERJMP	E$$EOE			;[2247] Too bad

	HRRZ	T1,DC.JF		;[2346] Get other JFN on exe file
	DVCHR%				;[2346] Get the device charisterics
	 ERNAM	(DVCHR%)		;[2346] Very unhealthy device
	LDB	T2,[POINTR T2,DV%TYP]	;[2346] Get the device type
	CAIE	T2,.DVDSK		;[2346] Is it a disk?
	 JRST	[HRRZ T1,DC.JF		;[2346] No, get the JFN again
		 RLJFN%			;[2346] Give it back
		 ERNAM (RLJFN%)		;[2346] Unexpected problem
		 SETZM IO.PTR+%VC	;[2346] Remember no usable EXE
		 POPJ P,]		;[2346] Return

	HRRZ	T1,DC.JF		;[2346] Get JFN on exe file again
	HRL	T1,LC.JF		;[2346] And the fork handle
	GET%				;[2247] Map them back in
	 ERNAM	(GET%)			;[2247] Unexpected failure
	POPJ	P,			;[2247] File saved

;[2247] Here to make the final decision about execution, and to type
;[2247] the appropriate messages.  Don't execute the program if there
;[2247] are errors unless /DEBUG is set.
DOXMES:	SKIPN	STADDR			;[2247] Is there a start addr?
	 PUSHJ	P,E02NSA		;[2247] No
	SKIPN	EXECSW			;[2247] Start it?
	 POPJ	P,			;[2247] No
	SKIPE	ERRNO			;[2247] Don't run if errors
	SKIPGE	DEBUGSW			;[2247] Unless debugging
	 PJRST	EXEMES			;[2247] No, announce execution
E02DLT::.ERR.	(MS,0,V%L,L%F,S%W,DLT,<Execution deleted>) ;[2247]
	SETZM	EXECSW			;[2247] Don't execute
	POPJ	P,			;[2247] Return

E02NSA::.ERR.	(MS,0,V%L,L%F,S%I,NSA,<No start address>) ;[2247]
	AOS	ERRNO			;[2247] Don't execute
	POPJ	P,			;[2247] Return


> ;[2202] IFN TOPS20
IFE TOPS20,<			;[2247]
SUBTTL	DECIDE TO LOAD OR SAVE


;DETERMINE IF WE CAN LOAD THE PROGRAM INTO MEMORY OR MUST WRITE AN .EXE FILE
;INSTEAD. WE MUST WRITE AN .EXE FILE IF ANY OF THE FOLLOWING ARE SATISFIED:
;
;  1.	USER SPECIFIED /SAVE (SCAN BLOCK ALREADY SET UP).
;  2.	THERE ARE PAGE GAPS BETWEEN PSECTS, EXCEPT BELOW .HIGH. (BEWARE THAT
;	OVERLAPS DO NOT COUNT AS GAPS).
;  3.	THERE ARE ANY PSECTS ABOVE THE HIGH SEGMENT.
;  4.	ANY PSECT HAS NON-DEFAULT WRITEABILITY.
;  5.	THE PROGRAM WILL NOT FIT IN MEMORY WITH LINK'S FINAL PLACEMENT CODE
;	(THIS INCLUDES THE CASE IN WHICH THE REMAP UUO WOULD HAVE TO MOVE THE
;	HIGH SEGMENT DOWN).

SAVTST:
	SKIPE	IO.PTR+%VC	;[1146] SAVE FILE REQUIRED?
	JRST	JBSAVE		;YES

;TEST FOR GAPS BETWEEN PSECTS, PSECTS ABOVE THE HIGH SEGMENT AND PSECT
;PROPERTIES THAT WE CAN'T HANDLE EXCEPT IN AN EXE FILE.

	MOVE	T1,HL.S1	;[1146] SEE IF LOW SEG (CONTAINS ALL PSECTS)
	SKIPE	LL.S2		;[1170]   HITS HIGH SEG (IF ANY) WHICH CHECKS
	CAMG	T1,LL.S2	;[1146]   FOR PSECTS ABOVE HIGH SEG ORIGIN
	SKIPA			;[1146] NO--OK SO FAR
	JRST	JBCMPX		;[1146] YES--CAN'T LOAD IT
	MOVEI	R,0		;[1146] START AT .ABS.
	MOVE	W1,@RC.TB	;[1146] GET POINTER TO ITS RELOC BLOCK
	MOVE	T1,RC.HL(W1)	;[1146] START WITH ITS HIGH LIMIT
	ADDI	R,1		;[1146] ADVANCE TO .LOW. FOR CHECKS
	MOVX	T4,2		;[1146] # OF SEG CONTAINING ONLY .HIGH.

;BACK HERE FOR EACH NEW PSECT.

SAVTS1:	MOVE	W2,@RC.TB	;[1146] GET POINTER TO THIS RELOC BLOCK
	MOVE	T2,RC.AT(W2)	;[1171] GET THIS PSECT'S ATTRIBUTES

	CAMN	T4,RC.SG(W2)	;[1171] TOPS-10 HIGH SEGMENT?
	JRST	[TXNE T2,AT.RW	;[1171] YES, USER ASKED FOR WRITEABLE?
		JRST JBCMPX	;[1171] YES, LET MONITOR FIGURE IT OUT
		JRST SAVTS2]	;[1171] NO, ATTRIBUTES ARE OK

	TXNE	T2,AT.RO	;[1171] NON-HI SEG PAGE TO BE READ ONLY?
	JRST	JBCMPX		;[1171] YES, WE CAN'T HANDLE IT
SAVTS2:	CAML	T1,RC.HL(W2)	;[1171] DOES PREVIOUS PSECT ENGULF THIS ONE?
	JRST	SAVTS6		;[1171] YES--NO GAP POSSIBLE YET
	CAMN	T4,RC.SG(W2)	;[1146] POSSIBLE GAP BELOW .HIGH.?
	JRST	SAVTS5		;[1171] YES--OK. USUAL CASE
	MOVEI	T2,-1(T1)	;[1146] COMPUTE LAST PAGE USED
	LSH	T2,-9		;[1146]   ..
	LDB	T3,[POINTR RC.IV(W2),^-^O777] ;[1146] GET FIRST PAGE USED BY NEXT PSECT
	SUB	T3,T2		;[1146] COMPUTE # PAGES BETWEEN THIS AND LAST
	SOJG	T3,JBCMPX	;[1146] CAN'T LEAVE GAPS IN MEMORY
SAVTS5:	MOVE	T1,RC.HL(W2)	;[1171] SO FAR SO GOOD--ADVANCE TO NEXT PSECT
SAVTS6:	MOVE	W1,W2		;[1171] ADVANCE TO NEXT PSECT
	CAMGE	R,RC.NO		;[1146] LOOKED AT ALL PSECTS?
	AOJA	R,SAVTS1	;[1146] NO--LOOK AT NEXT
	;  ..
	;  ..

;COMPUTE HOW MUCH MEMORY IT WILL TAKE TO HOLD THE PROGRAM DURING THE LAST STAGES
;OF LOADING, AND MAKE SURE THAT WE CAN GET THAT MUCH.  IF  WE  CAN'T,  THEN  THE
;PROGRAM IS TOO COMPLEX. THERE ARE TWO SIZES TO WORRY ABOUT:
;
;  1.	LINK'S  LOW SEGMENT + THE PROGRAM'S ACTUALLY LOADED LOW SEGMENT (DOESN'T
;	COUNT BLOCK'S AT THE END OF THE LOW SEGMENT) + THE PROGRAM'S ACTUALLY
;	LOADED HIGH SEGMENT. THIS IS THE MEMORY REQUIREMENT IN JBLOAD.
;
;  2.	THE  PROGRAM'S  ENTIRE  LOW  SEGMENT + HIGH SEGMENT.  THIS IS THE MEMORY
;	REQUIREMENT IN THE FINAL EXIT CODE AT %5.  NOTE THAT  WE  MUST  REMEMBER
;	THAT WE HAVE A HIGH SEGMENT NOW BUT WON'T THEN.

	MOVE	T1,DY.AB	;[1146] START WITH HIGHEST ADDR LINK NEEDS
	ADD	T1,HC.S1	;[1146] ADD LENGTH OF ACTUALLY LOADED CODE
	IOR.	T1,.PGSIZ	;[1146]   ..
	SKIPE	LL.S2		;[1170] HIGH SEG EXISTS
	CAMGE	T1,LL.S2	;[1146]   AND ORIGIN BELOW WHERE WE CAN PUT IT?
	SKIPA			;[1146] NO--OK
	JRST	JBCMPX		;[1146] YES--REMAP WOULD FAIL SO TOO COMPLEX
	ADD	T1,HC.S2	;[1170] ADD LENGTH OF HIGH SEGMENT
	IOR.	T1,.PGSIZ	;[1146]   ..
	HRRZ	T2,.JBHRL##	;[1170] DON'T COUNT SIZE OF CURRENT HIGH SEG
	SUB	T2,HIORGN	;[1170]   ..
	MOVNI	T2,2(T2)	;[1170]   ..
	ADD	T2,HL.S1	;[1170] + ENTIRE PROGRAM LOW SEG
	IOR.	T2,.PGSIZ	;[1170]   ROUNDED TO A PAGE
	ADD	T2,HL.S2	;[1170] + ENTIRE PROGRAM HIGH SEG
	IOR.	T2,.PGSIZ	;[1170]   ROUNDED TO A PAGE TOO
	CAMGE	T1,T2		;[1170] PICK MAX OF TWO
	MOVE	T1,T2		;[1170]   ..
	TLNE	T1,-1		;[732] OVERFLOWED INTO THE LH?
	JRST	JBCMPX		;[1146] YES--CAN'T FIT SO WRITE .EXE FILE
	CAMG	T1,.JBREL	;DO WE HAVE ENOUGH ALREADY?
	JRST	JBLOAD		;[1146] YES, READ IN REST OF TEMP FILE
	CORE	T1,		;NO TRY FOR IT
	  JRST	JBCMPX		;[1146] WON'T FIT--WRITE .EXE FILE
	MOVEI	T1,HG.TAB	;OK, BUT DON'T FORGET TO GIVE IT TO SOMEONE
	SKIPN	TAB.LB(T1)	;USUAL LOOP
	SOJA	T1,.-1
	MOVE	T2,.JBREL
	MOVEM	T2,TAB.UB(T1)
	JRST	JBLOAD		;[1146] PROGRAM WILL FIT--GO BRING IT IN
SUBTTL	FORCE nnnLNK/SAVE


;HERE IF USER DID NOT SPECIFY /SAVE BUT PROGRAM IS TOO COMPLEX (TOO LARGE, PSECT
;GAPS, ETC.) TO LOAD. DUMMY UP A SCAN BLOCK AS IF THE USER TYPED nnnLNK/SAVE,
;PRINT A WARNING AND FALL INTO .EXE WRITING CODE.

JBCMPX:	MOVEI	T2,F.LEN	;[1146] SET UP FILE SPEC
	PUSHJ	P,DY.GET##	;AS THOUGH WE HAD SEEN /SAVE
	PUSH	P,P1		;[1261] Save pointer to users JOBDAT area
	MOVE	P1,T1		;STORE POINTER TO "SCAN" BLOCK
	HLLZ	T2,JOBNUM	;SIXBIT JOBNUMBER
	HRRI	T2,'LNK'	;REST OF NAME
	MOVEM	T2,F.NAME(T1)
	MOVEM	T2,SSNAME	;HERE ALSO
IFE FTEXE,<
	MOVSI	T2,'HGH'	;MARK NON-SHAREABLE
	SKIPN	HL.S2		;IF NO HIGH
	MOVSI	T2,'SAV'	;SO MESSAGE IS CORRECT
>
IFN FTEXE,<
	MOVSI	T2,'EXE'	;SO MESSAGE IS CORRECT
>
	MOVEM	T2,F.EXT(T1)	
	MOVEM	T2,SSEXT	;FOR SAVE FILE
	MOVSI	T2,'DSK'	;MAKE SURE IT GOES ON DSK
	MOVEM	T2,F.DEV(T1)	;INCASE DEFAULTS SCREWED UP BY NOW
	PUSHJ	P,DVOUT.##	;SETUP DATA BLOCK
	  %VC,,.IODPR		;ON FAKE CHAN IN DUMP MODE
	SKIPE	EXECSW		;WANT TO EXECUTE?
	JRST	E$$PCX		;[1174] YES--LNKPCX
E$$PCL::.ERR.	(MS,.EC,V%L,L%W,S%W,PCL,<Program too complex to load, saving as file >) ;[1174]
	.ETC.	(JMP,.EC,,,,JBCMP2)
E$$PCX::.ERR.	(MS,.EC,V%L,L%W,S%I,PCX,<Program too complex to load and execute, will run from file >) ;[1174]
JBCMP2:	.ETC.	(FSP,,,,,%VC)
	POP	P,P1		;[1261] RESTORE USERS JOBDAT POINTER
;	JRST	JBSAVE		;[1146] FALL THROUGH TO WRITE .EXE FILE
SUBTTL	GENERATE .EXE (OR .XPN/.SHR/.HGH/.LOW) FILE

>;[2247] IFE TOPS20	
;SOME JOBDAT LOCATIONS WE NEED TO KNOW
.JBHSO==75		;PAGE # OF HIGH SEG ORIGIN
.JBSDD==114		;SAVED .JBDDT
.JBS41==122		;SAVED .JB41
	EXTERN	.JBREN
JOBHSA==0		;HIGH .JBSA
JOBH41==1		;HIGH .JB41
JOBHRN==3		;HIGH .JBHRL & .JBREN
JOBHSO==7		;PAGE # OF HIGH SEG ORIGIN IN HIGH

IFE TOPS20,<			;[2247]
;HERE TO SETUP SAVED LOCATIONS
JBSAVE:				;[1174] WRITE A SAVED FILE
E$$CSF::.ERR.	(MS,0,V%L,L%I,S%I,CSF,<Creating saved file>) ;[1174]
IFE FTEXE,<
	MOVE	T2,.JBDDT(P1)	;GET DDT  START
	MOVEM	T2,.JBSDD(P1)	;TO SAFE PLACE
	MOVE	T2,.JB41(P1)	;SAME FOR UUO HANDLER
	MOVEM	T2,.JBS41(P1)
>
	HLRZ	T1,.JBSA(P1)	;ALSO SETUP RIGHT HALF OF .JBCOR
	SUBI	T1,1		;[1317] POINT AT LAST WORD USED
IFN FTOVERLAY,<
	SKIPL	LNKMAX		;SEEN ANY?
	SKIPN	JOB116		;YES, AND WANT SYMBOLS?
	CAIA			;NO
	HLRZ	T1,.JBCOR(P1)	;INCLUDE SYMBOLS
>
	IOR.	T1,.PGSIZ	;TO HIGHEST LOC REQUIRED
	HRRM	T1,.JBCOR(P1)	;SO SAVE GET WORKS
	SKIPL	SYMSEG		;[1132] SYMBOLS IN A PSECT?
	JRST	JBSAVX		;[1132] NO, SKIP THIS
	HLRE	T1,.JBSYM(P1)	;[1132] YES, GET -LENGTH OF TABLE
	HRRZ	T2,.JBSYM(P1)	;[1132] GET FIRST ADDR OF TABLE
	SUB	T2,T1		;[1132] COMPUTE FIRST FREE AFTER TABLE
	CAMLE	T2,HC.S1	;[1132] UPDATE AMOUNT OF CODE IN LC AREA
	MOVEM	T2,HC.S1	;[1132] BUT NEVER DECREASE
	CAMLE	T2,HL.S1	;[1132] ALSO UPDATE SIZE OF SEGMENT
	MOVEM	T2,HL.S1	;[1132] NEVER D