Google
 

Trailing-Edge - PDP-10 Archives - BB-X117B-SB_1986 - 10,7/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) DIGITAL EQUIPMENT CORPORATION 1980,1981,1982,1986. ALL RIGHTS RESERVED.
!
!
!THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
!ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH LICENSE AND WITH THE
!INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR ANY  OTHER
!COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
!OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF THE  SOFTWARE  IS  HEREBY
!TRANSFERRED.
!
!THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT  NOTICE
!AND  SHOULD  NOT  BE  CONSTRUED  AS A COMMITMENT BY DIGITAL EQUIPMENT
!CORPORATION.
!
!DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY  OF  ITS
!SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
!

!++
! FACILITY:	MCB Configuration Facility, 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: