Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/lib5/crt.c
There are 9 other files named crt.c in the archive. Click here to see a list.
/*
** CRT - C Run Time machine-language support routines
**	Split out and rewritten from TOPS20.FAI by KLH@SRI-NIC, June 1985
**	Revised for new syntax features by KLH, Sep 1986
**	Edits for ITS:  Copyright (C) 1988 Alan Bawden
**
**	CRT consists of the essential machine-language support needed
** to run any KCC-compiled program.  All possible routines are included
** in this one module, and no others; in particular there are no
** URT (Unix RunTime simulation) aspects except for the variables
** _END, _ETEXT, _EDATA, and _EALLOC.
**	Note that only a few of the global symbols defined here will
** also have entry points.  This is because all modules always ask for
** the $$$CRT symbol, and only one entry point is sufficient
** to cause loading of the entire CRT support module.
*/

#include "c-env.h"

/* Some externally visible data cells */

		/* UNIX loader symbol simulation */
char	*_etext,	/* 1st addr above program text (code) region */
	*_edata,	/* 1st addr above initialized data region */
	*_end,		/* 1st addr above uninitialized data */
			/*  == 1st addr of dynamically allocated stuff. */
	*_ealloc;	/* 1st addr above space for dynamic allocation */

int `$STOFF` = 1;	/* Start address offset (either 0 or 1) */
int `$STACS`[16];	/* Saved ACs at startup */

double `$ZERO` = 0.0;	/* Double zero, for floating constant reference */
int `$KCCID` = 0534343604755;	/* Sixbit /KCCPGM/ to identify KCC pgms */

#if SYS_ITS+SYS_WAITS+SYS_T10
static int `$STKSZ` = 010000;	/* Min stack size to allocate at startup */
#endif				/* This is a variable so it can be patched */

static int startf = 0;		/* Start flag.  Non-zero if already started */
static int pdlp = 0;		/* Initial PDL ptr (set if already inited!) */
`$$$CRT`()			/* Start of moby assembler code stuff */
{
#asm
RV==1		/* Return-Value register */
A==3		/* A,B,C,D sequential miscellaneous regs */
B==4		/* Please keep these half-killed so that */
C==5		/* ITS hackers don't go nuts */
D==6
S==16		/* Runtime scratch register */
P==17		/* PDL pointer */

	EXTERN	.RUNTM
	EXTERN $$SECT
	EXTERN $$BP90, $$BP91, $$BP92, $$BP93
	EXTERN $$BP70, $$BP71, $$BP72, $$BP73, $$BP74

; System-dependent runtime code should contain the following:
;	(1) A "SSTART" label, jumped to at program startup.  This code should:
;		- Set up the stack and point P at it.
;		- Arrange for whatever memory shuffling is desired,
;			including extended addressing.
;		- Set the global vars .END, .ETEXT, .EDATA, .EALLOC
;			as word (not char) addresses.
;		- Finally, jump back to SREADY.
;	(2) A "RESTART" label, jumped to on an attempt to restart the program.
;		This code should emit an error message and exit.
;	(2) A "..EXIT" label, for a function that should halt the process
;		normally with the exit status provided by arg 1.

	INTERN $START
$START:	SETZM $STOFF		/* Start offset is 0 */
				/* Start offset is 1 ($STOFF left set to 1) */
	SKIPE STARTF		/* Attempting to restart the program? */
	 JRST RESTART		/* Ugh!! Go fail loudly. */
	AOS STARTF		/* Nope, OK to set flag and proceed. */
	MOVEM 17,$STACS+17	/* Save Start AC 17 */
	MOVEI 17,$STACS		/* Set up BLT from ACs to storage block */
	BLT 17,$STACS+16	/* Save remaining ACs. */
	JRST SSTART		/* Now perform sys-dependent startup! */

	; Jump back here when system-dependent startup is complete.
SREADY:	MOVSI A,$$BP90	/* Set up proper bits for byte pointer conversion */
	IORM A,.END	/* Convert the word addrs to KCC char pointers */
	IORM A,.EDATA
	IORM A,.ETEXT
	IORM A,.EALLOC
	SETZ 0,		; Make sure any refs to 0 just get 0.
	SKIPE S,INITS	; Are there any inits set up by loader?
	 PUSHJ P,1(S)	; Yeah, go hack them (obscure feature)
	PUSHJ P,.RUNTM	; Invoke higher level setup.  This will call MAIN.

			; This should exit by itself, but just in case
	PUSH P,RV	; we return, pass on the return value
	PUSHJ P,..EXIT	; and exit forcibly, without any cleanup.
	JRST .-1	; Insist.

	/* Link for runtime initializations.  KCC cannot always
	** initialize some variables at compile time, and so it uses
	** a link chain to tie together the code it generates to
	** perform the initializations at run time.
	*/
INITS:	BLOCK	1		;Make space for LINK to fill in with init chain
	.LNKEND	1,INITS		;Tell it to head the chain here
#endasm
#asm

$RETF:
$RETZ:	SETZ RV,		; Return Zero (also False)
$RET:	POPJ P,

$RETT:
$RETP:	MOVEI RV,1		; Return Positive (also True)
	POPJ P,
$RETN:	SETO RV,		; Return Negative
	POPJ P,

	INTERN	$RET,$RETP,$RETT,$RETZ,$RETF,$RETN
#endasm
/* Byte pointer tables.
*/
#asm
	EXTERN $$BMP6, $$BMP7, $$BMP8, $$BMP9, $$BMPH
	INTERN $BPMUL, $BPADT
	INTERN $BADL6, $BADL7, $BADL8, $BADL9, $BADLH
	INTERN $BADX6, $BADX7, $BADX8, $BADX9, $BADXH

/* The tables $BPMUL and $BPADT are both indexed by either the
** S field (for local-format BPs) or the P+S field (for OWGBPs).
** The index values can thus be from 00 to 77, but only those corresponding
** to 6, 7, 8, 9, or 18 bits are ever actually used.
**	$BPMUL contains the value that P_SUBBP should use for multiplication.
**	$BPADT points to the table that P_SUBBP should use for addition.
**
** The values for the $BPMUL table should actually be <size>_$$BSHF
** but FAIL interprets _ as assignment instead of left-shift!  Barf.
*/
$BPMUL:	BLOCK 6		; 0 Local sizes 0-5
	$$BMP6		; 6 Local size 6  
	$$BMP7		; 7 Local size 7  
	$$BMP8		; 10 Local size 8  
	$$BMP9		; 11 Local size 9  
	BLOCK 10	; 12 Local sizes 10-17
	$$BMPH		; 22 Local size 18  
	BLOCK 22	; 23 Local sizes 19-36
	0		; 45 OWGBP 6-bit offset -1
	$$BMP6		; 46 OWGBP 6-bit offset 0
	$$BMP6		; 47 OWGBP 6-bit offset 1
	$$BMP6		; 50 OWGBP 6-bit offset 2
	$$BMP6		; 51 OWGBP 6-bit offset 3
	$$BMP6		; 52 OWGBP 6-bit offset 4
	$$BMP6		; 53 OWGBP 6-bit offset 5
 	0		; 54 OWGBP 8-bit offset -1
	$$BMP8		; 55 OWGBP 8-bit offset 0
	$$BMP8		; 56 OWGBP 8-bit offset 1
	$$BMP8		; 57 OWGBP 8-bit offset 2
	$$BMP8		; 60 OWGBP 8-bit offset 3
 	0		; 61 OWGBP 7-bit offset -1
	$$BMP7		; 62 OWGBP 7-bit offset 0
	$$BMP7		; 63 OWGBP 7-bit offset 1
	$$BMP7		; 64 OWGBP 7-bit offset 2
	$$BMP7		; 65 OWGBP 7-bit offset 3
	$$BMP7		; 66 OWGBP 7-bit offset 4
 	0		; 67 OWGBP 9-bit offset -1
	$$BMP9		; 70 OWGBP 9-bit offset 0
	$$BMP9		; 71 OWGBP 9-bit offset 1
	$$BMP9		; 72 OWGBP 9-bit offset 2
	$$BMP9		; 73 OWGBP 9-bit offset 3
 	0		; 74 OWGBP 18-bit offset -1
	$$BMPH		; 75 OWGBP 18-bit offset 0
	$$BMPH		; 76 OWGBP 18-bit offset 1
	0		; 77 illegal

$BPADT:	BLOCK 6		; 0 Local sizes 0-5
	$BADL6		; 6 Local size 6  
	$BADL7		; 7 Local size 7  
	$BADL8		; 10 Local size 8  
	$BADL9		; 11 Local size 9  
	BLOCK 10	; 12 Local sizes 10-17
	$BADLH		; 22 Local size 18  
	BLOCK 22	; 23 Local sizes 19-36
	0		; 45 OWGBP 6-bit offset -1
	$BADX6		; 46 OWGBP 6-bit offset 0
	$BADX6		; 47 OWGBP 6-bit offset 1
	$BADX6		; 50 OWGBP 6-bit offset 2
	$BADX6		; 51 OWGBP 6-bit offset 3
	$BADX6		; 52 OWGBP 6-bit offset 4
	$BADX6		; 53 OWGBP 6-bit offset 5
 	0		; 54 OWGBP 8-bit offset -1
	$BADX8		; 55 OWGBP 8-bit offset 0
	$BADX8		; 56 OWGBP 8-bit offset 1
	$BADX8		; 57 OWGBP 8-bit offset 2
	$BADX8		; 60 OWGBP 8-bit offset 3
 	0		; 61 OWGBP 7-bit offset -1
	$BADX7		; 62 OWGBP 7-bit offset 0
	$BADX7		; 63 OWGBP 7-bit offset 1
	$BADX7		; 64 OWGBP 7-bit offset 2
	$BADX7		; 65 OWGBP 7-bit offset 3
	$BADX7		; 66 OWGBP 7-bit offset 4
 	0		; 67 OWGBP 9-bit offset -1
	$BADX9		; 70 OWGBP 9-bit offset 0
	$BADX9		; 71 OWGBP 9-bit offset 1
	$BADX9		; 72 OWGBP 9-bit offset 2
	$BADX9		; 73 OWGBP 9-bit offset 3
 	0		; 74 OWGBP 18-bit offset -1
	$BADXH		; 75 OWGBP 18-bit offset 0
	$BADXH		; 76 OWGBP 18-bit offset 1
	0		; 77 illegal
/* Addition tables for P_SUBBP.
**	These are indexed by the high-order word resulting from
** a multiplication of the byte-pointer difference.  Note that the
** tables extend on both sides of the labels so that negative indices
** are kept happy.
**	Some of the tables are much sparser than they need to be,
** because of a $$BSHF value higher than necessary for that particular
** BP size; the reason for this is so we can use a single value of
** $$BSHF (depending on whether using local-format or global-format BPs)
** and avoid having to look up a size-dependent shift value.  Thus
** $$BSHF is set to the lowest possible value that satisfies ALL of the
** BP sizes (the main problem is the 18-bit one).
**
** The PARITH.C program in the KCC source directory was used to
** generate and test this stuff.
**
** Don't look at the values too hard; let magic be magic.
*/

	/*  6-bit local-format P_SUBBP fixup table */

	<40000,,5>	; -12.
	    0 ;unused	; -11.
	<0,,4>  	; -10.
	<200000,,4>	; -9.
	    0 ;unused	; -8.
	<140000,,3>	; -7.
	    0 ;unused	; -6.
	<100000,,2>	; -5.
	    0 ;unused	; -4.
	<40000,,1>	; -3.
	    0 ;unused	; -2.
	    0 ;unused	; -1.
$BADL6:	0		; 0.
	    0 ;unused	; 1.
	-<40000,,1>	; 2.
	    0 ;unused	; 3.
	-<100000,,2>	; 4.
	    0 ;unused	; 5.
	-<140000,,3>	; 6.
	    0 ;unused	; 7.
	-<200000,,4>	; 8.
	-<0,,4> ; 9.
	    0 ;unused	; 10.
	-<40000,,5>	; 11.


	/*  7-bit local-format P_SUBBP fixup table */

	<140000,,4>	; -9.
	    0 ;unused	; -8.
	<110000,,3>	; -7.
	    0 ;unused	; -6.
	<60000,,2>	; -5.
	    0 ;unused	; -4.
	<30000,,1>	; -3.
	    0 ;unused	; -2.
	    0 ;unused	; -1.
$BADL7:	0		; 0.
	    0 ;unused	; 1.
	-<30000,,1>	; 2.
	    0 ;unused	; 3.
	-<60000,,2>	; 4.
	    0 ;unused	; 5.
	-<110000,,3>	; 6.
	    0 ;unused	; 7.
	-<140000,,4>	; 8.


	/*  8-bit local-format P_SUBBP fixup table */

	<0,,3>		; -7.
	<200000,,3>	; -6.
	<0,,2>		; -5.
	<200000,,2>	; -4.
	<0,,1>		; -3.
	<200000,,1>	; -2.
	    0 ;unused	; -1.
$BADL8:	0		; 0.
	-<200000,,1>	; 1.
	-<0,,1> ; 2.
	-<200000,,2>	; 3.
	-<0,,2> ; 4.
	-<200000,,3>	; 5.
	-<0,,3> ; 6.


	/*  9-bit local-format P_SUBBP fixup table */

	<140000,,3>	; -7.
	    0 ;unused	; -6.
	<100000,,2>	; -5.
	    0 ;unused	; -4.
	<40000,,1>	; -3.
	    0 ;unused	; -2.
	    0 ;unused	; -1.
$BADL9:	0		; 0.
	    0 ;unused	; 1.
	-<40000,,1>	; 2.
	    0 ;unused	; 3.
	-<100000,,2>	; 4.
	    0 ;unused	; 5.
	-<140000,,3>	; 6.


	/* 18-bit local-format P_SUBBP fixup table */

	<40000,,1>	; -3.
	    0 ;unused	; -2.
	    0 ;unused	; -1.
$BADLH:	0		; 0.
	    0 ;unused	; 1.
	-<40000,,1>	; 2.


	/*  6-bit OWGBP-format P_SUBBP fixup table */

	-<0,,5>		; -31.
	-<770000,,5>	; -30.
	    0 ;unused	; -29.
	    0 ;unused	; -28.
	    0 ;unused	; -27.
	    0 ;unused	; -26.
	-<0,,4>		; -25.
	-<770000,,4>	; -24.
	    0 ;unused	; -23.
	    0 ;unused	; -22.
	    0 ;unused	; -21.
	    0 ;unused	; -20.
	-<0,,3>		; -19.
	-<770000,,3>	; -18.
	    0 ;unused	; -17.
	    0 ;unused	; -16.
	    0 ;unused	; -15.
	    0 ;unused	; -14.
	-<0,,2>		; -13.
	-<770000,,2>	; -12.
	    0 ;unused	; -11.
	    0 ;unused	; -10.
	    0 ;unused	; -9.
	    0 ;unused	; -8.
	-<0,,1>		; -7.
	-<770000,,1>	; -6.
	    0 ;unused	; -5.
	    0 ;unused	; -4.
	    0 ;unused	; -3.
	    0 ;unused	; -2.
	    0 ;unused	; -1.
$BADX6:	0		; 0.
	    0 ;unused	; 1.
	    0 ;unused	; 2.
	    0 ;unused	; 3.
	    0 ;unused	; 4.
	<770000,,1>	; 5.
	<0,,1>		; 6.
	    0 ;unused	; 7.
	    0 ;unused	; 8.
	    0 ;unused	; 9.
	    0 ;unused	; 10.
	<770000,,2>	; 11.
	<0,,2>		; 12.
	    0 ;unused	; 13.
	    0 ;unused	; 14.
	    0 ;unused	; 15.
	    0 ;unused	; 16.
	<770000,,3>	; 17.
	<0,,3>		; 18.
	    0 ;unused	; 19.
	    0 ;unused	; 20.
	    0 ;unused	; 21.
	    0 ;unused	; 22.
	<770000,,4>	; 23.
	<0,,4>		; 24.
	    0 ;unused	; 25.
	    0 ;unused	; 26.
	    0 ;unused	; 27.
	    0 ;unused	; 28.
	<770000,,5>	; 29.
	<0,,5>		; 30.


	/*  7-bit OWGBP-format P_SUBBP fixup table */

	-<0,,4>		; -21.
	-<770000,,4>	; -20.
	    0 ;unused	; -19.
	    0 ;unused	; -18.
	    0 ;unused	; -17.
	-<0,,3>		; -16.
	-<770000,,3>	; -15.
	    0 ;unused	; -14.
	    0 ;unused	; -13.
	    0 ;unused	; -12.
	-<0,,2>		; -11.
	-<770000,,2>	; -10.
	    0 ;unused	; -9.
	    0 ;unused	; -8.
	    0 ;unused	; -7.
	-<0,,1>		; -6.
	-<770000,,1>	; -5.
	    0 ;unused	; -4.
	    0 ;unused	; -3.
	    0 ;unused	; -2.
	    0 ;unused	; -1.
$BADX7:	0		; 0.
	    0 ;unused	; 1.
	    0 ;unused	; 2.
	    0 ;unused	; 3.
	<770000,,1>	; 4.
	<0,,1>		; 5.
	    0 ;unused	; 6.
	    0 ;unused	; 7.
	    0 ;unused	; 8.
	<770000,,2>	; 9.
	<0,,2>		; 10.
	    0 ;unused	; 11.
	    0 ;unused	; 12.
	    0 ;unused	; 13.
	<770000,,3>	; 14.
	<0,,3>		; 15.
	    0 ;unused	; 16.
	    0 ;unused	; 17.
	    0 ;unused	; 18.
	<770000,,4>	; 19.
	<0,,4>		; 20.


	/*  8-bit OWGBP-format P_SUBBP fixup table */

	-<0,,3>		; -13.
	-<770000,,3>	; -12.
	    0 ;unused	; -11.
	    0 ;unused	; -10.
	-<0,,2>		; -9.
	-<770000,,2>	; -8.
	    0 ;unused	; -7.
	    0 ;unused	; -6.
	-<0,,1>		; -5.
	-<770000,,1>	; -4.
	    0 ;unused	; -3.
	    0 ;unused	; -2.
	    0 ;unused	; -1.
$BADX8:	0		; 0.
	    0 ;unused	; 1.
	    0 ;unused	; 2.
	<770000,,1>	; 3.
	<0,,1>		; 4.
	    0 ;unused	; 5.
	    0 ;unused	; 6.
	<770000,,2>	; 7.
	<0,,2>		; 8.
	    0 ;unused	; 9.
	    0 ;unused	; 10.
	<770000,,3>	; 11.
	<0,,3>		; 12.


	/*  9-bit OWGBP-format P_SUBBP fixup table */

	-<0,,3>		; -13.
	-<770000,,3>	; -12.
	    0 ;unused	; -11.
	    0 ;unused	; -10.
	-<0,,2>		; -9.
	-<770000,,2>	; -8.
	    0 ;unused	; -7.
	    0 ;unused	; -6.
	-<0,,1>		; -5.
	-<770000,,1>	; -4.
	    0 ;unused	; -3.
	    0 ;unused	; -2.
	    0 ;unused	; -1.
$BADX9:	0		; 0.
	    0 ;unused	; 1.
	    0 ;unused	; 2.
	<770000,,1>	; 3.
	<0,,1>		; 4.
	    0 ;unused	; 5.
	    0 ;unused	; 6.
	<770000,,2>	; 7.
	<0,,2>		; 8.
	    0 ;unused	; 9.
	    0 ;unused	; 10.
	<770000,,3>	; 11.
	<0,,3>		; 12.


	/* 18-bit OWGBP-format P_SUBBP fixup table */

	-<0,,1>		; -3.
	-<770000,,1>	; -2.
	    0 ;unused	; -1.
$BADXH:	0		; 0.
	<770000,,1>	; 1.
	<0,,1>		; 2.
#endasm
/* $ADJBP - Support for ADJBP instruction simulation.
**	For KA-10s and any other CPU which does not have the ADJBP instruction,
** KCC will define an ADJBP macro which expands into:
**	ADJBP AC,MEM 
**		MOVE 16,MEM
**		EXCH 15,AC
**		PUSHJ 17,$ADJBP
**		EXCH 15,AC
**
**	The routine here (from KLH's UUO package) is completely general
** and simulates the KL ADJBP instruction exactly, including alignment
** preservation.
**	Note that for most cases this hair is unnecessary, and you can get
** MUCH better efficiency by
**	(1) using prior knowledge of the byte size, and
**	(2) assuming alignment is always a normal byte boundary, and
**	(3) assuming 44 is never used as a P field value.
** This also permits inline coding.  Nevertheless, because much C library
** support uses the ADJBP instruction, an assembler macro (and thus
** a runtime routine for it to call) are needed.
*/

#asm

; $ADJBP - Software simulation of ADJBP instruction, which is just
;	IBP with non-zero AC.
; Following description taken from DEC hardware manual.  Integer
; divisions, of course.
; Let A = rem((36-P)/S)
; If S > 36-A	set no divide & exit
; If S = 0	set (E) -> (AC)
; If 0 < S <= 36-A:		NOTE: Dumb DEC doc claims < instead of <= !!!
;	L = (36-P)/S = # bytes to left of P
;	B = L + P/S  = # bytes to left + # bytes to right = # bytes/word
;	Find Q and R, Q*B + R = (AC) + L
;		where 1 <= R <= B	; that is, not neg or zero!
;	Then:
;		Y + Q	-> new Y	; must wraparound correctly.
;	36 - R*S - A	-> new P
;	Put new BP in AC.  Only P and Y fields changed, not S, I, X.

	INTERN $ADJBP

$ADJBP:	PUSH P,A
	PUSH P,B
	PUSH P,C
	PUSH P,D

	; First get S
	LDB A,[300600,,15]	; Get S
	JUMPE A,UIBP9		; If S = 0 just set (AC) to (E).
	CAILE A,44
	 JRST UIBP9		; In theory should set "no divide"

	; Now get A and test.
	LDB C,[360600,,15]	; Get P
	MOVE B,C		; Save copy
	SUBI C,44		; Get -(36-P)
	IDIVI C,(A)		; Get -( Alignment = rem (36-P)/s )
	CAILE A,44(D)		; Compare S <= 36 - A
	 JRST UIBP9		; Ugh, error return.

	; Get L and B
	PUSH P,D		; Save - rem = A = # unbyted bits to left of P
	MOVM D,C		; Save quotient = L = # bytes to left of P
	IDIVI B,(A)		; Now get P/S
	ADDI B,(D)		; L + P/S = B bytes per wd.
	MOVE C,16		; Get # bytes to adjust by. Don't optimize if 0
				; because want canonicalization effect.
	ADDI C,(D)		; Get (AC) + L
	IDIVI C,(B)		; Find  (AC + L)/B = Q and R
	JUMPLE D,[ADDI D,(B)	; If R <= 0 then adjust to 0 < R.
		SOJA C,.+1]	; which means adjusting Q also.
	
	IMULI D,(A)		; Get R*S
	POP P,A			; Restore -A
	SUBI A,-44(D)		; Now have new P = (36 - R*S - A)

	DPB A,[360600,,15]	; Deposit new P in byte pointer
	ADDI C,(15)		; Find new Y = Y + Q
	HRRI 15,(C)		; Set this way to wrap properly.

UIBP9:			; In theory should set Trap 1, Ovfl, No Div.
	POP P,D
	POP P,C
	POP P,B
	POP P,A
	POPJ P,
#endasm
}	/* End of dummy routine! */
#if SYS_T20+SYS_10X
/************************************************************
**	C low-level Runtime Support Routines
**	TOPS-20/TENEX Operating System
************************************************************
*/

void
__exit()
{
#asm
	SEARCH	MONSYM

	MOVE 0,$KCCID		; Get KCC identifier into AC 0
EXIT1:	MOVE 1,-1(P)		; Get possible argument into AC 1
	HALTF%			; Exit to monitor.
	HRROI 1,[ASCIZ/Cannot continue/]
	ESOUT%			; Complain if continued
	JRST EXIT1		; and stop again.

RESTART:HRROI 1,[ASCIZ /Cannot restart/]
	ESOUT%
	JRST EXIT1

.JBHSO==75		; Contains page number of start of high seg
.JBHRL==115		; Contains <high seg first free addr>,,<highest addr>
.JBSYM==116		; Contains -<# wds in symtab>,,<addr of symtab>
.JBSA==120		; Contains <low seg first free addr>,,<start addr>
PG$BTS==11		; log 2 of T20/TNX page size
PG$SIZ==1000		; # words in T20/TNX page
PG$MSK==<PG$SIZ-1>


	/* Start of TOPS-20/TENEX program */
SSTART:	RESET%			/* Initialize the world monitor-wise. */
	MOVEI 1,.FHSLF		/* Ensure stupid PA1050 compat pkg is */
	SETO 2,			/* thoroughly disabled, to help track down */
	SCVEC%			/* any bugs! */
	SKIPE P,PDLP		/* Are we already initialized otherwise? */
	 JRST SREADY		/* Yes!  All set up, back to generic stuff! */

#if SYS_T20
	XMOVEI 1,.		/* See if loaded into non-zero section */
	HLRZS 1			/* Get section # into RH */
	JUMPE 1,STRT05		/* Jump if plain zero section */
	CAIE 1,$$SECT		/* Non-zero, had better match what we think */
	 0			/* Ugh!!!  Fail horribly for now. */
	JRST ESTART		/* Great, already mapped right! */
STRT05:
#endif
	SKIPN A,.JBHSO		/* Get page # of start of high seg */
	 JRST DOPSCT		/* If no highseg, assume PSECTed code */
	HLRZ P,.JBSA		/* Get top of low core as start of stack */
	MOVEM P,.EDATA		/* Save as ptr to end of data */
	LSH A,PG$BTS		/* Shift 9 bits to get <hiseg addr> */
	MOVN B,A		/* Make it -<hiseg addr> */
	ADD B,P			/* Find -<hiseg - edata> (ie -<# wds avail>) */
	HRL P,B			/* Put count in LH of PDL pointer */

	HLRZ	B,.JBHRL	/* Get first free high seg. relative address */
	ADD	A,B		/* Add to <hiseg addr> to make it absolute */
	JRST	DOETXT		/* Skip over PSECT stuff */

	/* No high segment.  Assume we were loaded with data & code PSECTs.
	** Further assume that the symbol table was put into the data PSECT,
	** and the code PSECT starts at 400000.
	** Thus the gap between these can be used for the stack.  The LH of
	** .JBSA has the highest free address, which will be above the code
	** PSECT.
	*/
DOPSCT:	HRRZ	P,.JBSYM	/* Get start addr of symtab */
	HLRE	A,.JBSYM	/* Get -<# wds in symtab> */
	SUB	P,A		/* Add to address to get 1st free addr */
	MOVEI	A,400000	/* Assume this is start of code psect */
	SUB	A,P		/* Find # words gap between data & code */
	MOVNS	A		/* Negate, and insert */
	HRL	P,A		/* -<count> in LH of of PDL pointer */
	HLRZ	A,.JBSA		/* Get top of code seg */

DOETXT:				/* Rejoin original code here */
	TRZE	A,PG$MSK	/* Round up to page boundry, since */
	 ADDI	A,PG$SIZ	/* hiseg may be write-protected */
	MOVEM	A,.END		/* Save addr in A as the END */

	MOVEM	A,.ETEXT	/* Same as END */
	MOVEI	A,770000-2000	/* Set this as allocation limit, so that */
	MOVEM	A,.EALLOC	/* DDT can be mapped in pages 770-777 */
				/* (with 2 data pages saved for $@#! UDDT) */
#if SYS_T20
	SKIPE	[$$SECT]	/* Want extended addressing? */
	 JRST	DOEXTA		/* Yeah, must do hairy setup */
#endif
	JRST SREADY		/* All ready to go, jump to start the rest. */
#endasm
#asm
#if SYS_T20
/* Perform extended addressing setup */

DOEXTA:	SETZ	11,		; From section zero
	MOVEI	10,$$SECT	; to Destination section
	MOVEI	6,.FHSLF
	MOVEI	7,.FHSLF	; From and to ourself
	PUSHJ P,$MAPSC		; Map section!

	; Mapped ourselves into a non-zero section, now start executing there.
	MOVE 16,[XCODE,,1]	; Copy code into ACs for extended-addr start.
	BLT 16,1+XCODEL-1
	JRST 4			; Go!

XCODE:	-1			; 1 PMAP arg: unmap
	.FHSLF,,0		; 2 PMAP arg: starting on page 0 of self
	PM%CNT!PM%EPN!1000	; 3 PMAP arg: All pages of section zero
	PMAP%			; 4 Code: execute PMAP to flush sect 0
	XJRSTF 6		; 5 Code: then jump into non-zero section!
	0			; 6 Address: no PC flags
	$$SECT,,ESTART		; 7 Address: jump to here (extended addr)
XCODEL==<.-XCODE>

	; At this point we are now running in a non-zero section!
	; Need to set up new stack and adjust some variables.
ESTART:
	;; Make a stack in section N+1
	MOVSI P,$$SECT+1	; Get stack pointer to 1st loc in sect N+1
	SETZ	1,		; Creating
	HLRZ	2,P		; In stack section
	HRLI	2,.FHSLF	; On ourself
	MOVEI	3,1		; One section
	SMAP%			; Make it
	SETZM	(P)		; Create page 0 of stack section
	HLLOS	P		; Make max section address (n,,-1)
	SETZM	(P)		; Create high page (777) of stack section

	MOVE	1,P		; Use that address
	LSH	1,-PG$BTS	; to set up highest page number
	HRLI	1,.FHSLF	; On self
	SETZ	2,		; No access privileges
	SPACS%			; Write-protect the last page!
	TRZ	1,777		; Similarly write-protect page zero,
	SPACS%			; to bracket stack.
	HRRI	P,PG$SIZ	; Now point to page 1 as start of stack!

	; Set up EDATA, ETEXT, and END for memory allocation
	MOVSI 1,$$SECT+1	/* Set up <2,,0> as end of data and code */
	MOVEM	1,.EDATA	;Both initialized data and code
	MOVEM	1,.ETEXT	;are in section 1 only.
	SETZ	1,		;Make a new section
	HRRZI	2,$$SECT+2	;In section 3
	HRLI	2,.FHSLF	;For us
	MOVEI	3,1		;One section
	SMAP%
	MOVSI 1,$$SECT+2	/* Say <3,,0> (section 3) is */
	MOVEM 1,.END		/* the first location past end of program */
	MOVE 1,[37,,700000]	/* And this is the first location XDDT wants */
	MOVEM 1,.EALLOC		/* so stop allocating memory at that point. */

	JRST SREADY		; Done, return to main startup.
#endif /* T20 */
#endasm
/* <KCC.LIB>CRT.C.14, 26-Jul-85 14:35:26, Edit by KRONJ */
/*  Fix $MAPSC to work for pre-release-5 TOPS-20 */
#asm
/*
** $MAPSC - Check map for one section and copy across to new fork.
** This auxiliary subroutine is also used by FORK().
** Call with
**    5/unchangeable by $mapsc
**    6/destination fork handle
**    7/source fork handle
**    10/destination section
**    11/source section
**
** We use the stack for scratch space, so have to be careful.
*/
	INTERN $MAPSC
$MAPSC:	MOVE 16,P		/* Copy stack pointer */
	ADJSP P,10000		/* Give us some stack space */

/*
** Normal TOPS-20 (releases 5 and beyond) code.
** Read in the map all at once, and then do individual copies.
**
** Note that no SMAP% is needed to create the destination section;
** it will be done implicitly by the PMAP%s.
*/

#if SYS_T20
	MOVE 1,11		/* Copy source section number */
	HRL 1,7			/* and source handle */
	RSMAP%			/* Read section map */
	 ERJMP mapsc3		/* lost, go try it the old way */
	AOJE 1,mapsc2		/* If unmapped, dont copy */

	/* Have section, read page maps */
	MOVEI 1,4		/* Length of argument block is 4 */
	MOVEI 2,1000		/* Want a full section of pages */
	DMOVEM 1,1(16)		/* Save as first two words of argument block */
	MOVE 1,11		/* Get source section number */
	LSH 1,11		/* into page number (9 bits) */
	XMOVEI 2,5(16)		/* and a pointer to some scratch space */
	DMOVEM 1,3(16)		/* as third and fourth words of block */
	HRLZ 1,7		/* On source handle */
	XMOVEI 2,1(16)		/* with argument block */
	XRMAP%			/* read in a bunch of paging info at once */

	/* Now set up for individual page loop */
	XMOVEI 13,4000(16)	/* Get a place above the top of XRMAP% info */
	LSH 13,-11		/* as page number (9 bits) */
	HRLI 13,.FHSLF		/* of self (not source) */
	MOVE 14,10		/* Get destination section this time */
	LSH 14,11		/* as page number (9 bits) */
	HRLI 14,-1000		/* make AOBJN pointer */
	XMOVEI 12,5(16)		/* point to start of XRMAP% block */

mapse0:	DMOVE 1,0(12)		/* Get # of page in 1, page access wd in 2 */
	PUSHJ 17,mappag		/* Map that page */
	ADDI 12,2		/* Move over XRMAP% info to next page */
	AOBJN 14,mapse0		/* Loop over all pages in section */
	JRST mapsc4		/* Go on to cleanup and return */
#endif /* T20 */

/*
** Fall into here when not T20 (i.e. TENEX).
** Also come here if RSMAP% fails (pre-rel-5 TOPS20 or out of range section).
** Do it the old way, with a RPACS% per page.
*/

mapsc3:	CAIN 10,0		/* Make sure destination */
	 CAIE 11,0		/* and source sections are both zero */
	  JRST mapsc2		/* Can't handle non-zero, just return */
	MOVEI 13,777(16)
	LSH 13,-11		/* Get page # of a scratch page (9 bits) */
	HRLI 13,.FHSLF		/* Make page handle */
	MOVSI 14,-1000		/* Set up AOBJN pointer */

mapsc5:	MOVSI 1,(7)		/* Get source fork handle in LH */
	HRRI 1,(14)		/* Source page # */
	RPACS%			/* Get access of page */
	PUSHJ P,MAPPAG		/* Map the page over */
	AOBJN 14,mapsc5

/*
** Here after either sequence of code.
** Unmap the scratch page and return.
*/

mapsc4:	SETO 1,			/* Unmapping */
	MOVE 2,13		/* Into temporary page */
	MOVE 3,[PM%EPN]		/* One page, extended addressing */
	PMAP%			/* Do the unmap */

/*
** Here after scratch space unmapped or if error occurred.
** Give our space back to the stack and return.
*/

mapsc2:	ADJSP P,-10000		/* Get space back */
	POPJ P,			/* Done with mapping section */
; Map one page of fork into another (can be same) fork
; 1/ page handle (fork/file,,#) of source
; 2/ page access bits for above
; 6  / fork handle of destination
; 12 / <don't touch>
; 13 / page handle of temporary page on stack for our own use
; 14 / AOBJN pointer to page number of dest, including section

mappag:	TDNN	2,[RM%PEX]	; Check page access bits - page exists?
	 POPJ P,		;No, dont map across
	CAMN	1,13		; Page handle same as our temporary page?
	 POPJ P,		;Yes, dont copy
	MOVE	4,2		; Save access bits.
	MOVEI	2,(14)		; OK, copy to this dest page number
	HRLI	2,(6)		; In new inferior fork
	MOVE	3,[PM%RD!PM%EX!PM%CPY!PM%EPN] ;Copy-on-write, one page
	PMAP%			;Copy across, creating section if empty
#if SYS_T20
	JUMPGE	1,MAPPG9	;If directly from file, done with mapping
#endif
#if SYS_10X
	TLNN	4,200		; See if "Private" access bit (1B10) is set.
	 JRST MAPPG9		; Nope.
#endif

	;; Here when page is private, break copy-on-write link
	MOVE	1,2		;Now get page again as source this time
	MOVE	2,13		;Get PMAP pointer to temporary page
	MOVE	3,[PM%RD!PM%WR!PM%EPN] ;Write not copy-on-write to self from fork
	PMAP%			;Copy the page
	 ERJMP	.+1		;Dont die if tried to make circular
	HRRZ	1,13		;Get pointer again
	LSH	1,11		;As address (9 bits)
	MOVES	(1)		;Break copy-on-write link in subfork to us
MAPPG9:	POPJ P,			;All done
#endasm
}
#endif /* T20+10X */
#if SYS_WAITS
/************************************************************
**	C low-level Runtime Support Routines
**	WAITS Operating System
************************************************************
*/
void
__exit()
{
#asm
	EXIT	0,		; exit to monitor
	JRST	..EXIT		; no reentry
RESTART:
	EXIT 0,
	JRST ..EXIT

JOBREL==44			; highest core usage
JOBFF==121			; first free location from monitor tables
JOBHRL==115			; Highest addr in high segment

SSTART:	RESET
	MOVE	P,JOBFF
	MOVN	A,$STKSZ
	HRL	P,A		; Set up stack pointer -<max size>,,<jobff>
	MOVE	A,JOBREL	; get max core usage
	ADD	A,$STKSZ	; get some stack space
	CORE	A,		; ask for more core
	 JRST	.+1		; no space, tough
	MOVE	A,JOBREL	; get highest usage
	MOVEM	A,JOBFF		; Update JOBFF past allocated stack
	MOVEM	A,.END		; This is where to allocate new memory.

	HRRZM	P,.EDATA	; This is where data ended (same as PDL start).
	HRRZ	A,JOBHRL	; Get highest addr in upper segment
	MOVEM	A,.ETEXT	; This is end of code.
	MOVEI	A,777777	/* Don't allocate past this address */
	MOVEM	A,.EALLOC
	
	JRST SREADY		; All set, jump to start the rest.
#endasm
}
#endif /* WAITS */
#if SYS_ITS
/************************************************************
**	C low-level Runtime Support Routines
**	ITS Operating System
*************************************************************
*/
void
__exit()
{
#asm
	MOVE 0,$KCCID
	MOVE 1,-1(P)		; Just in case, leave "exit status" in AC 1.
	.LOGOUT 1,		; Return to superior (log out if disowned)
	JRST .-1		; Never continue.

RESTART:
	.VALUE [ASCIZ /: Cannot restart 
/]
	JRST .-1

; Initially we are using the TOPS-20 linker.
; When we have our own, this protocol might change.
.JBHSP==75		; Contains (20X!) page number of start of high seg
.JBHRL==115		; Contains <high seg first free addr>,,<highest addr>
.JBSA==120		; Contains <low seg first free addr>,,<start addr>

#if 0 /* Remember these hard-to-find values for posterity or future use (!). */
SSEGLO==20	; STINK sets this to <loseg org>,,<loseg top>	; org always 0
SSEGHI==21	; STINK sets this to <hiseg org>,,<hiseg top>
#endif

PG$BTS==12		; log 2 of ITS page size
PG$SIZ==2000		; # words in ITS page
PG$MSK==<PG$SIZ-1>

; For the time being, we duplicate the TOPS-20 arrangement of having
; the stack at the end of the low segment, and new allocated memory
; at the end of the high segment.  If we want to use all of the address
; space, we can always make malloc smarter.

SSTART:	;; Initialize .EDATA, .ETEXT, .END, and .EALLOC

	HLRZ P,.JBSA		; P: 1st loc beyond data
	MOVEM P,.EDATA		; End of data
	MOVE A,.JBHSP		; Get (20X!) page # of start of high seg
	LSH A,9			; A: 1st loc of high seg
	HLRZ B,.JBHRL		; Get first free high seg. relative address
	ADDI B,(A)		; Add to <hiseg addr> to make it absolute
	MOVEM B,.ETEXT		; End of code
	ANDCMI A,PG$MSK		; A: 1ST loc of pure
	ADDI B,PG$SIZ-1
	ANDCMI B,PG$MSK		; B: 1st loc beyond pure
	MOVEM B,.END		; New memory starts there
	MOVEI C,777777		; Don't allocate past this address.
	MOVEM C,.EALLOC

	;; Now purify text (from A to B)

	MOVEI C,(A)
	LSH C,-PG$BTS
	LSH B,-PG$BTS
	SUBM C,B		; B: - # pages to purify
	HRLI C,(B)
	.CALL [	SETZ
		SIXBIT /CORBLK/
		MOVEI %CBNDR
		MOVEI %JSELF
		SETZ C ]
	 .LOSE %LSSYS

	;; Allocate PDL and initialize P

	MOVE B,$STKSZ
	ADDI B,PG$SIZ-1(P)
	ANDCMI B,PG$MSK		; B: 1st loc beyond stack 
	CAILE B,(A)
	 .LOSE			; Doesn't fit under hiseg
	MOVEI C,(P)
	SUBI C,(B)
	HRLI P,(C)
	HRRI P,-1(P)

	;; Create missing low pages (including PDL).
	;; We have to do this because the data area might contain large
	;; regions of zeros, and the linker won't create those pages.

	LSH B,-PG$BTS		; B: # pages to check
	MOVNI A,(B)
	HRLZI A,(A)		; A: page aobjn
SSTRT1:	.CALL [	SETZ
		SIXBIT /CORTYP/
		MOVEI (A)
		SETZM B ]
	 .LOSE %LSSYS
	JUMPN B,SSTRT2
	.CALL [	SETZ
		SIXBIT /CORBLK/
		MOVEI %CBNDW
		MOVEI %JSELF
		MOVEI (A)
		SETZI %JSNEW ]
	 .LOSE %LSSYS
SSTRT2:	AOBJN A,SSTRT1

	;; Prepare for UUOs and interrupts.

	SETZM 41		; No UUOs please
	MOVE A,[-1,,[P]]
	MOVEM A,42		; The null interrupt handler
	MOVE A,[-6,,[	SIXBIT /OPTION/
			TLO %OPINT+%OPOPC
			SIXBIT /MASK/
			MOVE [%PIPDL]
			SIXBIT /TTY/
			TLO %TBNVR	; Error if TTY not avail.
			]]
	.CALL [	SETZ
		SIXBIT /USRVAR/
		MOVEI %JSELF
		SETZ A ]
	 .LOSE %LSSYS
	JRST SREADY		; All set, jump to start the rest.
#endasm
}
#endif /* ITS */