|
|
DataMuseum.dkPresents historical artifacts from the history of: Bogika Butler |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Bogika Butler Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 152832 (0x25500)
Types: TextFile
Names: »MMPROCS.SA«
└─⟦1ed910a99⟧ Bits:30009789/_.ft.Ibm2.50006596.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦this⟧ »MMPROCS.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⟧ »MMPROCS.SA«
***********************************************************************
* Copyright 1984 by *
* NCR Corporation *
* Dayton, Ohio U.S.A. *
* All Rights Reserved *
***********************************************************************
* EOS Software produced by: *
* NCR Systems Engineering - Copenhagen *
* Copenhagen *
* DENMARK *
***********************************************************************
MM_PROCS IDNT 1,0 MEMORY MANAGEMENT PROCEDURES
OPT FRS FORWARD REFERENCE SHORT,
NOLIST
INCLUDE COMDEF.SA
LIST
* WRITTEN BY VILHELM ROSENQVIST
*
* A SYSTEM DEFINED PART OF THE ADDRESS SPACE IS MANAGED BY
* THE MM_PROCS. THE FIRST AND LAST PART OF THIS ADDRESS SPACE MUST BE RAM.
* NO_RAM AREAS MAY BE PRESENT IN BETWEEN. THA WHOLE ADDRESS SPACE IS
* STRUCTURED AS A TWO_WAY CHAINED LIST OF MEMORY RECORDS (MEM_RECS).
* THE CHAINS MAKE IT POSSIBLE TO SCAN THE MEMORY RECORDS IN INCREASING OR
* DECREASING ADDRESS ORDER. EACH MEMORY REC CONSISTS OF THREE PARTS; NAMELY
* A NO_USE PART, A FREE PART AND A USED PART
* THE NO_USE PART CANNOT BE USED TO ALLOCATE NEW OBJECTS. THE FREE PART MAY
* BE USED TO ALLOCATE KERNEL PARTS OR USER PARTS
* THE USED PART CONTAINS EITHER KERNEL PARTS OR USER PARTS, NOT BOTH.
* A MEM_REC CONTAINING KERNEL PARTS IN THE USED PART IS CALLED A KERNEL
* MEM_REC, WHILE A MEM_REC CONTAINING USER PARTS IS CALLED A USER MEM_REC.
* IF NO USED PART IS PRESENT THE RECORD IS CALLED A FREE MEM_REC.
* THE MEM_REC CHAIN STARTS AT 'F_ALLOC' AND ENDS AT 'L_ALLOC'. ALL KERNEL
* MEM_RECS PRECEDE ALL THE USER MEM_RECS. FREE MEM_RECS IS ONLY PRESENT
* WHEN THE LAST PART OF A RAM AREA IS FREE. OTHER FREE AREAS APPEARS
* ONLY AS THE FREE PART OF A KERNEL OR USER MEM_REC.
* THE TYPE OF THE MEM_REC, THE CHAIN FIELDS AND A DESCRIPTION OF THE
* THREE PARTS ARE PLACED AT THE BEGINNING OF THE MEM_REC, AND
* IS CALLED THE HEAD OF THE MEM_REC.
*
* HEAD OF MEM_REC
OFFSET 0
MR_NXT DS.L 1 NEXT: ADDR OF NEXT MEM_REC (OFFSET 0 USED)
MR_PRV DS.L 1 PREV: ADDR OF PRIOR MEM_REC (OFFSET 4 USED)
MR_FST DS.L 1 FIRST: ADDR OF THE FIRST FREE BYTE (THE FREE PART)
MR_FRE DS.L 1 FREE_BYTES: NUMBER OF BYTES IN THE FREE PART (MAY BE ZERO)
* ONE WORD WITH TWO BYTES FOLLOWS:
MR_FIX DS.B 1 FIXED: 0=DYNAMICLY CREATED MEM_REC HEAD, 1=INITIAL HEAD
MR_TYP DS.B 1 TYPE: 0=FREE MEM_REC, 1=KERNEL MEM_REC,-1=USER MEM_REC
MR_SIZ DS.W 0 HEAD_SIZE: SIZE OF HEAD
* LET HEAD BE THE ADDRESS OF A MEM_RECORD. WE DEFINE THE FOLLOWING ADDRESSES:
* FIRST_NO_USE = HEAD
* FIRST_FREE = HEAD.FST
* FIRST_USED = HEAD.FST+HEAD.FRE
* TOP_USED = HEAD.NXT
* THE THREE PARTS OF A MEM_RECORD ARE:
* NO_USE PART = FIRST_NO_USE..FIRST_FREE-1 (MAY BE EMPTY)
* FREE PART = FIRST_FREE..FIRST_USED-1 (MAY BE EMPTY)
* USED PART = FIRST_USED..TOP_USED-1 (MAY BE EMPTY)
*
XDEF MR_FRE,MR_SIZ USED BY ENTER TO COMPUTE SIZE OF FREE MEMORY.
*
* THE HEAD OF THE MEM_REC MAY BE PART OF THE NO_USE PART (FIXED=1, THE
* HEAD IS NEVER DESTROYED) OR THE FREE PART (THE HEAD MAY BE DESTROYED
* WHEN FREE MEMORY IS USED TO ALLOCATE OBJECTS,FIXED=0).
* IN THE LAST CASE FIRST_FREE POINT TO THE HEAD ITSELF.
* THE ADDRESS SPACE IS INITIALLY DEFINED TO MM AS A (SORTED) LIST OF
* ADDRESS PAIRS. EACH PAIR DEFINES A RAM AREA THROUGH
* ITS FIRST AND TOP ADDRESS. INITIAL MEM_RECS ARE CREATED AS FOLLOWS:
* ON THE LAST PAGE OF EACH RAM AREA IS PLACED A HEAD WHICH DESCRIBES THAT
* PAGE PLUS THE FOLLOWING NO_RAM AREA AS A NO_USE AREA AND DESCRIBE THE
* NEXT RAM AREA (EXCEPT ITS LAST PAGE) AS A FREE AREA. NO USED AREA IS PRESENT
* IN THESE INITIAL FREE MEM_RECS. AN INITIAL MEM_RECS HAS FIXED=1, AND THE
* FREE PART OF THE MEM_REC ENDS AT A PAGE BAUNDARY AND BEGINS AT A WORD
* BAUNDARY.
* THE FIRST AND LAST RAM AREA IS TREATED A LITTLE DIFFERENTLY:
* THE FIRST RAM AREA (EXCEPT THE LAST PAGE) IS DESCRIBED IN THE FIRST
* MR_SIZ BYTES OF THE AREA.
* THE HEAD IS EQUVALENT WITH THE NO_USE PART OF THIS FIRST MEM_REC
* THE ADDRESS OF THE FIRST HEAD IS CALLED F_ALLOC.
* THE LAST PART OF THE LAST RAM AREA IS USED FOR THE PAGE TABLE
* (SEE LATER), AND A DUMMY HEAD IN FRONT OF THE TABLE. THE ADDRESS
* OF THIS HEAD IS CALLED L_ALLOC. THE MEM_REC BEFORE L_ALLOC
* HAS A USED PART CONTAINING ONE "USER PART" (THE LAST REAL
* MEM_REC IS ALWAYS A USER MEM_REC). THIS USER PART IS
* USED TO HOLD THE SUPERVISOR STACK. IT IS NEVER MOVED,
* BUT MAY BE EXTENDED.
* IF ONLY ONE RAM AREA IS PRESENT, THE RULES FOR THE FIRST AND THE
* LAST RAM AREA APPLIES TO THIS AREA.
* HEADS OF INITIAL MEM_REC ARE NEVER DESTROYED, BECAUSE THEY ARE
* PLACED IN NO_USE PARTS. WHEN KERNEL, AND USER PARTS ARE CREATED AND REMOVED,
* NEW MEM_REC HEADS MAY BE CREATED. ALL THESE HEADS ARE PLACED IN THE FREE
* PART OF THE MEM_REC THEY DESCRIBE, I.E. HEAD.MR_FIRST=HEAD AND
* HEAD.MR_FIX=0.
* AN OBJECT IS REPRESENTED BY ONE KERNEL PART AND OPTIONALLY ONE USER PART.
* THE KERNEL PART IS ONLY ACCESSED BY THE KERNEL AND CONTAINS THE ADDRESS
* OF THE USER PART. THE USER PART REFERENCES THE KERNEL PART THROUGH A PAGE
* TABLE. THE TABLE CONSISTS OF ONE LONG WORD FOR EACH PAGE (256 BYTES) OF
* "ADDRESS SPACE", BETWEEN F_ALLOC AND L_ALLOC. LET TUA BE THE ADDRESS
* OF THE TOP BYTE OF A USER MEM_REC (THE HIGHEST ADDRESS +1), THEN
* PAGETABLE(TUA//256) CONTAINS THE ADDRESS OF THE KERNEL PART. PAGE TABLE
* ENTRIES THAT DO NOT CORRESPOND TO THE TOP PAGE OF A USER PART ARE
* UNDEFINED FOR THE MOMENT. ONLY ONE PAGETABLE IS PRESENT TO SIMPLIFY
* THE ALGORITHM. IF THE NO_USE AREAS ARE LARGE, A PAGETABLE COULD BE
* PLACED AT THE END OF EACH RAM AREA DESCRIBING THE PAGES OF
* THAT AREA. NO ENTRIES WOULD CORRESPOND TO NO_USE PAGES AS IS THE
* CASE IN THE PRESENT IMPLEMENTATION. THE METHOD ALLOWS ADDITION OF RAM AREAS
* "ON THE FLY".
* THE PAGE TABLE MAY ALSO BE REPLACED BY A CHAIN THROUGH ALL KERNEL PARTS.
* THE KERNEL PARTS SHOULD BE SORTED IN CHAIN, ACCORDING TO THE ADDRESS
* OF THEIR USER PART.
* THE PRESENT STRATEGY KEEPS ALL KERNEL PARTS IN THE LOW END OF THE ADDRESS
* SPACE, AND THE USER PARTS IN THE HIGH END. ANOTHER STRATEGY COULD USE
* EACH OF THE RAM AREAS IN THIS WAY I.E. ALLOCATE KERNEL PARTS IN
* THE LOW ADDRESS PART OF EACH RAM AREA WHILE USER PARTS ARE PLACED
* IN THE HIGH ADDRESS PARTS OF THESE AREAS. THIS APPROCH MAY HAVE A BETTER
* PERFORMANCE (LESS MOVE REQUIRED).
* THE PROCESS OF ALLOCATION AND DEALLOCATION SPLITS THE FREE MEMORY INTO
* SMALL FRAGMENTS. A FRAGMENT THAT IS SMALLER THAN THE SIZE OF A MEM_REC HEAD
* CANNOT HOLD THE MEMREC HEAD NEEDED TO DESCRIBE THE FRAGMENT AS BEING FREE.
* CONSEQUENTLY, SMALL FRAGMENTS CAN ONLY BE ALLOWED IF THEY BELONG TO AN
* FIXED MEM_REC (THE HEAD IS IN FRONT OF THE FREE AREA).
* TOO SMALL FRAGMENTS ARE AVOIDED AS FOLLOWS:
* KERNEL PARTS AND USER PARTS ARE ALWAYS BIGGER THAN A MEM_REC HEAD.
* USER PARTS ARE ALWAYS LOCATED ON A PAGE BAUNDARY AND OCCUPIES AN INTEGRAL
* NUMBER OF PAGES.CONSEQUENTLY, A FRAGMENT HAVING A USER PART AS NEIGHBOUR
* MUST BE AT LEAST ONE PAGE LONG I.E. IT CAN HOLD A MEM_REC HEAD, BE THE FIRST
* BYTES OF THE FREE AREA OF A FIXED MEM_REC I.E A MEM_REC HEAD IS NOT NEEDED,
* OR THE FRAGMENT MUST BE THE FREE AREA BETWEEN KERNEL PARTS AND USER PARTS.
* IN THE LAST CASE AN EXPLICIT CHECK IS MADE TO INSURE THAT ROOM FOR A HEAD IS
* SET ASIDE. THE KERNEL PARTS ARE NOT LOCATED ON PAGE BAUNDARIES. WHEN PARTS
* ARE ALLOCATED IT IS CHEKED THAT THE NEW PART FITS EXACTLY INTO THE FREE PART
* ,LEAVING NO FRAGMENT, OR LEAVES A FRAGMENT THAT CAN HOLD A MEM_REC HEAD.
PAGE
SECTION.S 7 = KNEL_VAR
* VARIABLES OF MEMORY MANAGEMENT:
*
* LOCAL VARIABLES = VARIABLES HAVING A MEANING BETWEEN CALLS TO THE MM_PROCS:
F_ALLOC DS.L 1 CONTAINS THE ADDRESS OF THE FIRST MEM_REC
L_ALLOC DS.L 1 CONTAINS THE ADDRESS OF THE LAST MEM_REC
F_SUPVS DS.L 1 CONTAINS THE ADDRESS OF THE SUPERVISOR STACK (FIRST BYTE)
PAGE_TAB DS.L 1 CONTAINS THE ADDRESS OF THE PAGE TABLE (ADDR OF ENTRY ZERO)
SUPV_STK DS.L 1 CONTAINS THE "LAST + 1" ADDRESS OF THE SUPERVISOR STACK
MM_QUEUE DS.W CHAIN CHAIN OF PROCESSES WAITING TO CREATE/REMOVE AN OBJECT.
MM_LOCK DS.B 1 BIT_7=1 <=> ONE PROC CREATES/REMOVES AN OBJECT
DS.W 0 BIT_7=0 <=> NO PROC CREATES/REMOVES AN OBJECT
*
* CURKMOVE, CURUMOVE AND USERDEST: THESE VARIABLES
* ARE DESCRIBED LATER AS GLOBAL TEMP VARIABLES BUT ARE IN FACT LOCALS.
*
* KERNEL VARIABLES DEFINED WITHIN OTHER MODULES:
* PREFACE MODULE:
XREF.S 7:KV_FRMEM CONTAINS INITIALLY THE ADDRESS OF THE RAM AREA LIST; LATER
* THE NUMBER OF FREE BYTES FOR ALLOCATION OF OBJECTS
XREF.S 7:KV_BOTLD CONTAINS ADDR. OF THE FIRST BOOT LOADED MODULE (RAM-BOOT)
* OR THE VALUE -1 (ROM-BOOT)
XREF.S 7:KV_STUB CONTAINS THE ADDRESS OF A ROM-STUB OR -1 WHEN THE STUB
* IS THE FIRST MODULE OF THE RAM-BOOT.
XREF.S 7:TSTSTATU TEST OUTPUT FROM ALLOC/DEALLOC IS GENERATED WHEN BIT ZERO
* OF THIS VARIABLE EQUALS ONE
XREF PRINTA02 TEST PRINT PROCEDURE
*
* XREF.VAL TRP7STAK SUPERVISOR STACK SPACE (IN BYTES) NEEDED BY
* THE KERNEL OPERATIONS.
* XREF.VAL KV_STKSIZ INITIAL SIZE OF THE SUPERVISOR STACK
* SCHEDULER MODULE:
XREF.S 7:KV_INVEC INTERRUPT VECTOR (NORMALLY = 0), CONTAINS ADDRESSES OF THE
* INTERRUPT PROCEDURES. THE ADDRESSES ARE ADJUSTET WHEN THE
* SEGMENTS HOLDING THE PROCEDURES ARE MOVED.
XREF.S 7:DRIV_TAB DRIVER TABLE, CONTAINS ADDRESSES OF DRIVER ENVELOPES.
* THE ADDRESSES ARE ADJUSTET WHEN THE ENVELOPES ARE MOVED.
XREF.S 7:KV_CTX CURRENT CONTEXT,
*
XREF.S 7:KV_PROC CURRENT PROCESS
* KERNEL OPERATIONS MODULE:
* NONE SO FAR
* ENTER MODULE:
* NONE SO FAR
PAGE
* INITIAL POINTERS
KV_IOWNP DS.B PT_SIZ OWNS OBJECT THAT ARE NEVER DELETED
* XDEF KV_IOWNP ?? STUB OBJECT IS FIRST IN SET
KV_IMANP DS.B PT_SIZ MANAGES ENVELOPES THAT ARE NEVER DEMANAGED
* XDEF KV_IMANP ?? STUB ENVELOPE IS FIRST IN SET
DUMMYOWN DS.B PT_SIZ OWNS A KERNEL PART WHILE THE USER PART
* IS BEING ALLOCATED. (IS NOT INITIALIZED)
* INITIAL OBJECTS
ALLOCSIZ EQU SE_SIZ+SP_SIZ
ALLOCOBJ DS.B ALLOCSIZ
* ALLOCOBJ HOLDS THE KERNEL PART OF THE KERNEL DEFINED ALLOC OBJECT.
* DURING MM_INITIALIZATION THE KERNEL PART IS USED AS THE KERNEL PART
* OF A NON_EMBEDDED SEGMENT DESCRIBING THE BOOT LOADED MODULES.
NEMB_SIZ EQU SE_SIZ+SP_SIZ SIZE OF NON.EMB.SEGM.OBJ.
FULSPACE DS.B NEMB_SIZ
* FULSPACE IS A SEGMENT OBJECT DESCRIBING THE WHOLE ADDRESS SPACE OF
* THE MC68000. SUBSEGMENTS OF FULSPACE IS USED BY DRIVER OBJECTS.
* THE STUB OBJECT GETS A REFERENCE TO FULSPACE.
XDEF ALLOCOBJ,F_ALLOC,L_ALLOC,F_SUPVS,SUPV_STK,GETSTUBE,GETSTUBO
XDEF INITGEIN,INITKNEL,INIT_ENV,MAKESEGM,SIMPLEPT,MM_CRE
XDEF MM_LOCK,MM_QUEUE,I_MMPROC,CHAINOWN
PAGE
* "ALLOCATION PROCEDURES"
*
* NON EMBEDDED OBJECTS ARE ALLOCATED/DEALLOCATED BY CALLS TO MM_PROCS.
* THE FUNCTIONS ARE INVOKED FROM KERNEL OPERATIONS.
XDEF ALLOC_OB ENTRY POINT FOR OBJCALL TO THE ALLO(CATE) OBJECT.
XDEF MM_TERM LAST TERMINATION PROCEDURE FOR ALL NON EMB. OBJECTS.
*
* "SUB_ALLOCATION PROCEDURES"
*
* THE KERNEL PART AND USER PART OF AN OBJECT ARE USED BY
* THE KERNEL (OPERATIONS) TO HOLD THE FOLLOWING ENTITIES:
* KERNEL PART:
* 1) OBJECT-TYPE RELATED INFORMATION (GA, CO, SE, SU, GE, ...)
* 2) ENVELOPE DESCRIPTIONS
* 3) CONTEXT DESCRIPTIONS
* 4) DESCRIPTORS FOR EMBEDDED SEGM/SUBSEGM.
* USER PART:
* 5) SEGMENT DATA OF EMBEDDED AND NON EMBEDDED SEGMENT OBJECTS
*
* ALLOCATION/DEALLOCATION IS DONE BY CALLS TO THE FOLLOWING MM_PROCS
XDEF MM_PUSHK ALLOCATES AN ENVELOPE OR CONTEXT DESCRIPTION
XDEF MM_POPK DEALLOCATES
XDEF MM_PUSHU ALLOCATES A DATA SEGMENT
XDEF MM_POPU DEALLOCATES
XDEF MM_PUSHD ALLOCATES AN EMBEDDED DESCRIPTOR
XDEF MM_POPD DEALLOCATES
XDEF MM_PUSHO ALLOCATES SPACE FOR OBJECT-TYPE RELATED INFORMATION
XDEF MM_POPO DEALLOCATES
*
* ALLOCATION/DEALLOCATION
* MUST BE SYNCHRONIZED WITH THE MEMORY COMPACTION PROCEDURES
* (MOVEKNEL, MOVEUSER).
*
* THE GLOBAL VARIABLES SHARED BETWEEN THE COMPACTION PROCEDURES AND
* THE "SUB ALLOCATION" ARE CURKMOVE, CURUMOVE AND USERDEST (SEE BELOW).
PAGE
* GLOBAL TEMP VARIABLES = VARIABLES USED DURING CALLS TO MM_PROCS.
CURKMOVE DS.L 1 CURRENT KERNEL MOVE CANDIDATE
CURUMOVE EQU CURKMOVE CURRENT USER MOVE CANDIDATE
* HOLDS THE ADDRESS OF THE NEXT ITEM (ENVELOPE, CONTEXT, SEGMENT) TO BE
* MOVED BY MM_PROCS. THE ITEM WILL BE MOVED WHEN MM_PROC REENTERS
* THE "SUB_MM" MONITOR
*
* THE ITEM MAY BE DESTROYED BY A CALL TO AN "MM_POP" -PROCEDURE.
* IN THIS CASE, THE "MM_POP" -PROCEDURE WILL UPDATE THE VARIABLE
CURKHEAD DS.L 1
CUR_HEAD EQU CURKHEAD
* HOLDS THE ADDRESS OF THE HEAD OF A CONTEXT CHAIN OR OF AN ENVELOPE CHAIN.
CUROBOB DS.L 1
* HOLDS THE ADDRESS OF AN OBJECT
CURDIST DS.L 1
* HOLDS THE DISTANCE THAT ITEMS SHOULD BE MOVED.
CUR_STAK DS.L 1
* HOLDS THE ADDRESS OF A CONTEXT OR ENVELOPE
CUR_EMBS DS.L 1
* HOLDS THE ADDRESS OF AN EMBEDDED SEGMENT OBJECT
USERDEST DS.L 1
* HOLDS THE FUTURE ADDRESS OF A USER PART BEING MOVED
* IF THE CURRENT USER MOVE CANDIDATE IS DESTROYED, THE MOVE
* IS ACTUALLY FINISHED, AND FUTURE ALLOCATION OF USER SEGMENTS
* SHOULD BE ALLOCATED ACCORDING TO THE NEW POSITION OF THE
* USER PART. THIS IS ENSURED BY MM_POPU, BY MOVING
* USERDEST TO SP_FIRU OF THE SPACE DESCRIPTION, IN CASE
* CURUMOVE IS POPPED.
SAVENEED DS.L 1 HOLDS THE >>BYTES NEEDED<< DURING ALLOC.NEW_OBJ
SAVE_RPA DS.L 1 HOLDS THE POINTER ARGUMENT DURING ALLOC.NEW_OBJ
*
* SAVEAREAS FOR REGISTERS ( PROCSAVE MACRO ==>> 7-CHAR NAMES )
*
KSAVPRT DS.L 15 USED BY C_UPARTS AND C_KPARTS
USAVPRT EQU KSAVPRT
KSAVCRS DS.L 15 USED BY M_UACROS AND M_KACROS
USAVCRS EQU KSAVCRS
KSAVMOV DS.L 15 USED BY MOVEUSER AND MOVEKNEL
USAVMOV EQU KSAVMOV
SAV_CHK DS.L 2 USED BY CHECK_TIR
PAGE
* INSTALLATION MODULE FORMAT.
* THE STUB IS NORMALLY THE FIRST INSTALATION MODULE.
OFFSET 0 HEADER FIELDS
MOD_HSIZ DS.W 1 THE SIZE OF THE MODULE HEADER SEGMENT
MOD_SIZE DS.L 1 THE SIZE OF THE WHOLE MODULE. 1)
MOD_KIND DS.W 1 MODULE KIND, SHOULD BE ZERO: PROGRAM MODULE
MOD_PROG DS.W 1 THE ADDRESS OF THE PROGRAM DESCRIPTION. 2)
OFFSET 0 PROGRAM OBJECT DESCRIPTION FIELDS
MOD_FDSD DS.W 1 ADDRESS OF FIRST DATA SEGMENT DESCRIPTION. 3)
MOD_LOCS DS.W 1 NO OF LOCAL POINTERS IN OBJECT
MOD_TEMP DS.W 1 NO OF TEMP POINTERS IN CONTEXTS
MOD_TEMD DS.L 1 NO OF TEMP BYTES IN CONTEXTS
MOD_STK DS.W SZ_TYP CALL STACK REQUIREMENT = SIZE OF BOOT PROC
MOD_ENT DS.L 1 ENTRY ADDRESS TO PROGRAM
MOD_NUL1 DS.W 1 UNUSED FIELD
MOD_LDSS DS.W 1 NUMBER OF LOCAL DATA SEGMENT DESCRIPTIONS
OFFSET 0 LOCAL DATA SEGMENT DESCRIPTION FIELDS
MOD_DSIZ DS.W 1 SIZE OF DESCRIPTION
MOD_NUL2 DS.B 24 THESE FIELDS ARE NOT USED
MOD_LSDS DS.W 1 NO OF LOAD SECTION DESCRIPTIONS
MOD_LDSZ DS.W 0 SIZE OF FIXED PART OF DATA SEGMENT DESCRIPTION
OFFSET 0 LOAD SECTION DESCRIPTION FIELDS
MOD_NUL3 DS.B 4 THESE FIELDS ARE NOT USED
MOD_SLEN DS.L 1 THE LENGTH OF THE LOAD SECTION SEGMENT
MOD_NUL4 DS.B 4 THESE FIELDS ARE NOT USED
MOD_LSDZ DS.W 0 SIZE OF ONE LOAD SECTION DESCRIPTION
* 1) 0 MEANS DUMMY TOP MODULE.
* 2) REL TO MOD_HSIZ
* 3) REL TO MOD_FDSD
PAGE
* NEWHEAD MACRO
* THE NEWHEAD MACRO CREATES A HEAD FOR A NEW MEM_REC AND
* AJUSTS THE CHAINS TO THE NEXT AND PRIOR MEM_RECS.
* NEWHEAD NEW_HEAD,FIX+TYPE,PRIOR,NEXT
NEWHEAD MACRO
MOVE.L Ø1,MR_FST(Ø1) NEW_HEAD.FIRST_FREE:=NEW_HEAD;
MOVE.W Ø2,MR_FIX(Ø1) NEW_HEAD.RECORD_TYPE:=TYPE;"FIXED+TYPE"
MOVE.L Ø3,MR_PRV(Ø1) NEW_HEAD.PRIOR_REC:=PRIOR;
MOVE.L Ø4,MR_NXT(Ø1) NEW_HEAD.NEXT_REC:=NEXT;
MOVE.L Ø1,MR_NXT(Ø3) PRIOR.NEXT_REC:=NEW_HEAD;
MOVE.L Ø1,MR_PRV(Ø4) NEXT.PRIOR_REC:=NEW_HEAD;
ENDM
* OBS FREE_BYTES ARE NOT ASSIGNED. THE FIELDS ARE OFTEN REASSIGNED BY CALLER.
*
*-----------------
* PROCSAVE MACRO
* SAVES REGISTERS IN A GLOBAL AREA
*
* PROCSAVE <REGLIST>,<SAVEAREA>
*
PROCSAVE MACRO
.Ø2 REG Ø1
MOVEM.L .Ø2,Ø2
ENDM
*
*------------------
* PROCRTRN MACRO
* RESTORE REGISTERS FROM A GLOBAL AREA
*
PROCRTRN MACRO
MOVEM.L Ø1,.Ø1
RTS
ENDM
*
PAGE
* MOVLM MACRO
*
* AJUST PRIOR AND NEXT, AND MOVE CHAIN ELEMENT
*
* CALL: MOVLM AS, AD AS=SOURCE ADDRESS REGISTER
* AD=DESTINATION ADDRESS REGISTER (=NEW
* POSITION)
* EXAMPLE: MOVLM A1,A0
*
* FUNCTION: REFERENCES TO THE ELEMENT TO BE MOVED ARE CHANGED TO REFLECT
* THE NEW POSITION OF THE ELEMENT
* THE ELEMENT IS MOVED
* AS AND AD IS INCREASED BY SIZE OF ELEMENT (=8)
* NOTE: A5 AND A6 ARE USED AS WORKING ADDRESS REGISTERS
*
MOVLM MACRO
MOVEM.L (Ø1),A5/A6 (A5,A6):=(NEXT,PRIOR) ELEMENT;
MOVE.L Ø2,4(A5) NEXT.PRIOR:=NEW POSITION;
MOVE.L Ø2,(A6) PRIOR.NEXT:=NEW POSITION;
MOVE.L (Ø1)+,(Ø2)+ MOVE CHAIN ELEMENT
MOVE.L (Ø1)+,(Ø2)+ AND UPDATE ADDRESS REGISTERS;
ENDM
*
* 104 CYKLES ARE USED TO EXECUTE THE INSTRUCTIONS ABOVE
PAGE
* MOVHD MACRO
* AJUST PRIOR AND NEXT AND ALL REFS IN CHAIN, AND MOVE CHAIN HEAD
*
* CALL: MOVHD AS,AD,NR AS=SOURCE ADDRESS REGISTER
* AD=DESTINATION ADDRESS REGISTER
* (=NEW POSITION)
* NR=NEW REFERENCE REGISTER
* EXAMPLE: MOVHD A1,A0,A2
*
* FUNCTION: ALL REFS IN ELEMENTS IN CHAIN ARE SET TO NR
* REFERENCES TO THE CHAIN HEAD ARE CHANGED TO REFLECT
* THE NEW POSITION OF THE CHAIN HEAD
* THE ELEMENT IS MOVED
* AS AND AD IS INCREASED BY SIZE OF HEAD (=8)
* NOTE: A5 AND A6 ARE USED AS WORKING ADDRESS REGISTERS
*
MOVHD MACRO
MOVEM.L (Ø1),A5/A6 (A5,A6):=(NEXT,PRIOR) ELEMENT,
MOVE.L Ø2,4(A5) NEXT.PRIOR:=NEW POSITION;
MOVE.L Ø2,(A6) PRIOR.NEXT:=NEW POSITION;
MOVE.L (Ø1),A5 A5:=CUR:=NEXT;"MAY HAVE CHANGED"
WHILE.L A5 <NE> Ø2 DO.S WHILE CUR <> NEW POSITION DO
MOVE.L Ø3,CH_HOLD(A5) CUR.REF:=NEW REFERENCE;
PRT_MEM MOVHD_NEWREF,(A5),PT_SIZ ********
MOVE.L (A5),A5 CUR:=CUR.NEXT
ENDW ENDW
MOVE.L (Ø1)+,(Ø2)+ MOVE CHAIN HEAD
MOVE.L (Ø1)+,(Ø2)+ AND UPDATE ADDRESS REGISTERS
ENDM ENDW
*
*
*
* TEST THAT A VALUE IS A MULTIPLUM OF 256
* GENERATE AN ADDRESS EXCEPTION IF IT IS NOT THE CASE
* THE TEST IS USED IN THE INITIALIZATION.
*---------------------------------------------------------------------
TSTPAGE MACRO
TST.B Ø1 Ø1 MUST BE A DREG
IF <NE> THEN.S IF LAST BYTE IS NOT ZERO THEN
ERROR Ø2 ERROR(Ø2);
ENDI ENDI;
ENDM
PAGE
SECTION 11 = INITIALIZE
* THE MM_PROC INITIALIZATION GETS CONTROL RIGHT AFTER THE PREFACE
*
* THE FOLLOWING STEPS ARE CARRIED OUT:
*
* 1) ALLOCATE PAGETABLE
*
* 2) SET UP INITIAL MEM_REC STRUCTURE
*
* 3) BOOT LOADED MODULES (IN RAM) ARE DESCRIBED AS ONE SEGMENT OBJECT
*
* 4) CREATE THE FULSPACE SEGMENT OBJECT AND INITIAL POINTERS.
*
* 5) ALLOCATE AND INITIALIZE THE STUB OBJECT, EXCEPT LOCAL POINTERS.
*
* 6) CREATE THE BOOT OWNER SET, DESCRIBING THE BOOT LOADED MODULES,
* IN LOCAL-2 OF THE STUB OBJECT.
*
* 7) INITIALIZE LOCAL-1: REF TO THE CODE OF THE STUB
* LOCAL-6: REF TO THE FULSPACE SEGMENT OBJECT
*
* 8) CREATE THE ALLOC OBJECT.
*
*
* XREF.VAL SCHTEMP,SCHTEMD CONSTANTS OF SCHED
XREF 11:I_SCHED INIT OF SCHEDULER
* BELOW FOLLOWS PROCEDURES USED BY THE INITIALIZATION.
* SOME PROCEDURES IN SECTION 9 OF MMPROCS SHOULD BE MOVED TO SECTION 11
MMBUSERR EQU * BUS_ERROR_EXCEPTION:
*
* BUS_ERROR_EXCEPTION MAY BE GENERATED BY ILLEGAL ADDRESS
* SPECIFICATIONS IN THE RAM AREA LIST.
*
*
ERROR 0 ERROR(0);
*
PAGE
GET_STMD EQU * RETURN THE STUB MODULE ADDRESS IN A5
MOVE.L KV_STUB,A5 A5:=STUB ADDRESS;
IF.L A5 <EQ> #-1 THEN.S IF STUB_ADDRESS=-1 THEN "STUB IN RAM"
GET_LDMD EQU * RETURN ADDRESS OF BOOT LOADED MODULES IN A5
LEA ALLOCOBJ,A5 A5:=FIRST_OF_BOOT :=
MOVE.L SE_FIR(A5),A5 ALLOC.FIRST_BYTE_OF_SEGMDATA;
ENDI ENDI;
RTS RETURN;
*
*
GETSTUBE EQU * GET ADDRESS OF THE STUB ENVELOPE INTO A3
MOVE.L KV_IMANP,A3 A3:=STUB_ENVELOPE:=KV_IMANP.FIRST;
RTS RETURN;
*
*
GETSTUBO EQU * GET ADDRESS OF THE STUB OBJECT INTO A0
MOVE.L KV_IOWNP,A0 A0:=STUB_OBJECT:=KV_IOWNP.FIRST;
RTS
MAKESEGM EQU * MAKE A NON EMBEDDED SEGMENT OBJECT
* CALL RETURN
* D1 LENGTH OF USER PART SAME
* A0 ADDRESS OF KERNEL PART SAME
* A1 ADDRESS OF USER PART SAME
*
PRT_REG MAKESEGM_D1/A0/A1 ********
ENTRYSAV D0/A0-A1,.MAKESEG SAVE REGS
MOVE.L D1,D0 D0:=TOP ADDRESS OF USER PART :=
ADD.L A1,D0 LENGTH+FIRST OF USER PART;
EXG.L A0,A1 A0:=USER PART, A1:=OBJECT:=KNELPART;
IF.L D0 <LT> L_ALLOC THEN.S IF TOP_ADDRESS INSIDE PAGETABLE THEN
IF.L D0 <GT> F_ALLOC THEN.S
BSR.L PGTABSET PAGETABLE (D0=TOP_ADDRESS):=KNEL_PART=A1;
ENDI ENDI;
ENDI ENDI;
MOVE.B #OB_SEOB,OB_KIN(A1) OBJECT.KIND:=SEGMENT OBJECT;
MOVE.B #OB_SEGM,OB_STA(A1) OBJECT.STATE:=SEGMENT;
CLR.W SE_IO(A1) OBJECT.IO_COUNT:=0;
MOVE.L A0,SE_FIR(A1) OBJECT.FIRST SEGMENT:=USER PART;
MOVE.L D1,SE_LEN(A1) OBJECT.LENGTH SEGMENT:=USER BYTES;
LEA SE_WAIT(A1),A1 A1:= SEGM.SE_WAIT; "CHAIN HEAD"
MOVE.L A1,(A1) SE_WAIT:=
MOVE.L A1,4(A1) EMPTY;
MOVE.L OB_SPA-SE_WAIT(A1),A1 A1:=SP_DESC:=OBJECT.SPACE_DESCR;
MOVE.L A0,SP_FIRU(A1) SP_DESCR.FIRST_FREE_USER:=USER PART;
CLR.L SP_FREU(A1) SP_DESC.FREE_USER_BYTES:=0;
MOVE.L D1,SP_SIZU(A1) SP_DESC.SIZE_OF_USER_PART:=USER BYTES;
ADDI.L #(SE_SIZ-OB_SIZ),SP_FIRK(A1) SP_DESC.FIRST_FREE_KNEL:=...
SUBI.W #(SE_SIZ-OB_SIZ),SP_FREK(A1) SP_DESC.FREE_KNEL_BYTES:=...
MOVEM.L (A7)+,.MAKESEG RESTORE REGS BEFORE PRT_MEM
PRT_MEM MAKESEGM,(A0),ALLOCSIZ ********
RTS RETURN;
PAGE
I_MMPROC EQU * START OF INITIALIZATION:
XDEF I_MMPROC GETS CONTROL AFTER INIT OF THE PREFACE
LEA MMBUSERR,A0 A0:=BUSERROR EXECPTION HANDLER
MOVE.L A0,12 ADDRESS EXCEPTION :=
MOVE.L A0,8 BUSEXCEPTION:=BUSERROR EXCEPTION HANDLER
* THE BUSERROR EXCEPTION HANDLER GETS CONTROL IF A NON EXISTING ADDRESS
* OR UNEVEN ADDRESS IS REFERENCED BY THE MM_PROC INITIALIZATION PHASE.
*
* FORMAT THE LAST PART OF THE LAST RAM AREA.
* COMPUTE THE ADDRESS OF: PAGE_TAB, L_ALLOC, F_ALLOC, F_SUPVS, SUPVSTK
*
MOVE.L KV_FRMEM,A0 A0:=RAM AREA LIST;
MOVE.W (A0)+,D0 D0:=NO_OF_RAM_AREAS;
SUBQ.W #1,D0 D0:=INDEX TO LAST ADDRESS PAIR
ASL.W #3,D0 :=(NO_OF_RAM_AREAS-1) *8;
MOVE.L 4(A0,D0.W),A1 A1:=TOP_LAST_RAM;
MOVE.L A1,D1 D1:=ALLOC_SPACE:=TOP_LAST_RAM
SUB.L (A0),D1 -FIRST_FIRST_RAM;
IF <LT> THEN.S IF ALLOC_SPACE <=0 THEN
ERROR 3 ERROR(3);
ENDI ENDI
* THE PAGETABLE NEED NOT DESCRIBE THE MEMORY HOLDING THE PAGETABLE.
* THE TABLE CONTAINS 4 BYTES FOR EACH PAGE OF 256 BYTES, CONSEQUENTLY:
* TABSIZE *64+TABSIZE=ALLOC_SPACE<=>TABSIZE=ALLOC_SPACE DIV 65;
* DIVIDE ALLOC_SPACE (D1) WITH 65;
* TABSIZE MAY BE LARGER THEN 1<<16, HENCE SIMPLE DIVISION IS INSUFFICIENT.
*
CLR.L D2 D2:=TABSIZE:=0;
MOVEQ.L #65,D3 D3:=65
MOVE.L #65000,D4 D4:=65000
MOVE.L #4225000,D5 D5:=65x65000
WHILE.L D1 <GT> D5 DO.S WHILE ALLOC_SPACE > 65x65000 DO
SUB.L D5,D1 ALLOC_SPACE:=...-65x65000;
ADD.L D4,D2 TABSIZE:=TABSIZE+65000;
ENDW ENDW
PAGE
DIVU D3,D1 D1:=DIVRES:=ALLOC_SPACE DIV 65
CLR.L D3 D3:=
MOVE.W D1,D3 EXTEND DIVRES TO LONG
ADD.L D3,D2 TABSIZE:=...+DIVRES;
ADDQ.L #7,D2 ROUND UP TABSIZE
BCLR.L #0,D2 TABSIZE MUST BE EVEN.
SUBA.L D2,A1 A1:=FIRST_ENTRY:=TOP_LAST_RAM-TABSIZE;
MOVE.L A1,D1 D1:=LAST_MEM_REC
SUBI.L #MR_SIZ,D1 :=FIRST_ENTRY-SIZE OF MEM_REC HEAD;
CLR.B D1 ROUNDED TO A PAGE BOUNDARY;
MOVE.L D1,L_ALLOC L_ALLOC:=LAST_MEM_REC;
MOVE.L D1,SUPV_STK TOP BYTE OF SUPV.STACK:=L_ALLOC
* SET UP THE SUPERVISOR STACK, SUBROUTINES MAY NOW BE CALLED.
MOVE.L D1,A7 A7:=STACK:=SUPV_STK;
SUB.L #KV_STKSIZ,D1 D1:=F_SUPVS:=SUPV_STK-STK_SIZE
CLR.B D1 ROUNDED TO APAGE BOUNDARY;
MOVE.L D1,F_SUPVS F_SUPVS:=D1;
* THE VARIABLE CALLED PAGE_TAB SHOULD CONTAIN THE ADDRESS OF "ENTRY ZERO" OF
* THE PAGE TABLE AND NOT "ENTRY FIRST" (=A1).
MOVE.L (A0),D1 D1:=FIRST_FIRST_RAM;
LSR.L #8,D1 D1:=FANTOM_TABSIZE:=
LSL.L #2,D1 FIRST_FIRST_RAM DIV 256*4;
SUB.L D1,A1 A1:=PAGE_TAB:=ENTRY ZERO
MOVE.L A1,PAGE_TAB :=ENTRY FIRST-FANTOM_TABSIZE;
MOVE.L (A0),F_ALLOC F_ALLOC:=FIRST_FIRSTRAM;
PRT_MEM F_ALLOC_ETC.,F_ALLOC,MM_QUEUE-F_ALLOC ********
PAGE
* SET UP THE INITIAL MEM_RECS.
* D0=INDEX TO LAST PAIR OF ADDRESS; A0=ADDRESS OF FIRST PAIR
CLR.W D1 D1:=NEXT_PAIR:=FIRST_PAIR:=0;
MOVE.L (A0),A1 A1:=CUR_MEM_REC:=FIRST_FIRST_RAM;
MOVE.L A1,D2 D2:=FIRST_FREE:=FIRST_FIRST_RAM
ADDI.L #MR_SIZ,D2 +SIZE OF MEM_REC HEAD;
MOVE.L D2,A4 A4:=PRIOR_MEM_REC:=FIRST_FREE; "BAD TRICK"
REPEAT REPEAT "ONE MEM_REC FOR EACH PAIR"
IF.W D1 <NE> D0 THEN.S IF CUR_PAIR <> LAST_PAIR THEN
MOVE.L 4(A0,D1.W),D3 D3:=TOP_FREE:=TOP_RAM(NEXT_PAIR)
SUBI.L #MR_SIZ,D3 -SIZE OF MEM_REC HEAD
CLR.B D3 ROUNDED TO A PAGE BOUNDARY;
MOVE.L D3,A2 A2:=NEXT_MEM_REC:=TOP_FREE;
ADDQ.L #8,D1 D1:=NEXT PAIR;
ELSE.S ELSE
MOVEQ.L #-1,D0 D0:=STOP;
MOVE.L L_ALLOC,A2 A2:=NEXT_MEM_REC:=LAST_MEM_REC;
MOVE.L F_SUPVS,D3 D3:=TOP_FREE:=F_SUPVS;
ENDI ENDI
* A1=CUR_MEM_REC,A2=NEXT_MEM_REC,A4=PRIOR_MEM_REC
* D2=FIRST_FREE,D1=NEXT_PAIR (OR LAST PAIR),D3=TOP_FREE
PRT_REG INITIAL_MEMREC_D0/D1/D2/D3/A1/A2/A4 ********
IF.L A1 <GE> D3 THEN.S IF CUR > = NEXT THEN
ERROR 4 ERROR (4)
ENDI ENDI;
NEWHEAD A1,#256,A4,A2 CREATE INITIAL MEM_REC HEAD
SUB.L D2,D3 D3:=FREE_BYTES:=TOP_FREE-FIRST_FREE
MOVE.L D2,MR_FST(A1) ASSIGN FIRST_FREE TO MEM_REC;
MOVE.L D3,MR_FRE(A1) ASSIGN FREE_BYTES TO MEM_REC;
PRT_MEM NEW_HEAD,(A1),MR_SIZ ********
MOVE.L A1,A4 A4:=PRIOR_MEM_REC:=CUR_MEM_REC
MOVE.L A2,A1 A2:=CUR_MEM_REC:=NEXT_MEM_REC
MOVE.L (A0,D1.W),D2 D2:=FIRST_FREE:=FIRST_RAM (NEXT_PAIR);
TST.W D0 TEST FOR STOP;
UNTIL <LT> UNTIL STOP;
* A1=LAST_MEM_REC,A4:=MEM_REC HOLDING SUPERVISOR STACK
* ADJUST THESE MEM_REC.
MOVE.L A4,MR_PRV(A1) LAST_MEM_REC.PREV:=PRIOR MEM_REC;
* ASSIGN USER_TYPE TO
MOVE.B #-1,MR_TYP(A4) THE MEM_REC HOLDING THE SUPERVISOR STACK;
* ASSIGN KNOWN BUT ILLEGAL ADDRESSES TO UNDEFINED CHAINFIELDS.
MOVE.L #$4711,MR_NXT(A1) NEXT TO LAST:=ODD ADDRESS;
MOVE.W #256,MR_FIX(A1) L_ALLOC.FIX:=INITIAL;
CLR.L MR_FRE(A1) L_ALLOC.FREE_BYTES:=0;
PRT_MEM LAST_HEAD,(A1),MR_SIZ ********
MOVE.L F_ALLOC,A1
MOVE.L #$7913,MR_PRV(A1) PRIOR TO FIRST:=UNEVEN ADDRESS;
PRT_MEM FIRST_HEAD,(A1),MR_SIZ ********
PAGE
* CREATE ONE SEGMENT OBJECT THAT HAS THE BOOT LOADED MODULES
* AS SEGMENT DATA. THIS WILL PROTECT THE MODULES DURING THE INITIALIZATION;
* THE ALLOCOBJ IS USED AS THE KERNEL PART OF THIS SEGMENT OBJECT.
IF.L KV_BOTLD <NE> #-1 THEN.S IF MODULES HAVE BEEN BOOT LOADED THEN
* FIND THE MEM_REC THAT HOLDS THE BOOT LOADED MODULES. THIS MEM_REC IS
* CALLED "HOLDER". THE MODULES MUST BE PRESENT IN ONE OF THE MEM_RECS.
* THE MODULES HAVE BEEN DAMAGED BY THE PREVIOUS INITIALIZATION IF
* THEY WERE LOCATED TOO NEAR TO THE END (OR BEGINNING) OF THE
* RAM AREA THAT HOLDS THE MODULES.
*
MOVE.L F_ALLOC,A1 A1:=CUR_MEM_REC:=FIRST_MEM_REC
MOVE.L KV_BOTLD,A3 A3:=BOOT LOADED MODULES;
REPEAT REPEAT
MOVE.L A1,A0 A0:=HOLDER:=CUR_MEM_REC;
MOVE.L (A1),A1 A1:=CUR_MEM_REC:=NEXT_MEM_REC
UNTIL.L A1 <GT> A3 UNTIL CUR_MEM_REC > BOOT LOADED MODULES;
* A0 = HOLDER; FIND LENGTH OF BOOT LOADED MODULES
* A3=FIRST_MODULE
MOVE.L A3,A1 A1:=FIRST MODULE;
REPEAT REPEAT
MOVE.L MOD_SIZE(A3),D1 D1:=LENGTH OF NEXT MODULE
ADDA.L D1,A3 A3:=NEXT_MODULE:=...+LENGTH;
TST.L D1
UNTIL <EQ> UNTIL LENGTH=0;
LEA 256(A3),A3 A3:=A3+256;"INCLUDE THE "ZERO" MODULE"
* A0=HOLDER,A1=FIRST_FIRST_MODULE,A3=TOP_LAST_MODULE,
* RESTRUCTURE THE MEM_REC IN A0; CREATE MEM_REC AT A3;
*
PRT_REG BOOT_MODULE_A0/A1/A3 ********
MOVE.L A3,D1 D1:=TOP_LAST_MODULES;
TST.B D1 TEST TOP_LAST_ADDRESS;
IF <NE> THEN.S IF ADDRESS <> PAGE START THEN
ERROR 1 STOP WITH ERROR=1
ENDI ENDI;
SUB.L A1,D1 D1:=SIZE OF BOOT:=TOP_LAST-FIRST_FIRST;
TST.B D1 TEST FIRST_FIRST_ADDRESS;
IF <NE> THEN.S IF ADDRESS <> PAGE START THEN
ERROR 2 STOP WITH ERROR=2
ENDI ENDI
MOVE.W #$FF,D7 D7:=USER PART:=FF
IF.L D1 <GT> #256 THEN.S IF REAL BOOT MODULES PRESENT THEN
BSR.L RECHAINC RECHAINC(A0=MEM_REC,A1=NEW_PART,
* D1=SIZE OF PART, D7=TYPE);
ENDI ENDI;
ELSE.S ELSE "NO BOOT LOADED MODULES"
CLR.L D1 D1:=SIZE:=NO_MODULE:=0;
ENDI ENDI;
MOVE.L #ALLOCSIZ,D0 D0:=SIZE OF KNELPART OF ALLOC
LEA ALLOCOBJ,A0 A0:=ADDRESS OF KNELPART OF ALLOC
BSR.L INITKNEL INITKNEL (A0=ALLOC,D0=SIZE_OF_ALLOC);
IF.L D1 <GT> #256 THEN.S IF BOOT LOADED MODULES THEN
BSR.L MAKESEGM MAKESEGM(A0=ALLOC,A1=BOOTMODULES,D1=SIZE)
ENDI ENDI;
PAGE
* CREATE FULSPACE OBJECT
LEA FULSPACE,A0 A0:=FULSPACE OBJECT
MOVE.W #NEMB_SIZ,D0 D0:=LENGTH OF KERNEL PART
BSR.L INITKNEL INITIALIZE_KERNEL_PART_OF_OBJECT(A0,D0);
MOVE.W #0,A1 A1:=SEGMENT ADDRESS:=0;
MOVE.L #$1000000,D1 D1:=SEGMENT LENGTH:=TOP OF ADDRESS SPACE
BSR.L MAKESEGM MAKE_SEGMENT OBJECT(A0=FULSPACE,A1=SEGMENT
* START D1:=LENGTH);
* INITIAL POINTER INIT
LEA KV_IOWNP,A0 A0:=INITIAL OWNER POINTER;
MOVE.L A0,(A0) OWNER_SET:=EMPTY;
MOVE.L A0,4(A0)
CLR.B PT_INF(A0) SCOPE:= INITIAL; ???
LEA KV_IMANP,A0 A0:=INITIAL MANAGER POINTER;
MOVE.L A0,(A0) MANAGER:= EMPTY;
MOVE.L A0,4(A0)
CLR.B PT_INF(A0) SCOPE:= INITIAL; ???
* VARIOUS GLOBAL VARIABLES
CLR.B MM_LOCK MM_LOCK := OPEN;
LEA MM_QUEUE,A0 MM_QUEUE := EMPTY;
MOVE.L A0,(A0)
MOVE.L A0,4(A0)
CLR.L CURKMOVE CLEAR MOVE CANDIDATE
PRT_MEM MM_QUEUE_ETC.,MM_QUEUE,ALLOCOBJ-MM_QUEUE ********
*
PAGE
* ALLOCATE STUB OBJECT
* THE STUB MODULE CAN BE FOUND IN KV_STUB (STUB IN ROM),
* OR (WHEN KV_STUB=-1) IN ALLOCOBJ.SE_FIR (STUB IN RAM).
BSR.L GET_STMD GET_STUB_MODULE (A5:=STUB_MODULE);
* COMPUTE THE SIZE OF THE STUB OBJECT IN D0
ADDA.W MOD_PROG(A5),A5 A5:=PROGRAM DESCRIPTION IN STUB MODULE
MOVE.W MOD_LOCS(A5),D1 D1:=NO_OF_LOCALS
IF.W D1 <LT> #10 THEN.S IF NO_OF_LOCALS < 10 THEN
ERROR 8 ERROR(8);
ENDI ENDI;
MOVEQ.L #PT_SIZ,D0 D0:=SIZE OF KERNEL PART:=POINTER_SIZE
MULU.W D1,D0 *NO_OF_LOCALS +
ADDI.L #(SP_SIZ+GE_SIZ+EN_SIZ),D0 SPACE FOR GENERAL OBJECT;
CLR.L D1 D1:=SIZE OF USER PART:=0;
BSR.L MM_CRE CREATE_OBJECT(D0=KERNEL_BYTES,D1=USER_BYTE
* A0:=KERNEL_PART,A1:=USER_PART);
IF <EQ> THEN.S IF NO_ROOM THEN
ERROR 5 ERROR(5)
ENDI ENDI;
* INITIAL OWNER POINTER HOLDS THE STUB AS THE FIRST MEMBER.
LEA KV_IOWNP,A3 (A3,D3.W):=INITIAL OWNER POINTER
CLR.W D3
BSR.L CHAINOWN CHAINOWN(A0=STUB OBJECT,(A3,D3.W)=INITIAL
* OWNER, A2:=INITIAL OWNER POINTER);
* CREATE PRIMARY ENVELOPE, A0=STUB,D0=KERNEL PART SIZE;
SUBI.W #SP_SIZ+GE_SIZ,D0 D0:=SIZE OF ENVELOPE ELEMENT;
BSR.L MM_PUSHK PUSH_ENV(A0=KNELPART,D0=SIZE,
* A3:=ENV,A6:=SPACEDESC);
BSR.L INIT_ENV INITIALIZE_ENV(D0=SIZE,A3=ENVELOPE,
* A6=SPACE DESCR);
* INITIAL MANAGER POINTER HOLDS THE STUB ENVELOPE AS FIRST MEMBER.
MOVE.L A3,A0 A0:=ENVELOPE
LEA KV_IMANP,A3 A3:=INITIAL MANAGER POINTER, D3=0;
BSR.L CHAINMAN CHAINMAN(A0=ENVELOPE,(A3,D3.W)=
* INITIAL MANAGER,
* A2:=INITIAL MANAGER POINTER);
PAGE
* INITIALIZE GENERAL PART OF STUB OBJECT
*
BSR.L GETSTUBO A0:=KERNEL PART OF STUB OBJECT;
BSR.L GET_STMD A5:=STUB MODULE ADDRESS;
ADDA.W MOD_PROG(A5),A5 A5:=PROGRAM DESCR.OF STUB MODULE;
MOVE.L MOD_ENT(A5),A1 A1:=ENTRY POINT OF STUB PROGRAM;
BSR.L INITGEIN INITGEIN (A0=KNELPART,A1:=ENTRY POINT);
* MODIFY STUB OBJECT ACCORDING TO THE DESCRIPTION.
MOVE.W MOD_TEMP(A5),GE_TEMP(A0) STUB.TEMPPOINTERS:=MODULE.TEMPPOINTERS
ADDQ.W #1,GE_TEMP(A0) STUB.TEMPPOINTERS:=...+1; "INCLUDE T(0)"
MOVE.L MOD_STK(A5),D5 STUB.CALLSTK:=MODULE.CALLSTK
MOVE.L D5,GE_STK(A0) .
MOVE.W MOD_STK+SZ_K(A5),D4 .
MOVE.W D4,GE_STK+SZ_K(A0) .
EXT.L D4 D4.L/D5.L HOLDS STUB.CALLSTK
MOVEM.L D4/D5,-(A7) CALL STACK IS LEFT ON THE STACK
* IT IS PICKED UP WHEN THE BOOT PROCESS IS CREATED BY THE ENTER MODULE
MOVE.L MOD_TEMD(A5),GE_TEMD(A0) STUB.TEMPDATA:= MODULE.TEMPDATA;
PAGE
* CREATE A SET OF NON EMBEDDED SEGMENT OBJECTS.
* EACH SEGMENT OBJECT CONTAINS A HEADER SEGMENT OR A LOAD SECTION
* FROM THE BOOT LOADED MODULES CURRENTLY "PROTECTED" BY THE ALLOC OBJECT.
* THE SEGMENT DATA OF THE ALLOC OBJECT SHRINKS AS THE NEW SET
* GROWS. THE SET IS OWNED BY LOCAL-2 OF THE STUB OBJECT.
* THE HEADER SECTIONS AS WELL AS THE LOAD SECTIONS MUST BE
* AN INTEGRAL NUMBER OF PAGES.
*
IF.L KV_BOTLD <NE> #-1 THEN.L IF RAM-BOOT IS THE CASE THEN
BSR.L GET_LDMD A5:=FIRST BOOT LOADED MODULE
REPEAT REPEAT "FOR EACH MODULE DO"
PRT_MEM HEADER_SECTION,(A5),300
* MOVE THE SIZE OF THE HEADER SECTION, AND OF THE ASSOCIATED
* LOAD SECTIONS, TO THE STACK.
MOVE.L A7,A6 A6:=OLD STACK TOP;
MOVE.L MOD_SIZE(A5),A0 A0:=REST:=LENGTH OF TOTAL MODULE;
MOVE.W MOD_HSIZ(A5),D0 D0:=LENGTH OF HEADER SECTION;
TSTPAGE D0,6 LENGTH SHOULD BE ON INTEGRAL #PAGES;
SUBA.W D0,A0 A0:=REST:=...-LENGTH OF HEADER;
MOVE.W D0,-(A7) PUSH LENGTH OF HEADER SECTION;
ADDA.W MOD_PROG(A5),A5 A5:=ADDRESS OF PROGRAM OBJECT DESCRIPTION;
MOVE.W MOD_LDSS(A5),D5 D5:=#LOAD DATA SEGMENT DESCRIPTIONS;
ADDA.W MOD_FDSD(A5),A5 A5:=FIRST LOCAL DATA SEGMENT DESCRIPTION;
WHILE.W D5 <NE> #0 DO.S WHILE MORE LOCAL DATA SEGM DESCR DO
MOVE.W MOD_LSDS(A5),D4 D4:=#LOAD SECTION DESCRIPTIONS;
LEA MOD_LDSZ(A5),A4 A4:=FIRST LOAD SECTION DESCRIPTION;
WHILE.W D4 <NE> #0 DO.S WHILE MORE LOAD SECTION DESCR. DO
MOVE.L MOD_SLEN(A4),D0 D0:=LENGTH OF LOAD SECTION;
TSTPAGE D0,6 LENGTH MUST BE AN INTEGRAL #PAGES;
SUBA.L D0,A0 A0:=REST:=...-LENGTH OF SECTION;
MOVE.L D0,-(A7) PUSH LENGTH OF LOAD SECTION;
SUBQ.W #1,D4 D4:=REST #LOAD SECTION DESC:=...-1;
LEA MOD_LSDZ(A4),A4 A4:=ADDRESS OF NEXT LOAD SECTION DESCR;
ENDW ENDW;
SUBQ.W #1,D5 D5:=REST #LOAD DATA SEFM DESCR:=..-1
ADDA.W MOD_DSIZ(A5),A5 A5:=ADDRESS OF NEXT LOCAL DATA SEGM DESC.
ENDW ENDW;
IF.L A0 <NE> #0 THEN.S IF REST <> 0 THEN
ERROR 7 ERROR 7; "MODULE JAM"
ENDI ENDI;
MOVE.L A6,-(A7) SAVE OLD STACK TOP AN TOP OF STACK;
PAGE
* THE STACK CONTAINS A WORD AND A NUMBER OF LONGS.
* CREATE SEGMENT OBJECTS ACCORDING TO THESE VALUES.
MOVE.L #NEMB_SIZ,D0 D0:=KNEL_PART SIZE FOR NON EMB SEGM;
MOVE.W -(A6),D6 D6:=SIZE OF FIRST SEGMENT;
EXT.L D6 SIGN EXTEND D6
REPEAT REPEAT "FOR ALL VALUES DO"
CLR.W D1 D1:=NO USER PART:=0;
BSR.L MM_CRE CREATEOBJ (D0=KNELSIZE, D1=USER SIZE,
* A0:=KNELPART,A1:=USER PART);
IF <EQ> THEN.S IF NO_ROOM THEN
ERROR 8 ERROR(8);
ENDI ENDI;
BSR.L GET_LDMD A1:=A5:=PROTECTED BOOT MODULES;
MOVE.L A5,A1
MOVE.L D6,D1 D1:=LENGTH OF SEGMENT
* REMAP DATA INTO NEW OBJECT
BSR.L MAKESEGM MAKESEGM (D1=LENGTH,A0=SEGM,A1=DATA)
* REMOVE DATA FROM THE PROTECTING ALLOC SEGMENT
LEA ALLOCOBJ,A3 A3:=ALLOCOBJ;
ADD.L D1,SE_FIR(A3) ALLOCOBJ.FIRSTSEGMDATA:=...+LENGTH;
SUB.L D1,SE_LEN(A3) ALLOCOBJ;.SEGMLENGTH:=...-LENGTH;
MOVE.L OB_SPA(A3),A3 A3:=SPACE_DESCR OF ALLOCOBJ;
ADD.L D1,SP_FIRU(A3) ALLOCOBJ.FIRST USER DTAT:=...+LENGTH;
SUB.L D1,SP_SIZU(A3) ALLOCOBJ;.SIZE USER DATA:=...-LENGTH;
PRT_MEM UNPROTECT,ALLOCOBJ,ALLOCSIZ ********
* CHAIN NEW SEGMENT OBJECT (A0) TO LOCAL-2 OF STUB ENVELOPE
BSR.L GETSTUBE A3:=STUB ENVELOPE;
MOVE.W #EN_SIZ+PT_SIZ,D3 D3:=OFFSET TO LOCAL-2;
BSR.L CHAINOWN CHAINOWN(A0=OBJECT,A3/D3=POINTER,
* A2:=UNDEF);
MOVE.L -(A6),D6 D6:=SIZE OF NEXT SEGMENT;
UNTIL.L A6 <EQ> A7 UNTIL ALL SIZES HAVE BEEN USED;
MOVE.L D6,A7 A7:=OLD STACK TOP; "POP SIZE LIST"
BSR.L GET_LDMD A5:=ADDR OF PROTECTED MODULES;
TST.L MOD_SIZE(A5) TEST FOR TERMINATING ZERO MODULE;
UNTIL <EQ> UNTIL ZERO MODULE IS REACHED;
*
LEA ALLOCOBJ,A3 A3=ALLOCOBJ
MOVE.L SE_LEN(A3),D1 D1=ALLOCOBJ.SEGMLENGTH;
IF.L D1 <NE> #256 THEN.S IF ALLOCOBJ <> ZERO MODULE THEN
ERROR 7 ERROR 7 "MODULE JAM"
ENDI ENDI;
MOVE.L A5,A1 A1:=ADDRESS OF ZERO MODULE;
BSR.L REMOVEUS REMOVEUS(D1=SIZE,A1=USERPART,
* A0:=UNDEF);
ENDI ENDI; "RAM-BOOT APPEARS"
PAGE
* SET UP PROGRAM REF IN LOCAL-1 OF STUB.
*
IF.L KV_STUB <NE> #-1 THEN.S IF STUB MODULE IN ROM THEN
* CREATE A SUBSEGMENT OF THE FULSPACE SEGMENT, DESCRIBING THE
* LOCAL SECTION(S) OF THE MODULE.
MOVE.L #SU_SIZ+SP_SIZ,D0 D0:=SIZE OF NON EMB SUB SEGM OBJ;
CLR.L D1 D1:=NO USER PART:=0;
BSR.L MM_CRE CREATEOBJ (D0=KNELSIZE,D1=0,
* A0:= OBJECT A0:=KNELPART,A1:=UNDEF);
MOVE.L KV_STUB,A1 A1:=STUB MODULE
MOVE.L MOD_SIZE(A1),A2 A2:=SIZE OF SECTIONS:=SIZE OF MODULE
SUBA.W MOD_HSIZ(A1),A2 -SIZE OF HEADER;
ADDA.W MOD_HSIZ(A1),A1 A1:=ADDRESS OF SECTIONS
* :=ADDRESS OF MODULE+SIZE OF HEADER;
MOVE.B #OB_SEOB,OB_KIN(A0) OBJECT.KIND:=SEGMENT;
MOVE.B #OB_SUBS,OB_STA(A0) OBJECT.STATE:=SUBSEGMENT;
CLR.W SE_IO(A0) OBJECT.IOCOUNT:=0;
MOVE.L A1,SE_FIR(A0) OBJECT.FIRST SEGM DATA:=ADDRESS OF SECTION
MOVE.L A2,SE_LEN(A0) OBJECT.SEGMLENGTH:=SIZE OF SECTIONS;
INIT_HEAD SE_WAIT(A0),A3 OBJECT.WAITING := EMPTY;
BSR.L GETSTUBE A3:=ENVELOPE OF STUB;
MOVE.W #EN_SIZ,D3 D3:=OFFSET TO LOCAL-1;
BSR.L CHAINOWN CHAINOWN(A0=SUBSEGM,A3=STUBENV
* D3=LOCAL-1,A2:=UNDEF);
* LET THE SEGMENT POINTER OF THE SUBSEGMENT POINT TO THE FULSPACE SEGM OBJECT
LEA FULSPACE,A4 A4:=FULSPACE SEGM OBJECT
LEA SU_P(A0),A0 A0:=OBJECT.SEGM POINTER;
BSR.L SIMPLEPT SEGM POINTER(=A0)POINTS TO FULSPACE(=A4)
MOVE.B #PT_SEG,PT_KIN(A0) CHANGE POINTER KIND TO "SEGM POINTER";
ELSE.S ELSE "THE STUB MODULE IS IN RAM"
* THE SECOND OBJECT IN THE OWNER SET OF LOCAL-2 OF THE STUB WILL
* BE THE CODE SEGMENT. CREATE A SIMPLE POINTER TO THAT OBJECT.
BSR.L GETSTUBE A3:=STUB ENVELOPE
LEA EN_SIZ+PT_SIZ(A3),A0 A0:=LOCAL-2
MOVE.L (A0),A4 A4:=FIRST_IN_SET:=LOCAL-2.NEXT;
MOVE.L (A4),A4 A4:=CODE_SEGM_OBJ:=FIRST_IN_SET.NEXT;
LEA -PT_SIZ(A0),A0 A0:=LOCAL-1;
BSR.L SIMPLEPT LOCAL-1(=A0)POINTS TO CODE_SEGM(=A4)
ENDI ENDI;
* LOCAL-6 OF THE STUB ENVELOPE SHOULD POINT TO THE FULSPACE OBJECT
* A0 = LOCAL-1
LEA 5*PT_SIZ(A0),A0 A0:=LOCAL-6
LEA FULSPACE,A4 A4:=FULSPACE OBJECT
BSR.L SIMPLEPT LOCAL-6(=A0)POINTS TO FULSPACE(=A4)
PAGE
* INITIALIZE ALLOCOBJ AS THE INITIAL ALLOC OBJECT OF THE KERNEL.
*
LEA ALLOCOBJ,A0 A0:=KNELPART OF ALLOC;
MOVE.L #ALLOCSIZE,D0 D0:=SIZE OF KNELPART;
BSR.L INITKNEL INITIALIZE ALLOC OBJ;
MOVE.B #OB_ALLO,OB_KIN(A0) OBJECT.KIND:=ALLOCATE;
MOVE.B #1<<OB_REEN,OB_STA(A0) OBJECT.STATE:=...+ ALLOC IS REENTRANT;
PRT_MEM FINAL_ALLOC,(A0),ALLOCSIZ ********
* LOCAL-3 OF THE STUB SHOULD POINT TO THE ALLOC OBJECT
*
MOVE.L A0,A4 A4:=ALLOC OBJECT
BSR.L GETSTUBE A3:=STUB ENVELOPE
LEA 2*PT_SIZ+EN_SIZ(A3),A0 A0:=LOCAL-3 OF STUB
BSR.L SIMPLEPT LOCAL-3(=A0) POINTS TO ALLOC(=A4);
* LOCAL 4,5,7,8 AND 9 ARE INITIALIZED BY THE SCHEDULER, LOCAL 10 BY ENTER.
PRT_MEM END_OF_MMPROCS,(A7),8
BRA.L I_SCHED CONTINUE IN KNELOP INITIALIZATION
* END OF SECTION INITIALIZE.
PAGE
SECTION 9 = RUNTIME
* PROCEDURES DEFINED IN OTHER MODULES:
XREF 9:KNELWAIT,KNELSIGN,TIMCHECK PROCS OF SCHED
XREF 9:C_PT,C_SUB,CLR_SMP PROCS OF KNELOP
MM_POPU EQU * RELEASE THE SEGMENT DATA OF A SEGMENT OBJECT
* A0 KERNEL PART OF OBJECT SAME
* A4 SEGMENT OBJECT SAME
* D0.L SIZE OF SEGMENT (INTEGRAL NO OF PAGES) SAME
* A6 ANY SPACE DESCR OF OBJECT
* THE SEGMENT DATA MUST BE ON TOP OF THE DATA STACK OF THE OBJECT (A0)
*
* FUNCTION
* UPDATES THE SPACE DESCRIPTION OF THE OBJECT (SP_FREU IS INCREASED)
* IF THE SEGMENT OBJECT EQUALS THE CURRENT USER MOVE CANDIDATE, THE
* CURRENT USER MOVE CANDIDATE IS SET TO ZERO, AND
* SP_FIRU IN THE SPACE DESCR IS SET TO FUTURE USER DESTINATION.
* CURRENT USER MOVE CANDIDATE AND FUTURE USER DESTINATION ARE
* GLOBAL VARIABLES OF MM_PROCS (CURUMOVE AND USERDEST)
MOVEA.L OB_SPA(A0),A6 A6:=SPACE DESCR OF OBJECT;
ADD.L D0,SP_FREU(A6) FREE_USER_BYTES:=...+SIZE OF SEGMENT
IF.L CURUMOVE <EQ> A4 THEN.S IF CURRENT_USER_MOVE_CANDIDATE=SEGMENT THEN
PRT_REG **********A4=CORUMOVE_RELEASE ********
CLR.L CURUMOVE CURRENT_USER_MOVE_CANDIDATE:=NOMOVE:=0,
MOVE.L USERDEST,SP_FIRU(A6) FIRST_FREE_USER_BYTE:=FUTURE USER DESTINAT
ENDI ENDI;
RTS RETURN;
MM_PUSHU EQU * ALLOCATE SEGMENT DATA IN THE USER PART
* CALL: RETURN:
* A0 KERNEL PART OF OBJECT SAME
* D0.L NO OF USER BYTES (INTEGRAL NO OF PAGES) SAME
* A4 ANY SEGMENT DATA ADDRESS OR UNDEF
* A6 ANY SPACE DESCR OF OBJECT
* CCR <EQ>: ERROR; <NE>: OK
*
* UPDATES THE SPACE DESCR OF THE OBJECT (SP_FREU IS REDUCED),
* AND RETURNS THE START ADDRESS OF THE SEGMENT.
* THE ADDRESS OF THE SEGMENT IS COMPUTED AS FOLLOWS:
* SP_FREU:=SP_FREU-SIZE_OF_NEW_SEGMENT;
* A4 := SP_FIRU + SP_FREU;
*
MOVE.L D0,-(A7) SAVE D0
MOVE.L OB_SPA(A0),A6 A6:=SPACE DESCRIPTION;
NEG.L D0 D0:=NEW_FREE_USER_BYTES:=
ADD.L SP_FREU(A6),D0 FREE_USER_BYTES-SIZE_OF_NEW_SEGMENT;
IF <LT> THEN.S IF NEW_FREE_USER_BYTES <0 THEN "NO ROOM"
CMP.W D0,D0 CCR:=NO ROOM:= <EQ>;
ELSE.S ELSE "ROOM IS AVAILABLE"
MOVE.L D0,SP_FREU(A6) FREE_USER_BYTES:=NEW_FREE_USER_BYTES=D0;
ADD.L SP_FIRU(A6),D0 A4:=SEGMENT ADDRESS;
MOVE.L D0,A4 CCR:=OK:=<NE>
ENDI ENDI;
MOVEM.L (A7)+,D0 RESTORE D0;
RTS RETURN;
PAGE
MM_PUSHK EQU * CREATE A STACK ELEMENT IN OBJECT
* CALL: RETURN:
* A0 KERNEL PART TO PROVIDE THE SPACE SAME
* A3 ANY STACK ELEMENT OR UNDEF
* D0.W SIZE OF STACK ELEMENT INCL. POINTERS SAME
* A6 ANY SPACE DESCR OF OBJECT
* CCR <EQ>:ERROR,<NE>:OK
*
* CREATES A STACK ELEMENT AND RETURNS ITS ADDRESS (IF RESOURCES
* ARE AVAILABLE). ST_HOLD OF THE ELEMENT EQUALS A0.
* ACTUAL CHAIN OF THE STACK ELEMENT IS INITIALIZED TO EMPTY
* ST_TOP EQUALS D0.W
* FIRST_EMBEDDED EQUALS 0
* RESIDENT_COUNT IS ZERO
* IO_COUNT IS ZERO
* THE ADDRESS OF THE STACK ELEMENT WILL BE COMPUTED AS FOLLOWS.
* SP_FREK:=SP_FREK-D0.W;
* A3:=SP_FIRK+SP_FREEK;
*
MOVE.L OB_SPA(A0),A6 A6:=SPACE DESCRIPTION;
MOVEA.W SP_FREK(A6),A3 A3.L:=FREE BYTES IN THE KERNEL PART;
SUBA.W D0,A3 A3.L:=NEW_FREE_BYTES:=FREE_BYTES-SIZE;
IF.W A3 <LT> #0 THEN.S IF NEW_FREE_BYTES <0 THEN
CMP.W D0,D0 CCR:=NO_ROOM:=<EQ>
ELSE.S ELSE "CREATE STACK ELEMENT"
MOVE.W A3,SP_FREK(A6) FREE_BYTES:=NEW_FREE_BYTES;
ADDA.L SP_FIRK(A6),A3 A3:=ADDRESS_OF_STACK_ELEMENT:=FREE_BYTES+
* FIRST_FREE_KERNEL_BYTE
* INITIALIZE FIELDS OF THE NEW STACK ELEMENT
CLR.W ST_FIR(A3) STACK.FIRST_EMB:=0;
MOVE.W D0,ST_TOP(A3) STACK.TOP_POINTERS:=SIZE;
CLR.W ST_RES(A3) STACK.RESIDENT_COUNT:=0;
CLR.W ST_IO(A3) STACK.IO_COUNT:=0;
LEA ST_ACT(A3),A3 A3:=ACTUAL CHAIN HEAD;
MOVE.L A3,(A3) :=EMPTY;
MOVE.L A3,4(A3)
LEA -ST_ACT(A3),A3 A3:=ADDRESS OF STACK ELEMENT;
MOVE.L A0,ST_HOLD(A3) STACK.HOLDING_OBJECT:=KERNEL PART;
* CCR:=<NE>;
ENDI ENDI;
RTS RETURN;
PAGE
MM_POPK EQU * POPS A STACK ELEMENT FROM AN OBJECT
*
* CALL: RETURN:
* A3 ELEMENT TO BE POPPED PRIOR ELEMENT
* A6 ANY SPACE DESCR OF OBJECT
* THE ELEMENT SIZE IS DESCRIBED IN THE ELEMENT (ST_TOP-ST_FIR)
* THE AMOUNT OF FREE MEMORY IS INCREASED (SP_FREK)
* THE STACK ELEMENT IS UNCHAINED FROM THE STACK CHAIN.
* IF THE STACK ELEMENT EQUALS THE CURRENT_KERNEL_MOVE_CANDIDATE,
* THE CURRENT KERNEL MOVE CANDIDATE IS CHANGED TO POINT TO PRIOR
* ELEMENT. CURRENT KERNEL MOVE CANDIDATE IS A GLOBAL
* VARIABLE OF MM_PROC (CURKMOVE).
ENTRYSAV D0/A0/A1,.MM_POPK SAVE REGISTERS;
MOVEA.L ST_HOLD(A3),A6 A6:=KERNEL PART OF OBJECT HOLDING ELEMENT;
MOVEA.L OB_SPA(A6),A6 A6:=SPACE DESCR OF OBJECT;
MOVE.W ST_TOP(A3),D0 D0:=SPACE_FOR_STACK_ELEMENT
SUB.W ST_FIR(A3),D0 + SPACE_FOR_SEGM_DESCRIPTIONS;ALWAYS 0?
ADD.W D0,SP_FREK(A6) FREE_KERNEL_BYTES:=FREE_KERNEL_BYTES+
* SPACE_FOR_STACK_ELEMENT+SPACE_FOR_SEGM_DE
* REMOVE ELEMENT FROM ITS STACK (ENV OR CTX).
LEA ST_STK(A3),A3 A3:=STACK CHAIN ELEMENT;
MOVEM.L (A3),A0/A1 A0:=HEAD OF STACK:=ELEMENT.NXT;
* A1:=PRIOR STACK ELEMENT;
MOVE.L A0,(A1) PRIOR.NXT:=HEAD OF STACK;
MOVE.L A1,4(A0) HEAD_OF_STACK.PRV:=PRIOR STACK ELEMENT;
IF.L CURKMOVE <EQ> A3 THEN.S IF CURRENT CANDIDATE=POPPED ELEMENT THEN
PRT_REG **********A3=CURKMOVE_RELEASED ********
MOVE.L A1,CURKMOVE CURRENT CANDIDATE:=PRIOR ELEMENT;
ENDI ENDI;
LEA -ST_STK(A1),A3 A3:=FIRST OF PRIOR ELEMENT;
RETURN .MM_POPK RETURN;
PAGE
MM_PUSHD EQU * PUSH DESCRIPTOR ON TOP OF STACK
* CALL: RETURN:
* A0 KERNEL PART SAME
* D0.W SE_SIZ OR SU_SIZ SAME
* A5 ANY SEGMENT/SUBSEGMENT DESCRIPTOR ADDR.
* A6 ANY SPACE DESCR
* CCR <EQ>:ERROR,<NE>:OK
* THE DESCRIPTOR IS NOT INITIALIZED IN ANY WAY, SPACE DESCR IS UPDATED
* ST_FIR OF THE STACK ELEMENT IS UPDATED BY THE CALLER.
MOVE.W D0,-(A7) SAVE DO.W;
MOVEA.L OB_SPA(A0),A6 A6:=SPACE DESCRIPTION
NEG.W D0 D0:=NEW_FREE_KNEL_BYTES:=
ADD.W SP_FREK(A6),D0 FREE_KERNEL_BYTES-SIZE_OF_SEGMENT_DESC;
IF <LT> THEN.S IF NEW_FREE_KNEL_BYTES <0 THEN "NO ROOM"
MOVE.W (A7)+,D0 RESTORE D0.W
CMP.W D0,D0 CCR:=NO_ROOM:=<EQ>;
ELSE.S ELSE
MOVE.W D0,SP_FREK(A6) FREE_KNEL_BYTES:=NEW_FREE_KNEL_BYTES;
MOVEA.L SP_FIRK(A6),A5 A5:=SEGM_DESC_ADDR:=
ADDA.W D0,A5 FIRST_FREE_ADDR+FREE_KNEL_BYTES;
MOVE.W (A7)+,D0 RESTORE D0.W; CCR:= OK := <NE>;
ENDI ENDI;
RTS RETURN;
MM_POPD EQU * POP DESCRIPTOR FROM TOP OF STACK
* CALL: RETURN:
* D0.W SE_SIZ OR SU_SIZ SAME
* A0 KERNEL PART SAME
* A5 DESCRIPTOR ADDRESS PREVIOUS DESCRIPTOR ADDRESS
* A6 ANY SPACE DESCR
*
* RELEASE THE DESCRIPTOR, UPDATE SPACE DESCR.
* ST_FIR IS UPDATED BY THE CALLER.
MOVE.L OB_SPA(A0),A6 A6:=SPACE DESCRIPTOR;
ADD.W D0,SP_FREK(A6) FREE_KNEL_BYTES:=...+SIZE OF SEGM DESCR;
ADD.W D0,A5 A5:=PREVIOUS_DESCR_ADDR:=
* DESCR_ADDR+SIZE OF SEGM DESCR;
RTS RETURN
PAGE
MM_PUSHO EQU * ALLOCATE OBJECT-TYPE RELATED INFORMATION IN KNEL PART
* CALL: RETURN:
* A0 KERNEL PART SAME
* D0.W SPACE NEEDED (E.G.:GE_SIZ-OB_SIZ) UNDEF
* A6 ANY SPACE DESCR
* CCR <EQ>:ERROR,<NE>:OK
* SPACE IS ALLOCATED IN THE BEGINNING OF THE KERNEL PART.
MOVEA.L OB_SPA(A0),A6 A6:=SPACE_PART
IF.W D0 <GT> SP_FREK(A6) THEN.S IF SPACE NEEDED > FREE KERNEL BYTES THEN
CLR.W D0 D0:=NO ROOM:=0; CCR:=NO_ROOM:=<EQ>;
ELSE.S ELSE
SUB.W D0,SP_FREK(A6) FREE KERNEL BYTES:=...-SPACE NEEDED
EXT.L D0 D0.L:=BYTES NEEDED
ADD.L D0,SP_FIRK(A6) FIRST FREE KNEL BYTE:=...+SPACE NEEDED
* CCR:= OK:= <NE>;
ENDI ENDI;
RTS RETURN;
MM_POPO EQU * RELEASE OBJECT_TYPE RELATED INFORMATION FROM KERNEL PART
*
* CALL: RETURN:
* A0 KERNEL PART SAME
* D0 SPACE RELEASED SAME
* A6 ANY SPACE DESCR
* SPACE IS RELEASED IN THE BEGINNING OF THE KERNEL PART
*
MOVE.L OB_SPA(A0),A6 A6:=SPACE DESCRIPTION;
ADD.W D0,SP_FREK(A6) FREE KERNEL BYTES:=...+SPACE RELEASED;
EXT.L D0 D0.L:=BYTES RELEASED;
SUB.L D0,SP_FIRK(A6) FIRST FREE KNEL BYTES:=...-SPACE RELEASED;
RTS RETURN;
******* SPECIAL TEST OUTPUT PROCEDURES
MEMPLUS EQU * D0=USER,D1=KNEL
MOVEM.L D0/D1/A0/A2,-(A7) SAVE A0/A2, PUSH USER AND KNEL
LEA 8(A7),A2 A2:= TOP OF SAVED D1
ADD.L D1,D0 D0:=SUM
MOVE.L KV_FRMEM,D1 D1:=FREE MEMORY
MOVEM.L D0/D1,-(A7) PUSH SUM AND FREE
MOVE.L #$DDDDDDDD,D0 D0:= D DOR DEALLOC
MOVE.L D0,-(A7)
MOVE.L D0,-(A7)
MOVE.L A7,A0
BSR.L PRINTA02 TESTOUTPUT(A0=FIRST,A2=TOP,D0/D1/A0:=?);
LEA -8(A2),A7 A7:= TOP OF SAVED REGISTERS
MOVEM.L (A7)+,D0/D1/A0/A2 RESTORE ALL REGS: D0/D1/A0/A2
RTS
MEMMINUS EQU * D0=KNEL,D1=USER,D2=SUM,D3=FREE
EXG.L D0,D1 D0:=USER,D1:=KNEL
MOVEM.L D0/D1/A0/A2,-(A7) SAVE A0/A2, PUSH USER AND KNEL
LEA 8(A7),A2 A2:= TOP OF SAVED D1
MOVEM.L D2/D3,-(A7) PUSH SUM AND FREE
MOVE.L #$AAAAAAAA,D0 D0:= A FOR ALLOC
MOVE.L D0,-(A7)
MOVE.L D0,-(A7)
MOVE.L A7,A0
BSR.L PRINTA02 TESTOUTPUT(A0=FIRST,A2=TOP,D0/D1/A0:=?);
LEA -8(A2),A7 A7:= TOP OF SAVED REGS
MOVEM.L (A7)+,D0/D1/A0/A2 RESTORE ALL REGS: D0/D1/A0/A2
EXG.L D0,D1 D0:=KNEL,D1:=USER
RTS
PAGE
ALLOC_OB EQU * ENTRY POINT FOR OBJ_CALL TO ALLOC OBJECT
* CALL: RETURN:
* A0 EXTENSION (NOT USED) SAME
* A2 CUR_CTX SAME
* A4 ARGUMENT UNDEF
* A5 ALLOC OBJECT UNDEF
* D3 CALLER (=0 FOR NORMAL OBJECT) UNDEF
* D4 LOW_ARG UNDEF
* D5 FUNCTION UNDEF
* D6/D7 ARG#/UNDEF RESULT
* CCR <EQ>: RETURN TO CALLING CONTEXT;
* OTHER REGISTERS ARE UNDEF AT RETURN
* ONLY ONE ALLOC OBJECT IS PRESENT IN THE SYSTEM
*
LSL.W #1,D5 D5:=FUNC:=FUNCTION *2
CMP.W #4,D5 TEST FUNCTION < 2<<1
BGT.S ER_FUILL WHEN FUNC >4 GOTO FUNCTION_ILLEGAL;
TST.W D3 TEST THE CALLER
BNE.S ER_FUILL WHEN CALLER <> NORMAL_CTX GOTO FUNCTION_ILL
CASEJMP D5 GOTO CASE FUNC OF
CASELAB ER_FUILL 0<<1: NOT POSSIBLE
CASELAB NEW_OBJ 1<<1: NEW_OBJ
CASELAB ER_FUILL 2<<1: FUNCTION_ILLEGAL "GET AMOUNT?"
ER_ADDR EQU * ADDRESS ILLEGAL:
MOVE.L #ECRADDR,D7 D7:=RESULT:= ADDRESS ILLEGAL;
BRA.S ALREJECT GOTO RETURN_REJECT;
ER_FUILL EQU * FUNCTION_ILLEGAL:
MOVE.L #ECRFUNC,D7 D7:=RESULT:= FUNCTION ILLEGAL;
BRA.S ALREJECT GOTO RETURN_REJECT;
ER_ARGMIS EQU * ARGUMENTS_MISSING:
MOVE.L #ECRARGMIS,D7 D7:=RESULT:= ARGUMENTS MISSING;
BRA.S ALREJECT GOTO RETURN_REJECT;
ER_VAL3MIS EQU *
MOVEQ.L #3,D6 D6:=ARG# OF VALUE SUB SEGM ARGUMENT;
ER_VALMIS EQU * TOO_FEW_VALUE_PARAMS:
MOVE.L #ECRVALMIS,D7 D7:=RESULT:= VALUE PARAMETERS MISSING;
BRA.S ALREJECT GOTO RETURN_REJECT;
ER_DAILL EQU * DATA_ILLEGAL:
MOVE.L #ECRDATA,D7 D7:=RESULT:= DATA VALUE ILLEGAL;
* BRA.S ALREJECT GOTO RETURN_REJECT;
ALREJECT EQU * RETURN_REJECT:
CMP.W D0,D0 CC := RETURN := <EQ>;
RTS RETURN; "TO CALLING CONTEXT"
PAGE
NEW_OBJ EQU * CREATE NEW OPEN OBJECT.
*
* GET AND CHECK VALUE DATA
LEA -AR_SIZ<<1(A4),A1 TEST #REMAINING ARGUMENTS >=2;
CMPA.L D4,A1 TEST (ARG-(2*ACT_SIZE)) - LOWARG;
BLT.S ER_ARGMIS WHEN REMAINING <2 GOTO ARGUMENTS_MISSING;
TST.W -2(A4) TEST FOR VOID VALUE DATA
BEQ.S ER_VAL3MIS WHEN VOID GOTO TOO_FEW_VALUE_PARAMS;
BSR.L C_SUB CHECK_SUB(A5:=BSEG,D0:=T_REL,D2:=LENGTH,.
BEQ.S ALREJECT WHEN NOT OK GOTO RETURN_REJECT;
MOVE.L SE_FIR(A5),A6 A6:=FIRST OF BASE SEGMENT DATA
ADD.L A6,D0 D0:=FIRST_VALUE:=T_REL+FIRST_DATA;
BTST.L #0,D0 IF FIRST_VALUE ADDRESS IS ODD
BNE.S ER_ADDR THEN REJECT;
BTST.L #0,D2 IF LENGTH OF VALUE SEGM IS ODD
BNE.S ER_ADDR THEN REJECT;
MOVE.L D0,A6 A6:=FIRST_VALUE;
CMP.L #14,D2 TEST LENGTH-14; "14 BYTES REQUIRED"
BLT.S ER_VALMIS WHEN LENGTH <14 GOTO TOO_FEW_VALUE_PARAMS
MOVEQ.L #0,D6 D6:=FIRST VALUE PARAMETER IDENT;
SUBQ.B #1,D6 .
MOVE.W -(A6),D0 D0:=LENGTH OF FIRST VALUE;
CMP.W #6,D0 TEST LENGTH OF FIRST VALUE;
BNE.S ER_DAILL WHEN LENGTH <> 6 GOTO DATA_VALUE_ILLEGAL;
MOVEQ.L #1,D0 D0.L:=ROUNDUP BIT;"KNEL_BYTES MAY BE ODD"
ADD.W -(A6),D0 D0.L:=KNEL_BYTES+1; "CALL VALUE"
BLE.S ER_DAILL WHEN KNEL_BYTES+1 <= 0 GOTO DATA_ILLEGAL;
BCLR.L #0,D0 D0:= EVEN KNEL_BYTES;
MOVE.L -(A6),D1 D1.L:=USER_BYTES; "CALL VALUE"
BLT.S ER_DAILL WHEN USER_BYTES <0 GOTO DATA_ILLEGAL;
ADD.L #255,D1 ADJUST USER_BYTES, TO AN
CLR.B D1 INTEGRAL NUMBER OF PAGES
TST.L D1
BLT.S ER_DAILL WHEN USER_BYTES <0 GOTO DATA_ILLEGAL;
ADD.L #(OB_SIZ+SP_SIZ),D0 KNEL_BYTES:=... + SIZE OF MINIMAL OBJECT;
* A6 POINTS NEXT TO THE RETURN VALUE
SUBQ.B #1,D6 D6:=SECOND VALUE PARAMETER ARG#
MOVE.W -(A6),D2 D2:=VALUE_LENGTH OF RETURN VALUE;
CMP.W #4,D2 TEST VALUE_LENGTH;
BNE.S ER_DAILL WHEN VALUE_LENGTH <>4 GOTO DATA_ILLEGAL;
MOVE.L D1,D2 D2:=BYTES_NEEDED:=KNEL_BYTES
ADD.L D0,D2 + USER_BYTES;
MOVE.L D2,-(A6) RETURN_VALUE:=BYTES_NEEDED;
MOVE.L -(A4),D3 D3:="ADDRESS OF FUTURE OWNER POINTER"
* MOVE.W -(A4),D4 SE NOTE BELOW D4:= CALL/RETURN;
TAS.B MM_LOCK LOCK THE MM_LOCK;
IF <NE> THEN.S IF MM_LOCK ALREADY LOCKED THEN
MOVEM.L D0/D1/D2/D3,-(A7) SAVE SIZE AND POINTER ADDRESS ON STAC
LEA MM_QUEUE,A1 A1:=MM_QUEUE
BSR.L KNELWAIT MM_QUEUE.WAIT;
MOVEM.L (A7)+,D0/D1/D2/D3 RESTORE SIZE AND POINTER ADDRESS
ENDI ENDI;
MOVE.L D3,SAVE_RPA SAVE OWNER POINTER ADDRESS;
MOVE.L KV_FRMEM,D3 D3:=FREE_BYTES:=FREE_BYTES
PRT_REG NEW_OBJ_D0/D1/D2/D3 ********
*
* SPECIAL TESTOUTPUT FROM MEMORY ALLOCATION
BTST.B #0,TSTSTATU+1
IF <NE> THEN.S
BSR.L MEMMINUS MEMMINUS(D0=KNEL,D1=USER,D2=SUM,D3=FREE);
ENDI
*
SUB.L D2,D3 -BYTES_NEEDED;
IF <LT> THEN.S IF BYTES_NEEDED NOT AVAILABLE THEN
AL_NORES EQU * NO_RESOURCES:
MOVE.L #ECRNO_RES,D7 D7:=RESULT:=NO_RESOURCES;
BRA.S ALRETURN GOTO ALLOC_RETURN;
ENDI ENDI;
* THE TEST BELOW IS NOT EFFECTIVE !!! D4 CANNOT BE USED TO HOLD THIS SINGLE
* BIT OF INFORMATION ACROSS THE KNELWAIT ABOVE. ONLY 4 REGISTERS CAN BE SAVED
* AT THIS POINT. THE BIT CAN BE ENCODED AS SIGNBIT OF SOM OF THE OTHER REGS.
* BTST.L #1,D4 TEST THAT RETURN BIT IS SET IN THE ACTUAL
* IF <EQ> THEN.S IF ACTUAL IS NOT RETURN ACTUAL THEN
* MOVEQ.L #,D7 RESULT:= OK;
* BRA.S ALRETURN GOTO ALLOC_RETURN;
* ENDI ENDI;
MOVE.L D2,SAVENEED SAVE BYTES_NEEDED
* TRY TO ALLOCATE THE OBJECT
*
BSR.L MM_CRE MM_CRE(D0/D1=SIZE,A0/A1:=OBJECT)
BEQ.S AL_NORES WHEN NOT OK GOTO NO_RESOURCES;
MOVE.L KV_CTX,A2 A2:=CUR_CTX;
TST.L CT_OBJ(A2) TEST FOR DUMMYFIED.
BEQ.S REM_DUM WHEN CTX DUMMY GOTO DUMMYFIED
MOVE.W #4+SAVE_RPA,A4 A4.L:=TOP ADDR OF SAVED ARG;
MOVEQ #3,D6 D6:=#PREVIOUSLY CHECKED ARGS:=3;
BSR.L C_PT CHECK_POINTER(A6:=PT,D2:=KIND,...
BEQ.S REM_PTE WHEN NOT OK GOTO POINTER_ERROR;
CMP.W #PT_OWN,D2 TEST POINTER KIND
IF <EQ> THEN.S IF OWN_SET POINTER THEN "DO NOTHING"
ELSE.S ELSE
IF <LT> THEN.S IF SIMPLE POINTER THEN
BSR.L CLR_SMP CLEAR_POINTER(A1,D1=PT,...
MOVE.B #PT_OWN,PT_KIN(A6) POINTER.KIND:=OWN_SET;
ELSE.S ELSE
BRA.S REM_PTV GOTO POINTER_VALUE_ILL;
ENDI ENDI;
ENDI ENDI;
MOVE.L A6,A3 A3:=POINTER CHAIN
INS_ELEM A3,A0,A6,A3/A6 CHAIN OBJECT TO POINTER
MOVE.L A1,OB_OWN(A0) OBJECT.OWNER:=
MOVE.W D1,OB_OFF(A0) (POINTER STRUCTURE,POINTER OFFSET);
MOVE.L SAVENEED,D7 D7:= BYTES_NEEDED;
SUB.L D7,KV_FRMEM FREE_BYTES:=...-BYTES_NEEDED;
CLR.L D7 D7:=RESULT:=OK;
ALRETURN EQU * RETURN FROM ALLOC (MM_LOCK HAS BEEN LOCKED)
LEA MM_QUEUE,A1 A1:=MM_QUEUE;
BSR.L KNELSIGN MM_QUEUE.SIGNAL;
IF <NE> THEN.S IF NO PROC SCHEDULED THEN
BCLR.B #7,MM_LOCK OPEN THE MM_LOCK;
ENDI ENDI;
MOVE.L KV_PROC,A1 A1:=CURRENT PROCESS
MOVE.L EX_EXT+4(A4),A1 A1:=CURRENT EXTENSION MEMBER;
LEA -EX_EXT(A1),A0 A0:=ADDRESS OF CUR_EXTENSION;
CMP.W D0,D0 CCR:=<EQ>; RETURN TO CALLER;
RTS RETURN;
PAGE
REM_DUM EQU * DUMMYFIED: "D7 NEED NOT BE ASSIGNED"
REM_PTE EQU * POINTER_ERROR:
MOVE.L A0,A1 A1:=KNEL PART
BSR.L REMOVOBJ REMOVE OBJ(A1=OBJ,D0:=BYTES,D1/A0:=...);
BRA.S ALRETURN GOTO ALLOC_RETURN;
*
REM_PTV EQU * POINTER_VALUE_ILL;
MOVE.L A0,A1 A1:=KNEL PART
BSR.L REMOVOBJ REMOVE OBJ(A1=OBJ,D0:=BYTES,D1/A0:=...);
MOVE.L #ECRVALUE,D7 D7:=RESULT:=VALUE_ILLEGAL;
BRA.S ALRETURN GOTO ALLOC_RETURN;
*
MM_TERM EQU * TERMINATE OBJECT: TERMINATION PROCEDURE OF KERNEL ALLOC
* CALL: RETURN
* A1 OBJECT UNDEF
* D0/D1/A0 ANY UNDEF
*
* THE MM_LOCK AND MM_QUEUE IS MANAGED OUTSIDE THIS PROCEDURE.
*
BSR.S REMOVOBJ REMOVE OBJ(A1=OBJ,D0:=BYTES,D1/A0:=...);
ADD.L D0,KV_FRMEM ADJUST FREE_BYTES;
RTS RETURN;
PAGE
MM_CRE EQU * CREATE OBJECT
* CALL: RETURN:
* D0 KNEL BYTE >0 SAME
* D1 USER BYTE >=0 SAME
* A0 ANY KNEL_PART
* A1 ANY USER_PART WHEN D1 >0
* CCR <EQ> : NO_RESOURCES, <NE>: OK
* SR 27XX -> 2000 DURING CALL-> 27XX
*
* ALLOCATE THE KERNEL PART AND (WHEN D1>0) THE USER PART
* THE OBJECT WILL BE AN OPEN OBJECT WITH STATE = 0
* THE OWNER FIELDS OF THE OBJECT ARE UNDEFINED.
MOVE.W #$2000,SR ALLOW INTERRUPTS
EXG.L D0,D1 D1:=KNEL BYTES; D0:=USER BYTES
LEA KNELGET,A0
BSR.L GETROOM GETROOM(D1=SIZE,A0=KNELGET,A0:=MEM_REC);
IF.W A0 <EQ> #0 THEN.S IF NO ROOM THEN
BRA.S MM_CREEX GOTO NO_ROOM;
ENDI ENDI;
BSR.L CREATEKN CREATEKN(D1=SIZE,A0=MEM_REC,A0:=KNELPART)
EXG.L D0,D1 D1:=USER BYTES; D0:=KNEL BYTES;
BSR.L INITKNEL INIT KNELPART(D0=SIZE,A0=KNELPART);
MOVE.W #OB_OPOB<<8,OB_KIN(A0) OBJECT.KIND:=OPEN;
* OBJECT.STATE:=0;
TST.L D1
IF <EQ> THEN.S IF USER BYTES = 0 THEN
EXG.L A0,A1 A0:=USER PART,A1:=KNELPART;
ELSE.S ELSE
LEA DUMMYOWN,A1 A1:=DUMMY OWNER POINTER;
MOVE.L A1,(A0) LET DUMMY OWNER POINTER
MOVE.L A1,4(A0) OWN THE KNEL PART. THIS MAKES
MOVE.L A0,(A1) IT POSSIBLE TO FIND IT AFTER
MOVE.L A0,4(A1) THE CALL TO GETROOM;
LEA USERGET,A0
BSR.L GETROOM GETROOM(D1=SIZE,A0=USERGET,A0:=MEM_REC);
MOVE.L DUMMYOWN,A1 A1:=KNEL PART;
IF.W A0 <EQ> #0 THEN.S IF NO ROOM FOR USER PART THEN
EXG.L D0,D1 D0:=USER_BYTES,D1:=KNEL BYTES;
BSR.L REMOVEKN REMOVEKN(D1=SIZE,A1=KNELPART);
EXG.L D0,D1 RESTORE D0,D1;
BRA.S MM_CREEX GOTO NO_ROOM;
ENDI ENDI;
BSR.L CREATEUS CREATEUS(D1=SIZE,A0=MEM_REC,A0:=USER_PART
ENDI ENDI;
* D1 = 0 OR SIZE OF USER PART
BSR.L ASSIGNUS ASSIGNUS(D1=SIZE,A0=USERPART,A1=KNELPART,
* WHEN D1=0 , A1:=0 );
EXG.L A0,A1 A0:=KNELP@RT; A1:=USER PART
MOVE.W #$2700,SR PREVENT INTERRUPTS; CCR:= <NE>;
RTS RETURN;
*
MM_CREEX EQU * EXIT, NO_ROOM:
MOVE.W #$2704,SR PREVENT INTERRUPTS; CCR:= <EQ>;
RTS RETURN;
PAGE
REMOVOBJ EQU * REMOVE OBJECT
* CALL RETURN
* A1 KERNEL PART OF OBJECT UNDEF
* D0 ANY BYTES_RELEASED
* D1,A0 ARE SPOILED
* THE FUNCTION CORRESPONDS TO THE TERMINATION PROCEDURE OF THE ALLOC OBJECT.
* THE MM_GATE HAS BEEN LOCKED BY THE CALLER OF THIS PROCEDURE.
* THE FUNCTION REMOVES THE KERNEL PART AND THE USER PART AND UPDATES THE
* MEMORY STRUCTURES TO REFLECT THAT. CALLING PROC IS NOT SUSPENDED.
*
MOVE.L A1,-(A7) SAVE THE CALL PARAM
MOVE.L OB_SPA(A1),A1 A1:=SPACE DESCRIPTION;
PRT_MEM REMOVOBJ,-SP_SIZ(A1),SP_SIZ ********
MOVE.L SP_SIZU(A1),D1 D1:=SIZE OF USER PART;
MOVE.L SP_FIRU(A1),A1 A1:=USER PART ADDRESS;
MOVE.L D1,D0 D0:=USER_BYTES:=SIZE OF USER PART;
IF <NE> THEN.S IF USER PART PRESENT THEN
BSR.L REMOVEUS REMOVE USER PART (D1,A1,A0/A1:=?);
ENDI ENDI;
MOVE.L (A7)+,A1 A1:=SAVED KERNEL PART ADDRESS;
MOVE.W OB_SIZK(A1),D1 D1:=SIZE OF KERNEL PART;
EXT.L D1
*
* SPECIAL TESTOUTPUT FROM MEMORY DEALLOC
BTST.B #0,TSTSTATU+1
IF <NE> THEN.S
BSR.L MEMPLUS MEMPLUS(D0=USER,D1=KNEL);
ENDI
*
ADD.L D1,D0 D0:=BYTES_RELEASED:=USER_BYTES+KNEL_BYTES;
BSR.L REMOVEKN REMOVE KERNEL PART (D1,A1,A0/A1:=?);
RTS RETURN;
PGTABSET EQU * ASSIGN ENTRY OF PAGE TABLE
* CALL: RETURN:
* D0 TOP ADDRESS OF USER PART SAME
* A1 KERNEL PART ADDRESS SAME
*
ENTRYSAV D0/A0,.PGTABSE SAVE REGISTERS;
LSR.L #6,D0 D0:=OFFSET:=D0 SHIFTFT(-8)SHIFT 2;
MOVE.L PAGE_TAB,A0 A0:=BASE ADDRESS OF PAGE_TABLE
MOVE.L A1,(A0,D0.L) PAGE_TABLE_OFFSET:=A1=KERNEL PART ADDRESS;
PRT_MEM PGTABSET,<(A0,D0.L)>,4 ********
RETURN .PGTABSE RETURN;
PGTABGET EQU * GET ENTRY FROM PAGE TABLE : KERNEL PART ADDRESS.
* CALL: RETURN:
* D3 USER PART TOP ADDRESS SAME
* A1 ANY KERNEL PART ADDRESS
*
MOVE.L D3,-(A7) SAVE D3;
LSR.L #6,D3 D3:=D3 SHIFT -6,"RELATIVE ENTRY ADDRESS"
MOVE.L PAGE_TAB,A1 A1:=BASE OF PAGE TABLE;
PRT_MEM PGTABGET,<(A1,D3.L)>,4 ********
MOVE.L (A1,D3.L),A1 A1:=KERNEL PART ADDRESS:=CONTENT OF ENTRY;
MOVE.L (A7)+,D3 RESTORE D3;
RTS RETURN;
PAGE
CHAIN_IT EQU * CHAIN NEW ELEMENT NEXT TO OLD ELEMENT
* CALL: RETURN:
* A4 OLD ELEMENT SAME
* A0 NEW ELEMENT SAME
* A2 ANY ELEMENT NEXT TO NEW ELEMENT
*
* OLD ELEMENT IS A CHAIN HEAD OR A CHAIN MEMBER
*
MOVE.L (A4),A2 A2:=OLDNEXT:=OLD.NXT;
MOVEM.L A2/A4,(A0) NEW.NXT:=A2:=OLDNEXT;NEW.PRV:=A4:=OLD;
MOVE.L A0,4(A2) OLDNEXT.PRV:=A0:=NEW;
MOVE.L A0,(A4) OLD.NXT:=A0:=NEW;
RTS
CHAINOWN EQU * CHAIN OBJECT TO NIL POINTER OR OWN POINTER
* CALL: RETURN:
* A0 KERNEL PART OF OBJECT SAME
* A3 OWNER ENV OR CTX SAME
* D3.W POINTER OFFSET INTO ENV OR CTX SAME
* A2 ANY OWNER POINTER ADDRESS
*
* (A3,D3.W) MUST BE THE ADDRESS OF A POINTER VARIABLE.
* THE CHAIN FIELD OF THE VARIABLE MAY BE THE HEAD OF AN OWNER SET
* OR IT MAY POINT TO ITSELF. THE OBJECT BECOMES THE LAST MEMBER
* OF THE POINTER CHAIN. THE POINTER KIND IS SET TO OWNER_SET;
*
MOVE.L A4,-(A7) SAVE A4;
MOVE.L 4(A3,D3.W),A4 A4:=LAST IN POINTER CHAIN;
BSR.S CHAIN_IT INSERT KERNEL PART NEXT TO LAST IN POINTER
* A2:= OWNER POINTER;
MOVE.L A3,OB_OWN(A0) OBJECT.OWNER_STRUCT:=OWNER ENV OR CTX
MOVE.W D3,OB_OFF(A0) OBJECT.OWNER_OFFSET:=POINTER OFFSET
MOVE.B #PT_OWN,PT_KIN(A2) OWNER POINTER.KIND:=OWN_SET
MOVE.L (A7)+,A4 RESTORE A4;
RTS RETURN;
CHAINMAN EQU * CHAIN ENVELOPE TO NIL POINTER OR MANAGER POINTER
* CALL: RETURN:
* A0 ENVELOPE SAME
* A3 MANAGER ENVELOPE SAME
* D3 POINTER OFFSET INTO MANAGER ENVELOPE SAME
* A2 ANY MANAGER POINTER ADDRESS
*
* (A3,D3.W) MUST BE THE ADDRESS OF A POINTER VARIABLE.
* THE FIRST FIELDS OF AN ENVELOPE HAS THE SAME FORMAT AS AN OBJECT.
* THEREFORE CHAINOWN MAY BE USED.
*
BSR.S CHAINOWN CHAIN ENVELOPE AS LAST MEMBER OF THE CHAIN
MOVE.B #PT_MAN,PT_KIN(A2) MANAGER_POINTER.KIND:=MAN_SET;
RTS RETURN;
PAGE
SIMPLEPT EQU * CREATE SIMPLE POINTER TO OBJECT;
* CALL RETURN
* A0 NIL POINTER SAME
* A4 OBJECT SAME
*
ENTRYSAV D0/D1/A2/A4,.SIMPLEP SAVE REGS;
MOVE.L A4,PT_REF(A0) POINT.REF:=OBJECT;
MOVE.B OB_KIN(A4),D0 D0.B:=OBJECT KIND;
LEA OB_REF(A4),A4 A4:=REF_OBJECT CHAIN HEAD;
BSR.S CHAIN_IT CHAIN POINTER TO REF_OBJECT CHAIN;
MOVE.B #PT_OBJ,PT_KIN(A0) POINTER KIND:=REF_OBJECT
MOVE.W CC_MASK(PC),D1 D1:= CALLABLE OBJECT KINDS
BTST.L D0,D1 TEST THAT BIT # D0.B IS SET IN D1
IF <NE> THEN.S IF CALL CAP MAKE SENSE THEN
ORI.B #1<<PT_CC,PT_INF(A0) ASSIGN CALL CAP TO POINTER;
ENDI ENDI;
RETURN .SIMPLEP RETURN;
* CALLABLE OBJECTS:
CC_MASK DC.W 1<<OB_GEOB+1<<OB_GAOB+1<<OB_COOB+1<<OB_ALLO+1<<OB_SCHE
INIT_ENV EQU * INITIALIZE ENVELOPE
* CALL RETURN:
* D0=SIZE OF ENVELOPE INCLUDING LOCAL POINTERS SAME
* A3=ENVELOPE ADDRESS SAME
* A6=SPACE_DESC OF OBJECT SAME
*
* FUNCTION: INITIALIZE AN EMPTY ENVELOPE ON TOP OF THE ENVELOPE STACK.
*
ENTRYSAV A0/A2/A4,.INIT_EN SAVE REGISTERS;
LEA EN_STK(A3),A0 A0:=STACK CHAIN_ELEMENT
MOVE.L SP_ENV+4(A6),A4 A4:=LAST ELEMENT IN ENVELOPE STACK
BSR.S CHAIN_IT CHAIN ENVELOPE AS LAST IN ENVELOPE STACK
* A2:=HEAD OF STACK CHAIN
LEA EN_REF(A3),A0 A0:=HEAD OF REF_ENV CHAIN
MOVE.L A0,(A0) REF_ENV CHAIN:=EMPTY
MOVE.L A0,4(A0)
LEA EN_SIZ(A3),A2 A2:=CURRENT POINTER:=FIRST POINTER;
* ASSIGN ZERO TO TERM_PROC, SIZE_VALUES, AND -COUNT.
LEA EN_TERM(A3),A4 A4:= FIRST WORD TO BE CLERED; A2=TOP;
REPEAT REPEAT
CLR.W (A4)+ ASSIGN ZERO; A4:=NEXT WORD;
UNTIL.L A4 <EQ> A2 UNTIL NEXT_WORD = TOP;
LEA (A3,D0.W),A4 A4:=TOP LOCAL POINTER
MOVE.L #$FFFFFF,EN_MAXU(A3) SIZ_MAX:= MAX_VAL
MOVE.W #$7FFF,EN_MAXK(A3) .
MOVE.W #1,EN_COU(A3) INITIALLY=1 (OR 0?)
*INIT LOCAL POINTERS.
WHILE.L A2 <NE> A4 DO.S WHILE CURRENT_POINTER <> TOP POINTER DO
MOVE.L A2,(A2) CURRENT POINTER CHAIN
MOVE.L A2,4(A2) :=EMPTY;
MOVE.W #PT_NIL<<8+1<<PT_LSC,PT_KIN(A2) POINTER.KIND:=NIL
* POINTER.INF:=LOCAL;
LEA PT_SIZ(A2),A2 CURRENT POINTER:=NEXT_POINTER;
ENDW ENDW;
PRT_MEM INIT_ENV,(A3),EN_SIZ+3*PT_SIZ ********
PRT_MEM TOPOFENV,(A4),SP_SIZ ********
RETURN .INIT_EN RETURN;
PAGE
INITGEIN EQU * INITIALIZE GENERAL PART OF STUB OR SCHEDULER OBJECT.
* CALL RETURN
* A0=KERNEL PART OF OBJECT SAME
* A1=ENTRY POINT OF CODE SEGMENT UNDEF
*
* FUNCTION: ASSIGN ENTRY POINT, EX_CHAIN,CONTROL_PROC,NO_OF_TEMP POINTER/BYTES,
* STACK ADDRESS, REQUIRED FREE STACK SPACE,OBJECT STATE;
MOVE.L A1,GE_ENT(A0) ENTRY POINT OF OBJECT:=A1;
MOVE.W #OB_GEOB<<8+1<<OB_REEN+1<<OB_OCC,OB_KIN(A0) OBJ.KIND:=GENERAL;
* OBJ.STATE:= REENTRANT+OWNERS CALL CAP;
MOVEA.L OB_SPA(A0),A1 A1:=SPACE DESCR OF OBJECT
SUBI.W #(GE_SIZ-OB_SIZ),SP_FREK(A1) RESERVE ROOM FOR GENERAL FIELDS
ADDI.L #(GE_SIZ-OB_SIZ),SP_FIRK(A1) .
LEA GE_EX(A0),A1 A1:=HEAD OF EXECUTED_BY CHAIN;
MOVE.L A1,(A1) EXECUTED_BY CHAIN
MOVE.L A1,4(A1) := EMPTY;
CLR.W GE_CON(A0) CONTROL PROCEDURE:=NO CONTROL:=0;
MOVE.W #SCHTEMP,GE_TEMP(A0) INITIALIZE NO_OF_TEMP POINTERS IN CONTEXT
MOVE.L #SCHTEMD,GE_TEMD(A0) INITIALIZE NO OF TEMP BYTES IN CONTEXTS;
MOVE.L #FL_TEMPD,GE_STKM(A0) LOGICAL ADDRESS OF FIRST OF STACK;
CLR.W GE_STK(A0) REQUIRED FREE CALL STACK
CLR.L GE_STK+2(A0) := 0;
PRT_MEM INITGEIN,(A0),GE_SIZ ********
RTS
* NOTE, THAT SIZE OF REQUIRED FREE CALL STACK IS SET TO ZERO.
* MANY VALUES ARE REASSIGNED WHEN A0 IS THE STUB.
PAGE
INITKNEL EQU * INITIALIZE OB AND SP FIELDS OF OBJECT.
* CALL: RETURN:
* A0 KERNEL PART SAME
* D0 LENGTH OF KERNEL PART SAME
*
* AFTER INITKNEL, THE FOLLOWING IS TRUE
* THE SPACE PART DESCRIBES THE FREE KERNEL BYTES
* THE ENVELOPE STACK IS EMPTY
* SIZE OF KERNEL PART AND ADDRESS OF SPACE PART IS SAVED IN OBJECT
* RESIDENT COUNT IS ZERO
* THE OWNER CHAIN AND REF_OBJECT CHAIN IS EMPTY.
ENTRYSAV D0/A0/A1/A2,.INITKNE SAVE REGISTERS;
LEA (A0,D0.L),A2 A2:=SPACE PART:=KNELPART+LENGTH OF KNELPA
MOVE.L A2,OB_SPA(A0) SAVE SPACE PART ADDRESS IN OBJECT;
MOVE.W D0,OB_SIZK(A0) SAVE LENGTH OF KNEL PART;
SUBI.W #OB_SIZ+SP_SIZ,D0 D0:=FREE_KNEL_BYTES:=LENGTH-FIXED
MOVE.W D0,SP_FREK(A2) SAVE FREE_KNEL_BYTES IN SPACE PART OF OBJ
LEA OB_SIZ(A0),A1 A1:=FIRST FREE KERNEL BYTE;
MOVE.L A1,SP_FIRK(A2) SAVE FIRST_FREE_KERNEL_BYTE IN SPACE PART;
CLR.L SP_SIZU(A2) NO USER PART IS PRESENT;
LEA SP_ENV(A2),A2 A2:=ENVELOPE STACK;
MOVE.L A2,(A2) ENVELOPE STACK:=EMPTY;
MOVE.L A2,4(A2) .
MOVE.L A0,(A0) OWNSET CHAIN:=EMPTY;
MOVE.L A0,4(A0) .
LEA OB_REF(A0),A2 A2:=OB_REF CHAIN HEAD;
MOVE.L A2,(A2) OB_REF CHAIN:=EMPTY;
MOVE.L A2,4(A2) .
CLR.W OB_RES(A0) RESIDENT COUNT:=0;
PRT_MEM INITKNEL,(A0),OB_SIZ ********
RETURN .INITKNE RETURN
ASSIGNUS EQU * ASSIGN USER PART TO KERNEL PART OF OBJECT
* CALL: RETURN:
* A0 USER PART OR ANY, SAME, OR 0 WHEN D1=0
* WHEN D1=0
* A1 KNEL PART SAME
* D1.L SIZE OF USER PART OR 0 SAME
ENTRYSAV D0/A2,.ASSIGNU SAVE REGS;
TST.L D1
IF <EQ> THEN.S IF SIZE USER PART = 0 THEN
MOVE.L D1,A0 USER PART ADDRESS:=0;
ENDI ENDI;
MOVE.L OB_SPA(A1),A2 A2:=SPACE PART;
MOVE.L A0,SP_FIRU(A2) SAVE USER PART ADDRESS;
MOVE.L D1,SP_FREU(A2) FREE USER BYTES:=SIZE OF USER PART;
MOVE.L D1,SP_SIZU(A2) SAVE SIZE OF USER PART;
PRT_MEM ASSIGNUS,-SP_SIZ(A2),SP_SIZ ********
LEA (A0,D1.L),A2 A2:=TOP USER PART:=USER PART+SIZE OF USER
IF.W A2 <NE> #0 THEN.S IF USER PART PRESENT THEN
MOVE.L A2,D0 D0:=TOP USER PART;
BSR.L PGTABSET PAGE TABLE (TOP USER PART):=KNEL PART=A1;
ENDI ENDI;
RETURN .ASSIGNU RETURN;
PAGE
REMOVEUS EQU * REMOVE USER PART
* CALL: RETURN:
* D1 NO_OF_BYTES SAME
* A1 USER PART ADDRESS UNDEF
* A0 ANY UNDEF
*
BSR.S GETUREC A0:=MEM_REC HOLDING THE USER PART;
BSR.L RECHAINR REMOVE AND RESTRUCTURE (D1,A0,A1);
RTS RETURN;
REMOVEKN EQU * REMOVE KNEL PART
* CALL: RETURN:
* D1 NO_OF_BYTES SAME
* A1 KERNEL PART ADDRESS UNDEF
* A0 ANY UNDEF
*
BSR.S GETKREC A0:=MEM_REC HOLDING THE KERNEL PART;
BSR.L RECHAINR REMOVE AND RESTRUCTURE (D1,A0,A1);
RTS RETURN;
GETUREC EQU * GET MEM_REC HOLDING USER PART
* CALL: RETURN:
* A1 USER PART SAME
* A0 ANY MEM_REC
*
MOVE.L L_ALLOC,A0 A0:=LAST MEM_REC; "=DUMMY MEM_REC"
REPEAT REPEAT
MOVE.L MR_PRV(A0),A0 A0:=PRIOR MEM_REC;
UNTIL.L A0 <LT> A1 UNTIL PRIOR MEM_REC HOLDS USER PART;
RTS RETURN;
GETKREC EQU * GET MEM_REC HOLDING KERNEL PART
* CALL: RETURN:
* A1 KERNEL PART SAME
* A0 ANY MEM_REC
*
MOVE.L F_ALLOC,A0 A0:=FIRST MEM_REC; "NOT DUMMY"
REPEAT REPEAT
MOVE.L (A0),A0 A0:=NEXT MEM_REC;
UNTIL.L A0 <GT> A1 UNTIL NEXT MEM_REC IS NEXT TO KERNEL PART
MOVE.L MR_PRV(A0),A0 A0:=PRIOR MEM_REC;
RTS RETURN;
PAGE
CREATEUS EQU * CREATE USER PART
* CALL: RETURN:
* D1 NO_OF_BYTES IN USER PART SAME
* A0 MEM_REC TO HOLD NEW USER PART USER PART ADDRESS
*
ENTRYSAV D7/A1,.CREATEU SAVE REGS;
* COMPUTE ADDRESS OF NEW USER PART
* A USER PART IS ALWAYS LOCATED IN THE HIGH ADDRESS PART OF THE FREE AREA
MOVE.L MR_FST(A0),A1 A1:=USER_PART_ADDRESS:=MEM_REC.FIRST_FREE
ADDA.L MR_FRE(A0),A1 + MEM_REC.FREE_BYTES
SUBA.L D1,A1 - NUMBER OF BYTES IN USER PART;
MOVEQ #-1,D7 D7:=-1=USER_PART_CREATE;
BSR.S RECHAINC CREATE AND RESTRUCTURE (D1,D7,A0,A1);
MOVE.L A1,A0 A0:=USER PART ADDRESS;
RETURN .CREATEU RETURN;
CREATEKN EQU * CREATE KERNEL PART
* CALL: RETURN:
* D1 NO OF BYTES IN KERNEL PART SAME
* A0 MEM_REC TO HOLD NEW KERNEL PART KERNEL PART ADDRESS
*
ENTRYSAV D7/A1,.CREATEK SAVE REGS;
* COMPUTE ADDRESS OF NEW KERNEL PART
* A KERNEL PART IS ALWAYS LOCATED IN THE LOW ADDRESS PART OF THE FREE AREA
MOVE.L MR_FST(A0),A1 A1:=KERNEL PART ADDRESS:=MEM_REC.FIRST_FRE
MOVEQ #+1,D7 D7:=1=KERNEL PART CREATE;
BSR.S RECHAINC CREATE AND RESTRUCTURE (D1,D7,A0,A1);
MOVE.L A1,A0 A0:=KERNEL PART ADDRESS;
RETURN .CREATEK RETURN;
PAGE
RECHAINC EQU * RECHAIN MEM_RECS AFTER CREATION OF A KERNEL OR USER PART
* CALL: RETURN:
* D1 #BYTES SAME
* D7 TYPE: 1 = KERNEL,FF = USER SAME
* A0 DESTIN_REC "TO HOLD NEW PART" UNDEF
* A1 PART "TO BE CREATED" SAME
*
* THE NEW PART IS ALLOCATED SOMEWHERE IN THE FREE AREA OF THE MEM_REC.
*
ENTRYSAV D0/A1-A6,.CHAINC SAVE REGS
CLR.W D0 D0:=FIX_TYP:=0 SHIFT 8
MOVE.B MR_TYP(A0),D0 + DESTIN_REC.TYPE;
MOVEM.L (A0),A5/A6 A5/A6:=DESTIN_REC.NEXT/PREV;
LEA (A1,D1.L),A2 A2:=TOP_PART:=PART+#BYTES;
MOVE.L MR_FST(A0),A3 A3:=TOP_FREE:=DESTIN_REC.FIRST
ADD.L MR_FRE(A0),A3 + DESTIN_REC.FREE_BYTES;
IF.L A1 <EQ> A0 THEN.S IF DESTIN_REC=PART THEN "1 OR 4"
IF.L A3 <EQ> A2 THEN.S IF TOP_FREE=TOP_PART THEN
LEA CASE_C4,A4 A4:=PROC:=CREATE_4;
PRT_REG C4 ********
ELSE.S ELSE
LEA CASE_C1,A4 A4:=PROC:=CREATE_1;
PRT_REG C1 ********
ENDI ENDI;
ELSE.S ELSE
IF.L A3 <EQ> A2 THEN.S IF TOP_FREE=TOP_PART THEN
LEA CASE_C3,A4 A4:=PROC:=CREATE_3;
PRT_REG C3 ********
ELSE.S ELSE
LEA CASE_C2,A4 A4:=PROC:=CREATE_2;
PRT_REG C2 ********
ENDI ENDI;
ENDI ENDI;
JSR (A4) CALL PROC;
PRT_MEM OLD_A0,(A0),MR_SIZ ********
PRT_MEM PRV_A6,(A6),MR_SIZ ********
PRT_MEM NEW_A2,(A2),MR_SIZ ********
PRT_MEM NXT_A5,(A5),MR_SIZ ********
RETURN .CHAINC RETURN;
PAGE
CASE_C1 EQU * PROC CREATE_1;
* THIS CASE IS THE REVERSE OF CASE_R3.
* PART IS INCLUDED IN USED AREA OF PRIOR MEM_REC,
* CREATE NEW MEM_REC_HEAD AFTER PART
SUB.L A2,A3 A3:=FREE:=TOP_FREE-TOP_PART;
NEWHEAD A2,D0,A6,A5 NEWHEAD(NEW_HEAD,TYPE,PRIOR,NEXT);
MOVE.L A3,MR_FRE(A2) NEW_HEAD.FREE_BYTES:=FREE;
MOVE.B D7,MR_TYP(A6) PREV_REC.TYPE:=TYPE;
RTS
CASE_C2 EQU * PROC CREATE_2;
* THIS CASE IS THE REVERSE OF CASE_R4.
* PART IS PLACED BETWEEN THE HEAD OF THE MEM_REC AND TOP_FREE.
* DESTIN_REC IS DIVIDED IN TWO MEM_REC:
MOVE.L A0,A6 A6=PRIOR_REC:=DESTIN_REC;
BSR.S CASE_C1 CALL CREATE_1; A3:= TOP_FREE-TOP_PART;
MOVE.L D1,D0 D0:=REMOVE:= #BYTES
ADD.L A3,D0 + (TOP_FREE-TOP_PART);
SUB.L D0,MR_FRE(A0) DESTIN_REC.FREE_BYTES:=...-REMOVED;
RTS RETURN;
CASE_C3 EQU * PROC CREATE_3;
* THIS CASE IS THE REVERSE OF CASE_R1
* PART IS PLACED IN THE HIGH ADDRESS END OF THE FREE AREA.
* ADJUST FREE_BYTES,
SUB.L D1,MR_FRE(A0) DESTIN_REC.FREE_BYTES:=...-#BYTES;
MOVE.B D7,MR_TYP(A0) DESTIN_REC.TYPE := TYPE;
RTS RETURN;
CASE_C4 EQU * PROC CREATE_4;
* THIS CASE IS THE REVERSE OF CASE_R2
* PART FITS THE HOLE BETWEEN TWO USED AREAS OF THE SAME TYPE (?)
* INCLUDED DESTIN_REC IN THE AREA OF THE PREVIOUS RECORD.
MOVE.L A5,(A6) PREV_REC.NEXT:=NEXT_REC
MOVE.L A6,MR_PRV(A5) NEXT_REC.PREV:=PREV_REC
RTS RETURN;
PAGE
RECHAINR EQU * RECHAIN MEM_RECS AFTER REMOVAL OF KERNEL OR USER PART
* CALL: RETURN:
* D1 #BYTES SAME
* A0 DESTIN_REC "HOLDS PART" UNDEF
* A1 PART "TO BE REMOVED" UNDEF
*
* PART IS LOCATED SOMEWHERE IN THE USED AREA OF DESTIN_REC
*
ENTRYSAV D0/D7/A2-A5,.CHAINR SAVE REGS;
CLR.W D0 D0:=FIX_TYP:=DYNAMIC SHIFT 8
MOVE.B MR_TYP(A0),D0 + DESTIN_REC.TYPE;
MOVE.L (A0),A5 A5:=TOP_USED:=NEXT_REC:=DESTIN_REC.NEXT;
LEA (A1,D1.L),A2 A2:=TOP_PART:=PART+#BYTES;
MOVE.L MR_FST(A0),A3 A3:=TOP_FREE:=SOURCE_REC.FIRST
ADD.L MR_FRE(A0),A3 + DESTIN_REC.FREE_BYTES;
IF.L A1 <EQ> A3 THEN.S IF PART=TOP_FREE THEN
IF.L A2 <EQ> A5 THEN.S IF TOP_PART=TOP_USED THEN
LEA CASE_R4,A4 A4:=PROC:=REMOVED_4
PRT_REG R4 ********
ELSE.S ELSE
LEA CASE_R1,A4 A4:=PROC:=REMOVED_1
PRT_REG R1 ********
ENDI ENDI;
ELSE.S ELSE
IF.L A2 <EQ> A5 THEN.S IF TOP_PART=NEXT_REC THEN
LEA CASE_R3,A4 A4:=PROC:=REMOVE_3;
PRT_REG R3 ********
ELSE.S ELSE
LEA CASE_R2,A4 A4:=PROC:=REMOVE_2;
PRT_REG R2 ********
ENDI ENDI;
ENDI ENDI;
PRT_MEM OLD_A5,(A5),MR_SIZ ********
JSR (A4) CALL PROC;
PRT_MEM NNXTA5,(A5),MR_SIZ ********
PRT_MEM OLD_A0,(A0),MR_SIZ ********
PRT_MEM NEW_A1,(A1),MR_SIZ ********
RETURN .CHAINR RETURN;
PAGE
CASE_R1 EQU * PROC REMOVE_1;
* THIS CASE IS THE REVERSE OF CASE_C3
* PART IS PRESENT AS THE FIRST BYTES OF THE USED AREA OF DESTIN_REC
* ADJUST FREE BYTES
ADD.L D1,MR_FRE(A0) DESTIN_REC.FREE_BYTES:=...+#BYTES;
RTS RETURN;
CASE_R2 EQU * PROC REMOVE_2;
* THIS CASE IS THE REVERSE OF CASE_C4
* PART IS PRESENT IN THE MIDDLE OF THE USED AREA OF DESTIN_REC
* DIVIDE DESTIN_REC IN TWO MEM_RECS.
NEWHEAD A1,D0,A0,A5 NEWHEAD(NEW_HEAD,TYPE,PRIOR,NEXT);
MOVE.L D1,MR_FRE(A1) NEW_HEAD.FREE_BYTES:=#BYTES;
RTS RETURN;
CASE_R3 EQU * PROC REMOVE_3;
* THIS CASE IS THE REVERSE OF CASE_C1
* PART IS PRESENT AT THE BOTTOM OF THE USED AREA OF DESTIN_REC;
* EXTEND THE FREE ARE OF NEXT_REC, UNLESS NEXT_REC IS AN INITIAL MEM_REC.
TST.B MR_FIX(A5)
IF <NE> THEN.S IF NEXT_REC IS AN INITIAL MEM_REC THEN
CLR.W D0 D0:=FIX_TYPE:=DYNAMIC+EMPTY
BRA.S CASE_R2 GOTO REMOVE_2;
ENDI ENDI;
MOVE.B MR_TYP(A5),D0 D0:=FIX_TYPE:=DYNAMIC+NEXT_REC.TYPE;
MOVE.L MR_FRE(A5),D7 D7:=NEXT_FREE:=NEXT_REC.FREE_BYTES
MOVE.L (A5),A5 A5:=NEXT_REC:=NEXT_REC.NEXT;
BSR.S CASE_R2 CALL REMOVE_2
ADD.L D7,MR_FRE(A1) NEW_HEAD.FREE_BYTES:=...+NEXT_FREE;
RTS RETURN;
CASE_R4 EQU * PROC REMOVE_4
* THIS CASE IS THE REVERSE OF CASE_C2
* PART EQUALS THE WHOLE USED AREA OF DESTIN_REC
* COMBINE DESTIN_REC AND NEXT_REC, UNLESS NEXT_REC IS AN INITIAL MEM_REC.
TST.B MR_FIX(A5)
IF <NE> THEN.S IF NEXT_REC IS AN INITIAL MEM_REC THEN
CLR.B MR_TYP(A0) DESTIN_REC.TYPE:=FREE:=0;
BRA.S CASE_R1 GOTO REMOVE_1;
ENDI ENDI;
MOVE.L MR_FRE(A5),D7 D7:=EXTRA_FREE:=NEXT_REC.FREE_BYTES
ADD.L D1,D7 + #BYTES
ADD.L D7,MR_FRE(A0) DESTIN_REC.FREE_BYTES:=...+EXTRA_FREE;
MOVE.B MR_TYP(A5),MR_TYP(A0) DESTIN_REC.TYPE:= NEXT_REC.TYPE;
MOVE.L (A5),A5 A5:=NEXT_REC:=NEXT_REC.NEXT;
MOVE.L A5,(A0) DESTIN_REC.NEXT:=NEXT_REC;
MOVE.L A0,MR_PRV(A5) NEXT_REC.PRV:= DESTIN_REC;
RTS RETURN;
PAGE
USERGET EQU * PARAMETER LIST TO GETROOM WHEN A KERNEL PART IS CREATED
BRA.L SEARCHUS SEARCH FOR USER SPACE
BRA.L COMPUSER COMPRESS USER PARTS
BRA.L COMPKNEL COMPRESS KERNEL PARTS
KNELGET EQU * PARAMETER LIST TO GETROOM WHEN A USER PART IS CREATED.
BRA.L SEARCHKN SEARCH FOR KERNEL SPACE
BRA.L COMPKNEL COMPRESS KERNEL PARTS
BRA.L COMPUSER COMPRESS USER PARTS
* OFFSETS INTO THE PARAMETER LISTS ABOVE
SEARCH EQU 0 SEARCH PROCEDURE
COMPRESS EQU 4 COMPRESS PROCEDURE
OPPOSITE EQU 8 COMPRESS OPPOSITE PROCEDURE
GETROOM EQU * GET ROOM FOR A USER OR KERNEL PART
* CALL: RETURN:
* D1 NO_OF_BYTES SAME
* A0 PROC ADDRESS MEM_RECORD, OR 0 WHEN NO ROOM.
*
MOVE.L A1,-(A7) SAVE A1;
MOVE.L A0,A1 A1 := PROC ADDRESS;
JSR (A1) PROC.SEARCH(D1=NO_OF_BYTES,A0:=MEM_REC);
IF.W A0 <NE> #0 THEN.S IF MEM_REC WAS FOUND THEN
MOVE.L (A7)+,A1 RESTORE A1;
RTS RETURN;
ENDI ENDI;
JSR COMPRESS(A1) PROC.COMPRESS(D1=NO_OF_BYTES,A0:=MEM_REC OR
IF.W A0 <NE> #0 THEN.S IF MEM_REC WAS FOUND THEN
MOVE.L (A7)+,A1 RESTORE A1;
RTS RETURN;
ENDI ENDI;
MOVE.L D1,-(A7) SAVE D1;
MOVE.L #$FFFFFF,D1 D1 := VERY BIG SIZE; "CANNOT BE FOUND"
JSR OPPOSITE(A1) PROC.OPPOSITE(D1=VERY BIG, A0:=0);
MOVE.L (A7)+,D1 RESTORE D1;
JSR (A1) PROC.SEARCH(D1=#BYTES,A0:=MEM_REC/0);
MOVE.L (A7)+,A1 RESTORE A1;
RTS RETURN;
PAGE
SEARCHUS EQU * SEARCH FOR FREE SPACE TO A USER PART
* CALL: RETURN:
* D1 NO_OF_BYTES SAME "AN INTERGRAL NUMBER OF PAGES"
* A0 ANY MEM_REC, OR 0 WHEN NO SPAVCE IS AVAILABLE
*
* A USER PART CAN BE ALLOCATED IN A MEM_REC CONTAINING OTHER USER PARTS,
* OR IN AN EMPTY MEM_REC POSITIONED AFTER THE LAST KERNEL PART IN THE SYSTEM
*
ENTRYSAV D2/A1,.SEARCHU SAVE REGS;
MOVE.L L_ALLOC,A0 A0:=CUR_MEM_REC:=LAST_DUMMY_MEM_REC;
REPEAT REPEAT
MOVE.L MR_PRV(A0),A0 A0:=CUR_MEM_REC:=CUR_MEM_REC.PREV;
PRT_MEM SEARCHUS,(A0),MR_SIZ ********
TST.B MR_TYP(A0)
IF <GT> THEN.S IF CUR_MEM_REC.TYPE=KERNEL THEN
NO_ROOM1 EQU * NO_ROOM:
MOVE.W #0,A0 A0:=NO_SPACE:=0;
RETURN .SEARCHU RETURN;
ENDI ENDI;
MOVE.L MR_FRE(A0),D2 D2:=FREE:=CUR_MEM_REC.FREE_BYTES;
UNTIL.L D1 <LE> D2 UNTIL NO_OF_BYTES<=FREE;
MOVE.L MR_PRV(A0),A1 A1:=PREVCUR:=CUR_MEM_REC.PREV;
TST.B MR_TYP(A1)
IF <GT> THEN.S IF PREVCUR.TYPE=KERNEL THEN
TST.B MR_FIX(A0)
IF <NE> THEN.S IF CUR_MEM_REC IS NOT FIXED THEN
SUBI.L #MR_SIZ,D2 D2:=FREE:=FREE-HEAD_SIZE;
IF.L D1 <GT> D2 THEN.S IF NO_OF_BYTES > FREE THEN
BRA.S NO_ROOM1 GOTO NO_ROOM;
ENDI ENDI;
ENDI ENDI;
ENDI ENDI;
RETURN .SEARCHU RETURN;
COMPUSER EQU * COMPRESS USER PARTS TO GENERATE FREE SPACE.
* CALL: RETURN:
* D1 NO_OF_BYTES SAME
* A0 ANY MEM_REC, OR 0 WHEN REQUIRED SPACE WAS NOT GENERATED.
*
* MOVES ALL USER PARTS TOWARDS THE HIGH ADDRESS END OF THE RAM AREA.
* IF A HOLE IS CREATED DURING THIS PROCESS WITH A SIZE >= D1, THE PROCEDURE
* RETURNS IMMEDIATELY WITH A0 POINTING TO THAT HOLE.
*
REPEAT REPEAT
BSR.S C_UPARTS COMPRESS EACH USER RAM(D1,A0:=MEM_REC);
CMPA.W #0,A0 TEST A0.L
IF <NE> THEN.S IF A MEM_REC WAS RETURNED IN A0 THEN
RTS RETURN, "OK"
ENDI ENDI;
BSR.L M_UACROS MOVE USER ACROSS NO_RAM(D1,A0:=RESULT)
CMPA.W #0,A0 TEST A0.L
UNTIL <EQ> UNTIL RESULT=NOTHING MOVED;
RTS RETURN;
PAGE
C_UPARTS EQU * COMPRESS EACH USER RAM AREA TO GENERATE FREE SPACE
* CALL: RETURN:
* D1 NO_OF_BYTES SAME
* A0 ANY MEM_REC, OR 0 WHEN REQUIRED SPACE WAS NOT AVAILABLE
*
* ALL CONSEQUTIVE RAM AREAS HOLDING USER PARTS ARE PROCESSED
* THE USER PARTS ARE PLACED IN THE HIGH ADDRESS PART OF ITS RAM AREA
PROCSAVE D2/D3/D5/A1-A5,USAVPRT
MOVE.L L_ALLOC,A2 A2:=TOP_REC:=LAST DUMMY MEM_REC
REPEAT A2 IS A FIXED MEMREC REPEAT "COMBINE LAST AND PREV"
MOVE.L MR_PRV(A2),A0 A0:=LAST_REC:=TOP_REC.PREV;
MOVE.L MR_PRV(A0),A4 A4:=PREV_REC:=LAST_REC.PREV;
PRT_MEM C_U_PREV,(A4),MR_SIZ ********
TST.B MR_TYP(A4)
IF <GT> THEN.S IF PREV_REC.TYPE = KERNEL THEN
BRA.S EXIT1 GOTO EXIT; "ALL HAS BEEN PROCESSED"
ENDI ENDI;
TST.B MR_FIX(A0) TEST WHETHER RAM_AREA=ONE MEM_REC
IF <GT> THEN.S IF LAST_REC IS AN INITIAL MEM_REC THEN
MOVE.L A0,A2 A2:=TOP_REC:=LAST_REC;
ELSE.S ELSE
* COMPUTE SOURCE ADDRESSES OF PARTS TO BE MOVED
MOVE.L MR_FST(A4),D2 D2:=FIRST_SOURCE:=
ADD.L MR_FRE(A4),D2 PREV_REC.FIRST+PREV_REC.FREE_BYTES;
MOVE.L A0,D3 D3:=TOP_SOURCE:=LAST_MEM_REC;
* UPDATE MEM_REC STRUCTURE: COMBINE LAST AND PREV;
MOVE.L A2,MR_NXT(A4) TOP_REC.NEXT:=PREV_REC;
MOVE.L A4,MR_PRV(A2) PREV_REC.NEXT:=TOP_REC;
MOVE.L MR_FRE(A0),D5 D5:= EXTRA:= LAST_REC.FREE_BYTES;
ADD.L D5,MR_FRE(A4) PREV_REC.FREE_BYTES:= ... + EXTRA ;
MOVE.B #-1,MR_TYP(A4) PREV_REC.TYPE:=USER;
* COMPUTE DESTINATION ADDRESS OF PARTS TO BE MOVED: A0:=TOP_DESTIN:=
ADD.L MR_FRE(A0),A0 LAST_REC+LAST_REC.FREE_BYTES;
* MOVE USER PARTS,
REPEAT A4 CANNOT BE FREE REPEAT "MOVE ONE USER PART"
BSR.L PGTABGET A1:=KERNEL PART:=PAGETABLE(D3);
MOVE.L OB_SPA(A1),A5 A5:=TOP_KERNEL_PART;
MOVE.L SP_SIZU(A5),D5 D5:=SIZE; "OF KERNEL PART TO BE MOVED"
PRT_REG C_U_REGS ********
BSR.L MOVEUSER MOVEUSER (A0=TOP_DESTIN,A1=KERNEL PART);
SUB.L D5,A0 TOP_DESTIN:=TOP_DESTIN-SIZE;
SUB.L D5,D3 TOP_SOURCE:=TOP_SOURCE-SIZE;
UNTIL.L D2 <EQ> D3 UNTIL TOP_SOURCE=FIRST_SOURCE;
ENDI ENDI;
UNTIL.L MR_FRE(A4) <GE> D1 UNTIL PREV_REC.FREE_BYTES>=NO_OF_BYTES;
MOVE.L A4,A0 A0:=LAST_REC:=PREV_REC;
MOVE.L MR_PRV(A0),A4 A4:=PREV_REC:=LAST_REC.PREV;
TST.B MR_TYP(A4)
EXIT1 EQU * EXIT1:
IF <GT> THEN.S IF PREV_REC.TYPE=KERNEL THEN
MOVEQ #MR_SIZ,D5 D5:=HEAD_PLUS_BYTES:=HEAD_SIZE
ADD.L D1,D5 + NO_OF_BYTES;
IF.L D5 <GT> MR_FRE(A0) THEN.S IF HEAD_PLUS_BYTES>LAST_REC.FREE_BYTES THEN
MOVE.W #0,A0 A0=LAST_REC:=NO SPACE:=0;
ENDI ENDI;
ENDI ENDI;
PROCRTRN USAVPRT RETURN; "OK/NOT_OK"
PAGE
M_UACROS EQU * MOVE USER PARTS ACROSS NO_RAM AREAS.
* CALL: RETURN:
* D1 #BYTES SAME "THE CALL VALUE IS NOT USED AT PRESENT
* A0 ANY = 0 WHEN NOTHING HAS BEEN MOVED, <> 0 OTHERWISE
*
* USER PARTS FROM THE FIRST USER MEM_REC IS MOVED TO THE FREE PART OF
* MEM_RECS AT HIGHER ADDRESSES.
PROCSAVE D0-D3/A1-A3,USAVCRS
MOVE.L L_ALLOC,A2 A2:=CUR_REC:=LAST MEM_REC;
REPEAT REPEAT
MOVE.L MR_PRV(A2),A2 CUR_REC:=CUR_REC.PREV;
TST.B MR_TYP(A2)
IF <LT> THEN.S IF CUR_REC.TYPE=USER THEN
MOVE.L A2,A3 A3:=SOURCE_REC:=CUR_REC;
ENDI ENDI;
UNTIL <GT> UNTIL CUR_REC.TYPE=KERNEL;
CLR.L D0 D0:=RESULT:=NOTHING_MOVED:=0;
MOVE.L L_ALLOC,D2 D2:=LAST MEM_REC;
PRT_REG M_UACROS ********
IF.L D2 <NE> MR_NXT(A3) THEN.S
* IF LAST MEM_REC <> SOURCE_REC.NEXT THEN
MOVE.L MR_FST(A3),D2 D2:=FIRST_SOURCE:=SOURCE_REC.FIRST
ADD.L MR_FRE(A3),D2 + SOURCE_REC.FREE_BYTES;
MOVE.L (A3),A2 A2:=LAST_TRY:=SOURCE_REC.NEXT;
MOVE.L A2,D3 D3:=TOP_SOURCE:=LAST_TRY;
REPEAT REPEAT "NEXT USER PART"
BSR.L PGTABGET A1:=KERNEL PART OF D3;
MOVE.L OB_SPA(A1),A0 A0:=TOP ADDRESS OF KERNEL PART;
MOVE.L SP_SIZU(A0),D1 D1:=SIZE; "OF USER PART TO BE MOVED"
MOVE.L L_ALLOC,A0 A0:=CUR_REC:=LAST MEM_REC;
REPEAT REPEAT "NEXT MEM_REC"
MOVE.L MR_PRV(A0),A0 A0:=CUR_REC:=CUR_REC.PREV;
IF.L MR_FRE(A0) <GE> D1 THEN.S IF CUR_REC.FREE_BYTES >= SIZE THEN
BSR.L CREATEUS A0:=NEW_USER_PART(D1,A0);
ADD.L D1,A0 A0:=TOP_DESTIN:=USER PART+SIZE;
BSR.L MOVEUSER MOVE USER PART (A0,A1);
ADD.L D1,D0 D0=RESULT:=RESULT+SIZE; "RESULT <>0"
MOVE.L D3,A1 A1:=USER_PART:=TOP_SOURCE
SUB.L D1,A1 - SIZE;
MOVE.L A3,A0 A0:=SOURCE_REC;
BSR.L RECHAINR REMOVE(D1,A0,A1); "A0,A1 SPOILED"
MOVE.L A2,A0 A0:=CUR_REC:=LAST_TRY; "EXIT REPEAT"
ENDI ENDI;
UNTIL.L A0 <EQ> A2 UNTIL CUR_REC=LAST_TRY;
SUB.L D1,D3 D3=TOP_SOURCE:=...-SIZE; "NEXT TOP"
UNTIL.L D3 <EQ> D2 UNTIL TOP_SOURCE=FIRST_SOURCE;
ENDI ENDI;
MOVE.L D0,A0 A0:=RESULT;
PROCRTRN USAVCRS RETURN;
PAGE
SEARCHKN EQU * SEARCH FOR FREE SPACE TO A KERNEL PART
* CALL: RETURN:
* D1 NO_OF_BYTES SAME "AN INTEGRAL NUMBER OF WORDS"
* A0 ANY MEM_REC, OR 0 WHEN NO SPACE IS AVAILABLE
*
* A KERNEL PART CAN BE ALLOCATED IN A MEM_REC HOLDING OTHER KERNEL PARTS
* OR IN AN EMPTY MEM_REC POSITIONED BEFORE THE FIRST USER PART IN THE SYSTEM,
* OR IN THE FIRST MEM_REC HOLDING USER PARTS.
*
ENTRYSAV D0/D2,.SEARCHK
MOVEQ #MR_SIZ,D0 D0:=HEAD_PLUS_BYTES:=HEAD_SIZE
ADD.L D1,D0 + NO_OF_BYTES;
MOVE.L F_ALLOC,A0 A0:=CUR_MEM_REC:=FIRST MEM_REC;
REPEAT REPEAT
PRT_MEM SEARCHKN,(A0),MR_SIZ ********
MOVE.L MR_FRE(A0),D2 D2:=FREE:=CUR_MEM_REC.FREE_BYTES;
CMP.L D0,D2 TEST D2-D0
BGE.S FOUND2 WHEN HEAD_PLUS_BYTES<=FREE GOTO FOUND;
CMP.L D1,D2 TEST D2-D1
BEQ.S TSTTYPE WHEN NO_OF_BYTES=FREE GOTO TSTTYPE;
IF <GT> THEN.S WHEN D1 < D2 < D0 THEN
* ROOM FOR A MEM_REC HEAD IS NOT AVAILABLE, TEST WHETHER A HEAD IS NEEDED
TST.B MR_FIX(A0)
IF <NE> THEN.S IF CUR_MEM_REC IS FIXED THEN
TSTTYPE EQU * TSTTYPE: "TEST FOR USER MEM_REC"
TST.B MR_TYP(A0) IF CUR_MEM_REC IS NOT A USER MEMREC
BGE.S FOUND2 THEN GOTO FOUND "NO HEAD NEEDED";
ENDI ENDI;
ENDI ENDI;
* A0=CUR_MEM_REC= TOO_SMALL_REC
TST.B MR_TYP(A0) TEST THE TYPE OF TOO_SMALL_REC;
MOVEA.L MR_NXT(A0),A0 A0=CUR_MEM_REC:=TOO_SMALL_REC.NEXT
UNTIL <LT> UNTIL TOO_SMALL_REC.TYPE=USER;
MOVE.W #0,A0 A0:= NO_SPACE:=0;
FOUND2 EQU * FOUND:
RETURN .SEARCHK RETURN;
COMPKNEL EQU * COMPRESS KERNEL PARTS TO GENERATE FREE SPACE;
* CALL: RETURN:
* D1 NO_OF_BYTES SAME
* A0 ANY MEM_REC, OR 0 WHEN REQUIRED SPACE WAS NOT GENERATED
*
* MOVES ALL KERNEL PARTS TOWARDS THE LOW ADDRESS END OF THE RAM AREA
* IF A HOLE IS CREATED DURING THIS PROCESS WITH A SIZE>=D1, THE PROCEDURE
* RETURNS IMMEDIATELY WITH A0 POINTING TO THAT HOLE
*
REPEAT REPEAT
BSR.S C_KPARTS COMPRESS EACH KERNEL RAM(D1,A0:=MEM_REC);
CMPA.W #0,A0 TEST A0.L
IF <NE> THEN.S IF A MEM_REC WAS RETURNED IN A0 THEN
RTS RETURN; "OK"
ENDI ENDI;
BSR.L M_KACROS MOVE KERNEL ACROSS NO_RAM(D1,A0:=RESULT);
CMPA.W #0,A0 TEST A0.L
UNTIL <EQ> UNTIL RESULT=NOTHING MOVED;
RTS RETURN;
PAGE
C_KPARTS EQU * COMPRESS EACH KERNEL RAM AREA TO GENERATE FREE SPACE
* CALL: RETURN:
* D1 NO_OF_BYTES SAME
* A0 ANY MEM_REC, OR 0 WHEN REQUIRED SPACE WAS NOT AVAILABLE
*
* ALL CONSEQUTIVE RAM AREAS HOLDING KERNEL PARTS ARE PROCESSED;
* THE KERNEL PARTS ARE PLACED IN THE LOW ADDRESS END OF THE ENCLOSING RAM AREA
*
PROCSAVE D0/D2/D3/D7/A1-A3,KSAVPRT
MOVEQ #MR_SIZ,D0 D0:=HEAD_PLUS_BYTES:=HEAD_SIZE
ADD.L D1,D0 + NO_OF_BYTES;
MOVE.L F_ALLOC,A3 A0:=A3:=FIRST_REC:=FIRST MEM_REC;
MOVE.L A3,A0 .
MOVE.L MR_FRE(A3),D7 D7:=FREE IN FIRST;
TST.B MR_TYP(A3) TEST TYPE OF FIRST;
REPEAT REPEAT
* A3=A0 POINTS TO THE HEAD OF A RAM AREA, I.E. AN INITIAL MEM_REC_HEAD
* D7= FREE IN THE INITIAL MEM_REC, CCR=TYPE OF MEM_REC.
PRT_MEM C_K_FIX,(A3),MR_SIZ ********
BLE.L C_KPART2 WHEN TYPE<>KNEL GOTO DON'T_COMPRESS_FIRST
* A3 = FIRST_REC IS A KERNEL MEM_REC,
TST.L D7
IF <GT> THEN.S IF FIRST_REC.FREE_BYTES >0 THEN
MOVE.L MR_FST(A3),A0 A0:=DESTINATION:=FIRST_REC.FIRST;
MOVE.L A3,A2 A2:=SOURCE_REC:=FIRST_REC;
BRA.S C_KPART1 GOTO COMPRESS_FIRST;
ENDI ENDI;
MOVE.L MR_NXT(A3),A0 A0:=SOURCE_REC:=FIRST_REC.NEXT;
MOVE.L MR_FRE(A0),D7 D7:=FREE:=SOURCE_REC.FREE_BYTES;
TST.B MR_FIX(A0)
IF <GT> THEN.S IF SOURCE_REC IS AN INITIAL MEM_REC THEN
* BECAUSE FIRST_REC.FREE_BYTES=0(SEE ABOVE),THE WHOLE AREA MUST BE OCCUPIED
MOVE.L A3,A0 A0:=LAST REC IN AREA := FIRST_REC;
ELSE.L ELSE "SOURCE_REC IS NOT INITIAL"
BRA.S C_KPART2 GOTO DON'T_COMPRESS_FIRST;
PAGE
REPEAT REPEAT "NEXT KERNEL MEM_REC"
MOVE.L A0,A2 A2:=SOURCE_REC; "A0=DESTINATION"
C_KPART1 EQU * COMPRESS_FIRST:
* MOVE CAN BE PERFORMED ON ALL KERNEL PARTS OF SOURCE_REC
MOVE.L MR_FST(A2),A1 A1:=KERNEL_PART:=SOURCE_REC.FIRST
ADD.L MR_FRE(A2),A1 + SOURCE_REC.FREE_BYTES;
MOVE.L MR_NXT(A2),A2 A2:=NEXT_REC:=SOURCE_REC.NEXT;
REPEAT REPEAT "NEXT KERNEL PART IN SOURCE_REC"
MOVEQ #0,D3
MOVE.W OB_SIZK(A1),D3 D3.L:=SIZE:=KERNEL_PART.SIZE;
PRT_REG C_K_REGS ********
BSR.L MOVEKNEL MOVE THE KERNEL PART (A0,A1);
ADD.L D3,A0 A0:=DESTINATION:=...+SIZE;
ADD.L D3,A1 A1:=KERNEL_PART:=...+SIZE;
UNTIL.L A1 <EQ> A2 UNTIL KERNEL_PART=NEXT_REC;
MOVE.L A2,D7 D7:=FREE:=NEXT_REC
SUB.L A0,D7 - DESTINATION;
TST.B MR_FIX(A2)
IF <GT> THEN.S IF NEXT_REC IS AN INITIAL MEM_REC THEN
CLR.W D2 D2:=TYPE:=EMPTY:=0;
ELSE.S ELSE
MOVE.W MR_FIX(A2),D2 D2:=TYPE:=NEXT_REC.TYPE;
ADD.L MR_FRE(A2),D7 D7=FREE:=FREE+NEXT_REC.FREE_BYTES;
MOVE.L MR_NXT(A2),A2 A2=NEXT_REC:=NEXT_REC.NEXT;
ENDI ENDI;
NEWHEAD A0,D2,A3,A2 A0:=SOURCE_REC:=CREATE NEW HEAD;
MOVE.L D7,MR_FRE(A0) D2=TYPE, A3=PREV, A2=NEXT, D7=FREE_BYTES.
PRT_MEM C_K_NEW,(A0),MR_SIZ ********
C_KPART2 EQU * DON'T_COMPRES_FIRST:
TST.B MR_TYP(A0)
IF <LT> THEN.S IF SOURCE_REC.TYPE=USER THEN
BRA.S C_KPART3 GOTO TERMINATE;
ENDI ENDI;
IF.L D7 <GE> D0 OR.L D7 <EQ> D1 THEN.S IF SPACE IS AVAIL. IN SOURCE_REC THEN
PROCRTRN KSAVPRT RETURN;
ENDI ENDI;
TST.B MR_TYP(A0)
UNTIL <EQ> UNTIL SOURCE_REC.TYPE=EMPTY;"NEXT_REC FIXED
PAGE
ENDI ENDI; "RAM WAS NOT TOTALLY OCCUPIED"
* A0 = LAST REC IN RAM AREA = LAST REC IN FRONT OF NEW RAM AREA
MOVE.L MR_NXT(A0),A3 A0:=A3:=FIRST_REC:=LAST_REC.NEXT;
MOVE.L A3,A0 .
MOVE.L MR_FRE(A3),D7 D7:= FREE IN FIRST;
TST.B MR_TYP(A3)
UNTIL <LT> UNTIL FIRST_REC.TYPE=USER;
C_KPART3 EQU * TERMINATE:
* A0 = FIRST USER MEM_REC
IF.L D0 <GT> MR_FRE(A0) THEN.S IF NO SPACE IS AVAILABLE IN MEM_REC THEN
MOVE.W #0,A0 A0:=NO SPACE:=0;
ENDI ENDI;
PROCRTRN KSAVPRT RETURN;
PAGE
M_KACROS EQU * MOVE KERNEL PARTS ACROSS NO_RAM AREAS.
* CALL: RETURN*
* D1 #BYTES SAME "THE CALL VALUE IS NOT USED AT PRESENT"
* A0 ANY =0 WHEN NOTHING HAS BEEN MOVED, <> 0 OTHERWISE.
*
* KERNEL PARTS FROM THE LAST KERNEL MEM_REC IS MOVED TO THE FREE PART OF
* MEM_RECS AT LOWER ADDRESSES.
*
PROCSAVE D0-D5/A1-A3,KSAVCRS
MOVE.L F_ALLOC,A2 A2:=CUR_REC:=FIRST MEM_REC;
REPEAT REPEAT;
TST.B MR_TYP(A2) CURTYPE:=CUR_REC.TYPE
IF <GT> THEN.S IF CURTYPE=KERNEL THEN
MOVE.L A2,A3 A3:=SOURCE_REC:=CUR_REC;
ENDI ENDI;
MOVE.L (A2),A2 A2=CUR_REC:=CUR_REC.NEXT;
UNTIL <LT> UNTIL CURTYPE=USER;
* SOURCE_REC IS A FIXED MEM_REC
CLR.L D0 D0:=RESULT:=NOTHING_MOVED:=0;
MOVE.L F_ALLOC,A0 A0:=DESTIN_REC:=FIRST MEM_REC
PRT_REG M_KACROSS
IF.L A0 <NE> A3 THEN.S IF FIRST MEM_REC <> SOURCE_REC THEN
MOVE.L MR_FST(A3),D2 D2:=FIRST_SOURCE:=SOURCE_REC.FIRST
ADD.L MR_FRE(A3),D2 + SOURCE_REC.FREE_BYTES;
MOVE.L (A3),D3 D3:=TOP_SOURCE:=SOURCE_REC.NEXT;
REPEAT REPEAT "NEXT KERNEL PART"
MOVE.L D2,A1 A1:=KERNEL_PART:=FIRST_SOURCE;
MOVEQ #0,D1
MOVE.W OB_SIZK(A1),D1 D1.L:=SIZE; "OF KERNEL PART"
MOVEQ #MR_SIZ,D4 D4.L:=HEAD_PLUS_SIZE:=HEAD_SIZE
ADD.L D1,D4 + SIZE;
MOVE.L F_ALLOC,A0 A0:= DESTIN_REC:= FIRST MEM_REC;
REPEAT REPEAT "NEXT DESTIN_REC"
MOVE.L MR_FRE(A0),D5 D5:=FREE:=DESTIN_REC.FREE_BYTES;
IF.L D5 <GE> D4 OR.L D5 <EQ> D1 THEN.S
* IF SPACE AVAILABLE IN DESTIN_REC THEN
BSR.L CREATEKN A0:=NEW_KERNEL_PART (D1,A0);
BSR.S MOVEKNEL MOVE_KERNEL_PART (A0,A1);
ADD.L D1,D0 D0=RESULT:=RESULT+SIZE;
BSR.L REMOVEKN REMOVEKN (D1,A0,A1); "A0,A1 SPOILED"
MOVE.L A3,A0 A0:=A3; "FORCE UNTIL LOOP TO EXIT"
ELSE.S ELSE
MOVE.L (A0),A0 A0:=DESTIN_REC:=DESTIN_REC.NEXT;
ENDI ENDI;
UNTIL.L A0 <EQ> A3 UNTIL DESTIN_REC=SOURCE_REC;
ADD.L D1,D2 D2=FIRST_SOURCE:=...+SIZE;
UNTIL.L D2 <EQ> D3 UNTIL FIRST_SOURCE=TOP_SOURCE;
ENDI ENDI;
MOVE.L D0,A0 A0:=RESULT;
PROCRTRN KSAVCRS RETURN;
PAGE
MOVEKNEL EQU * MOVE KERNEL PART OF AN OBJECT
*
* CALL: RETURN:
* A0 FUTURE KERNEL PART ADDRESS SAME
* A1 KERNEL PART TO BE MOVED SAME
* SR 20XX ->27XX/20XX DURING CALL-> 20XX
*
* ASSUMES THAT A0 < A1 OR NO OVERLAP BETWEEN THE TWO AREAS.
* STACK: PC,SR,A4/A5/A6 + AT LEAST 7 LONG WORDS.
*
* THE FOLLOWING STEPS APPEARS
*
* 1: MOVE OB_PART AND OBJECT_TYPE RELEATED INFORMATION
* 2: MOVE CONTEXTS, STARTING WITH TOP CONTEXT.
* 3: MOVE ENVELOPES, STARTING WITH TOP ENVELOPE.
* 4: MOVE SPACE DESCRIPTION
*
* SR = $2700 DURING 1 AND 4; AND WHILE RESIDENT ITEMS ARE MOVED
* SR = $2000 OTHERWISE.
*
* CHECKTIM IS CALLED AFTER EACH "CONTEXT/ENVELOPE", TO RELEASE
* THE PROCESSOR IN CASE THE TIME SLICE OF THE CALLING PROCESS
* HAS ELAPSED.
*
* ALL ADDRESSES, POINTING TO MOVED ITEMS ARE ADJUSTED AS AN
* INTEGRATED PART OF THE MOVE ALGORITHM.
*
MOVE #$2700,SR PREVENT INTERRUPTS
PROCSAVE D0-D7/A0-A6,KSAVMOV ALL REGISTERS ARE USED
* THE REGISTER SAVE AREA OF THE PROCESS IS USED TO SAVE SOME PART OF THE STACK
PRT_MEM MOVEKNEL,(A7),60 ********
MOVEM.L (A7)+,D0-D6 D0-D6:= PART OF STACK
MOVE.L KV_PROC,A2 A2:= CALLING PROCESS
MOVEM.L D0-D6,PR_D0.A3(A2) SAVE PART OF STACK IN PROC DESCR.
MOVE.L A0,A2 A2:=FUTURE KERNEL PART;
MOVEQ #0,D1
MOVE.B OB_KIN(A1),D1 D1.W:=OBJECT_KIND
* MOVE THE FIXED ADDRESSABLE PART OF THE OBJECT ("THE OBJECT HEAD").
* A0 = DESTINATION OF OBJECT HEAD; A1 = SOURCE OF OBJECT HEAD
* A5 AND A6 ARE USED BY THE MACROES: MOVHD, MOVLM
* A2 = A0 = FUTURE KERNEL PART ADDRESS, D1.W = OBJECT KIND
BSR.L MOVEOBOB MOVE COMMON PART OF OBJECT
MOVE.W D1,D2 D2:=OBJECT KIND
LSL.W #1,D2 * 2;
CASEJMP D2 GOTO CASE OBJECT KIND OF "D2 BECOMES UNDEF";
CASELAB MOVEGEOB (GENERAL OBJECT,
CASELAB MOVEGAOB GATE OBJECT,
CASELAB MOVECOOB CONDITION OBJECT,
CASELAB ENDOFFIX END_OF_CASE, "OPEN OBJECT
CASELAB MOVEPROB DORMANT OBJECT,
CASELAB MOVEPROB PROCESS OBJECT,
CASELAB MOVEEXOB EXTENSION OBJECT,
CASELAB MOVESEOB SEGMENT OBJECT);
* ALLOC AND SCHEDULER KERNELTYPES ARE NEVER MOVED.
PAGE
* MOVE
MOVEGEOB EQU * =GENERAL OBJECT=
MOVHD A1,A0,A2 EXECUTED_BY CHAIN HEAD
MOVE.L (A1)+,(A0)+ CONTROL_PROC + NO_OF_TEMPS
MOVE.L (A1)+,(A0)+ NO_OF_TEMP_DATA IN STACK
MOVE.L (A1)+,(A0)+ SIZE OF REQUIRED
MOVE.W (A1)+,(A0)+ FREE CALL STACK
MOVE.L (A1)+,(A0)+ LOGICAL STACK ADDRESS
MOVE.L (A1)+,(A0)+ LOGICAL ENTRY ADDRESS
BRA.L ENDOFFIX
MOVEGAOB EQU * =GATE OBJECT=
BSR.L MOVESMPL SIMPLE POINTER TO SCHEDULER
MOVHD A1,A0,A2 COND MANSET CHAIN HEAD
MOVLM A1,A0 LOCKING START ELEMENT
MOVLM A1,A0 RELOCKING START ELEMENT
MOVLM A1,A0 SPEED RELOCKING START ELEMENT
MOVE.W (A1)+,(A0)+ STATE + LEVEL
BRA.L ENDOFFIX
MOVECOOB EQU * =CONDITION OBJECT=
MOVLM A1,A0 MANAGER ELEMENT
MOVE.L (A1)+,(A0)+ MANAGER ADDRESS
MOVHD A1,A0,A2 COND.WAIT CHAIN HEAD
BRA.L ENDOFFIX
MOVEPROB EQU * =PROCESS OBJECT=
LEA -OB_SIZ(A1),A5 A5 := OLD PROC ADDRESS;
IF.L A5 <EQ> KV_PROC THEN.S IF CURRENT PROC IS MOVED THEN
PRT_MEM ***CUR_PROC_MOVED,(A2),OB_SIZ ********
MOVE.L A2,KV_PROC CURRENT PROC ADDRESS:= NEW PROC ADDRESS;
ENDI ENDI;
MOVHD A1,A0,A2 CONTEXT CHAIN HEAD
MOVHD A1,A0,A2 EXTENSION CHAIN HEAD
ADDQ.L #4,A1
MOVE.L A2,(A0)+ PROCESS ADDRESS POINTS TO PROC ITSELF
MOVLM A1,A0 MAIN QUEUE ELEMENT
MOVLM A1,A0 AUX QUEUE ELEMENT
MOVE.L (A1)+,(A0)+ CONDITION ADDRESS
MOVLM A1,A0 PROCTERM START ELEMENT
BSR.L MOVE68 (12+2+2+1) LONG WORDS * 4;
BRA.S ENDOFFIX
MOVEEXOB EQU * =EXTENSION OBJECT=
MOVHD A1,A0,A2 CONTEXT CHAIN HEAD
MOVLM A1,A0 EXTENSION ELEMENT
MOVE.L (A1)+,(A0)+ PROCESS ADDRESS
BRA.S ENDOFFIX
MOVESEOB EQU * =SEGMENT OBJECT=
BSR.L MOVESESU MOVE SE+SU FIELDS OF OBJECT
ENDOFFIX EQU * END CASE;
PAGE
* ADJUST SPACEDESCR OF OBJECT, AND ENVELOPES REF TO OBJECT
MOVE.L OB_SPA(A2),A3 A3:=SPACE PART OF OBJECT
MOVE.L A0,SP_FIRK(A3) FIRST_FREE_KERNEL BYTE:=FIRST FREE DESTIN
LEA SP_ENV(A3),A5 A5:=ENVELOPE CHAIN HEAD;
MOVE.L (A5),A6 A6:=CUR:=FIRST_ENV;
WHILE.L A6 <NE> A5 DO.S WHILE CUR <> HEAD DO
MOVE.L A2,CH_HOLD(A6) CUR.OBJREF:=ADDR OF MOVED OBJECT HEAD;
MOVE.L (A6),A6 CUR:=CUR.NEXT;
ENDW ENDW;
SUBA.L A1,A0 D2:=A0:=DISTANCE:=DESTINATION-SOURCE
MOVE.L A0,D2 (=(A0-A1));
MOVE.L SP_SIZU(A3),D0 D0:= SIZE_USER_PART;
IF <NE> THEN.S IF USER PART PRESENT THEN
ADD.L SP_FIRU(A3),D0 D0:=TOP USER PART:=D0 + FIRST_USER_PAR ;
MOVE.L A2,A1 A1:=KERNEL PART ADDRESS; "(THE NEW ONE)"
BSR.L PGTABSET PAGETABLE(D0=TOPADDRESS):=A1=KERNEL PART);
ENDI ENDI; USER PART WAS PRESENT
PAGE
* D2 = DISTANCE TO MOVE ENVELOPES, CONTEXTS AND SPACE DESCR OF OBJECT
* A2 = FIXED PART OF OBJECT, WHICH HAS BEEN MOVED
* D1 = OBJECT KIND
MOVE.L A2,CUROBOB CUROBOB:=ADDRESS OF MOVED OBJECT HEAD
MOVE.L D2,CURDIST CURDIST:=DISTANCE TO MOVE REST OF OBJECT
MOVE #$2000,SR "ALLOW DRIVER SCHEDULING"
IF.B D1 <EQ> #OB_PROB OR.B D1 <EQ> #OB_EXOB THEN.L
* IF OBJECT CONTAINS CONTEXTS THEN
* MOVE CONTEXTS ONE BY ONE. ALLOW SCHEDULER TO RUN OTHER PROCESSES IN BETWEEN
LEA EX_CTX(A2),A3 CURKHEAD:= A3:=
MOVE.L A3,CURKHEAD ADDRESS OF CONTEXT STACK HEAD
MOVE.L 4(A3),A3 A3:=CONTEXT:=CONTEXT_HEAD.LAST;
MOVE.L A3,CURKMOVE CURRENT MOVE CANDIDATE:=CONTEXT;
LEA -CT_STK(A3),A6 A6:= BASE OF CTX
IF.L KV_CTX <EQ> A6 THEN.S IF CUR_CTX IS MOVED THEN
PRT_MEM ***CUR_CTX_MOVE,(A6),CT_SIZ+6*PT_SIZ ********
ADD.L D2,KV_CTX CUR_CTX:=... + DISTANCE
ENDI ENDI;
WHILE.L A3 <NE> CURKHEAD DO.L WHILE MORE CONTEXT DO
LEA -CT_STK(A3),A3 MOVE COMMON PART OF CONTEXT,
BSR.L MOVEENCT A0:=DESTINATION, A1:=SOURCE,
* A2:= NEW ADDRESS OF CONTEXT
MOVE.L (A1)+,(A0)+ SIZE OF FREE STACK + TOP TEMP
MOVE.L (A1)+,(A0)+ .
FOR.W D0=#1 TO #4 DO.S FOR I = 1 TO 4 DO
BSR.L MOVESMPL MOVE MMU_POINTER;
MOVE.L (A1)+,(A0)+ MOVE MMU_REGISTER CONTENT;
MOVE.L (A1)+,(A0)+ .
ENDF ENDF;
JSR.L MOVE000-(CT_SIZW+5)*2 MOVE WORK AREA AND 5 LONGS
MOVE.L A3,A4 A4:=ABS ADDR OF TOP TEMP POINTER :=
ADDA.W CT_TOPT(A2),A4 CONTEXT + REL ADDR OF TOP TEMP;
WHILE.L A1 <NE> A4 DO.S WHILE MORE TEMP POINTERS DO
BSR.L MOVEPOIN MOVE ONE POINTER;
ENDW ENDW;
MOVE.L A3,A4 A4:=ABS ADDR OF TOP FORMAL POINTER :=
ADDA.W CT_TOPF(A2),A4 CONTEXT + RELADDR OF TOP FORMAL;
WHILE.L A1 <NE> A4 DO.S WHILE MORE FORMALS DO
BSR.L MOVEPOIN MOVE ONE POINTER;
MOVLM A1,A0 MOVE ACTUAL CHAIN ELEMENT;
MOVE.L (A1)+,(A0)+ MOVE REF TO CTX OR ENV;
MOVE.W (A1)+,(A0)+ MOVE ACTUAL OFFSET;
ENDW ENDW;
PRT_MEM MOVED_CTX,(A2),CT_SIZ+6*PT_SIZ ********
MOVE.L CT_STK+4(A2),CURKMOVE CUR_MOVE_CANDIDATE:=PRIOR CONTEXT;
MOVE #$2700,SR PREVENT INTERRUPTS;
BSR.L TIMCHECK ALLOW OTHER PROCESSES TO RUN;
* CURKMOVE MAY HAVE BEEN CHANGED.
MOVE #$2000,SR ALLOW INTERRUPTS
MOVE.L CURKMOVE,A3 A3:=NEXT CONTEXT TO MOVE
ENDW ENDW MORE
ENDI ENDI; CONTEXTS WAS PRESENT IN PROC ø EXT
PAGE
* SR=$2000, CONTEXTS HAVE BEEN MOVED IF PRESENT, CUROBOB AND CURDIST ARE VALID
* MOVE ENVELOPES
MOVE.L CUROBOB,A4 A4:=ADDRESS OF MOVED OBJECT HEAD
MOVE.L OB_SPA(A4),A4 A4:=SPACE PART OF OBJECT
LEA SP_ENV(A4),A3 A3:=ENVELOPE STACK CHAIN HEAD
MOVE.L A3,CURKHEAD CURKHEAD:=ENVELOPE STACK CHAIN HEAD
MOVE.L 4(A3),A3 A3:=TOP ENVELOPE:=ENVELOPE_HEAD.LAST;
MOVE.L A3,CURKMOVE CURKMOVE:=TOP ENVELOPE;
WHILE.L A3 <NE> CURKHEAD DO.S WHILE MORE ENVELOPES DO
LEA -ST_STK(A3),A3 A3:=FIRST ADDRESS OF FIXED ENV FIELDS;
BSR.L MOVEENCT MOVE COMMON PART OF ENVELOPE =>
* A1:=SOURCE; A0:=DESTINATION; A2:= NEW ADDRESS OF CONTEXT;
MOVHD A1,A0,A2 MOVE REF_ENV CHAIN HEAD;
BSR.L MOVE20 MOVE TERM_PROC+SIZE_VALUES OF ENV;
MOVE.W (A1)+,(A0)+ MOVE EN_COU OF ENVELOPE
MOVE.L A3,A4 A4:=ABS ADDR OF TOP LOCAL POINTER:=
ADDA.W ST_TOP(A2),A4 ENVELOPE+REL ADDR OF TOP LOCAL;
WHILE.L A1 <NE> A4 DO.S WHILE MORE LOCAL POINTERS DO
BSR.L MOVEPOIN MOVE ONE POINTER;
ENDW ENDW;
PRT_MEM MOVED_ENV,(A2),EN_SIZ+3*PT_SIZ ********
MOVE.L ST_STK+4(A2),CURKMOVE CURKMOVE:=PRIOR ENVELOPE;
MOVE #$2700,SR PREVENT INTERRUPT PROCESSING;
BSR.L TIMCHECK ALLOW OTHER PROCESSES TO RUN;
* CURKMOVE MAY HAVE CHANGED AT RETURN
MOVE #$2000,SR ALLOW INTERRUPTS
MOVE.L CURKMOVE,A3 A3:=CUR_MOVE_CANDIDATE;
ENDW ENDW;
* MOVE SPACE DESCR OF OBJECT REGISTER CONTENT ARE NOT USED BELOW
MOVE.W #$2700,SR PREVENT INTERRUPTS
CLR.L CURKMOVE NO MOVE CANDIDATE
BSR.L TIMCHECK ENSURE ONE CHECK_CALL FOR EACH MOVE_CALL
MOVE.L CUROBOB,A4 A4:=OBJECT HEAD
MOVE.L OB_SPA(A4),A1 A1:=SOURCE:=SPACE PART
MOVE.L A1,A0 A0:=DESTINATION:=SOURCE
ADDA.L CURDIST,A0 + DISTANCE;
MOVE.L A0,OB_SPA(A4) OBJECT.SPACE_PART:=DESTINATION;
LEA SP_ENV(A1),A1 A1:=SOURCE OF ENVELOPE STACK CHAIN HEAD
LEA SP_ENV(A0),A0 A0:=DESTIN OF ENVELOPE STACK CHAIN HEAD
MOVLM A1,A0 MOVE ENVELOPE STACK CHAIN HEAD
MOVE.L (A1)+,(A0)+ MOVE NO_OF_FREE USER BYTES;
MOVE.W (A1)+,(A0)+ MOVE NO_OF_FREE KERNEL BYTES;
MOVE.L (A1)+,(A0)+ MOVE FIRST FREE USER BYTE;
MOVE.L (A1)+,(A0)+ MOVE FIRST FREE KERNEL BYTE;
MOVE.L (A1)+,(A0)+ MOVE TOTAL SIZE OF USER PART;
* RESTORE SUPERVISOR STACK
MOVE.L KV_PROC,A2 A2:= CALLING PROCESS;
MOVEM.L PR_D0.A3(A2),D0-D6 D0-D6:= SAVED STACK
MOVEM.L D0-D6,-(A7) RESTORE STACK
MOVE.W #$2000,SR ALLOW INTERRUPTS
PROCRTRN KSAVMOV RETURN
PAGE
MOVEOBOB EQU * MOVE OB FIELDS OF OBJECT
* CALL: RETURN:
* A1 = SOURCE SAME (UPDATED)
* A0 = DESTINATION SAME (UPDATED)
* A2 = FUTURE OBJECT (=A0) SAME
* A5,A6 SPOILED BY MACROS
*
PRT_MEM MOVEOBOB,(A1),PR_SIZ ********
MOVLM A1,A0 ; OWNER ELEMENT
MOVE.L (A1)+,(A0)+ ; OWNER ADDRESS
MOVE.W (A1)+,(A0)+ ; OWNER POINTER OFFSET
MOVHD A1,A0,A2 REFERRED BY CHAIN HEAD
MOVE.L (A1)+,(A0)+ RESIDENT COUNT+SIZE OF KNEL PART
MOVE.W (A1)+,(A0)+ OBJECT KIND AND STATE
MOVE.L (A1)+,(A0)+ ADDRESS OF SPACE PART
RTS
MOVESESU EQU * MOVE SE(+SU) FIELDS OF OBJECT
* CALL: RETURN:
* A1 = SOURCE SAME (UPDATED)
* A0 = DESTINATION SAME (UPDATED)
* A2 = SEGMENT OBJECT SAME
*
MOVE.W (A1)+,(A0)+ IO_COUNT
MOVE.L (A1)+,(A0)+ FIRST PHYSICAL ADDRESS
MOVE.L (A1)+,(A0)+ LENGTH OF SEGMENT
MOVLM A1,A0 CHAIN START OF WAITING PROCS.
BTST.B #OB_SUB,OB_STA(A2)
IF <NE> THEN.S IF SEGMENT IS A SUBSEGMENT THEN
BSR.L MOVESMPL MOVE SUBSEGMENT POINTER
ENDI ENDI;
RTS
* MOVELIST USED BY MOVEKNEL, CHECK THAT: (CT_SIZW+5) <= (72/4) ;
MOVE72 MOVE.L (A1)+,(A0)+
MOVE68 MOVE.L (A1)+,(A0)+
MOVE64 MOVE.L (A1)+,(A0)+
MOVE60 MOVE.L (A1)+,(A0)+
MOVE56 MOVE.L (A1)+,(A0)+
MOVE52 MOVE.L (A1)+,(A0)+
MOVE48 MOVE.L (A1)+,(A0)+
MOVE44 MOVE.L (A1)+,(A0)+
MOVE40 MOVE.L (A1)+,(A0)+
MOVE36 MOVE.L (A1)+,(A0)+
MOVE32 MOVE.L (A1)+,(A0)+
MOVE28 MOVE.L (A1)+,(A0)+
MOVE24 MOVE.L (A1)+,(A0)+
MOVE20 MOVE.L (A1)+,(A0)+
MOVE16 MOVE.L (A1)+,(A0)+
MOVE12 MOVE.L (A1)+,(A0)+
MOVE08 MOVE.L (A1)+,(A0)+
MOVE04 MOVE.L (A1)+,(A0)+
MOVE000: RTS
PAGE
MOVEPOIN EQU * MOVE COMMON PART OF POINTER
* CALL: RETURN:
* A0 DESTINATION SAME (UPDATED)
* A1 SOURCE SAME (UPDATED)
* A2 MOVED CONTEXT OR ENVELOPE SAME
* A5+A6+D6 ANY UNDEF
* A5+A6 ANY SPOILED BY MACROES
MOVE.B PT_KIN(A1),D6 D6:= POINTER KIND;
IF.B D6 <EQ> #PT_OWN OR.B D6 <EQ> #PT_MAN THEN.S IF SET POINTER THEN
MOVHD A1,A0,A2 MOVE POINTER SET HEAD
ADDQ.L #4,A1 SKIP 4 BYTES
ADDQ.L #4,A0 NOT USED
MOVE.W (A1)+,(A0)+ MOVE KIND + INF
RTS RETURN;
ENDI ENDI;
IF.B D6 <EQ> #PT_INT THEN.S IF INTERRUPT POINTER THEN
LEA DRIV_TAB,A6 A6:=ADDRESS OF DRIVER_TABLE
CLR.W D6
MOVE.B PT_INF(A1),D6 D6:=VECTOR INDEX:=POINTER INF
LSL.W #2,D6 TABLE_OFFSET:=RECTOR INDEX *4;
LEA EN_STK(A2),A5 A5:= ENV.STACK;
MOVE.L A5,(A6,D6.W) DRIVERTABLE.TABLE_OFFSET:=ENV.STACK;
PRT_MEM ***DRIV_MOVE,<(A6,D6.W)>,4 ********
* CONTINUE IN >> MOVE SIMPLE POINTER <<
ENDI ENDI;
MOVESMPL EQU * MOVE SIMPLE POINTER : A2 IS NOT USED, A0/A1 IS UPDATED.
MOVLM A1,A0 MOVE POINTER CHAIN ELEMENT
MOVE.L (A1)+,(A0)+ MOVE POINTER REFFERENCE
MOVE.W (A1)+,(A0)+ MOVE KIND + INF
RTS
PAGE
MOVEENCT EQU * MOVE COMMON PART OF ENVELOPE AND CONTEXT
* CALL: RETURN:
* A3 = STACK ELEMENT (ENV/CTX) SAME
* A2 ANY ENV/CTX (AFTER MOVE)
* A0 ANY DESTINATION (AFTER MOVE)
* A1 ANY SOURCE (AFTER MOVE)
* SR MAY BE CHANGED TO $2700
MOVE.L A3,A1 A1:=SOURCE:=STACK ELEMENT
ADDA.W ST_FIR(A3),A1 +FIRST EMBEDDED;
MOVE.L A1,A0 A0:=DESTINATION:=SOURCE
ADDA.L CURDIST,A0 +DISTANCE;
WHILE.L A1 <NE> A3 DO.S WHILE EMBEDDED SEGMENT OBJECTS DO
MOVE.L A0,A2 A2:=FUTURE EMBEDDED OBJECT:= DESTINATION;
TST.W OB_RES(A2)
IF <NE> THEN.S IF EMBEDDED.RESIDENT_COUNT <> 0 THEN
MOVE #$2700,SR NO INTERRUPT PROCESSING IS ALLOWED
ENDI ENDI;
BSR.L MOVEOBOB MOVE OB OF EMBEDDED
BSR.L MOVESESU MOVE SESU OF EMBEDDED
MOVE #$2000,SR ALLOW INTERRUPT PROCESSING
ENDW
TST.W ST_RES(A3) IF STACK_ELEMENT.RESIDENT COUNT <> 0 THEN
IF <NE> THEN.S ENSURE THAT INTERRUPT PROCESSING
MOVE #$2700,SR CANNOT BE SCHEDULED;
ENDI ENDI;
* MOVE FIXED PART OF STACK ELEMENT
MOVE.L A0,A2 A2:=NEW POSITION OF CONTEXT/ENVELOPE
MOVLM A1,A0 EXECUTED BY/MANAGED BY - ELEMENT
MOVE.L (A1)+,(A0)+ OBJECT /ENVELOPE
MOVE.W (A1)+,(A0)+ MODE+SPEED /MANAGER POINTER
MOVLM A1,A0 STACK ELEMENT-ELEMENT
MOVE.L (A1)+,(A0)+ HOLDING OBJECT
MOVHD A1,A0,A2 ACTUAL POINTER CHAIN HEAD
MOVE.L (A1)+,(A0)+ TOP POINTER + FIRST EMBEDDED
MOVE.L (A1)+,(A0)+ RESIDENT COUNT + IO_COUNT
RTS RETURN
* "SR MAY BE $2700 AT RETURN"
PAGE
MOVEUSER EQU * MOVE USER PART
* CALL: RETURN:
* A0 TOPADDRESS OF NEW USER PART SAME
* A1 KERNEL PART ADDRESS SAME
* SR 20XX ->27XX/20XX DURING CALL-> 20XX
* A0 > OLD TOP ADDRESS OR NO OVERLAP BETWEEN AREAS HOLDING THE USER PART
* STACK: PC,SR,A4/A5/A6 + AT LEAST 8 LONG WORDS
*
* MOVES THE USER PART (A1) TO THE NEW LOCATION (A0). THE HIGH ADDRESS
* PARTS ARE MOVED FIRST. THE PROCESS IS DIRECTED BY THE EMBEDDED
* SEGMENT OBJECTS OF THE ENVELOPES (OLDEST PROCESSED FIRST) AND
* CONTEXTS (OLDEST PROCESSED FIRST) AND BY THE OBJECT HEAD IN CASE
* A1 IS A NON EMBEDDED SEGMENT OBJECT.
* IN CASE THE RESIDENT COUNT OF THE SEGMENT IS NON ZERO. SR:=$2700
* WHILE THE MOVE IS PERFORMED. OTHERWISE SR:=$2000
* IN CASE THE IO_COUNT OF THE SEGMENT IS NON ZERO, THE PROCESS WAITS
* UNTIL IT BECOMES ZERO.
*
* IN CASE TIME_OUT HAS OCCURED, THE CURRENT PROCESS SUSPENDS ITSELF
*
* ALL ADDRESSES POINTING TO MOVED SEGMENTS ARE ADJUSTED AS AN
* INTEGRATED PART OF THE MOVE ALGORITHM.
MOVE.W #$2700,SR PREVENT INTERRUPTS
PRT_MEM MOVEUSER,(A7),80 ********
PROCSAVE D0-D7/A0-A6,USAVMOV SAVE REGISTERS
* SAVE PART OF THE STACK IN THE PROC DESCRIPTION OF CALLING PROCESS.
MOVE.L KV_PROC,A2 A2:= CALLING PROC.
MOVEM.L (A7)+,D0-D7 D0-D7:= 8 LONG WORDS FROM STACK
MOVEM.L D0-D7,PR_D0.A3(A2) SAVE STACK IN PROC DESCR.
MOVE.L OB_SPA(A1),A2 A2:=SPACE DESCR OF OBJECT;
MOVE.L A0,D0 D0:=NEW TOP ADDRESS;
BSR.L PGTABSET PAGETABLE(D0=TOP ADDRESS):=KNEL PART=A1;
SUB.L SP_SIZU(A2),D0 D0:=NEW FIRST ADDRESS:=NEW TOP ADDRESS-SIZ
MOVE.L D0,USERDEST USER DESTINATON:=NEW FIRST ADDRESS
CLR.L CURUMOVE CURRENT MOVE CANDIDATE:=NO CANDIDATE;
SUB.L SP_FIRU(A2),D0 D0:=DISTANCE:=NEW_FIRST-OLD_FIRST;
MOVE.L D0,CURDIST CURDIST:=DISTANCE;
MOVE.L A1,CUROBOB CUROBOB:=KERNEL PART;
LEA SP_ENV(A2),A3 A3:=CUR_HEAD:=
MOVE.L A3,CUR_HEAD ENVELOPE STACK CHAIN HEAD;
MOVE.L (A3),A4 A4:=FIRST_ENV:=CUR_HEAD.FIRST
PAGE
MOVEUSXX EQU * MOVE_EMBEDDED_SEGMENTS:
WHILE.L A4 <NE> CUR_HEAD DO.S WHILE MORE STACK ELEMENTS DO
CLR.W D4 D4:=CUR_SEGM:=DUMMY SEGMENT;
REPEAT REPETE "FOR ALL EMBEDDED SEGMENTS"
* FIND OLDEST SEGMENT YOUNGER THAN CUR_SEGM (CALLED NEXT_SEGM BELOW).
CLR.W D5 D5:=NEXT SEGM:=NO NEXT:=0;
MOVE.W ST_FIR-ST_STK(A4),D3 D3:=OLDER:=YOUNGEST SEGMENT;
WHILE.W D3 <NE> D4 DO.S WHILE OLDER <> CUR_SEGM DO
BTST.B #OB_SUB,OB_STA-ST_STK(A4,D3.W)
IF <EQ> THEN.S IF OLDER IS NOT A SUBSEGM THEN "ROOT SEGM"
MOVE.W D3,D5 D5:=NEXT_SEGM:=OLDER;
ENDI ENDI;
ADD.W OB_SIZK-ST_STK(A4,D3.W),D3 D3:=OLDER:=SEGMENT OLDER THAN OLDER;
ENDW ENDW;
MOVE.W D5,D4 CUR_SEGM:=NEXT_SEGM;
IF <NE> THEN.S IF CUR_SEGM <> NO NEXT THEN
* MOVE THE SEGMENT DESCRIBED BY A4 AND D4.
LEA -ST_STK(A4,D4.W),A2 A2:=SEGMENT OBJECT;
BSR.L CHK_TIR CHECK FOR TIME_OUT,IO,RESIDENT
* D4/A2/A4 ARE STILL VALID, SR MAY HAVE BEEN CHANGED TO $2000
IF <EQ> THEN.S IF SEGMENT DELETED THEN
MOVE.L CUROBOB,A2 A2:=KERNEL PART;
BRA.S MOVEUSEX GOTO NO_MORE_SEGMENTS;
ENDI ENDI;
BSR.L MOVESEDA MOVE DATA AND ADJUST ADDRESS; SR:=$2700;
TST.W D4 RESTORE CONDITION CODES TO <NE>
ENDI ENDI;
UNTIL <EQ> UNTIL NO MORE EMBEDDED SEGMENTS;
MOVE.L (A4),A4 A4:=NEXT STACK ELEMENT;
ENDW ENDW; MORE STACK ELEMENTS
MOVE.L CUROBOB,A2 A2:=KERNEL PART;
MOVE.L OB_SPA(A2),A4 A4:=SPACE DESCRIPTION;
LEA SP_ENV(A4),A3 A3:=ENVELOPE STACK;
IF.L A3 <EQ> CUR_HEAD THEN.S IF ENVELOPE DATA HAS JUST BEEN MOVED THEN
MOVE.B OB_KIN(A2),D4 D4:= OBJECT KIND;
IF.B D4 <EQ> #OB_PROB OR.B D4 <EQ> #OB_EXOB THEN.S
* IF OBJECT CONTAINS CONTEXTS THEN
LEA EX_CTX(A2),A3 A3 AND CUR_HEAD :=
MOVE.L A3,CUR_HEAD CONTEXT STACK CHAIN HEAD
MOVE.L (A3),A4 A4:=FIRST_CTX:=CUR_HEAD.FIRST;
BRA.S MOVEUSXX GOTO MOVE_EMBEDDED_SEGMENTS;
ENDI ENDI;
ENDI ENDI;
PAGE
IF.B OB_KIN(A2) <EQ> #OB_SEOB THEN.S
BTST.B #OB_SUB,OB_STA(A2) IF SEGMENT OBJECT
IF <EQ> THEN.S BUT NOT A SUBSEGMENT THEN
BSR.S CHK_TIR CHECK FOR TIME_OUT,IO,RESIDENT
IF <NE> THEN.S IF SEGMENT NOT DELETED THEN
BSR.L MOVESEDA MOVE DATA AND ADJUST ADDRESSES;
ENDI ENDI;
ENDI ENDI;
ENDI ENDI;
MOVEUSEX EQU * NO_MORE_SEGMENTS:
MOVE.L USERDEST,SP_FIRU(A4) FIRST USER BYTE:=NEW FIRST ADDRESS;
CLR.L CURUMOVE CUR_MOVE_CANDIDATE:=NO CANDIDATE;
* RESTORE SUPERVISOR STACK
BSR.L TIMCHECK ENSURE ONE CHECK_CALL FOR EACH MOVE_CALL
MOVE.L KV_PROC,A2 A2:= CALLING PROCESS
MOVEM.L PR_D0.A3(A2),D0-D7 D0-D7:= SAVED STACK FROM PROC DESCR.
MOVEM.L D0-D7,-(A7) RESTORE STACK;
MOVE.W #$2000,SR ALLOW INTERRUPTS
PROCRTRN USAVMOV RETURN;
PAGE
CHK_TIR EQU * : TIME_OUT,IO_COUNT, RESIDENT_COUNT
*
* CALL: RETURN
* D4 ANY SAME
* A2 SEGMENT OBJECT SAME, OR 0 <-> OBJECT DELETED
* A4 STACK ELEMENT WHEN A2 IS EMBEDDED SAME
* CC ANY <NE>, OR <EQ> <-> OBJECT DELETED
* SR $27XX $20XX OR $27XX (SE RESIDENT CHECK)
* OTHER ANY UNDEF
* TIME_OUT CHECK: SUSPEND CURRENT PROCESS IF TIME_OUT HAS OCCURED
* IO_CHECK : WAIT UNTIL IO_COUNT=0
* RESIDENT CHECK: ALLOW INTERRUPTS IF RESIDENT_COUNT=0;
*
PROCSAVE D4/A4,SAV_CHK SAVE D4/A4
MOVE.L A2,CURUMOVE SET CURRENT MOVE CANDIDATE
CHK_REP EQU * CHECK_AGAIN:
BSR.L TIMCHECK IF TIME_OUT THEN SUSPEND PROCESSING
MOVE.L CURUMOVE,A2 A2:=CURRENT MOVE CANDIDATE
CMPA.W #0,A2 TEST A2.L = 0;
IF <EQ> THEN.S IF CURRENT MOVE CANDIDATE DELETED THEN
PROCRTRN SAV_CHK RETURN WITH CC=<EQ>
ENDI ENDI;
TST.W SE_IO(A2)
IF <NE> THEN.S IF IO_COUNT <> 0 THEN "IO PENDING"
LEA SE_WAIT(A2),A1 A1:=TERMINATION CONDITION OF SEGMENT;
MOVE.L KV_CTX,A2 A2:= CURRENT CONTEXT
BSR.L KNELWAIT KNELWAIT(A1=COND,A2=CTX);
MOVE.L CURUMOVE,A2 A2:=CURRENT MOVE CANDIDATE;
CMPA.W #0,A2 TEST A2.L = 0;
IF <EQ> THEN.S IF CURRENT MOVE CANDIDATE DELETED THEN
PROCRTRN SAV_CHK RETURN WITH CC = <EQ>
ENDI ENDI;
BRA.S CHK_REP GOTO CHECK_AGAIN;"REP. THE WHOLE CHECK"
ENDI ENDI;
TST.W OB_RES(A2)
IF <EQ> THEN.S IF RESIDENT COUNT = 0 THEN
MOVE #$2000,SR ALLOW INTERRUPTS; CC:=<NE>;
ENDI ENDI;
PROCRTRN SAV_CHK RETURN;
PAGE
MOVESEDA EQU * MOVE SEGMENT DATA
*
* CALL: RETURN:
* A2 SEGMENT OBJECT SAME
* D0/D1/D2/D5/D6/D7/A3/A5 ANY UNDEF
* SR $20XX OR $27XX (SE CHK_TIR) $2700 (=PREVENT INTERUPTS)
*
* ALL REFERENCES TO THE DATA ARE ADJUSTED,
* AND THE DATA SEGMENT IS MOVED
*
PRT_MEM MOVESEDA,(A2),SE_SIZ ******
BTST.B #OB_ABOR,OB_STA(A2) ABORTED SEGM HAS NO VALID DATA PART
IF <EQ> THEN.S IF NOT ABORTED THEN
MOVE.L CURDIST,D1 D1:=DISTANCE TO MOVE
LEA NEWSEFIR,A3
BSR.S MM_SETRE SCAN TREE(A2=ROOT,A3=NODE_PROC)
MOVE.L SE_FIR(A2),A1 A1:=SOURCE
MOVE.L A1,A0 A0:=DESTINATION
ADD.L D1,A0 :=SOURCE+DISTANCE
MOVE.L A0,SE_FIR(A2) SEGMENT.FIRST_BYTE:=DESTINATION;
MOVE.L SE_LEN(A2),D5 D5:=SEGMENT.LENGTH
BSR.L MOVE_MEM MOVE_MEMORY(A0,A1,D5);
ENDI ENDI;
MOVE #$2700,SR PREVENT INTERRUPTS
RTS RETURN;
PAGE
MM_SETRE EQU * SCAN TREE OF SUBSEGMENTS AND POINTERS.
*
* A3 NODE PROCEDURE EXECUTED FOR EACH NODE IN THE TREE
* A2 ROOT NODE OF THE TREE
* SPOILED D0,D6,D7,A0
* D1-D5/A1-A5 ARE UNCHANGED WHEN THE NODE PROCEDURE IS CALLED
* A0=CURRENT NODE WHEN THE NODE PROC IS CALLED
* D0=KIND OF CURRENT NODE WHEN NODE PROC IS CALLED
*
* THE NODE PROCEDURE IS NOT CALLED ON THE ROOT NODE
* THE NODE PROCEDURE IS CALLED BEFORE THE SUBTREE IS SCANNED
LEA OB_REF(A2),A0 A0:=ROOT_HEAD;
SCANBRAN EQU * "RECURSIVE PROCEDURE", CALLED ON REF_CHAIN OF EACH SEGMENT;
MOVE.L A0,D6 D6:=CUR_HEAD;
MOVE.L (A0),A0 A0:=CUR_POINTER:=CUR_HEAD.FIRST
WHILE.L A0 <NE> D6 DO.S WHILE CUR_POINTER <> CUR_HEAD DO
MOVE.B PT_KIN(A0),D0 D0:=POINTER KIND;
JSR (A3) CALL THE NODE PROCEDURE;
PRT_MEM ADDR_ADJUST,SE_FIR-SU_P(A0),MM_SIZ-(SE_FIR-SU_P) ********
IF.B D0 <EQ> #PT_SEG THEN.S IF POINTER=SEGM_POINTER THEN
* THE POINTER IS PART OF A SUBSEGMENT. A SUBSEGMENT NODE STARTS
* A NEW BRANCH IN THE TREE. SCAN THAT BRANCH.
LEA (OB_REF-SU_P)(A0),A0 A0:=CUR_POINTER:=HEAD OF BRANCH
BRA.S SCANBRAN "RECURSIVE CALL" OF SCANBRAN
PREVBRAN EQU * "RECURSIVE CALL" RETURNS TO HERE
* RESTORE REGISTERS TO REFLECT THE RESUMED BRANCH
LEA SU_P-OB_REF(A0),A0 A0:=CUR_POINTER:=POINTER OF SUBSEGM;
MOVEQ.L #OB_REF,D6 D6:=CUR_HEAD:=HEAD OF POINTER CHAIN:=
ADD.L PT_REF(A0),D6 REF_CHAIN_OFFSET+BASE OF SEGMENT;
ENDI ENDI;
MOVE.L (A0),A0 A0:=CUR_POINTER:=NEXT_POINTER
ENDW ENDW;
BTST.B #OB_SUB,OB_STA-OB_REF(A0) TEST FOR ROOT SEGM;
BNE.S PREVBRAN WHEN SUBSEGM RETURN TO PREVIOUS BRANCH
RTS RETURN
PAGE
NEWSEFIR EQU * NEW VALUE OF SE_FIR SHOULD BE REGISTERED
* CALL: RETURN:
* A5 ANY UNDEF
* D2 ANY UNDEF
* A0 POINTER TO BE ADJUSTED SAME
* D1 DISTANCE SEGM WAS MOVED SAME
* D0 POINTER KIND OF POINTER SAME
IF.B D0 <EQ> #PT_OBJ THEN.S IF POINTER KIND=REF_OBJECT THEN
RTS RETURN
ENDI ENDI
IF.B D0 <EQ> #PT_SEG THEN.S IF POINTER KIND=SEGMENT THEN
ADD.L D1,SE_FIR-SU_P(A0) SUBSEG.FIRST_BYTE:=...+DISTANCE
RTS RETURN;
ENDI ENDI
IF.B D0 <EQ> #PT_MMU THEN.S IF POINTER_KIND=MMU_DESCRIPTION THEN
MOVE.L D1,D2 D2:=DISTANCE
LSR.L #8,D2 D2.W:=PAGE DISTANCE:=DISTANCE //256
ADD.W D2,MM_REG+4(A0) MMU.RELOCATION:=....+DISTANCE
RTS RETURN;
ENDI ENDI
* A DRIVER POINTER IS FOUND
CLR.W D2
MOVE.B PT_INF(A0),D2 D2.W:=VECTOR NUMBER
LSL.W #2,D2 D2.W:=VECTOR INDEX := VECTOR NUMBER << 2;
LEA KV_INVEC,A5 A5:=ADDRESS OF INT VECTOR (NORMALLY=0)
ADD.L D1,(A5,D2.W) INT_VECT(VECT_INDEX):=...+DISTANCE;
PRT_MEM ***INT_PROC_MOVED,<(A5,D2.W)>,4 ********
RTS RETURN;
PAGE
MOVE_MEM EQU * MOVES AN INTEGRAL NUMBER OF SEGMENTS
*
* A0 DESTINATION ADDRESS SAME
* A1 SOURCE ADDRESS SAME
* D5 SIZE UNDEF
* 0 < SIZE < 2**23 MUST BE FULFILLED.
* ROUND UP SIZE TO AN INTEGRAL NUMBER OF PAGES.
ADD.L #255,D5
CLR.B D5
ADDA.L D5,A0 A0:=TOP DESTINATION:=DESTINATION+SIZE
ADDA.L D5,A1 A1:=TOP SOURCE:=SOURCE+SIZE
* THE LAST PART OF THE SEGMENT IS MOVED FIRST
* D5:=NO OF TIMES TO REPEATE THE LIST BELOW
LSR.L #7,D5 :=SIZE//128
SUBQ.L #1,D5 ADJUST D5 TO MATCH THE WAY 'DBF' WORKS.
MOVAGAIN EQU *
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
MOVE.L -(A1),-(A0)
DBF D5,MOVAGAIN
* NOTE: A0/A1 WAS COUNTED DOWN TO THE CALL VALUE BY THE LOOP ABOVE.
RTS RETURN
END ! END OF MMPROCS
«eof»