Google
 

Trailing-Edge - PDP-10 Archives - BB-R595B-SM_11-9-85 - mcb/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) 1980, 1981, 1982
!                    DIGITAL EQUIPMENT CORPORATION
!                        Maynard, Massachusetts
!
!     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