Google
 

Trailing-Edge - PDP-10 Archives - BB-X117B-SB_1986 - 10,7/vnp36/rsxfnc.bli
There are 2 other files named rsxfnc.bli in the archive. Click here to see a list.
!NET:<DECNET20-V3P0.TKB-VNP.BIGVNP>RSXFNC.BLI.44 29-Sep-82 11:41:38, Edit by PECKHAM
!NET:<DECNET20-V3P0.TKB-VNP.BIGVNP>RSXFNC.BLI.42 29-Sep-82 10:14:27, Edit by PECKHAM
!NET:<DECNET20-V3P0.TKB-VNP.BIGVNP>RSXFNC.BLI.40 28-Sep-82 16:11:16, Edit by PECKHAM
!NET:<DECNET20-V3P0.TKB-VNP.BIGVNP>RSXFNC.BLI.39 26-Mar-82 16:13:43, Edit by PECKHAM
MODULE RSXFNC (					!Provide RSX Functions
		IDENT = 'X3.3'			!edit 29Sep82
		) =
BEGIN
!
!
!
!COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1980,1981,1982,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.
!

!++
! FACILITY: MCB Configuration Facility, VNP-20
!
! ABSTRACT:
!
!	This module contains all routines which manipulate RSX-11S Data
!	Structures.
!
!
! ENVIRONMENT: TOPS-10 or TOPS-20 User Mode
!
! AUTHOR: Scott G. Robinson, Creation Date: 16-APR-80
!
! MODIFIED BY:
! 	, : VERSION
! 01	-
! 03	- Change MCBMAP text in TELLK.
!--

!
! TABLE OF CONTENTS:
!

FORWARD ROUTINE
    RCOR : NOVALUE,				!READ CORE IMAGE
    WCOR : NOVALUE,				!WRITE CORE IMAGE
    FCOR : NOVALUE,				!FREE CORE IMAGE
    DEL_MODU,					!DELETE A MODULE
    DEL_PSECT,					!DELETE A PSECT
    DEL_GLOBAL,					!DELETE A GLOBAL
    GETSYM : NOVALUE,				!READ SYMBOLS INTO VALUE BLOCK
    GETSYM_1 : NOVALUE,				!READ RSX RELATED SYMBOLS
    GETBYT,					!GET A PDP-11 BYTE
    GETWRD,					!GET A WORD
    PUTBYT : NOVALUE,				!STORE A BYTE
    PUTWRD : NOVALUE,				!STORE A WORD
    ALOCB,					!ALLOCATE PDP-11 CORE
    DEACB : NOVALUE,				!DEALLOCATE PDP-11 CORE
    M_PCB,					!MAKE A PCB
    INSTAL : NOVALUE,				!INSTALL A TASK
    LOADD : NOVALUE,				!LOAD A DRIVER
    LNKDCB : NOVALUE,				!LINK A DCB INTO KERNEL
    VRBL_SYM,					!MAKE A SYMBOL AND GET VALUE
    FCLEAN : NOVALUE,				!PERFORM FINAL EXEC CLEANUP
    TELLK : NOVALUE,				!TELL USER ABOUT CONFIG
    TELLP : NOVALUE;				!TELL USER ABOUT PARTITIONS

!
! INCLUDE FILES:
!

LIBRARY 'VNPLIB';

!REQUIRE 'BLOCKH.REQ';				!PREPARE TO DEFINE STORAGE BLOCKS
!REQUIRE 'FILE.REQ';				!DEFINE FILE BLOCK
!REQUIRE 'FILSW.REQ';				!DEFINE FILE SWITCHES
!REQUIRE 'GLOBL.REQ';				!DEFINE GLOBAL BLOCK
!REQUIRE 'MODU.REQ';				!DEFINE MODULE BLOCK
!REQUIRE 'PSECT.REQ';				!DEFINE PSECT BLOCK
!REQUIRE 'VNPVAL.REQ';				!VALUE BLOCK FOR VNP20
!REQUIRE 'LLC.REQ';				!DEFINE LLC BLOCK
!REQUIRE 'DLC.REQ';				!DEFINE DLC BLOCK
!REQUIRE 'DDM.REQ';				!DEFINE DDM BLOCK
!REQUIRE 'BLOCKT.REQ';				!END OF DEFINING STORAGE BLOCKS
!REQUIRE 'TSKDEF.REQ';				!DEFINE TASK OFFSETS
!
! MACROS:
!
!	NONE
!
! EQUATED SYMBOLS:
!

LITERAL
    DEBUG = 0;

!
! OWN STORAGE:
!
!	NONE
!
! EXTERNAL REFERENCES:
!

EXTERNAL ROUTINE
    ATOR50 : NOVALUE,				!CONVERT ASCII TO RADIX50_11
    R50TOA : NOVALUE,				!CONVERT RADIX50_11 TO ASCII
    OPEN,					!OPEN A FILE
    CLOSE : NOVALUE,				!CLOSE A FILE
    INPUT,					!READ FROM A FILE
    OUTPUT : NOVALUE,				!WRITE ON A FILE
    RSTB : NOVALUE,				!READ SYMBOL TABLE
    PCRLF : NOVALUE,				!PRINT CR THEN LF
    OUTSTR : NOVALUE,				!PRINT A STRING
    OUTNUM : NOVALUE,				!PRINT A NUMBER
    ERROR : NOVALUE,				!SIGNAL PROGRAMMING ERROR
    ERRMSG : NOVALUE,				!ERROR MESSAGE
    SYM_VAL,					!OBTAIN VALUE OF A SYMBOL
    GETSTG,					!GET STORAGE FROM FREE LIST
    GETBLK,					!GET A BLOCK OF STORAGE
    FRESTG : NOVALUE,				!RETURN STORAGE TO FREE LIST
    FREBLK : NOVALUE,				!RETURN A BLOCK OF STORAGE
    FND_CHAIN,					!"FIND" AN ITEM IN A CHAIN
    DEL_PTRS : NOVALUE;				!DELETE CHAIN BLOCKS

GLOBAL ROUTINE RCOR (FILE_PTR, FILE_CHAN, CORE_LEN) : NOVALUE = 	!READ CORE IMAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!	READ A CORE IMAGE FOR CORE IMAGE BUILDER (VNP20)
!	 THIS INCLUDES THE KERNEL AND TASK IMAGES.
!
! FORMAL PARAMETERS:
!
!	FILE_PTR - POINTER TO THE FILE BLOCK WHICH DESCRIBES
!	 THE CORE IMAGE FILE TO BE READ
!	FILE_CHAN - THE CHANNEL NUMBER TO USE WHEN READING THE FILE.
!	CORE_LEN - LENGTH OF THE CORE IMAGE, IN 8-BIT BYTES.
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	FILLS THE 'CORE_IMAGE' ARRAY WITH THE CORE IMAGE
!	 AND STORES POINTERS IN THE FILE BLOCK
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	OPENS, READS AND CLOSES THE SPECIFIED FILE
!	 OBTAINS TWO ARRAYS FROM FREE SPACE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'RCOR');

    MAP
	FILE_PTR : REF FILE_BLOCK;

    LOCAL
	CHAR,
	CORE_IMAGE : REF VECTOR,
	CORE_WORD,
	LABEL_IMAGE : REF VECTOR [1024],
	LOCN,
	READ_DONE;

!
! GET SPACE FOR THE CORE IMAGE AND LABELS FROM FREE STORAGE
!

    IF ((CORE_IMAGE = GETSTG (.CORE_LEN/4)) EQL 0)
    THEN
	ERRMSG (0, 1, ROUTINE_NAME, 0, 0, 0, 0)
    ELSE
	BEGIN

	IF ((LABEL_IMAGE = GETSTG (1024)) EQL 0)
	THEN
	    ERRMSG (0, 1, ROUTINE_NAME, 0, 0, 0, 0)
	ELSE
	    BEGIN
!
! CLEAR THE CORE ARRAY, SO ANY LOCATIONS NOT FILLED WILL BE
!  ZERO.
!

	    INCR COUNTER FROM 0 TO ((.CORE_LEN/4) - 1) DO
		CORE_IMAGE [.COUNTER] = 0;

!
! OPEN THE FILE CONTAINING THE KERNEL.
!

	    IF (OPEN (.FILE_CHAN, FILE_PTR [FILE_NAME], 2, 0, UPLIT (%ASCIZ'TSK')) NEQ 0)
	    THEN
		BEGIN				!SUCCESSFUL INPUT OPEN
		READ_DONE = 0;
		LOCN = 0;
!
! RECORD THE LABEL BLOCK SEPARATELY
!

		INCR COUNTER FROM 0 TO 1023 DO
		    LABEL_IMAGE [.COUNTER] = INPUT (.FILE_CHAN);

!
! READ THE DATA INTO THE CORE IMAGE ARRAY
!

		WHILE (.READ_DONE EQL 0) DO
		    BEGIN
		    CHAR = INPUT (.FILE_CHAN);

		    IF (.CHAR LSS 0)
		    THEN
			READ_DONE = -1
		    ELSE
			BEGIN
			CORE_WORD = .CORE_IMAGE [.LOCN/4];
			CORE_WORD<(CASE (.LOCN AND 3) FROM 0 TO 3 OF
				SET
				[0] : 18;
				[1] : 26;
				[2] : 0;
				[3] : 8;
				TES), 8> = .CHAR;
			CORE_IMAGE [.LOCN/4] = .CORE_WORD;
			LOCN = .LOCN + 1;

			IF (.LOCN GTR .CORE_LEN) THEN READ_DONE = -1;

			END;

		    END;

!
! NOW STORE POINTERS TO THE CORE IMAGE AND LABEL IMAGE IN THE FILE
!  BLOCK, FOR CONVENIENT REFERENCE.
!
		FILE_PTR [FILE_CORE] = .CORE_IMAGE;
		FILE_PTR [FILE_CORE_LEN] = .CORE_LEN;
		FILE_PTR [FILE_LABEL] = .LABEL_IMAGE;
		CLOSE (.FILE_CHAN);
		END;

	    END;

	END;

    END;					!OF RCOR

GLOBAL ROUTINE WCOR (FILE_CHAN, FILE_PTR) : NOVALUE = 	!WRITE CORE IMAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!	WRITE A CORE IMAGE FOR THE CORE IMAGE BUILDER (VNP20).
!
! FORMAL PARAMETERS:
!
!	FILE_CHAN - THE CHANNEL NUMBER TO USE WHEN READING THE FILE.
!	FILE_PTR - POINTER TO THE FILE BLOCK WHICH DESCRIBES
!	 THE CORE IMAGE FILE TO BE READ
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	OPENS, WRITES AND CLOSES THE SPECIFIED FILE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'WCOR');

    MAP
	FILE_PTR : REF FILE_BLOCK;

    LOCAL
	CORE_IMAGE : REF VECTOR,
	LABEL_IMAGE : REF VECTOR [1024],
	CHAR,
	CORE_LEN,
	CORE_WORD,
	LOCN,
	WRITE_DONE;

!
! OPEN THE FILE WHICH IS TO CONTAIN THE CORE IMAGE
!

    IF (OPEN (.FILE_CHAN, FILE_PTR [FILE_NAME], 2, 1, UPLIT (%ASCIZ'SYS')) NEQ 0)
    THEN
	BEGIN					!SUCCESSFUL OUTPUT OPEN
	CORE_IMAGE = .FILE_PTR [FILE_CORE];
	CORE_LEN = .FILE_PTR [FILE_CORE_LEN];
	LABEL_IMAGE = .FILE_PTR [FILE_LABEL];
	WRITE_DONE = 0;
	LOCN = 0;
!
! FIRST WRITE OUT THE LABEL BLOCK
!

	INCR COUNTER FROM 0 TO 1023 DO
	    OUTPUT (.FILE_CHAN, .LABEL_IMAGE [.COUNTER]);

!
! WRITE THE DATA FROM THE CORE IMAGE ARRAY
!

	WHILE (.WRITE_DONE EQL 0) DO
	    BEGIN
	    CORE_WORD = .CORE_IMAGE [.LOCN/4];
	    CHAR = .CORE_WORD<(CASE (.LOCN AND 3) FROM 0 TO 3 OF
		    SET
		    [0] : 18;
		    [1] : 26;
		    [2] : 0;
		    [3] : 8;
		    TES), 8>;
	    OUTPUT (.FILE_CHAN, .CHAR);
	    LOCN = .LOCN + 1;

	    IF (.LOCN GEQ .CORE_LEN) THEN WRITE_DONE = -1;

	    END;

	CLOSE (.FILE_CHAN);
	END;

    END;					!OF WCOR

GLOBAL ROUTINE FCOR (FILE_PTR) : NOVALUE = 	!FREE CORE IMAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!	PURGE A CORE IMAGE - DISCARD ITS FILE BLOCK AND ALL THAT
!	 IT POINTS TO.
!
! FORMAL PARAMETERS:
!
!	FILE_PTR - POINTER TO THE FILE BLOCK WHICH DESCRIBES
!	 THE CORE IMAGE FILE TO BE FREED
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	RETURNS SPACE TO FREE STORAGE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'FCOR');

    MAP
	FILE_PTR : REF FILE_BLOCK;

    LOCAL
	CORE_IMAGE : REF VECTOR,
	LABEL_IMAGE : REF VECTOR [1024],
	CORE_LEN;

!
! EXTRACT POINTERS AND SO ON FROM THE FILE BLOCK
!
    LABEL_IMAGE = .FILE_PTR [FILE_LABEL];
    CORE_LEN = .FILE_PTR [FILE_CORE_LEN];
    CORE_IMAGE = .FILE_PTR [FILE_CORE];
!
! FREE THE CORE IMAGE AND THE LABEL IMAGE
!

    IF (.CORE_LEN NEQ 0) THEN FRESTG (.CORE_IMAGE, .CORE_LEN/4);

    IF (.LABEL_IMAGE NEQ 0) THEN FRESTG (.LABEL_IMAGE, 1024);

!
! SCAN THROUGH THE SYMBOL TABLE, FREEING IT.
!
    FND_CHAIN (.FILE_PTR [FILE_DOWN], DEL_MODU, 0);
!
! NOW FREE THE CHAIN BLOCKS
!
    DEL_PTRS (.FILE_PTR [FILE_DOWN]);
!
! NEW FREE THE FILE BLOCK ITSELF
!
    FREBLK (.FILE_PTR);
!
    END;					!OF FCOR

ROUTINE DEL_MODU (MODU_PTR, UNUSED) = 		!DELETE A MODULE

!++
! FUNCTIONAL DESCRIPTION:
!
!	DELETE A MODULE AFTER DELETEING THE PSECTS IT POINTS TO.
!	 USED IN CALL TO FND_CHAIN.
!
! FORMAL PARAMETERS:
!
!	MODU_PTR - POINTER TO THE MODULE BLOCK TO BE DELETED
!	UNUSED - NOT USED
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	ALWAYS 0 TO CONTINUE THE SCAN
!
! SIDE EFFECTS
!
!	RETURNS SPACE TO FREE STORAGE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'DEL_MODU');

    MAP
	MODU_PTR : REF MODU_BLOCK;

!
! FREE ALL THE PSECTS FIRST
!

    IF (.MODU_PTR [MODU_PSECTS] NEQ 0)
    THEN
	BEGIN
	FND_CHAIN (.MODU_PTR [MODU_PSECTS], DEL_PSECT, 0);
	DEL_PTRS (.MODU_PTR [MODU_PSECTS]);
	END;

!
! FREE ALL THE GLOBALS NEXT
!

    IF (.MODU_PTR [MODU_GLOBALS] NEQ 0)
    THEN
	BEGIN
	FND_CHAIN (.MODU_PTR [MODU_GLOBALS], DEL_GLOBAL, 0);
	DEL_PTRS (.MODU_PTR [MODU_GLOBALS]);
	END;

!
! NOW FREE THE MODULE BLOCK
!
    FREBLK (.MODU_PTR);
!
! ALWAYS RETURN 0 TO CONTINUE THE SCAN
!
    0
    END;					!OF DEL_MODU
ROUTINE DEL_PSECT (PSECT_PTR, UNUSED) = 	!DELETE A PSECT

!++
! FUNCTIONAL DESCRIPTION:
!
!	DELETE A PSECT AFTER DELETEING THE GLOBALS IT POINTS TO.
!	 USED IN CALL TO FND_CHAIN.
!
! FORMAL PARAMETERS:
!
!	PSECT_PTR - POINTER TO THE PSECT BLOCK TO BE DELETED
!	UNUSED - NOT USED
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	ALWAYS 0 TO CONTINUE THE SCAN
!
! SIDE EFFECTS
!
!	RETURNS SPACE TO FREE STORAGE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'DEL_PSECT');

    MAP
	PSECT_PTR : REF PSECT_BLOCK;

!
! FREE ALL THE GLOBALS FIRST
!
    FND_CHAIN (.PSECT_PTR [PSECT_GLOBALS], DEL_GLOBAL, 0);
!
! FREE THE POINTERS
!
    DEL_PTRS (.PSECT_PTR [PSECT_GLOBALS]);
!
! NOW FREE THE PSECT BLOCK
!
    FREBLK (.PSECT_PTR);
!
! ALWAYS RETURN 0 TO CONTINUE THE SCAN
!
    0
    END;					!OF DEL_PSECT
ROUTINE DEL_GLOBAL (GLOBAL_PTR, UNUSED) = 	!DELETE A GLOBAL

!++
! FUNCTIONAL DESCRIPTION:
!
!	DELETE A GLOBAL BLOCK.
!	 USED IN CALL TO FND_CHAIN.
!
! FORMAL PARAMETERS:
!
!	GLOBAL_PTR - POINTER TO THE GLOBAL BLOCK TO BE DELETED
!	UNUSED - NOT USED
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	ALWAYS 0 TO CONTINUE THE SCAN
!
! SIDE EFFECTS
!
!	RETURNS SPACE TO FREE STORAGE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'DEL_GLOBAL');

    MAP
	GLOBAL_PTR : REF GLOBL_BLOCK;

!
! FREE THE GLOBAL BLOCK.
!
    FREBLK (.GLOBAL_PTR);
!
! ALWAYS RETURN 0 TO CONTINUE THE SCAN
!
    0
    END;					!OF DEL_GLOBAL

GLOBAL ROUTINE GETSYM (KERNEL_FILE, CEX_FILE, RSXMS_FILE, VALUES) : NOVALUE = 	!FETCH SYMBOL VALUES

!++
! FUNCTIONAL DESCRIPTION:
!
!	FETCH SYMBOL VALUES FROM THE VARIOUS SYMBOL TABLES, CHECKING
!	 FOR CONSISTENCY.  THIS IS DONE ONCE RATHER THAN WHENEVER
!	 A SYMBOL VALUE IS NEEDED BECAUSE LOOKING UP A SYMBOL IS
!	 QUITE SLOW.
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - FILE BLOCK FOR THE KERNEL
!	CEX_FILE - FILE BLOCK FOR THE COMM EXEC
!	RSXMS_FILE - FILE BLOCK FOR THE EXEMC SYMBOLS
!	VALUES - BLOCK INTO WHICH TO STORE SYMBOL VALUES
!
! IMPLICIT INPUTS:
!
!	THE SYMBOL VALUES IN THE SYMBOL TABLES
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	FILLS IN SYMBOLS IN 'VALUES'
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'GETSYM');

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	CEX_FILE : REF FILE_BLOCK,
	RSXMS_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    GETSYM_1 (.KERNEL_FILE, .RSXMS_FILE, .VALUES);

    IF (.VALUES [P_LGTH] NEQ SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'P.LGTH'), 0))
    THEN
	ERRMSG (0, 29,
	    ROUTINE_NAME, UPLIT (%ASCIZ'P.LGTH'), KERNEL_FILE [FILE_NAME], RSXMS_FILE [FILE_NAME], 0);

    IF (SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$CLRMV'), 0) NEQ SYM_VAL (.CEX_FILE, UPLIT (%ASCIZ'$CLRMV'), 0))
    THEN
	ERRMSG (0, 29, ROUTINE_NAME, UPLIT (%ASCIZ'$CLRMV'), KERNEL_FILE [FILE_NAME], CEX_FILE [FILE_NAME], 0)

    ;

    IF (SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$HEADR'), 0) NEQ SYM_VAL (.CEX_FILE, UPLIT (%ASCIZ'$HEADR'), 0))
    THEN
	ERRMSG (0, 29, ROUTINE_NAME, UPLIT (%ASCIZ'$HEADR'), KERNEL_FILE [FILE_NAME], CEX_FILE [FILE_NAME], 0)

    ;

    IF (SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$INTX1'), 0) NEQ SYM_VAL (.CEX_FILE, UPLIT (%ASCIZ'$INTX1'), 0))
    THEN
	ERRMSG (0, 29, ROUTINE_NAME, UPLIT (%ASCIZ'$INTX1'), KERNEL_FILE [FILE_NAME], CEX_FILE [FILE_NAME], 0)

    ;
    END;					!OF GETSYM

ROUTINE GETSYM_1 (KERNEL_FILE, RSXMS_FILE, VALUES) : NOVALUE = 	!FETCH SYMBOL VALUES

!++
! FUNCTIONAL DESCRIPTION:
!
!	FETCH THE SYMBOLS
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - FILE BLOCK FOR THE KERNEL
!	RSXMS_FILE - FILE BLOCK FOR THE EXEMC SYMBOLS
!	VALUES - BLOCK INTO WHICH TO STORE SYMBOL VALUES
!
! IMPLICIT INPUTS:
!
!	THE SYMBOL VALUES IN THE SYMBOL TABLES
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	FILLS IN SYMBOLS IN 'VALUES'
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'GETSYM_1');

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	RSXMS_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    VALUES [CRAVL] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$CRAVL'), 0);
    VALUES [EXSIZ] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$EXSIZ'), 0);
    VALUES [POOL] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$POOL '), 0);
    VALUES [FMASK] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$FMASK'), 0);
    VALUES [SYSIZ] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$SYSIZ'), 0);
    VALUES [PARHD] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$PARHD'), 0);
    VALUES [TSKHD] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$TSKHD'), 0);
    VALUES [CLKHD] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$CLKHD'), 0);
    VALUES [DEVHD] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$DEVHD'), 0);
    VALUES [ABTIM] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$ABTIM'), 0);
    VALUES [TKPS] = SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$TKPS '), 0);
    VALUES [P_LGTH] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.LGTH'), 0);
    VALUES [P_LNK] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.LNK '), 0);
    VALUES [P_PRI] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.PRI '), 0);
    VALUES [P_IOC] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.IOC '), 0);
    VALUES [P_NAM] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.NAM '), 0);
    VALUES [P_SUB] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.SUB '), 0);
    VALUES [P_MAIN] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.MAIN'), 0);
    VALUES [P_REL] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.REL '), 0);
    VALUES [P_SIZE] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.SIZE'), 0);
    VALUES [P_WAIT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.WAIT'), 0);
    VALUES [P_BUSY] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.BUSY'), 0);
    VALUES [P_TCB] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.TCB '), 0);
    VALUES [P_STAT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.STAT'), 0);
    VALUES [P_HDR] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.HDR '), 0);
    VALUES [P_PRO] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.PRO '), 0);
    VALUES [P_ATT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'P.ATT '), 0);
    VALUES [FE_EXT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.EXT'), 0);
    VALUES [FE_MUP] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.MUP'), 0);
    VALUES [FE_EXV] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.EXV'), 0);
    VALUES [FE_DRV] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.DRV'), 0);
    VALUES [FE_PLA] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.PLA'), 0);
    VALUES [FE_CAL] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.CAL'), 0);
    VALUES [FE_PKT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.PKT'), 0);
    VALUES [FE_EXP] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.EXP'), 0);
    VALUES [FE_LSI] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.LSI'), 0);
    VALUES [FE_CEX] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.CEX'), 0);
    VALUES [FE_NLG] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.NLG'), 0);
    VALUES [FE_NLG] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'FE.NLG'), 0);
    VALUES [PS_OUT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.OUT'), 0);
    VALUES [PS_CKP] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.CKP'), 0);
    VALUES [PS_CKR] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.CKR'), 0);
    VALUES [PS_CHK] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.CHK'), 0);
    VALUES [PS_FXD] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.FXD'), 0);
    VALUES [PS_PER] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.PER'), 0);
    VALUES [PS_LIO] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.LIO'), 0);
    VALUES [PS_NSF] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.NSF'), 0);
    VALUES [PS_COM] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.COM'), 0);
    VALUES [PS_PIC] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.PIC'), 0);
    VALUES [PS_SYS] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.SYS'), 0);
    VALUES [PS_DRV] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.DRV'), 0);
    VALUES [PS_DEL] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.DEL'), 0);
    VALUES [PS_APR] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'PS.APR'), 0);
    VALUES [T_PRI] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.PRI '), 0);
    VALUES [T_NAM] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.NAM '), 0);
    VALUES [T_RCVL] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.RCVL'), 0);
    VALUES [T_ASTL] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.ASTL'), 0);
    VALUES [T_TCBL] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.TCBL'), 0);
    VALUES [T_STAT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.STAT'), 0);
    VALUES [T_ST2] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.ST2 '), 0);
    VALUES [T_ST3] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.ST3 '), 0);
    VALUES [T_DPRI] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.DPRI'), 0);
    VALUES [T_LBN] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.LBN '), 0);
    VALUES [T_LDV] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.LDV '), 0);
    VALUES [T_PCB] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.PCB '), 0);
    VALUES [T_MXSZ] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.MXSZ'), 0);
    VALUES [T_LGTH] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T.LGTH'), 0);
    VALUES [H_HDLN] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'H.HDLN'), 0);
    VALUES [H_WND] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'H.WND '), 0);
    VALUES [H_GARD] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'H.GARD'), 0);
    VALUES [H_NLUN] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'H.NLUN'), 0);
    VALUES [H_LUN] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'H.LUN '), 0);
    VALUES [TS_EXE] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'TS.EXE'), 0);
    VALUES [TS_RDN] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'TS.RDN'), 0);
    VALUES [TS_MSG] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'TS.MSG'), 0);
    VALUES [TS_NRP] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'TS.NRP'), 0);
    VALUES [TS_RUN] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'TS.RUN'), 0);
    VALUES [TS_OUT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'TS.OUT'), 0);
    VALUES [TS_CKP] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'TS.CKP'), 0);
    VALUES [TS_CKR] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'TS.CKR'), 0);
    VALUES [T2_AST] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.AST'), 0);
    VALUES [T2_DST] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.DST'), 0);
    VALUES [T2_CHK] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.CHK'), 0);
    VALUES [T2_CKD] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.CKD'), 0);
    VALUES [T2_BFX] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.BFX'), 0);
    VALUES [T2_FXD] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.FXD'), 0);
    VALUES [T2_TIO] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.TIO'), 0);
    VALUES [T2_CAF] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.CAF'), 0);
    VALUES [T2_HLT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.HLT'), 0);
    VALUES [T2_ABO] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.ABO'), 0);
    VALUES [T2_STP] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.STP'), 0);
    VALUES [T2_SPN] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.SPN'), 0);
    VALUES [T2_WFR] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T2.WFR'), 0);
    VALUES [T3_ACP] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.ACP'), 0);
    VALUES [T3_PMD] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.PMD'), 0);
    VALUES [T3_REM] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.REM'), 0);
    VALUES [T3_PRV] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.PRV'), 0);
    VALUES [T3_MCR] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.MCR'), 0);
    VALUES [T3_SLV] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.SLV'), 0);
    VALUES [T3_CLI] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.CLI'), 0);
    VALUES [T3_RST] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.RST'), 0);
    VALUES [T3_NSD] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.NSD'), 0);
    VALUES [T3_CAL] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.CAL'), 0);
    VALUES [T3_ROV] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.ROV'), 0);
    VALUES [T3_NET] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'T3.NET'), 0);
    VALUES [D_LNK] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'D.LNK '), 0);
    VALUES [D_UCB] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'D.UCB '), 0);
    VALUES [D_NAM] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'D.NAM '), 0);
    VALUES [D_UNIT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'D.UNIT'), 0);
    VALUES [D_UCBL] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'D.UCBL'), 0);
    VALUES [D_DSP] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'D.DSP '), 0);
    VALUES [D_MSK] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'D.MSK '), 0);
    VALUES [D_PCB] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'D.PCB '), 0);
    VALUES [S_LHD] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'S.LHD '), 0);
    VALUES [S_VCT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'S.VCT '), 0);
    VALUES [S_FRK] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'S.FRK '), 0);
    VALUES [U_DCB] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'U.DCB '), 0);
    VALUES [U_RED] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'U.RED '), 0);
    VALUES [U_CW1] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'U.CW1 '), 0);
    VALUES [U_CW2] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'U.CW2 '), 0);
    VALUES [U_CW3] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'U.CW3 '), 0);
    VALUES [U_CW4] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'U.CW4 '), 0);
    VALUES [U_SCB] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'U.SCB '), 0);
    VALUES [CLK_LNK] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.LNK '), 0);
    VALUES [CLK_RQT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.RQT '), 0);
    VALUES [CLK_EFN] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.EFN '), 0);
    VALUES [CLK_TCB] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.TCB '), 0);
    VALUES [CLK_TIM] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.TIM '), 0);
    VALUES [CLK_LGTH] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.LGTH'), 0);
    VALUES [CLK_MRKT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.MRKT'), 0);
    VALUES [CLK_SCHD] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.SCHD'), 0);
    VALUES [CLK_SSHT] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.SSHT'), 0);
    VALUES [CLK_SYST] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.SYST'), 0);
    VALUES [CLK_SYTK] = SYM_VAL (.RSXMS_FILE, UPLIT (%ASCIZ'C.SYTK'), 0);
    END;					!OF GETSYM_1

GLOBAL ROUTINE GETBYT (FILE_PTR, LOCN) = 	!GET A BYTE FROM A CORE OR TASK IMAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!	FETCH A SPECIFIED BYTE FROM A CORE IMAGE OR TASK IMAGE.
!
! FORMAL PARAMETERS:
!
!	FILE_PTR - FILE BLOCK WHICH CONTAINS POINTERS TO THE IMAGE
!	LOCN - ADDRESS OF LOCATION TO FETCH
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	THE 8-BIT BYTE AT THE LOCATION, OR -1 IF ERROR.
!
! SIDE EFFECTS
!
!	NONE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'GETBYT');

    MAP
	FILE_PTR : REF FILE_BLOCK;

    LOCAL
	CORE_IMAGE : REF VECTOR,
	LABEL_IMAGE : REF VECTOR,
	CORE_LEN,
	CORE_WORD,
	RESULT,
	BASE_ADDRESS;

    IF (DEBUG GEQ 3)
    THEN
	BEGIN					!DEBUG
	PCRLF (1);
	OUTPUT (1, %O'11');
	OUTPUT (1, %O'11');
	OUTSTR (1, UPLIT (%ASCIZ'GETBYT: '));
	OUTNUM (1, .LOCN, 8, 6);
	END;					!DEBUG

!
! GET POINTERS TO THE MEMORY INFORMATION
!
    CORE_IMAGE = .FILE_PTR [FILE_CORE];
    CORE_LEN = .FILE_PTR [FILE_CORE_LEN];
    LABEL_IMAGE = .FILE_PTR [FILE_LABEL];
!
! VALIDATE THE ADDRESS
!
    BASE_ADDRESS = .LABEL_IMAGE [L$BSA] + (.LABEL_IMAGE [L$BSA + 1]*256);

    IF (((.LOCN - .BASE_ADDRESS) GEQ .CORE_LEN) OR (.LOCN LSS .BASE_ADDRESS))
    THEN
	BEGIN
	ERRMSG (0, 25, ROUTINE_NAME, .LOCN, FILE_PTR [FILE_NAME], 0, 0);
	RESULT = -1;
	END
    ELSE
	BEGIN
!
! FETCH THE DATA
!
	CORE_WORD = .CORE_IMAGE [(.LOCN - .BASE_ADDRESS)/4];
	RESULT = .CORE_WORD<(CASE ((.LOCN - .BASE_ADDRESS) AND 3) FROM 0 TO 3 OF
		SET
		[0] : 18;
		[1] : 26;
		[2] : 0;
		[3] : 8;
		TES), 8>
	END;

    IF (DEBUG GEQ 3)
    THEN
	BEGIN					!DEBUG
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .RESULT, 8, 6);
	END;					!DEBUG

    .RESULT
    END;					!OF GETBYT

GLOBAL ROUTINE GETWRD (FILE_PTR, LOCN) = 	!GET A WORD FROM A CORE OR TASK IMAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!	FETCH A SPECIFIED WORD FROM A CORE IMAGE OR TASK IMAGE.
!
! FORMAL PARAMETERS:
!
!	FILE_PTR - FILE BLOCK WHICH CONTAINS POINTERS TO THE IMAGE
!	LOCN - ADDRESS OF LOCATION TO FETCH
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	THE 16-BIT WORD AT THE LOCATION, OR -1 IF ERROR.
!
! SIDE EFFECTS
!
!	NONE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'GETWRD');

    MAP
	FILE_PTR : REF FILE_BLOCK;

    LOCAL
	CORE_IMAGE : REF VECTOR,
	LABEL_IMAGE : REF VECTOR,
	CORE_LEN,
	CORE_WORD,
	RESULT,
	BASE_ADDRESS;

    IF (DEBUG GEQ 3)
    THEN
	BEGIN					!DEBUG
	PCRLF (1);
	OUTPUT (1, %O'11');
	OUTPUT (1, %O'11');
	OUTSTR (1, UPLIT (%ASCIZ'GETWRD: '));
	OUTNUM (1, .LOCN, 8, 6);
	END;					!DEBUG

!
! GET POINTERS TO THE MEMORY INFORMATION
!
    CORE_IMAGE = .FILE_PTR [FILE_CORE];
    CORE_LEN = .FILE_PTR [FILE_CORE_LEN];
    LABEL_IMAGE = .FILE_PTR [FILE_LABEL];
!
! VALIDATE THE ADDRESS
!
    BASE_ADDRESS = .LABEL_IMAGE [L$BSA] + (.LABEL_IMAGE [L$BSA + 1]*256);

    IF (((.LOCN - .BASE_ADDRESS) GEQ .CORE_LEN) OR (.LOCN LSS .BASE_ADDRESS)) OR ((.LOCN AND %O'1') NEQ 0)
    THEN
	BEGIN
	ERRMSG (0, 25, ROUTINE_NAME, .LOCN, FILE_PTR [FILE_NAME], 0, 0);
	RESULT = -1;
	END
    ELSE
	BEGIN
!
! FETCH THE DATA
!
	CORE_WORD = .CORE_IMAGE [(.LOCN - .BASE_ADDRESS)/4];
	RESULT = .CORE_WORD<(CASE ((.LOCN - .BASE_ADDRESS) AND 3) FROM 0 TO 2 OF
		SET
		[0] : 18;
		[1] : -1;
		[2] : 0;
		TES), 8> + 			!
	(.CORE_WORD<(CASE ((.LOCN + 1 - .BASE_ADDRESS) AND 3) FROM 1 TO 3 OF
		SET
		[1] : 26;
		[2] : -1;
		[3] : 8;
		TES), 8>*256);
	END;

    IF (DEBUG GEQ 3)
    THEN
	BEGIN					!DEBUG
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .RESULT, 8, 6);
	END;					!DEBUG

    .RESULT
    END;					!OF GETWRD

GLOBAL ROUTINE PUTBYT (FILE_PTR, LOCN, VAL) : NOVALUE = 	!PUT A BYTE IN A CORE IMAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!	STORE A SPECIFIED BYTE IN A CORE IMAGE.
!
! FORMAL PARAMETERS:
!
!	FILE_PTR - FILE BLOCK WHICH CONTAINS POINTERS TO THE IMAGE
!	 (WILL ALWAYS BE THE KERNEL)
!	LOCN - ADDRESS OF LOCATION TO STORE
!	VAL - VALUE TO BE STORED; ONLY THE LOW-ORDER 8 BITS ARE STORED
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	CHANGES THE CORE IMAGE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'PUTBYT');

    MAP
	FILE_PTR : REF FILE_BLOCK;

    LOCAL
	CORE_IMAGE : REF VECTOR,
	LABEL_IMAGE : REF VECTOR,
	CORE_LEN,
	CORE_WORD,
	BASE_ADDRESS;

    IF (DEBUG GEQ 3)
    THEN
	BEGIN					!DEBUG
	PCRLF (1);
	OUTPUT (1, %O'11');
	OUTPUT (1, %O'11');
	OUTSTR (1, UPLIT (%ASCIZ'PUTBYT: '));
	OUTNUM (1, .LOCN, 8, 6);
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .VAL, 8, 6);
	END;					!DEBUG

!
! GET POINTERS TO THE MEMORY INFORMATION
!
    CORE_IMAGE = .FILE_PTR [FILE_CORE];
    CORE_LEN = .FILE_PTR [FILE_CORE_LEN];
    LABEL_IMAGE = .FILE_PTR [FILE_LABEL];
!
! VALIDATE THE ADDRESS
!
    BASE_ADDRESS = .LABEL_IMAGE [L$BSA] + (.LABEL_IMAGE [L$BSA + 1]*256);

    IF (((.LOCN - .BASE_ADDRESS) GEQ .CORE_LEN) OR (.LOCN LSS .BASE_ADDRESS))
    THEN
	ERRMSG (0, 25,
	    ROUTINE_NAME, .LOCN, FILE_PTR [FILE_NAME], 0, 0)
    ELSE
	BEGIN
!
! STORE THE DATA
!
	CORE_WORD = .CORE_IMAGE [(.LOCN - .BASE_ADDRESS)/4];
	CORE_WORD<(CASE ((.LOCN - .BASE_ADDRESS) AND 3) FROM 0 TO 3 OF
		SET
		[0] : 18;
		[1] : 26;
		[2] : 0;
		[3] : 8;
		TES), 8> = .VAL;
	CORE_IMAGE [(.LOCN - .BASE_ADDRESS)/4] = .CORE_WORD;
	END;

    END;					!OF PUTBYT

GLOBAL ROUTINE PUTWRD (FILE_PTR, LOCN, VAL) : NOVALUE = 	!PUT A WORD IN A CORE IMAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!	STORE A 16-BIT WORD IN A CORE IMAGE
!
! FORMAL PARAMETERS:
!
!	FILE_PTR - FILE BLOCK WHICH CONTAINS POINTERS TO THE IMAGE
!	 (WILL ALWAYS BE KERNEL)
!	LOCN - ADDRESS OF LOCATION TO STORE
!	VAL - VALUE TO STORE; ONLY THE LOW-ORDER 16 BITS ARE STORED
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	CHANGES THE CORE IMAGE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'PUTWRD');

    MAP
	FILE_PTR : REF FILE_BLOCK;

    LOCAL
	CORE_IMAGE : REF VECTOR,
	LABEL_IMAGE : REF VECTOR,
	CORE_LEN,
	CORE_WORD,
	BASE_ADDRESS;

    IF (DEBUG GEQ 3)
    THEN
	BEGIN					!DEBUG
	PCRLF (1);
	OUTPUT (1, %O'11');
	OUTPUT (1, %O'11');
	OUTSTR (1, UPLIT (%ASCIZ'PUTWRD: '));
	OUTNUM (1, .LOCN, 8, 6);
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .VAL, 8, 6);
	END;					!DEBUG

!
! GET POINTERS TO THE MEMORY INFORMATION
!
    CORE_IMAGE = .FILE_PTR [FILE_CORE];
    CORE_LEN = .FILE_PTR [FILE_CORE_LEN];
    LABEL_IMAGE = .FILE_PTR [FILE_LABEL];
!
! VALIDATE THE ADDRESS
!
    BASE_ADDRESS = .LABEL_IMAGE [L$BSA] + (.LABEL_IMAGE [L$BSA + 1]*256);

    IF (((.LOCN - .BASE_ADDRESS) GEQ .CORE_LEN) OR (.LOCN LSS .BASE_ADDRESS) OR ((.LOCN AND %O'1') NEQ 0))
    THEN
	ERRMSG (0, 25, ROUTINE_NAME, .LOCN, FILE_PTR [FILE_NAME], 0, 0)
    ELSE
	BEGIN
!
! STORE THE DATA
!
	CORE_WORD = .CORE_IMAGE [(.LOCN - .BASE_ADDRESS)/4];
	CORE_WORD<(CASE ((.LOCN - .BASE_ADDRESS) AND 3) FROM 0 TO 2 OF
		SET
		[0] : 18;
		[1] : -1;
		[2] : 0;
		TES), 8> = .VAL<0, 8>;
	CORE_WORD<(CASE ((.LOCN + 1 - .BASE_ADDRESS) AND 3) FROM 1 TO 3 OF
		SET
		[1] : 26;
		[2] : -1;
		[3] : 8;
		TES), 8> = .VAL<8, 8>;
	CORE_IMAGE [(.LOCN - .BASE_ADDRESS)/4] = .CORE_WORD;
	END;

    END;					!OF PUTWRD

GLOBAL ROUTINE ALOCB (FILE_PTR, AMOUNT, DUMMY, VALUES) = 	!ALLOCATE PDP-11 CORE

!++
! FUNCTIONAL DESCRIPTION:
!
!	ALLOCATE SPACE FROM THE PDP-11'S SYSTEM POOL
!	 (TRANSLATED FROM RSX-11M VERSION 3.1, MODULE CORAL)
!	 (MODIFIED BASED ON VMR TO ALLOCATE TOP-DOWN.)
!	 (Modified to remove Allocation from MCB partition)
!
! FORMAL PARAMETERS:
!
!	FILE_PTR - FILE BLOCK WHICH CONTAINS POINTERS TO THE IMAGE
!	 AND SYMBOL TABLE
!	AMOUNT - THE NUMBER OF BYTES TO GET
!	DUMMY - Unused in this version was:
!		(WHERE - 1 = COMM EXEC PARTITION OR SYSTEM POOL,
!			0 = SYSTEM POOL ONLY)
!	VALUES - BLOCK WHICH HOLDS SYMBOL VALUES
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	MODIFIES THE CORE IMAGE TO ALLOCATE THE SPACE
!
! ROUTINE VALUE:
!
!	PDP-11 ADDRESS OF WHERE CORE HAS BEEN ALLOCATED, OR 0
!
! SIDE EFFECTS
!
!	PRINTS AN ERROR MESSAGE IF PDP-11 SYSTEM POOL IS EXHAUSTED
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'ALOCB');

    MAP
	FILE_PTR : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	R0,
	R1,
	R2,
	SCAN_DONE,
	TEMP,
	RESULT;

    IF (DEBUG GEQ 2)
    THEN
	BEGIN					!DEBUG
	PCRLF (1);
	OUTPUT (1, %O'11');
	OUTSTR (1, UPLIT (%ASCIZ'ALOCB: '));
	OUTNUM (1, .AMOUNT, 8, 6);
	OUTSTR (1, UPLIT (%ASCIZ', '));
	END;					!DEBUG

    RESULT = -1;
    R1 = .AMOUNT;				!SIZE OF CORE BUFFER TO ALLOCATE IN BYTES
    R0 = .VALUES [CRAVL] - 2;			!POINT TO ALLOCATION MASK WORD
    R1 = .R1 + GETWRD (.FILE_PTR, .R0);		!ROUND TO NEXT BOUNDRY
    R1 = .R1 AND ( NOT (GETWRD (.FILE_PTR, .R0)));	!CLEAR EXCESS
    R0 = .R0 + 2;

    IF (.R1 NEQ 0)
    THEN
						!ASSUME ZERO LENGTH BLOCK; IF EQ ZERO LENGTH REQUEST
	BEGIN
	SCAN_DONE = 0;

	WHILE (.SCAN_DONE EQL 0) DO
	    BEGIN
	    R2 = .R0;				!SAVE ADDRESS OF CURRENT BLOCK
	    R0 = GETWRD (.FILE_PTR, .R2);	!GET ADDRESS OF NEXT BLOCK

	    IF (.R0 EQL 0)
	    THEN
		SCAN_DONE = -1			!IF EQ END OF CHAIN
	    ELSE
		BEGIN
		TEMP = GETWRD (.FILE_PTR, .R0 + 2);

		IF (.TEMP GEQ .R1)
		THEN
		    				!BLOCK BIG ENOUGH?  IF LO NO
		    BEGIN

		    IF (.TEMP GTR .R1)
		    THEN
						!IF EQ, BLOCK IS EXACT SIZE
			BEGIN
			PUTWRD (.FILE_PTR, .R0 + 2, .TEMP - .R1);	!REDUCE SIZE OF FREE BLOCK
			R0 = .R0 + .TEMP - .R1;	!CALCULATE ADDRESS OF ALLOCATED BLOCK
			END			!.TEMP GTR .R1
		    ELSE
			PUTWRD (.FILE_PTR, .R2, GETWRD (.FILE_PTR, .R0));	!LINK AROUND ALLOCATED BLOCK

		    SCAN_DONE = 1;
		    END;			!.TEMP GEQ .R1

		END;				!.R0 EQL 0

	    END;				!.SCAN_DONE EQL 0

	END					!.R1 NEQ 0
    ELSE
	SCAN_DONE = -1;

    IF (.SCAN_DONE GTR 0) THEN RESULT = .R0;

    IF (.RESULT LSS 0) THEN ERRMSG (0, 26, ROUTINE_NAME, FILE_PTR [FILE_NAME], .AMOUNT, 0, 0);

    IF (DEBUG GEQ 2)
    THEN
	BEGIN					!DEBUG
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .RESULT, 8, 6);
	END;					!DEBUG

    .RESULT
    END;					!OF ALOCB

GLOBAL ROUTINE DEACB (FILE_PTR, LOCN, AMOUNT, VALUES) : NOVALUE = 	!DEALLOCATE PDP-11 CORE

!++
! FUNCTIONAL DESCRIPTION:
!
!	DEALLOCATE SPACE FROM THE PDP-11'S SYSTEM POOL
!
! FORMAL PARAMETERS:
!
!	FILE_PTR - FILE BLOCK WHICH CONTAINS POINTERS TO THE IMAGE
!	 AND SYMBOL TABLE
!	LOCN - THE STARTING ADDRESS OF THE SPACE TO BE DEALLOCATED
!	AMOUNT - THE NUMBER OF BYTES TO FREE
!	VALUES - BLOCK WHICH HOLDS SYMBOL VALUES
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	MODIFIES THE CORE IMAGE TO DEALLOCATE THE SPACE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	NONE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'DEACB');

    MAP
	FILE_PTR : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	R0,
	R1,
	R2,
	R3,
	SAVE,
	SCAN_DONE,
	TEMP;

    IF (DEBUG GEQ 2)
    THEN
	BEGIN					!DEBUG
	PCRLF (1);
	OUTPUT (1, %O'11');
	OUTSTR (1, UPLIT (%ASCIZ'DEACB: '));
	OUTNUM (1, .LOCN, 8, 6);
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .AMOUNT, 8, 6);
	END;					!DEBUG

    R0 = .LOCN;					!ADDRESS OF STORAGE TO FREE
    R1 = .AMOUNT;				!NUMBER OF BYTES TO FREE
    R3 = .VALUES [CRAVL] - 2;			!POINT TO ALLOCATION MASK WORD
    TEMP = GETWRD (.FILE_PTR, .R3);		!ROUND TO NEXT BOUNDRY
    R1 = .R1 + .TEMP;
    R1 = .R1 AND ( NOT .TEMP);
    R3 = .R3 + 2;

    IF (.R1 NEQ 0)				!IF EQ NO BLOCK TO RELEASE
    THEN
	BEGIN
	SCAN_DONE = 0;

	WHILE (.SCAN_DONE EQL 0) DO
	    BEGIN
	    R2 = .R3;				!SAVE ADDRESS OF CURRENT BLOCK
	    R3 = GETWRD (.FILE_PTR, .R3);	!GET ADDRESS OF NEXT BLOCK

	    IF (.R3 EQL 0)			!IF EQ END OF CHAIN
	    THEN
		SCAN_DONE = 1
	    ELSE

		IF (.R0 LSS .R3)		!BLOCK GO HERE?
		THEN
		    SCAN_DONE = 1;		!IF HIS NO

	    END;				!OF WHILE SCAN_DONE

	PUTWRD (.FILE_PTR, .R0, .R3);		!ASSUME NO AGLOMERATION
	SAVE = .R0;				!CALCULATE ADDRESS OF NEW BLOCK
	SAVE = .SAVE + .R1;

	IF (.SAVE GEQ %O'200000')		!IF CS ILLEGAL DEALLOCATION
	THEN
	    ERRMSG (0, 27, ROUTINE_NAME, FILE_PTR [FILE_NAME], .AMOUNT, .LOCN, 1)
	ELSE
	    BEGIN

	    IF (.R0 LSS .VALUES [POOL])		! DEALLOCATION BEFORE FRONT OF LIST?
	    THEN 				!IF LO, YES
		ERRMSG (0, 27, ROUTINE_NAME, FILE_PTR [FILE_NAME], .AMOUNT, .LOCN, 2)
	    ELSE
		BEGIN
		TEMP = GETWRD (.FILE_PTR, .VALUES [EXSIZ]);

		IF (.SAVE GTR .TEMP)		!DEALLOCATION PAST END OF POOL?
		THEN 				!IF HI YES
		    ERRMSG (0, 27, ROUTINE_NAME, FILE_PTR [FILE_NAME], .AMOUNT, .LOCN, 3)
		ELSE
		    BEGIN

		    IF ((.R3 LSS .SAVE)		!EQUAL TO NEXT IN CHAIN?
			AND (.R3 NEQ 0))	!INSERT AT END OF LIST?
		    THEN 			!IF EQ YES, OK
			ERRMSG (0, 27, ROUTINE_NAME, FILE_PTR [FILE_NAME], .AMOUNT, .LOCN, 4)
		    ELSE
			BEGIN

			IF (.R3 EQL .SAVE)
			THEN
			    			!IF NE NO
			    BEGIN
			    TEMP = GETWRD (.FILE_PTR, .R3);	!MOVE LINK WORD TO BLOCK RELEASED
			    R3 = .R3 + 2;
			    PUTWRD (.FILE_PTR, .R0, .TEMP);
			    TEMP = GETWRD (.FILE_PTR, .R3);	!MERGE TWO BLOCKS
			    R1 = .R1 + .TEMP;
			    END;

			SAVE = .R2;		!SAVE ADDRESS OF PREVIOUS BLOCK
			PUTWRD (.FILE_PTR, .R2, .R0);	!ASSUME NO AGLOMERATION
			R2 = .R2 + 2;
			TEMP = GETWRD (.FILE_PTR, .R2);	!CALCULATE ADDRESS OF NEXT BLOCK
			SAVE = .SAVE + .TEMP;

			IF (.R0 LSS .SAVE)	!EQUAL TO BLOCK BEING RELEASED?
			THEN 			!IF HIS, NO OVERLAP
			    ERRMSG (0, 27, ROUTINE_NAME, FILE_PTR [FILE_NAME], .AMOUNT, .LOCN, 5)
			ELSE
			    BEGIN

			    IF (.R0 EQL .SAVE)	!IF NE NO
			    THEN
				BEGIN
				R1 = .R1 + GETWRD (.FILE_PTR, .R2);	!MERGE TWO BLOCKS
				TEMP = GETWRD (.FILE_PTR, .R0);	!MOVE LINK WORD TO PREVIOUS BLOCK
				R2 = .R2 - 2;
				PUTWRD (.FILE_PTR, .R2, .TEMP);
				R0 = .R2;	!SET NEW ADDRESS OF BLOCK
				END;

			    PUTWRD (.FILE_PTR, .R0 + 2, .R1);	!SET SIZE OF BLOCK RELEASED
			    END;

			END;

		    END;

		END;

	    END;

	END;

    END;					!OF DEACB

GLOBAL ROUTINE M_PCB (KERNEL_FILE, PAR_NAME, PAR_MAIN, PAR_BASE, PAR_TOP, BUSY_FLAGS, STAT_FLAGS,
	MIN_PCB_LEN, VALUES) = 			!CREATE A PCB

!++
! FUNCTIONAL DESCRIPTION:
!
!	CREATE A PARTITION CONTROL BLOCK (PCB).  FILL IN ITS FIELDS
!	 AND PUT IT ON THE KERNEL'S LIST OF PCBS.  THIS ROUTINE WILL
!	 CREATE EITHER A MAIN PARTITION OR A SUB PARTITION.
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - FILE BLOCK FOR THE KERNEL
!	PAR_NAME - PARTITION NAME, SIX ASCII CHARACTERS
!	PAR_MAIN - MAIN PCB FOR SUB-PARTITION, OR 0 FOR MAIN PARTITION
!	PAR_BASE - BASE ADDRESS OF THIS PARTITION
!	PAR_TOP - HIGHEST ADDRESS OF THIS PARTITION, OR 0
!	BUSY_FLAGS - FLAGS FOR THE P.BUSY WORD
!	STAT_FLAGS - FLAGS FOR THE P.STAT WORD
!	MIN_PCB_LEN - MINIMUM LENGTH PCB TO CREATE
!	VALUES - VALUES READ FROM CETAB.MAC AND THE SYMBOL TABLES
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	MAY STORE TOP OF PARTITION IN .KERNEL_FILE[FILE_HWM] FOR THE
!	 SAKE OF THE NEXT CALL TO M_PCB.
!
! ROUTINE VALUE:
!
!	PDP-11 ADDRESS OF THE PCB CREATED
!
! SIDE EFFECTS
!
!	CHANGES THE CORE IMAGE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'M_PCB');

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	PCB_ADDR,
	HIGH_EXEC_ADDR,
	FLAGS,
	TEMP1,
	TEMP2,
	DYNAMIC_PAR,
	R50VAL : VECTOR [4];

    IF (DEBUG GEQ 1)
    THEN
	BEGIN					!DEBUG
	PCRLF (1);
	OUTSTR (1, UPLIT (%ASCIZ'MAKE PCB: '));
	OUTSTR (1, .PAR_NAME);
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .PAR_BASE, 8, 6);
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .PAR_TOP, 8, 6);
	END;					!DEBUG

!
! STORE TOP OF PARTITION IN THE HIGH-WATER-MARK (HWM) CELL.
!  IT CAN BE USED AS THE BASE FOR THE NEXT CALL TO M_PCB
!  OR AS THE LIMIT FOR WHAT TO WRITE OUT OF THE CORE IMAGE.
! NOTE THAT THE HWM IS ONLY STORED IF THE NEW VALUE IS LARGER THAN
!  THE VALUE ALREADY IN THE CELL.  THIS IS BECAUSE OF SUB-PARTITIONS
!  AND SYSTEM-CONTROLLED PARTITIONS.
!

    IF (.KERNEL_FILE [FILE_HWM] LSS (.PAR_TOP OR 63)) THEN KERNEL_FILE [FILE_HWM] = .PAR_TOP OR 63;

!
! FIND THE FLAGS FROM THIS CORE IMAGE.
!  WE NEED THEM TO SUPPORT PLAS.
!
    FLAGS = GETWRD (.KERNEL_FILE, .VALUES [FMASK]);
!
! DETERMINE IF THIS IS A DYNAMIC PARTITION
!  (THAT IS, IF IT IS A SUB-PARTITION OF A SYSTEM-CONTROLLED PARTITION)
!

    IF (.PAR_MAIN EQL 0)
    THEN
	DYNAMIC_PAR = 0
    ELSE
	BEGIN					!SUB-PARTITION
	DYNAMIC_PAR = 0;

	IF ((GETWRD (.KERNEL_FILE, .PAR_MAIN + .VALUES [P_STAT]) AND .VALUES [PS_SYS]) NEQ 0)
	THEN
	    DYNAMIC_PAR = 1;

	END;

!
! NOW ALLOCATE A PARTITION CONTROL BLOCK.
!
    PCB_ADDR = ALOCB (.KERNEL_FILE, MAX (.VALUES [P_LGTH], .MIN_PCB_LEN), 0, .VALUES);
!
! NEXT, STORE APPROPRIATE VALUES IN IT
!
    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_LNK], 0);
    PUTBYT (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_PRI], 0);
    PUTBYT (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_IOC], 0);
    ATOR50 (.PAR_NAME, R50VAL);

    INCR COUNTER FROM 0 TO 3 DO
	PUTBYT (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_NAM] + .COUNTER, .R50VAL [.COUNTER]);

    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_SUB], 0);

    IF (.PAR_MAIN NEQ 0)
    THEN
	BEGIN					!LINK SUB-PARTITION TO PARTITION'S LIST
	TEMP1 = .PAR_MAIN;

	WHILE (.TEMP1 NEQ 0) DO
	    BEGIN
	    TEMP2 = .TEMP1;
	    TEMP1 = GETWRD (.KERNEL_FILE, .TEMP2 + .VALUES [P_SUB]);
	    END;

	PUTWRD (.KERNEL_FILE, .TEMP2 + .VALUES [P_SUB], .PCB_ADDR);
	END;

    IF (.PAR_MAIN EQL 0)
    THEN
	PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_MAIN], .PCB_ADDR)
    ELSE
	PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_MAIN], .PAR_MAIN);

    TEMP1 = .PAR_BASE/64;
    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_REL], .TEMP1);

    IF (.PAR_TOP NEQ 0)
    THEN
	BEGIN
	TEMP1 = (.PAR_TOP - .PAR_BASE + 64)/64;
	PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_SIZE], .TEMP1);
	END;

    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_WAIT], 0);

    IF (.DYNAMIC_PAR EQL 0)
    THEN
	PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_WAIT] + 2,
	    .PCB_ADDR + .VALUES [P_WAIT])
    ELSE
	PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_WAIT] + 2, 0);

    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_BUSY], .BUSY_FLAGS);
    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_TCB], 0);
    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_STAT], .STAT_FLAGS);
    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_HDR], 0);

    IF (.FLAGS AND .VALUES [FE_PLA])
    THEN
	BEGIN					! PLAS SUPPORT
	PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_PRO], 0);
	PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_ATT], 0);
	PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_ATT] + 2, .PCB_ADDR + .VALUES [P_ATT]);
	END;					!OF PLAS SUPPORT

!
! UNLESS THIS IS A SUB-PARTITION OF A SYSTEM-CONTROLLED PARTITION,
!  LINK IT INTO THE KERNEL'S LIST OF PARTITIONS.
!

    IF (.DYNAMIC_PAR EQL 0)
    THEN
	BEGIN					!LINK IT IN
	TEMP1 = .VALUES [PARHD];		!HEADER OF PARTITION LIST

	WHILE (.TEMP1 NEQ 0) DO
	    BEGIN
	    TEMP2 = .TEMP1;
	    TEMP1 = GETWRD (.KERNEL_FILE, .TEMP2 + .VALUES [P_LNK]);
	    END;

	PUTWRD (.KERNEL_FILE, .TEMP2 + .VALUES [P_LNK], .PCB_ADDR);
	END;

!
! WE ARE DONE, RETURN THE PCB ADDRESS
!
    .PCB_ADDR
    END;					!OF M_PCB

GLOBAL ROUTINE INSTAL (KERNEL_FILE, TASK_FILE, TASK_NAME, PCB_ARG, VALUES) : NOVALUE = 	!INSTALL A TASK

!++
! FUNCTIONAL DESCRIPTION:
!
!	INSTALL A TASK IN A GIVEN PARTITION, OR IN THE
!	 SYSTEM-CONTROLLED PARTITION.  FIX THE TASK IN CORE.
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - POINTER TO THE FILE BLOCK WHICH DESCRIBES THE
!	 RSX-11S KERNEL
!	TASK_FILE - POINTER TO A SIMILAR FILE BLOCK WHICH DESCRIBES
!	 THE TASK TO BE INSTALLED
!	TASK_NAME - POINTER TO THE TASK NAME, IN ASCII
!	PCB_ARG - THE PDP-11 ADDRESS OF THE PARTITION INTO WHICH
!	 THE TASK IS TO BE INSTALLED.  IF 0, THE TASK IS TO BE
!	 INSTALLED IN THE SYSTEM-CONTROLLED PARTITION.
!	VALUES - POINTER TO THE VALUES BLOCK
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	MODIFIES THE KERNEL'S DATA STRUCTURES
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'INSTALL');

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	TASK_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	TCB_ADDR,
	PCB_ADDR,
	PCB_NAME : VECTOR [CH$ALLOCATION(7)],
	HDR_ADDR,
	HDR_SIZE,
	TASK_LABEL : REF VECTOR [1024],
	TEMP1,
	TEMP2,
	TEMP3,
	TASK_BASE,
	TASK_TOP,
	TASK_SIZE,
	ASCVAL : VECTOR [4],
	TASK_FLAGS,
	PARTITION_BASE,
	NLUN,
	PRIORITY,
	SEARCH_DONE;

    IF (DEBUG GEQ 1)
    THEN
	BEGIN					!DEBUG
	PCRLF (1);
	OUTSTR (1, UPLIT (%ASCIZ'INSTALL: '));
	OUTSTR (1, TASK_FILE [FILE_NAME]);
	END;					!DEBUG

!
! COMPUTE THE SIZE OF THE TASK, AND ITS FLAGS
!
    TASK_LABEL = .TASK_FILE [FILE_LABEL];
    TASK_BASE = .TASK_LABEL [L$BSA] + (.TASK_LABEL [L$BSA + 1]*256);
    TASK_TOP = .TASK_LABEL [L$BHGV] + (.TASK_LABEL [L$BHGV + 1]*256);
    TASK_SIZE = .TASK_TOP - .TASK_BASE + 1;
    TASK_FLAGS = .TASK_LABEL [L$BFLG] + (.TASK_LABEL [L$BFLG + 1]*256);
!
! ALLOCATE A TCB
!
    TCB_ADDR = ALOCB (.KERNEL_FILE, .VALUES [T_LGTH], 0, .VALUES);
!
! COMPUTE THE LENGTH OF THE HEADER, AND ALLOCATE IT.
!
    HDR_SIZE = GETWRD (.TASK_FILE, .TASK_BASE + .VALUES [H_HDLN]) + 2;
    HDR_ADDR = ALOCB (.KERNEL_FILE, .HDR_SIZE, 0, .VALUES);
!
! FETCH THE NAME OF THE TASK, AND ITS PRIORITY
!
    ATOR50 (.TASK_NAME, ASCVAL);
    PRIORITY = .TASK_LABEL [L$BPRI];
!
!  IF THE TASK'S PRIORITY FIELD IS 0, DEFAULT IT TO 50.
!

    IF (.PRIORITY EQL 0) THEN PRIORITY = 50;
!
!  FETCH NAME OF PARTITION IN ASCIZ
!
    TEMP1 = (.TASK_LABEL [L$BPAR]^16) + (.TASK_LABEL [L$BPAR + 1]^24) + (.TASK_LABEL [L$BPAR + 2]) + (
	    .TASK_LABEL [L$BPAR + 3]^8);
    R50TOA (.TEMP1, PCB_NAME);

!
! IF WE NEED A PCB, ALLOCATE ONE.  OTHERWISE USE THE ONE SPECIFIED.
!

    IF (.PCB_ARG NEQ 0)
    THEN
	PCB_ADDR = .PCB_ARG
    ELSE
	BEGIN					!ALLOCATE A PCB
!
! FIND THE SYSTEM-CONTROLLED PARTITION
!
	TEMP1 = .VALUES [PARHD];
	SEARCH_DONE = 0;

	WHILE (.SEARCH_DONE EQL 0) DO
	    BEGIN
	    TEMP2 = GETWRD (.KERNEL_FILE, .TEMP1);

	    IF (.TEMP2 EQL 0)
	    THEN
		SEARCH_DONE = -1
	    ELSE
		BEGIN
		TEMP3 = GETWRD (.KERNEL_FILE, .TEMP2 + .VALUES [P_STAT]);

		IF ((.TEMP3 AND .VALUES [PS_SYS]) NEQ 0)
		THEN
		    SEARCH_DONE = 1
		ELSE
		    TEMP1 = .TEMP2 + .VALUES [P_LNK];

		END;

	    END;

	IF (.SEARCH_DONE LEQ 0) THEN ERROR (UPLIT (%ASCIZ'NO GEN PARTITION - INSTALL'));

!
! NOW ALLOCATE A SUB-PARTITION OF THE SYSTEM-CONTROLLED PARTITION
!
	PCB_ADDR = M_PCB (.KERNEL_FILE, PCB_NAME, .TEMP2, .KERNEL_FILE [FILE_HWM],
	    .KERNEL_FILE [FILE_HWM] + .TASK_SIZE, %O'000000', .VALUES [PS_SYS], 0, .VALUES);
	END;

!
! BE SURE THE TCB IS ALL ZERO, SO WE WON'T HAVE TO EXPLICITLY
!  CLEAR ZERO FIELDS BELOW.
!

    INCR COUNTER FROM 0 TO .VALUES [T_LGTH] DO
	PUTBYT (.KERNEL_FILE, .TCB_ADDR + .COUNTER, 0);

!
! FILL IN THE TCB
!
    PUTBYT (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_PRI], .PRIORITY);

    INCR COUNTER FROM 0 TO 3 DO
	PUTBYT (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_NAM] + .COUNTER, .ASCVAL [.COUNTER]);

    PUTWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_RCVL] + 2, .TCB_ADDR + .VALUES [T_RCVL]);
    PUTWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_ASTL] + 2, .TCB_ADDR + .VALUES [T_ASTL]);
    PUTWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_STAT], .VALUES [TS_EXE]);
    PUTWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_ST2], .VALUES [T2_CHK] OR .VALUES [T2_FXD]);
    PUTWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_ST3], .VALUES [T3_PMD] OR 	!
	(IF ((.TASK_FLAGS AND TS$PRV) NEQ 0) THEN .VALUES [T3_PRV] ELSE 0) OR 	!
	(IF ((.TASK_FLAGS AND TS$ACP) NEQ 0) THEN .VALUES [T3_ACP] ELSE 0) OR 	!
	(IF ((.TASK_FLAGS AND (TS$NSD OR TS$ACP)) NEQ 0) THEN .VALUES [T3_NSD] ELSE 0));
    PUTBYT (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_DPRI], .PRIORITY);
!
! SET THE 3-BYTE FIELD WHICH SPECIFIES WHERE ON ITS LOAD DEVICE
!  THIS TASK CAME FROM TO 0.
!

    INCR COUNTER FROM 0 TO 3 DO
	PUTBYT (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_LBN] + .COUNTER, 0);

!
! PRETEND THAT THIS TASK CAME FROM DEVICE LB:
!  FIND THE UCB ADDRESS FOR LB, AND STORE IT IN THE TCB.
!
    SEARCH_DONE = 0;
    TEMP1 = GETWRD (.KERNEL_FILE, .VALUES [DEVHD]);

    WHILE (.SEARCH_DONE EQL 0) DO
	BEGIN

	IF (GETWRD (.KERNEL_FILE, .TEMP1 + .VALUES [D_NAM]) EQL (%C'L' + (256*%C'B')))
	THEN
	    BEGIN
	    TEMP1 = GETWRD (.KERNEL_FILE, .TEMP1 + .VALUES [D_UCB]);
	    SEARCH_DONE = 1;
	    END
	ELSE
	    BEGIN
	    TEMP1 = GETWRD (.KERNEL_FILE, .TEMP1 + .VALUES [D_LNK]);

	    IF (.TEMP1 EQL 0) THEN SEARCH_DONE = -1;

	    END;

	END;

    IF (.SEARCH_DONE LEQ 0) THEN ERROR (UPLIT (%ASCIZ'NO DEVICE LB - INSTALL'));

!
! WE HAVE THE UCB ADDRESS OF LB IN TEMP1.
!
    PUTWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_LDV], .TEMP1);
    PUTWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_PCB], .PCB_ADDR);
    PUTWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_MXSZ], .TASK_SIZE/64);
!
! THE HEADER IS MOSTLY A COPY OF THE FIRST FEW BYTES OF THE TASK
!  IMAGE.
!

    INCR COUNTER FROM 0 TO .HDR_SIZE - 1 DO
	PUTBYT (.KERNEL_FILE, .HDR_ADDR + .COUNTER, GETBYT (.TASK_FILE, .TASK_BASE + .COUNTER));

!
! SOME FIELDS OF THE HEADER HAVE TO BE RELOCATED
!
    PUTWRD (.KERNEL_FILE, .HDR_ADDR + .VALUES [H_WND],
	GETWRD (.KERNEL_FILE, .HDR_ADDR + .VALUES [H_WND]) + .HDR_ADDR);
    PUTWRD (.KERNEL_FILE, .HDR_ADDR + .VALUES [H_GARD],
	GETWRD (.KERNEL_FILE, .HDR_ADDR + .VALUES [H_GARD]) + .HDR_ADDR);
    NLUN = GETWRD (.KERNEL_FILE, .HDR_ADDR + .VALUES [H_NLUN]);
    PUTWRD (.KERNEL_FILE, .HDR_ADDR + .VALUES [H_LUN] + (.NLUN*4) + 2, .PCB_ADDR);
!
! LINK THE PCB WITH THE TCB AND HDR
!
    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_TCB], .TCB_ADDR);
    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_HDR], .HDR_ADDR);
!
! NOW COPY THE TASK INTO ITS PARTITION
!
    PARTITION_BASE = GETWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_REL])*64;

    IF (DEBUG GEQ 1)
    THEN
	BEGIN					!DEBUG
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .PARTITION_BASE, 8, 6);
	OUTSTR (1, UPLIT (%ASCIZ', '));
	OUTNUM (1, .PARTITION_BASE + .TASK_SIZE - 1, 8, 6);
	END;					!DEBUG

    INCR COUNTER FROM 0 TO .TASK_SIZE - 1 DO
	PUTBYT (.KERNEL_FILE, .PARTITION_BASE + .COUNTER, GETBYT (.TASK_FILE, .COUNTER + .TASK_BASE));

!
! LINK THE TCB INTO THE SYSTEM'S LIST OF TCBS
!
    TEMP1 = GETWRD (.KERNEL_FILE, .VALUES [TSKHD]);
    TEMP3 = 0;
    SEARCH_DONE = 0;

    WHILE (.SEARCH_DONE EQL 0) DO
	BEGIN
	TEMP2 = GETBYT (.KERNEL_FILE, .TEMP1 + .VALUES [T_PRI]);

	IF (.TEMP2 LSS .PRIORITY)
	THEN
	    SEARCH_DONE = 1
	ELSE
	    BEGIN
	    TEMP3 = .TEMP1;
	    TEMP1 = GETWRD (.KERNEL_FILE, .TEMP1 + .VALUES [T_TCBL]);

	    IF (.TEMP1 EQL 0) THEN SEARCH_DONE = -1;

	    END;

	END;

    IF (.SEARCH_DONE LSS 0) THEN ERROR (UPLIT (%ASCIZ'TCB LINKS BAD - INSTALL'));

!
! NOW, TEMP3 POINTS TO THE PREVIOUS TCB AND TEMP1 TO THE NEXT TCB.
!  IF TEMP3 IS ZERO, THIS TCB IS TO BE FIRST.
!

    IF (.TEMP3 EQL 0)
    THEN
	PUTWRD (.KERNEL_FILE, .VALUES [TSKHD], .TCB_ADDR)
    ELSE
	PUTWRD (.KERNEL_FILE,
	    .TEMP3 + .VALUES [T_TCBL], .TCB_ADDR);

    PUTWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_TCBL], .TEMP1);
    END;					!OF INSTALL

GLOBAL ROUTINE LOADD (KERNEL_FILE, TASK_FILE, TASK_NAME, GEN_PCB, VALUES) : NOVALUE = 	!INSTALL A DRIVER

!++
! FUNCTIONAL DESCRIPTION:
!
!	INSTALL A LOADABLE DRIVER, WITH DATA BASE.  IT IS ALWAYS
!	 INSTALLED IN THE SYSTEM-CONTROLLED PARTITION.
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - POINTER TO THE FILE BLOCK WHICH DESCRIBES THE
!	 RSX-11S KERNEL
!	TASK_FILE - POINTER TO A SIMILAR FILE BLOCK WHICH DESCRIBES
!	 THE TASK (DRIVER) TO BE INSTALLED
!	TASK_NAME - POINTER TO THE TASK NAME, IN ASCII.
!	 THIS IS ALWAYS OF THE FORM XXDRV, WHERE XX IS THE DEVICE NAME.
!	GEN_PCB - PDP-11 ADDRESS OF THE SYSTEM-CONTROLLED PARTITION
!	VALUES - POINTER TO THE VALUES BLOCK
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	MODIFIES THE KERNEL'S DATA STRUCTURES
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'LOADD');

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	TASK_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	PCB_ADDR,
	PAR_BASE,
	TASK_LABEL : REF VECTOR [1024],
	TASK_BASE,
	TASK_TOP,
	TASK_SIZE,
	TASK_FLAGS,
	PCB_BASE,
	FIRST_DCB_ADDR,
	LAST_DCB_ADDR,
	DCB_ADDR,
	LAST_SCB_ADDR,
	SCB_ADDR,
	FIRST_UCB_ADDR,
	UCB_ADDR,
	UCB_LENGTH,
	XXEND,
	XXDAT,
	INPINT,
	OUTINT,
	VECTOR,
	LOC,
	NUNITS;

    IF (DEBUG GEQ 1)
    THEN
	BEGIN					!DEBUG
	PCRLF (1);
	OUTSTR (1, UPLIT (%ASCIZ'LOAD DRIVER: '));
	OUTSTR (1, TASK_FILE [FILE_NAME]);
	END;					!DEBUG

!
! COMPUTE THE SIZE OF THE TASK, AND ITS FLAGS
!
    TASK_LABEL = .TASK_FILE [FILE_LABEL];
    TASK_BASE = .TASK_LABEL [L$BSA] + (.TASK_LABEL [L$BSA + 1]*256);
    TASK_TOP = .TASK_LABEL [L$BHGV] + (.TASK_LABEL [L$BHGV + 1]*256);
    TASK_SIZE = .TASK_TOP - .TASK_BASE + 1;
    TASK_FLAGS = .TASK_LABEL [L$BFLG] + (.TASK_LABEL [L$BFLG + 1]*256);
!
! COMPUTE THE LENGTH OF THE DRIVER'S DATA BASE
!  AND ALLOCATE SPACE FOR IT.
!
    XXEND = VRBL_SYM (.TASK_FILE, 2, UPLIT (%ASCIZ'$\\END'), 0);
    XXDAT = VRBL_SYM (.TASK_FILE, 2, UPLIT (%ASCIZ'$\\DAT'), 0);
    FIRST_DCB_ADDR = ALOCB (.KERNEL_FILE, .XXEND - .XXDAT, 0, .VALUES);
!
! COPY THE DATA BASE TO THE KERNEL POOL
!

    INCR COUNTER FROM .XXDAT TO .XXEND - 1 DO
	PUTBYT (.KERNEL_FILE, .FIRST_DCB_ADDR + .COUNTER - .XXDAT, GETBYT (.TASK_FILE, .COUNTER));

!
! ALLOCATE A PCB IN THE SYSTEM-CONTROLLED AREA TO POINT TO THE
!  DRIVER MEMORY.
!
    PAR_BASE = .KERNEL_FILE [FILE_HWM] + 1;
    PCB_ADDR = M_PCB (.KERNEL_FILE, UPLIT (%ASCIZ'GEN   '), .GEN_PCB, .PAR_BASE,
	.PAR_BASE + .TASK_SIZE - (.XXEND - .XXDAT), %O'000000', .VALUES [PS_SYS] OR .VALUES [PS_DRV], 0,
	.VALUES);
!
! PROCESS EACH DCB, WITH ITS UCBS AND SCBS.
!
    SCB_ADDR = 0;
    DCB_ADDR = .FIRST_DCB_ADDR;

    WHILE (.DCB_ADDR NEQ 0) DO
	BEGIN
	LAST_DCB_ADDR = .DCB_ADDR;
!
! COMPUTE THE NUMBER OF UNITS AND THE LENGTH OF EACH UCB
!
	NUNITS = GETBYT (.KERNEL_FILE, .DCB_ADDR + .VALUES [D_UNIT] + 1) - GETBYT (.KERNEL_FILE,
	    .DCB_ADDR + .VALUES [D_UNIT]) + 1;
	UCB_LENGTH = GETWRD (.KERNEL_FILE, .DCB_ADDR + .VALUES [D_UCBL]);
!
! RELOCATE THE DCB, UCB AND SCB.
!
	FIRST_UCB_ADDR = GETWRD (.KERNEL_FILE, .DCB_ADDR + .VALUES [D_UCB]) - .XXDAT + .DCB_ADDR;
	PUTWRD (.KERNEL_FILE, .DCB_ADDR + .VALUES [D_UCB], .FIRST_UCB_ADDR);
	PUTWRD (.KERNEL_FILE, .DCB_ADDR + .VALUES [D_DSP],
	    VRBL_SYM (.TASK_FILE, 2, UPLIT (%ASCIZ'$\\TBL'), 0));
	PUTWRD (.KERNEL_FILE, .DCB_ADDR + .VALUES [D_PCB], .PCB_ADDR);

	INCR COUNTER FROM 0 TO .NUNITS - 1 DO
	    BEGIN				!EACH UCB
	    UCB_ADDR = .FIRST_UCB_ADDR + (.UCB_LENGTH*.COUNTER);
	    PUTWRD (.KERNEL_FILE, .UCB_ADDR + .VALUES [U_DCB],
		GETWRD (.KERNEL_FILE,
		    .UCB_ADDR + .VALUES [U_DCB]) - .XXDAT + .DCB_ADDR);
	    PUTWRD (.KERNEL_FILE, .UCB_ADDR + .VALUES [U_RED],
		GETWRD (.KERNEL_FILE,
		    .UCB_ADDR + .VALUES [U_RED]) - .XXDAT + .DCB_ADDR);
	    LAST_SCB_ADDR = .SCB_ADDR;
	    SCB_ADDR = GETWRD (.KERNEL_FILE, .UCB_ADDR + .VALUES [U_SCB]) - .XXDAT + .DCB_ADDR;
	    PUTWRD (.KERNEL_FILE, .UCB_ADDR + .VALUES [U_SCB], .SCB_ADDR);

	    IF (.SCB_ADDR NEQ .LAST_SCB_ADDR)
	    THEN
		BEGIN
		PUTWRD (.KERNEL_FILE, .SCB_ADDR + .VALUES [S_LHD] + 2,
		    GETWRD (.KERNEL_FILE,
			.SCB_ADDR + .VALUES [S_LHD] + 2) - .XXDAT + .DCB_ADDR);
		PUTWRD (.KERNEL_FILE, .SCB_ADDR + .VALUES [S_FRK] + 8, .PAR_BASE/64);

		IF ((VECTOR = GETBYT (.KERNEL_FILE, .SCB_ADDR + .VALUES [S_VCT])^2) NEQ 0)
		THEN
		    BEGIN
		    OUTINT = -1;

		    IF ((INPINT = VRBL_SYM (.TASK_FILE, 2, UPLIT (%ASCIZ'$\\INT'), 1)) LEQ 0)
		    THEN
			BEGIN
			OUTINT = VRBL_SYM (.TASK_FILE, 2, UPLIT (%ASCIZ'$\\OUT'), 0);
			INPINT = VRBL_SYM (.TASK_FILE, 2, UPLIT (%ASCIZ'$\\INP'), 0);
			END;

		    IF (INPINT GTR 0)
		    THEN
			BEGIN
			LOC = ALOCB (.KERNEL_FILE, 28, 0, .VALUES);
!
! INPUT INTERRUPT VECTOR SETUP
!
			PUTWRD (.KERNEL_FILE, .VECTOR, .LOC);
			PUTWRD (.KERNEL_FILE, .VECTOR + 2, 7*32);
!
! NOW COMPILE INSTRUCTIONS, AS FOLLOWS:
!
!	JSR R5,$INTSV
!	.WORD PRIORITY
!	MOV @#KIASR5,-(SP)
!	MOV #BIAS,@#KIASR5
!	JSR PC,@#$??INP 	OR	JSR PC,@#$??INT
!	MOV (SP)+,@#KIASR5
!	RETURN
!
			PUTWRD (.KERNEL_FILE, .LOC, %O'4537');
			PUTWRD (.KERNEL_FILE, .LOC + 2, SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$INTSV'), 0));
			LOC = .LOC + 4;
			PUTWRD (.KERNEL_FILE, .LOC,
			    (GETBYT (.KERNEL_FILE, .SCB_ADDR + .VALUES [S_VCT] - 1) XOR %O'340'));
			LOC = .LOC + 2;
			PUTWRD (.KERNEL_FILE, .LOC, %O'13746');
			PUTWRD (.KERNEL_FILE, .LOC + 2, %O'172352');
			LOC = .LOC + 4;
			PUTWRD (.KERNEL_FILE, .LOC, %O'12737');
			PUTWRD (.KERNEL_FILE, .LOC + 2, GETWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_REL]));
			PUTWRD (.KERNEL_FILE, .LOC + 4, %O'172352');
			LOC = .LOC + 6;
			PUTWRD (.KERNEL_FILE, .LOC, %O'4737');
			PUTWRD (.KERNEL_FILE, .LOC + 2, .INPINT);
			LOC = .LOC + 4;
			PUTWRD (.KERNEL_FILE, .LOC, %O'12637');
			PUTWRD (.KERNEL_FILE, .LOC + 2, %O'172352');
			LOC = .LOC + 4;
			PUTWRD (.KERNEL_FILE, .LOC, %O'207');
			END;

		    IF (OUTINT GTR 0)
		    THEN
			BEGIN
			LOC = ALOCB (.KERNEL_FILE, 28, 0, .VALUES);
!
!  OUTPUT INTERRUPT VECTOR SETUP
!
			PUTWRD (.KERNEL_FILE, .VECTOR + 4, .LOC);
			PUTWRD (.KERNEL_FILE, .VECTOR + 6, 7*32);
!
! NOW COMPILE INSTRUCTIONS, AS FOLLOWS:
!
!	JSR R5,@#$INTSV
!	.WORD PRIORITY
!	MOV @#KIASR5,-(SP)
!	MOV #BIAS,@#KIASR5
!	JSR PC,@#$??OUT
!	MOV (SP)+,@#KIASR5
!	RETURN
!
			PUTWRD (.KERNEL_FILE, .LOC, %O'4537');
			PUTWRD (.KERNEL_FILE, .LOC + 2, SYM_VAL (.KERNEL_FILE, UPLIT (%ASCIZ'$INTSV'), 0));
			LOC = .LOC + 4;
			PUTWRD (.KERNEL_FILE, .LOC,
			    (GETBYT (.KERNEL_FILE, .SCB_ADDR + .VALUES [S_VCT] - 1) XOR %O'340'));
			LOC = .LOC + 2;
			PUTWRD (.KERNEL_FILE, .LOC, %O'13746');
			PUTWRD (.KERNEL_FILE, .LOC + 2, %O'172352');
			LOC = .LOC + 4;
			PUTWRD (.KERNEL_FILE, .LOC, %O'12737');
			PUTWRD (.KERNEL_FILE, .LOC + 2, GETWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_REL]));
			PUTWRD (.KERNEL_FILE, .LOC + 4, %O'172352');
			LOC = .LOC + 6;
			PUTWRD (.KERNEL_FILE, .LOC, %O'4737');
			PUTWRD (.KERNEL_FILE, .LOC + 2, .OUTINT);
			LOC = .LOC + 4;
			PUTWRD (.KERNEL_FILE, .LOC, %O'12637');
			PUTWRD (.KERNEL_FILE, .LOC + 2, %O'172352');
			LOC = .LOC + 4;
			PUTWRD (.KERNEL_FILE, .LOC, %O'207');
			END;

		    IF ((.INPINT LEQ 0) AND (.OUTINT LEQ 0))
		    THEN
			ERRMSG (0, 40, ROUTINE_NAME,
			    UPLIT (%ASCIZ'Interrupt Setup'), UPLIT (%ASCIZ'for driver in file'),
			    TASK_FILE [FILE_NAME], 0);

		    END;

		END;

	    END;

	DCB_ADDR = GETWRD (.KERNEL_FILE, .DCB_ADDR + .VALUES [D_LNK]);
	END;

!
! STORE IN THE TCB POINTER FIELD OF THE PCB, A POINTER TO
!  THE FIRST DCB.
!
    PUTWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_TCB], .FIRST_DCB_ADDR);
!
! COPY THE DRIVER CODE INTO THE PARTITION CREATED FOR IT
!

    INCR COUNTER FROM 0 TO .TASK_SIZE - 1 DO
	PUTBYT (.KERNEL_FILE, .PAR_BASE + .COUNTER, GETBYT (.TASK_FILE, .TASK_BASE + .COUNTER));

!
! LINK THE DCB INTO THE SYSTEM'S LIST OF DCBS
!
    LNKDCB (.KERNEL_FILE, .FIRST_DCB_ADDR, .VALUES);
    END;					!OF LOADD

GLOBAL ROUTINE LNKDCB (KERNEL_FILE, DCB_ADDR, VALUES) : NOVALUE = 	!LINK DCB INTO KERNEL

!++
! FUNCTIONAL DESCRIPTION:
!
!	LINK A DCB INTO THE KERNEL'S LIST OF DCBS.  IT IS PLACED
!	 IN ALPHABETICAL ORDER.
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - POINTER TO THE FILE BLOCK WHICH DESCRIBES THE
!	 RSX-11S KERNEL
!	DCB_ADDR - PDP-11 ADDRESS OF THE DCB TO BE LINKED
!	VALUES - POINTER TO THE VALUES BLOCK
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	MODIFIES THE KERNEL'S DATA STRUCTURES
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'LNKDCB');

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	PREV_DCB,
	NEXT_DCB,
	SEARCH_DONE;

!
! FIND THE TWO EXISTING DCBS WHICH THIS ONE MUST GO BETWEEN
!
    NEXT_DCB = GETWRD (.KERNEL_FILE, .VALUES [DEVHD]);
    PREV_DCB = 0;
    SEARCH_DONE = 0;

    WHILE (.SEARCH_DONE EQL 0) DO
	BEGIN

	IF (.NEXT_DCB EQL 0)
	THEN
	    SEARCH_DONE = 1
	ELSE
	    BEGIN

	    IF (GETWRD (.KERNEL_FILE, .NEXT_DCB + .VALUES [D_NAM]) GTRU GETWRD (.KERNEL_FILE,
		    .DCB_ADDR + .VALUES [D_NAM]))
	    THEN
		SEARCH_DONE = 1
	    ELSE
		BEGIN
		PREV_DCB = .NEXT_DCB;
		NEXT_DCB = GETWRD (.KERNEL_FILE, .PREV_DCB + .VALUES [D_LNK]);
		END;

	    END;

	END;

!
! WE NOW HAVE THE TWO DCBS.  IF PREV_DCB IS ZERO THIS DCB IS TO BE FIRST
!
    PUTWRD (.KERNEL_FILE, .DCB_ADDR + .VALUES [D_LNK], .NEXT_DCB);

    IF (.PREV_DCB EQL 0)
    THEN
	PUTWRD (.KERNEL_FILE, .VALUES [DEVHD], .DCB_ADDR)
    ELSE
	PUTWRD (.KERNEL_FILE,
	    .PREV_DCB + .VALUES [D_LNK], .DCB_ADDR);

    END;					!OF LNKDCB

GLOBAL ROUTINE VRBL_SYM (FILE_PTR, LEN, SYMBOL_NAME, ERR) = 	!GET VALUE OF SYMBOL WITH COMPUTED NAME

!++
! FUNCTIONAL DESCRIPTION:
!
!	GET THE VALUE OF A PARTIALLY NAMED SYMBOL.  PART OF THE NAME OF
!	 THE FILE MUST BE SUBSTITUTED INTO THE GIVEN NAME.
!
! FORMAL PARAMETERS:
!
!	FILE_PTR - THE FILE BLOCK THAT MAY HAVE THE SPECIFIED SYMBOL.
!	LEN - NUMBER OF CHARACTERS TO COPY FROM THE FILE NAME
!	SYMBOL_NAME - NAME OF THE SYMBOL, "\" STARTS PLACE TO
!	 SUBSTITUTE FILE NAME.
!	ERR - PASSED TO SYM_VAL.
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	VALUE OF THE SYMBOL, OR -1 IF UNDEFINED.
!
! SIDE EFFECTS
!
!	NONE
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'VRBL_SYM');

    MAP
	FILE_PTR : REF FILE_BLOCK;

    LOCAL
	CONVERTED_NAME : VECTOR [(CH$ALLOCATION (7))],
	BACKSL,
	RESULT;

    RESULT = -1;
!
! COPY THE SYMBOL NAME TO LOCAL STORAGE SO IT CAN BE MODIFIED
!
    CH$MOVE (7, CH$PTR (.SYMBOL_NAME), CH$PTR (CONVERTED_NAME [0]));
!
! FIND THE BACKSLASH
!
    BACKSL = -1;

    INCR C_POINTER FROM 0 TO 6 BY 1 DO

	IF (CH$RCHAR (CH$PTR (CONVERTED_NAME [0], .C_POINTER)) EQL %C'\')
	THEN
	    BEGIN
	    BACKSL = .C_POINTER;
	    EXITLOOP
	    END;

    IF (.BACKSL EQL -1)
    THEN
	ERROR (UPLIT (%ASCIZ'BACKSLASH MISSING - VRBL_SYM'))
    ELSE
	BEGIN
	CH$MOVE (.LEN, CH$PTR (FILE_PTR [FILE_NAME]), CH$PTR (CONVERTED_NAME [0], .BACKSL));
	RESULT = SYM_VAL (.FILE_PTR, CONVERTED_NAME [0], .ERR);
	END;

    .RESULT
    END;					!OF VRBL_SYM

GLOBAL ROUTINE FCLEAN (KERNEL_FILE, VALUES) : NOVALUE = 	!FINAL CLEANUP OF KERNEL

!++
! FUNCTIONAL DESCRIPTION:
!
!	DO FINAL CLEANUP OF THE KERNEL.  THIS ROUTINE IS CALLED
!	 AFTER THE LAST TASK HAS BEEN INSTALLED BUT BEFORE THE
!	 CORE IMAGE IS WRITTEN OUT.
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - FILE BLOCK FOR THE KERNEL
!	VALUES - BLOCK WHICH HOLDS VARIOUS USEFUL VALUES
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	MODIFIES THE KERNEL CORE IMAGE AND LABEL
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'FCLEAN');

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	KERNEL_LABEL : REF VECTOR [1024],
	KERNEL_SIZE,
	ROUNDED_SIZE;

!
! FETCH POINTERS AND COMPUTE THE SIZE OF THE KERNEL
!
    KERNEL_LABEL = .KERNEL_FILE [FILE_LABEL];
    KERNEL_SIZE = (.KERNEL_FILE [FILE_HWM] + 64) AND (NOT 63);
    ROUNDED_SIZE = (.KERNEL_FILE [FILE_HWM] + 512) AND (NOT 511);
!
! RETURN TO FREE POOL AMOUNT OF MEMORY UNUSED BY THIS SYSTEM
!
    FRESTG (.KERNEL_FILE [FILE_CORE] + (.ROUNDED_SIZE/4), (.KERNEL_FILE [FILE_CORE_LEN] - .ROUNDED_SIZE)/4);
    KERNEL_FILE [FILE_CORE_LEN] = .ROUNDED_SIZE;
!
! SET SYSTEM SIZE AND THE LABEL TO INDICATE THE NUMBER OF BYTES
!  IN THIS CORE IMAGE.
!
    PUTWRD (.KERNEL_FILE, .VALUES [SYSIZ], .ROUNDED_SIZE/64);
    KERNEL_LABEL [L$BLDZ] = (.ROUNDED_SIZE/64) MOD 256;
    KERNEL_LABEL [L$BLDZ + 1] = (.ROUNDED_SIZE/64)/256;
    KERNEL_LABEL [L$BMXZ] = (.ROUNDED_SIZE/64) MOD 256;
    KERNEL_LABEL [L$BMXZ + 1] = (.ROUNDED_SIZE/64)/256;
!
! Copy node name to kernel_file name
!
    CH$COPY (LEN_NODE_NAME, CH$PTR (VALUES [NODNAM]), 0, 7, CH$PTR (KERNEL_FILE [FILE_NAME]));
    END;					!OF FCLEAN

GLOBAL ROUTINE TELLK (KERNEL_FILE, TELL_CHAN, VALUES) : NOVALUE = 	!TELL ABOUT CORE IMAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!	TELL ABOUT THIS CORE IMAGE, AND CHANGE THE NAME OF THE KERNEL
!	 FILE TO BE THE NAME OF THE NODE BEING BUILT.  THE TYPEOUTS
!	 ARE FOR THE SAKE OF SOFTWARE SUPPORT ANALYZING A DUMP.
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - POINTER TO THE FILE BLOCK WHICH DESCRIBES
!	 THE KERNEL.
!	TELL_CHAN - THE CHANNEL NUMBER ON WHICH TO WRITE THE INFO.
!	VALUES - A VECTOR OF LOTS OF GOOD THINGS FOR VNP20
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	WRITES ON THE SPECIFIED CHANNEL
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'TELLK');

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	MAIN_PCB_ADDR,
	MAIN_SCAN_DONE,
	SUB_PCB_ADDR,
	SUB_SCAN_DONE,
	PCB_ADDR,
	KERNEL_SIZE,
	IMAGE_KW,
	MINIMUM_KW,
	SYSTEM_KW,
	CHAR;

    SYSTEM_KW = GETWRD (.KERNEL_FILE, .VALUES [SYSIZ])^6;

    IMAGE_KW = (.SYSTEM_KW + 2047)/2048;

    MINIMUM_KW = ((.SYSTEM_KW + .VALUES [COR]) + 2047)/2048;

    SYSTEM_KW = ((.SYSTEM_KW + ((.VALUES [COR]*180)/100)) + 2047)/2048;

    PCRLF (.TELL_CHAN);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ' Node name: '));
    OUTSTR (.TELL_CHAN, KERNEL_FILE [FILE_NAME]);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ', number: '));
    OUTNUM (.TELL_CHAN, .VALUES [NODNM], 10, 0);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ'.'));
    PCRLF (.TELL_CHAN);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ' The conjured system image is '));
    OUTNUM (.TELL_CHAN, .IMAGE_KW, 10, 0);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ'K words. Considering buffers,'));
    PCRLF (.TELL_CHAN);
    OUTPUT (.TELL_CHAN, %C' ');
    OUTNUM (.TELL_CHAN, .MINIMUM_KW, 10, 0);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ'K words of memory will be required during execution.'));
    PCRLF (.TELL_CHAN);

    IF .SYSTEM_KW GTR 124
    THEN
	BEGIN
	OUTPUT (.TELL_CHAN, %C' ');
	OUTNUM (.TELL_CHAN, .SYSTEM_KW, 10, 0);
	OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ'K words of memory is recommended for reasonable performance.'));
	PCRLF (.TELL_CHAN);
	END;

    PCRLF (.TELL_CHAN);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ' Partition   Base   Size   Task Name'));
    PCRLF (.TELL_CHAN);
    MAIN_PCB_ADDR = GETWRD (.KERNEL_FILE, .VALUES [PARHD]);
    MAIN_SCAN_DONE = 0;

    WHILE (.MAIN_SCAN_DONE EQL 0) DO

	IF (.MAIN_PCB_ADDR EQL 0)
	THEN
	    MAIN_SCAN_DONE = 1
	ELSE
	    BEGIN

	    IF (GETWRD (.KERNEL_FILE, .MAIN_PCB_ADDR + .VALUES [P_MAIN]) EQL .MAIN_PCB_ADDR)
	    THEN
		BEGIN
		TELLP (.KERNEL_FILE, .TELL_CHAN, .MAIN_PCB_ADDR, .VALUES);
		SUB_PCB_ADDR = GETWRD (.KERNEL_FILE, .MAIN_PCB_ADDR + .VALUES [P_SUB]);
		SUB_SCAN_DONE = 0;

		WHILE (.SUB_SCAN_DONE EQL 0) DO
		    BEGIN

		    IF (.SUB_PCB_ADDR EQL 0)
		    THEN
			SUB_SCAN_DONE = 1
		    ELSE
			BEGIN
			TELLP (.KERNEL_FILE, .TELL_CHAN, .SUB_PCB_ADDR, .VALUES);
			END;

		    SUB_PCB_ADDR = GETWRD (.KERNEL_FILE, .SUB_PCB_ADDR + .VALUES [P_SUB]);
		    END;

		END;

	    MAIN_PCB_ADDR = GETWRD (.KERNEL_FILE, .MAIN_PCB_ADDR + .VALUES [P_LNK]);
	    END;

    PCRLF (.TELL_CHAN);

    IF .MINIMUM_KW GTR 124
    THEN
	ERROR (UPLIT (%ASCIZ 'DN20 SYSTEM IS LARGER THAN 124K WORDS'));

    END;					!OF TELLK

ROUTINE TELLP (KERNEL_FILE, TELL_CHAN, PCB_ADDR, VALUES) : NOVALUE = 	!TELL ABOUT A PARTITION

!++
! FUNCTIONAL DESCRIPTION:
!
!	TELL ABOUT A PARTITION
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - POINTER TO THE FILE BLOCK WHICH DESCRIBES
!	 THE KERNEL.
!	TELL_CHAN - THE CHANNEL NUMBER ON WHICH TO WRITE THE INFO.
!	PCB_ADDR - PDP-11 ADDRESS OF THE PARTITION CONTROL BLOCK
!	VALUES - A VECTOR OF LOTS OF GOOD THINGS FOR VNP20
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	WRITES ON THE SPECIFIED CHANNEL
!
!--

    BEGIN

    BIND
	ROUTINE_NAME = UPLIT (%ASCIZ'TELLP');

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	R50VAL,
	ASCVAL : VECTOR [CH$ALLOCATION (7)],
	TCB_ADDR;

!
! FIRST TELL THE PARTITION NAME, THEN THE BASE ADDRESS AND SIZE,
!  LAST THE NAME OF THE TASK RESIDENT IN THE PARTITION.
!
    R50VAL = 0;
    R50VAL<16, 16> = GETWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_NAM]);
    R50VAL<0, 16> = GETWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_NAM] + 2);
    R50TOA (.R50VAL, ASCVAL);
    PCRLF (.TELL_CHAN);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ' '));
    OUTSTR (.TELL_CHAN, ASCVAL);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ'     '));
    OUTNUM (.TELL_CHAN, GETWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_REL])*64, 8, 7);
    OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ' '));
    OUTNUM (.TELL_CHAN, GETWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_SIZE])*64, 8, 7);
    TCB_ADDR = GETWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_TCB]);

    IF (.TCB_ADDR NEQ 0)
    THEN
	BEGIN

	IF ((GETWRD (.KERNEL_FILE, .PCB_ADDR + .VALUES [P_STAT]) AND .VALUES [PS_DRV]) EQL 0)
	THEN
	    BEGIN
	    R50VAL = 0;
	    R50VAL<16, 16> = GETWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_NAM]);
	    R50VAL<0, 16> = GETWRD (.KERNEL_FILE, .TCB_ADDR + .VALUES [T_NAM] + 2);
	    R50TOA (.R50VAL, ASCVAL);
	    END
	ELSE
	    BEGIN
	    ASCVAL = 0;
	    CH$WCHAR (GETBYT (.KERNEL_FILE, .TCB_ADDR + .VALUES [D_NAM]), CH$PTR (ASCVAL, 0));
	    CH$WCHAR (GETBYT (.KERNEL_FILE, .TCB_ADDR + .VALUES [D_NAM] + 1), CH$PTR (ASCVAL, 1));
	    CH$WCHAR (%C':', CH$PTR (ASCVAL, 2));
	    END;

	OUTSTR (.TELL_CHAN, UPLIT (%ASCIZ'  '));
	OUTSTR (.TELL_CHAN, ASCVAL);
	END;

    END;					!OF TELLP
END

ELUDOM
! Local Modes:
! Comment Column:36
! Comment Start:!
! Mode:Fundamental
! Auto Save Mode:2
! Word Abbrev Mode:1