Google
 

Trailing-Edge - PDP-10 Archives - BB-R595B-SM_11-9-85 - mcb/vnp36/mcbfnc.bli
There are 2 other files named mcbfnc.bli in the archive. Click here to see a list.
!NET:<DECNET20-V3P0.TKB-VNP.VNPV3>MCBFNC.BLI.162 13-Feb-81 14:16:19, Edit by SROBINSON
!NET:<DECNET20-V3P0.TKB-VNP.VNPV3>MCBFNC.BLI.160 10-Dec-80 11:50:07, Edit by SROBINSON
!<DECNET20-V3P0.TKB-VNP.VNPV3>MCBFNC.BLI.158, 26-Aug-80 13:12:53, Edit by SROBINSON
!<DECNET20-V3P0.TKB-VNP.VNPV3>MCBFNC.BLI.157, 25-Aug-80 14:44:48, Edit by SROBINSON
!<DECNET20-V3P0.TKB-VNP.VNPV3>MCBFNC.BLI.155, 21-Jul-80 07:47:31, Edit by SROBINSON
!<DECNET20-V3P0.TKB-VNP.VNPV3>MCBFNC.BLI.38,  3-Jul-80 09:28:27, Edit by SROBINSON
MODULE MCBFNC (					!MCB Related Functions
		IDENT = 'X03020'
		) =
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, VNP36
!
! ABSTRACT:
!
!	This module contains all routines associated with MCB process database
!	construction.
!
! ENVIRONMENT:	TOPS-20 or TOPS-10 User Mode
!
! AUTHOR: Scott G. Robinson , CREATION DATE: 14-Apr-80
!
! MODIFIED BY:
!
!	, : VERSION
! 01	- Change COMMLINK usage to LINE 
! 02	- Add CTL$DF parameters
!--

!
! TABLE OF CONTENTS
!

FORWARD ROUTINE
    LODMCB : NOVALUE,
    LLC_LOADS,
    DLC_LOADS : NOVALUE,
    DDM_LOADS : NOVALUE,
    BLOCK_LOAD : NOVALUE,
    GET_VARIABLE,
    NEXT_LIX,
    MCEX : NOVALUE,
    ALOC_POOL,
    LD_DCB;

!
! INCLUDE FILES:
!

LIBRARY 'VNPLIB';

!
! MACROS:
!
!	None
!
! EQUATED SYMBOLS:
!

LITERAL
    TRUE = 1 EQL 1,
    FALSE = 0 EQL 1,
    DEBUG = FALSE;

!
! OWN STORAGE:
!

OWN
!
! Variables used by BLOCK_LOAD
!
    CURBLK,					!Current Allocated Block Addr
    CURBAS,					!Current Block Base Address
    CURMAX,					!Current Maximum Address
    CURLIX,					!Current Line Index
    CURSLT : REF SLT_BLOCK,			!Pointer to Current SLT
    CURDEV : REF DEV_BLOCK,			!Pointer to Current DEV
    CURCTL : REF CTL_BLOCK,			!Pointer to Current CTL
    CURUNT : REF UNT_BLOCK,			!Pointer to Current UNT
    CURTRB : REF TRB_BLOCK;			!Pointer to Current TRB

!
! EXTERNAL REFERENCES:
!

EXTERNAL ROUTINE
    ALOCB,					!Allocate some Executive Storage
    DEACB,					!Deallocate some Executive Storage
    GETBLK,					!Allocate a 'typed' block
    FND_CHAIN,					!Search a Chain
    M_PCB,					!Build a Partition Control Block
    ERRMSG : NOVALUE,				!Write an error message
    ERROR : NOVALUE,				!Write a fatal error message
    GETWRD,					!Get a word of PDP-11 Memory
    PUTWRD : NOVALUE,				!Write into a word of PDP-11 Memory
    GETBYT,					!Get a byte of PDP-11 Memory
    PUTBYT : NOVALUE,				!Write into a byte of PDP-11 Memory
    OUTNUM : NOVALUE,				!Output a Number
    OUTPUT : NOVALUE,				!Output a Character
    OUTSTR : NOVALUE,				!Output a String
    R50TOA : NOVALUE,				!Conver R50 to ASCII
    PCRLF : NOVALUE,				!Output a CR/LF
    RCOR : NOVALUE,				!Read a task's image
    FCOR : NOVALUE,				!Free the memory used by RCOR
    RSTB : NOVALUE,				!Read a task's symbol table
    SYM_VAL,					!Return a symbols value
    LNKDCB : NOVALUE,				!Link a DCB into executive
    $CBOMG;					!Convert Binary to Octal ASCII
GLOBAL ROUTINE LODMCB (KERNEL_FILE, GEN_PCB, FILE_CHAN, VALUES) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Load MCB process's data bases according to system configuration
!
! FORMAL PARAMETERS
!
!	NONE.
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

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

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	PAR_BLK : VECTOR [4];			!Global Parameter Block

!
! Initialize Variables
!
    CURBLK = 0;					!Current Allocated Block Addr
    CURBAS = 0;					!Current Block Base Address
    CURMAX = 0;					!Current Maximum Address
    CURLIX = 0;					!Current Line Index
    CURSLT = 0;					!Pointer to Current SLT
    CURDEV = 0;					!Pointer to Current DEV
    CURCTL = 0;					!Pointer to Current CTL
    CURUNT = 0;					!Pointer to Current UNT
    CURTRB = 0;					!Pointer to Current TRB
!
    KERNEL_FILE [FILE_HWM] = (.KERNEL_FILE [FILE_HWM] + 1) AND ( NOT 1);
!
! Start by loading the LLC data bases
!
    PAR_BLK [0] = .GEN_PCB;
    PAR_BLK [1] = .KERNEL_FILE;
    PAR_BLK [2] = .VALUES;
    PAR_BLK [3] = .FILE_CHAN;
    FND_CHAIN (.VALUES [LLC_CHAIN], LLC_LOADS, PAR_BLK);
!
! Load the DLC data bases
!
    DLC_LOADS (.KERNEL_FILE, .FILE_CHAN, .VALUES);
!
! Load the DDM data bases
!
    DDM_LOADS (.KERNEL_FILE, .FILE_CHAN, .VALUES);
!
! We are done loading data base items, round up the high water mark
!  of the KERNEL so that the database partition size can be set
!  correctly.
!
    KERNEL_FILE [FILE_HWM] = ((.KERNEL_FILE [FILE_HWM] + 64) AND ( NOT 63)) - 1;
!
    END;					! of LODMCB
ROUTINE LLC_LOADS (LLC_PTR, PAR_BLK) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Load the LLC Data Bases for an MCB.
!
! FORMAL PARAMETERS
!
!	LLC_PTR = Pointer to LLC_BLOCK
!	PAR_VECTOR = Pointer to Parameter Vector
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
!
!	Always 0, so as to scan all LLC blocks
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

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

    MAP
	LLC_PTR : REF LLC_BLOCK,
	PAR_BLK : REF VECTOR;

    BIND
	GEN_PCB = PAR_BLK [0],
	KERNEL_FILE = PAR_BLK [1] : REF FILE_BLOCK,
	VALUES = PAR_BLK [2] : REF VNPVAL_BLOCK,
	FILE_CHAN = PAR_BLK [3];

    LOCAL
	CB_ADDRESS,
	DB_FILE : REF FILE_BLOCK,
	DB_POINTER,
	LB_POINTER,
	MCB_NAME : VECTOR [CH$ALLOCATION (7)],
	MODU_PTR : REF MODU_BLOCK,
	PRIMARY_COMMAND,
	XXXNAME : VECTOR [CH$ALLOCATION (7)];

!
! Tell someone what we are doing
!
    OUTSTR (0, UPLIT (%ASCIZ'[Loading LLC Data Base for '));
    OUTSTR (0, LLC_PTR [LLC_NAME]);
!
! Get data base file
!

    IF ((DB_FILE = GETBLK (FILE_TYP, FILE_LEN)) EQL 0)
    THEN
	ERRMSG (0, 1, ROUTINE_NAME, 0, 0, 0, 0)
    ELSE
	BEGIN
!
! Build xxxLLC file name
!
	CH$MOVE (LEN_MCB_NAME, CH$PTR (LLC_PTR [LLC_NAME]), CH$PTR (DB_FILE [FILE_NAME]));
	CH$MOVE (3, CH$PTR (UPLIT (%ASCIZ'LLC')),
	    CH$FIND_CH (LEN_FILE_STRING, CH$PTR (DB_FILE [FILE_NAME]),
		0));
	RSTB (.FILE_CHAN, .DB_FILE);
	RCOR (.DB_FILE, .FILE_CHAN, 8*2048);
!
! Printout Identification Information
!
	R50TOA (GETWRD (.DB_FILE, 0), MCB_NAME);
	CH$MOVE (4, CH$PTR (MCB_NAME, 3), CH$PTR (MCB_NAME));
	OUTSTR (0, UPLIT (%ASCIZ' ('));
	OUTSTR (0, MCB_NAME);
	OUTPUT (0, %C' ');
	OUTNUM (0, GETBYT (.DB_FILE, 2), 10, 0);
	OUTPUT (0, %C'.');
	OUTNUM (0, GETBYT (.DB_FILE, 3), 10, 0);
	OUTSTR (0, UPLIT (%ASCIZ') --> '));
!
! Process Primary Load Block Command
!
	DB_POINTER = 4;
	PRIMARY_COMMAND = GETBYT (.DB_FILE, .DB_POINTER);

	SELECTONE .PRIMARY_COMMAND OF
	    SET

	    [CMD_ALLOC_DB_DSR] :
		CURBLK = ALOCB (.KERNEL_FILE, GETWRD (.DB_FILE, .DB_POINTER + 2), 0, .VALUES);

	    [CMD_ALLOC_DB_POOL] :
		CURBLK = ALOC_POOL (.KERNEL_FILE, GETWRD (.DB_FILE, .DB_POINTER + 2), 0, .VALUES);

	    [OTHERWISE] :
	    ;
	    TES;

	CURBAS = (.CURBLK AND ( NOT 63));
	CURMAX = .CURBLK + GETWRD (.DB_FILE, .DB_POINTER + 2);
!
! Process the Load Block associated with this Primary Request
!
	LB_POINTER = GETWRD (.DB_FILE, .DB_POINTER + 4);
	BLOCK_LOAD (.KERNEL_FILE, .DB_FILE, .LB_POINTER, .VALUES);
!
! Store data base address in LLCxxx
!
	CH$COPY (3, CH$PTR (UPLIT (%ASCIZ'LLC')), LEN_MCB_NAME, CH$PTR (LLC_PTR [LLC_NAME]), 0, 7,
	    CH$PTR (XXXNAME));
	CB_ADDRESS = .VALUES [CE_DATA_BASE] + SYM_VAL (.VALUES [CE_DATA_FILE], XXXNAME, 0);
	PUTWRD (.KERNEL_FILE, .CB_ADDRESS, (IF (.CURBLK GEQ %O'120000') THEN .CURBAS<6, 12, 0> ELSE 0));
	PUTWRD (.KERNEL_FILE, .CB_ADDRESS + 2,
	    (IF (.CURBLK GEQ %O'120000') THEN ((.CURBLK - .CURBAS) + %O'140000') ELSE .CURBLK));
!
! Printout Task information
!
	MODU_PTR = .DB_FILE [FILE_MODU];
	OUTSTR (0, MODU_PTR [MODU_NAME]);
	OUTPUT (0, %C' ');
	OUTSTR (0, MODU_PTR [MODU_IDENT]);
	OUTSTR (0, UPLIT (%ASCIZ' ]'));
	PCRLF (0);
	FCOR (.DB_FILE);
	END;

    0
    END;					! of LLC_LOADS
ROUTINE DLC_LOADS (KERNEL_FILE, FILE_CHAN, VALUES) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Load DLC Process Data Bases for each SLT in the MCB.
!
! FORMAL PARAMETERS
!
!	KERNEL_FILE - System Image File Descriptor
!	FILE_CHAN   - Channel to use for I/O
!	VALUES      - Misc Data Items
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

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

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	CB_ADDRESS,
	CTL_LENGTH,
	DB_FILE : REF FILE_BLOCK,
	DB_POINTER,
	DB_VARIABLE_1,
	DB_VARIABLE_2,
	LB_POINTER,
	MCB_NAME : VECTOR [CH$ALLOCATION (7)],
	MODU_PTR : REF MODU_BLOCK,
	PRIMARY_COMMAND,
	TEMPORARY_PTR,
	UNT_LENGTH,
	XXXNAME : VECTOR [CH$ALLOCATION (7)];

!
! Start by initializing some of the data items
!
    CURLIX = 0;
    CURSLT = 0;
    CURCTL = 0;
    NEXT_LIX (VAR_CURRENT_CTL, .VALUES);
!

    IF (.CURSLT NEQ 0)
    THEN

	DO

	    IF (.CURSLT [SLT_DLC] NEQ 0)
	    THEN
		BEGIN
!
! Tell someone what we are doing
!
		OUTSTR (0, UPLIT (%ASCIZ'[Loading '));
		OUTSTR (0, CURSLT [SLT_DLC]);
		OUTSTR (0, UPLIT (%ASCIZ' data base for LINE '));
		OUTSTR (0, (IF (.CURSLT [SLT_DEV] NEQ 0) THEN CURSLT [SLT_DEV] ELSE CURSLT [SLT_DLC]));
		OUTPUT (0, %C'-');
		OUTNUM (0, .CURSLT [SLT_CTL], 10, 0);
		OUTPUT (0, %C'-');
		OUTNUM (0, .CURSLT [SLT_UNT], 10, 0);
!
! Get data base file
!

		IF ((DB_FILE = GETBLK (FILE_TYP, FILE_LEN)) EQL 0)
		THEN
		    ERRMSG (0, 1, ROUTINE_NAME, 0, 0, 0,
			0)
		ELSE
		    BEGIN
!
! Build xxxDLC file name
!
		    CH$MOVE (LEN_MCB_NAME, CH$PTR (CURSLT [SLT_DLC]), CH$PTR (DB_FILE [FILE_NAME]));
		    CH$MOVE (3, CH$PTR (UPLIT (%ASCIZ'DLC')),
			CH$FIND_CH (LEN_FILE_STRING,
			    CH$PTR (DB_FILE [FILE_NAME]), 0));
		    RSTB (.FILE_CHAN, .DB_FILE);
		    RCOR (.DB_FILE, .FILE_CHAN, 4*2048);
!
! Printout Identification Information
!
		    R50TOA (GETWRD (.DB_FILE, 0), MCB_NAME);
		    CH$MOVE (4, CH$PTR (MCB_NAME, 3), CH$PTR (MCB_NAME));
		    OUTSTR (0, UPLIT (%ASCIZ' ('));
		    OUTSTR (0, MCB_NAME);
		    OUTPUT (0, %C' ');
		    OUTNUM (0, GETBYT (.DB_FILE, 2), 10, 0);
		    OUTPUT (0, %C'.');
		    OUTNUM (0, GETBYT (.DB_FILE, 3), 10, 0);
		    OUTSTR (0, UPLIT (%ASCIZ') --> '));
!
! Process Primary Load Block Command
!
		    DB_POINTER = 4;
		    PRIMARY_COMMAND = GETBYT (.DB_FILE, .DB_POINTER);
		    DB_VARIABLE_1 = GETBYT (.DB_FILE, .DB_POINTER + 1);
		    DB_VARIABLE_2 = 0;

		    SELECTONE .PRIMARY_COMMAND OF
			SET

			[CMD_ALLOC_DB_DSR, CMD_ALLOC_DB_POOL] :
			    BEGIN
			    CURBLK = (IF (.PRIMARY_COMMAND EQL CMD_ALLOC_DB_DSR) THEN ALOCB (.KERNEL_FILE,
				    GETWRD (.DB_FILE, .DB_POINTER + 2), 0, .VALUES) ELSE ALOC_POOL (
				    .KERNEL_FILE, GETWRD (.DB_FILE, .DB_POINTER + 2), 0, .VALUES));
			    CURBAS = (.CURBLK AND ( NOT 63));
			    CURMAX = .CURBLK + GETWRD (.DB_FILE, .DB_POINTER + 2);
!
! Process the Load Block associated with this Primary Request
!
			    LB_POINTER = GETWRD (.DB_FILE, .DB_POINTER + 4);
			    BLOCK_LOAD (.KERNEL_FILE, .DB_FILE, .LB_POINTER, .VALUES);
!
! Store data base address in DLCnnn
!

			    DO
				BEGIN
				CH$MOVE (3, CH$PTR (UPLIT (%ASCIZ'DLC')), CH$PTR (XXXNAME));
				TEMPORARY_PTR = CH$PTR (XXXNAME, 3);
				$CBOMG (TEMPORARY_PTR, .CURLIX, 0);
				CH$WCHAR (0, .TEMPORARY_PTR);
				CB_ADDRESS = .VALUES [CE_DATA_BASE] + SYM_VAL (.VALUES [CE_DATA_FILE],
				    XXXNAME, 0);
				PUTWRD (.KERNEL_FILE, .CB_ADDRESS,
				    (IF (.CURBLK GEQ %O'120000') THEN .CURBAS<6, 12, 0> ELSE 0));
				PUTWRD (.KERNEL_FILE, .CB_ADDRESS + 2,
				    (IF (.CURBLK GEQ %O'120000') THEN ((.CURBLK - .CURBAS) + %O'140000') ELSE
					.CURBLK));
				END
			    UNTIL NEXT_LIX (.DB_VARIABLE_1, .VALUES);

			    END;

			[CMD_ALLOC_MUX_DSR, CMD_ALLOC_MUX_POOL] :
			    BEGIN
			    DB_VARIABLE_2 = GETBYT (.DB_FILE, .DB_POINTER + 2);
			    CTL_LENGTH = GETWRD (.DB_FILE, .DB_POINTER + 4);
			    UNT_LENGTH = GETWRD (.DB_FILE, .DB_POINTER + 8);
			    CURMAX = .CTL_LENGTH + (GET_VARIABLE (.DB_VARIABLE_2, .VALUES)*.UNT_LENGTH);
			    CURBLK = (IF (.PRIMARY_COMMAND EQL CMD_ALLOC_MUX_DSR) THEN ALOCB (.KERNEL_FILE,
				    .CURMAX, 0, .VALUES) ELSE ALOC_POOL (.KERNEL_FILE, .CURMAX, 0, .VALUES));
			    CURBAS = (.CURBLK AND ( NOT 63));
			    CURMAX = .CURMAX + .CURBLK;
!
! Load the Controller block
!
			    LB_POINTER = GETWRD (.DB_FILE, .DB_POINTER + 6);
			    BLOCK_LOAD (.KERNEL_FILE, .DB_FILE, .LB_POINTER, .VALUES);
!
! Load each unit's block
!
			    CURBLK = .CURBLK + .CTL_LENGTH;
			    LB_POINTER = GETWRD (.DB_FILE, .DB_POINTER + 10);

			    DECR DUMMY FROM GET_VARIABLE (.DB_VARIABLE_2, .VALUES) TO 1 DO
				BEGIN
				BLOCK_LOAD (.KERNEL_FILE, .DB_FILE, .LB_POINTER, .VALUES);
!
! Plug Addresses into Data Structures
!

				DO
				    BEGIN
				    CH$MOVE (3, CH$PTR (UPLIT (%ASCIZ'DLC')), CH$PTR (XXXNAME));
				    TEMPORARY_PTR = CH$PTR (XXXNAME, 3);
				    $CBOMG (TEMPORARY_PTR, .CURLIX, 0);
				    CH$WCHAR (0, .TEMPORARY_PTR);
				    CB_ADDRESS = .VALUES [CE_DATA_BASE] + SYM_VAL (.VALUES [CE_DATA_FILE],
					XXXNAME, 0);
				    PUTWRD (.KERNEL_FILE, .CB_ADDRESS,
					(IF (.CURBLK GEQ %O'120000') THEN .CURBAS<6, 12, 0> ELSE 0));
				    PUTWRD (.KERNEL_FILE, .CB_ADDRESS + 2,
					(IF (.CURBLK GEQ %O'120000') THEN ((.CURBLK - .CURBAS) + %O'140000')
					ELSE .CURBLK));
				    END
				UNTIL NEXT_LIX (.DB_VARIABLE_1, .VALUES);

				CURBLK = .CURBLK + .UNT_LENGTH;
				END;

			    END;

			[OTHERWISE] :
			;
			TES;

!
! Printout Task information
!
		    MODU_PTR = .DB_FILE [FILE_MODU];
		    OUTSTR (0, MODU_PTR [MODU_NAME]);
		    OUTPUT (0, %C' ');
		    OUTSTR (0, MODU_PTR [MODU_IDENT]);
		    OUTSTR (0, UPLIT (%ASCIZ' ]'));
		    PCRLF (0);
		    FCOR (.DB_FILE);
		    END;

		END
	    ELSE
		NEXT_LIX (VAR_CURRENT_CTL, .VALUES)

	WHILE (.CURLIX LEQ .VALUES [SLTNUM]);

    END;					! of DLC_LOADS
ROUTINE DDM_LOADS (KERNEL_FILE, FILE_CHAN, VALUES) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Load DDM Process Data Bases for each SLT in the MCB.
!
! FORMAL PARAMETERS
!
!	KERNEL_FILE - System Image File Descriptor
!	FILE_CHAN   - Channel to use for I/O
!	VALUES      - Misc Data Items
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

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

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	CB_ADDRESS,
	CTL_LENGTH,
	DB_FILE : REF FILE_BLOCK,
	DB_POINTER,
	DB_VARIABLE_1,
	DB_VARIABLE_2,
	LB_POINTER,
	MCB_NAME : VECTOR [CH$ALLOCATION (7)],
	MODU_PTR : REF MODU_BLOCK,
	PRIMARY_COMMAND,
	TEMPORARY_PTR,
	UNT_LENGTH,
	XXXNAME : VECTOR [CH$ALLOCATION (7)];

!
! Start by initializing some of the data items
!
    CURLIX = 0;
    CURSLT = 0;
    CURCTL = 0;
    NEXT_LIX (VAR_CURRENT_CTL, .VALUES);
!

    IF (.CURSLT NEQ 0)
    THEN

	DO

	    IF (.CURSLT [SLT_DEV] NEQ 0)
	    THEN
		BEGIN
!
! Tell someone what we are doing
!
		OUTSTR (0, UPLIT (%ASCIZ'[Loading data base for LINE '));
		OUTSTR (0, CURSLT [SLT_DEV]);
		OUTPUT (0, %C'-');
		OUTNUM (0, .CURSLT [SLT_CTL], 10, 0);
		OUTPUT (0, %C'-');
		OUTNUM (0, .CURSLT [SLT_UNT], 10, 0);
!
! Get data base file
!

		IF ((DB_FILE = GETBLK (FILE_TYP, FILE_LEN)) EQL 0)
		THEN
		    ERRMSG (0, 1, ROUTINE_NAME, 0, 0, 0,
			0)
		ELSE
		    BEGIN
!
! Build xxxDDM file name
!
		    CH$MOVE (LEN_MCB_NAME, CH$PTR (CURSLT [SLT_DEV]), CH$PTR (DB_FILE [FILE_NAME]));
		    CH$MOVE (3, CH$PTR (UPLIT (%ASCIZ'DDM')),
			CH$FIND_CH (LEN_FILE_STRING,
			    CH$PTR (DB_FILE [FILE_NAME]), 0));
		    RSTB (.FILE_CHAN, .DB_FILE);
		    RCOR (.DB_FILE, .FILE_CHAN, 4*2048);
!
! Printout Identification Information
!
		    R50TOA (GETWRD (.DB_FILE, 0), MCB_NAME);
		    CH$MOVE (4, CH$PTR (MCB_NAME, 3), CH$PTR (MCB_NAME));
		    OUTSTR (0, UPLIT (%ASCIZ' ('));
		    OUTSTR (0, MCB_NAME);
		    OUTPUT (0, %C' ');
		    OUTNUM (0, GETBYT (.DB_FILE, 2), 10, 0);
		    OUTPUT (0, %C'.');
		    OUTNUM (0, GETBYT (.DB_FILE, 3), 10, 0);
		    OUTSTR (0, UPLIT (%ASCIZ') --> '));
!
! Process Primary Load Block Command
!
		    DB_POINTER = 4;
		    PRIMARY_COMMAND = GETBYT (.DB_FILE, .DB_POINTER);
		    DB_VARIABLE_1 = GETBYT (.DB_FILE, .DB_POINTER + 1);
		    DB_VARIABLE_2 = 0;

		    SELECTONE .PRIMARY_COMMAND OF
			SET

			[CMD_ALLOC_DB_DSR, CMD_ALLOC_DB_POOL] :
			    BEGIN
			    CURBLK = (IF (.PRIMARY_COMMAND EQL CMD_ALLOC_DB_DSR) THEN ALOCB (.KERNEL_FILE,
				    GETWRD (.DB_FILE, .DB_POINTER + 2), 0, .VALUES) ELSE ALOC_POOL (
				    .KERNEL_FILE, GETWRD (.DB_FILE, .DB_POINTER + 2), 0, .VALUES));
			    CURBAS = (.CURBLK AND ( NOT 63));
			    CURMAX = .CURBLK + GETWRD (.DB_FILE, .DB_POINTER + 2);
!
! Process the Load Block associated with this Primary Request
!
			    LB_POINTER = GETWRD (.DB_FILE, .DB_POINTER + 4);
			    BLOCK_LOAD (.KERNEL_FILE, .DB_FILE, .LB_POINTER, .VALUES);
!
! Store data base address in DDMnnn
!

			    DO
				BEGIN
				CH$MOVE (3, CH$PTR (UPLIT (%ASCIZ'DDM')), CH$PTR (XXXNAME));
				TEMPORARY_PTR = CH$PTR (XXXNAME, 3);
				$CBOMG (TEMPORARY_PTR, .CURLIX, 0);
				CH$WCHAR (0, .TEMPORARY_PTR);
				CB_ADDRESS = .VALUES [CE_DATA_BASE] + SYM_VAL (.VALUES [CE_DATA_FILE],
				    XXXNAME, 0);
				PUTWRD (.KERNEL_FILE, .CB_ADDRESS,
				    (IF (.CURBLK GEQ %O'120000') THEN .CURBAS<6, 12, 0> ELSE 0));
				PUTWRD (.KERNEL_FILE, .CB_ADDRESS + 2,
				    (IF (.CURBLK GEQ %O'120000') THEN ((.CURBLK - .CURBAS) + %O'140000') ELSE
					.CURBLK));
				END
			    UNTIL NEXT_LIX (.DB_VARIABLE_1, .VALUES);

			    END;

			[CMD_ALLOC_MUX_DSR, CMD_ALLOC_MUX_POOL] :
			    BEGIN
			    DB_VARIABLE_2 = GETBYT (.DB_FILE, .DB_POINTER + 2);
			    CTL_LENGTH = GETWRD (.DB_FILE, .DB_POINTER + 4);
			    UNT_LENGTH = GETWRD (.DB_FILE, .DB_POINTER + 8);
			    CURMAX = .CTL_LENGTH + (GET_VARIABLE (.DB_VARIABLE_2, .VALUES)*.UNT_LENGTH);
			    CURBLK = (IF (.PRIMARY_COMMAND EQL CMD_ALLOC_MUX_DSR) THEN ALOCB (.KERNEL_FILE,
				    .CURMAX, 0, .VALUES) ELSE ALOC_POOL (.KERNEL_FILE, .CURMAX, 0, .VALUES));
			    CURBAS = (.CURBLK AND ( NOT 63));
			    CURMAX = .CURMAX + .CURBLK;
!
! Load the Controller block
!
			    LB_POINTER = GETWRD (.DB_FILE, .DB_POINTER + 6);
			    BLOCK_LOAD (.KERNEL_FILE, .DB_FILE, .LB_POINTER, .VALUES);
!
! Load each unit's block
!
			    CURBLK = .CURBLK + .CTL_LENGTH;
			    LB_POINTER = GETWRD (.DB_FILE, .DB_POINTER + 10);

			    DECR DUMMY FROM GET_VARIABLE (.DB_VARIABLE_2, .VALUES) TO 1 DO
				BEGIN
				BLOCK_LOAD (.KERNEL_FILE, .DB_FILE, .LB_POINTER, .VALUES);
!
! Plug Addresses into Data Structures
!

				DO
				    BEGIN
				    CH$MOVE (3, CH$PTR (UPLIT (%ASCIZ'DDM')), CH$PTR (XXXNAME));
				    TEMPORARY_PTR = CH$PTR (XXXNAME, 3);
				    $CBOMG (TEMPORARY_PTR, .CURLIX, 0);
				    CH$WCHAR (0, .TEMPORARY_PTR);
				    CB_ADDRESS = .VALUES [CE_DATA_BASE] + SYM_VAL (.VALUES [CE_DATA_FILE],
					XXXNAME, 0);
				    PUTWRD (.KERNEL_FILE, .CB_ADDRESS,
					(IF (.CURBLK GEQ %O'120000') THEN .CURBAS<6, 12, 0> ELSE 0));
				    PUTWRD (.KERNEL_FILE, .CB_ADDRESS + 2,
					(IF (.CURBLK GEQ %O'120000') THEN ((.CURBLK - .CURBAS) + %O'140000')
					ELSE .CURBLK));
				    END
				UNTIL NEXT_LIX (.DB_VARIABLE_1, .VALUES);

				CURBLK = .CURBLK + .UNT_LENGTH;
				END;

			    END;

			[OTHERWISE] :
			;
			TES;

!
! Printout Task information
!
		    MODU_PTR = .DB_FILE [FILE_MODU];
		    OUTSTR (0, MODU_PTR [MODU_NAME]);
		    OUTPUT (0, %C' ');
		    OUTSTR (0, MODU_PTR [MODU_IDENT]);
		    OUTSTR (0, UPLIT (%ASCIZ' ]'));
		    PCRLF (0);
		    FCOR (.DB_FILE);
		    END;

		END
	    ELSE
		NEXT_LIX (VAR_CURRENT_CTL, .VALUES)

	WHILE (.CURLIX LEQ .VALUES [SLTNUM]);

    END;					! of DDM_LOADS
ROUTINE BLOCK_LOAD (KERNEL_FILE, DB_FILE, LB_POINTER, VALUES) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Process Data Base Load Blocks actually constructing the data base
!	in the Kernel_File.
!
! FORMAL PARAMETERS
!
!	KERNEL_FILE - RSX Kernel File
!	DB_FILE - Process Data Base File
!	LB_POINTER - Pointer to Load Block in DB_FILE
!	VALUES - Misc. Important Locations for VNP
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	Can call itself recursively!
!
!--

    BEGIN

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

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

    LOCAL
	CB_ADDRESS,				!Physical Address of current memory block
	CB_LENGTH,
	CB_SAVE_BASE,				!Save location for Current Block Base
	CB_SAVE_MAX,				!Save location for Maximum Extent of block
	CB_SAVE,				!Save location for current block pointer
	LB_ADDRESS,
	LB_COMMAND,				!Current command
	LB_LENGTH,
	LB_PC,					!Pointer to current command word
	LB_VARIABLE,				!Current Variable from command
	FATAL_ERROR;				!Aborts processing on error

!
! Initialize processing loop
!
    FATAL_ERROR = FALSE;
    LB_PC = .LB_POINTER;
    CB_SAVE = .CURBLK;
    CB_SAVE_BASE = .CURBAS;
    CB_SAVE_MAX = .CURMAX;

    DO						! Main Processing Loop
	BEGIN
	LB_COMMAND = GETBYT (.DB_FILE, .LB_PC);
	LB_VARIABLE = GETBYT (.DB_FILE, .LB_PC + 1);
	LB_PC = .LB_PC + 2;

	IF DEBUG
	THEN
	    BEGIN
	    PCRLF (0);
	    OUTSTR (0, UPLIT (%ASCIZ'Command, Variable # = '));
	    OUTNUM (0, .LB_COMMAND, 8, 0);
	    OUTPUT (0, %C',');
	    OUTNUM (0, .LB_VARIABLE, 8, 0);
	    END;

	SELECTONE .LB_COMMAND OF
	    SET

	    [CMD_END] :
	    ;

	    [CMD_MOVE_WORD] :
		BEGIN
		CB_ADDRESS = .CURBLK + GETWRD (.DB_FILE, .LB_PC);
		PUTWRD (.KERNEL_FILE, .CB_ADDRESS, GET_VARIABLE (.LB_VARIABLE, .VALUES));
		LB_PC = .LB_PC + 2;
		END;

	    [CMD_MOVE_BYTE] :
		BEGIN
		CB_ADDRESS = .CURBLK + GETWRD (.DB_FILE, .LB_PC);
		PUTBYT (.KERNEL_FILE, .CB_ADDRESS, GET_VARIABLE (.LB_VARIABLE, .VALUES));
		LB_PC = .LB_PC + 2;
		END;

	    [CMD_ADD_WORD] :
		BEGIN
		CB_ADDRESS = .CURBLK + GETWRD (.DB_FILE, .LB_PC);
		PUTWRD (.KERNEL_FILE, .CB_ADDRESS,
		    GETWRD (.KERNEL_FILE, .CB_ADDRESS) + GET_VARIABLE (.LB_VARIABLE, .VALUES));
		LB_PC = .LB_PC + 2;
		END;

	    [CMD_ADD_BYTE] :
		BEGIN
		CB_ADDRESS = .CURBLK + GETWRD (.DB_FILE, .LB_PC);
		PUTBYT (.KERNEL_FILE, .CB_ADDRESS,
		    GETBYT (.KERNEL_FILE, .CB_ADDRESS) + GET_VARIABLE (.LB_VARIABLE, .VALUES));
		LB_PC = .LB_PC + 2;
		END;

	    [CMD_MOVE_TEXT] :
		BEGIN
		CB_ADDRESS = .CURBLK + GETWRD (.DB_FILE, .LB_PC);
		LB_LENGTH = GETWRD (.DB_FILE, .LB_PC + 2);
		LB_ADDRESS = GETWRD (.DB_FILE, .LB_PC + 4);

		IF ((.CB_ADDRESS + .LB_LENGTH) GTR .CURMAX)
		THEN
		    ERRMSG (0, 25, ROUTINE_NAME,
			.CB_ADDRESS + .LB_LENGTH, DB_FILE [FILE_NAME], 0, 0);

		IF (.LB_LENGTH GTR 0)
		THEN

		    INCR BYTE_NUMBER FROM 0 TO .LB_LENGTH - 1 DO
			PUTBYT (.KERNEL_FILE, .CB_ADDRESS + .BYTE_NUMBER,
			    GETBYT (.DB_FILE,
				.LB_ADDRESS + .BYTE_NUMBER));

		LB_PC = .LB_PC + 6;
		END;

	    [CMD_VERIFY_VALUES] :
		BEGIN

		IF (GETWRD (.DB_FILE, .LB_PC) NEQU GETWRD (.DB_FILE, .LB_PC + 2))
		THEN
		    BEGIN
		    PCRLF (0);
		    OUTSTR (0, UPLIT (%ASCIZ'? Database Verification Error, Value 1='));
		    OUTNUM (0, GETWRD (.DB_FILE, .LB_PC), 8, 0);
		    OUTSTR (0, UPLIT (%ASCIZ', Value 2 ='));
		    OUTNUM (0, GETWRD (.DB_FILE, .LB_PC + 2), 8, 0);
		    FATAL_ERROR = TRUE;
		    END;

		LB_PC = .LB_PC + 4;
		END;

	    [CMD_ALLOC_DSR] :
		BEGIN
		CB_LENGTH = GETWRD (.DB_FILE, .LB_PC + 2);
		CB_ADDRESS = ALOCB (.KERNEL_FILE, .CB_LENGTH, 0, .VALUES);
		PUTWRD (.KERNEL_FILE, .CURBLK + GETWRD (.DB_FILE, .LB_PC), .CB_ADDRESS);
		CURMAX = .CB_ADDRESS + .CB_LENGTH;
		CURBLK = .CB_ADDRESS;
		CURBAS = (.CURBLK AND ( NOT 63));

		IF ((LB_ADDRESS = GETWRD (.DB_FILE, .LB_PC + 4)) NEQ 0)
		THEN
		    BLOCK_LOAD (.KERNEL_FILE,
			.DB_FILE, .LB_ADDRESS, .VALUES);

		CURBLK = .CB_SAVE;
		CURBAS = .CB_SAVE_BASE;
		CURMAX = .CB_SAVE_MAX;
		LB_PC = .LB_PC + 6;
		END;

	    [CMD_ALLOC_POOL] :
		BEGIN
		CB_LENGTH = GETWRD (.DB_FILE, .LB_PC + 2);
		CB_ADDRESS = ALOC_POOL (.KERNEL_FILE, .CB_LENGTH, 0, .VALUES);
		PUTWRD (.KERNEL_FILE, .CURBLK + GETWRD (.DB_FILE, .LB_PC), .CB_ADDRESS<6, 12, 0>);
		PUTWRD (.KERNEL_FILE, .CURBLK + GETWRD (.DB_FILE, .LB_PC) + 2,
		    ((.CB_ADDRESS AND 63) + %O'140000'));
		CURMAX = .CB_ADDRESS + .CB_LENGTH;
		CURBLK = .CB_ADDRESS;
		CURBAS = (.CURBLK AND ( NOT 63));

		IF ((LB_ADDRESS = GETWRD (.DB_FILE, .LB_PC + 4)) NEQ 0)
		THEN
		    BLOCK_LOAD (.KERNEL_FILE,
			.DB_FILE, .LB_ADDRESS, .VALUES);

		CURBLK = .CB_SAVE;
		CURBAS = .CB_SAVE_BASE;
		CURMAX = .CB_SAVE_MAX;
		LB_PC = .LB_PC + 6;
		END;

	    [OTHERWISE] :
		FATAL_ERROR = TRUE;
	    TES;

	END
    UNTIL ((.LB_COMMAND EQL CMD_END) OR .FATAL_ERROR);

    IF (.FATAL_ERROR) THEN ERROR (UPLIT (%ASCIZ'Fatal Database Format Error -- BLOCK_LOAD'));

    END;					! of BLOCK_LOAD
ROUTINE GET_VARIABLE (VAR_NUMBER, VALUES) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Return the value of a Load Block Variable
!	to the caller.
!
! FORMAL PARAMETERS
!
!	VAR_NUMBER - the variable number to return
!	VALUES - Misc info maintained by VNP
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
!
!	The variable's contents or 0.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

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

    MAP
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	RESULT;

    RESULT = 0;

    SELECTONE .VAR_NUMBER OF
	SET

	[VAR_CURRENT_ADDRESS] :

	    IF (.CURBLK LSS %O'120000') THEN RESULT = .CURBLK ELSE RESULT = (.CURBLK - .CURBAS) + %O'140000';

	[VAR_CURRENT_LIX] :
	    RESULT = .CURLIX;

	[VAR_CURRENT_CTL] :

	    IF .CURSLT NEQ 0 THEN RESULT = .CURSLT [SLT_CTL];

	[VAR_CURRENT_UNT] :

	    IF .CURSLT NEQ 0 THEN RESULT = .CURSLT [SLT_UNT];

	[VAR_CURRENT_TRB] :

	    IF .CURSLT NEQ 0 THEN RESULT = .CURSLT [SLT_TRB];

	[VAR_NUMBER_SLTS] :
	    RESULT = .VALUES [SLTNUM];

	[VAR_NUMBER_CTLS] :

	    IF .CURDEV NEQ 0 THEN RESULT = .CURDEV [DEV_NUM_OF_CTLS];

	[VAR_NUMBER_UNTS] :

	    IF .CURCTL NEQ 0 THEN RESULT = .CURCTL [CTL_NUM_OF_UNTS];

	[VAR_NUMBER_TRBS] :

	    IF .CURUNT NEQ 0 THEN RESULT = .CURUNT [UNT_NUM_OF_TRBS];

	[VAR_CTL_CHARS_0 TO VAR_CTL_CHARS_7] :

	    IF .CURCTL NEQ 0 
	    THEN

		CASE .VAR_NUMBER FROM VAR_CTL_CHARS_0 TO VAR_CTL_CHARS_7 OF
		    SET

		    [VAR_CTL_CHARS_0] :
			RESULT = .CURCTL [CTL_PAR_0];

		    [VAR_CTL_CHARS_1] :
			RESULT = .CURCTL [CTL_PAR_1];

		    [VAR_CTL_CHARS_2] :
			RESULT = .CURCTL [CTL_PAR_2];

		    [VAR_CTL_CHARS_3] :
			RESULT = .CURCTL [CTL_PAR_3];

		    [VAR_CTL_CHARS_4] :
			RESULT = .CURCTL [CTL_PAR_4];

		    [VAR_CTL_CHARS_5] :
			RESULT = .CURCTL [CTL_PAR_5];

		    [VAR_CTL_CHARS_6] :
			RESULT = .CURCTL [CTL_PAR_6];

		    [VAR_CTL_CHARS_7] :
			RESULT = .CURCTL [CTL_PAR_7];
		    TES;


	[VAR_UNT_CHARS_0 TO VAR_UNT_CHARS_7] :

	    IF .CURUNT NEQ 0
	    THEN

		CASE .VAR_NUMBER FROM VAR_UNT_CHARS_0 TO VAR_UNT_CHARS_7 OF
		    SET

		    [VAR_UNT_CHARS_0] :
			RESULT = .CURUNT [UNT_PAR_0];

		    [VAR_UNT_CHARS_1] :
			RESULT = .CURUNT [UNT_PAR_1];

		    [VAR_UNT_CHARS_2] :
			RESULT = .CURUNT [UNT_PAR_2];

		    [VAR_UNT_CHARS_3] :
			RESULT = .CURUNT [UNT_PAR_3];

		    [VAR_UNT_CHARS_4] :
			RESULT = .CURUNT [UNT_PAR_4];

		    [VAR_UNT_CHARS_5] :
			RESULT = .CURUNT [UNT_PAR_5];

		    [VAR_UNT_CHARS_6] :
			RESULT = .CURUNT [UNT_PAR_6];

		    [VAR_UNT_CHARS_7] :
			RESULT = .CURUNT [UNT_PAR_7];
		    TES;

	[VAR_TRB_CHARS_0 TO VAR_TRB_CHARS_7] :

	    IF .CURTRB NEQ 0
	    THEN

		CASE .VAR_NUMBER FROM VAR_TRB_CHARS_0 TO VAR_TRB_CHARS_7 OF
		    SET

		    [VAR_TRB_CHARS_0] :
			RESULT = .CURTRB [TRB_PAR_0];

		    [VAR_TRB_CHARS_1] :
			RESULT = .CURTRB [TRB_PAR_1];

		    [VAR_TRB_CHARS_2] :
			RESULT = .CURTRB [TRB_PAR_2];

		    [VAR_TRB_CHARS_3] :
			RESULT = .CURTRB [TRB_PAR_3];

		    [VAR_TRB_CHARS_4] :
			RESULT = .CURTRB [TRB_PAR_4];

		    [VAR_TRB_CHARS_5] :
			RESULT = .CURTRB [TRB_PAR_5];

		    [VAR_TRB_CHARS_6] :
			RESULT = .CURTRB [TRB_PAR_6];

		    [VAR_TRB_CHARS_7] :
			RESULT = .CURTRB [TRB_PAR_7];
		    TES;

	[OTHERWISE] :
	    RESULT = 0;
	TES;

    IF DEBUG
    THEN
	BEGIN
	PCRLF (0);
	OUTSTR (0, UPLIT (%ASCIZ'    Variable #'));
	OUTNUM (0, .VAR_NUMBER, 8, 0);
	OUTSTR (0, UPLIT (%ASCIZ' = '));
	OUTNUM (0, .RESULT, 8, 0);
	END;

    .RESULT
    END;					! of GET_VARIABLE
ROUTINE NEXT_LIX (VAR_NUMBER, VALUES) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Keep the BLOCK_LOAD data base up to date based upon the current
!	system line. Return an indication if data items associated with
!	the CTL, UNT, or TRB parameters have been changed.
!
! FORMAL PARAMETERS
!
!	VAR_NUMBER - the Variable Set to return indication on
!	VALUES - Misc info maintained by VNP
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
!
!	TRUE - if the set of parameters for VAR_NUMBER have changed or no
!		next line exists.
!	FALSE - otherwise
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

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

    MAP
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	NEW_DEV : REF DEV_BLOCK,
	NEW_CTL : REF CTL_BLOCK,
	NEW_UNT : REF UNT_BLOCK,
	NEW_TRB : REF TRB_BLOCK,
	RESULT,
	TEMP_LIX;

!
! These set of support routines allow for searching VNP's data structures
! for the data items we want.
!
    ROUTINE SEL_SLT (SLT_PTR, LIX_NUM) =
	BEGIN

	MAP
	    SLT_PTR : REF SLT_BLOCK;

	IF ((.LIX_NUM = ..LIX_NUM - 1) LEQ 0) THEN .SLT_PTR ELSE 0

	END;
!
    ROUTINE SEL_DEV (DEV_PTR, DEV_NAM) =
	BEGIN

	MAP
	    DEV_PTR : REF DEV_BLOCK;

	IF (CH$EQL (3, CH$PTR (DEV_PTR [DEV_NAME]), 3, CH$PTR (.DEV_NAM))) THEN .DEV_PTR ELSE 0

	END;
!
    ROUTINE SEL_CTL (CTL_PTR, CTL_NUM) =
	BEGIN

	MAP
	    CTL_PTR : REF CTL_BLOCK;

	IF (.CTL_PTR [CTL_CONT] EQL .CTL_NUM) THEN .CTL_PTR ELSE 0

	END;
!
    ROUTINE SEL_UNT (UNT_PTR, UNT_NUM) =
	BEGIN

	MAP
	    UNT_PTR : REF UNT_BLOCK;

	IF (.UNT_PTR [UNT_UNIT] EQL .UNT_NUM) THEN .UNT_PTR ELSE 0

	END;
!
    ROUTINE SEL_TRB (TRB_PTR, TRB_NUM) =
	BEGIN

	MAP
	    TRB_PTR : REF TRB_BLOCK;

	IF (.TRB_PTR [TRB_LADDR] EQL .TRB_NUM) THEN .TRB_PTR ELSE 0

	END;
!
! The start of NEXT_LIX
!-
!
! Setup default new values for the next SLT
!
    NEW_DEV = 0;
    NEW_CTL = 0;
    NEW_UNT = 0;
    NEW_TRB = 0;
    RESULT = TRUE;				!Default response is TRUE
!
! Get next SLT based upon line index and setup pointers to it's associated
! data structures. Upon completion, RESULT will be TRUE if an
! important change occured otherwise it will be FALSE.
!
    CURLIX = .CURLIX + 1;			!Update the Line Index
    TEMP_LIX = .CURLIX;				!Used to find correct LIX
    CURSLT = FND_CHAIN (.VALUES [SLT_CHAIN], SEL_SLT, TEMP_LIX);

    IF (.CURSLT NEQ 0)
    THEN
	BEGIN
	NEW_DEV = FND_CHAIN (.VALUES [DEV_CHAIN], SEL_DEV,
	    (IF (.CURSLT [SLT_DEV] NEQ 0) THEN CURSLT [SLT_DEV] ELSE CURSLT [SLT_DLC]));

	IF (.NEW_DEV NEQ 0)
	THEN
	    BEGIN
	    NEW_CTL = FND_CHAIN (.NEW_DEV [DEV_CTL], SEL_CTL, .CURSLT [SLT_CTL]);

	    IF (.NEW_CTL NEQ 0)
	    THEN
		BEGIN
		NEW_UNT = FND_CHAIN (.NEW_CTL [CTL_UNT], SEL_UNT, .CURSLT [SLT_UNT]);

		IF (.NEW_UNT NEQ 0)
		THEN
		    BEGIN
		    NEW_TRB = FND_CHAIN (.NEW_UNT [UNT_TRB], SEL_TRB, .CURSLT [SLT_TRB]);
		    END;

		END;

	    END;

	END;

    IF ((.NEW_CTL NEQ .CURCTL) AND (.VAR_NUMBER EQL VAR_CURRENT_CTL))
    THEN
	RESULT = TRUE
    ELSE

	IF ((.NEW_UNT NEQ .CURUNT) AND (.VAR_NUMBER EQL VAR_CURRENT_UNT))
	THEN
	    RESULT = TRUE
	ELSE

	    IF ((.NEW_TRB NEQ .CURTRB) AND (.VAR_NUMBER EQL VAR_CURRENT_TRB))
	    THEN
		RESULT = TRUE
	    ELSE
		RESULT = FALSE;

    CURDEV = .NEW_DEV;
    CURCTL = .NEW_CTL;
    CURUNT = .NEW_UNT;
    CURTRB = .NEW_TRB;
    .RESULT
    END;					! of NEXT_LIX
GLOBAL ROUTINE MCEX (KERNEL_FILE, CEX_FILE, VALUES) : NOVALUE = 	!MERGE THE COMM EXEC

!++
! FUNCTIONAL DESCRIPTION:
!
!	MERGE THE COMM EXEC INTO THE KERNEL.  THIS REQUIRES SETTING
!	 UP A COMMON PARTITION.  INFORMATION ON THE PARTITION IS
!	 TAKEN FROM THE COMM EXEC'S LABEL AND HEADER BLOCKS,
!	 AND FROM CETAB.MAC.
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - FILE BLOCK FOR THE KERNEL
!	CEX_FILE - FILE BLOCK FOR THE COMM EXEC
!	VALUES - VALUES READ FROM CETAB.MAC AND THE SYMBOL TABLES
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	CHANGES THE CORE IMAGE
!
!--

    BEGIN

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

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

    LOCAL
	PCB_ADDR,
	CEX_LABEL : REF VECTOR [1024],
	KERNEL_LABEL : REF VECTOR [1024],
	HIGH_EXEC_ADDR,
	FLAGS,
	CEX_BASE,
	CEX_TOP,
	TEMP1,
	TEMP2,
	TEMP3,
	R50VAL : VECTOR [4];

    CEX_LABEL = .CEX_FILE [FILE_LABEL];
    KERNEL_LABEL = .KERNEL_FILE [FILE_LABEL];
!
! FIND THE FLAGS FROM THIS CORE IMAGE, AND CHECK THAT ALL NECESSARY
!  OPTIONS AND NO BAD OPTIONS ARE SELECTED.
!
    FLAGS = GETWRD (.KERNEL_FILE, .VALUES [FMASK]);
!
! VERIFY THAT FE_EXT (22-BIT ADDRESSING) IS CLEAR.
!  ALSO, FE_CEX (COMM EXEC LOADED) SHOULD BE CLEAR.
!

    IF ((.FLAGS AND .VALUES [FE_EXT]) NEQ 0)
    THEN
	ERRMSG (0, 28, ROUTINE_NAME, KERNEL_FILE [FILE_NAME], 0, 0,
	    0);

    IF ((.FLAGS AND .VALUES [FE_CEX]) NEQ 0)
    THEN
	ERRMSG (0, 30, ROUTINE_NAME, KERNEL_FILE [FILE_NAME], 0, 0,
	    0);

!
! SINCE WE HAVE NOT REALLY CHECKED OUT PLAS SUPPORT, DONT ALLOW IT.
!

    IF ((.FLAGS AND .VALUES [FE_PLA]) NEQ 0)
    THEN
	ERRMSG (0, 33, ROUTINE_NAME, KERNEL_FILE [FILE_NAME], 0, 0,
	    0);

!
! EXTEND THE EXECUTIVE POOL TO THE BOTTOM OF THE COMM EXEC PARTITION
!
    CEX_BASE = .CEX_LABEL [L$BSA] + (256*.CEX_LABEL [L$BSA + 1]);
    CEX_TOP = .CEX_LABEL [L$BHGV] + (256*.CEX_LABEL [L$BHGV + 1]);

    IF ((.FLAGS AND .VALUES [FE_EXV]) EQL 0) THEN HIGH_EXEC_ADDR = 16*2048 ELSE HIGH_EXEC_ADDR = 20*2048;

    IF (.CEX_TOP GTR .HIGH_EXEC_ADDR)
    THEN
	ERRMSG (0, 31, ROUTINE_NAME, CEX_FILE [FILE_NAME], .CEX_TOP,
	    .HIGH_EXEC_ADDR, 0);

!
! ROUND THE BASE OF THE EXEC STORAGE POOL UP TO A MULTIPLE OF 4 BYTES
!
    TEMP1 = GETWRD (.KERNEL_FILE, .VALUES [CRAVL]);	!BASE OF POOL
    TEMP2 = GETWRD (.KERNEL_FILE, .TEMP1 + 2);	!CURRENT LENGTH OF POOL
    PUTWRD (.KERNEL_FILE, .TEMP1 + 2, 0);	!CLEAR OLD LENGTH WORD
    TEMP3 = ((.TEMP1 + 3) AND ( NOT 3));	!ROUND UP BASE TO MULT. OF 4
    TEMP2 = .TEMP2 - (.TEMP3 - .TEMP1);		!ADJUST LENGTH WORD
    PUTWRD (.KERNEL_FILE, .VALUES [CRAVL], .TEMP3);	!STORE NEW BASE
    PUTWRD (.KERNEL_FILE, .TEMP3, 0);		!CLEAR NEW POINTER WORD
    PUTWRD (.KERNEL_FILE, .TEMP3 + 2, .TEMP2);	!STORE NEW LENGTH
!
! INCREASE THE SIZE OF THE EXEC
!
    TEMP1 = GETWRD (.KERNEL_FILE, .VALUES [EXSIZ]);	!REMEMBER OLD SIZE
    PUTWRD (.KERNEL_FILE, .VALUES [EXSIZ], .CEX_BASE);	!STORE NEW SIZE
!
! FREE THE NEW SPACE, THUS PLACING IT IN THE EXEC STORAGE POOL
!
    DEACB (.KERNEL_FILE, .TEMP1,
	(.CEX_BASE - .TEMP1) AND ( NOT (GETWRD (.KERNEL_FILE, .VALUES [CRAVL] - 2))), .VALUES);
!
! CREATE A PARTITION CONTROL BLOCK
!
    PCB_ADDR = M_PCB (.KERNEL_FILE, UPLIT (%ASCIZ'CEXCOM'), 0, .CEX_BASE, .CEX_TOP, %O'100200',
	.VALUES [PS_COM], 0, .VALUES);
!
! NOW COPY THE COMM EXEC INTO THE KERNEL IMAGE
!

    INCR ADDRESS FROM .CEX_BASE TO .CEX_TOP DO
	PUTBYT (.KERNEL_FILE, .ADDRESS, GETBYT (.CEX_FILE, .ADDRESS));

!
! NOW SET THE BIT IN THE FLAGS WORD WHICH MEANS THAT WE HAVE
!  LOADED THE COMM EXEC.
!
    FLAGS = .FLAGS OR .VALUES [FE_CEX];
    PUTWRD (.KERNEL_FILE, .VALUES [FMASK], .FLAGS);
!
    END;					!OF MCEX
ROUTINE ALOC_POOL (KERNEL_FILE, AMOUNT, DUMMY, DUMMY2) = 	!ALLOCATE FROM POOL PARTITION

!++
! FUNCTIONAL DESCRIPTION:
!
!	ALLOCATE "AMOUNT" BYTES FROM THE CEXDAT PARTITION
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - THE RSX KERNEL
!	AMOUNT - THE NUMBER OF BYTES TO ALLOCATE
!	DUMMY - Dummy Parameter to Make CALL look like ALOCB Routine
!	DUMMY2 - Dummy Parameter to Make CALL look like ALOCB Routine
!
! IMPLICIT INPUTS:
!
!	FILE_HWM for KERNEL_FILE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	Address of start of allocated area
!
! SIDE EFFECTS
!
!	Expands the size of the SYSTEM image
!
!--

    BEGIN

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

    MAP
	KERNEL_FILE : REF FILE_BLOCK;

    LOCAL
	REAL_AMOUNT,
	RESULT;

!
! Round amount to two word boundary
!
    REAL_AMOUNT = (.AMOUNT + 3) AND ( NOT 3);
!
! Allocate by Moving the KERNEL_FILE's High Water Mark
!
    RESULT = .KERNEL_FILE [FILE_HWM];
    KERNEL_FILE [FILE_HWM] = .KERNEL_FILE [FILE_HWM] + .REAL_AMOUNT;
!
    .RESULT
    END;					!OF ALOC_POOL
GLOBAL ROUTINE LD_DCB (KERNEL_FILE, FILE_CHAN, PCB_ADDR, DEV_NAME, VALUES) =
    !BUILD A DCB FOR AN LLC

!++
! FUNCTIONAL DESCRIPTION
!
! 	ALLOCATE AND INSERT A DCB FOR A PARTICULAR LLC.
!
! FORMAL PARAMETERS:
!
!	KERNEL_FILE - POINTER TO FILE THAT HOLDS THE KERNAL IMAGE
!	FILE_CHAN - CHANNEL FOR PERFORMING I/O AT THIS LEVEL
!	PCB_ADDR - PDP-11 ADDRESS OF PCB FOR THIS LLC
!	DEV_NAME - LOCATION CONTAINING 2 CHARACTER DEVICE NAME
!	VALUES - BLOCK OF LOTS OF GOOD THAINGS FOR VNP20
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS
!
!	THE KERNEL IS MODIFIED
!
!--

    BEGIN

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

    MAP
	KERNEL_FILE : REF FILE_BLOCK,
	VALUES : REF VNPVAL_BLOCK;

    LOCAL
	LOC,
	DCB_FILE : REF FILE_BLOCK,
	DCB_NAME : VECTOR [CH$ALLOCATION (7)],
	XXBEG,
	XXEND,
	DCB_DATA_ADDR,
	DCB_ADDR,
	LAST_DCB_ADDR,
	UCB_ADDR,
	FIRST_UCB_ADDR,
	UCB_LENGTH,
	SCB_ADDR,
	LAST_SCB_ADDR,
	NUNITS,
	MODU_PTR : REF MODU_BLOCK;

!
! GET FILE BLOCK TO READ IN FILE
!
    DCB_FILE = GETBLK (FILE_TYP, FILE_LEN);
!
! Tell someone what we are doing
!
    OUTSTR (0, UPLIT (%ASCIZ'[Loading Device '));
    OUTSTR (0, DEV_NAME);
    OUTSTR (0, UPLIT (%ASCIZ':	--> '));
!
! SETUP FILENAME AS ??TAB
!
    CH$COPY (2, CH$PTR (DEV_NAME), 3, CH$PTR (UPLIT (%ASCIZ'TAB')), 0, 6, CH$PTR (DCB_FILE [FILE_NAME]));
!
! READ IN THE CORE FILE AND SYMBOL TABLE
!
    RSTB (.FILE_CHAN, .DCB_FILE);
    RCOR (.DCB_FILE, .FILE_CHAN, 2*1024);
!
    MODU_PTR = .DCB_FILE [FILE_MODU];
    OUTSTR (0, MODU_PTR [MODU_NAME]);
    OUTPUT (0, %C' ');
    OUTSTR (0, MODU_PTR [MODU_IDENT]);
    OUTSTR (0, UPLIT (%ASCIZ' ]'));
    PCRLF (0);
!
! NOW LOOK UP THE STARTING AND ENDING SYMBOLS FOR COPYING
!
    CH$COPY (1, CH$PTR (UPLIT (%ASCIZ'$')), 2, CH$PTR (DEV_NAME), 0, 7, CH$PTR (DCB_NAME));
    CH$MOVE (3, CH$PTR (UPLIT (%ASCIZ'DAT')), CH$PTR (DCB_NAME, 3));
    XXBEG = SYM_VAL (.DCB_FILE, DCB_NAME, 0);
    CH$MOVE (3, CH$PTR (UPLIT (%ASCIZ'END')), CH$PTR (DCB_NAME, 3));
    XXEND = SYM_VAL (.DCB_FILE, DCB_NAME, 0);
!
! ALLOCATE THE DCB STRUCTURES
!
    DCB_DATA_ADDR = ALOCB (.KERNEL_FILE, .XXEND - .XXBEG, 1, .VALUES);
!
! COPY IN THE DATA STRUCTURE
!

    INCR COUNTER FROM .XXBEG TO .XXEND - 1 DO
	PUTBYT (.KERNEL_FILE, .DCB_DATA_ADDR + .COUNTER - .XXBEG, GETBYT (.DCB_FILE, .COUNTER));

!
! NOW RELOCATE SOME OF THE DATA STRUCTURE LOCATIONS
!
!
! PROCESS EACH DCB, WITH ITS UCBS AND SCBS.
!
    SCB_ADDR = 0;
    DCB_ADDR = .DCB_DATA_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]) - .XXBEG + .DCB_ADDR;
	PUTWRD (.KERNEL_FILE, .DCB_ADDR + .VALUES [D_UCB], .FIRST_UCB_ADDR);
	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]) - .XXBEG + .DCB_ADDR);
	    PUTWRD (.KERNEL_FILE, .UCB_ADDR + .VALUES [U_RED],
		GETWRD (.KERNEL_FILE,
		    .UCB_ADDR + .VALUES [U_RED]) - .XXBEG + .DCB_ADDR);
	    LAST_SCB_ADDR = .SCB_ADDR;
	    SCB_ADDR = GETWRD (.KERNEL_FILE, .UCB_ADDR + .VALUES [U_SCB]) - .XXBEG + .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) - .XXBEG + .DCB_ADDR);
		END;

	    END;

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

!
! LINK THE DCB INTO THE SYSTEM'S LIST OF DCBS
!
    LNKDCB (.KERNEL_FILE, .DCB_DATA_ADDR, .VALUES);
!
! If this is for the CE: Device then we special case and store the data
! base address for use in loading other processes.
!

    IF (CH$EQL (2, CH$PTR (DEV_NAME), 2, CH$PTR (UPLIT (%ASCIZ'CE')), 0))
    THEN
	BEGIN
	VALUES [CE_DATA_BASE] = .DCB_DATA_ADDR;
	VALUES [CE_DATA_FILE] = .DCB_FILE;
	END
    ELSE
!
! FREE SOME DATA STRUCTURES
!
	FCOR (.DCB_FILE);

!
! Return Address of Start of Data Base
!
    .DCB_DATA_ADDR
    END;					!OF LD_DCB

END

ELUDOM
! Local Modes:
! Comment Column:36
! Comment Start:!
! Mode:Fundamental
! Auto Save Mode:2
! End: