DataMuseum.dk

Presents historical artifacts from the history of:

Bogika Butler

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Bogika Butler

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦4eaaa5345⟧ TextFile

    Length: 211328 (0x33980)
    Types: TextFile
    Names: »KNELOP.SA«

Derivation

└─⟦0b578df25⟧ Bits:30009789/_.ft.Ibm2.50006602.imd Mogens Pelles Zilog 80,000 / EOS projekt
    └─⟦this⟧ »KNELOP.SA« 
└─⟦798d317aa⟧ Bits:30009789/_.ft.Ibm2.50006626.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦798d317aa⟧ Bits:30009789/_.ft.Ibm2.50006628.imd Mogens Pelles Zilog 80,000 / EOS projekt
    └─⟦this⟧ »KNELOP.SA« 

TextFile

 
***********************************************************************
*                       Copyright 1984 by                             *
*                       NCR Corporation                               *
*                       Dayton, Ohio  U.S.A.                          *
*                       All Rights Reserved                           *
***********************************************************************
*                       EOS Software produced by:                     *
*                       NCR Systems Engineering - Copenhagen          *
*                       Copenhagen                                    *
*                       DENMARK                                       *
***********************************************************************
 
KNELOP     IDNT  1,0
           NOLIST
           INCLUDE COMDEF.SA
           LIST
* KERNEL OPERATIONS AND TRAP-ENTRIES.  LIST OF CONTENTS:
*-----------------------------------------------------------------------
* TRAP ENTRIES:
* TR_TR7        TRAP7, NORMAL KERNEL ENTRIES
* TR_XXX        INTERNAL EXCEPTIONS AND INITIALIZATION
* VARIOUS       RETURNS THROUGH JUMPS
 
* CALL AND RETURN:
* OBJ_CALL    * FROM NORMAL CONTEXT  ( * INDICATES KERNEL OPERATION)
* OBJ_RES     * FROM RESIDENT CONTEXT
* OBJ_RET     * OBJ_RETURN, NORMAL CONTEXT
* OBJ_RRET    * OBJ_RETURN, RES. CONTEXT
* SAVE_STK      SAVE SUPERVISOR STACK
* RSTO_STK      RESTORE SUPERVISOR STACK
* ENT_CTX       ENTER CONTEXT
* PREP_RET      PREPARE RETURN
* LOAD_MMU      LOAD MMU REGISTERS
* CRE_CTX       CREATE CONTEXT
* SET_FP        SET FORMAL POINTERS
* SET_ACT       SET ACTUAL REF
* RESETLMS      RESET CHAIN IN ELEMENTS
* RET_FP        RETURN FORMALS
* DEL_CTX       DELETE CONTEXT
 
* OBJECT CREATION AND DELETION:
* DECL_GEN    * DECLARE GENERAL
* CRE_ENV       CREATE AND INIT ENVELOPE
* DECL_SEG    * DECLARE SEGMENT (NON_EMBEDDED)
* DECL_SUB    * DECLARE SUBSEGM (NON_EMBEDDED)
* NEW_SEG     * NEW EMBEDDED SEGMENT
* NEW_SUB     * NEW_EMBEDDED SUBSEGMENT
* CRE_SEG       CREATE EMBEDDED SEGMENT
* CRE_SUB       CREATE EMBEDDED SUBSEGMENT
* MAKE_REEN   * MAKE GENERAL OBJECT REENTRANT
* SET_CALL_STK* SET CALL STACK FOR GENERAL OBJECT
* CLR_PT        CLEAR POINTER (OF ANY KIND)
* DEL_EMB       DELETE EMBEDDED OBJECTS (SEGMENTS ONLY)
* AB_SEGM       ABORT SEGMENT
* DEL_ENV     * DELETE ENVELOPE
* D_ENV_OK      DELETE ENVELOPE (CHECKS OK)
* DEALLOC     * DEALLOCATE OBJECT
* C_NXT_M       CALL NEXT MANAGER AND DELETE OBJECT
* DUM_MAN       DUMMY MANAGER OBJECT
* RSTO_STR      RESTORE STRUCTURE HOLDING DELETING OBJECT
 
* POINTER MANIPULATION:
* COPY        * COPY POINTER
* CLR_SMP       CLEAR SIMPLE POINTER
* COPY_NIL      COPY SIMPLE REF TO NIL POINTER
* MOVE_OWN    * MOVE TO NEW OWNER SET
* MOVE_MAN    * MOVE TO NEW MANAGER SET
* FIRSTINSET  * GET FIRST MEMBER OF SET
* NXTINSET    * GET NEXT MEMBER OF SET
* M_OWN_OK      MOVE OWNER, CHECK PERFORMED
* INS_OWN       INSERT IN OWNER SET
* M_MAN_OK      MOVE MANAGER, CHECK PERFORMED
* INS_MAN       INSERT IN MANAGER SET
* DUM_ACT       DUMMYFY ACTUAL REFS
* DUM_ENV       DUMMYFY ENV REFS AND REMOVE FROM MANSET
* DUM_OBJ       DUMMYFY OBJ REFS AND REMOVE FROM OWN_SET
 
* EXECUTION CONTROL:
* MAP_SEGM    * MAP SEGMENT, NORMAL OR RESIDENT CTX
* MAP_RESOK     MAP RESIDENT OR NORMAL OK
* MAP_OK        MAP SEGMENT INTO MMU DESCRIPTOR
* MAP_FIRST     MAP SEGMENT INTO UNINITIALIZED MMU DESCR.
 
* PROCESS MANAGEMENT AND SYNC:
* DECL_PROC   * DECLARE PROCESS
* STOP_PROC     STOP PROCESS
* NEW_ST_CALL * NEW STACK CALL
* ABORT       * ABORT GENERAL OBJECT
* SPEED_UP    * SPEED UP GENERAL OBJECT
* ABORT_ONE     ABORT ENVELOPE WITHOUT LOCAL TREE
* ABORT_ENV     ABORT ENVELOPE AND LOCAL MANAGER TREE
* PROPAGATE     PROPAGATE SPEED
* SET_MODE    * SET PROPAGATION MODE
* TEST_SPEED  * TEST SPEED-UP STATUS
 
* IDENTIFICATION CONTROL:
* DECL_ENV    * DECLARE ENVELOPE
* INSP_OBJ    * INSPECT OBJECT
* INSP_ACT    * INSPECT HOLDER OF ACTUAL POINTER
* INSP_CALL   * INSPECT CALLER
* INSP_PROC   * INSPECT PROCESS
* INSP_INIT     INSPECT INITIALIZATION
* INSP_COM      COMMON INSPECT
* SET_CAPS    * SET CALL CAPABILITY
 
* CHECK PROCEDURES:
* C_PT          CHECK POINTER ARGUMENT, NORMAL CTX
* C_PTRES       CHECK POINTER, NORMAL OR RESIDENT
* C_ENT         CHECK ENTITY ARGUMENT, NORMAL CTX
* C_ENTRES      CHECK ENTITY, NORMAL OR RESIDENT
* C_CALL        CHECK CALLABLE OBJECT AND FUNCTION#
* C_SUB         CHECK SUBSEGM ARGUMENT  (NOT VOID)
* C_OPEN        CHECK OWNER POINTER AND OPEN OBJECT
* C_PRIM        CHECK AND GET PRIMARY ENVELOPE
* C_TOPOWN      CHECK TOP STACK, OWNER OR SIMPLE POINTER
* C_PTS         CHECK #POINTERS
* C_ADDR        CHECK ADDRESS
* C_SIZ         CHECK SIZE ARGUMENT
 
* STACK CHECK:
* S_MOVE        STACK CHECK FOR MOVE OWNER
* S_TERM        STACK CHECK BEFORE TERM PROC ENTRY
* S_GROW        STACK CHECK FOR GROWTH
* S_UPDATE      STACK REQUIREMENT UPDATE
* S_SHRINK      SHRINK STACK REQUIREMENTS
* S_ENV         INIT ALL ENVELOPE TERM REQUIREMENTS
* S_LOC         CHECK FREE STACK FOR DELETE LOCALS
* S_MAX         FIND MAX SIZE AND COMPARE
* S_INITENV     INIT ENVELOPE TERM WITHOUT LOCALS
* S_CTX         GET TERMINATION CTX REQUIREMENTS
* S_MAXLOC      FIND MAX TERM REQUIREMENTS OF LOCALS
    PAGE
    SECTION 9    NORMAL CODE SECTION
    XREF.S KV_CTX,SAVE_SR,SAVE_PC,RUNNING,KV_INVEC,DRIV_TAB,STAK_TAB
    XREF   I_ENTER,TERMGATE,TERMCOND,PROPSPED,START_PROC,NEXT_PROC
    XREF   GATE_OBJ,COND_OBJ,ALLOC_OB,SCHEDOBJ
    XREF   MM_PUSHU,MM_POPU,MM_PUSHK,MM_POPK
    XREF   MM_PUSHD,MM_POPD,MM_PUSHO,MM_POPO
    XREF   NIOBEGIN,NIO_END,NABSADDR,RIOBEGIN,RIO_END,RABSADDR
    XREF   IIOBEGIN,IIO_END,IABSADDR,INT_SIGN,TERMDRIV,FORCE_OPEN
    XREF   KNELWAIT,KNELSIGN,SAVE_STK,RSTO_STK,INCRDECR
    XREF   MM_LOCK,MM_QUEUE,MM_TERM,TEXTLINE,PRINTA02,CONVADDR,GET_TIME
 
    XDEF   I_KNELOP,STOP_PROC,CRE_CTX,SET_FP,INT_EXC,PREP_RET,LOAD_MMU
    XDEF   C_ENT,C_ENTRES,C_PT,C_SUB,CLR_SMP,RET_FAST,TR_SPEED
 
 
TR_TR7     EQU *                  TRAP7:  NORMAL KERNEL ENTRIES.
 
*        CALL:                    RETURN:
* A4-A6  --                       SAME
* D2.W   LENGTH ARG LIST          UNDEF
* D4.L   LOWEST ARG ADDR (LOGICAL)UNDEF
* D5.W   KERNEL F  UNCTION#       UNDEF
* D6/D7  RESULT (OBJ_RETURN ONLY) RESULT
* OTHER REGS:  --                 UNDEF OR SPECIAL RETURN VALUES.
 
*** TEST OUTPUT
    PRT_REG KNEL_ENTRY
    PRT_MEM SUPV_STACK,(A7),20
    MOVE   (A7),D3                    D3:=CALLERS SR;
    MOVEM.L A4-A6,-(A7)               SAVE A4-A6
    MOVE   #1<<13+7<<8,SR             DISABLE;
    ASL    #1,D5                      D5:=KERNEL FUNCTION *2;
    AND    #$2700,D3                  D3:=CALLERS SUPV MODE + INTRPT MASK;
  IF D3 <GT> #$2000 THEJ.S          IF SUPV MODE AND INTRPT MASK > 0 THEN
    MOVEQ.L #0,D6                     D6:= ARG# := 0 ;
    SUB    #36*2,D5               "SUPERVISOR MODE:"
    CMP    #8,D5                    IF FNC <36 OR >39
  IF <HI> THEN.S                    THEN
    MOVE.L        #ECRADDR,D7         D7:= REJECT, ILL_ADDR;
    BRA    RET_FAST                   GOTO RETURN;
  ENDI                              ENDI;
    CASEJMP D5                        CASE KERNEL FUNCTION OF
    CASELAB IIOBEGIN              36:
    CASELAB IIO_END               37:
    CASELAB IABSADDR              38:
    CASELAB INT_SIGN              39:
    CASELAB ITSTDUMP              40: ONLY IN TEST VERSION OF KERNEL
  ENDI                              END "SUPERVISOR MODE";
 
    MOVE.L KV_CTX,A2                  A2:= CURRENT CTX;
    CMP    #MAXFNC,D5
  IF <HI> THEN.S                    IF FNC <0 OR >MAX THEN
    MOVEQ.L #0,D6                     D6:= ARG#:0;
    BRA    EE_ADDR                    GOTO REJECT ;
  ENDI                              ENDI;
    MOVE.W ARG_MIN(D5),D1             D1:= REQUIRED:= MIN(KNEL_FUNC);
  IF <EQ> THEN.S                    IF REQUIRED=0 THEN
    MOVE.L D4,A4                      ARG_ADDR:= LOW_ARG; "SIMULATE EMPTY ARGS"
    BRA    PREP_OK                    GOTO OK;   D6 IS LEFT UNCHANGED
  ENDI                              ENDI;
    MOVEQ.L #0,D6                   D6:= ARG#:= 0;
    CMP    D1,D2                    IF LENGTH ARG LIST < MIN(KERNEL FUNC)
    BLT    EE_ADDR                  THEN REJECT END;
    AND.L  #1<<24-2,D4                ROUND LOW ARG AND LENGTH TO WORD
    AND.L  #1<<16-2,D2                ADDR IN MAX ADDRESS RANGE;
 
    ADD.L  D4,D2                      D2:=TOP ARG:=LOW ARG+LENGTH;
    SUBQ.L #1,D2                      D2:=LAST_OF_ARG:=TOP ARG -1;
    ROR.L  #8,D2                      D2.W:=LAST_OF_ARG/256;
    ROR.L  #8,D4                      D4.W:=LOW ARG/256;
    LEA CT_MM0+MM_REG(A2),A1          A1:=ADDR OF CTX.MMU_DESCR_0;
    MOVE   #3,D1                      D1:=COUNT:=3 MMU DESCRIPTORS;
REP_0      EQU *                    FOR ALL MMU DESCRIPTORS DO
    CMP    (A1)+,D4                 IF LOW ARG >= MMU.FIRST "UNSIGNED"
  IF <CC> THEN.S                    AND
 
    CMP    (A1)+,D2                   LAST_OF_ARG <= MMU.LAST "UNSIGNED"
  IF <LS> THEN.S                    AND
    BTST.B #0,3(A1)                   MMU.ENABLED
  IF <NE> THEN.S                    THEN
    ADD    (A1),D2                    D2:=ARG ADDR:=LAST_OF_ARG + 1
    ROL.L  #8,D2                          + DISPLACEMENT
    ADDQ.L #1,D2
    ADD    (A1),D4                    D4:=LOW ARG:=LOW ARG+DISPLACEMENT
    ROL.L  #8,D4
    MOVE.L D2,A4                      A4:=ARG ADDR;
    BRA.S  PREP_OK                    GOTO OK
  ENDI                              END;
  ENDI
 
  ELSE.S                            ELSE "LOW_ARG < MMU.FIRST
    ADDQ.L #2,A1                      ADJUST A1 AS IF MMU.LAST HAS BEEN CHECKED
  ENDI
    ADD    #MM_SIZ-4,A1               A1:=NEXT MMU DESCR;
    DBF    D1,REP_0                 END "FOR ALL MMU DESCRIPTORS";
 
    BRA    EE_ADDR                    REJECT;
 
ARG_MIN    EQU *                  MINIMAL LENGTH OF ARGUMENT LISTS:
 
    DC.W   AR_PTSIZ+4+AR_SIZ       0:  OBJ_CALL
    DC.W   0                       1:  OBJ_RET
    DC.W   3*AR_PTSIZ+6*4+3*6+2    2:  DECL_GEN
    DC.W   AR_PTSIZ+4              3:  DECL_SEG
    DC.W   AR_PTSIZ+AR_SIZ         4:  DECL_SUB
    DC.W   AR_PTSIZ+4              5:  NEW_SEG
    DC.W   AR_PTSIZ+AR_SIZ         6:  NEW_SUB
    DC.W   2*AR_PTSIZ+AR_SIZ       7:  DEALLOC
    DC.W   2*AR_PTSIZ              8:  DEL_ENV
    DC.W   AR_PTSIZ+6              9:  SET_CALL_STK
    DC.W   AR_PTSIZ               10:  MAKE_REENT
    DC.W   0                      11:  NOT USED
    DC.W   0                      12:  NOT USED
    DC.W   2*AR_PTSIZ             13:  COPY
    DC.W   2*AR_PTSIZ             14:  MOVE_OWN
    DC.W   2*AR_PTSIZ             15:  MOVE_MAN
    DC.W   2*AR_PTSIZ             16:  FIRSTINSET
    DC.W   2*AR_PTSIZ             17:  NXTINSET
    DC.W   2*AR_PTSIZ             18:  REFEQUAL
    DC.W   AR_PTSIZ+4+AR_SIZ      19:  DECL_PROC
    DC.W       2*AR_PTSIZ+4+AR_SIZ    20:  NEW_ST_CALL
    DC.W   AR_PTSIZ               21:  ABORT
    DC.W   AR_PTSIZ               22:  SPEED_UP
    DC.W   4                      23:  SET_MODE
    DC.W   0                      24:  TEST_SPEED
    DC.W   0                      25:  NOT USED
    DC.W   3*AR_PTSIZ+2*4+2*6     26:  DECL_ENV
    DC.W   3*AR_PTSIZ             27:  INSP_OBJ
    DC.W   3*AR_PTSIZ             28:  INSP_ACT
    DC.W   2*AR_PTSIZ             29:  INSP_CALL
    DC.W   2*AR_PTSIZ             30:  INSP_PROC
    DC.W   AR_PTSIZ+4             31:  SET_CAPS
    DC.W   0                      32:  NOT USED
    DC.W   AR_PTSIZ+2*4           33:  MAP_SEGM
    DC.W   0                      34:  GET_TIME
    DC.W   4                      35:  SET_SLICE
    DC.W   AR_PTSIZ               36:  IOBEGIN
    DC.W   AR_PTSIZ               37:  IO_END
    DC.W   AR_PTSIZ               38:  ABS_ADDR
    DC.W   0                      39:  INT_SIGN (NOT USED)
    DC.W   2                      40:  TESTDUMP, ONLY IN TEST VERSION OF KERNEL
 
PREP_OK    EQU *                  OK:
    PAGE
***
    PRT_REG KNEL_SWITCH
    AND    #$700,D3                   D3:=RESIDENT:=INTRPT MASK;
* IN NORMAL MODE A TIME OUT MAY BE PENDING.  THEN CALLER'S
* SUPV_MODE = 1, INTRPT_MASK = 0.
  IF <EQ> THEN.S                    IF CALLER IN NORMAL MODE THEN
 
    CASEJMP D5                    CASE KERNEL FUNCTION OF
 
    CASELAB OBJ_CALL               0:  CALL AND RETURN:
    CASELAB OBJ_RET                1:
    CASELAB DECL_GEN               2:  OBJECT CREATE AND DELETE:
    CASELAB DECL_SEG               3:
    CASELAB DECL_SUB               4:
    CASELAB NEW_SEG                5:
    CASELAB NEW_SUB                6:
    CASELAB DEALLOC                7:
    CASELAB DEL_ENV                8:
    CASELAB SET_CALL_STK           9:
    CASELAB MAKE_REENTR           10:
    CASELAB ER_ADDR1              11:  NOT USED
    CASELAB ER_ADDR1              12:  NOT USED
    CASELAB COPY                  13:  POINTER MANIPULATION:
    CASELAB MOVE_OWN              14:
    CASELAB MOVE_MAN              15:
    CASELAB FIRSTINSET            16:
    CASELAB NXTINSET              17:
    CASELAB REFEQUAL              18:
    CASELAB DECL_PROC             19:  PROCESS MANAGEMENT:
    CASELAB NEW_ST_CALL           20:
    CASELAB ABORT                 21:
    CASELAB SPEED_UP              22:
    CASELAB SET_MODE              23:
    CASELAB TEST_SPEED            24:
    CASELAB ER_ADDR1              25:  NOT USED
    CASELAB DECL_ENV              26:  IDENTIFICATION CONTROL:
    CASELAB INSP_OBJ              27:
    CASELAB INSP_ACT              28:
    CASELAB INSP_CALL             29:
    CASELAB INSP_PROC             30:
    CASELAB SET_CAPS              31:
    CASELAB ER_ADDR1              32:  NOT USED
    CASELAB MAP_SEGM              33:  EXECUTION CONTROL:
    CASELAB GET_TIME              34:  GET_TIME
    CASELAB ER_ADDR1              35:  SET_SLICE
    CASELAB NIOBEGIN              36:
    CASELAB NIO_END               37:
    CASELAB NABSADDR              38:
    CASELAB ER_ADDR1              39:  INTERRUPT SIGNAL
    CASELAB TESTDUMP              40: ONLY IN TEST VERSION OF KNEL
MAXFNC     EQU 40*2
 
  ENDI                              END "NORMAL MODE"
    PAGE
*                                 "CALLER IN RESIDENT MODE"
    CASEJMP D5                      CASE KERNEL FUNCTION OF
 
    CASELAB OBJ_RES                0:  CALL AND RETURN:
    CASELAB OBJ_RRET               1:
    CASELAB ER_ADDR1               2:  OBJECT CREATE AND DELETE:
    CASELAB ER_ADDR1               3:
    CASELAB ER_ADDR1               4:
    CASELAB ER_ADDR1               5:
    CASELAB ER_ADDR1               6:
    CASELAB ER_ADDR1               7:
    CASELAB ER_ADDR1               8:
    CASELAB ER_ADDR1               9:
    CASELAB ER_ADDR1              10:
    CASELAB ER_ADDR1              11:
    CASELAB ER_ADDR1              12:
    CASELAB ER_ADDR1              13:  POINTER MANIPULATION:
    CASELAB ER_ADDR1              14:
    CASELAB ER_ADDR1              15:
    CASELAB ER_ADDR1              16:
    CASELAB ER_ADDR1              17:
    CASELAB ER_ADDR1              18:
    CASELAB ER_ADDR1              19:  PROCESS MANAGEMENT:
    CASELAB ER_ADDR1              20:
    CASELAB ER_ADDR1              21:
    CASELAB ER_ADDR1              22:
    CASELAB SET_MODE              23:  PROPAGATE MODE  (TO DEVICE CONDITION)
    CASELAB ER_ADDR1              24:
    CASELAB ER_ADDR1              25:
    CASELAB ER_ADDR1              26:  IDENTIFICATION CONTROL:
    CASELAB ER_ADDR1              27:
    CASELAB ER_ADDR1              28:
    CASELAB ER_ADDR1              29:
    CASELAB ER_ADDR1              30:
    CASELAB ER_ADDR1              31:
    CASELAB ER_ADDR1              32:
    CASELAB MAP_SEGM              33:  EXECUTION CONTROL:
    CASELAB GET_TIME              34:  GET_TIME
    CASELAB ER_ADDR1              35:
    CASELAB RIOBEGIN              36:
    CASELAB RIO_END               37:
    CASELAB RABSADDR              38:
    CASELAB ER_ADDR1              39:
    CASELAB TESTDUMP              40:
    PAGE
* INTERNAL EXCEPTIONS:
 
TR_BUS     MOVE.L #2,-(A7)        BUS ERROR: 8 BYTES INF SAVED BY HARDWARE
           BRA.L INT_EXC              GOTO COMMON ADDR EXC;
 
TR_ADDR    MOVE.L #3,-(A7)        ADDRESS ERROR: 8 BYTES INF SAVED BY H/W
           BRA.L INT_EXC
 
TR_ILLE    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #4,-(A7)        ILLEGAL INSTRUCTION:
           BRA.L INT_EXC
 
TR_ZDIV    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #5,-(A7)        ZERO DIVIDE:
           BRA.L INT_EXC
 
TR_CHK     SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #6,-(A7)        CHK INSTRUCTION:
           BRA.L INT_EXC
 
TR_TRAPV   SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #7,-(A7)        TRAPV INSTRUCTION:
           BRA.L INT_EXC
 
TR_PRIV    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #8,-(A7)        PRIVILEGED INSTRUCTION:
           BRA.L INT_EXC
 
TR_TRACE   SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #9,-(A7)        TRACE
           BRA.L INT_EXC
 
TR_1010    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #10,-(A7)       1010 EMULATOR
           BRA.L INT_EXC
 
TR_1111    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #11,-(A7)       1111 EMULATOR
           BRA.L INT_EXC
 
TR_TR0     SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #32,-(A7)       TRAP0
           BRA.L INT_EXC
 
TR_TR1     SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #33,-(A7)       TRAP1
           BRA.S INT_EXC
 
TR_TR2     SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #34,-(A7)       TRAP2
           BRA.S INT_EXC
 
TR_TR3     SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #35,-(A7)       TRAP3
           BRA.S INT_EXC
 
TR_TR4     SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #36,-(A7)       TRAP4
           BRA.S INT_EXC
 
TR_TR5     SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #37,-(A7)       TRAP5
           BRA.S INT_EXC
 
TR_TR6     SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #38,-(A7)       TRAP6
           BRA.S INT_EXC
 
TR_TR9     SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #41,-(A7)       TRAP 9 (TRAP 7 AND 8: KERNEL ENTRY)
           BRA.S INT_EXC
 
TR_TR10    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #42,-(A7)       TRAP10
           BRA.S INT_EXC
 
TR_TR11    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #43,-(A7)       TRAP11
           BRA.S INT_EXC
 
TR_TR12    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #44,-(A7)       TRAP12
           BRA.S INT_EXC
 
TR_TR13    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #45,-(A7)       TRAP13
           BRA.S INT_EXC
 
TR_TR14    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #46,-(A7)       TRAP14
           BRA.S INT_EXC
 
TR_TR15    SUBQ.L #8,A7           PUSH DUMMY INF
           MOVE.L #47,-(A7)       TRAP15
           BRA.S INT_EXC
 
TR_SPEED   SUBQ.L #8,A7           DUMMY INF
           CLR.L  -(A7)           CAUSE:=0;
*          BRA.S INT_EXC
 
INT_EXC    EQU *
 
* CALL:    THE STACK MUST CONTAIN: 12 BYTES INF, SR, PC
*          INF IS LOADED INTO D3/D5/D6/D7 AS SHOWN BELOW
*
* AT RETURN TO ENTRY POINT OF THE USER CODE SEGMENT:
* D0 = 0 (EXCEPTION ENTRY),
* D1 = A7       <==>  NO REGISTERS SAVED ON STACK
* D1 = A7-70    <==>     REGISTERS SAVED ON STACK BETWEEN D1 AND A7
* D2 = SR , D3 = INF (CAUSE) , D4 = PC , D5 = INF (R/W,FUNCTION)
* D6 = INF (ACCESS ADDRESS) , D7 = INF (INSTRUCTION REGISTER)
* A0-A3 UNDEF, A4-A7 UNCHANGED
 
* MAPS THE CODE SEGMENT IN LOCAL(1) AND REENTERS THE CURRENT OBJECT.
* THE ORIGINAL USER REGISTERS ARE SAVED ON STACK
* OTHER SEGMENT MAPPING IS UNCHANGED - THUS THE USER MAY NOT
* HAVE A STACK SEGMENT AVAILABLE.
* RETURNS TO THE PREVIOUS CONTEXT IN ERROR CASES: LOCAL(1) IS
* NOT CODE SEGMENT, CONTEXT RESIDENT BUT CODE SEGMENT NOT.
* HALTS THE CPU WHEN SUPERVISOR MODE CAUSES EXCEPTION.
 
***
    PRT_REG EXCEPTION
    PRT_MEM SUPV_STACK,(A7),64
    MOVE   #$2700,SR                  DISABLE;
    MOVEM.L D0-D7/A0-A3,-(A7)         SAVE ORIGINAL REGISTERS
    MOVE.L 48(A7),D3                  D3.L:= CAUSE
    MOVE.W 52(A7),D5                  D5.W:= R/W, FUNCTION
    MOVE.L 54(A7),D6                  D6.L:= ACCESS ADDRESS
    MOVE.W 58(A7),D7                  D7.W:= INSTRUCTION REGISTER
    MOVEM.L A4-A6,48(A7)              INF:= ORIGINAL  A4-A6
    MOVE.W 60(A7),D4                  D4:=CALLERS STATUS REGISTER
    MOVEM.L D1/D3/D5/D6/D7,-(A7)      SAVE ENTRY REGS, D1 IS ASSIGNED LATER
    AND    #$2700,D4                  D4:=CALLERS SUPV MODE+INTRPT MASK;
    CMP    #$2000,D4                  IF SUPV MODE AND INTRPT MASK >0
    BGT    HALT                       THEN HALT END;
    AND    #$700,D4                   D4:=RESIDENT:=INTRPT MASK;
    MOVE.L KV_CTX,A3                  A3:=CURRENT CTX;
    MOVE.L CT_OBJ(A3),A6              A6:=CTX.CURRENT OBJ; "NOT ABORTED"
    MOVE.L OB_SPA(A6),A5
    MOVE.L SP_ENV+4(A5),A5            A5:=TOP ENVELOPE;
    MOVE.B PT_KIN+EN_SIZ-EN_STK(A5),D0  D0:=L(1).POINTER_KIND;
    TST.W  D4
  IF <NE> THEN.S                    IF EXCEPTION FROM RESIDENT CTX THEN
    BTST.B #PT_RES,PT_INF+EN_SIZ-EN_STK(A5)
    BEQ.L  EXC_UNDEF                IF L(1) NOT RESIDENT THEN RETURN TO PREV
*   THE SEGMENT ADDRESSED BY 'USP' BELOW WILL BE RESIDENT BECAUSE IT IS MAPPED
  ENDI                              ENDI;
  IF.B D0 <EQ> #PT_OBJ THEN.S       IF OBJ_REF THEN
    MOVE.L PT_REF+EN_SIZ-EN_STK(A5),A5  A5:=CODE OBJ:=OBJ REFERENCED
  ELSE.S                            ELSE
    CMP.B  #PT_OWN,D0                 IF NOT OWN SET
    BNE.L  EXC_UNDEF                  THEN RETURN TO PREV CTX END;
    MOVE.L 4+EN_SIZ-EN_STK(A5),A5     A5:=CODE OBJ:=LAST IN SET
  ENDI                              END;
    CMP.B #OB_SEOB,OB_KIN(A5)       IF CODE OBJ.KIND<>SEGMENT THEN
    BNE.L  EXC_UNDEF                THEN GOTO ERROR
* PROBLEM:: SEGMENT MAY STILL BE A SUBSEGMENT WITH NO BASE SEGMENT !!!!!
    CLR.L  D0                         D0:=LOGICAL ADDRESS:=0;
    LEA    CT_MM1(A3),A1              A1:=MMU DESCR 1;
    TST    D4
  IF <NE> THEN.S                    IF CALLER RESIDENT THEN
    TST    OB_RES(A5)                 IF CODE_OBJ NOT RESIDENT
    BEQ.L  EXC_UNDEF                  THEN RETURN TO PREV CTX END;
  ENDI                              END;
    MOVE   D4,D3                      D3:=RESIDENT OR NORMAL;
    BSR    MAP_RESOK                  MAP RES OR NORMAL (MMU,SEGM,
*                                       LOG ADDR,D1/D2:=UNDEF);
* A6 = OBJECT TO CALL     DUMP REGISTERS ABOVE USP
    MOVE.L USP,A4                     A4:= USER STACK POINTER
    MOVE.L A4,D3                      D3:= USER STACK POINTER
    BSR.L  CONVADDR                   D3:= ABS_ADDR(USP); D5:= MMU
    BEQ.S  NOREGSAVE                  WHEN ERROR GOTO NOREGSAVE
    MOVE.W D5,D4                      D4:= MMU OF USP
    LEA    -70(A4),A0                 A0:= DUMP ADDRESS; "FUTURE D1"
    MOVE.L A0,D3                      D3:= DUMP ADDRESS;
    BSR.L  CONVADDR                   D3:= ABS_ADDR(D3); D5:= MMU
    BEQ.S  NOREGSAVE                  WHEN ERROR GOTO NOREGSAVE
    CMP.W  D4,D5                      WHEN MMU OF USP <> MMU OF DUMP ADDRESS
    BNE.S  NOREGSAVE                  THEN GOTO NOREGSAVE
* ROOM FOR DUMP IS AVAILABLE BETWEEN DUMP ADDRESS AND USP
    MOVE.L A0,(A7)                    SAVED FUTURE D1:= USP-70;
    MOVE.L D3,A5                      A5:= DUMP ADDRESS
    MOVEM.L 20(A7),D0-D7/A0-A3        MOVE REGISTERS TO DUMP ADDRESS
    MOVEM.L D0-D7/A0-A3,(A5)          D0-D7/A0-A3
    MOVEM.L 68(A7),D4-D6
    MOVEM.L D4-D6,48(A5)              A4-A6
    MOVE.L  A4,60(A5)                 USP
    MOVEQ.L #1,D3                     REGSSAVED:= TRUE;
    BRA.S   CONTSAVE                  GOTO CONTINUE SAVE
NOREGSAVE EQU *                   NOREGSAVE:
    MOVEQ.L #0,D3                     REGSSAVED:= FALSE;
    MOVE.L A4,(A7)                    SAVED FUTURE D1:= USP
CONTSAVE  EQU *                   CONTINUE SAVE:
* A6=OBJ, D3 = REGSSAVED, A5 = DUMP ADDRESS / UNDEFINED
    MOVE.W  80(A7),D2                 D2:= SR FROM STACK
    MOVE.L  GE_ENT(A6),D0             D0:= ENTRY POINT OF OBJECT
    BTST.L  #5+8,D2
  IF <EQ> THEN.S                    IF NO TIME OUT PENDING THEN
    MOVE.L  82(A7),D4                 D4:= ORIGINAL PC:= STACKED PC;
    MOVE.L  D0,82(A7)                 STACKED PC:= ENTRY POINT ADDRESS;
  ELSE.S                            ELSE
    MOVE.W  SAVE_PC,D2                D2:= ORIGINAL SR:= SAVED SR;
    MOVE.L  SAVE_PC,D4                D4:= ORIGINAL PC:= SAVED PC;
    MOVE.L  D0,SAVE_PC                SAVED_PC:= ENTRY POINT ADDRESS OF OBJ;
  ENDI                              ENDI;
    TST.B  D3
  IF <NE> THEN.S                    IF REGSSAVED THEN "SAVE SR AND PC"
    MOVE.W  D2,64(A5)                 DUMP.SR:= ORIGINAL SR;
    MOVE.L  D4,66(A5)                 DUMP.PC:= ORIGINAL PC;
  ENDI                              ENDI;
    MOVEQ.L #0,D0                     D0:=ENTRY FUNC:= EXCEPTION ENTRY;
    MOVEM.L (A7)+,D1/D3/D5/D6/D7      LOAD ENTRY REGISTERS
    LEA     48(A7),A7                 POP SAVED ORIGINAL REGS EXCEPT A4-A6
    MOVE.L  KV_CTX,A3                 A3:= CURRENT CONTEXT;
    BCLR.B  #7,CT_SPE(A3)             CLEAR SPEEDUP EXCEPTION (IF PENDING)
    AND.B   #3,CT_MODE(A3)            CLEAR EXCEPTION MODE OF CONTEXT
*** PRT_MEM REENTER_CTX,(A3),CT_SIZ
    BRA.L   RET_OLD3                  GOTO RETURN;"A4-A6,SR,PC ON STACK"
 
 
EXC_UNDEF  EQU *                 RETURN TO PREV CTX:
    ADD.W  #68,A7                     POP REGISTERS; A7.L:=A7.L + 68;
    CLR.L  D6                         D6/D7:=RESULT:=STATUS,DUMMYFIED;
    MOVE.L #ECSDUMMY,D7
    MOVE.L A3,A2                      A2:=CURRENT CTX;
    TST    D4                       IF CALLER NORMAL MODE THEN
    BEQ    OBJ_RET                    OBJ_RETURN
    BRA    OBJ_RRET                 ELSE RESIDENT_RETURN END;
    PAGE
    SECTION 11                    INITIALIZATION SECTION
 
I_KNELOP   EQU *
    LEA    KV_INVEC,A0            A0:=BASE EXCEPTION VECTORS  (ZERO NORMALLY)
    MOVE.L #TR_ADDR,12(A0)        INITIALIZE INTERNAL EXCEPTION VECTORS
    MOVE.L #TR_BUS,8(A0)
    MOVE.L #TR_ILLE,16(A0)
    MOVE.L #TR_ZDIV,20(A0)
    MOVE.L #TR_CHK,24(A0)
    MOVE.L #TR_TRAPV,28(A0)
    MOVE.L #TR_PRIV,32(A0)
    MOVE.L #TR_TRACE,36(A0)
    MOVE.L #TR_1010,40(A0)
    MOVE.L #TR_1111,44(A0)
    MOVE.L #TR_TR0,128(A0)
    MOVE.L #TR_TR1,132(A0)
    MOVE.L #TR_TR2,136(A0)
    MOVE.L #TR_TR3,140(A0)
    MOVE.L #TR_TR4,144(A0)
    MOVE.L #TR_TR5,148(A0)
    MOVE.L #TR_TR6,152(A0)
    MOVE.L #TR_TR7,156(A0)
    MOVE.L #-1,DRIV_TAB+156           RESERVE TRAP #7
    MOVE.L #-1,STAK_TAB+156
    MOVE.L #TR_TR10,168(A0)
    MOVE.L #TR_TR11,172(A0)
    MOVE.L #TR_TR12,176(A0)
    MOVE.L #TR_TR13,180(A0)
    MOVE.L #TR_TR14,184(A0)
    MOVE.L #TR_TR15,188(A0)
    BRA    I_ENTER                CONTINUE INITIALIZATION
 
    SECTION 9                     NORMAL CODE SECTION
    PAGE
* RETURNS CAN TAKE PLACE THROUGH JUMPS TO THESE LABELS:
 
* RETURN:    RTS  (IN C_ENT).
* RET_OLD2:  RETURN TO USER, A2=CUR_CTX, ABORT CHECKED AND MMU LOADED
* RET_OLD3:  RETURN TO USER, A3=CUR_CTX, ABORT CHECKED AND MMU LOADED
* RET_FAST:  RETURN TO USER, NO CHECK.  (IN OBJ_CALL LIKE RET_OLD2, RET_OLD3)
* HALT:      STOP, KERNEL ERROR.  (IN C_NXT_M)
* ER_XXX:  ERROR RETURN, SR:=EQ "NOT OK", RTS.  (SEE BELOW)
* EE_XXX:  ERROR EXIT,   A2=CUR_CTX, RETURN TO USER.  (SEE BELOW)
 
ER_ADDR    MOVE.L #ECRADDR,D7         ADDRESS ILLEGAL: D7:=RESULT
           CMP    D7,D7                   SR:=EQ;  "NOT OK"
           RTS                            RETURN
 
ER_ADDR1   EQU *
EE_ADDR    MOVE.L #ECRADDR,D7
           BRA    RET_OLD2
 
ER_FUNC    MOVE.L #ECRFUNC,D7         FUNCTION ILLEGAL:
           CMP    D7,D7
           RTS
 
ER_SCOPE   MOVE.L #ECRSCOPE,D7        POINTER SCOPE ILLEGAL:
           CMP    D7,D7
           RTS
EE_SCOPE   MOVE.L #ECRSCOPE,D7
           BRA    RET_OLD2
 
ER_VALUE   MOVE.L #ECRVALUE,D7        POINTER VALUE ILLEGAL:
           CMP    D7,D7
           RTS
EE_VALUE   MOVE.L #ECRVALUE,D7
           BRA    RET_OLD2
 
* ER_RETURN                       RETURN POINTER ILLEGAL:
*          SPECIAL CONVENTIONS, SEE RET_FP
 
ER_STATE   MOVE.L #ECRSTATE,D7        OBJECT STATE ILLEGAL:
           CMP    D7,D7
           RTS
EE_STATE   MOVE.L #ECRSTATE,D7
           BRA    RET_OLD2
 
ER_DATA    MOVE.L #ECRDATA,D7         DATA VALUE ILLEGAL:
           CMP    D7,D7
           RTS
EE_DATA    MOVE.L #ECRDATA,D7
           BRA    RET_OLD2
 
ER_CAP     MOVE.L #ECRCAP,D7          CAPABILITY VIOLATION:
           CMP    D7,D7
           RTS
 
ER_CONC    MOVE.L #ECRCONC,D7         CONCURRENCY VIOLATION:
           CMP    D7,D7
           RTS
 
ER_SELF    MOVE.L #ECRSELF,D7         SELF DELETION:
           CMP    D7,D7
           RTS
 
ER_OBJSP   MOVE.L #ECROBJSP,D7        OBJECT SPACE LIMITED:
           CMP    D7,D7
           RTS
EE_OBJSP   MOVE.L #ECROBJSP,D7
           BRA    RET_OLD2
 
ER_PROSP   MOVE.L #ECRPROSP,D7        PROCESS SPACE LIMITED:
           CMP    D7,D7
           RTS
EE_PROSP   MOVE.L #ECRPROSP,D7
           BRA    RET_OLD2
 
ER_ENVLIM  MOVE.L #ECRENVLIM,D7        OWNER ENVELOPE LIMITED:
           CMP    D7,D7
           RTS
 
ER_CONLIM  MOVE.L #ECRCONLIM,D7        OWNER CONTEXT LIMITED:
           CMP    D7,D7
           RTS
 
ITSTDUMP   EQU *  TESTDUMP CALLED FROM INTERRUP PROCEDURE, SET UP A4
    MOVE.L D4,A4     A4:= TOP_ARG := LOW_ARG
    ADDA.L D2,A4                   + LENGTH;
TESTDUMP   EQU *  D5=OP=FUNC<<16+11, D4/A4 DEFINES AREA TO BE PRINTED
*
    SWAP D5                       D5.W:= FUNC
    LSL.W #1,D5
    CMP.W #2*2,D5
  IF <HI> THEN.S
DUMP_ERR EQU *
    MOVE.L #ECRADDR,D7
    BRA.L  RET_FAST
  ENDI
    CASEJMP D5
    CASELAB DUMP_ERR
    CASELAB TEXT_OUT
    CASELAB HEX_OUT
 
TEXT_OUT EQU *  FUNC=1,PRINT AS TEXT, AT RETURN: D0=0 <=> PANEL SWITCH ENABLED
    MOVE.L  D4,A3                 A3:= FIRST OF TEXT
    LEA     96(A3),A1
  IF.L A4 <GT> A1 THEN.S        IF MORE THEN ONE LINE THEN
    MOVE.L A1,A4                  CUT TO ONE LINE
  ENDI                          ENDI;
    BSR.L  TEXTLINE               TEXTLINE(A3,A4) D0:=ON/OFF
    CLR.L  D7                     RESULT:= OK;
    BRA.L  RET_FAST               RETURN
 
HEX_OUT  EQU *  FUNC=2,PRINT AS HEX DIGITS
    MOVE.L D4,A0
    MOVE.L A4,A2
    BSR.L  PRINTA02               PRINTA02(A0,A2)
    CLR.L  D7                     RESULT:=OK
    BRA.L  RET_FAST               RETURN
 
    TTL    CALL AND RETURN
    PAGE
OBJ_CALL   EQU *                  OBJ_CALL FROM NORMAL CONTEXT
 
*          CALL:                  ENTER NEW CTX:    RETURN OLD CTX:
* A0/A1    -                      UNDEF             UNDEF
* A2       CUR_CTX                UNDEF             UNDEF
* A3       -                      UNDEF             UNDEF
* A4       ARGUMENT ADDR (PHYS)   UNDEF             SAVED VALUE
* A5       -                      FIRST TEMP        SAVED VALUE
* A6       -                      TOP VALUE         SAVED VALUE
* D0       -                      FUNCTION CODE     UNDEF
* D1-2     -                      UNDEF             UNDEF
* D3.W     0 (NOT RESIDENT)       #FORMALS          UNDEF
* D4       LOW ARG ADDR (PHYS)    UNDEF             UNDEF
* D5       -                      UNDEF             UNDEF
* D6-7     ARGUMENT#,UNDEF        UNDEF             RESULT
* STACK:   SAVED A4-A6,SR,PC      (USER STACK)      (USER STACK)
 
    MOVE.L CT_HOLD(A2),A0             A0:=CUR_CTX.EXTENSION_OBJ;
    BSR    C_CALL                     CHECK_CALL(A0,...,A5:=OBJ,D5:=FUNCTION);
*                                 "WILL COMPLETE KERNEL OBJECT CALLS"
    BEQ    RET_OLD2                 IF RETURN THEN RETURN (A2=CTX) END;
    CLR    D3                         D3:=ADDITIONAL FORMALS:=0;
    BSR    CRE_CTX                    CREATE_CTX(...,A3:=NEW_CTX,D4:=ENTRY,
*                                       A1/A5/A6/D0-D2:=UNDEF);
    BEQ.S  RET_FAST                 IF NOT OK THEN RETURN "NO ABORT" END;
 
    MOVE   USP,A1                 "SAVE SUPV.STACK ETC. IN OLD_CTX:"
    MOVE.L A1,CT_USP(A2)              SAVE USER STACK POINTER;
    MOVEM.L -2(A7),D0-D3/D7           D0-D3.LEFT:=SAVED A4-A6;
    BTST.L #5+8,D3                    D3.RIGHT:=SR; D7:=PC;
  IF <NE> THEN.S                    IF TIME OUT PENDING "SUPV MODE" THEN
    MOVE.W SAVE_SR,D3                 D3.RIGHT:=SAVED SR;
    MOVE.L SAVE_PC,D7                 D7:=SAVED PC;
    MOVE.L D4,SAVE_PC                 SAVED PC:=ENTRY
  ELSE.S                            ELSE
    MOVE.L D4,14(A7)                  SUPV_STACK.PC:=ENTRY;
  ENDI                              END;
    MOVEM.L D0-D3/D7,CT_WRK-20(A2)    CTX.SAVE:=SAVED A4-A6,SR,PC;
    MOVE.L D5,(A7)                    SUPV_STACK.FUNCTION:=FUNCTION;
 
    CLR    D3                         D3:=ADDITIONAL FORMALS:=0;
    BSR    SET_FP                     SET_FORMALS(...,D3:=#FORMALS,USP:=...,
*                                       A1/A5/A6/D0-D2/D4/D5:=UNDEF);
  IF <NE> THEN.S                    IF OK THEN
    BSR    ENT_CTX                    ENTER CONTEXT(A3=CTX,D3=#FORMALS)
*                                 "CONTINUES HERE AT OBJ_RETURN. A3=CTX"
    BSR    RET_FP                     RETURN FORMALS(A3=CTX,D6/D7:=UPDATED);
  ENDI                              END;
    BSR    DEL_CTX                    DELETE_CTX(CTX,A3:=OLD CTX,A0:=EXT);
 
    MOVEM.L CT_WRK-20(A3),D0-D4   "RESTORE SUPV_STACK AND USP FROM OLD CTX:"
    BTST.B #5,12(A7)                  D0-D4:=CTX.SAVE A4-A6,SR,PC;
  IF <NE> THEN.S                    IF TIME OUT PENDING "SUPV MODE" THEN
    MOVE.W D3,SAVE_SR                 SAVED SR:=CTX.SR;
    MOVE.L D4,SAVE_PC                 SAVED PC:=CTX.PC;
    MOVE.W 12(A7),D3                  D3.RIGHT:=SUPV_STACK.SR;
    MOVEM.L D0-D3,-2(A7)              SUPV STACK.A4-A6:=CTX.A4-A6;
  ELSE.S                            ELSE
    MOVEM.L D0-D4,-2(A7)              SUPV STACK.A4-A6,SR,PC:=CTX. ...
  ENDI                              END;
    MOVE.L CT_USP(A3),A5              RESTORE USP;
    MOVE   A5,USP
 
RET_OLD3   EQU *                  RETURN_TO_OLD_CTX:  "A3=CTX"
    BSR    PREP_RET                   PREPARE_RETURN;  "MAY PERFORM OBJ_RETURN"
  IF <LT> THEN.S                    IF SPEEDUP EXCEPTION THEN
    MOVEM.L (A7)+,A4-A6               RESTORE REGS
    BRA.L  TR_SPEED                   GOTO SPEEDUP EXCEPTION
  ENDI                              ENDI;
 
RET_FAST   EQU *                  RETURN_FAST:
    MOVEM.L (A7)+,A4-A6               RESTORE A4-A6;
***
    PRT_REG KNEL_EXIT
    RTE                               RETURN TO USER MODE;
    PAGE
OBJ_RES    EQU *                  OBJ_CALL FROM RESIDENT CONTEXT
 
* CALL AND RETURN AS FOR OBJ_CALL.  HOWEVER, D3<> 0 "RESIDENT".
 
    MOVE.L CT_HOLD(A2),A0             A0:=CUR_CTX.EXTENSION_OBJ;
    BSR    C_CALL                     CHECK_CALL(A0,...);
*                                 "WILL COMPLETE KERNEL OBJECT CALLS"
    BNE    EE_STATE                 IF ENTER THEN REJECT END;
 
RET_OLD2   EQU *                  RETURN_TO_OLD_CTX: "A2=CTX"
    MOVE.L A2,A3                      A3:=CTX;
    BRA    RET_OLD3                   RETURN (A3=CTX);
 
 
OBJ_RRET   EQU *                  OBJ_RETURN, RESIDENT CONTEXT
 
* CALL AND RETURN: AS OBJ_RET
 
    BSR    FORCE_OPEN                 FORCE DEVICE GATE OPEN (A2=CTX);
* CONTINUE WITH OBJ_RET.  OBJECT MAY BE ABORTED DURING FORCE_OPEN.
 
 
OBJ_RET    EQU *                  OBJ_RETURN, NORMAL CONTEXT
 
*          CALL:                  CONTINUE IN KERNEL:
* A2       CUR_CTX                SAME
* A3       -                      CUR_CTX
* D6/D7    RESULT                 SAME
* STACK:   SAVED A4-A6,SR,PC      SAME
 
    MOVE.L CT_CON(A2),-(A7)
    MOVE.L A2,A3                      A3:=CUR_CTX;
    RTS                               RETURN TO CUR_CTX.CONTINUE_ADDR;
 
ENT_CTX    EQU *                  ENTER CONTEXT
 
*          CALL:                  ENTRY TO NEW CTX:
* A3       NEW CTX                UNDEF
* D2-D5 ENTRY VALUES TO USER CTX  SAME  (IMPLICIT,#FORMALS,INDEX/CAP,BYTES)
* A5/A6/D0 -                      FTMP,TOPVAL,FNC
* STACK: RETURN,FNC,FTMP,TOPVAL,SR,PC  (USER STACK)
 
* SAVES RETURN POINT IN CONTEXT.  USES PREP_RET TO TEST FOR ABORTED AND
* LOAD MMU.  ENTERS USER CONTEXT IF NOT ABORTED.
 
    MOVE.L (A7)+,CT_CON(A3)           CTX.CONTINUE_ADDR:=POP RETURN;
    BSR.S  PREP_RET                   PREPARE RETURN; "MAY PERFORM OBJ_RETURN"
    MOVEM.L (A7)+,D0/A5/A6            D0/A5/A6:=POP;
*   BLT.L  TR_SPEED !!!CANNOT OCCUR, BECAUSE EXC_MODE OF A NEW CTX IS ZERO!!!
***
    PRT_REG ENT_CTX
    RTE                               RETURN TO USER MODE;
    PAGE
 
PREP_RET   EQU *                  PREPARE RETURN
 
*          CALL:                  RETURN:
* A3       CTX                    SAME
* A4       -                      UNDEF
* CCR      -                      LT <==> SPEEDUP EXCEPTION IS PENDING
* STACK: RETURN,SAVED A4-A6,SR,PC IF ABORTED: TO OBJ_RET
*                                 ELSE: NORMAL RETURN
 
* IF CONTEXT IS ABORTED, CONTINUES WITH OBJ_RET.
* ELSE SETS CURRENT CONTEXT (KV_CTX) AND LOADS MMU.
* THE CALLER OF PREP_RET MUST CHECK THE CCR AT RETURN -
* IF CCR=<LT>, THE CALLER MUST RESTORE REGS AND GOTO TR_SPEED
 
    TST.L  CT_OBJ(A3)
  IF <EQ> THEN.S                    IF CTX.CUR_OBJ=ABORTED THEN
    MOVE.L A3,A2                      A2:=CUR_CTX;
    MOVE.L #ECSDUMMY,D7
    CLR.L  D6                         D6/D7:=RESULT:=STATUS,DUMMYFIED;
    TST.L  (A7)+                      POP RETURN;
    TST    CT_RES(A3)               IF CTX NORMAL MODE THEN
    BEQ    OBJ_RET                    GOTO OBJ_RETURN, NORMAL
    BRA    OBJ_RRET                 END;  GOTO OBJ_RETURN, RESIDENT;
  ENDI                              END;
    MOVE.L A3,KV_CTX                  CURRENT_CONTEXT:=CTX;
 
* CONTINUE IN LOAD_MMU
 
 
LOAD_MMU   EQU *                  LOAD MMU REGISTERS
 
*          CALL:                  RETURN:
* A3       CTX                    SAME
* A4       -                      UNDEF
* CCR      -                      <LT>  <==>  SEE PREP_RET ABOVE
 
    LEA    KV_MMU,A4                  A4:=MMU REG ADDR;
    MOVE.L CT_MM0+MM_REG(A3),(A4)+    COPY FROM CTX.MMU TO MMU REG;
    MOVE.L CT_MM0+MM_REG+4(A3),(A4)+
    MOVE.L CT_MM1+MM_REG(A3),(A4)+
    MOVE.L CT_MM1+MM_REG+4(A3),(A4)+
    MOVE.L CT_MM2+MM_REG(A3),(A4)+
    MOVE.L CT_MM2+MM_REG+4(A3),(A4)+
    MOVE.L CT_MM3+MM_REG(A3),(A4)+
    MOVE.L CT_MM3+MM_REG+4(A3),(A4)+
 
***
    PRT_MEM MMU0,CT_MM0(A3),MM_SIZ
    PRT_MEM MMU1,CT_MM1(A3),MM_SIZ
    PRT_MEM MMU2,CT_MM2(A3),MM_SIZ
    PRT_MEM MMU3,CT_MM3(A3),MM_SIZ
    TST.B  CT_SPE(A3)                 CCR:= SPEEDUP EXCEPTION;
    RTS                               RETURN
 
    PAGE
CRE_CTX    EQU *                  CREATE CONTEXT
 
*          CALL:                  RETURN:
* A0       EXT OBJECT             SAME
* A2       OLD_CTX                SAME  (SPECIFIES OLD SPEED-UP ETC.)
* A3       -                      NEW_CTX
* A4       ARGUMENT ADDR          SAME  (FOR FINDING #FORMALS)
* A5       OBJECT TO CALL         UNDEF  (GENERAL OBJECT, POSSIBLY ABORTED)
* D3.W     ADDITIONAL FORMALS     SAME  (0 FOR OBJ_CALL,2 FOR DEALLOC,
*                                        1 FOR CONTROL)
* D4.L     LOW ARG ADDR (PHYS)    ENTRY ADDRESS
* D7.L     -                      UNDEF IF OK, RESULT IF NOT OK
* A1/A6/D0-D2      -              UNDEF
* SR       -                      NE=OK, EQ=NOT OK (NO SPACE ONLY)
 
* CREATES A CONTEXT INCLUDING TEMP AND FORMAL POINTERS.
* MAPS CODE SEGMENT TO MMU DESCR1 IF OBJECT IS NON-ABORTED (AVOIDS HAVING
* ENVELOPES ETC. IN A DUMMY MANAGER). INITIALIZES ALL FIELDS SO THAT
* DEL_CTX CAN BE PERFORMED IN CASE SET_FP FAILS.
 
*                                 "RESERVE SPACE FOR CONTEXT:"
    SUB.L  A4,D4                      D4:=NEGATIVE #FORMALS:=
    DIVS   #AR_SIZ,D4
    BVS    ER_PROSP                   (LOW_ARG-ARG)/ARG_SIZE+1
    ADDQ   #1,D4                      "VAL DATA NOT IN FORMALS"
    SUB    D3,D4                      -ADDITIONAL FORMALS;
    BVS    ER_PROSP                   "D4 WORD ENSURED"
    MULS   #FP_SIZ,D4                 D4:=-SIZE OF FORMALS;
    MOVE   GE_TEMP(A5),D0             D0:=SIZE OF TEMPS:=
    MULU   #PT_SIZ,D0                   OBJ.TEMP_POINTERS * POINTER SIZE;
    SUB.L  D4,D0                      D0:=SIZE OF TEMPS AND FORMALS;
    CMPI.L #$8000-CT_SIZ,D0         IF D0 >=1<<15-CTX_SIZE "UNSIGNED" THEN
    BCC    ER_PROSP                   REJECT END; "D0=WORD ENSURED"
    ADD    #CT_SIZ,D0                 D0:=SIZE OF CONTEXT+TEMPS+FORMALS;
    BSR    MM_PUSHK                   RESERVE_STACK_ELEM(EXT OBJ,D0=SIZE,
*                                       A3:=NEW CTX,A6:=TOP OBJ);
    BEQ    ER_PROSP                 IF NOT OK THEN REJECT END;
    LEA    EX_CTX(A0),A1              A1:=EXT_OBJ.CTX STACK HEAD;
    LEA    ST_STK(A3),A3              A3:=CTX.STACK ELEM;
    INS_ELEM A1,A3,A6,A1/A6           INSERT(HEAD=EXT OBJ, NEW=CTX,A6:=PREV);
    LEA    -ST_STK(A3),A3             A3:=NEW CTX;
    ADD    D0,D4                      D4:=NEW_CTX.TOP_TEMP:=
    MOVE   D4,CT_TOPT(A3)               TOP_FORMAL - SIZE OF FORMALS;
    MOVE.L A5,CT_OBJ(A3)              NEW_CTX.EXECUTES:=OBJECT TO CALL;
    LEA    GE_EX(A5),A1
    INS_ELEM A1,A3,A6,A1/A6
    MOVE.L GE_ENT(A5),D4              D4:=ENTRY ADDRESS:=OBJECT TO CALL.ENTRY
 
    BTST.B #OB_ABOR,OB_STA(A5)
  IF <EQ> THEN.S                    IF OBJECT NOT ABORTED THEN
*                                 "FIND CODE SEGMENT:"
    MOVE.L OB_SPA(A5),A6              A6:=TOP OBJECT TO CALL;
    MOVE.L SP_ENV+4(A6),A6            A6:=TOP ENVELOPE TO CALL; "OFFSET"
    MOVE.B PT_KIN+EN_SIZ-EN_STK(A6),D0  D0:=L(1).POINTER_KIND;
  IF.B D0 <EQ> #PT_OBJ THEN.S       IF OBJ_REF THEN
    MOVE.L PT_REF+EN_SIZ-EN_STK(A6),A5  A5:=CODE_OBJ:=OBJECT REFERENCED
  ELSE.S                            ELSE
  IF.B D0 <EQ> #PT_OWN THEN.S       IF OWN_SET THEN
    MOVE.L EN_SIZ+4-EN_STK(A6),A5     A5:=CODE_OBJ:=LAST IN SET
  ENDI                              ELSE A5=GENERAL OBJECT END;
  ENDI                              END;
    CMP.B  #OB_SEOB,OB_KIN(A5)        SR:=CODE_OBJ IS SEGMENT;
  ENDI                              END "OBJECT NOT ABORTED"
 
*                                 "INITIALIZE EXECUTES, SPEED, MMU1:"
  IF <NE> THEN.S                    IF ABORTED OR CODE OBJ NOT SEGMENT THEN
    CLR.L  CT_OBJ(A3)                 NEW_CTX.EXECUTES:=ABORTED;
    MOVE.B #3,CT_MODE(A3)             CTX.MODE:=NO_EXCEPTION/PROPAGATE_SAME;
    MOVE.B #3,CT_SPE(A3)              CTX.SPEED:= UNDEF;
    INIT_HEAD CT_MM1(A3),A1           MMU1.REFERS TO:=DUMMY;
    CLR.L  MM_REF(A1)                 A1=MMU DESCR1;
    CLR    MM_REG+6(A1)               MMU1.ENABLE:=DISABLED
  ELSE.S                            ELSE
    MOVE.B CT_MODE(A2),D0             D0:=NEW_CTX.SPEED:=
    AND.B  CT_SPE(A2),D0                MIN(OLD_CTX.MODE,OLD_CTX.SPEED);
    MOVE.B D0,CT_SPE(A3)                CTX.SPEEDEXC:=FALSE;
    CLR.B  CT_MODE(A3)                NEW_CTX.MODE:=NO_EXCEPTION/STOP ;
    CLR.L  D0                         D0:=LOGICAL ADDRESS:=0;
    LEA    CT_MM1(A3),A1              A1:=MMU DESCR1;
    BSR    MAP_FIRST                  MAP_FIRST_TIME(MMU1,CODE OBJ,LOG ADDR,
*                                       D1-D2:=UNDEF);
    ADD.L  D0,D4                      D4:=ENTRY:=...+ADJUSTED LOGICAL ADDR;
*                                       "CODE SEGM MAY BE SUBSEGM"
  ENDI                              END  "INITIALIZE EXECUTES, ETC";
    MOVE.B #PT_MMU,MM_KIN(A1)         MMU1.KIND:=MMU_REF;
 
*                                 "INIT OTHER MMU DESCRIPTORS"
    INIT_HEAD CT_MM0(A3),A1           MMU0.REFERS TO:=DUMMY;
    CLR.L  MM_REF(A1)
    CLR    MM_REG+6(A1)               MMU0.ENABLE:=DISABLED;
    MOVE.B #PT_MMU,MM_KIN(A1)         MMU0.KIND:=MMU_REF;
    INIT_HEAD CT_MM2(A3),A1           MMU2 ...
    CLR.L  MM_REF(A1)
    CLR    MM_REG+6(A1)
    MOVE.B #PT_MMU,MM_KIN(A1)
    INIT_HEAD CT_MM3(A3),A1           MMU3 ...
    CLR.L  MM_REF(A1)                 A1=MMU DESCR3;
    CLR    MM_REG+6(A1)
    MOVE.B #PT_MMU,MM_KIN(A1)
 
    MOVE   #CT_SIZ,D0             "INIT POINTERS:"
    MOVE   CT_TOPT(A3),D1             D1:=TOP TEMPS;
  WHILE D0 <NE> D1 DO.S             FOR ALL TEMPS IN NEW_CTX DO
    INIT_HEAD <(A3,D0)>,A1            TEMP POINTER:=NIL, TEMP_SCOPE;
    MOVE #PT_NIL<<8+1<<PT_TSC,PT_KIN(A1)
    ADD    #PT_SIZ,D0               ENDF;
  ENDW
    MOVE   CT_TOPF(A3),D1             D1:=TOP FORMALS;
  WHILE D0 <NE> D1 DO.S             FOR ALL FPRMALS IN NEW_CTX DO
    INIT_HEAD <(A3,D0)>,A1            FORMAL POINTER:=NIL, FORMAL SCOPE;
    MOVE #PT_NIL<<8+1<<PT_FSC,PT_KIN(A1)        "A1=POINTER"
    INIT_HEAD FP_ACT(A1),A6           FORMAL POINTER.ACTUAL:=DUMMY
    CLR.L  FP_STR(A1)                 "FP_STR =0 USED BY INSPECT"
    ADD    #FP_SIZ,D0                 D0:= INDEX TO NEXT FORMAL;
  ENDW                              ENDF;
***
    PRT_MEM NEW_CTX,(A3),CT_SIZ+4*PT_SIZ+3*FP_SIZ
    TST    D0                         SR:=NE; "OK"
    RTS                               RETURN;
    PAGE
SET_FP     EQU *                  SET FORMAL POINTERS
 
*          CALL:                  RETURN:
* A0       EXT OBJECT             SAME
* A2       OLD CTX                SAME
* A3       NEW CTX                SAME
* A4       ARGUMENT ADDR          UPDATED
* D3.W     ADDITIONAL FORMALS     #FORMALS IN NEW CTX
* D6.W     ARGUMENT#              UPDATED
* D7.L     -                      UNDEF IF OK, RESULT IF NOT OK
* A1/A5/A6/D0-D2/D4/D5  -         UNDEF
* SR       -                      NE = OK, EQ = NOT OK
* USP      -                      INITIAL VALUE IN NEW CTX
* STACK: ROOM FOR FNC,A5,A6       SAME, FIRST TEMP, TOP VALUE
 
* CHECKS THE VALUE PARAMETER AND CREATES THE TEMP SEGMENT USED
* FOR STACK AND VALUE DATA.  COPIES THE VALUE DATA.
* INITIALIZES T(1) AND MAPS IT TO MMU DESCR 0.
* INTERPRETES ARGUMENTS AND SETS UP FORMAL POINTERS.  CHECKS FREE STACK.
 
    TST    -2(A4)                 "CHECK VAL SUBSEGM:"
  IF <NE> THEN.S                    IF NEXT ARG <> VOID THEN
*                                     CHECK SUBSEGMENT (A1:=PSTR,D1:=PREL,
    BSR    C_SUB                        A5:=BASE SEGM,D0:=TREL,D5:=FREL,
*                                       D2:=LENGTH,D4:=CAPS);
    BEQ    RETURN                   IF NOT OK THEN RETURN END;
    LEA    OB_REF(A5),A6              A6:=BASE_SEGM.REF_HEAD
    MOVE.L A6,D7                      D7:=END OF REF_CHAIN;
    MOVE.L (A6),A6                    A6:= FIRST REF IN REF_CHAIN;
  WHILE.L A6 <NE> D7 DO.S           WHILE NOT END OF REF_CHAIN DO
  IF.L A6 <LE> A2 THEN.S            IF  REF IS NOT AN MMU_REF
    BRA    ER_STATE                       (I.E. THE REF IS NOT LOCATED
  ENDI                                     IN THE FIXED PART
    LEA    -CT_SIZ(A6),A6                  OF THE CALLING CONTEXT)
  IF.L A6 <GE> A2 THEN.S            THEN
    BRA    ER_STATE                     REJECT
  ENDI                              ENDI;
    MOVE.L CT_SIZ(A6),A6              A6:=NEXT REF;
  ENDW                              ENDW;
    BTST.B #OB_SUB,OB_STA(A5)       IF BASE_SEGM IS A SUB_SEGM
    BNE    ER_STATE                 THEN REJECT END;
    BTST.B #PT_TSC,PT_INF(A1,D1)    IF VAL POINTER NOT TEMP
    BEQ    ER_SCOPE                 THEN REJECT END;
    BCLR   #OB_EXEC,D4                D4:=VAL SEGM USE BITS.READ AND WRITE;
    CMPI   #1<<OB_READ+1<<OB_WRIT,D4  IF VAL SEGM NOT READ AND WRITE
    BNE    ER_CAP                   THEN REJECT END;
    CMP.L  #AR_MAXVAL,D2            IF VAL SEGM LENGTH > MAX VAL LENGTH
    BGT    ER_ADDR                  THEN REJECT END;
    BTST.L #0,D0                    IF TOPREL IS ODD
    BNE    ER_ADDR                  THEN REJECT END;
    BTST.L #0,D5                    IF FIRSTREL IS ODD
    BNE    ER_ADDR                  THEN REJECT END;
    MOVE   D1,CT_VAL(A3)              NEW_CTX.VAL_BASE_SEGM:=PREL;
    MOVE.L D0,CT_TREL(A3)             NEW_CTX.TOPREL:=TREL;
    MOVE.L D5,CT_FREL(A3)             NEW_CTX.FIRSTREL:=FREL;
 
  ELSE.S                            ELSE  "VOID VAL SEGM"
    CLR.L  D2                         D2:=LENGTH:=0;
    CLR.L  CT_TREL(A3)                NEW_CTX.TOPREL:=0;
    CLR.L  CT_FREL(A3)                NEW_CTX.FIRSTREL:=0;
    SUB    #AR_SIZ,A4                 ARGUMENT_ADDR:=NEXT ARGUMENT;
    ADDQ   #1,D6                      ARGUMENT#:=...+1;
    MOVE.L A3,A5                      A5:=BASE_SEGM:=DUMMY "CTX"
  ENDI                              END;
 
    TST.L  CT_OBJ(A3)             "CREATE TEMP SEGMENT:"
  IF <NE> THEN                      IF NEW_CTX NOT ABORTED THEN
    MOVEM.L D2/A5,-(A7)               SAVE LENGTH VAL DATA, BASESEGM;
    MOVE.L CT_OBJ(A3),A6              A6:=OBJ:=NEW_CTX.CUROBJ;
    MOVE.L GE_TEMD(A6),D0             D0:=SIZE:=OBJ.TEMP_DATA
    ADD.L  D2,D0                      +LENGTH VAL DATA;
    MOVE.L A3,A1                      A1:=PSTR:=NEW CTX;
    MOVE   #CT_SIZ+PT_SIZ,D1          D1:=PREL:=T(1);
    BSR    CRE_SEG                    CREATE_SEGM (EXT,PSTR,PREL,SIZE,
*                                       A5:=SEGM OBJ);
  IF <EQ> THEN.S                    IF NOT OK THEN
    ADD.L  #8,A7                      POP SAVED D2,D5;
    BRA    ER_PROSP                   REJECT
  ENDI                              END;
 
*                                 "MAP STACK SEGMENT AND INIT USP:"
    MOVE.L GE_STKM(A6),D0             D0:=LOGICAL ADDR:=OBJ.STACK_MAP;
    LEA    CT_MM0(A3),A1              A1:=MMU DESCR0;
    BSR    MAP_FIRST                  MAP_FIRST_TIME(MMU0,SEGMOBJ,LOGADDR,
*                                       D1,D2:=UNDEF);
    MOVE.L D0,16(A7)                  STACK.FIRST_TEMP:=LOG ADDR;
    MOVE.L SE_FIR(A5),A5              A5:=SEGM OBJ.FIRST_PHYS_ADDR
    ADD.L  GE_TEMD(A6),A5             +OBJ.TEMP DATA;
    ADD.L  GE_TEMD(A6),D0             D0:=LOGICAL ADDR+OBJ.TEMP DATA;
    MOVE.L D0,A1                      USP:=D0;
    MOVE.L A1,USP
    ADD.L  (A7)+,D0                   D0:=STACK.TOPVAL:=D0+LENGTH VAL DATA;
    MOVE.L D0,16(A7)
    MOVE.L (A7)+,A6                   A6:=SAVED BASE SEGM;
 
*                                 "COPY VAL DATA:  A5=PHYS FIRST VAL ADDR"
    MOVE.L SE_FIR(A6),A1              A1:=BASE_SEGM.FIRST_PHYS_ADDR;
*                                     "NONSENSE IN CASE OF NO VAL DATA"
    MOVE.L CT_TREL(A3),D0             D0:=NEW_CTX.TOPREL;
    MOVE.L CT_FREL(A3),D5             D5:=CUR_REL:=NEW_CTX.FIRSTREL;
  WHILE.L D5 <NE> D0 DO.S           WHILE CUR_REL <> TOPREL DO
    MOVE   (A1,D5),(A5)+              COPY ONE WORD;
    ADDQ   #2,D5                      D5:=CUR_REL:=...+2
  ENDW                              END;
* THIS COPYING SHOULD BE IMPROVED IN TWO WAYS:
* (1) WHEN VAL DATA IS TOP OF CTX, VAL BASE SEGM MAY BE SHORTENED
*     BEFORE TEMP IS CREATED.  THEN NO COPYING IS NEEDED.
* (2) IN OTHER CASES, COPYING SHOULD USE LONGS, AVOID LOOP OVERHEAD, ETC.
 
*                                 "INITIALIZE FORMALS:"
    MULS   #FP_SIZ,D3                 D3:=CUR_FPREL:=ADDITIONAL FORMALS
    ADD    CT_TOPT(A3),D3               *FP_SIZE+NEW_CTX.FIRST_FPREL;
  WHILE D3 <NE> CT_TOPF(A3) DO      WHILE CUR_FPREL <> TOP FORMALS DO
 
    TST    -2(A4)
  IF <EQ> THEN.S                    IF NEXT ARG = VOID THEN
    SUB.L  #AR_SIZ,A4                 ARGUMENT_ADDR:=NEXT ARGUMENT;
    ADDQ   #1,D6                      ARGUMENT#:=...+1
  ELSE.S                            ELSE
 
    TST.L  -AR_SIZ(A4)
  IF <NE> THEN.S                    IF NEXT ARG = SUBSEGM THEN
*                                     CHECK SUBSEGMENT (A1:=PSTR,D1:=PREL,
    BSR    C_SUB                      A5:=BASESEGMENT,D0:=TREL,D5:=FREL,
*                                     D2:=LENGTH,D4:=CAPS);
    BEQ    RETURN                     IF NOT OK THEN RETURN END;
  IF.L A5 <EQ> A6 THEN.S            IF BASESEGMENT = VAL BASE SEGM
  IF.L D5 <LT> CT_TREL(A3) THEN.S     AND FREL < NEW_CTX.TOPREL
    CMP.L  CT_FREL(A3),D0             AND TREL > NEW_CTX.FIRSTREL
    BGT    ER_ADDR                  THEN REJECT "OVERLAP"
  ENDI                              END;
  ENDI
    MOVE.L A3,A1                      A1:=PSTR:=NEW CTX;
    MOVE   D3,D1                      D1:=PREL:=CURRENT FORMAL PREL;
    BSR    CRE_SUB                    CREATE_SUBSEGMENT(EXT,PSTR,PREL,
*                                       BASESEGM,FREL,LENGTH,CAPS,A5:=SUBSEGM);
    BEQ    ER_PROSP                 IF NOT OK THEN REJECT END;
 
  ELSE.S                            ELSE  "POINTER ACTUAL:"
    MOVE.L A6,-(A7)                   SAVE VAL BASE SEGM;
*                                     CHECK ENTITY(A1:=PSTR,D1:=PREL,
    BSR    C_ENT                      A5:=ENTITY,A6:=PT,D2:=PTKIND,
*                                     D4:=CAPS,D5:=ENTKIND);
    MOVEA.L (A7)+,A6                  A6:=RESTORE VAL BASE SEGM;
    BEQ    RETURN                   IF NOT OK THEN RETURN END;
    SUB.L  #AR_SIZ-AR_PTSIZ,A4        ARGUMENT ADDR:=NEXT ARGUMENT;
    BSR    SET_ACT                    SET ACTUAL REF(PSTR,PREL,FPREL);
    BTST.B #0,9(A4)
  IF <NE> THEN.S                    IF ACTUAL.CALL PARAM THEN
    BTST.L #PT_CON,D4
  IF <NE> THEN.S                    IF COPY CONTROL THEN
    BCLR.L #PT_CC,D4                  D4:=CAPS-CALL CAP
  ENDI                              END;
    MOVE.L A6,-(A7)                   SAVE VAL BASE SEGM;
    LEA    (A3,D3),A6                 A6:=FORMAL POINTER ADDR;
    BSR    COPY_NIL                   COPY TO NIL(FORMAL POINTER,ENTITY,ENTKIND,
*                                       CAP,A1:=UNDEF);
    MOVEA.L (A7)+,A6                  A6:=RESTORE VAL BASE SEGM;
  ENDI                              END;
    BTST.B #1,9(A4)
  IF <NE> THEN.S                    IF ACTUAL.RETURN PARAM THEN
    BSET.B #PT_RET,PT_INF(A3,D3)      FORMAL POINTER.RETURN:=TRUE
  ENDI                              END;
  ENDI                              END  "POINTER ACTUAL";
 
  ENDI                              END  "NOT VOID";
    ADD    #FP_SIZ,D3                 D3:=NEXT FPREL;
  ENDW                              END  "FOR ALL FORMALS";
 
*                                 "CHECK STACK SPACE"
    MOVE.L OB_SPA(A0),A6              A6:=TOP EXTENSION OBJECT;
    MOVE.L SP_FREU(A6),D0             D0/D1:=NEW_CTX.FREE_CALL_STACK
    MOVE.L D0,CT_STKU(A3)                  :=EXT.FREE_SPACE;
    MOVE   SP_FREK(A6),D1
    MOVE   D1,CT_STKK(A3)
    MOVE.L CT_OBJ(A3),A1              A1:=OBJ:=NEW_CTX.CUROBJ;
    CMP.L  GE_STK(A1),D0            IF FREE SPACE < OBJ.REQUIRED_CALL_STACK
    BLT    ER_PROSP                 THEN REJECT
    CMP    GE_STK+SZ_K(A1),D1       END;
    BLT    ER_PROSP
  ELSE.S                            ELSE "CTX ABORTED"
    CLR.L  CT_TREL(A3)                NO VALUE DATA TO RETURN IN THIS CASE;
    MOVE.L OB_SPA(A0),A6              A6:= TOP OF EXTENSION OBJECT;
    MOVE.L SP_FREU(A6),CT_STKU(A3)    CTX.FREE_STK:= EXT.FREE_STK;
    MOVE.W SP_FREK(A6),CT_STKK(A3)    "MUST BE ASSIGNED TO SATISFY S_TERM"
  ENDI                              ENDI;
 
    MOVE   CT_TOPF(A3),D3             D3:=#FORMALS:=
    SUB    CT_TOPT(A3),D3               (TOP FORMALS-TOP TEMPS)//FP_SIZE;
    DIVU   #FP_SIZ,D3
***
    PRT_REG SET_FP
    PRT_MEM FORMALS,CT_SIZ(A3),4*PT_SIZ+3*FP_SIZ
    CMP.L  A2,A3                      SR:=NE;  "OK"
    RTS                               RETURN;
    PAGE
SET_ACT    EQU *                  SET ACTUAL REF
 
*          CALL:                  RETURN:
* A1       POINTER STRUCT         SAME  (ACTUAL POINTER)
* D1.W     POINTER REL            SAME  (ACTUAL POINTER)
* A3       FORMAL POINTER STRUCT  SAME  (=CTX)
* D3.W     FORMAL POINTER REL     SAME
 
* INSERT THE ACTUAL REF OF A FORMAL POINTER.
 
    MOVEM.L A4-A6,-(A7)               SAVE REGISTERS:
    MOVE.L A1,FP_STR(A3,D3)           FP.ACTUAL:=POINTER;
    MOVE   D1,FP_OFF(A3,D3)
    LEA    ST_ACT(A1),A4
    LEA    FP_ACT(A3,D3),A5           INSERT(HEAD=POINTER STRUCT,
    INS_ELEM A4,A5,A6,A4/A6             NEW=FP,A6:=PREV);
    MOVEM.L (A7)+,A4-A6               RESTORE REGISTERS
    RTS                               RETURN
 
 
RESETLMS   EQU *         RESET CHAIN ELEMENT IN ARRAY OF REFS
*          CALL:                      RETURN:
* A0       CHAIN ELEMENT OF FIRST REF UNDEF
* A1       CHAIN ELEMENT OF TOP REF   SAME
* D0       SIZE OF ONE REF            SAME
* A4/A6           -                   UNDEF
*
* USED IN DEL_CTX TO "UNCHAIN" FORMAL POINTERS AND MMU DESCRIPTORS
*
  WHILE.L A0 <NE> A1 DO.S             WHILE MORE ELEMENTS DO
    MOVEM.L (A0),A4/A6                  REMOVE
    MOVE.L  A4,(A6)                     ELEMENT
    MOVE.L  A6,4(A4)                    FROM CHAIN
    MOVE.L  A0,(A0)                     ELEMENT:=
    MOVE.L  A0,4(A0)                    SELFREF;
    ADDA.W  D0,A0                       A0:=NEXT ELEMENT;
  ENDW                                ENDW;
    RTS                                 RETURN;
    PAGE
RET_FP     EQU *                  RETURN FORMATLS
 
*          CALL:                  RETURN:
* A3       CTX                    SAME
* D6       RESULT (SYSID,ERR#)    SAME OR UPDATED (IF POINTER RETURN IMPOSSIBLE)
* D7       RESULT (CAUSE,MAIN)    SAME OR UPDATED
* OTHER REGISTERS  -              UNDEF
 
* COPIES THE VALUE DATA.  CHECKS THAT POINTER RETURN IS POSSIBLE FOR ALL
* POINTERS.  IF IT IS, POINTERS ARE RETURNED.
 
    MOVE.L CT_TREL(A3),D0             D0:=CTX.TOP_VAL_REL;
  IF <NE> THEN.S                    IF VAL DATA EXISTS THEN
*                                 "FIND VAL BASE SEGM:"
    MOVE.L CT_HOLD(A3),A0             A0:=EXT:=CTX.HOLDER_OBJ;
    LEA    EX_CTX(A0),A0              "OFFSET"
  IF.L CT_STK+4(A3) <NE> A0 THEN.S  IF CTX.PREV_CTX <> EXT THEN
    MOVE.L CT_STK+4(A3),A2            A2:=OLD_CTX:=CTX.PREV_CTX
  ELSE.S                            ELSE
    MOVE.L EX_EXT+4-EX_CTX(A0),A1     A1:=EXT.PREV_EXT;
    MOVE.L EX_CTX+4-EX_EXT(A1),A2     A2:=OLD_CTX:=PREV_EXT.LAST_CTX;
  ENDI                              END;
    LEA    -CT_STK(A2),A2             "OFFSET OLD CTX"
    MOVE   CT_VAL(A3),D2              D2:=PREL:=CTX.PREL_OF_VAL_BASE_SEGM;
*                                 "POINTER IS OWN_SET"
    MOVE.L 4(A2,D2),A1                A1:=BASE_SEGM:=POINTER.LAST
 
*                                 "COPY VAL DATA:"
    MOVE.L SE_FIR(A1),A1              A1:=BASE_SEGM.FIRST_PHYS_ADDR;
    MOVE.L CT_FREL(A3),D5             D5:=CUR_REL:=CTX.FIRST REL;
    MOVE.L SE_FIR-SE_SIZ(A3),A5       A5:=TOP TEMP:=
    ADD.L  SE_LEN-SE_SIZ(A3),A5         FIRST EMBEDDED.FIRST ADDR+LENGTH;
    ADD.L  D5,A5                      A5:=FIRST VAL:=TOP TEMP
    SUB.L  D0,A5                        -(CTX.TOP VAL REL-CTX.FIRST VAL REL);
***
    PRT_REG VAL_DATA_RETURN
  WHILE.L D5 <NE> D0 DO.S           WHILE CUR_REL <> TOP REL DO
    MOVE   (A5)+,(A1,D5)              COPY ONE WORD;
    ADDQ   #2,D5                      D5:=CUR_REL:=...+2
  ENDW                              END;
* THIS COPYING SHOULD BE IMPROVED.  SEE NOTE IN SET_FP.
  ENDI                              END  "VAL DATA EXISTS"
 
    TST.B D7                      "CHECK RETURN POSSIBLE:"
  IF.B <GE> THEN                   IF RESULT.MAIN <> REJECT THEN
    CLR    D2                         D2:=INITIALLY NOTHING TO RETURN;
    MOVE   CT_TOPT(A3),D3             D3:=CUR_FP:=CTX.FIRST_FP_REL;
  WHILE D3 <NE> CT_TOPF(A3) DO.S    FOR ALL FORMALS DO
    BTST.B #PT_RET,PT_INF(A3,D3)
  IF <NE> THEN.S                    IF FP.RETURN THEN
    MOVE.L FP_STR(A3,D3),A1           A1:=ACTUAL STRUCTURE;
    CMPA.L #0,A1                      IF DUMMY ACTUAL
    BEQ    ER_RETURN                  THEN REJECT END;
    MOVE.B PT_KIN(A3,D3),D5           D5:=FP.KIND;
  IF <NE> THEN.S                    IF FP NOT NIL THEN
    MOVE   FP_OFF(A3,D3),D1           D1:=ACTUAL REL;
    MOVE.B PT_KIN(A1,D1),D4           D4:=ACTPT.KIND;
  IF.B D5 <LE> #PT_ENV THEN.S       IF FP SIMPLE THEN
    CMP.B  #PT_ENV,D4                 IF ACT PT NOT SIMPLE
    BGT    ER_RETURN                  THEN REJECT END;
  ELSE.S                            ELSE "FP IS OWN:"
    CMP.B  #PT_OWN,D4                 IF ACTPT NOT SIMPLE OR OWN
    BGT    ER_RETURN                  THEN REJECT END;
    MOVE.L (A3,D3),A5
  REPEAT                            FOR A5:=OBJECTS IN OWN SET DO
    BSR    S_MOVE                     MOVE_STACK_CHECK(ACTSTR,ACTREL,OBJ);
    BEQ    ER_RET1                    IF NOT OK THEN REJECT END;
    LEA    (A3,D3),A6                 A6:=FP ADDR;
    MOVE.L (A5),A5                    A5:=NEXT OBJECT;
  UNTIL.L A5 <EQ> A6                END FOR;
  ENDI                              END "FP IS OWN";
    MOVEQ  #1,D2                      D2:=SOMETHING TO RETURN;
  ENDI                              END "FP NOT NIL";
  ENDI                              END  "FP.RETURN"
    ADD    #FP_SIZ,D3                 D3:=CUR_FP:=NEXT FORMAL;
  ENDW                              END "FOR ALL FORMALS";
 
    TST    D2
  IF <NE> THEN.S                    IF SOMETHING TO RETURN THEN
    MOVE   CT_TOPT(A3),D3             D3:=CUR_FP:=CTX.FIRST_FP_REL;
  WHILE D3 <NE> CT_TOPF(A3) DO.S    FOR ALL FORMALS DO
    MOVE.B PT_INF(A3,D3),D4           D4:=CUR_FP.CAPS_ETC;
    BTST   #PT_RET,D4
  IF <NE> THEN.S                    IF FP.RETURN THEN
    MOVE.B PT_KIN(A3,D3),D5           D5:=ENTITY KIND:=FP.KIND;
  IF <NE> THEN.S                    IF FP NOT NIL THEN
    MOVE.L FP_STR(A3,D3),A1           A1:=ACTUAL STRUCTURE;
    MOVE   FP_OFF(A3,D3),D1           D1:=ACTUAL REL;
  IF.B D5 <LE> #PT_ENV THEN.S       IF FP SIMPLE THEN
  IF.B PT_KIN(A1,D1) <LE> #PT_ENV THEN.S  IF ACTUAL STILL SIMPLE THEN
    BSR    CLR_SMP                    CLEAR SIMPLE (ACTUAL,A6:=ACTPT);
    MOVE.L PT_REF(A3,D3),A5           A5:=ENTITY:=FP.REF;
    BTST   #PT_CON,D4
  IF <NE> THEN.S                    IF COPY CONTROL THEN
    BCLR   #PT_CC,D4                  D4:=CAPS:=CAPS-CALLCAP;
  ENDI                              END;
    AND.B  #1<<PT_CC+1<<PT_CON,D4     D4:=CAPS,REMOVE OTHER BITS;
    BSR    COPY_NIL                   COPY TO NIL(ACT PT, ENTITY, CAP,
*                                       ENTITY KIND, A1:=UNDEF);
  ENDI                              END  "ACTUAL STILL SIMPLE"
  ELSE.S                            ELSE "FP IS OWN_SET"
    MOVE.L (A3,D3),A5
  REPEAT                            FOR A5:=OBJECTS IN OWN SET DO
    BSR    M_OWN_OK                   MOVE_OWNER (ACT STR, ACTREL, OBJECT,
*                                       A6:=ACTPT);
    BSR    S_UPDATE                   UPDATE_STACK_REQUIREMENTS (OBJECT,
*                                       A6/D0:=UNDEF);
    LEA    (A3,D3),A6                 A6:=FP ADDR;
    MOVEA.L (A6),A5                   A5:=NEXT OBJ:=FIRST IN SET;
  UNTIL.L A5 <EQ> A6                END FOR;
  ENDI                              END  "OWN SET";
  ENDI                              END "FP NOT NIL";
  ENDI                              END  "FP.RETURN";
    ADD    #FP_SIZ,D3                 D3:=CUR FP:=NEXT FORMAL;
  ENDW                              END  "FOR ALL FORMALS"
  ENDI                              END  "SOMETHING TO RETURN";
 
  ENDI                              END  "RESULT <> REJECT";
    RTS                               RETURN
 
 
ER_RETURN  EQU *                  RETURN POINTER ILLEGAL: "D3:=FP REL"
    MOVE.L #ECRRETURN,D7              D7:=RESULT:=(REJECT,...)
ER_RET1    EQU *                  "AFTER STACK CHECK ERROR:"
    SUB    CT_TOPT(A3),D3             D3:=D6:=SYSID,ERROR#
    DIVU   #FP_SIZ,D3                   :=(FP REL-FP FIRST)//FP_SIZE;
    MOVE.L D3,D6
    CMP    D7,D7                      SR:=EQ;  "NOT OK"
    RTS                               RETURN
    PAGE
DEL_CTX    EQU *                  DELETE CONTEXT
 
*          CALL:                  RETURN:
* A0       -                      EXT OBJECT (USED BY NEW_STACK_CALL, ETC.)
* A3       CTX                    PREV CTX (NONSENSE IF FIRST IN EXT OBJECT)
* D6/D7    -                      SAME
* OTHER REGS  -                   UNDEF  (USER CONTEXTS MAY BE CALLED)
 
* REMOVES CTX FROM EXECUTES.  DUMMYFIES ACTUAL REFS TO CONTEXT.
* REMOVES FORMAL PTS. FROM ACTUAL CHAINS. REMOVES MMU DESCRIPTORS FROM CHAINS.
* ACTUAL REFS TO THIS CONTEXT CANNOT EXIST (REMOVED WHEN YOUNGER CTX RETURNS).
* CLEARS POSSIBLE TEMP OR FORMAL IO-LOCKS.  DELETES EMBEDDED SEGMENTS TO
* GET MAXIMAL FREE STACK BEFORE POINTER CLEARING.
* CLEARS ALL TEMP AND FORMAL POINTERS.  RELEASES CTX SPACE.
 
    PRT_MEM DEL_CTX,(A3),CT_SIZ+4*PT_SIZ+3*FP_SIZ
    REM_ELEM (A3),A0,A4,A0/A4         REMOVE FROM EXECUTES;
 
* ACTUALS MAY HAVE FORMALS IN CONTEXTS IN OTHER PROCESSES (DECL_PROC);
    MOVE.L A3,A5                      A5:= STRUCT:= CTX;
    BSR.L  DUM_ACT                    DUMMYFY ACTUALS(STRUCT,A0/A4/A6:=?);
 
    LEA    FP_ACT(A3),A0           "RESET ACTUAL CHAIN IN FORMAL POINTERS"
    MOVE.L A0,A1
    ADDA.W CT_TOPT(A3),A0             A0:=ACT_CHAIN_ELEM OF FIRST FORMAL
    ADDA.W CT_TOPF(A3),A1             A1:=ACT_CHAIN_ELEM OF TOP FORMAL
    MOVEQ.L #FP_SIZ,D0                D0:= SIZE OF FORMAL POINTER
    BSR    RESETLMS                   RESET ELEMS(FIRST,TOP,SIZE,A0/A4/A6:=?);
 
    LEA    CT_MM0(A3),A0           "RESET SEGM CHAIN IM MMU DESCRIPTORS"
    LEA    CT_MM3+MM_SIZ(A3),A1       A0:= FIRST MMU; A1:= TOP MMU
    MOVEQ.L #MM_SIZ,D0                D0:= SIZE OF MMU DESCRIPTOR
    BSR    RESETLMS                   RESET ELEMS(FIRST,TOP,SIZE,A0/A4/A6:=?);
 
    MOVEM.L D6/D7,CT_MM0+MM_REG(A3)   SAVE RESULT;
    MOVE.L A3,A1                      A1:=STRUCT:=CTX;
 
    TST    CT_IO(A3)              "CLEAR POSSIBLE TEMP/FORMAL IO-LOCKS:"
  IF <NE> THEN.S                    IF CTX.IO_COUNT <> 0 THEN
    MOVE   #CT_SIZ+PT_SIZ,D1          D1:=CUR_TMP:=CTX.TMP(1);
  WHILE D1 <NE> CT_TOPT(A3) DO.S    FOR D1:=ALL USER ACCESSIBLE TEMPS DO
    BTST.B #PT_IO,PT_INF(A1,D1)       "OBS: NO DRIVER POINTERS IN CTX"
  IF <NE> THEN.S                    IF TMP.IO_LOCK THEN
    BSR    CLR_SMP                    CLEAR SIMPLE PT (STRUCT, PREL, A6:=PT)
  ENDI                              END;
    ADD    #PT_SIZ,D1                 D1:=CUR_TMP:=NEXT
  ENDW                              END  "FOR ALL TEMPS";
  WHILE D1 <NE> CT_TOPF(A3) DO.S    FOR D1:=ALL FORMALS DO
    BTST.B #PT_IO,PT_INF(A1,D1)        "OBS: NO DRIVER POINTERS IN CTX"
  IF <NE> THEN.S                    IF FORMAL.IO_LOCK THEN
    BSR    CLR_SMP                    CLEAR SIMPLE PT(STRUCT, PREL, A6:=PT)
  ENDI                              END;
    ADD    #FP_SIZ,D1                 D1:=CUR_FP:=NEXT;
  ENDW                              END  "FOR ALL FORMALS";
  ENDI                              END  "IO_COUNT <> 0":
 
    BSR    DEL_EMB                    DELETE EMBEDDED(STRUCT,CTX,A6:=TOPEXT,
*                                       A0/A2/A4/A5/D0-D7:=UNDEF);
    MOVE.L SP_FREU(A6),CT_STKU(A3)    CTX.FREE STACK:=EXT OBJECT.FREE SPACE
    MOVE   SP_FREK(A6),CT_STKK(A3)    "FULL SPACE NEEDED FOR POSSIBLE OBJECT DEL
 
*                                 "CLEAR ALL TEMPS AND FORMALS:"
    MOVE   #CT_SIZ+PT_SIZ,D1          D1:=CUR_TMP:=CTX.TMP(1);
  WHILE D1 <NE> CT_TOPT(A3) DO.S    FOR D1:=ALL USER ACCESSIBLE TEMPS DO
    BSR    CLR_PT                     CLEAR_POINTER(STRUCT, CTX, PREL,
*                                       A0/A2/A4-A6/D0/D2-D7:=UNDEF);
    ADD    #PT_SIZ,D1                 D1:=NEXT;
  ENDW                              END  "FOR ALL TEMPS";
  WHILE D1 <NE> CT_TOPF(A3) DO.S    FOR D1:=ALL FORMALS DO
    BSR    CLR_PT                     CLEAR_POINTER(...);
    ADD    #FP_SIZ,D1                 D1:=NEXT;
  ENDW                              END  "FOR ALL FORMALS";
 
    MOVEM.L CT_MM0+MM_REG(A3),D6/D7   RESTORE RESULT;
    MOVE.L CT_HOLD(A3),A0             A0:=EXT_OBJECT:=CTX.HOLDER;
    BSR    MM_POPK                    POP_KERNEL_PART (CTX,A3:=NEW CTX,
*                                       A6:=TOP HOLDER OBJ);
    RTS                               RETURN
 
    TTL    OBJECT CREATION AND DELETION
    PAGE
DECL_GEN   EQU *                  DECLARE GENERAL
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_OPEN                     CHECK OPEN OBJ(A0:=A5:=OBJ,A1:=PSTR,
*                                       D1:=PREL,A6:=PT);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE   #GE_SIZ-OB_SIZ,D0          D0:=SIZE OF GENERAL OBJ PART;
    BSR    MM_PUSHO                   RESERVE KERNEL ENV(OBJ,SIZE,A6:=TOP OBJ);
    BEQ    EE_OBJSP                   IF NOT OK THEN REJECT END;
    BSR    CRE_ENV                   CREATE ENV(OBJ,CTX,A1/D1:=REF ENV PT,
*                                       A5/D5:=MAN SET PT,A3:=ENV,A6/D0:=UNDEF);
  IF <NE> THEN                      IF OK THEN
    MOVEM.L A1/A5/D1/D5,-(A7)         SAVE A1,D1,A5,D5;
    INIT_HEAD GE_EX(A0),A6            OBJ.EXECUTED_BY:=EMPTY;
    BSR    C_PTS                      CHECK POINTER COUNT(D0:=TEMPS);
    BEQ    GEN_REJ                    IF NOT OK THEN REJECT END;
    ADD    #1,D0                      "INCLUDE T(0):"
    MOVE   D0,GE_TEMP(A0)             OBJ.TEMP_POINTERS:=TEMPS+1;
    BSR    C_ADDR                     CHECK ADDR ARGUMENT(D0:=TEMP DATA);
    BEQ    GEN_REJ                    IF NOT OK THEN REJECT END;
    ADDQ.L #1,D0                      ROUND UP TEMP DATA
    CMP.L  #1<<22-AR_MAXVAL,D0        IF TEMP DATA > MAX
    BGT.L  GEN_DATA                   OR TEMP DATA = 0
    BCLR.L #0,D0                      EVEN TEMP DATA REQUIRED BY SET_FP
    TST.L  D0                         THEN REJECT
    BEQ.S  GEN_DATA                   END;
    MOVE.L D0,GE_TEMD(A0)             OBJ.TEMP_DATA:=TEMP DATA;
    ADD    #1,D6                      ARGUMENT#:=NEXT;
    MOVE   -(A4),GE_CON(A0)           OBJ.CONTROL PROC:=NEXT ARGUMENT;
    BGT.S  GEN_DATA                   IF > 0 THEN REJECT END;
    SUB    #2,A4                      SKIP REST OF ARGUMENT;
    BSR    C_ADDR                     CHECK ADDR ARGUMENT(D0:=ENTRY ADDR);
    BEQ.S  GEN_REJ                    IF NOT OK THEN REJECT END;
    MOVE.L D0,GE_ENT(A0)              OBJ.ENTRY:=ENTRY ADDR;
    MOVE.L #$200000,GE_STKM(A0)       OBJ.STACK ADDR:=DEFAULT;
    BSR    C_SIZ                      CHECK SIZE(D0:=SIZE_U,D1:=SIZE_K);
    BEQ.S  GEN_REJ                    IF NOT OK THEN REJECT END;
    MOVE.L D0,GE_STK(A0)              OBJ.STACK_REQUIREMENT_AT_ENTRY
    MOVE   D1,GE_STK+SZ_K(A0)           :=SIZE ARGUMENT;
 
* NOW ALL CHECKS HAVE BEEN PASSED
    TST.B  -2(A4)
  IF <NE> THEN.S                    IF CAPS <> 0 THEN
    BSET.B #OB_OCC,OB_STA(A0)         OBJ.OWNERS_CALL_CAP:=TRUE;
  ENDI                              END;
    MOVE.B #OB_GEOB,OB_KIN(A0)        OBJ.KIND:=GENERAL OBJECT;
    MOVEM.L (A7),D1/D5/A1/A5          RESTORE REFENV STRUCT AND REL;"DOM'T POP"
    BSR    CLR_SMP                    CLEAR SIMPLE POINTER(PSTR, PREL,A6:=PT);
    MOVE.L A3,A5                      A5:=ENVELOPE;
    CLR    D4                         D4:=NO CAPS;
    MOVE   #PT_ENV,D5                 D5:=REF_ENV;
    BSR    COPY_NIL                   COPY REF TO NIL(ENV,A6:=PT,A1:=UNDEF);
    MOVEM.L (A7)+,D0/D1/D7/A1         RESTORE MAN SET STRUCT AND REL;"DO POP"
    BSR    INS_MAN                    INSERT IN MAN SET(PSTR,PREL,A5=ENV)
***
    PRT_MEM DECL_GEN,(A0),GE_SIZ
    MOVE.L A0,A5                      A5:=OBJ;
    BSR    S_UPDATE                   STACK REQ UPDATE(OBJ,A6/D0:=UNDEF);
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD2                   RETURN TO USER;  "RELOCATION POSSIBLE"
 
 
GEN_DATA   EQU *                  DATA VALUE ILLEGAL:
    MOVE.L #ECRDATA,D7                D7:=RESULT;
 
GEN_REJ    EQU *                  REJECT AND RELEASE(A0=OBJ,A3=ENV):
    BSR    MM_POPK                    RELEASE STACK ELEM(ENV,A6:=TOP OBJ);
    MOVEM.L (A7)+,D1/D5/A1/A5         RELEASE SAVED REGISTERS;
  ENDI                            END  "ONLY KERNEL ENVELOPE RESERVED"
    MOVE   #GE_SIZ-OB_SIZ,D0          D0:=SIZE OF GENERAL OBJ PART;
    BSR    MM_POPO                    RELEASE KERNEL ENV(OBJ,SIZE,A6:=TOPOBJ);
    BRA    RET_OLD2                   RETURN TO USER; "RELOCATION POSSIBLE"
    PAGE
CRE_ENV    EQU *                  CREATE AND INIT ENVELOPE
 
*          CALL:                  RETURN:
* A0       OBJECT                 SAME  (UNDEF IF NOT OK)
* A1       -                      POINTER STRUCT OF SIMPLE REF (UNDEF IF NOT OK)
* A2       CTX                    SAME
* A3       -                      ENVELOPE  (UNDEF IF NOT OK)
* A4       ARGUMENT ADDR          UPDATED  (UNDEF IF NOT OK)
* A5       -                      POINTER STRUCT OF MAN_SET (UNDEF IF NOT OK)
* D1       -                      POINTER REL OF SIMPLE REF (UNDEF IF NOT OK)
* D5       -                      POINTER REL OF MAN_SET (UNDEF IF NOT OK)
* D6.W     ARGUMENT#              UPDATED
* D7.L     -                      RESULT IF NOT OK, UNDEF IF OK
* SR       -                      NE = OK, EQ = NOT OK
* A6/D0    -                      UNDEF
 
* CREATES AN ENVELOPE AND INITIALIZES IT ACCORDING TO ARGUMENTS.
* ALSO CHECKS STACK.  IN CASE OF ERRORS, THE ENVELOPE IS REMOVED.
* DOES NOT INSERT INTO MAN_SET AND SIMPLE REF SINCE THIS MAY BE SKIPPED
* IN CASE THE CALLER FINDS ERROR.  DOES NOT UPDATE STACK REQUIREMENTS.
 
*                                 "CHECK MAN_SET AND SIMPLE REF:"
    BSR    C_PT                       CHECK POINTER ARG(A1:=PSTR,D1:=PREL,
*                                       D2:=PT KIND,A6:=PT);
    BEQ    RETURN                     IF NOT OK THEN REJECT END;
    BTST.B #PT_LSC,PT_INF(A6)
  IF <NE> THEN.S                    IF LOCAL POINTER THEN
    MOVE.L EN_OBJ(A1),A6              A6:=OBJECT HOLDING ENV;
    CMP.B  #OB_GEOB,OB_KIN(A6)        IF NOT GENERAL OBJECT
    BNE    ER_STATE                   THEN REJECT END;
    MOVE.L OB_SPA(A6),A6              A6:=TOP OBJECT;
    LEA    SP_ENV(A6),A6              A6:=HEAD ENV CHAIN;
    CMP.L  EN_STK(A1),A6              IF POINTER STRUCT <> TOP ENVELOPE
    BNE    ER_SCOPE                   THEN REJECT END;
  ELSE.S                            ELSE
    BTST.B #PT_TSC,PT_INF(A6)         IF NOT TEMP POINTER
    BEQ    ER_SCOPE                   THEN REJECT END;
  ENDI                              END "CHECK TEMP OR IN PRIMARY ENV"
    MOVE.L A1,A5                      A5:=POINTER STRUCT OF MAN_SET;
    MOVE.L D1,D5                      D5:=POINTER REL OF MAN_SET;
    BTST.B D2,SIM_MAN                 IF POINTER KIND <> SIMPLE, MANAGER
    BEQ    ER_VALUE                   THEN REJECT END;
    BSR    C_PT                       CHECK POINTER ARG(A1:=PSTR,D1:=PREL,
*                                       D2:=PT KIND,A6:=PT);
    BEQ    RETURN                     IF NOT OK THEN REJECT END;
    CMP.B  #PT_ENV,D2                 IF POINTER KIND <> SIMPLE
    BHI    ER_VALUE                   THEN REJECT END;
 
*                                 "RESERVE ENVELOPE:"
    BSR    C_PTS                      CHECK POINTER COUNT(D0:=#LOCALS);
    BEQ    RETURN                   IF NOT OK THEN REJECT END;
    MULU   #PT_SIZ,D0                 D0:=SIZE:=
    ADD    #EN_SIZ,D0                 #LOCALS * PT_SIZE + ENV SIZE;
    BSR    MM_PUSHK                   RESERVE STACK ELEM(OBJ,SIZE,
*                                       A3:=ENVELOPE,A6:=TOP OBJ);
    BEQ    ER_OBJSP                 IF NOT OK THEN REJECT END;
    MOVEM.L A1/A5/D1/D5,-(A7)         SAVE A1,A5,D1,D5;
    MOVE.L A5,EN_MAN(A3)              ENV.MANAGER:=MAN_SET POINTER:
    MOVE   D5,EN_OFF(A3)              "NEEDED BY STACK CHECK"
    LEA    SP_ENV(A6),A1              A1:=TOP OBJ.ENV_HEAD;
    LEA    EN_STK(A3),A5              A5:=ENV.ENV_STACK_MEMBER;
    INS_ELEM A1,A5,A6,A1/A6           INSERT (HEAD=OBJ,NEW=ENV,A6:=PREV);
    INIT_HEAD EN_REF(A3),A6           ENV.REFERRED_BY:=EMPTY;
 
    ADD    #1,D6                  "INIT VARIOUS FIELDS:"  ARGUMENT#:=NEXT;
    MOVE   -(A4),EN_TERM(A3)          ENV.TERM_PROC:=NEXT ARGUMENT;
    BGT.S  ENV_DATA                   IF > 0 THEN REJECT END;
    SUB    #2,A4                      SKIP REST OF ARGUMENT;
    BSR    C_SIZ                      CHECK SIZE(D0:=SIZE_U,D1:=SIZE_K);
    BEQ.S  ENV_REJ                    IF NOT OK THEN REJECT END;
    MOVE.L D0,EN_FIXU(A3)             ENV.FIXED_TERM_REQUIREMENT:=
    MOVE   D1,EN_FIXK(A3)               DEALLOC REQUIREMENT;
    BSR    C_SIZ                      CHECK SIZE(D0:=SIZE_U,D1:=SIZE_K)
*                                     "LARGE IN CASE MAX_STK < 0 (=NONE)"
    BEQ.S  ENV_REJ                    IF NOT OK THEN REJECT END;
    MOVE.L D0,EN_MAXU(A3)             ENV.MAX_STACK:=SIZE ARGUMENT;
    MOVE   D1,EN_MAXK(A3)
    BSR    S_ENV                      STACK CHECK ENV(A3=ENV);
    BEQ.S  ENV_REJ                    IF NOT OK THEN REJECT END;
    MOVE   #EN_SIZ,D0
  WHILE D0 <NE> EN_TOPL(A3) DO.S      FOR ALL LOCAL POINTERS DO
    INIT_HEAD <(A3,D0)>,A6              POINTER:=NIL; A6:= POINTER;
    MOVE   #PT_NIL<<8+1<<PT_LSC,PT_KIN(A6)
    ADD    #PT_SIZ,D0
  ENDW                              END;
    MOVEM.L (A7)+,A1/A5/D1/D5         RESTORE A1,A5,D1,D5
***
    PRT_MEM CRE_ENV,(A3),EN_SIZ+PT_SIZ
    TST    D0                         SR:=NE; "OK"
    RTS                               RETURN
 
SIM_MAN    DC.B 1<<PT_NIL+1<<PT_OBJ+1<<PT_ENV+1<<PT_MAN    MASK FOR MAN_SET.
           DS.W 0                     MAKE ADDRESS EVEN
 
ENV_DATA   EQU *                  DATA VALUE ILLEGAL:
    MOVE.L #ECRDATA,D7                D7:=RESULT;
ENV_REJ    EQU *                  REJECT AND RELEASE ENV(A3=ENV):
    BSR    MM_POPK                    RELEASE STACK ELEM(ENV,A6:=TOPOBJ);
    MOVEM.L (A7)+,A1/A5/D1/D5         RELEASE SAVED REGISTERS;
    CMP    D7,D7                      SR:=EQ;  "NOT OK"
    RTS                               RETURN
    PAGE
DECL_SEG   EQU *                  DECLARE SEGMENT  (NON-EMBEDDED)
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_OPEN                     CHECK OPEN OBJ(A0:=A5:=OBJ,A1:=PSTR,
*                                       D1:=PREL,A6:=PT);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BSR    C_ADDR                     CHECK ADDR(D0:=USER SIZE);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE.L D0,D1                      D1:=USER SIZE;
    MOVE   #SE_SIZ-OB_SIZ,D0          D0:=SIZE:=SIZE OF KERNEL ENVELOPE;
    BSR    MM_PUSHO                   RESERVE OBJECT PART(OBJ,SIZE,A6:=TOPOBJ);
    BEQ    EE_OBJSP                   IF NOT OK THEN REJECT END;
    MOVE.L D1,D0
    ADD.L  #255,D0                    D0:=USER SIZE ROUNDED TO MULTIPLE 256;
    CLR.B  D0
    BSR    MM_PUSHU                   RESERVE_U_SPACE (OBJ,SIZE,
*                                       A4:=PHYS ADDR,A6:=TOP OBJ);
  IF <EQ> THEN.S                    IF NOT OK THEN
    MOVE   #SE_SIZ-OB_SIZ,D0          D0:=SIZE OF KERNEL ENVELOPE;
    BSR    MM_POPO                    RELEASE OBJECT PART(OBJ,SIZE,A6:=TOPOBJ);
    BRA    EE_OBJSP                   REJECT
  ENDI                              END;
    CLR    SE_IO(A0)                  OBJ.IO_COUNT:=0;
    MOVE.L A4,SE_FIR(A0)              OBJ.FIRST:=PHYS ADDR;
    MOVE.L D1,SE_LEN(A0)              OBJ.LENGTH:=USER SIZE; "UNROUNDED"
    INIT_HEAD SE_WAIT(A0),A6          IO_LOCK_WAIT:=EMPTY;
    MOVE #OB_SEOB<<8+1<<OB_READ+1<<OB_WRIT+1<<OB_EXEC,OB_KIN(A0)
***
    PRT_MEM DECL_SEG,(A0),SE_SIZ
    CLR.L  D7                         OBJ.KIND,STATE:=...;D7:=RESULT:=OK;
    BRA    RET_OLD2                   RETURN TO USER; "RELOCATION POSSIBLE"
    PAGE
DECL_SUB   EQU *                  DECLARE SUBSEGMENT  (NON-EMBEDDED)
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_OPEN                     CHECK OPEN OBJ(A0:=A5:=OBJ,A1:=PSTR,
*                                       D1:=PREL,A6:=PT);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BSR    C_SUB                      CHECK SUBSEGM(A1:=PSTR,A5:=BASE SEGM,
*                                       D0:=TOPREL,D1:=PREL,D2:=LENGTH,D4/D5:=);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE   #SU_SIZ-OB_SIZ,D0          D0:=SIZE OF KERNEL ENVELOPE;
    BSR    MM_PUSHO                   RESERVE OBJECT PART(OBJ,SIZE,A6:=TOPOBJ);
    BEQ    EE_OBJSP                   IF NOT OK THEN REJECT END;
    CLR    SE_IO(A0)                  OBJ.IO_COUNT:=0;
    ADD.L  SE_FIR(A5),D5              D5:=OBJ.FIRST:=BASE SEGM.FIRST+FIRST REL;
    MOVE.L D5,SE_FIR(A0)
    MOVE.L D2,SE_LEN(A0)              OBJ.LENGTH:=LENGTH;
    INIT_HEAD SE_WAIT(A0),A6          IO_LOCK_WAIT:=EMPTY;
    MOVE.L A5,SU_REF(A0)              OBJ.BASE:=BASE SEGM;
    MOVE.B #PT_SEG,SU_KIN(A0)         OBJ.KIND:=REF FROM SUBSEGM;
    ADD #OB_SEOB<<8+1<<OB_SUB,D4      D4:=OBJ.KIND:=...+CAPS;
    MOVE   D4,OB_KIN(A0)
    LEA    OB_REF(A5),A5              A5:=BASE SEGM.REFERRED_BY;
    LEA    SU_P(A0),A0                A0:=OBJ.BASE POINTER;
    INS_ELEM A5,A0,A6,A5/A6           INSERT (HEAD=BASE SEGM,NEW=OBJ,
*                                       A6:=PREV);
***
    PRT_MEM DECL_SUB,-SU_P(A0),SU_SIZ
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD2                   RETURN TO USER;  "RELOCATION POSSIBLE"
    PAGE
NEW_SEG    EQU *                  NEW EMBEDDED SEGMENT
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_TOPOWN                   CHECK TOP STACK,OWNER(A0:=HOLDER,
*                                       A1:=PSTR,D1:=PREL,A6:=PT);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BSR    C_ADDR                     CHECK ADDR(D0:=SIZE);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BSR    CRE_SEG                    CREATE SEGM(HOLDER,SIZE,PSTR,PREL,
*                                       A5:=SEGM OBJ);
    BEQ.S  EE_SPACE                   IF NOT OK THEN GOTO SPACE LIMIT END;
 
NEW_COM    EQU *
  IF.L CT_HOLD(A2) <EQ> A0 THEN.S   IF CTX.HOLDER = HOLDER THEN
    MOVE.L OB_SPA(A0),A6              A6:=TOP HOLDER
    MOVE.L SP_FREU(A6),CT_STKU(A2)    CTX.FREE_CALL_STACK:=
    MOVE   SP_FREK(A6),CT_STKK(A2)      EXT.FREE_SPACE;
  ENDI                              END;
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD2                   RETURN TO USER;  "RELOCATION POSSIBLE"
 
 
EE_SPACE   EQU *                  ERROR EXIT,SPACE LIMIT(A0=HOLDER,A2=CTX):
    CMP.L  CT_HOLD(A2),A0             IF CTX.HOLDER=HOLDER THEN
    BEQ    EE_PROSP                   REJECT "PROCESS SPACE LIMIT" END;
    BRA    EE_OBJSP                   REJECT "OBJECT SPACE LIMIT";
 
 
NEW_SUB    EQU *                  NEW EMBEDDED SUBSEGMENT
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_TOPOWN                   CHECK TOP STACK, OWNER(A0:=HOLDER,
*                                       A1:=PSTR,D1:=PREL,A6:=PT);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVEM.L A1/D1,-(A7)               SAVE PSTR,PREL;
    BSR    C_SUB                      CHECK SUBSEGM(A1:=PSTR,A5:=BASE SEGM,
*                                       D0:=TOPREL,D1:=PREL,D2:=LENGTH,D4/D5:=);
    MOVEM.L (A7)+,A1/D1               RESTORE PSTR,PREL OF FUTURE OWNER;
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BSR    CRE_SUB                    CREATE SUBSEGM(HOLDER,PSTR,PREL,LENGHT,...
*                                       BASE SEGM,A5:=SUBSEGM);
    BEQ    EE_SPACE                   IF NOT OK THEN GOTO SPACE LIMIT END;
    BRA    NEW_COM                    GOTO COMMON PART, NEW_SUB/NEW_SEG
    PAGE
CRE_SEG    EQU *                  CREATE EMBEDDED SEGMENT
 
*          CALL:                      RETURN:
* A0       HOLDER                 SAME  (EXT, OPEN, DORMANT, OR GENERAL OBJ)
* A1       POINTER STRUCT         SAME  (OWNER POINTER)
* A5       -                      SEGM OBJ
* D0       SIZE (UNROUNDED >0)    SAME  (SIZE OF USER PART)
* D1       POINTER REL            SAME  (OWNER POINTER)
* SR       -                      NE=OK, EQ=NOT OK  ("NO SPACE" ONLY)
 
* CREATES AN EMBEDDED SEGMENT IN THE HOLDER OBJECT.  THE EMBEDDED SEGMENT
* CONSISTS OF USER PART AND KERNEL PART.  THE POINTER BECOMES THE OWNER.
 
    MOVEM.L D0/A4/A6,-(A7)            SAVE USER SIZE,A4,A6;
    MOVE   #SE_SIZ,D0                 D0:=SIZE:=SIZE OF SEGM DESCRIPTOR;
    BSR    MM_PUSHD                   RESERVE_DESCRIPTOR(HOLDER,SIZE,
*                                       A5:=SEGM OBJ,A6:=TOP OBJ);
  IF <NE> THEN.S                    IF OK THEN
    MOVE.L (A7),D0                    D0:=SAVED USER SIZE;
    ADD.L  #255,D0                    D0:=SIZE ROUNDED TO MULTIPLE OF 256;
    CLR.B  D0
    BSR    MM_PUSHU                   RESERVE_U_SPACE(HOLDER,SIZE,
*                                       A4:=PHYS ADDR,A6:=TOP OBJ);
  IF <EQ> THEN.S                    IF NOT OK THEN
    MOVE   #SE_SIZ,D0                 D0:=SIZE OF SEGM DESCRIPTOR;
    BSR    MM_POPD                    RELEASE_DESCRIPTOR(HOLDER,SIZE,SEGM OBJ)
    CMP    D0,D0                      SR:=EQ;  "NOT OK"
  ELSE.S                            ELSE  "SPACE SUFFICIENT"
    SUB    #SE_SIZ,ST_FIR(A1)         STRUCT.FIRST_EMB:=...-DESCR_SIZE;
    BSR    INS_OWN                    INSERT_OWNER (PSTR,PREL,SEGM OBJ,
*                                       A6:=PT ADDR);
    CLR    SE_IO(A5)                  SEGM.IO_COUNT:=0;
    MOVE.L A4,SE_FIR(A5)              SEGM.FIRST:=PHYS ADDR;
    MOVE.L (A7),SE_LEN(A5)            SEGM.LENGTH:=USER SIZE;  "UNROUNDED"
    INIT_HEAD SE_WAIT(A5),A6          IO_LOCK_WAIT:=EMPTY;
    INIT_HEAD OB_REF(A5),A6           SEGM.REFERRED_BY:=EMPTY;
    CLR    OB_RES(A5)                 SEGM.RESIDENT_COUNT:=0;
    MOVE   #SE_SIZ,OB_SIZK(A5)        SEGM.SIZE_KERNEL_PART:=SIZE OF DESCRIPTOR;
    MOVE #OB_SEOB<<8+1<<OB_EMB+1<<OB_READ+1<<OB_WRIT+1<<OB_EXEC,OB_KIN(A5)
*                                     SEGM.KIND,STATE:=...; SR:=NE;  "OK"
***
    PRT_MEM CRE_SEG,(A5),SE_SIZ
  ENDI                              END  "SPACE SUFFICIENT"
  ENDI                              END  "DESCRIPTOR RESERVED";
 
    MOVEM.L (A7)+,D0/A4/A6            RESTORE A4,A6, USER SIZE;
    RTS                               RETURN
    PAGE
CRE_SUB    EQU *                  CREATE EMBEDDED SUBSEGMENT
 
*          CALL:                  RETURN:
* A0       HOLDER                 SAME  (EXT,OPEN, OR GENERAL OBJECT)
* A1       POINTER STRUCT         SAME  (OWNER POINTER)
* A5       BASE SEGM OBJ          SUBSEGM  OBJ  (IF OK)
* D1       POINTER REL            SAME  (OWNER POINTER)
* D2       LENGTH (UNROUNDED, >0) UNDEF
* D4       CAPS                   UNDEF  (READ,WRITE,EXECUTE AS IN OB_STA)
* D5       FIRST REL              UNDEF
* SR       -                      NE = OK, EQ = NOT OK  ("NO SPACE" ONLY)
 
* CREATES AN EMBEDDED SUBSEGMENT DESCRIPTOR WHICH REFERS TO A PART
* OF THE BASE SEGMENT.  THE POINTER BECOMES THE OWNER POINTER.
 
    MOVEM.L A4-A6,-(A7)
    MOVE   #SU_SIZ,D0                 D0:=SIZE OF SUBSEGM DESCR;
    BSR    MM_PUSHD                   RESERVE_DESCRIPTOR(HOLDER,SIZE,
*                                       A5:=SUBSEGM,A6:=TOP OBJ);
  IF <NE> THEN.S                    IF OK THEN
    SUB    #SU_SIZ,ST_FIR(A1)         STRUCT.FIRST_EMB:=...-DESCR_SIZE;
    BSR    INS_OWN                    INSERT_OWNER(PSTR,PREL,SUBSEGM,
*                                       A6:=PT ADDR);
    CLR    SE_IO(A5)                  SUBSEGM.IO_COUNT:=0;
    MOVE.L 4(A7),A4                   A4:=BASE SEGMENT OBJ;
    MOVE.L A5,4(A7)                   STACK.A5:=SUBSEGM;
    ADD.L  SE_FIR(A4),D5              D5:=SUBSEGM.FIRST:=FIRST REL
    MOVE.L D5,SE_FIR(A5)                + BASE SEGM.FIRST;
    MOVE.L D2,SE_LEN(A5)              SUBSEGM.LENGTH:=LENGTH;
    INIT_HEAD SE_WAIT(A5),A6          IO_LOCK_WAIT:=EMPTY;
    MOVE.L A4,SU_REF(A5)              SUBSEGM.BASE:=BASE SEGM;
    MOVE.B #PT_SEG,SU_KIN(A5)         SUBSEGM.KIND:=REF FROM SUBSEGM;
    INIT_HEAD OB_REF(A5),A6           SUBSEGM.REFERRED_BY:=EMPTY;
    CLR    OB_RES(A5)                 SUBSEGM.RESIDENT_COUNT:=0;
    MOVE   #SU_SIZ,OB_SIZK(A5)        SUBSEGM.SIZE_KERNEL_PART:=DESCR SIZE;
    ADD #OB_SEOB<<8+1<<OB_EMB+1<<OB_SUB,D4
    MOVE   D4,OB_KIN(A5)              D4:=SUBSEGM.KIND:=...+CAPS;
    LEA    OB_REF(A4),A4              A4:=BASE_SEGM.REFERRED_BY;
    LEA    SU_P(A5),A5                A5:=SUBSEGM.BASE SEGM;
    INS_ELEM A4,A5,A6,A4/A6           INSERT(HEAD=BASE SEGM, NEW = SUBSEGM,
*                                       A6:=PREV);  SR:=NE;  "OK"
    LEA    -SU_P(A5),A5               A5:=SUBSEGM;
  ENDI                              END  "OK";
***
    PRT_MEM CRE_SUB,(A5),SU_SIZ
    MOVEM.L (A7)+,A4-A6               RESTORE A4,A5 (=SUBSEGM),A6
    RTS
    PAGE
MAKE_REENT EQU *                  MAKE GENERAL OBJECT REENTRANT
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_PRIM                     CHECK PRIMARY ENV(A0:=OBJ,
*                                       A1/A5/A6/D1/D2/D4/D5:=...)
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BSET.B #OB_REEN,OB_STA(A0)        OBJ.REENTRANT:=TRUE
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_FAST                   RETURN TO USER;
 
 
SET_CALL_STK EQU *                SET CALL STACK FOR GENERAL OBJECT
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_PRIM                     CHECK PRIMARY ENV(A0:=OBJ,A5:=TOP ENV
*                                       A1/A6/D1/D2/D4/D5:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
 
* CHECK THAT NO OBJECT IS MANAGED BY THIS OBJECT: PREVENT TERM STACK VIOLATE.
    MOVE   #EN_SIZ,D5
  WHILE D5 <NE> EN_TOPL(A5) DO.S    FOR ALL LOCALS IN TOP ENV DO
    CMP.B  #PT_MAN,PT_KIN(A5,D5)      IF LOCAL.KIND = MAN_SET
    BEQ    EE_STATE                   THEN REJECT END;
    ADD    #PT_SIZ,D5
  ENDW                              END;
    LEA    GE_EX(A0),A3               A3:=HEAD EXECUTED BY;
    MOVE.L (A3),A6                    A6:=FIRST CTX EXECUTED;
  WHILE.L A6 <NE> A3 DO.S           FOR ALL CONTEXTS EXECUTED DO
    MOVE   #CT_SIZ+PT_SIZ,D3          D3:=T(1);
  WHILE D3 <NE> CT_TOPT(A6) DO.S    FOR ALL TEMPS IN CTX DO
    CMP.B  #PT_MAN,PT_KIN(A6,D3)      IF TEMP.KIND=MAN_SET
    BEQ    EE_STATE                   THEN REJECT END;
    ADD    #PT_SIZ,D3
  ENDW                              END  "FOR ALL TEMPS"
    MOVE.L (A6),A6                    A6:=CTX:=NEXT(CTX);
  ENDW                              END  "FOR ALL CONTEXTS"
    BSR    C_SIZ                      CHECK SIZE(D0/D1:=SIZE);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE.L D0,GE_STK(A0)              OBJ.CALL STACK REQUIREMENT:=SIZE;
    MOVE   D1,GE_STK+SZ_K(A0)
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_FAST                   RETURN TO USER;
    PAGE
CLR_PT     EQU *                  CLEAR POINTER  (OF ANY KIND)
 
*          CALL:                  RETURN:
* A1       POINTER STRUCT         SAME  (RESTORED THROUGH T(0))
* A2       -                      IF OWNER POINTER:  UNDEF, ELSE:  SAME
* A3       CURRENT CTX            SAME  (UPDATED FOR RELOCATION).
* D1.W     POINTER REL            SAME
* OTHER REGS:  -                  UNDEF
* T(0):    NIL OR REF_ENV         SAME  (NIL: PT_STR=CTX, REF_ENV: PT_STR=ENV)
 
* DEPENDING ON POINTER KIND, THE POINTER IS CLEARED AS FOLLOWS:
* SIMPLE:  AS CLEAR SIMPLE POINTER  (CLR_SMP)
* OWN_SET: ALL OBJECTS IN OWNER SET ARE DELETED.  NONE OF THEM ARE EMBEDDED
*          SINCE EMBEDDED OBJECTS IN POINTER STRUCT HAVE BEEN DELETED.
* MAN_SET: ALL ENVELOPES IN MAN_SET ARE DEMANAGED AS FOLLOWS:  REFS AND
*          ACTUALS TO ENV ARE REMOVED, THE ENV IS REMOVED FROM MAN_SET
*          AND GETS A DUMMY MANAGER, THE ENV AND POSSIBLE BRANCHES ARE ABORTED.
* INTRPT_PT:  DRIVER IS REMOVED.
 
    MOVEQ.L #0,D2
    MOVE.B PT_KIN(A1,D1),D2           D2:=POINTER KIND *2;
    LSL    #1,D2
    CASEJMP D2                        CASE POINTER KIND OF
    CASELAB RETURN                NIL: RETURN;
    CASELAB CLR_SMP               REF_OBJ:  CLEAR SIMPLE POINTER; RETURN;
    CASELAB CLR_SMP               REF_ENV:  CLEAR SIMPLE POINTER; RETURN;
    CASELAB OWN_4                 OWN_SET:  "SEE BELOW"
    CASELAB MAN_4                 MAN_SET:  "SEE BELOW"
    CASELAB INT_4                 INTRPT_PT:  "SEE BELOW"
 
OWN_4      EQU *                  OWN_SET:
  REPEAT                            REPEAT
    MOVE.L 4(A1,D1),A5                A5:=OBJ:=POINTER.LAST_OBJ;
    MOVE.L OB_SPA(A5),A6              A6:=TOP OBJ;
    LEA    SP_ENV(A6),A0              A0:=HEAD OF ENV STACK;
    MOVE.L SP_ENV+4(A6),A4            A4:=ENV:=TOP ENVELOPE;
  IF.L A0 <NE> A4 THEN.S            IF HEAD <> TOP ENVELOPE
    LEA    -EN_STK(A4),A4             "OFFSET ENV"
    TST    EN_TERM(A4)              AND
  IF <GT> THEN.S                      ENV.TERM_PROC=TERM PROC CALLED THEN
 
* "TOP ENVELOPE TO BE DELETED.  POINTER CAN ONLY BE IN CURRENT CTX".
    MOVE   D1,-(A7)                   SAVE POINTER REL;
    BSR    D_ENV_OK                   DELETE_ENV(CTX,ENV,A3:=CTX,A5:=OBJ,
*                                       OTHER REGS:=UNDEF);
    MOVE   (A7)+,D1                   RESTORE POINTER REL;
    MOVE.L A3,A1                      POINTER STRUCT:=CURRENT CTX;
  ENDI
  ENDI                              END  "DELETE TOP ENVELOPE";
 
    LEA    DEL_ARG,A4                 A4/D4:=DEFAULT ARG LIST;
    MOVE.L #LOW_ARG,D4                CALL NEXT MANAGER(CTX,OBJ,PREL,PSTR,
    BSR    C_NXT_M                      ARG,LOWARG,D6/D7:=RESULT,
*                                       A0/A2/A4-A6/D0/D2-D5:=UNDEF);
  UNTIL.B PT_KIN(A1,D1) <EQ> #PT_NIL  UNTIL POINTER KIND=NIL;
    RTS                               RETURN;
 
 
MAN_4      EQU *                  MAN_SET:
  REPEAT                            REPEAT
    MOVE.L 4(A1,D1),A5                A5:=ENV:=POINTER.LAST_ENV;
    BSR    DUM_ACT                    DUMMYFY ACTUAL REFS(ENV,A0/A4/A6:=UNDEF);
    BSR    DUM_ENV                    DUMMYFY ENV REFS(ENV,A0/A4/A6:=UNDEF);
*                                       "ALSO REMOVES FROM MAN_SET"
    CLR    EN_TERM(A5)                ENV.TERM PROC:=DUMMY;
    BSR    ABORT_ENV                  ABORT ENVELOPE(ENV);
* REMOVES ENV FROM MAN_SET. ABORTS POSSIBLE BRANCHES TOO
  UNTIL.B PT_KIN(A1,D1) <EQ> #PT_NIL  UNTIL POINTER KIND=NIL;
    RTS                               RETURN
 
 
INT_4      EQU *                  INTERRUPT POINTER:
    MOVEM.L D1/A1/A3,-(A7)            SAVE D1,A1,A3;
    LEA    (A1,D1),A6                 A6:=DRIVER POINTER;
    BSR    TERMDRIV                   TERMINATE DRIVER (DRIVPT,D0/D1/A1/A3/A6
*                                       :=UNDEF)
    MOVEM.L (A7)+,D1/A1/A3            RESTORE;
    RTS                               RETURN
 
 
LOW_ARG    DCB.B AR_SIZ,0         DEFAULT ARG LIST:  VOID VAL SEGM;
DEL_ARG    DS.W  0
    PAGE
DEL_EMB    EQU *                  DELETE EMBEDDED OBJECTS (SEGMENTS ONLY)
 
*          CALL:                  RETURN:
* A1       STRUCTURE              SAME  (TOP_CTX OR TOP_ENV)
* A3       CURRENT CTX            SAME  (UPDATED FOR RELOCATION)
* A6       -                      TOP HOLDING OBJECT (FOR ADDRESSING SPACE DESC
* OTHER:   -                      UNDEF
* T(0):    NIL OR REF_ENV         SAME  (USED FOR RESTORING "STRUCTURE")
 
* ABORTS ALL EMBEDDED OBJECTS, RELEASES THE USER PART, AND REMOVES
* THE OBJECT FROM THE OWNER SET.  FINALLY RELEASES THE KERNEL PARTS.
* IO-POINTERS IN STRUCTURE MUST HAVE BEEN CLEARED PRIOR TO DEL_EMB, SINCE
* OTHERWISE THE IO-LOCK MAY NEVER BE RELEASED.
* USE OF T(0) FOR RESTORING:  SEE RSTO_STR.
 
    MOVE   ST_FIR(A1),D1              D1:=CUR_REL:=STRUCT.FIRST EMBEDDED;
  WHILE <NE> DO.S                   WHILE MORE EMBEDDED OBJECTS DO
***
    PRT_REG DEL_EMB
    LEA    (A1,D1),A5                 A5:=OBJ:=STRUCT+CUR_REL;
    BSR.S  AB_SEGM                    ABORT SEGMENT(CTX,OBJ,STRUCT,CUR_REL,
*                                       A1:=STRUCT "USING T(0)",D0:=SIZE KNEL EN
*                                       A5:=OBJ,A0/A2/A4/A6/D2-D5:=UNDEF);
* ALSO RELEASES USER PART OF ROOT SEGMENTS.
    BSR    DUM_OBJ                    DUMMYFY OBJECT(OBJ,A0/A4/A6:=UNDEF);
* CLEARS OBJ_REFS TO OBJECT AND REMOVES FROM OWNER SET.
    ADD    OB_SIZK(A5),D1             D1:=CUR_REL:=...+OBJ.SIZE KNEL PART;
  ENDW                              END;
    MOVE   ST_FIR(A1),D0              D0:=-SIZE:=STRUCT.FIRST EMBEDDED;
    LEA    (A1,D0),A5                 A5:=FIRST OBJ:=STRUCT+FIRST EMBEDDED;
    MOVE.L ST_HOLD(A1),A0             A0:=HOLDER:=STRUCT.HOLDER OBJECT;
    NEG    D0                         D0:=SIZE OF ALL EMBEDDED KNEL PARTS;
    BSR    MM_POPD                    RELEASE DESCRIPTORS(HOLDER,FIRST OBJ,SIZE,
*                                       A6:=TOP HOLDER);
    MOVE   #0,ST_FIR(A1)              STRUCT.FIRST_EMB:=0;
    RTS                               RETURN;
    PAGE
AB_SEGM    EQU *                  ABORT SEGMENT
 
*          CALL:                  RETURN:
* A1       STRUCTURE (IF EMBEDDED)  SAME OR STRUCTURE RESTORED THROUGH T(0).
* A3       CURRENT CTX            SAME  (UPDATED FOR RELOCATION)
* A5       SEGMENT OBJECT         RESTORED THROUGH T(0) AND "REL".
* D0       -                      SIZE  (OF KERNEL ENVELOPE PART)
* D1       REL                    SAME  (IF < 0: EMBEDDED SEGM)
* OTHER:   -                      UNDEF
* T(0):    NIL,REF_ENV,OWN_SET    SAME  (USED FOR RESTORING SEGM AND STRUCTURE)
 
* WAITS FOR IO-COUNT TO BECOME ZERO.
* THIS SEGMENT AND THE BRANCH OF SUB-SEGMENTS ARE SEARCHED. ALL SEGMENTS GETS
* ALL SEGMENTS GET USE_BITS=0.(INACCESSIBLE SEGS. ARE EQUIVALENT TO "ABORTED").
* ALL MMU_DESCRIPTORS REFERRING TO THE SEGMENTS ARE DISABLED.
* ALL INTERRUPT POINTERS REFERING TO THE SEGMENTS ARE TERMINATED (BECOMES NIL).
* RESIDENT COUNT OF ALL SEGMENTS ON THE PATH TOWORDS THE ROOT SEGMENT ARE
* DECREASED WITH THE VALUE OF RESIDENT COUNT IN THIS SEGMENT, AND THE POINTER
* TO THE BASE SEGMENT IS CLEARED.
* IF THE SEGMENT IS A ROOT SEGMENT, THE USER PART OF IT IS RELEASED.
 
* "STRUCTURE" IS ONLY USED FOR EMBEDDED ROOT SEGMENTS AND MUST THEN
* BE THE STACK ELEMENT HOLDING THE EMBEDDED SEGMENT.  SEE ALSO RSTO_STR.
 
***
    PRT_REG AB_SEGM
  WHILE SE_IO(A5) <NE> #0 DO.S      WHILE SEGM.IO_COUNT <> 0 DO
    MOVE   D1,-(A7)                   SAVE REL;
    LEA    SE_WAIT(A5),A1             A1:=IO_CONDITION;
    BSR    KNELWAIT                   IO_CONDITION.WAIT(A2:=A3:=CTX,
*                                       OTHER:=UNDEF);
    MOVE   (A7)+,D1                   D1:=RESTORE REL;
    BSR    RSTO_STR                   RESTORE STRUCT(CTX,REL,A1:=STRUCT,A5:=SEGM
  ENDW                              END  "IO-COUNT";
 
*                                 "ABORT TREE OF SUBSEGMENTS AND REFS:"
    MOVE.L A5,A6                      A6:=CUR_SEGM:=SEGM;
AB_NEXT1   EQU *                  PROCEDURE ABORT_NEXT(CUR_SEGM): "RECURSIVE"
    AND.B  #-1-(7<<OB_READ),OB_STA(A6) CUR_SEGM.USE_BITS:= NO_USEBITS=0;
    LEA    OB_REF(A6),A0              A0:=HEAD;
    MOVE.L (A0),A2                    A2:=CUR_REF:=CUR_SEGM.FIRST REF;
 
  WHILE.L A2 <NE> A0 DO.S           WHILE CUR_REF <> HEAD DO
    CLR    D0
    MOVE.B PT_KIN(A2),D0              D0:=CUR_REF.REF_KIND;
***
    PRT_REG AB_NEXTREF
    LSL    #1,D0
    CASEJMP D0                    CASE REF_KIND OF
    CASELAB HALT                  NIL:
    CASELAB NEXT_5                REF_OBJ:  "NO ACTION"
    CASELAB HALT                  REF_ENV:
    CASELAB HALT                  OWN_SET:
    CASELAB HALT                  MAN_SET:
    CASELAB INT_5                 INTERRUPT POINTER:
    CASELAB MMU_5                 MMU DESCR:
    CASELAB SUB_5                 SUB_SEGM DESCR:
 
INT_5      EQU *                  INTERRUPT POINTER:
    MOVEM.L D1/A1/A3/A6,-(A7)         SAVE REGISTERS;
    MOVE.L A2,A6                      A6:=DRIVER PT;
    MOVE.L 4(A6),A2                   A2:= PT.PREV; "POINTER BECOMES NIL"
    BSR    TERMDRIV                   TERMINATE DRIVER(DRIVPT,D0/D1/A1/A3:=?);
    MOVEM.L (A7)+,D1/A1/A3/A6         RESTORE;
    BRA.S  NEXT_5                     GOTO NEXT REF;
 
MMU_5      EQU *                  MMU DESCR:
    CLR    MM_REG+6(A2)               MMU_DESCR.ENABLE:=DISABLE;
    BRA.S  NEXT_5                     GOTO NEXT REF;
 
SUB_5      EQU *                  SUB_SEGM DESCR:
    LEA    -SU_P(A2),A6               A6:=CUR_SEGM:=SUB_SEGM;
    BRA    AB_NEXT1                   ABORT_NEXT(SUB_SEGM);  "SIMULATE CALL"
 
NEXT_5     EQU *                  NEXT REF:
    MOVE.L (A2),A2                    A2:=CUR_REF:=NEXT(CUR_REF)
  ENDW                              END  "FOR ALL REFS";
 
  IF.L A6 <NE> A5 THEN.S            IF CUR_SEGM <> SEGM THEN
*                                   "SIMULATE RETURN FROM RECURSIVE ABORT_NEXT:"
    LEA    SU_P(A6),A2                A2:=CUR_REF:=CUR_SEGM.REF ADDR;
    MOVE.L SU_REF(A6),A6              A6:=CUR_SEGM:=CUR_SEGM.BASE_SEGM;
    LEA    OB_REF(A6),A0              A0:=CUR_SEGM.HEAD;
    BRA    NEXT_5                     GOTO NEXT_REF;  "RETURN"
  ENDI                              END;  "END PROCEDURE ABORT_NEXT"
 
    BTST.B #OB_SUB,OB_STA(A5)
  IF <NE> THEN.S                    IF SEGM IS SUB_SEGM THEN
    REM_ELEM SU_P(A5),A2,A6,A2/A6     REM. PT. TO BASE_SEGM. FRM CHAIN AND MAKE
    INIT_HEAD SU_P(A5),A6             IT SELF_REF; A6:=PT; PT_REF IS STILL OK;
    MOVE.W OB_RES(A5),D0              D0:=RES_COUNT OF SEGM.
  IF <GT> THEN.S                    IF RES_COUNT > 0 THEN "DECR. IN BASE_SEGS"
    MOVE.W D1,D3                      D3:= SAVE PT_REL;
    MOVE.L A3,A4                      A4:= SAVE CTX;
    MOVE.W #OB_RES,D1                 D1:= ADDR OF RESIDENT COUNT
    BSR.L  INCRDECR                   DECREASE RESIDENT COUNTS;A3/A6:=?;
    MOVE.W D3,D1                      D1:= RESTORED PT_REL FROM D3;
    MOVE.L A4,A3                      A3:= RESTORED CTX FROM A4;
  ENDI                              ENDI;
    CLR.L SU_REF(A5)                  REF TO BASE SEGM:=0; " = NO BASE SEGM"
    MOVE   #SU_SIZ-OB_SIZ,D0          D0:=SIZE OF SUB_SEGM KERNEL ENVELOPE
  ELSE.S                            ELSE
    BTST.B #OB_EMB,OB_STA(A5)       "ROOT SEGMENT:"
  IF <NE> THEN.S                    IF SEGM IS EMBEDDED THEN
    MOVE.L ST_HOLD(A1),A0             A0:=HOLDER:=STRUCTURE.HOLDER;
  ELSE.S                            ELSE
    MOVE.L A5,A0                      A0:=HOLDER:=SEGM
  ENDI                              END;
    MOVE.L A5,A4                      A4:=DESCRIPTOR:=SEGM;
    MOVE.L SE_LEN(A4),D0
    ADD.L  #255,D0                    D0:=SEGM.LENGTH ROUNDED TO MULTIPLE 256;
    CLR.B  D0
    BSR    MM_POPU                    RELEASE_U_SPACE(HOLDER,DESCRIPTOR,SIZE,
*                                       A6:=TOP_HOLDER);
    MOVE   #SE_SIZ-OB_SIZ,D0          D0:=SIZE OF SEGM KERNEL ENVELOPE
  ENDI                              END  "ROOT SEGMENT"
    RTS                               RETURN
    PAGE
DEL_ENV    EQU *                  DELETE ENVELOPE
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
*                                 "GET OWN_SET AND TOP ENVELOPE:"
    BSR    C_ENT                      CHECK ENTITY(A1:=PSTR,D1:=PREL,A6:=PT,
*                                       A5:=OBJ,D2:=PTKIND,D4/D5:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_OWN,D2                 IF POINTER KIND <> OWN_SET
    BNE    EE_VALUE                   THEN REJECT END;
    BTST.B #PT_LSC,PT_INF(A6)         IF POINTER SCOPE = LOCAL
    BNE    EE_SCOPE                   THEN REJECT END;
    MOVE.B OB_KIN(A5),D2              D2:=OBJ.KIND;
    BTST.B D2,OBJ_USER                IF OBJ.KIND <> GENERAL,OPEN
    BEQ    EE_STATE                   THEN REJECT END;
    MOVE.L OB_SPA(A5),A6              A6:=TOP OBJ;
    MOVE.L SP_ENV+4(A6),A3            A3:=OBJ.TOP ENV;
    LEA    SP_ENV(A6),A6              A6:=OBJ.ENV STACK HEAD
    CMPA.L A6,A3                      IF ENV STACK EMPTY
    BEQ    EE_STATE                   THEN REJECT END;
    LEA    -EN_STK(A3),A3             A3:=ENV:="OFFSET TOP ENV";
 
*                                 "GET MAN_SET:"
    BSR    C_PT                       CHECK POINTER(A1:=PSTR,D1:=PREL,A6:=PT,
*                                       D2:=PTKIND);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMPA.L EN_MAN(A3),A1              IF ENV.MANAGER ENV <> POINTER STRUCT
    BNE    EE_VALUE                   THEN REJECT END;
    CMP    EN_OFF(A3),D1              IF ENV.MANAGER PREL <> POINTER REL
    BNE    EE_VALUE                   THEN REJECT END;
 
    BSR    S_LOC                      STACK CHECK LOCALS(A2=CTX,A3=ENV,
*                                       A0/A6/D0/D4/D5:=UNDEF);
    BEQ    RET_FAST                   IF NOT OK THEN REUTRN TO USER END;
    MOVE.L A3,A4                      A4:=ENVELOPE;
    MOVE.L A2,A3                      A3:=CURRENT CTX;
    BSR.S  D_ENV_OK                   DELETE ENVELOPE(CTX,ENVELOPE,A5:=OBJ;
*                                       OTHER REGS:=UNDEF);
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD3                   RETURN TO USER(A3=CTX);"DELETION POSSIBLE"
 
OBJ_USER   DC.B 1<<OB_GEOB+1<<OB_OPOB  MASK FOR USER OBJECT KINDS.
    DS.W   0
* OBJ_USER MAY INCLUDE 1<<OB_DOOB WHEN SCHEDULER'S ENVELOPES
* ARE HANDLED "CORRECTLY".
    PAGE
D_ENV_OK   EQU *                  DELETE ENVELOPE  (CHECKS OK)
 
*          CALL:                  RETURN:
* A3       CURRENT CTX            SAME  (UPDATED FOR RELOCATION)
* A4       ENVELOPE               UNDEF
* A5       -                      OBJECT HOLDING ENVELOPE
* OTHER REGS:  -                  UNDEF
* T(0):    NIL                    NIL  (USED AS REF_ENV DURING D_ENV_OK)
 
* DUMMYFIES ALL REFS AND ACTUALS REFERRING TO THE ENVELOPE.
* REMOVES THE ENVELOPE FROM THE MAN_SET (AND GIVES IT A DUMMY MANAGER).
* ABORTS THE ENVELOPE (EXCLUDING POSSIBLE BRANCHES).
* CLEARS POSSIBLE LOCAL IO_LOCKS AND DELETES EMBEDDED SEGMENTS.
* CLEARS ALL LOCAL POINTERS (THIS WILL ABORT POSSIBLE BRANCHES).
* RELEASES ENV SPACE.
* IF THE OBJECT HOLDING THE ENVELOPE IS A GENERAL OBJECT, IT BECOMES AN OPEN OB
* T(0) OF CURRENT CTX IS USED TO KEEP TRACK OF THE ENV DURING DELETION.
 
    MOVE.L A4,A5                      A5:=ENV;
    BSR    DUM_ACT                    DUMMYFY ACTUAL REFS(ENV,A0/A4/A6:=UNDEF);
    BSR    DUM_ENV                    DUMMYFY ENV REFS(ENV,A0/A4/A6:=UNDEF);
*                                       "ALSO REMOVES FROM MAN_SET"
    BSR    ABORT_ONE                  ABORT_ONE(ENV);
    LEA    CT_SIZ(A3),A6              A6:=PT_ADDR:=T(0);
    MOVE   #PT_ENV,D5                 D5:=ENTITY KIND:=REF_ENV;
    BSR    COPY_NIL                   COPY TO NIL(A5=ENV,PT ADDR,ENT KIND,
*                                       A1/D4:=UNDEF);
    MOVE.L A5,A1                      A1:=ENV;
 
    TST    EN_IO(A4)              "CLEAR POSSIBLE IO-LOCKS:"
  IF <NE> THEN.S                    IF ENV.IO_COUNT <> 0 THEN
    MOVE   #EN_SIZ,D1                 D1:=CUR_LOCAL:=ENV.LOC(1);
  WHILE D1 <NE> EN_TOPL(A1) DO.S    FOR D1:=ALL LOCALS IN ENV DO
*                                   IF LOCAL IS SIMPLE THEN
  IF.B PT_KIN(A1,D1) <LE> #PT_ENV THEN.S  "DRIVER POINTERS MAY BE PRESENT"
    BSR    CLR_SMP                    CLEAR SIMPLE PT(PSTRUCT=ENV,PREL,A6:=PT);
  ENDI                              END;
    ADD    #PT_SIZ,D1                 D1:=CUR_LOCAL:=NEXT
  ENDW                              END  "FOR ALL LOCALS";
  ENDI                              END  "IO COUNT <> 0";
 
    BSR    DEL_EMB                    DELETE EMBEDDED (A1=ENV,CTX,
*                                       A0/A2/A4-A6/D0-D7:=UNDEF);
*                                       "MAY RESTORE A1 THROUGH T(0)"
 
*                                 "CLEAR ALL LOCAL POINTERS:"
    MOVE   #EN_SIZ,D1                 D1:=CUR_LOCAL:=ENV.LOC(1)
  WHILE D1 <NE> EN_TOPL(A1) DO.S    FOR D1:=ALL LOCALS IN ENV DO
    BSR    CLR_PT                     CLEAR POINTER(PSTRUCT=ENV,CTX,PREL,
*                                       A0/A2/A4-A6/D0/D2-D7:=UNDEF);
*                                       "MAY RESTORE A1=ENV THROUGH T(0)"
    ADD    #PT_SIZ,D1                 D1:=NEXT LOCAL;
  ENDW                              END  "FOR ALL LOCALS";
 
    REM_ELEM CT_SIZ(A3),A4,A5,A4/A5   REMOVE (T(0),A4:=NEXT,A5:=PREV);
    CLR.B  PT_KIN+CT_SIZ(A3)          T(0).KIND:=NIL;
    MOVE.L EN_OBJ(A1),A5              A5:=OBJECT HOLDING ENV;
    EXG.L  A1,A3                      A3:=ENV, A1:=CTX;
    BSR    MM_POPK                    RELEASE STACK ELEMENT(A3=ENV,A3:=PREV,
*                                       A6:=TOP OBJ);
    MOVE.L A1,A3                      A3:=CTX;
  IF.B OB_KIN(A5) <EQ> #OB_GEOB THEN.S
    MOVE.L A5,A0                    IF OBJ.KIND=GENERAL OBJECT THEN
    MOVE   #GE_SIZ-OB_SIZ,D0
    BSR    MM_POPO                    RELEASE KERNEL ENV(A0=OBJ,D0=SIZE,
    MOVE.B #OB_OPOB,OB_KIN(A5)        A6:=TOP OBJ); OBJ.KIND:=OPEN OBJECT
  ENDI                              END;
    RTS                               RETURN;
    PAGE
DEALLOC    EQU *                  DEALLOCATE OBJECT
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_PT                       CHECK POINTER(A6:=PT,D2:=PT KIND,
*                                       A1/D1:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_OWN,D2                 IF POINTER KIND <> OWN SET
    BNE    EE_VALUE                   THEN REJECT END;
    MOVE.L A6,D0                      D0:=OWN PT ADDR;
    MOVE.L D4,D3                      D3:= LOWARG;
    BSR    C_ENT                      CHECK ENTITY(A5:=OBJ,D5:=ENT KIND,
*                                       A1/A6/D1/D2/D4:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE.L D3,D4                      D4:= LOWARG;
    CMP.B  #PT_OBJ,D5                 IF ENTITY KIND <> OBJECT
    BNE    EE_VALUE                   THEN REJECT END;
    SUB.L  OB_OWN(A5),D0              IF OBJ.OWNER <> OWN PT ADDR
    CMP    OB_OFF(A5),D0              THEN REJECT END;
    BNE    EE_VALUE
    BTST.B #OB_EMB,OB_STA(A5)         IF OBJECT EMBEDDED
    BNE    EE_VALUE                   THEN REJECT END;
    MOVE.L A2,A3                      A3:=CURR CTX;
    BSR.S  C_NXT_M                    CALL NEXT MANAGER(CTX,ARG,OBJ,
*                                       LOW ARG,PREL=NONSENSE,D6/D7:=RESULT,
*                                       A0-A2/A4-A6/D0/D2-D5:=UNDEF);
    BRA    RET_OLD3                   RETURN TO USER;
    PAGE
C_NXT_M    EQU *                  CALL NEXT MANAGER AND DELETE OBJECT
 
*          CALL:                  RETURN:
* A1       POINTER STRUCTURE      RESTORED THROUGH T(0)
* A3       CURRENT CTX            SAME  (UPDATED FOR RELOCATION)
* A4       ARGUMENT ADDR (PHYS)   UNDEF
* A5       OBJECT TO BE DELETED   UNDEF  (ONLY NON-EMBEDDED OBJECTS ALLOWED)
* D1.W     POINTER REL            SAME  (POINTER WHICH OWNED OBJECT)
* D4       LOW ARG ADDR (PHYS)    UNDEF
* D6       ARGUMENT#              UPDATED OR RESULT RETURNED BY TOP MANAGER
* D7       -                      REJECT RESULT OR RESULT RETURNED BY TOP MANAGE
* T(0):    NIL OR REF_ENV         SAME (IF REF_ENV, OBJ IS OWNED BY THAT ENV)
* OTHER REGS:  -                  UNDEF
 
* CALLS THE NEXT MANAGER (IF ANY) AND EVENTUALLY DELETES THE OBJECT:
* IF THE OBJECT IS OF KERNEL TYPE, THE KERNEL TERMINATION PROCEDURE IS CALLED
* AND THE OBJECT BECOMES "OPEN".  DURING THIS, THE OBJECT IS OWNED BY T(0)
* OR THE ENVELOPE SPECIFIED BY (T(0).
* NEXT, IF THE OBJECT HAS NO MORE ENVELOPES, IT IS ACTUALLY DELETED, USING
* AGAIN T(0) TO GIVE POINTER ACCESS TO IT.
* OTHERWISE, IF THE OBJECT HAS MORE ENVELOPES, THE NEXT MANAGER IS CALLED
* AND AT RETURN, DEL_CTX WILL TAKE CARE OF CONTINUEING DELETION.
* ALSO A DUMMY MANAGER WILL BE "CALLED" USING A CONTEXT TO HANDLE DEL_ENV.
 
    MOVE   D1,-(A7)                   SAVE POINTER REL;
    MOVEQ  #0,D2
    MOVE.B OB_KIN(A5),D2              D2.W:=OBJ.KIND;
***
    PRT_REG C_NXT_M
    BTST.B D2,OBJ_USER              IF NOT USER OBJECT "GENERAL,OPEN"THEN
 
  IF <EQ> THEN                      "KERNEL OBJECTS:"
  IF.B PT_KIN+CT_SIZ(A3) <EQ> #PT_NIL THEN.S  "ESTABLISH POINTER ACCESS TO OBJ:
    MOVE.L A3,A1                      IF T(0).KIND = NIL THEN
    MOVE   #CT_SIZ,D1                 A1:=NEW PSTR:=CTX; D1:=NEW PREL:=T(0);
    BSR    S_MOVE                     MOVE_STACK_CHECK(NEW PSTR,NEW PREL,OBJ);
    BEQ    RET_C_NXT                  IF NOT OK THEN RETURN END;
    BSR    M_OWN_OK                   MOVE OWNER(NEW PSTR,NEW PREL,OBJ,A6:=PT);
  ENDI                              END  "T(0) IS NOW REF_ENV OR OWN_SET";
 
*                                 "PERFORM KERNEL TERMINATION PROCEDURE:"
    LSL    #1,D2                      D2:=OBJECT KIND *2;
    CASEJMP D2                      CASE OBJECT KIND OF
    CASELAB HALT                  GENERAL OBJECT:
    CASELAB GATE_TERM
    CASELAB COND_TERM
    CASELAB HALT                  OPEN OBJECT
    CASELAB DORM_TERM
    CASELAB PROC_TERM
    CASELAB HALT                  EXTENSION OBJECT
    CASELAB SEGM_TERM
    CASELAB HALT                  ALLOCATE
    CASELAB HALT                  SCHEDULER
 
GATE_TERM  EQU *                  GATE DELETE:
    MOVE.L A5,A0                      A0:=GATE;
    BSR    TERMGATE                   TERMINATE GATE(A0=GATE);
    MOVE   #GA_SIZ-OB_SIZ,D0          D0:=SIZE OF KERNEL ENVELOPE;
    BRA.S  D_K_ENV                    GOTO DELETE KERNEL ENVELOPE;
 
COND_TERM  EQU *                  CONDITION DELETE:
    MOVE.L A5,A0                      A0:=CONDITION;
    BSR    TERMCOND                   TERMINATE CONDITION(A0=CONDITION);
    MOVE   #CO_SIZ-OB_SIZ,D0          D0:=SIZE OF KERNEL ENVELOPE;
    BRA.S  D_K_ENV                    GOTO DELETE KERNEL ENVELOPE;
 
PROC_TERM  EQU *                  PROCESS DELETE:
* CHECK AGAINST SELF-DELETE WAS DONE AS PART OF MOVING OWNER-SHIP.
    LEA    PR_TERM(A5),A1             A1:=PROC TERM CONDITION;
    MOVE.L A3,A2                      A2:=CURRENT CTX;
    BSR    KNELWAIT                   PROC_TERM.WAIT(A3:=CTX,OTHERS:=UNDEF)
    MOVE   (A7),D1                    D1:=POINTER REL;
    BSR    RSTO_STR                   RESTORE STRUCT(CTX,REL,A1:=STRUCT,A5:=OBJ)
 
DORM_TERM  EQU *                  DORMANT DELETE:
    MOVE   #PR_SIZ-OB_SIZ,D0          D0:=SIZE KERNEL ENVELOPE;
    BRA.S  D_K_ENV                    GOTO DELETE KERNEL ENVELOPE;
 
 
SEGM_TERM  EQU *                  SEGMENT DELETE: "CANNOT BE EMBEDDED"
    MOVE   (A7)+,D1                   D1:=RESTORE POINTER REL; "OBS: MAX STACK"
    BSR    AB_SEGM                    ABORT SEGM(CTX,OBJ,POINTER REL, PSTR,
*                                       D0:=SIZE OF KERNEL ENVELOPE,
*                                       A0/A2/A4/A6/D2-D7:=UNDEF);
    MOVE   D1,-(A7)                   SAVE POINTER REL;
 
D_K_ENV    EQU *                  DELETE KERNEL ENVELOPE:
    MOVE.L A5,A0                      A0:=OBJ;
    BSR    MM_POPO                    RELEASE KERNEL ENV(OBJ,SIZE,A6:=TOPOBJ)
    MOVE   #OB_OPOB<<8,OB_KIN(A5)     OBJ.KIND,STATE:=OPEN OBJECT;
    MOVE.L #LOW_ARG,D4                A4/D4:=DEFAULT ARG LIST;
    LEA    DEL_ARG,A4
* "THE FOLLOWING CORRESPONDS TO KERNEL_TERM PERFORMING DEALLOC(OBJ):"
* "TERM STACK CHECK HAS BEEN DONE PREVIOUSLY".
  ENDI                              END  "KERNEL OBJECTS";
 
    MOVE.L OB_SPA(A5),A6              A6:=TOP OBJ;
    MOVE.L SP_ENV+4(A6),A2            A2:=OBJ.TOP ENV;
    LEA    SP_ENV(A6),A6              A6:=OBJ.ENV STACK HEAD;
  IF.L A6 <EQ> A2 THEN.S            IF NO MORE ENVELOPES THEN
 
*                                 "DELETE OBJECT:"
  IF.B PT_KIN+CT_SIZ(A3) <EQ> #PT_NIL THEN.S  "ESTABLISH POINTER ACCESS TO OBJ:"
    MOVE.L A3,A1                    IF T(0).KIND = NIL THEN
    MOVE   #CT_SIZ,D1                 A1:=NEW PSTR:=CTX; D1:=NEW PREL:=T(0);
    BSR    M_OWN_OK                   MOVE OWNER(NEW_PSTR,NEW_PREL,OBJ,A6:=PT)
  ENDI                              END  "T(0) IS NOW REF_ENV OR OWN_SET";
 
    TAS.B  MM_LOCK                    LOCK THE MM_LOCK;
  IF <NE> THEN.S                    IF LOCKED ALREADY THEN
    LEA    MM_QUEUE,A1                A1:=MM_QUEUE;
    MOVE.L A3,A2                      A2:=CUR_CTX;
    BSR    KNELWAIT                   MM_QUEUE.WAIT(A3:=CTX,OTHERS:=UNDEF);
    MOVE   (A7),D1                    D1:=SAVED POINTER REL;
    BSR    RSTO_STR                   RESTORE STRUCT(CTX,REL,A1:=STRUCT,A5:=OBJ)
  ENDI                              END;
    BSR    DUM_OBJ                    DUMMYFY OBJ(OBJ,A0/A4/A6:=UNDEF);
* CLEARS OBJ_REFS TO OBJECT AND REMOVES FROM OWN_SET.  T(0) IS NOW NIL OR REF_EN
    MOVE.L A5,A1                      A1:=OBJECT;
    BSR    MM_TERM                    RELEASE OBJ SPACE(OBJ,A0/D0/D1:=UNDEF);
    LEA    MM_QUEUE,A1                A1:=MM_QUEUE;
    BSR    KNELSIGN                   MM_QUEUE.SIGNAL(A4/A5/A6:=UNDEF);
  IF <NE> THEN.S                    IF NO PROC SCHEDULED THEN
    BCLR.B #7,MM_LOCK                 OPEN MM_LOCK
  ENDI                              END;
* D7:=RESULT:=OK IS SET AFTER 'ELSE'
 
  ELSE                              ELSE  "CALL TOP MANAGER:"
* T(0) IS NIL, REF_ENV OR OWN_SET (AFTER DELETE KERNEL ENVELOPE).
    LEA    -EN_STK(A2),A2             A2:=ENV:="OFFSET TOP ENV";
***
    PRT_MEM TERM_ENV,(A2),EN_SIZ
    MOVE   EN_TERM(A2),D5             D5:=FUNCTION:=ENV.TERM_PROC;
  IF <GT> THEN.S                    IF TERM PROC CALLED THEN
    ADDQ.L #2,A7                      POP PT_REL;   "ONLY POSSIBLE WHEN DEALLOC
    BRA    ER_STATE                   GOTO REJECT;     IS CALLED EXPLICIT ??"
  ENDI                              ENDI;
    MOVEM.L A2/A5,-(A7)               SAVE ENV, OBJ;
  IF <EQ> THEN.S                    IF DUMMY TERM PROC THEN
    MOVE.L #DUM_MAN,A5                A5:=MANAGER OBJ:=DUMMY MANAGER
  ELSE.S                            ELSE
    MOVE.L EN_MAN(A2),A1              A1:=MANAGER STRUCT;
    MOVE   EN_OFF(A2),D1              D1:=MANAGER PT REL;
    BTST.B #PT_LSC,PT_INF(A1,D1)
  IF <EQ> THEN.S                    IF NON LOCAL MAN_SET THEN
    MOVE.L #DUM_MAN,A5                A5:=MANAGER OBJ:=DUMMY MANAGER
  ELSE.S                            ELSE
    MOVE.L EN_OBJ(A1),A5              A5:=MANAGER OBJ:=MANAGER STRUCT.OBJECT;
  ENDI                              END;
  ENDI                              END  "A5 = MANAGER OBJ";
 
*                                   "CREATE CTX AND SET FORMALS:"
    MOVE.L A3,A2                      A2:=CUR_CTX;
    MOVE.L CT_HOLD(A2),A0             A0:=CUR_CTX.EXTENSION_OBJ;
    MOVE   #2,D3                      D3:=ADDITIONAL FORMALS:=2;
    BSR    CRE_CTX                    CREATE_CTX(...,A3:=NEW_CTX,D4:=ENTRY);
    MOVEM.L (A7)+,D0/D2               D0:=RESTORE ENV; D2:=RESTORE OBJ;
    BEQ    R2_C_NXT                   IF NOT OK THEN RETURN END;
    MOVE   CT_TOPT(A3),D1             D1:=NEW_CTX.F(1);
    MOVE.L D0,PT_REF+FP_SIZ(A3,D1)    F(2).REF:=ENV; "POINTER MADE LATER"
    MOVE.L D2,PT_REF(A3,D1)           F(1).REF:=OBJ; "POINTER MADE LATER"
    EXT.L  D5                         D5.L:=FUNCTION;
    BSR    SAVE_STK                   SAVE SUPV STACK(CTX,ENTRY,FUNCTION,
*                                       A5/A6:=UNDEF);
    BSR    SET_FP                     SET_FORMALS(EXT,CTX,NEW CTX,ARG ADDR,
*                                       ADDITIONAL FORMALS, ARG#,D3:=FORMALS,
*                                       A1/A5/A6/D0-D2/D4/D5:=UNDEF)
  IF <NE> THEN.S                    IF OK THEN
    MOVE   CT_TOPT(A3),D1             D1:=NEW PREL:=NEW_CTX.F(1);
    MOVE.L A3,A1                      A1:=NEW PSTR:=NEW_CTX;
    MOVE.L PT_REF(A1,D1),A5           A5:=OBJ:=F(1).REF; "OBJ TO DELETE"
    BSR    S_TERM                     STACK CHECK TERM(NEW PSTR,NEW PREL,OBJ);
  IF <NE> THEN.S                    IF OK THEN
*                                   "SET F(1), F(2):"
    BSR    M_OWN_OK                   MOVE OWNER(NEW PSTR,NEW PREL,OBJ,A6:=PT);
    CLR.L  FP_STR(A1,D1)              F(1).ACTUAL:=DUMMY;
    MOVE.L PT_REF+FP_SIZ(A1,D1),A5    A5:=ENV:=F(2).REF;
    MOVE   #PT_ENV,D5                 D5:=ENTITY KIND:=REF_ENV;
    CLR    D4                         D4:=CAPS:=O;
    LEA    FP_SIZ(A1,D1),A6           A6:=F(2);
    CLR.L  FP_STR(A6)                 F(2).ACTUAL:=DUMMY;
    BSR    COPY_NIL                   COPY TO NIL(F(2),ENV,REF_ENV,A1:=UNDEF);
    MOVE   #1,EN_TERM(A5)             ENV.TERM_PROC:=TERM PROC CALLED;
 
*                                "SET FORMAL ARGUMENTS:"
  IF.L A4 <EQ> #LOW_ARG THEN.S      IF ARG LIST = DEFAULT THEN
    MOVE.L #-1,D2                     D2:=DEALLOC MODE:=IMPLICIT; "-1"
  ELSE.S                            ELSE
    CLR    D2                         D2:=DEALLOC MODE:=EXPLICIT; "0"
  ENDI                              END;
    CLR.L  D4                         PREPARE DIVIDE;
    MOVE   EN_OFF(A5),D4              D4:=MANAGER INDEX:=
    SUB    #EN_SIZ-PT_SIZ,D4            (ENV.MAN OFFSET-L(0))/POINTER_SIZE;
    DIVU   #PT_SIZ,D4                 "NOT USED FOR TEMP MAN_SETS"
    MOVE.L (A3,D1),A1                 A1:=OBJ:=F(1).FIRST;  "OBJ TO DELETE"
    CLR    D5
    MOVE   OB_SIZK(A1),D5             D5.L:=TOTAL BYTES IN OBJ:=
    MOVE.L OB_SPA(A1),A6                SIZE KERNEL PART +
    ADD.L  SP_SIZU(A6),D5               TOP OBJ.SIZE USER PART;
 
    BSR    ENT_CTX                    ENTER CONTEXT(A3=CTX,D2,D3,D4,D5=...);
*                                     "CONTINUES HERE AT OBJ_RETURN.A3=CTX"
    BSR    RET_FP
  ENDI                              END  "STACK CHECK OK";
  ENDI                              END  "SET FORMALS OK";
 
    BSR    DEL_CTX                    DELETE_CTX(CTX,A3:=OLD CTX,A0:=EXT);
* "CONTINUES OBJECT DELETION ONLY AFTER A SUCCESSFUL CALL OF TERM PROC.
* IN OTHER CASES, F(1) IS NOT YET OWN_SET."
    BSR    RSTO_STK                   RESTORE SUPV STACK AND USP(OLD CTX);
  ENDI                              END  "CALL TOP MANAGER";
 
* AT PRESENT DEALLOC WILL IGNORE THE RESULT OF THE CALLED MANAGERS
* AND ALWAYS RETURN  'OK'  IF THE OBJECT WAS DEALLOCATED.
  MOVEQ.L  #0,D7                      D7:=RESULT:= OK;
 
RET_C_NXT  EQU *                  RETURN FROM C_NXT_M:
    MOVE   (A7)+,D1                   D1:=RESTORE POINTER REL;
    BSR    RSTO_STR                   RESTORE STRUCT (CTX,PREL,A1:=PSTR,
*                                       A5:=UNDEF "NORMALLY A5:=OBJ");
    RTS                               RETURN;
 
R2_C_NXT   EQU *                  RETURN FROM C_NXT_M, A2=CTX:
    MOVE.L A2,A3                      A3:=CUR_CTX;
    BRA.S  RET_C_NXT                  GOTO RETURN;
 
 
HALT       STOP #$2717            HALT:  STOP "KERNEL ERROR"
    BRA    HALT
 
 
* * * * THIS DATA STRUCTURE SHOULD BE MOVED TO SECTION  7
* * * *                     AND INITIALIZED IN SECTION 11
DUM_MAN    EQU *                  DUMMY MANAGER OBJECT:
    DS.W   MEMBER                     OWNER:
    DS.W   1
    DS.W   CHAIN                      REFERRED BY:
    DC.W   0                          RESIDENT COUNT:
    DC.W   0                          SIZE OF KERNEL PART:
    DC.B   OB_GEOB                    OBJECT KIND:  GENERAL OBJECT
    DC.B   1<<OB_ABOR                 OBJECT STATE:  ABORTED
    DS.L   1                          SPACE DESCR:  "ABSENT, NOT USED"
    DC.L   *                          EXECUTED BY:=
    DC.L   *-4                            EMPTY
    DC.W   0                          CONTROL PROCEDURE: DUMMY
    DC.W   1                          TEMP POINTERS:  1 "T(0)"
    DC.L   2                          TEMP STACK:  > 0, EVEN
    DC.L   0                          REQUIRED FREE CALL STACK:  0
    DC.W   0
    DC.L   $200000                    LOGICAL ADDRESS FOR TEMP STACK:
    DC.L   0                          ENTRY ADDRESS:
 
* CHECK LENGTH OF OBJECT AT ASSEMBLY TIME.
  IFNE     *-DUM_MAN-GE_SIZ
    FAIL   *-DUM_MAN-GE_SIZ
  ENDC
    PAGE
RSTO_STR   EQU *                  RESTORE STRUCTURE HOLDING DELETING OBJECT
 
*          CALL:                  RETURN:
* A1       -                      POINTER STRUCT (CTX OR T(0).ENV)
* A3       CTX                    SAME
* A5       -                      OBJECT (NONSENSE IF T(0) IS NIL)
* D1.W     REL                    SAME (PT_REL IN T(0).ENV OR REL OF EMB OBJ)
* T(0):    NIL,REF_ENV,OR OWN_SET SAME
 
* USES T(0) TO FIND THE STRUCTURE WHICH HOLDS/HELD AN OBJECT.
* FINDS THE OBJECT IF IT STILL EXISTS.
* RESTORING IS DONE A FOLLOWS:                 (USED IN CALL PATH:)
* T(0)=NIL, REL <0: STRUCT:=CTX, OBJ:=CTX+REL  (DEL_CTX, DEL_EMB, AB_SEGM)
*           REL >0: STRUCT:=CTX, OBJ:=NONSENSE (DEL_CTX, CLR_PT, C_NXT_M)
*                                              (DEALLOC, C_NXT_M)
* T(0)=OWN, REL <0: STRUCT:=CTX, OBJ:=CTX+REL  (NOT USED)
*           REL >0: STRUCT:=CTX, OBJ:=T(0).LAST (DEL_CTX,CLR_PT,C_NXT_M,AB_SEGM)
*                                                (DEALLOC, C_NXT_M, AB_SEGM)
* T(0)=ENV, REL <0: STRUCT:=ENV, OBJ:=ENV+REL  (D_ENV_OK, DEL_EMB, AB_SEGM)
*           REL >0: STRUCT:=ENV, OBJ:=ENV(REL).LAST (D_ENV_OK,CLR_PT,C_NXT_M)
 
  IF.B CT_SIZ+PT_KIN(A3) <EQ> #PT_ENV THEN.S
    MOVE.L CT_SIZ+PT_REF(A3),A1     IF T(0)=REF_ENV THEN A1:=STRUCT:=T(0).ENV
    MOVE.L 4(A1,D1),A5                A5:=OBJ:=STRUCT(REL).LAST_OBJ;
  ELSE.S                            ELSE
    MOVE.L A3,A1                      A1:=STRUCT:=CTX;
    MOVE.L CT_SIZ+4(A3),A5            A5:=OBJ:=T(0).LAST_OBJ;
*                                     "NONSENSE WHEN T(0) IS NIL"
  ENDI                              END;
    TST    D1                       IF REL < 0 THEN
  IF <LT> THEN.S                    "EMBEDDED OBJECT:"
    LEA    (A1,D1),A5                 A5:=OBJ:=STRUCT+REL;
  ENDI                              END;
 
***
    PRT_REG RSTO_STR
    RTS                               RETURN
 
    TTL    POINTER MANIPULATION
    PAGE
COPY       EQU *                  COPY
 
* CALL AND RETURN: AS OTHER KERNEL OPERATIONS.
 
    BSR    C_ENT                      CHECK ENTITY(A5:=ENTITY,D4:=CAPS,
*                                       D5:=ENTITY KIND, A1/A6/D1/D2:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
SET_SIMPLE EQU *                  SET SIMPLE REF: "COMMON WITH FIRST IN SET"
    BSR    C_PT                       CHECK POINTER(A1:=PSTR,D1:=PREL,D2:=PTKIND
*                                       A6:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_ENV,D2                 IF PT KIND > REF_ENV "NOT SIMPLE"
    BGT    EE_VALUE                   THEN REJECT END;
STO_SIMPLE EQU *                  STORE SIMPLE REF: "COMMON WITH NEXT IN SET"
    BSR.S  CLR_SMP                    CLEAR SIMPLE(PSTR,PREL,A6:=PT ADDR);
    BSR    COPY_NIL                   COPY TO NIL(ENTITY,PT ADDR,CAPS,ENT KIND);
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_FAST                   RETURN TO USER;
    PAGE
CLR_SMP    EQU *                  CLEAR SIMPLE POINTER
 
*          CALL:                  RETURN:
* A1       POINTER_STRUCT         SAME
* A6                              POINTER (NIL, REF_ENV, REF_OBJ)
* D1       POINTER_REL            SAME
 
* MAKES THE SIMPLE POINTER NIL.  UPDATES IO-COUNT AND RESIDENT COUNT.
 
    LEA    (A1,D1),A6                 A6:=POINTER ADDR;
    TST.B  PT_KIN(A6)
  IF <NE> THEN                      IF NOT NIL POINTER THEN
    MOVEM.L D0/A4/A5,-(A7)            SAVE REGISTERS;
 
    BTST.B #PT_IO,PT_INF(A6)
  IF <NE> THEN.S                    IF IO_POINTER THEN
    MOVE.L PT_REF(A6),A5              A5:=OBJ;
    SUB    #1,ST_IO(A1)               POINTER_STRUCT.IO_COUNT:=...-1;
  REPEAT                            REPEAT
    SUB    #1,SE_IO(A5)               SEGM_OBJ.IO_COUNT:=...-1;
  IF <EQ> THEN.S                    IF COUNT = 0 THEN
 
    MOVEM.L A1/A4/A5/A6,-(A7)         SAVE REGS;
    LEA    SE_WAIT(A5),A1             A1:=IO_CONDITION;
  REPEAT                            REPEAT
    BSR    KNELSIGN                   IO_CONDITION.SIGNAL(A4/A5/A6:=UNDEF);
  UNTIL <NE>                        UNTIL NO PROCS ACTIVATED;
    MOVEM.L (A7)+,A1/A4/A5/A6         RESTORE REGS;
  ENDI                              END;
    BTST.B #OB_SUB,OB_STA(A5)
  IF <NE> THEN.S                    IF SUB_SEGM_OBJ THEN
    MOVE.L SU_REF(A5),D0              A5:=D0:=OBJ:=BASE_SEGM;
    MOVE.L D0,A5
  ENDI                              END;
  UNTIL <EQ>                        UNTIL NO_BASE_SEGMENT;
  ENDI                              END  "IO_POINTER HANDLING";
 
    BTST.B #PT_RES,PT_INF(A6)
  IF <NE> THEN.S                    IF RESIDENT POINTER THEN
    MOVE.L PT_REF(A6),A5              A5:=OBJ OR ENV;
  IF.B #PT_ENV <EQ> PT_KIN(A6) THEN.S  IF PT_KIND = ENV_REF THEN
    SUB    #1,EN_RES(A5)              ENV.RES_COUNT:=...-1
  ELSE.S                            ELSE
  REPEAT                            REPEAT
    SUB    #1,OB_RES(A5)              OBJ.RES_COUNT:=...-1;
    BTST.B #OB_SUB,OB_STA(A5)
  IF <NE> THEN.S                    IF SUB_SEGM_OBJ THEN
    MOVE.L SU_REF(A5),D0              A5:=D0:=OBJ:=BASE_SEGM;
    MOVE.L D0,A5
  ENDI                              END;
  UNTIL <EQ>                        UNTIL NO_BASE_SEGMENT;
  ENDI                              END;
  ENDI                              END  "RESIDENT POINTER HANDLING";
 
    MOVEQ  #-1-1<<PT_CC-1<<PT_CON-1<<PT_IO-1<<PT_RES,D0
    AND.B  D0,PT_INF(A6)              POINTER.CAPABILITIES:=0;
    CLR.B  PT_KIN(A6)                 POINTER.KIND:=NIL;
    REM_ELEM (A6),A4,A5,A4/A5         REMOVE FROM REFERRED_BY(POINTER);
    MOVE.L A6,(A6)                    POINTER.CHAIN:=SELF_REF;
    MOVE.L A6,4(A6)
    MOVEM.L (A7)+,D0/A4/A5            RESTORE REGISTERS;
  ENDI                              END  "NOT NIL POINTER";
    RTS                               RETURN
    PAGE
COPY_NIL   EQU *                  COPY SIMPLE REF TO NIL POINTER
 
*          CALL:                  RETURN:
* A5       ENTITY (ENV OR OBJ)    SAME
* A6       POINTER                SAME
* D4.B     CALL_CAP,COPY_CONTROL  UNDEFINED
* D5.B     ENT_KIND (FUTURE PT_KIN)  SAME
* A1       -                      UNDEFINED
 
* CREATES A SIMPLE REF IN THE POINTER, WHICH MUST BE NIL AT CALL TIME.
* ENT_KIND CAN BE NIL, ENV, OR OBJ.
 
***
    PRT_REG COPY_NIL
    OR.B   D4,PT_INF(A6)              POINTER.CALL_CAP:=CALL_CAP
    CLR    D4                         POINTER.COPY_CONTROL:=COPY_CONTROL
    MOVE.B D5,D4                      D4:=ENTITY KIND *2;  "WORD"
    LSL    #1,D4
    CASEJMP D4                        CASE ENTITY KIND OF
    CASELAB NIL_1
    CASELAB OBJ_1
    CASELAB ENV_1
 
OBJ_1      EQU *                  OBJECT:
    LEA    OB_REF(A5),A1              A1:=HEAD:=OBJ.REFERRED_BY;
    BRA.S  COM_1                      GOTO COMMON;
 
ENV_1      EQU *                  ENVELOPE:
    LEA    EN_REF(A5),A1              A1:=HEAD:=ENV.REFERRED_BY;
 
COM_1      EQU *                  COMMON:
    MOVE.L A5,PT_REF(A6)              POINTER.REF:=ENTITY;
    INS_ELEM  A1,A6,A5,A1/A5          INSERT(HEAD,NEW=POINTER,A5:=PREV)
    MOVE.L PT_REF(A6),A5              A5:= ENTITY; "RESTORE A5"
 
NIL_1      EQU *                  NIL:
    MOVE.B D5,PT_KIN(A6)              POINTER.KIND:=ENTITY_KIND;
 
***
    PRT_MEM SIMPLE_PT,(A6),FP_SIZ
    RTS                               RETURN
    PAGE
MOVE_OWN   EQU *                  MOVE TO NEW OWNER SET
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_ENT                      CHECK ENTITY (A5:=OBJ,D5:=ENTITY KIND,
*                                       A1/A6/D1/D2/D4:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_OBJ,D5                 IF ENTITY KIND <> OBJECT
    BNE    EE_VALUE                   THEN REJECT END;
    BSR    C_PT                       CHECK POINTER(A1:=NEW PSTR,D1:=NEW PREL,
*                                       D2:=PT_KIND,A6:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BTST.B D2,SIM_OWN                 IF PT_KIND <> SIMPLE, OWN_SET
    BEQ    EE_VALUE                   THEN REJECT END;
 
    MOVE.L OB_OWN(A5),A3              A3:=OLD PSTR:=OBJ.OWNER STRUCT;
    MOVE   OB_OFF(A5),D3              D3:=OLD PREL:=OBJ.OWNER REL;
    BTST.B #PT_FSC,PT_INF(A3,D3)      IF OLD OWNER FORMAL
    BNE    EE_SCOPE                   THEN REJECT END;
    BTST.B #PT_FSC,PT_INF(A1,D1)      IF NEW OWNER FORMAL
    BNE    EE_SCOPE                   THEN REJECT END;
  IF.L A3 <NE> A1 THEN.S            IF OLD PSTR <> NEW PSTR THEN
    BTST.B #OB_EMB,OB_STA(A5)         IF OBJECT EMBEDDED
    BNE    EE_SCOPE                   THEN REJECT END;
    MOVE.L CT_OBJ(A2),A6              A6:=CURRENT OBJ;
    MOVE.L OB_SPA(A6),A6
    MOVE.L SP_ENV+4(A6),A6            A6:=CUR ENV:=CURRENT OBJ.TOP ENV;
    LEA    -EN_STK(A6),A6             "OFFSET"
  IF.L A3 <EQ> A2 THEN.S            IF OLD PSTR = CTX THEN
    CMPA.L A1,A6                      IF NEW PSTR <> CUR ENV
    BNE    EE_SCOPE                   THEN REJECT END;
  ELSE.S                            ELSE  "OLD PSTR <> CTX:"
    CMPA.L A3,A6                      IF OLD PSTR <> CUR ENV
    BNE    EE_SCOPE                   THEN REJECT END;
    CMPA.L A1,A2                      IF NEW PSTR <> CTX
    BNE    EE_SCOPE                   THEN REJECT END;
  ENDI                              END;
  ENDI                              END  "OLD PSTR <> NEW PSTR";
 
    BSR    S_MOVE                     CHECK STACK(OBJ,NEW PSTR, NEW PREL,
*                                       A0/A6/D0/D4/D5:=UNDEF);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BSR    M_OWN_OK                   MOVE OWNER(OBJ,NEW PSTR,NEW PREL,A6:=PT);
    BSR    S_UPDATE                   UPDATE STACK REQ(OBJ,A6/D0:=UNDEF);
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_FAST                   RETURN TO USER;
 
*** MIGHT OPTIMIZE WHEN OLD PSTR=NEW PSTR TO AVOID STACK CHECK AND M_OWN_OK.
    PAGE
MOVE_MAN   EQU *                  MOVE TO NEW MANAGER SET
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_ENT                      CHECK ENTITY(A5:=ENV,D5:=ENTITY KIND,
*                                       A1/A6/D1/D2/D4:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_ENV,D5                 IF ENTITY KIND <> ENVELOPE
    BNE    EE_VALUE                   THEN REJECT END;
    BSR    C_PT                       CHECK POINTER(A1:=NEW PSTR,D1:=NEW PREL,
*                                       D2:=PT_KIND,A6:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BTST.B D2,SIM_MAN                 IF PT_KIND <> SIMPLE, MAN_SET
    BEQ    EE_VALUE                   THEN REJECT END;
 
    MOVE.L EN_MAN(A5),A3              A3:=OLD PSTR:=ENV.MAN_STRUCT;
    MOVE   EN_OFF(A5),D3              D3:=OLD PREL:=ENV.MAN_REL;
    BTST.B #PT_FSC,PT_INF(A1,D1)      IF NEW MANAGER FORMAL
    BNE    EE_SCOPE                   THEN REJECT END;
  IF.L A3 <NE> A1 THEN.S            IF OLD PSTR <> NEW PSTR THEN
    MOVE.L CT_OBJ(A2),A6              A6:=CURRENT OBJ;
    MOVE.L OB_SPA(A6),A6
    MOVE.L SP_ENV+4(A6),A6            A6:=CUR ENV:=CURRENT OBJ.TOP ENV;
    LEA    -EN_STK(A6),A6             "OFFSET"
  IF.L     A3 <EQ> A2 THEN.S        IF OLD PSTR = CTX THEN
    CMPA.L A1,A6                      IF NEW PSTR <> CUR ENV
    BNE    EE_SCOPE                   THEN REJECT END;
  ELSE.S                            ELSE  "OLD PSTR <> CTX:"
    CMPA.L A3,A6                      IF OLD PSTR <> CUR ENV
    BNE    EE_SCOPE                   THEN REJECT END;
    CMPA.L A1,A2                      IF NEW PSTR <> CTX
    BNE    EE_SCOPE                   THEN REJECT END;
  ENDI                              END;
  ENDI                              END  "OLD PSTR <> NEW PSTR";
 
    BSR    M_MAN_OK                   MOVE MANAGER(ENV,NEW PSTR,NEW PREL,
*                                       A6:=PT);
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_FAST                   RETURN TO USER;
    PAGE
FIRSTINSET EQU *                  GET FIRST MEMBER OF SET
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_PT                       CHECK POINTER(A6:=PT,D2:=PT KIND,
*                                       A1/D1:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CLR    D4                         D4:=CAPS:=0;
    LSL    #1,D2
    CASEJMP D2                      CASE POINTER KIND OF
    CASELAB EE_VALUE                NIL: REJECT
    CASELAB EE_VALUE                REF OBJ: REJECT
    CASELAB EE_VALUE                REF ENV: REJECT
    CASELAB OWN_6
    CASELAB MAN_6
    CASELAB EE_VALUE                INTERRUPT POINTER: REJECT
    CASELAB EE_VALUE                VOID: REJECT
 
OWN_6      EQU *                  OWNER SET:
    MOVE.L (A6),A5                    A5:=ENTITY:=FIRST OBJ IN SET;
    BSR    OWN_6A                     GET OWNER CAPS(D4:=CAPS,D5:=ENT KIND);
*                                       "PART OF C_ENT, D4=0 AT CALL"
    BRA    SET_SIMPLE                 GOTO SET SIMPLE REF; "IN COPY"
 
MAN_6      EQU *                  MANAGER SET:
    MOVE.L (A6),A5                    A5:=ENTITY:=FIRST ENV IN SET;
    MOVEQ  #PT_ENV,D5                 D5:=ENTITY KIND:=ENV;
    BRA    SET_SIMPLE                 GOTO SET SIMPLE REF;  "IN COPY"
    PAGE
NXTINSET   EQU *                  GET NEXT MEMBER OF SET
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_PT                       CHECK POINTER(A1:=SET STR,D1:=SET REL,
*                                       D2:=PT KIND,A6:=PT);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE.L A1,A3                      A3:=SET STRUCTURE;
    MOVE   D1,D3                      D3:=SET RELATIVE;
    BSR    C_ENT                      CHECK ENTITY(A5:=ENTITY,D2:=PT KIND,
*                                       A1/A6/D1/D4/D5:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
 
    CLR    D4                         D4:=CAPS:=0;
  IF.B #PT_OBJ <EQ> D2 THEN.S       IF OBJ REF THEN  "A5=OBJ"
    CMP.L  OB_OWN(A5),A3              IF OWNER STRUCT <> SET STRUCTURE
    BNE    EE_VALUE                   THEN REJECT END;
    CMP    OB_OFF(A5),D3              IF OWNER REL <> SET REL
    BNE    EE_VALUE                   THEN REJECT END;
    CMP.L  4(A3,D3),A5                IF OBJ = LAST IN SET
    BEQ.S  END_SET                    THEN GOTO END_SET END;
    MOVE.L (A5),A5                    A5:=OBJ:=NEXT IN SET;
    BSR    OWN_6A                     GET OWNER CAPS(D4:=CAPS,D5:=ENT KIND);
    BRA    STO_SIMPLE                 GOTO STORE SIMPLE REF;  "IN COPY"
  ENDI                              END;  "OBJ REF"
 
    CMP.B  #PT_ENV,D2                 IF NOT ENV REF
    BNE    EE_VALUE                   THEN REJECT END;
    CMP.L  EN_MAN(A5),A3              IF MAN STRUCT <> SET STRUCTURE
    BNE    EE_VALUE                   THEN REJECT END;
    CMP    EN_OFF(A5),D3              IF MAN REL <> SET REL
    BNE    EE_VALUE                   THEN REJECT END;
    CMP.L  4(A3,D3),A5                IF ENV = LAST IN SET
    BEQ.S  END_SET                    THEN GOTO END_SET END;
    MOVE.L (A5),A5                    A5:=ENV:=NEXT IN SET;
    MOVEQ  #PT_ENV,D5                 D5:=ENTITY KIND:=ENV;
    BRA    STO_SIMPLE                 GOTO STORE SIMPLE REF;  "IN COPY"
 
END_SET    EQU *                  END SET:
    MOVE.L #ECRNOT_IN,D7              D7:=RESULT:=NOT_IN_SET;
    BRA    RET_FAST                   RETURN TO USER;
 
 
REFEQUAL EQU *                   SAME ENTITY OR NOT ???
 
* CALL AND RETURN AS OTHER KERNEL OPERATIONS.
 
    BSR.L  C_ENT                      CHECK_ENTITY(A5:=ENTITY,D5:=KIND);
    BEQ.L  RET_FAST
    MOVE.W D5,D0                      A0/D0:= FIRST ENTITY;
    MOVE.L A5,A0
    BSR.L  C_ENT                      CHECK_ENTITY(A5:=ENTITY,D5:=KIND);
    BEQ.L  RET_FAST
  IF.W D5 <EQ> D0 THEN.S            IF SAME KIND THEN
    TST.W  D5
  IF <NE> THEN.S                    IF NOT NIL THEN
    CMP.L A5,A0                       SAME:= SAME ENTITY ADDRESS
  ENDI                              ELSE SAME:=TRUE ENDI;
  ENDI                              ELSE SAME:=FALSE ENDI;
  IF <EQ> THEN.S                    IF SAME THEN
    MOVEQ.L #0,D7                     D7:= RESULT:= OK;
  ELSE.S                            ELSE
    MOVEQ.L #ECSVALUE,D7              D7:= STATUS,POINTER VALUE ILLEGAL;
  ENDI                              ENDI;
    BRA.L RET_FAST                    GOTO FAST RETURN
 
    PAGE
M_OWN_OK   EQU *                  MOVE OWNER, CHECK PERFORMED
 
*          CALL:                  RETURN:
* A1       POINTER STRUCT         SAME  (NEW OWNER POINTER)
* A5       OBJECT                 SAME
* A6                              POINTER
* D1       POINTER REL            SAME  (NEW OWNER POINTER)
 
* REMOVES OBJECT FROM ITS OLD OWNER SET AND INSERTS IT IN THE NEW.
* SHRINKS STACK REQUIREMENT FOR OLD OWNER SET.  CLEARS NEW POINTER IF NOT OWN.
 
    MOVEM.L A2/A3,-(A7)               SAVE REGISTERS;
    REM_ELEM (A5),A2,A3,A2/A3         REMOVE FROM OWN_SET(OBJ,
  IF.L A2 <EQ> A3 THEN.S                A2:=NEXT,A3:=PREV);
    CLR.B  PT_KIN(A2)               IF NEXT=PREV THEN OLD_PT.KIND:=NIL
  ENDI                              END;
    BSR    S_SHRINK                   SHRINK STACK REQUIREMENTS(OBJ,A6:=UNDEF);
*                                     "REF FROM OBJ TO OWN SET STILL EXISTS"
    MOVEM.L (A7)+,A2/A3               RESTORE REGISTERS;  GOTO INS_OWN;
 
 
INS_OWN    EQU *                  INSERT IN OWNER SET
 
*          CALL/RETURN AS M_OWN_OK
* CLEARS POINTER IF NOT OWNER POINTER.  INSERTS OBJECT.
 
    MOVE.L A2,-(A7)                   SAVE A2;
    LEA    (A1,D1),A2                 A2:=POINTER ADDR;
    MOVE.L A1,OB_OWN(A5)              OBJECT.OWNER:=(PSTR,PREL);
    MOVE   D1,OB_OFF(A5)
  IF.B PT_KIN(A2) <NE> #PT_OWN THEN.S  IF SIMPLE POINTER THEN
    BSR    CLR_SMP                    CLEAR SIMPLE (PSTR,PREL,A6:=POINTER);
    MOVE.B #PT_OWN,PT_KIN(A6)         POINTER.KIND:=OWN_SET
  ENDI                              END;
    INS_ELEM A2,A5,A6,A2/A6           INSERT(HEAD=POINTER,NEW=OBJ,A6:=PREV)
    MOVE.L A2,A6                      A6:=POINTER ADDR
    MOVE.L (A7)+,A2                   RESTORE A2;
 
***
    PRT_MEM INS_OWN,(A6),FP_SIZ
    RTS                               RETURN
    PAGE
 
M_MAN_OK   EQU *                  MOVE MANAGER, CHECK PERFORMED
 
*          CALL:                  RETURN:
* A1       POINTER STRUCT         SAME
* A5       ENVELOPE               SAME
* A6                              POINTER
* D1       POINTER REL            SAME
 
* REMOVES ENVELOPE FROM ITS OLD MANAGER SET AND INSERTS IT IN THE NEW.
* CLEARS NEW POINTER IF NOT MAN_SET.
 
    MOVEM.L A2/A3,-(A7)               SAVE REGISTERS;
    REM_ELEM (A5),A2,A3,A2/A3         REMOVE FROM MAN_SET(OBJ,
  IF.L A2 <EQ> A3 THEN.S                A2:=NEXT,A3:=PREV);
    CLR.B  PT_KIN(A2)               IF NEXT=PREV THEN OLD_PT.KIND:=NIL
  ENDI                              END;
    MOVEM.L (A7)+,A2/A3               RESTORE REGISTERS;  GOTO INS_MAN;
 
 
INS_MAN    EQU *                  INSERT IN MANAGER SET
 
*          CALL/RETURN AS M_MAN_OK
* CLEARS POINTER IF NOT MAN_SET.  INSERTS ENVELOPE.
 
    MOVE.L A2,-(A7)                   SAVE A2;
    LEA    (A1,D1),A2                 A2:=POINTER;
    MOVE.L A1,EN_MAN(A5)              ENVELOPE.MANAGER:=(PSTR,PREL);
    MOVE   D1,EN_OFF(A5)
  IF.B PT_KIN(A2) <NE> #PT_MAN THEN.S  IF SIMPLE POINTER THEN
    BSR    CLR_SMP                    CLEAR SIMPLE(PSTR,PREL,A6:=POINTER);
    MOVE.B #PT_MAN,PT_KIN(A6)         POINTER.KIND:=MAN_SET
  ENDI                              END;
    INS_ELEM A2,A5,A6,A2/A6           INSERT(HEAD=POINTER,NEW=ENV,A6:=PREV);
    MOVE.L A2,A6                      A6:=POINTER;
    MOVE.L (A7)+,A2                   RESTORE A2;
 
***
    PRT_MEM INS_MAN,(A6),FP_SIZ
    RTS                               RETURN
    PAGE
DUM_ACT    EQU *                  DUMMYFY ACTUAL REFS
 
*          CALL:                  RETURN:
* A5       STRUCT (ENV OR CTX)    SAME
* A0/A4/A6                        UNDEFINED
 
* DUMMYFIES ACTUAL REFERENCES TO STRUCT.  ACTUAL HEAD BECOMES EMPTY.
 
    LEA    ST_ACT(A5),A6              A6:=ACTUAL HEAD;
    MOVE.L (A6),A4                    A4:=CUR_FP:=HEAD.FIRST;
  WHILE.L A4 <NE> A6 DO.S           WHILE CUR_FP <> HEAD DO
    MOVE.L (A4),A0                    A0:=NEXT(CUR_FP);
    MOVE.L A4,(A4)                    CUR_FP.ACTUAL_CHAIN:=SELF_REF;
    MOVE.L A4,4(A4)
    CLR.L  CH_HOLD(A4)                CUR_FP.STRUCTURE:=DUMMY ACTUAL
    MOVE.L A0,A4                      A4:=CUR_FP:=NEXT;
  ENDW                              ENDW;
    MOVE.L A6,(A6)                    ACTUAL_HEAD:=SELF_REF;
    MOVE.L A6,4(A6)
    RTS                               RETURN
 
 
DUM_ENV    EQU *                  DUMMYFY ENV REFS AND REMOVE FROM MANSET
 
*          CALL:                  RETURN:
* A5       ENVELOPE               SAME
* A0/A4/A6                        UNDEFINED
 
* CLEARS ALL ENV_REFS TO ENVELOPE.  REFERRED_BY HEAD BECOMES EMPTY.
* THE ENVELOPE IS REMOVED FROM ITS MANAGER SET.
 
    LEA    EN_REF(A5),A6              A6:=REFERRED_BY HEAD:
    BRA.S  DUM_COM                    GOTO COMMON DUMMYFY;
    PAGE
DUM_OBJ    EQU *                  DUMMYFY OBJ REFS AND REMOVE FROM OWN_SET
 
*          CALL:                  RETURN:
* A5       OBJECT                 SAME
* A0/A4/A6                        UNDEFINED
 
* CLEARS ALL OBJ_REFS TO OBJECT.  REFERRED_BY HEAD BECOMES EMPTY.
* IO_REFS TO THE OBJECT DO NOT EXIST SINCE DELETION SUSPENDS UNTIL IO_COUNT
* IS 0.  RESIDENT_REFS ARE SIMPLY CLEARED.  INTERRUPT POINTERS HAVE BEEN
* ABORTED.  THE OBJECT IS REMOVED FROM ITS OWN SET.
 
    LEA    OB_REF(A5),A6              A6:=REFERRED_BY HEAD;
 
DUM_COM    EQU *                  COMMON DUMMYFY:
    MOVE.L (A6),A4                    A4:=CUR_PT:=HEAD.FIRST;
  WHILE.L A4 <NE> A6 DO.S           WHILE CUR_PT <> HEAD DO
    MOVE.L (A4),A0                    A0:=NEXT(CUR_PT);
    MOVE.L A4,(A4)                    CUR_PT.CHAIN:=SELF_REF;
    MOVE.L A4,4(A4)
  IF.B PT_KIN(A4) <LE> #PT_ENV THEN.S  IF SIMPLE REF THEN
    CLR.B  PT_KIN(A4)                 CUR_PT.KIND:=NIL;
    BCLR.B #PT_RES,PT_INF(A4)         CUR_PT.RESIDENT:=0;
  ELSE.S                            ELSE  "MMU OR SUBSEGM"
    CLR.L  PT_REF(A4)                 CUR_PT.REFERENCE:=NIL;
  ENDI                              END;
    MOVE.L A0,A4                      A4:=CUR_PT:=NEXT;
  ENDW                              END  "FOR ALL REFS";
 
    MOVE.L A6,(A6)                    HEAD:=SELF_REF;
    MOVE.L A6,4(A6)                   REMOVE FROM OWN OR MANSET(OBJ OR ENV,
    REM_ELEM (A5),A0,A4,A0/A4           A0:=NEXT,A4:=PREV);
  IF.L A0 <EQ> A4 THEN.S            IF NEXT=PREV THEN
    CLR.B  PT_KIN(A4)                 OWN OR MANSET.KIND:=NIL
  ENDI                              END;
    MOVE.L A5,(A5)                    OBJ OR ENV.CHAIN:=SELF_REF;
    MOVE.L A5,4(A5)
    CLR.L  CH_HOLD(A5)                OBJ OR ENV.HOLDER:=DUMMY HOLDER;
    RTS                               RETURN
 
    TTL    EXECUTION CONTROL
    PAGE
MAP_SEGM   EQU *                  MAP SEGMENT, NORMAL OR RESIDENT CTX
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
* D3=RESIDENT OR NORMAL.  A1:=LOGICAL ADDR, D3:=LENGTH, D5:=USE BITS.
 
    BSR    C_ENTRES                   CHECK ENTITY(A1/D1/A6/D2/D4:=...,
*                                       A5:=SEGMENT,D5:=ENTKIND);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
 
  IF.B D5 <EQ> #PT_NIL THEN.S       IF ENT_KIND=NIL THEN
    MOVE   #0,A5                      A5:=SEGMENT:=0 "DUMMY"
  ELSE.S                            ELSE
    CMP.B  #PT_OBJ,D5                 IF ENT_KIND <> OBJ THEN
    BNE    EE_VALUE                     REJECT END;
    CMPI.B #OB_SEOB,OB_KIN(A5)        IF SEGMENT.KIND <> SEGM OBJ THEN
    BNE    EE_STATE                     REJECT END;
  ENDI                              END;
    BSR    C_ADDR                     CHECK ADDR(D0:=LOG ADDR);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE.L -(A4),D1                   D1:=MMU#:=NEXT ARG;
    ADD    #1,D6                      ARGUMENT#:=...+1;
    CMP.L  #3,D1                      IF MMU# >3  "UNSIGNED"
    BHI    EE_DATA                    THEN REJECT END;
    MULU   #MM_SIZ,D1                 D1:=MMU DESCR SIZE * MMU#;
    LEA    CT_MM0(A2,D1),A1           A1:=MMU DESCR;
    BSR.S  MAP_RESOK                  MAP RES OR NORMAL(MMU,SEGM OR 0,LOG ADDR);
    MOVE.L D0,A1                      A1:=LOGICAL ADDR;
    MOVE.L SE_LEN(A5),D3              D3:=SEGMENT LENGTH;
    MOVE.B OB_STA(A5),D5              D5:=OBJECT STATE;
    LSR.B  #OB_READ,D5                D5:= USE BITS OF SEGMENT;
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD2                   LOAD MMU AND RETURN TO USER;
 
MAP_RESOK  EQU *                  MAP RESIDENT OR NORMAL OK
 
* CALL AND RETURN:  AS MAP OK, BUT D3=RESIDENT OR NORMAL
 
    TST    D3                       IF NORMAL CTX THEN
  IF <EQ> THEN.S                      MAP OK(MMU DESCR,SEGM OR 0,LOG ADDR,
    BSR.S MAP_OK                      D0:=ADJUSTED LOG ADDR,D1/D2:=UNDEF);
  ELSE.S                            ELSE
    MOVEM.L D0/A3/A6,-(A7)            SAVE LOG ADDR,A3,A6;
    MOVEQ  #-1,D0                     D0:=DECREASE;
    MOVE   #OB_RES,D1                 D1:=COUNT ADDR:=RESIDENT COUNTER;
    MOVE.L A1,A6                      A6:=MMU PT;
    BSR    INCRDECR                   DECREASE(COUNT ADDR,MMU PT,A3:=UNDEF);
    MOVE.L (A7),D0                    D0:=LOG ADDR;
    BSR.S  MAP_OK                     MAP OK(...,D1/D2:=UNDEF);
    MOVE.L D0,(A7)                    SAVE LOG ADDR;
    MOVEQ  #1,D0                      D0:=INCREASE;
    MOVE   #OB_RES,D1                 D1:=COUNT ADDR;
    BSR    INCRDECR                   INCREASE(COUNT ADDR,MMU PT,A3:=UNDEF);
    MOVEM.L (A7)+,D0/A3/A6            RESTORE LOG ADDR,A3,A6;
  ENDI                              END
    RTS                               RETURN
 
    PAGE
MAP_OK     EQU *                  MAP SEGMENT INTO MMU DESCRIPTOR
 
*          CALL:                  RETURN:
* A1       MM_DESCR               SAME
* A5       SEGM OR 0              SAME  (ROOT SEGMENT OR SUBSEGMENT)
* D0       LOG ADDR               UPDATED  (NORMALLY THE SAME)
* D1-D2    -                      UNDEF
 
* UNMAPS THE MMU DESCRIPTOR.  THEN MAPS THE SEGMENT IF IT IS SPECIFIED.
* THE LOGICAL ADDRESS AT RETURN GIVES THE ACTUAL LOGICAL ADDRESS WHERE
* THE FIRST WORD OF THE SEGMENT IS FOUND.  (THE RETURN VALUE MAY
* DIFFER FROM THE CALL VALUE IN ONLY THE LAST 8 BITS).
 
    MOVEM.L A2/A3,-(A7)               SAVE A2,A3;
    REM_ELEM (A1),A2,A3,A2/A3         REMOVE FROM REFERRED BY (MM_DESCR,
*                                       A2:=NEXT,A3:=PREV);
    CMPA   #0,A5                    IF SEGMENT NOT SPECIFIED THEN
    BNE.S  MAP_COM
    MOVE.L A1,(A1)                    MMU_REF
    MOVE.L A1,4(A1)                       := EMPTY;
    CLR.L  MM_REF(A1)                 MM_DESCR.BASE:=NONE;
    CLR    MM_REG+6(A1)               MM_DESCR.ENABLE:=FALSE;
    MOVEM.L (A7)+,A2/A3               RESTORE A2,A3;  RETURN
    RTS                             END;
* CONTINUE IN MAP_FIRST BUT SKIP SAVING A2/A3 AGAIN.
 
MAP_FIRST  EQU *                  MAP SEGMENT INTO UNINITIALIZED MMU DESCR.
 
* LIKE MAP_OK, BUT SEGM CANNOT BE 0.  DOES NOT UNMAP FIRST.
 
    MOVEM.L A2/A3,-(A7)               SAVE A2,A3;
MAP_COM    EQU *
    MOVE.L A5,MM_REF(A1)              MM_DESCR.BASE:=SEGMENT;
    LEA    OB_REF(A5),A2              INSERT(HEAD=SEGMENT,NEW=MM_DESCR,
    INS_ELEM A2,A1,A3,A2/A3             A3:=PREV);
    MOVEM.L (A7)+,A2/A3               RESTORE A2,A3;
    LSR.L  #8,D0                      D0:=FIRST LOGICAL:=LOG ADDR/256;
    MOVE.L SE_FIR(A5),D2
    MOVE.L D2,D1                      D1:=SEGM.FIRST_PHYS;
*                                     D2_LEFT:=SEGM.FIRST PHYS MOD 256;
    ROR.L  #8,D2                      D2:=OFFSET:=
    SUB.W  D0,D2                        SEGM.FIRST_PHYS/256-FIRST LOGICAL;
    AND.L  #255,D1                    D1:=LAST LOGICAL:=
    ADD.L  SE_LEN(A5),D1                (SEGM.FIRST PHYS MOD 255+SEGM.LENGTH
    SUBQ   #1,D1                        -1)/256
    LSR.L  #8,D1                        +FIRST LOGICAL;
    ADD.W  D0,D1                      MM_DESCR.FIRST_LOGICAL,LAST_LOGICAL,
    MOVEM.W D0-D2,MM_REG(A1)            OFFSET:=D0/D1/D2;  "WORD"
    MOVE.W D0,D2                      D2_RIGHT:=FIRST LOGICAL;
    ROL.L  #8,D2                      D0:=D2:=LOG ADDR:=FIRST LOGICAL *256
    MOVE.L D2,D0                        +SEGM.FIRST PHYS MOD 256;
    MOVE.W OB_KIN(A5),D2              D2:= SEGM.USE_BITS * 2;
    LSR.W  #OB_READ-1,D2
    AND.W  #7<<1,D2
    MOVE.W MMCONTRL(D2),MM_REG+6(A1)  MM_DESCR.(ENABLE+READ_ONLY) := ! ;
    RTS                               RETURN;
 
*   USE_BITS =   0 1 2 3 4 5 6 7
MMCONTRL   DC.W  0,3,1,1,3,3,1,1       0=DISABLE, 3=READ_ONLY, 1=READ+WRITE
    TTL    PROCESS MANAGEMENT AND SYNC
    PAGE
DECL_PROC  EQU *                  DECLARE PROCESS
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    MOVE.L D4,D3                      D3:=LOW_ARG;
    BSR    C_ENT                      CHECK ENTITY(A5:=PROC,D2:=PT_KIND,
*                                       A1/A6/D1/D4/D5:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_OWN,D2                 IF POINTER KIND <> OWN
    BNE    EE_VALUE                   THEN REJECT END;
    CMP.B  #OB_DOOB,OB_KIN(A5)        IF PROC KIND <> DORMANT
    BNE    EE_STATE                   THEN REJECT END;
 
    MOVE.L A5,A0                      A0:=EXT OBJ:=PROC;
    MOVE.L CT_OBJ(A2),A5              A5:=OBJ TO CALL:=CUR_CTX.OBJECT;
    MOVE.L D3,D4                      D4:=LOW_ARG;
    CLR    D3                         D3:=ADDITIONAL FORMALS:=0;
    MOVE.L -(A4),D5                   D5:=FUNCTION:=NEXT ARGUMENT;
    ADD    #1,D6                      D6:=ARGUMENT#:=...+1;
    BSR    CRE_CTX                    CREATE_CTX(...,A3:=NEW CTX,D4:=ENTRY;
*                                       A1/A5/A6/D0-D2:=UNDEF);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE.L D4,CT_WRK-4(A3)            NEW_CTX.PC:=ENTRY;
    MOVE.L D5,PR_D0.A3(A0)            PROC.SAVED_D0:=FUNCTION;
    BSR    SAVE_STK                   SAVE SUPV STACK(CUR_CTX,ENTRY,FUNCTION,
*                                       A5/A6/D0:=UNDEF);
    BSR    SET_FP                     SET FORMALS(EXT,CUR_CTX,NEW CTX,ARG ADDR,
*                                       ADDITIONAL FORMALS,ARG#,D3:=#FORMALS,
*                                       A1/A5/A6/D0-D2/D4/D5:=UNDEF);
  IF <NE> THEN.S                    IF OK THEN
    MOVE.B #OB_PROB,OB_KIN(A0)        PROC.KIND:=PROCESS OBJECT;
    MOVE.L D3,PR_D0.A3+12(A0)         PROC.SAVED_D3:=#FORMALS;
    LEA    CT_WRK-4(A3),A6            A6:=NEW_CTX.SAVED STACK;
    CLR.W  -(A6)                      SAVED STACK.SR:=0;
    MOVE.L 8(A7),-(A6)                SAVED STACK.A6:=TOP VALUE;
    MOVE.L 4(A7),-(A6)                SAVED STACK.A5:=FIRST TEMP;
    CLR.L  -(A6)                      SAVED STACK.A4:=0;
    MOVE   #-2,CT_COUNT(A3)           NEW_CTX.#ADDITIONAL WORDS:=-2;
    MOVE.L #START_PROC,-(A6)          SAVED STACK.RESUME:=START PROCESS;
    MOVE.L USP,A6                     A6:=NEW CTX.USP:=USP;
    MOVE.L A6,CT_USP(A3)
    MOVE.L #STOP_PROC,CT_CON(A3)      NEW_CTX.CONTINUE AT RETURN:=STOP_PROC;
    LEA    PR_AUX(A0),A0              A0:=PROCESS.AUX QUEUE;
    LEA    RUNNING,A1                 A1:=RUNNING QUEUE;
    INS_ELEM A1,A0,A6,A1/A6           INSERT PROCESS IN RUNNING QUEUE
    MOVEQ.L #0,D7                     RESULT:= OK;
  ELSE.S                            ELSE
    BSR    DEL_CTX                    DELETE_CTX(NEW_CTX,A0:=PROC,
*                                       A1-A6/D0-D5:=UNDEF);
  ENDI                              END;
    MOVE.L KV_CTX,A3                  A3:=CUR_CTX;
    BSR    RSTO_STK                   RESTORE SUPV STACK AND USP(CUR_CTX);
    BRA    RET_OLD3                   RETURN TO USER;
 
 
STOP_PROC  EQU *                  STOP PROCESS:  "RETURN FROM INITIAL CTX"
* RET_FP NOT CALLED SINCE NO RETURN POINTERS OR VALUES ARE HANDLED.
* (THIS WOULD CAUSE TROUBLE WHEN A NORMAL CALL ADDRESSES ITS VALUE BASE
* AT RETURN.  A DIFFERENT REPRESENTATION WOULD BE NEEDED.)
    BSR    DEL_CTX                    DELETE_CTX(CUR_CTX,A0:=PROC,
*                                       A1-A6/D0-D5:=UNDEF);
    MOVE.B #OB_DOOB,OB_KIN(A0)        PROC.KIND:=DORMANT;
    REM_ELEM PR_MAIN(A0),A1,A6,A1/A6  REMOVE PROC FROM TIMER Q (MAY BE EMPTY)
    INIT_HEAD PR_MAIN(A0),A1          MAIN:=SELF_REF;
    REM_ELEM PR_AUX(A0),A1,A6,A1/A6   REMOVE PROC FROM RUNNING QUEUE;
    INIT_HEAD PR_AUX(A0),A1           AUX:= SELF_REF;
    LEA    PR_TERM(A0),A1             A1:=PROC TERM CONDITION;
    BSR    KNELSIGN                   PROC TERM.SIGNAL(A4/A5/A6:=UNDEF);
*   AT PRESENT ONLY ONE PROC MAY BE WAITING (CALLER OF DEALLOC)
*   CONTEXT AND EXTENSION QUEUE ARE EMPTY.
    BRA    NEXT_PROC                  GOTO ACTIVATE NEXT PROCESS;
    PAGE
NEW_ST_CALL EQU *                 NEW STACK CALL
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    MOVE.L D4,D3                      D3:= LOW_ARG;
    BSR    C_OPEN                 CHECK OPEN OBJ(A0:=A5:=EXT,A6:=PT,A1/D1:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE.L D3,D4                      D4:= LOW_ARG;
    BTST.B #PT_TSC,PT_INF(A6)         IF POINTER SCOPE <> TEMP
    BEQ    EE_SCOPE                   THEN REJECT END;
    MOVE   #EX_SIZ-OB_SIZ,D0          D0:=SIZE OF EXT OBJ PART;
    BSR    MM_PUSHO                   RESERVE KERNEL ENV(EXT,SIZE,A6:=TOP OBJ);
    BEQ    EE_OBJSP                   IF NOT OK THEN REJECT END;
 
    MOVE.B #OB_EXOB,OB_KIN(A0)        EXT.KIND:=EXT OBJECT;
    INIT_HEAD EX_CTX(A0),A1           EXT.CONTEXTS:=EMPTY;
    MOVE.L CT_HOLD(A2),A1             A1:=CUR_CTX.HOLDER;
    MOVE.L EX_PR(A1),A1               A1:=PROC:=HOLDER.PROCESS;
    MOVE.L A1,EX_PR(A0)               EXT.PROCESS:=PROC;
    LEA    EX_EXT(A1),A1              A1:=PROC.HEAD EXT;
    LEA    EX_EXT(A0),A6              A6:=EXT.MEMBER;
    INS_ELEM A1,A6,A3,A1/A3           INSERT(HEAD=PROC,NEW=EXT,A3:=PREV);
 
    MOVEQ.L #0,D3                     D3:= CALLER IS NOT RESIDENT;
    BSR    C_CALL                     CHECK CALL(EXT,CUR CTX,A5:=OBJ,D5:=FUNC);
*                                     "WILL COMPLETE KERNEL OBJECT CALLS"
  IF <NE> THEN.S                    IF NOT RETURN THEN
    CLR    D3                         D3:=ADDITIONAL FORMALS:=0;
    BSR    CRE_CTX                    CREATE_CTX(...,A3:=NEW CTX,D4:=ENTRY,
*                                       A1/A5/A6/D0-D2:=UNDEF);
  IF <NE> THEN.S                    IF OK THEN
    BSR    SAVE_STK                   SAVE SUPV STACK(CUR_CTX,ENTRY,FUNCTION,
*                                       A5/A6/D0:=UNDEF);
    BSR    SET_FP                     SET FORMALS(EXT,CUR_CTX,NEW_CTX,ARG ADDR,
*                                       ADDITIONAL FORMALS,ARG#,D3:=#FORMALS,
*                                       A1/A5/A6/D0-D2/D4/D5:=UNDEF);
  IF <NE> THEN.S                    IF OK THEN
    BSR    ENT_CTX                    ENTER CONTEXT(A3=CTX,D3=#FORMALS);
*                                   "CONTINUES HERE AT OBJ_RETURN.  A3=CTX"
    BSR    RET_FP                     RETURN FORMALS(A3=CTX,D6/D7:=UPDATED);
  ENDI                              END  "CALL CARRIED OUT";
    BSR    DEL_CTX                    DELETE CTX(CTX,A0:=EXT,
*                                       A1-A6/D0-D5:=UNDEF);
    MOVE.L EX_EXT+4(A0),A1            A1:=OLD EXT:=EXT.PREV EXT;
    MOVE.L EX_CTX+4-EX_EXT(A1),A3     A3:=OLD CTX:=OLD EXT.LAST CTX;
    LEA    -CT_STK(A3),A3             "OFFSET"
    BSR    RSTO_STK                   RESTORE SUPV STACK AND USP(OLD CTX);
    MOVE.L A3,A2                      A2:=CTX:=OLD CTX
  ENDI                              END  "CONTEXT CREATED";
  ENDI                              END  "CALL ATTEMPTED";
 
* A0=EXT, A2=CTX
    REM_ELEM EX_EXT(A0),A1,A6,A1/A6  REMOVE FROM EXT CHAIN(EXT,A1/A6:=...);
    MOVE.B #OB_OPOB,OB_KIN(A0)        EXT.KIND:=OPEN OBJECT;
    MOVE   #EX_SIZ-OB_SIZ,D0          D0:=SIZE OF EXT OBJ PART;
    BSR    MM_POPO                    RELEASE KERNEL ENV(EXT,SIZE,A6:=TOP OBJ);
    BRA    RET_OLD2                   RETURN TO USER;  "A2=CTX"
    PAGE
ABORT      EQU *                  ABORT GENERAL OBJECT
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS
 
    BSR    C_PRIM                     CHECK PRIMARY ENV(A5:=ENV,
*                                       A0/A1/A6/D1/D2/D4/D5:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BSR    ABORT_ENV                  ABORT ENVELOPE(ENV);
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD2                   RETURN TO USER  "SELF-ABORT POSSIBLE"
 
 
SPEED_UP   EQU *                  SPEED UP GENERAL OBJECT
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_PRIM                     CHECK PRIMARY ENV(A0:=OBJ,
*                                       A1/A5/A6/D1/D2/D4/D5:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE.L GE_EX(A0),A1               A1:=CTX:=OBJ.FIRST CTX EXECUTED;
    LEA    GE_EX(A0),A5               A5:=OBJ.CTX HEAD;
  WHILE.L A1 <NE> A5 DO.S           WHILE CTX <> CTX_HEAD DO
    MOVE   #1,D1                      D1:=SPEED:=REJECT;
    BSR    PROPAGATE                  PROPAGATE SPEED (CTX,SPEED);
    MOVE.L (A1),A1                    A1:=NEXT CTX
  ENDW                              END;
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD2                   RETURN TO USER;
 
 
ABORT_ONE  EQU *                  ABORT ENVELOPE WITHOUT LOCAL TREE
 
*          CALL:                  RETURN:
* A5       ENVELOPE (ROOT_ENV)    SAME
 
* DUMMY IF THE ENVELOPE IS NOT TOP ENVELOPE OF A NON-ABORTED GENERAL OBJECT.
* OTHERWISE, THE GENERAL OBJECT BECOMES ABORTED AND ALL CONTEXTS EXECUTING
* IN IT ARE ABORTED.  ABORTING A CONTEXT MEANS PROPAGATING SPEED-UP STATUS
* AND ABORTING POSSIBLE TEMPORARY MAN_SET AND IO-LOCKS.  (USED BY D_ENV_OK).
 
    MOVEM.L A1/A2/A4/A6/D1,-(A7)  SAVE REGISTERS;
    MOVE.L A5,A4                      A4:=CUR_ENV:=ROOT_ENV;
    BRA    AB_ONE                     GOTO ABORT WITHOUT LOCALS;
    PAGE
ABORT_ENV  EQU *                  ABORT ENVELOPE AND LOCAL MANAGER TREE
 
*          CALL:                  RETURN:
* A5       ENVELOPE (ROOT_ENV)    SAME
 
* CLEARS POSSIBLE LOCAL IO-LOCKS AND ABORTS ALL ENVELOPES IN LOCAL MAN_SETS
* (RECURSIVELY).  IF AN ENVELOPE IS THE TOP ENVELOPE OF A NON-ABORTED
* GENERAL OBJECT, THE GENERAL OBJECT BECOMES ABORTED AND ALL CONTEXTS
* EXECUTING IN IT ARE ABORTED.  THIS INVOLVES PROPAGATING SPEED-UP STATUS
* AND ABORTING POSSIBLE TEMPORARY MAN_SET AND IO-LOCKS.
* (USED BY CLR_PT AND ABORT).
 
    MOVEM.L A1/A2/A4/A6/D1,-(A7)      SAVE REGISTERS;
    MOVE.L A5,A4                      A4:=CUR_ENV:=ROOT_ENV;
 
AB_NEXT3   EQU *                  PROCEDURE ABORT_ENV(CUR_ENV):  "RECURSIVE"
 
***
    PRT_REG AB_ENV
    MOVE.L A4,A1                      A1:=P_STR:=CUR_ENV;
    MOVE   #EN_SIZ,D1                 D1:=P_REL:=L(1);
  REPEAT                            FOR D1:=ALL LOCALS IN CUR_ENV DO
  IF.B PT_KIN(A1,D1) <LE> #PT_ENV THEN.S  "CLEAR POSSIBLE IO_LOCK:"
*                                   IF LOCAL IS SIMPLE THEN
    BSR    CLR_SMP                    CLEAR SIMPLE PT(PSTR,PREL,A6:=PT);
  ENDI                              END;
  IF.B #PT_MAN <EQ> PT_KIN(A1,D1) THEN.S  IF LOCAL.MAN_SET THEN
    MOVE.L (A1,D1),A4                 A4:=CUR_ENV:=MAN_SET.FIRST;
  REPEAT                            FOR A4:=ALL ENVELOPES IN SET DO
    BRA    AB_NEXT3                   ABORT_ENV(CUR_ENV);  "SIMULATE CALL"
 
AB_LOC     EQU *                  NEXT LOCALLY MANAGED:  "A1,D1,A4 RESTORED"
    LEA    (A1,D1),A2                 A2:=HEAD MAN_SET;
    MOVE.L (A4),A4                    A4:=NEXT ENVELOPE IN SET;
  UNTIL.L A4 <EQ> A2                END "FOR ALL ENVELOPES IN SET";
  ENDI                              END  "LOCAL.MAN_SET";
    ADD    #PT_SIZ,D1                 D1:=NEXT LOCAL;
  UNTIL D1 <EQ> EN_TOPL(A1)         END  "FOR ALL LOCALS"
    MOVE.L A1,A4                      A4:=CUR_ENV:=P_STR;
 
AB_ONE     EQU *                  ABORT WITHOUT LOCALS:  "A4=CUR_ENV"
    MOVE.L EN_OBJ(A4),A2              A2:=OBJ:=OBJECT HOLDING CUR_ENV;
    MOVE.L OB_SPA(A2),A6              A6:=TOP OBJ;
    LEA    SP_ENV(A6),A6              A6:=ENV HEAD;
  IF.L EN_STK(A4) <EQ> A6 THEN      IF CUR ENV = TOP ENV OF GENERAL OBJ
  IF.B OB_KIN(A2) <EQ> #OB_GEOB THEN
    BSET.B #OB_ABOR,OB_STA(A2)        AND OBJ NOT ABORTED
  IF <EQ> THEN                      THEN OBJ.ABORTED:=TRUE;
    MOVE.L GE_EX(A2),A1               A1:=CTX:=OBJ.FIRST CTX EXECUTED;
    LEA    GE_EX(A2),A2               A2:=OBJ.CTX HEAD;
  WHILE.L A2 <NE> A1 DO             WHILE CTX <> CTX HEAD DO "A4=TOP_ENV"
    MOVE.W CT_RES(A1),D1              D1:= CTX.RES_COUNT; "EQUALS ZERO OR ONE"
  IF <NE> THEN.S                    IF CTX IS RESIDENT THEN DECREASE RES_COUNT
    SUB.W D1,EN_RES(A4)               OF TOP_ENV NOW. NORMALLY IT IS DONE BY
  ENDI                              SETRESET, WHEN THE CTX OPENS THE DEVI_GATE.
    MOVE.B #3,CT_MODE(A1)             CTX.MODE:=SAME;
    MOVE.B #3,D1                      D1:=SPEED:=UNDEF;
    BSR    PROPAGATE                  PROPAGATE SPEED(CTX,SPEED);
 
    MOVE   #CT_SIZ+PT_SIZ,D1          D1:=P_REL:=T(1);
  REPEAT                            FOR D1:=ALL TEMPS IN CTX DO
    BTST.B #PT_IO,PT_INF(A1,D1)
  IF <NE> THEN.S                    IF TEMP.IO_LOCK THEN
    BSR    CLR_SMP                    CLEAR SIMPLE(PSTR=CTX,PREL,A6:=PT);
  ENDI                              END;
  IF.B #PT_MAN <EQ> PT_KIN(A1,D1) THEN.S  IF TEMP.MAN_SET THEN
    MOVE.L (A1,D1),A4                 A4:=CUR_ENV:=MAN_SET.FIRST;
  REPEAT                            FOR A4:=ALL ENVELOPES IN SET DO
    BRA    AB_NEXT3                   ABORT_ENV(CUR_ENV);  "SIMULATE CALL"
 
 
AB_TMP     EQU *                  NEXT TEMP MANAGED:  "A1,D1,A4 RESTORED"
    LEA    (A1,D1),A2                 A2:=HEAD MAN_SET;
    MOVE.L (A4),A4                    A4:=NEXT ENVELOPE IN SET;
  UNTIL.L A4 <EQ> A2                END  "FOR ALL ENVELOPES IN SET";
  ENDI                              END  "TEMP MAN_SET";
    ADD    #PT_SIZ,D1                 D1:=NEXT TEMP;
  UNTIL D1 <EQ> CT_TOPT(A1)         END  "FOR ALL TEMPS";
 
  WHILE D1 <NE> CT_TOPF(A1) DO.S    FOR D1:=ALL FORMALS IN CTX DO
    BTST.B #PT_IO,PT_INF(A1,D1)
  IF <NE> THEN.S                    IF FORMAL.IO_LOCK THEN
    BSR    CLR_SMP                    CLEAR SIMPLE (PSTR=CTX,PREL,A6:=PT)
  ENDI                              END
    ADD    #FP_SIZ,D1                 D1:=NEXT FORMAL;
  ENDW                              END  "FOR ALL FORMALS";
 
    CLR.L  CT_OBJ(A1)                 CTX.EXECUTES:=ABORTED;
    REM_ELEM (A1),A2,A6,A2/A6         REMOVE CTX FROM EXECUTES CHAIN;
    EXG.L  A2,A6                      A2:=CTX HEAD; A6:=NEXT CTX;
    MOVE.L A1,(A1)                    CTX.EXECUTES CHAIN:=DUMMY;
    MOVE.L A1,4(A1)
    MOVE.L A6,A1                      A1:=CTX:=NEXT CTX;
    MOVE.L OB_SPA-GE_EX(A2),A6        A6:=TOP OBJ;
    MOVE.L SP_ENV+4(A6),A4            A4:=CUR_ENV:=OBJ.TOP ENV;  A4 USED IN
    LEA    -CT_STK(A4),A4             "AJUST FOR OFF-SET"        LOOP START.
  ENDW                              ENDW "FOR ALL CTX EXECUTING OBJ"
  ENDI                              END  "TOP ENV OF NON-ABORTED GENERAL";
  ENDI
  ENDI
 
*                                 "SIMULATE RETURN FROM ABORT_ENV/AB_ONE:"
  IF.L A4 <NE> A5 THEN.S            IF CUR_ENV <> ROOT ENV THEN
    MOVE.L EN_MAN(A4),A1              A1:=P_STR:=CUR_ENV.MANAGER_ENV;
    MOVE   EN_OFF(A4),D1              D1:=P_REL:=CUR_ENV.MANAGER_REL;
    BTST.B #PT_LSC,PT_INF(A1,D1)      IF NOT LOCAL MAN_SET
    BEQ    AB_TMP                     THEN GOTO NEXT TEMP MANAGER END;
    BRA    AB_LOC                     GOTO NEXT LOCALLY MANAGED
  ENDI                              END;
    MOVEM.L (A7)+,A1/A2/A4/A6/D1      RESTORE REGISTERS;
    RTS                               RETURN
 
    PAGE
PROPAGATE  EQU *                  PROPAGATE SPEED
 
*          CALL:                  RETURN:
* A1       CONTEXT                SAME
* D1       SPEED                  UNDEF  (1=REJECT,3=SPEED UNDEF)
* A6       -                      UNDEF
 
* PROPAGATES "SPEED" STARTING IN "CONTEXT" AND PROCEEDING THROUGH YOUNGER
* CONTEXTS.  THE CONTEXT SPEED BECOMES MAX(SPEED,OLD CONTEXT SPEED).
* THE PROPAGATED VALUE IS SPEED = MIN(SPEED, OLD CONTEXT MODE).
 
    MOVEM.L D0/A1,-(A7)               SAVE CTX AND WORKING REG;
  REPEAT                            REPEAT  "FOR ALL CONTEXTS"
    OR.B   D1,CT_SPE(A1)            CTX.SPEED:=MAX(SPEED,CTX.SPEED);
    BSR.S  SPEEDEXC                   CHECK_SPEED_EXC(A1=CTX,D0:=?);
    AND.B  CT_MODE(A1),D1             SPEED:=MIN(SPEED,CTX.MODE);
***
    PRT_REG PROPAGATE
  IF <NE> THEN.S                    IF SPEED <> NORMAL THEN
    MOVE.L CT_HOLD(A1),A6             A6:=EXT OBJECT HOLDING CTX;
PROP_REP   EQU *                  GET_FIRST_CONTEXT_IN_NEW_EXTENSION_OBJ:
    LEA    EX_CTX(A6),A6              A6:=HEAD CTX STACK;
  IF.L CT_STK(A1) <NE> A6 THEN.S    IF NEXT CTX(CTX) <> HEAD CTX STACK THEN
    MOVE.L CT_STK(A1),A1              A1:=NEXT CTX(CTX)
    LEA    -CT_STK(A1),A1             "ADJUST FOR OFF-SET"
  ELSE.S                            ELSE
    MOVE.L EX_EXT-EX_CTX(A6),A6       A6:=EXT:=NEXT EXT(EXT OBJECT);
    LEA    -EX_EXT(A6),A6             "OFF-SET TO EXT OBJECT BASE"
  IF.B OB_KIN(A6) <EQ> #OB_EXOB THEN.S
    LEA    EX_CTX-CT_STK(A6),A1     IF EXT.KIND=EXT THEN
    BRA.S  PROP_REP  CT_STK(A1) == CTX_HEAD OF EXT_OBJ; GOTO GET_FIRST.....
  ELSE.S                            ELSE  "EXT.KIND=PROCESS: END CONTEXTS"
    MOVEM.L D7/A3,-(A7)               SAVE REGISTERS;
    MOVE.L A6,A1                      A1:=PROCESS;
    MOVE   D1,D0                      D0:=SPEED;
    BSR    PROPSPED                   PROPAGATE TO GATE OR COND(A1=PROC,
*                                       D0=SPEED,D7/A3/A6:=UNDEF);
    MOVEM.L (A7)+,D7/A3               RESTORE;
    CLR    D1                         SPEED:=NORMAL
  ENDI                              END;
  ENDI                              END  "NEXT EXT OBJECT";
  ENDI                              END  "SPEED <> NORMAL";
  UNTIL.B D1 <EQ> 0                 UNTIL SPEED = NORMAL;
    MOVEM.L (A7)+,D0/A1               RESTORE CTX AND WORKING REG;
    RTS                               RETURN
 
SPEEDEXC   EQU *                  CHECK FOR SPEEDUP EXCEPTION
*          CALL:                  RETURN:
* D0       -                      UNDEF
* A1       CTX                    SAME
*
* SHOULD A SPEEDUP EXCEPTION BE GENERATED ACORDING TO STATE AND MODE
*
    MOVE.B CT_MODE(A1),D0
    LSR.B  #2,D0                      D0:= EXCEPTION MODE OF CTX
    AND.B  CT_SPE(A1),D0              D0:= EXC:= MINIMUM(MODE,SPEED);
  IF <NE> THEN.S                    IF EXC THEN
    BSET.B #7,CT_SPE(A1)              CTX.SPEEDEXC:= TRUE;
  ENDI                              ENDI;
    RTS                               RETURN;
* SPEEDEXC IS CHECKED BY PREP_RET
 
    PAGE
 
SET_MODE   EQU *                  SET PROPAGATION MODE
* EXCEPTION MODE IS ALSO SET. LATER A NEW PROC MAY BE DEFINED
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    ADD    #1,D6                      ARGUMENT#:=...+1;
    MOVE.L -(A4),D0                   D0:=MODE:=INTEGER ARGUMENT;
    CMP.L  #15,D0                      IF MODE <0 OR >15
    BHI    EE_DATA                    THEN REJECT END;
    BTST.L #1,D0
  IF <NE> THEN.S                    IF PROP_MODE = 2 OR 3 THEN
    BSET.L #0,D0                      D0.PROP_MODE:=3;  "SAME"
  ENDI                              ENDI;
    BTST.L #2,D0
  IF <NE> THEN.S                    IF EXC_MODE = 1 OR 3 THEN
    BSET.L #3,D0                      D0.EXC_MODE:= 3; "REJECT AND UNDEF"
  ENDI                              ENDI;
    MOVE.B D0,CT_MODE(A2)             CURRENT_CTX.MODE:=MODE;
    MOVE.L A2,A1                      A1:= CTX;
    BSR.S  SPEEDEXC                   CKECK FOR SPEEDEXC IN CALLING CTX
*** PRT_MEM CTX_MODE,(A2),CT_SIZ
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD2                   RETURN TO USER;
 
 
TEST_SPEED EQU *                  TEST SPEED-UP STATUS
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.  D4:=SPEED.
 
* RETRIEVES THE SPEED-UP STATUS FROM THE CONTEXT.  RE-COMPUTES THE
* SPEED-UP STATUS FROM THE PREVIOUS CONTEXT. (THE RECOMPUTED VALUE
* CAN ONLY DIFFER FROM THE CURRENT VALUE AFTER "SPEED-UP" IN THE CONTEXT).
 
    CLR.L  D4
    MOVE.B CT_SPE(A2),D4              D4.L:=SPEED:=CURRENT_CTX.SPEED;
  IF.B D4 <EQ> #3 THEN.S            IF SPEED = UNDEF THEN
    MOVE   #2,D4                      D4.L:=SPEED:=UNDEF;  "USER FORM"
  ENDI                              END;
  IF.B D4 <EQ> #1 THEN.S            IF SPEED = REJECT THEN
    MOVE.L CT_HOLD(A2),A6             A6:=EXT OBJ HOLDING CTX;
    LEA    EX_CTX(A6),A6              A6:=CTX HEAD;
  IF.L CT_STK+4(A2) <NE> A6 THEN.S
    MOVE.L CT_STK+4(A2),A5          IF NOT FIRST CTX IN EXT OBJECT THEN
    LEA    -CT_STK(A5),A5             A5:=PREV CTX
  ELSE.S                            ELSE  IF NOT PROCESS OBJECT THEN
  IF.B OB_KIN-EX_CTX(A6) <NE> #OB_PROB THEN.S
    MOVE.L EX_EXT+4-EX_CTX(A6),A6     A6:=PREVIOUS EXTENSION;
    MOVE.L EX_CTX+4-EX_EXT(A6),A5
    LEA    -CT_STK(A5),A5             A5:=PREV EXTENSION.LAST CTX;
  ELSE.S                            ELSE
    CLR.B  CT_SPE(A2)                 CURRENT_CTX.SPEED:=NORMAL;
    MOVE.L A2,A5                      A5:=CURRENT_CTX
  ENDI                              END
  ENDI                              END  "FIND PREVIOUS CONTEXT"
    MOVE.B CT_SPE(A5),D0
    AND.B  CT_MODE(A5),D0             D0:=MIN(PREV SPEED,PREV MODE);
    MOVE.B D0,CT_SPE(A2)              CURRENT_CTX.SPEED:=MIN(...);
    AND.B  #3,CT_MODE(A2)             CLEAR SPEEDEXC AND EXCMODE;
  ENDI                              END  "SPEED = REJECT";
    CLR.L  D7                         D7:=RESULT;
    BRA    RET_OLD2                   RETURN TO USER;
 
    TTL    IDENTIFICATION CONTROL
    PAGE
DECL_ENV   EQU *                  DECLARE ENVELOPE
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    BSR    C_ENT                      CHECK ENTITY(A5:=OBJ,D2:=PT_KIND,
*                                       A1/A6/D1/D4/D5:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE.L A5,A0                      A0:=OBJECT;
    CMP.B  #PT_OWN,D2                 IF POINTER KIND <> OWN SET
    BNE    EE_VALUE                   THEN REJECT END;
    MOVE.B OB_KIN(A5),D0              D0:=OBJECT KIND;
    BTST.B D0,OPENDORM                IF OBJECT KIND <> OPEN, DORMANT
    BEQ    EE_STATE                   THEN REJECT END;
    BSR    CRE_ENV                    CREATE ENV(OBJ,CTX,A1/D1:=REF ENV PT,
*                                       A5/D5:=MAN SET PT,A3:=ENV,A6/D0:=UNDEF);
    BEQ    RET_OLD2                   IF NOT OK THEN RETURN TO USER END;
    BSR    CLR_SMP                    CLEAR SIMPLE POINTER(REF ENV STR,
*                                       REF ENV REL, A6:=PT ADDR);
    MOVE.L D5,D1                      D1:=MAN SET REL;
    EXG.L  A3,A5                      A5:=ENVELOPE; A3:=MAN SET STRUCT;
    MOVEQ  #0,D4                      D4:=NO CAPS;
    MOVEQ  #PT_ENV,D5                 D5:=REF_ENV;
    BSR    COPY_NIL                   COPY REF TO NIL(ENV,A6=PT,A1:=UNDEF);
    MOVE.L A3,A1                      A1:=MAN SET STRUCT; "D1=MAN SET REL"
    BSR    INS_MAN                    INSERT IN MAN SET(PSTR,PREL,A5=ENV);
***
    PRT_MEM DECL_ENV,(A5),EN_SIZ
    MOVE.L A0,A5                      A5:=OBJ;
    BSR    S_UPDATE                   STACK REQ UPDATE(OBJ,A6/D0:=UNDEF);
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD2                   RETURN TO USER;
 
OPENDORM   DC.B 1<<OB_OPOB+1<<OB_DOOB  MASK FOR OBJ KIND;
    DS.W   0
 
 
INSP_OBJ   EQU *                  INSPECT OBJECT
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.  D4:=INDEX.
 
    BSR    INSP_INIT                  INSPECT INIT(A5:=ENV,A1:=REF STR,
*                                       D1:=REF REL,A0/A3/A6/D2/D4/D5:=...)
    MOVE.L A5,A0                      A0:=ENV;
    MOVEM.L A0/A1/D1,-(A7)            SAVE ENV,REF STR,REF REL;
    BSR    C_ENT                      CHECK ENTITY(A5:=OBJ,D5:=ENTITY KIND,
*                                       A1/A6/D1/D2/D4:=...);
    MOVEM.L (A7)+,A0/A1/D1            RESTORE ENV,REF STR,REF REL;
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_OBJ,D5                 IF ENTITY KIND <> OBJECT
    BNE    EE_VALUE                   THEN REJECT END;
    EXG.L  A5,A0                      A0:=OBJ; A5:=ENV;
    BRA    INSP_COM                   GOTO COMMON INSPECT;
    PAGE
INSP_ACT   EQU *                  INSPECT HOLDER OF ACTUAL POINTER
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.  D4:=INDEX,D5:=COUNT.
 
    BSR    INSP_INIT                  INSPECT INIT(A5:=ENV,A1:=REF STR,
*                                       D1:=REF REL,A0/A3/A6/D2/D4/D5:=...);
    MOVEM.L A1/D1,-(A7)               SAVE REF STR,REF REL;
    BSR    C_PT                       CHECK POINTER(A6:=FP ADDR,D2:=FP KIND,
*                                       A1/D1:=...);
    MOVEM.L (A7)+,A1/D1               RESTORE REF STR,REF REL;
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_VOI,D2                 IF FP KIND = VOID
    BEQ    EE_SCOPE                   THEN REJECT END;
    BTST.B #PT_FSC,PT_INF(A6)         IF FP SCOPE <> FORMAL
    BEQ    EE_SCOPE                   THEN REJECT END;
 
    CLR.L  D5                         D5:=COUNT:=0;
  REPEAT                            REPEAT
    ADD.L  #1,D5                      D5:=COUNT:=COUNT+1;
    MOVE.L FP_STR(A6),A3              A3:=FP.ACTUAL STRUCT;
    MOVE.L A3,D3                      IF DUMMY ACTUAL
    BEQ    INSP_STA                   THEN STATUS RESULT END;
    MOVE   FP_OFF(A6),D3              D3:=FP.ACTUAL REL;
    LEA    (A3,D3),A6                 A6:=FP:=FP.ACTUAL;
    BTST.B #PT_FSC,PT_INF(A6)
  UNTIL <EQ>                        UNTIL FP NOT FORMAL;
 
    BTST.B #PT_TSC,PT_INF(A6)         "FP = ACTUAL"
  IF <NE> THEN.S                    IF ACTUAL TEMP THEN
    MOVE.L CT_OBJ(A3),A0              A0:=OBJ:=ACTUAL STRUCT.CUR_OBJECT;
  ELSE.S                            ELSE
    MOVE.L EN_OBJ(A3),A0              A0:=OBJ:=ACTUAL STRUCT.HOLDER;
  ENDI                              END;
    BRA    INSP_COM                   GOTO COMMON INSPECT;
    PAGE
INSP_CALL  EQU *                  INSPECT CALLER
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.  D4:=INDEX.
 
    BSR.S  INSP_INIT                  INSPECT INIT(A5:=ENV,A1:=REF STR,
*                                       D1:=REF REL,A0/A3/A6/D2/D4/D5:=...);
    ADD    #1,D6                      ARG#:=ARG#+1;
    MOVE.L -(A4),D5                   D5:=COUNT:=INTEGER ARGUMENT;
    BLT    EE_DATA                    IF COUNT <0 THEN REJECT END;
 
    MOVE.L CT_HOLD(A2),A0             A0:=EXT:=CUR_CTX.HOLDER;
    MOVE.L A2,A3                      A3:=CTX:=CUR_CTX;
  WHILE <NE> DO.S                   WHILE COUNT <> 0 DO
    LEA    EX_CTX(A0),A6              A6:=HEAD CTX STACK;
  IF.L     CT_STK+4(A3) <NE> A6 THEN.S
    MOVE.L CT_STK+4(A3),A3          IF CTX.PREV <> HEAD CTX STACK THEN
    LEA    -CT_STK(A3),A3             A3:=CTX:=PREVIOUS CTX;
  ELSE.S                            ELSE
    CMP.B  #OB_PROB,OB_KIN(A0)        IF EXT IS PROCESS
    BEQ    EE_DATA                    THEN REJECT "COUNT TOO LARGE END";
    MOVE.L EX_EXT+4(A0),A0            A0:=EXT:=PREVIOUS EXT;
    LEA    -EX_EXT(A0),A0             "OFFSET ADJUST"
    MOVE.L EX_CTX+4(A0),A3            A3:=CTX:=EXT.LAST CTX;
    LEA    -CT_STK(A3),A3             "OFFSET ADJUST"
  ENDI                              END;
    SUB    #1,D5                      D5:=COUNT:=COUNT-1
  ENDW                              END  "UNTIL COUNT = 0"
    MOVE.L CT_OBJ(A3),A0              A0:=CTX.CUR_OBJECT;
    BRA.S  INSP_COM                   GOTO COMMON INSPECT;
 
 
INSP_PROC  EQU *                  INSPECT PROCESS
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.  D4:=INDEX;
 
    BSR.S  INSP_INIT                  INSPECT INIT(A5:=ENV,A1:=REF STR,
*                                       D1:=REF REL,A0/A3/A6/D2/D4/D5:=...);
    MOVE.L CT_HOLD(A2),A0             A0:=EXT:=CUR_CTX.HOLDER;
    MOVE.L EX_PR(A0),A0               A0:=PROC:=EXT.PROCESS;
    BRA.S  INSP_COM                   GOTO COMMON INSPECT;
    PAGE
INSP_INIT  EQU *                  INSPECT INITIALIZATION
 
*          CALL:                  RETURN:
* A1       -                      REF STRUCT  (STRUCTURE OF FUTURE REF_ENV)
* A2       CONTEXT                SAME
* A4       ARGUMENT ADDR          UPDATED
* A5       -                      ENVELOPE  (OF MANAGER OBJECT)
* D1       -                      REF REL  (RELATIVE OF FUTURE REF_ENV)
* D6       ARGUMENT#              UPDATED
* A0/A3/A6/D2/D4/D5/D7:  -        UNDEF
* EXITS TO USER IN CASE OF ERRORS.
 
* CHECKS FIRST TWO POINTER ARGUMENTS TO FIND ENVELOPE (MANAGER OBJECT)
* AND FUTURE REF_ENV.
 
    MOVE.L (A7)+,A3                   A3:=POP RETURN;
    BSR    C_PRIM                     CHECK PRIMARY ENV(A5:=ENV,
*                                       A0/A1/A6/D1/D2/D4/D5:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    BSR    C_PT                       CHECK POINTER(A1:=REF STR,D1:=REF REL,
*                                       D2:=PT KIND,A6:=PT_ADDR);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_ENV,D2                 IF PT KIND <> SIMPLE
    BGT    EE_VALUE                   THEN REJECT END;
    JMP    (A3)                       RETURN;
    PAGE
INSP_COM   EQU *                  COMMON INSPECT
 
*          CALL:                  RETURN:
* A0       OBJECT                 UNDEF  (ZERO FOR ABORTED OBJECTS)
* A1       REF STRUCT(OF REF_ENV) UNDEF
* A2       CUR CTX                UNDEF
* A5       MANAGER ENVELOPE       UNDEF
* D1       REF REL (OF REF_ENV)   UNDEF
* D4       -                      INDEX  (OF MAN_SET WITHIN ENVELOPE)
* D5       COUNT OR UNDEF         SAME
* D7       -                      RESULT
* RETURNS TO USER, STACK AS AT ENTRY TO KERNEL OPERATIONS.
 
    MOVE.L A0,D0                      IF OBJ=0 "ABORTED CONTEXT"
    BEQ.S  INSP_STA                   THEN STATUS RESULT END;
    BTST.B #OB_EMB,OB_STA(A0)         IF EMBEDDED OBJECT
    BNE.S  INSP_STA                   THEN STATUS RESULT END;
    MOVE.L OB_SPA(A0),A6              A6:=TOP OBJ;
    MOVE.L SP_ENV+4(A6),A3            A3:=ENV:=OBJ.TOP ENV;  "OFFSET"
    LEA    SP_ENV(A6),A6              A6:=ENV_HEAD;
  WHILE.L A3 <NE> A6 DO.S           WHILE ENV <> ENV_HEAD DO
    CMP.L  EN_MAN-EN_STK(A3),A5
  IF <EQ> THEN.S                    IF ENV.MAN_STRUCT=MANAGER ENV THEN
    MOVE   EN_OFF-EN_STK(A3),D4       D4:=INDEX:=
    SUB    #EN_SIZ-PT_SIZ,D4            (ENV.MAN_REL-BASE)/POINTER SIZE;
    EXT.L  D4
    DIVU   #PT_SIZ,D4
    EXT.L  D4                         "LONG INTEGER"
    MOVEM.L D4/D5,-(A7)               SAVE INDEX,COUNT
    BSR    CLR_SMP                    CLEAR SIMPLE (REF STR, REF REL,A6:=PT);
    LEA    -CT_STK(A3),A5             A5:=ENV;
    MOVE   #PT_ENV,D5                 D5:=ENTITY KIND:=REF_ENV;
    CLR    D4                         D4:=NO CAPS;
    BSR    COPY_NIL                   COPY TO NIL(ENV,PT,REF_ENV,CAPS,A1:=...)
    MOVEM.L (A7)+,D4/D5               D4/D5:=INDEX,COUNT;
    CLR.L  D7                         D7:=RESULT:=OK;
    BRA    RET_OLD2                   RETURN TO USER;
  ENDI                              END;
    MOVE.L 4(A3),A3                   A3:=PREV ENV; "OFFSET"
  ENDW                              END "UNTIL NO MORE ENVELOPES";
 
INSP_STA   EQU *                  STATUS RESULT:
    MOVE.L #ECRNOT_IN,D7              D7:=RESULT:=NOT_IN_SET
    BRA    RET_OLD2                   RETURN TO USER;
    PAGE
SET_CAPS   EQU *                  SET CALL CAPABILITY
 
* CALL AND RETURN:  AS OTHER KERNEL OPERATIONS.
 
    MOVE.L D4,D0                      D0:= LOW_ARG; "SAVED FOR CRE_CTX"
    BSR    C_ENT                      CHECK ENTITY(A5:=OBJ,D2:=PTKIND,
*                                       A1:=PSTR,D1:=PREL,A6/D4/D5:=...);
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    CMP.B  #PT_OBJ,D2                 IF PT KIND <> REF OBJ
    BNE    EE_VALUE                   THEN REJECT END;
    CMP.B  #OB_GEOB,OB_KIN(A5)        IF OBJ.KIND <> GENERAL OBJ
    BNE    EE_STATE                   THEN REJECT END;
 
    MOVEM.L D0/D1/D4/A1/A5,-(A7)      SAVE OBJ, PSTR, CAPS, PREL, LOW_ARG;
    MOVE   GE_CON(A5),D5              D5:=FUNCTION:=OBJ.CONTROL_PROC;
  IF <EQ> THEN.S                    IF DUMMY CONTROL PROC THEN
    MOVE.L #DUM_MAN,A5                A5:=MAN_OBJ:=DUMMY MANAGER
  ELSE.S                            ELSE
    MOVE.L OB_SPA(A5),A6              A6:=TOP OBJ;
    MOVE.L SP_ENV+4(A6),A6            A6:=OBJ.TOP_ENV;  "OFFSET"
    MOVE   EN_OFF-EN_STK(A6),D0       D0:=TOP ENV.MAN_REL;
    MOVE.L EN_MAN-EN_STK(A6),A5       A5:=TOP ENV.MAN_STRUCT;
  IF.L A5 <EQ> #0 THEN.S            IF DUMMY MANAGER THEN
    CLR    D5                         D5:=FUNCTION:=DUMMY;
    MOVE.L #DUM_MAN,A5                A5:=MAN_OBJ:=DUMMY MANAGER;
  ELSE.S                            ELSE
    BTST.B #PT_LSC,PT_INF(A5,D0)
  IF <EQ> THEN.S                    IF TEMP MANAGER POINTER THEN
    CLR    D5                         D5:=FUNCTION:=DUMMY;
    MOVE.L #DUM_MAN,A5                A5:=MAN_OBJ:=DUMMY MANAGER;
  ELSE.S                            ELSE
    MOVE.L EN_OBJ(A5),A5              A5:=MAN_OBJ:=MAN_STRUCT.HOLDER;
  ENDI                              END
  ENDI                              END
  ENDI                              END  "FIND MANAGER"
 
    MOVE.L CT_HOLD(A2),A0             A0:=EXT:=CUR_CTX.HOLDER;
    MOVE.L (A7)+,D4                   D4:= LOW_ARG; "RESTORED"
    MOVE   #1,D3                      D3:=ADDITIONAL FORMALS:=1;
    BSR    CRE_CTX                    CREATE CTX(EXT,...,A3:=NEW CTX,D4:=ENTRY,
*                                       A1/A5/A6/D0-D2:=UNDEF);
    MOVEM.L (A7)+,D1/D2/A1/A5         RESTORE OBJ, PSTR, CAPS, PREL;
    BEQ    RET_FAST                   IF NOT OK THEN RETURN TO USER END;
    MOVE   D5,-(A7)                   SAVE FUNCTION;
    MOVE   CT_TOPT(A3),D3             D3:=NEW CTX.F(1);  "FP REL"
    BSR    SET_ACT                    SET ACTUAL REF(P STR,PREL,FP REL,NEW CTX);
    LEA    (A3,D3),A6                 A6:=FP:=NEW CTX.F(1);
    EXG.L  D4,D2                      D2:=ENTRY; D4:= CAPS;
    MOVE   #PT_OBJ,D5                 D5:=ENTITY KIND:=OBJECT;
    BSR    COPY_NIL                   COPY TO NIL(F(1),OBJ,CAPS,A1:=UNDEF);
    BSET.B #PT_RET,PT_INF(A6)         F(1).RETURN:=TRUE;
    MOVE.L D2,D4                      D4:=ENTRY;
    MOVE   (A7)+,D5                   RESTORE FUNCTION;
    EXT.L  D5                         FUNCTION:=32 BITS;
    BSR    SAVE_STK                   SAVE SUPV STACK(CUR_CTX,ENTRY,FUNCTION,
*                                       A5/A6/D0:=UNDEF);
    MOVE   #1,D3                      D3:=ADDITIONAL FORMALS:=1;
    BSR    SET_FP                     SET FORMALS(EXT,CUR_CTX,NEW_CTX,ARG ADDR,
*                                       ADDITIONAL FORMALS,ARG#,D3:=#FORMALS,
*                                       A1/A5/A6/D0-D2/D4/D5:=UNDEF);
  IF <NE> THEN.S                    IF OK THEN
    TST.L  (A7)
  IF <NE> THEN.S                    IF FUNCTION <> 0  "STACKED BY SAVE_STK" THEN
    BSR    ENT_CTX                    ENTER CONTEXT(A3=CTX,D3:=#FORMALS)
*                                   "CONTINUES HERE AT OBJ_RETURN.  A3=CTX"
  ELSE.S                            ELSE
    CLR.L  D7                         D7:=RESULT:=OK
  ENDI                              END;
    BSR    RET_FP                     RETURN FORMALS(A3=CTX,D6/D7:=UPDATED);
    TST.W  D7                       IF RESULT=OK
  IF <EQ> THEN.S                    THEN
    MOVE.W CT_TOPT(A3),D3              D3:=INDEX TO FIRST FORMAL
    MOVE.L FP_STR(A3,D3),A6            A6:=ACTUAL POINTER :=
    ADDA.W FP_OFF(A3,D3),A6              FML.STRUCT+FML.OFFSET;
  IF.B PT_KIN(A6) <EQ> #PT_OBJ THEN.S
    MOVE.L PT_REF(A6),A5            IF ACTUAL IS REF_OBJ AND   A5:=ACT.OBJECT;
  IF.B OB_KIN(A5) <EQ> #OB_GEOB THEN.S   IF OBJECT IS GENERAL THEN
    BSET.B #PT_CC,PT_INF(A6)          PUT ON CALL CAP IN ACTUAL POINTER;
  ENDI                              ENDI; OBJ IS GENERAL
  ENDI                              ENDI; ACTUAL IS REF_OBJ
  ENDI                              ENDI; RESULT=OK
  ENDI                              END  "SET FP CARRIED OUT"
    BSR    DEL_CTX                    DELETE CTX(CTX,A3:=OLD CTX,A0:=EXT);
    BSR    RSTO_STK                   RESTORE SUPV STACK(OLD CTX,A5/A6/D0:=UNDEF
    BRA    RET_OLD3                   RETURN TO USER;
 
    TTL    CHECK PROCEDURES
    PAGE
C_PT       EQU *                  CHECK POINTER ARGUMENT, NORMAL CTX
 
*          CALL:                  RETURN:
* A1       -                      POINTER STRUCT (UNDEF IF VOID ARG.)
* A2       CONTEXT                SAME
* A4       ARGUMENT ADDR          UPDATED
* A6       -                      POINTER  (UNDEF IF VOID ARG.)
* D1.W     -                      POINTER REL (UNDEF IF VOID ARG.)
* D2.W     -                      POINTER KIND (VOID KIND IF VOID ARG.)
* D6.W     ARGUMENT#              UPDATED
* D7.L     -                      UNDEF IF OK, RESULT IF NOT OK
* SR       -                      NE=OK, EQ=NOT OK
 
* TRANSFORMS A POINTER ARGUMENT (OR THE FIRST PART OF A SUBSEGM
* ARGUMENT) INTO A POINTER ADDRESS, ETC.
 
    MOVE   D3,-(A7)                   SAVE D3
    CLR    D3                         D3:=RESIDENT:=NORMAL CTX
    BRA.S  C_PTCOM                    GOTO COMMON WITH C_PTRES
 
 
C_PTRES    EQU *                  CHECK POINTER, NORMAL OR RESIDENT
 
*          CALL:                  RETURN:
* D3       RESIDENT CTX (<>0)     SAME
* OTHER:   AS C_PT
 
* IF CALLED FROM A RESIDENT CTX: CHECKS THAT AN
* INDIRECT ADDRESS HAS A RESIDENT FIRST PART. OTHERWISE AS C_PT.
 
    MOVE   D3,-(A7)                   SAVE D3
 
C_PTCOM    EQU *
    ADD    #1,D6                      ARGUMENT#:=...+1;
    MOVEQ  #PT_VOI,D2                 D2:=POINTER_KIND:=VOID;
    MOVE   -(A4),D7                   D7:=F/T/L,INDEX1 OR INDEX2;
  IF <NE> THEN                      IF NOT VOID THEN
    MOVE   -(A4),D1                   D1:=0 OR F/T/L, INDEX1;
  IF <EQ> THEN.S                    IF DIRECT THEN
    EXG    D1,D7                      D1:=F/T/L,INDEX1;  D7:=0
    TST    D1                       END;
  ENDI                              "D1=F/T/L,INDEX1; D7=0 OR INDEX2"
 
  IF <LT> THEN.S                    IF LOCAL THEN
    AND    #PT_MASK,D1                D1:=INDEX1;  "MULT OVERFLOW PREVENTED"
    BEQ    ER_ILLE                  IF INDEX1 = 0 THEN ADDR_ILLEGAL END;
    MULU   #PT_SIZ,D1                 D1:=POINTER_REL:=
    ADD    #EN_SIZ-PT_SIZ,D1          INDEX1*POINTER_SIZE+BASE;
    MOVE.L CT_OBJ(A2),A6              A6:=CURRENT_OBJECT(CTX);
    MOVE.L OB_SPA(A6),A6              A6:=TOP_OBJ;
    MOVE.L SP_ENV+4(A6),A1            A1:=POINTER STRUCT:=TOP_ENV(OBJ);
    LEA    -EN_STK(A1),A1             A1:= FIRST OF STRUCT;
    CMP    EN_TOPL(A1),D1           IF POINTER REL >= TOP_ENV.TOP_LOCAL
    BCC    ER_ILLE                  THEN ADDR_ILLEGAL END;
  ELSE.S                            ELSE  "END LOCAL"
 
    MOVE.L A2,A1                      A1:=POINTER STRUCT:=CTX;
    BTST.L #14,D1
  IF <NE> THEN.S                    IF TEMP THEN
    AND    #PT_MASK,D1                D1:=INDEX1;  "MULT OVERFLOW PREVENTED"
    BEQ    ER_ILLE                  IF INDEX1=0 THEN ADDR_ILLEGAL END;
    MULU   #PT_SIZ,D1                 D1:=POINTER_REL:=
    ADD    #CT_SIZ,D1                 INDEX1*POINTER_SIZE + BASE
    CMP    CT_TOPT(A1),D1           IF POINTER REL >= CTX.TOP_LOCAL
    BCC    ER_ILLE                  THEN ADDR_ILLEGAL END;
 
  ELSE.S                            ELSE  "FORMAL"
    AND    #PT_MASK,D1                D1:=INDEX1;  "MULT OVERFLOW PREVENTED"
    BEQ    ER_ILLE                  IF INDEX1 = 0 THEN ADDR_ILLEGAL END;
    SUB    #1,D1                      D1:=POINTER_REL:=
    MULU   #FP_SIZ,D1                   (INDEX1-1)*FP_SIZE+BASE;
    ADD    CT_TOPT(A1),D1
    CMP    CT_TOPF(A1),D1           IF POINTER REL >= CTX.TOP_FORMAL
    BCC.S  ER_ILLE                 THEN ADDR_ILLEGAL END;
  ENDI                              END  "FORMAL"
  ENDI                              END  "NON-LOCAL"
 
    AND    #PT_MASK,D7                D7:=INDEX2;  "MULT OVERFLOW PREVENTED"
  IF <NE> THEN.S                    IF INDEX2 <> 0 THEN  "INDIRECT"
  IF.B PT_KIN(A1,D1) <EQ> #PT_ENV THEN.S  IF POINTER.KIND = ENV_REF
    MOVE.L PT_REF(A1,D1),A1         THEN A1:=POINTER_STRUCT:=ENVELOPE
  ELSE.S                            ELSE  "INDIRECT THROUGH MAN_SET"
    CMPI.B #PT_MAN,PT_KIN(A1,D1)    IF POINTER.KIND <> MAN_SET
    BNE.S  ER_ILLE                  THEN ADDR_ILLEGAL END;
    TST    D3
  IF <NE> THEN.S                    IF RESIDENT CTX THEN
    BTST.B #PT_RES,PT_INF(A1,D1)      IF POINTER NOT RESIDENT
    BEQ.S  ER_ILLE                    THEN ADDR_ILLEGAL END
  ENDI                              END;
 
    MOVE.L 4(A1,D1),A1                POINTER_STRUCT:=MAN_SET.LAST_ENV;
  ENDI                              END  "ENVELOPE FOUND"
    MOVE   D7,D1
    MULU   #PT_SIZ,D1                 D1:=POINTER_REL:=
    ADD    #EN_SIZ-PT_SIZ,D1          INDEX2*PT_SIZE+BASE;
    CMP    EN_TOPL(A1),D1           IF POINTER REL >= ENV.TOP_LOCAL
    BCC.S  ER_ILLE                  THEN ADDR ILLEGAL END;
  ENDI                              END  "INDIRECT";
 
    LEA    (A1,D1),A6                 A6:=POINTER:=POINTER_STRUCT+POINTER_REL;
    MOVE.B PT_KIN(A6),D2              D2:=POINTER.KIND; "WORD CLEARED AT ENTRY"
***
    PRT_MEM C_PT,(A6),FP_SIZ
  ELSE.S                            ELSE  "VOID"
    SUB    #2,A4                      ARGUMENT ADDR:=UPDATED
  ENDI                              END;
 
    MOVE   (A7)+,D3                   RESTORE D3;
***
    PRT_REG C_PT
    CMPA.L A2,A4                      SR:=NE;  "OK"
    RTS                               RETURN
 
ER_ILLE    EQU *
    ADD    #2,A7                      RELEASE SAVED D3
    BRA    ER_ADDR                    GOTO ADDR_ILLEGAL;
 
    PAGE
C_ENT      EQU *                  CHECK ENTITY ARGUMENT, NORMAL CTX
 
*          CALL:                  RETURN:
* A1       -                      POINTER STRUCT  (UNDEF IF VOID ARG.)
* A2       CONTEXT                SAME
* A4       ARGUMENT ADDR          UPDATED
* A5       -                      ENTITY  (ENV, OBJ, OR UNDEF)
* A6       -                      POINTER  (UNDEF IF VOID ARG.)
* D1.W     -                      POINTER REL  (UNDEF IF VOID ARG.)
* D2.W     -                      POINTER KIND  (VOID KIND IF VOID ARG.)
* D4.W     -                      CALL CAP, COPY CONTROL  (AS IN PT_INF)
* D5.W     -                      ENTITY KIND  (ENV, OBJ, NIL, OR INTRPT)
* D6.W     ARGUMENT#              UPDATED
* D7.L     -                      UNDEF IF OK, RESULT IF NOT OK.
* SR       -                      NE = OK, EQ = NOT OK
 
* GETS A POINTER ARGUMENT AND RETRIEVES THE ENTITY FROM THE POINTER.
 
    BSR    C_PT                       CHECK POINTER ARG(A1:=PSTR,A6:=PT,
*                                       D1:=PREL,D2:=PT KIND);
    BEQ.S  RETURN                     IF NOT OK THEN RETURN END;
 
C_ENTCOM   EQU *
    CLR    D4                         D4:=CAPS:=0;
    MOVE   D2,D5                      D5:=POINTER_KIND*2
    LSL    #1,D5
    CASEJMP D5                     CASE POINTER_KIND OF
    CASELAB NIL_2
    CASELAB OBJ_2
    CASELAB ENV_2
    CASELAB OWN_2
    CASELAB MAN_2
    CASELAB ENV_2                     "INTERRUPT POINTER"
    CASELAB NIL_2                     "VOID"
 
OBJ_2      EQU *                  OBJ_REF:
    MOVE.B PT_INF(A6),D4              D4:=CALL CAP,COPY CONTROL;
    AND #1<<PT_CC+1<<PT_CON,D4
 
ENV_2      EQU *                  ENV_REF, INTERRUPT POINTER:
    MOVE.L PT_REF(A6),A5              A5:=ENTITY:=POINTER.REF;
    MOVE.B PT_KIN(A6),D5              D5:=ENTITY KIND:=POINTER KIND;
    EXT.W  D5                         "EXTEND TO WORD";  SR:=OK;
    RTS                               RETURN
 
NIL_2      EQU *                  NIL, VOID;
    CLR    D5                         D5:=ENTITY KIND:=NIL;
    CMPA.L A2,A4                      SR:=NE;  "OK"
    RTS                               RETURN
 
OWN_2      EQU *                  OWNER_SET:
    MOVE.L 4(A6),A5                   A5:=ENTITY:=LAST OBJ IN SET;
 
OWN_6A     EQU *                  COMMON WITH FIRST IN SET:
    BTST.B #OB_OCC,OB_STA(A5)
  IF <NE> THEN.S                    IF OBJ.OWNERS_CALL_CAP THEN
    BSET   #PT_CC,D4                  D4:=CAPS:=CALL CAP
  ENDI                              END;
  IF.B #OB_GEOB <EQ> OB_KIN(A5) THEN.S
    TST    GE_CON(A5)               IF GENERAL OBJECT
  IF <NE> THEN.S                    AND CONTROL PROC <> 0 THEN
    BSET   #PT_CON,D4                 D4:=CAPS:=CAPS+COPY CONTROL
  ENDI                              END;
  ENDI
    MOVEQ  #PT_OBJ,D5                 D5:=ENTITY KIND:=OBJ; SR:=OK;
    RTS                               RETURN
 
MAN_2      EQU *                  MAN_SET:
    MOVE.L 4(A6),A5                   A5:=ENTITY:=LAST ENV IN SET;
    MOVEQ  #PT_ENV,D5                 D5:=ENTITY KIND:=ENV; SR:=OK
 
RETURN     EQU *                  "RETURN, COMMON FOR ALL PROCEDURES"
    RTS                               RETURN
 
 
C_ENTRES   EQU *                  CHECK ENTITY, NORMAL OR RESIDENT
 
*          CALL:                  RETURN:
* D3       RESIDENT CTX (<>0)     SAME
* OTHER:   AS C_ENT
 
* IF CALLED FROM A RESIDENT CTX:  CHECKS THAT THE POINTER IS
* NIL, VOID, OR RESIDENT.  OTHERWISE AS C_ENT.
 
    BSR    C_PTRES                    CHECK POINTER RES(D3,...)
    BEQ.S  RETURN                     IF NOT OK THEN RETURN END;
    BSR    C_ENTCOM                   FIND ENTITY; "COMMON WITH C_ENT"
    TST    D3
  IF <NE> THEN.S                    IF RESIDENT CTX
    TST    D5                         AND ENTITY KIND <> NIL
  IF <NE> THEN.S                    THEN
    BTST.B #PT_RES,PT_INF(A6)         IF POINTER NOT RESIDENT
    BEQ    ER_CAP                     THEN CAPABILITY VIOLATION END;
  ENDI                              END;
  ENDI
 
    CMP.L  A2,A4                      SR:=NE; "OK"
    RTS                               RETURN
    PAGE
C_CALL     EQU *                  CHECK CALLABLE OBJECT AND FUNCTION#
 
*          CALL:                  RETURN:
* A0       EXT OR PROC OBJECT     SAME  (USED BY KERNEL OBJECTS)
* A2       CONTEXT                SAME
* A4       ARGUMENT ADDR          UPDATED  (UNDEF IF SR=RETURN)
* A5       -                      OBJECT TO CALL  (UNDEF IF SR=RETURN)
* D3.W     RESIDENT CTX (<>0)     UNDEF  (USED BY KERNEL OBJECTS)
* D4       LOW ARG ADDR (PHYS)    SAME  (UNDEF IF SR=RETURN)
* D5.L     -                      FUNCTION#  (UNDEF IF SR=RETURN)
* D6.W     ARGUMENT#              UPDATED
* D7.L     -                      RESULT IF SR=RETURN, UNDEF IF SR=ENTER
* SR       -                      NE=ENTER CONTEXT, EQ=RETURN  (IN THIS CASE
*                                 A KERNEL OBJECT MAY HAVE BEEN CALLED
*                                 AND SUSPENDED THE CONTEXT)
* OTHER    -                      UNDEF
 
* USES A POINTER ARGUMENT TO DETERMINE THE OBJECT.  CHECKS THE SIGN
* OF THE FUNCTION CODE ACCORDINGLY.  CALLS A KERNEL OBJECT DIRECTLY.
* CHECKS REENTRANCY AND CALL CAP FOR GENERAL OBJECTS.
* IF CALLED FROM A RESIDENT CTX, CHECKS THAT THE POINTER IS RESIDENT OR NIL.
 
 
    MOVE.L D4,D0                      D0:=LOW ARG ADDR;
*                                     CHECK ENTITY(A1/D1/A6:=...,A5:=ENTITY,
    BSR    C_ENTRES                     D2:=PTKIND,D4:=CAPS,D5:=ENTKIND);
    EXG.L  D4,D0                      D0:=CAPS; D4:=LOW ARG ADDR; CCR UNCHANGED
    BEQ    RETURN                     IF NOT OK THEN RETURN END;
    LSL    #1,D5                      D5:=ENTITY_KIND*2;
    CASEJMP D5                        CASE ENTITY_KIND OF
    CASELAB NIL_3
    CASELAB OBJ_3
    CASELAB ENV_3
 
NIL_3      EQU *                  NIL OR VOID:
    CMPI.B #PT_VOI,D2                 IF POINTER KIND <> VOID
    BNE    ER_VALUE                   THEN POINTER VALUE ILLEGAL END;
    MOVE.L CT_OBJ(A2),A5              A5:=OBJECT TO CALL:=CUR_OBJ;
    MOVE.L -(A4),D5                   D5:=FUNCTION#:=NEXT ARGUMENT;
    ADD    #1,D6                      D6:=ARGUMENT# :=...+1;
    RTS                               "SR=ENTER" RETURN;
 
OBJ_3      EQU *                  OBJECT:
    ADD    #1,D6                      D6:=ARGUMENT# :=...+1;
    MOVE.L -(A4),D5                   D5:=FUNCTION# :=NEXT ARGUMENT;
    BLE    ER_FUNC                  IF FUNCTION#<=0 THEN FUNC_ILLEGAL END;
    CLR    D7
    MOVE.B OB_KIN(A5),D7              D0.W :=OBJECT_KIND*2;
    LSL    #1,D7
 
    CASEJMP D7                        CASE OBJECT_KIND OF
    CASELAB GEN_1
    CASELAB GATE_OBJ
    CASELAB COND_OBJ
    CASELAB ER_STATE                  "OPEN OBJECT"
    CASELAB ER_STATE                  "DORMANT OBJECT"
    CASELAB ER_STATE                  "PROCESS OBJECT"
    CASELAB ER_STATE                  "EXTENSION OBJECT"
    CASELAB ER_STATE                  "SEGMENT OBJECT"
    CASELAB ALLOC_OB
    CASELAB SCHEDOBJ
 
* ENTRIES IN KERNEL OBJECTS:  SEE SEPARATE MODULE"
 
 
GEN_1      EQU *                  GENERAL OBJECT:
    BTST   #PT_CC,D0                IF CALL CAP=0 THEN CAP_VIOLATION
    BEQ    ER_CAP                   END;
    BTST.B #OB_REEN,OB_STA(A5)
  IF <EQ> THEN.S                    IF OBJECT.NOT_REENTRANT THEN
    LEA    GE_EX(A5),A6               A6:=OBJECT.EXECUTES_HEAD;
    CMPA.L GE_EX(A5),A6             IF CONTEXTS IN OBJ THEN CONC_ERROR
    BNE    ER_CONC                  END;
  ENDI                              END;
    CMPA.L A2,A4                      SR:=ENTER CONTEXT;  "NE"
    RTS                               RETURN
 
ENV_3      EQU *                  ENVELOPE:
    MOVE.L EN_OBJ(A5),A1              A1:=OBJECT:=ENVELOPE.HOLDING_OBJ;
    CMP.B  #OB_GEOB,OB_KIN(A1)      IF OBJECT NOT GENERAL THEN STATE_ILLEGAL
    BNE    ER_STATE                 END;
    MOVE.L OB_SPA(A1),A6              A6:=TOP_OBJ;
    LEA    SP_ENV(A6),A6              A6:=HEAD ENV CHAIN;
    CMPA.L EN_STK(A5),A6            IF ENVELOPE NOT TOP ENVELOPE
    BNE    ER_STATE                 THEN STATE_ILLEGAL END;
    MOVE.L A1,A5                      A5:=OBJECT;
    MOVE.L -(A4),D5                   D5:=FUNCTION# :=NEXT ARGUMENT;
    ADD    #1,D6                      ARGUMENT#:=...+1; SR:=ENTER;
    RTS                               RETURN;
 
    PAGE
C_SUB      EQU *                  CHECK SUBSEGM ARGUMENT  (NOT VOID)
 
*          CALL:                  RETURN:
* A1       -                      POINTER STRUCT
* A2       CONTEXT                SAME
* A4       ARGUMENT ADDR          UPDATED
* A5       -                      BASE SEGM DESCRIPTOR
* D0.L     -                      TOP RELATIVE ADDR IN BASE SEGM
* D1.W     -                      POINTER REL
* D2.L     -                      LENGTH OF SUBSEGM
* D4.W     -                      CAPS  (READ,WRITE,EXECUTE AS IN OB_STA)
* D5.L     -                      FIRST RELATIVE ADDR IN BASE SEGM
* D6.W     ARGUMENT#              UPDATED
* D7.L     -                      UNDEF IF OK, RESULT IF NOT OK
* SR       -                      NE = OK, EQ = NOT OK
 
* GETS AND CHECKS A SUBSEGMENT ARGUMENT.  CHECK FOR POSSIBLE VOID
* ARGUMENT MUST BE DONE BY CALLER.
 
    MOVEM.L A6,-(A7)                  SAVE A6;
    BSR    C_ENT                      CHECK ENTITY (A1:=PSTR,A5:=BASE SEGM,
*                                       A6:=PT,D1:=PREL,D5:=ENTKIN,D2/D4:=...);
    MOVEM.L (A7)+,A6                  RESTORE A6;
    BEQ    RETURN                     IF NOT OK THEN RETURN END;
    CMP.B  #PT_OBJ,D5                 IF ENTKIN <> OBJECT THEN
    BNE    ER_VALUE                     REJECT END;
    CMP.B  #OB_SEOB,OB_KIN(A5)        IF BASE_SEGM.OBJKIN <> SEGMENT THEN
    BNE    ER_STATE                     REJECT END;
    MOVE.W -(A4),D4                   D4:=NEXT ARGUMENT BITS 2:0;
    AND    #7,D4
    LSL    #OB_READ,D4                D4:=CAPS:=
    AND.B  OB_STA(A5),D4                USE BITS AND BASE_SEGM.CAPS;
    MOVE.L -(A4),D5                   D5:=FIRST REL:=NEXT ARGUMENT;
    CMP.L  SE_LEN(A5),D5              IF FIRST REL >= BASE_SEGM.LENGTH "UNSIGNED
    BCC    ER_DATA                    THEN REJECT END;
    MOVE.L -(A4),D2                   D2:=LENGTH:=NEXT ARGUMENT;
    BLE    ER_DATA                    IF LENGTH <= 0 THEN REJECT END;
    MOVE.L D2,D0                      D0:=TOPREL:=
    ADD.L  D5,D0                        LENGTH+FIRST REL;
    CMP.L  SE_LEN(A5),D0              IF TOP REL > BASE_SEGM.LENGTH
    BHI    ER_DATA                    THEN REJECT END;
***
    PRT_REG C_SUB
    TST    D6                         SR:=NE;  "OK"
    RTS                               RETURN;
    PAGE
C_OPEN     EQU *                  CHECK OWNER POINTER AND OPEN OBJECT
 
*          CALL:                  RETURN:
* A0       -                      OBJECT
* A1       -                      POINTER STRUCT
* A2       CONTEXT                SAME
* A4       ARGUMENT ADDR          UPDATED
* A5       -                      OBJECT (=A0)
* A6       -                      POINTER ADDR
* D1.W     -                      POINTER REL
* D2.W     -                      POINTER KIND  ("OWN_SET" IF OK)
* D6.W     ARGUMENT#              UPDATED
* D7.L     -                      UNDEF IF OK, RESULT IF NOT OK
* SR       -                      NE = OK, EQ = NOT OK
* D4/D5    -                      UNDEF
 
* GETS AN ENTITY ARGUMENT AND CHECKS FOR OWNER POINTER AND OPEN OBJECT.
* (TYPICALLY USED WHEN ADDING ENV OR KERNEL ENVELOPE TO AN OBJECT).
 
    BSR    C_ENT                      CHECK ENTITY(A1:=PT_STR,A5:=OBJ,A6:=PT,
*                                       D1:=PT_REL,D2:=PTKIND,D4/D5:=...);
    BEQ    RETURN                     IF NOT OK THEN RETURN END;
    CMP.B  #PT_OWN,D2                 IF POINTER KIND <> OWN SET
    BNE    ER_VALUE                   THEN REJECT END;
    CMP.B  #OB_OPOB,OB_KIN(A5)        IF OBJECT KIND <> OPEN
    BNE    ER_STATE                   THEN REJECT END;
    MOVE.L A5,A0                      A0:=A5:=OBJ;
«eof»