; CL1DYN - CLONE DYNAMIC MEMORY CONTROL ; LAST EDIT: 19-NOV-81 ; .TITLE CL1DYN ; ; TEXT$ ON ; ; THIS MODULE CONTAINS ROUTINES FOR THE ADMINISTRATION OF THE DYNAMIC ; MEMORY POOL. THIS AREA IS A SINGLE CONTIGUOUS BLOCK OF VIRTUAL ADDRESS ; SPACE COMPOSED OF BLOCKS OF WORDS REFERED TO AS 'ITEMS'. THOSE ITEMS ; WHICH ARE NOT IN USE FOR THE STORAGE OF CLONE DATA ARE LINKED TOGETHER ; IN A 'FREE-LIST'. ITEMS WHICH ARE IN USE MAY BE DE-ALLOCATED AND ARE ; LINKED BACK INTO THE FREE-LIST. ; ; THOSE ITEMS WHICH HAVE BEEN ALLOCATED TO CLONE HAVE A STANDARD TWO WORD ; HEADER: WORD 1- ADDRESS OF ITSELF ; THIS IS USED AS A CHECK ON SYSTEM INTEGRITY ; AND IS ALSO USEFUL AS A MEANS OF TERMINATING ; A CHAIN OF POINTERS. ; WORD 2- TOTAL LENGTH OF THE ITEM IN WORDS, THIS WILL ; ALWAYS BE A MULTIPLE OF 2. ; ; MANY ITEMS WITHIN CLONE ARE FORMED INTO FORWARD-BACKWARD LINKED LISTS. ; SUCH A LIST HAS A TWO-WORD 'LIST-HEAD', WHICH IS NOT CONSIDERED PART ; OF THE LIST ITSELF, AND ANY NUMBER OF ITEMS COMPRISING THE LIST. THE ; FORMAT OF THE LISTHED IS: ; WORD 1- ADDRESS OF FIRST ITEM IN LIST (0 FOR NULL LIST) ; WORD 2- ADDRESS OF LAST ITEM IN LIST (UNDEFINED FOR NULL LIST) ; ; SUCCESSIVE ITEMS IN THE LIST HAVE THE FORMAT: ; WORD 3- ADDRESS OF NEXT ITEM (ADDRESS OF LISTHEAD IF ; LAST ITEM) ; WORD 4- ADDRESS OF PREVIOUS ITEM (ADDRESS OF LISTHEAD ; IF FIRST ITEM) ; ; VALUES STORED INTERNALY IN CLONE ARE STORED IN ITEMS WHICH ARE NOT ; THEMSELVES LIST ITEMS. VALUE ITEM FORMAT IS: ; WORD 3- ADDRESS OF SYMBOL TABLE ENTRY FOR VALUE ; ZERO IF VALUE IS TEMPORARY. ; WORD 4- MODE OR TYPE OF THE VALUE (EX. INTEGER, STRING) ; WORD 5 ONWARD - VALUE DATA. ; ; ; THE DYNAMIC MEMORY POOL OCCUPIES VIRTUAL ADDRESS SPACE IN THE LOW ; MEMORY REGION NORMALY MAPPED TO THE EXECUTIVE IN A PRIVILIGED TASK ; THE PHYSICAL MEMORY IS THE SPACE BETWEEN THE HIGHEST WORD OF TASK ; CODE AND THE END OF THE TASK IMAGE ALLOCATION. THIS MAY BE ALLOCATED ; EITHER BY THE EXTTSK OPTION IN TKB OF BY THE /INC SWITCH IN INSTALL. ; IN EITHER CASE CLONE WILL USE AS MUCH SPACE AS IS AVAILABLE TO CREATE ; THE DYNAMIC STORAGE AREA. ; AS SOME ROUTINES REQUIRE PRIVILIGED TASK MAPPING, THE ROUTINES ; UNMAPD AND MAPD ARE PROVIDED TO UNMAP AND MAP THE DYNAMIC STORAGE AREA. ; ; TEXT$ OFF .PAGE .PSECT CL1DYN ; ; .MCALL CRAW$,MAP$,UMAP$,WDBBK$,DIR$,EXIT$S,EXTK$ ; ; ; DEFINE THE APR AND WINDOW SIZE FOR THE MAPPING DYNAPR=1 ;AVOID APR 0 COZ IT CAN CAUSE PROBLEMS DYNWSZ=12.*32. ;12K WINDOW IN 32 WORD BLOCKS ; ; ; ; LIST ADMINISTRATION ROUTINES ; ; ; THE FOLLOWING ROUTINES OPPERATE ON DOUBLE LINKED LISTS OF ITEMS ; ; THE FORWARD POINTER IS AT OFFSET 4 IN THE ITEM ; THE BACKWARD POINTER AT OFFSET 6 ; THE LISTHEAD IS JUST TWO WORDS: FIRST,LAST ; A FORWARD POINTER OF ZERO INDICATES END OF LIST ; BUT IS NOT SET BY THESE ROUTINES. A NULL LIST IS ; INDICATED BY A ZERO FIRST WORD OF THE LISTHEAD. ; ; ; ; LINKB - LINK AN ITEM TO THE BEGINNING OF A LIST ; INPUT: R2=ITEM TO BE LINKED ; R3=LISTHEAD ; ; REGISTERS DESTROYED: R4 ; LINKB:: MOV (R3),R4 ;GET FIRST ITEM BNE 1$ ;IS IT NULL MOV R2,(R3) MOV R2,2(R3) MOV R3,4(R2) MOV R3,6(R2) RETURN 1$: MOV R2,(R3) MOV R4,4(R2) MOV R3,6(R2) MOV R2,6(R4) RETURN ; ; ; ; UNLINK - UNLINK AN ITEM FROM A LIST ; INPUT: R2=ADDRESS OF ITEM ; R3=ADDRESS OF LISTHEAD ; ; REGISTERS DESTROYED: R4 ; UNLINK::CMP 4(R2),R3 ;LAST ITEM BNE 1$ MOV 6(R2),2(R3) ;SET REVERSE POINTER BR 2$ 1$: MOV 4(R2),R4 ;GET SUCCESSOR MOV 6(R2),6(R4) ;REVERSE POINTER 2$: CMP 6(R2),R3 ;FIRST ITEM ? BNE 3$ MOV 4(R2),(R3) ;UPDATE LISTHEAD BR 4$ 3$: MOV 6(R2),R4 MOV 4(R2),4(R4) 4$: CMP (R3),R3 ;NULL LIST ? BNE 5$ CLR (R3) ;ZERO LISTHEAD CLR 2(R3) 5$: RETURN ; ; ; ; LINKA - LINK AN ITEM AFTER A SPECIFIED ITEM ; INPUT: R1=CURRENT ITEM ; R2=ITEM TO LINK IN ; R3=LISTHEAD ADDRESS ; OUTPUT: ITEM IS LINKED IMMEDIATLY AFTER THE ITEM ; INDICATED BY R1 ; ; REGISTERS DESTROYED: R4 ; LINKA:: MOV 4(R1),R4 ;GET SUCCESSOR BNE 1$ ;IF NULL ITS END OF LIST MOV R3,R4 ;SO USE LISTHEAD 1$: MOV R4,4(R2) ;SET FORWARD LINK MOV R1,6(R2) ;AND BACKWARD LINK MOV R2,4(R1) ;LINK INTO FORWARD CHAIN CMP R4,R3 ;LAST ITEM ? BNE 2$ ;SKIP IF NOT MOV R2,2(R4) ;SET REVERSE POINTER IN LISTHEAD BR 3$ 2$: MOV R2,6(R4) ;SET REVERSE POINTER IN SUCCESSOR 3$: RETURN ; ; ; ; LINKE - LINK AN ITEM AT THE END OF A LINKED LIST ; ; INPUT: R2 - ITEM TO LINK ; R3 - ADDRESS OF LISTHEAD ; ; REGISTERS DESTROYED: R1,R4 ; LINKE:: TST (R3) ;NULL LIST ? BEQ LINKB ;IF SO LINK AT BEGINNING MOV 2(R3),R1 ;ELSE GET END OF LIST BR LINKA ;LINK AFTER LAST ITEM .PAGE ; ; THE FOLLOWING ROUTINES CREATE AND DELETE ITEMS ; ; ; ; VOIDSP - RETURN AN UNATTACHED ITEM TO THE FREE LIST ; INPUT: R0=ITEM TO RETURN CONDITIONALY ; OUTPUT: IF ITEM OWNER WORD IS ZERO THE ITEM ; IS RETURNED TO THE FREE-LIST. OTHERWISE ; NO ACTION OCCURES. ; R0=0 IF ITEM DE-ALLOCATED ; OTHERWISE PRESERVED ; ; ALL OTHER REGISTERS PRESERVED ; VOIDSP::MOV (SP),RTNADR ;SAVE RETURN ADDRESS TST R0 ;ANYTHING TO DO ? BEQ 1$ TST 4(R0) ;ANY OWNER ? BNE 1$ ;IF SO DO NOTHING CALLR FREESP ;ELSE FREE THE SPACE ; 1$: CLR R0 RETURN ; ; ; ; CPYITM - DUPLICATE AN ITEM IN R0 ; ; INPUT: R0 ADDRESS OF ITEM TO COPY ; OUTPUT: R0 ADDRESS OF DUPLICATE ITEM ; OWNER WORD IS CLEARED ; ; OTHER REGISTERS MODIFIED: NONE ; CPYITM::MOV (SP),RTNADR MOV R1,-(SP) MOV R2,-(SP) CMP R0,(R0) ;CHECK VALIDITY BNE CHKERR MOV R0,R2 MOV 2(R0),R1 CALL GETSP MOV R0,-(SP) CLR 4(R0) ADD #6,R0 ADD #6,R2 SUB #3,R1 1$: MOV (R2)+,(R0)+ SOB R1,1$ MOV (SP)+,R0 MOV (SP)+,R2 MOV (SP)+,R1 RETURN ; ; ; ; GETSPA - ALLOCATE A BLOCK OF DYNAMIC MEMORY ; ; INPUT: R1= LENGTH REQUIRED IN WORDS ; ; OUTPUT: R0= ADDRESS OF ITEM ALLOCATED ; WORD ONE IS SET TO ITS OWN ADDRESS ; WORD TWO CONTAINS THE ITEM LENGTH ; THE REMAINDER OF THE BUFFER IS ZERO ; ; IF SUFFICIENT SPACE IS NOT AVAILABLE IN DYNAMIC MEMORY, RETURN IS ; WITH C SET AND R0=ZERO ; ; GETSPA::CALL DISAST MOV R1,-(SP) MOV R2,-(SP) ASL R1 ;CONVERT TO BYTES MOV #FREEHD,R0 CALL $RQCB ;REQUEST CORE BLOCK BCC 1$ ERROR$ #E.SPA ;REPORT SPACE EXHAUSTED CLR R0 SEC BR 10$ ;RETURN ; 1$: MOV R0,R1 ;COPY ITEM ADDRESS MOV 2(SP),R2 ;GET BACK LENGTH IN WORDS 2$: CLR (R1)+ ;ZERO THE ITEM SOB R2,2$ MOV R0,(R0) ;SET CHECK WORD MOV 2(SP),2(R0) ;SET BLOCK LENGTH (WORDS) CLC ;NO ERRORS ; 10$: MOV (SP)+,R2 MOV (SP)+,R1 RETURN ; ; ; ; GETSP - ALLOCATE AN ITEM OF DYNAMIC MEMORY ; ; AS GETSPA BUT CAUSES A CLONE CRASH IF INSUFFICIENT SPACE IS ; IS AVAILABLE ; GETSP:: CALL GETSPA BCS 1$ RETURN ; 1$: JMP ABORT ;ABANDON ; ; ; ; FREESP - DE-ALLOCATE THE ITEM AT R0 ; INPUT: R0=ITEM POINTER ; OUTPUT: R0=0 ; ; REGISTERS DESTROYED: NONE ; ; FREESP::TST R0 ;IGNORE ARGUMENT OF ZERO BEQ 2$ MOV (SP),RTNADR ;SAVE CALLER IN CASE OF ERRORS CALL DISAST MOV R1,-(SP) MOV R2,-(SP) CMP R0,(R0) ;VERIFY CHECK WORD BNE CHKERR ; 1$: MOV 2(R0),R1 ;GET LENGTH ASL R1 ;IN BYTES MOV R0,R2 ;COPY ITEM ADDRESS MOV #FREEHD,R0 CALL $RLCB ;RELEASE CORE BLOCK MOV (SP)+,R2 MOV (SP)+,R1 CLR R0 2$: RETURN ; ; ; ; CHKERR - CRASH ON AN INVALID ITEM ; INPUT: RTNADR INITIALISED BY ENTRY TO ONE OF: ; VOIDSP ; FREESP ; CPYITM ; ; CHKERR: MOV #ADRBUF,R0 ;CONVERT CALLING ADDRESS MOV RTNADR,R1 MOV #1,R2 CALL $CBOMG ;CONVERT ADDRESS MOV #INVMES,R2 CALL OUT JMP ABORT ; RTNADR: .WORD 0 ; ; ; ; CHKSP - DETERMINE AVAILABLE ITEM SPACE ; ; OUTPUT: R3=TOTAL AVAILABLE SPACE IN WORDS ; R4=LARGEST CONTIGUOUS SPACE ; OTHER REGISTERS PRESERVED ; CHKSP:: CALL DISAST ;INHIBIT ASTS MOV R0,-(SP) MOV #FREEHD,R0 ;POINT TO LIST-HEAD CLR R3 ;INIT COUNTERS CLR R4 1$: MOV (R0),R0 ;NEXT ITEM BEQ 3$ ;STOP AT END ADD 2(R0),R3 ;ACCUMULATE SPACE CMP 2(R0),R4 ;BIGGEST HOLE TO-DATE BLE 2$ MOV 2(R0),R4 ;IF SO SAVE IT 2$: BR 1$ ;ON TO NEXT ITEM 3$: ASR R3 ;CONVERT BYTES TO WORDS ASR R4 MOV (SP)+,R0 RETURN ; ; ; ; INITSP - INITIALISE DYNAMIC SPACE ADMINISTRATION ; ; THIS ROUTINE CREATES A WINDOW IN THE ADDRESS RANGE OF APRS 1,2,3 ; AND MAPS IT TO THE REGION BETWEEN THE END OF TASK CODE AND THE ; END OF THE TASK ALLOCATION AS SET BY THE INS /INC SWITCH. ; ONCE THE REGION IS MAPPED IT IS INITIALIZED AS A SINGLE FREE ITEM ; FOR USE BY THE MEMORY ALLOCATION REOUTINS. ; INITSP::DIR$ #EXTDPB ;EXTEND TASK TO A REASONABLE SIZE BCS ERR4 DIR$ #CRWDPB ;CREATE A WINDOW FOR THE MAPPING BCS ERR1 MOV LIMIT+2,R1 ;GET HIGHEST ADDRESS IN TASK SUB #120000-77,R1 ;SUBTRACT VIRTUAL ADDRESS OF PHYSICAL ZERO ;AND ROUND UP TO 32 WORD BOUNDRY ASH #-6,R1 ;FORM OFFSET IN 32 WORD BLOCKS MOV R1,WDB+W.NOFF ;SET OFFSET IN TASK TO START MAPPING CALL MAPD ;MAP TO REGION MOV WDB+W.NBAS,R0 ;GET WINDOW BASE ADDRESS MOV R0,FREEHD ;INIT FREE LIST HEAD CLR (R0)+ ;END OF FREE LIST MOV WDB+W.NLEN,R1 ;GET LENGTH OF MAPPING (32 WORD BLOCKS) ASH #6,R1 ;CONVERT TO BYTES MOV R1,(R0)+ ;LENGTH OF FREE ITEM RETURN ;THATS ALL ; ; ; ; MAPD - MAP TO DYNAMIC SPACE AREA ; MAPD:: DIR$ #MAPDPB ;MAP REGION BCS ERR2 RETURN ; ; ; ; UNMAPD - UNMAP FROM DYNAMIC STORAGE AREA ; UNMAPD::DIR$ #UNMDPB ;UNMAP REGION BCS ERR3 RETURN ; ; ; ; OUTPUT ERROR MESSAGE AND EXIT WHEN SOMETHING SCREWS UP ; ERR4: INC ERRNUM ERR3: INC ERRNUM ERR2: INC ERRNUM ERR1: INC ERRNUM ADD #'0,ERRNUM MOV #MAPMES,R2 ;REPORT MAPPING ERROR OUTMES: CALL OUT EXIT$S ; ; ; MAPMES: .ASCII /CLONE -- DYNAMIC MEMORY ERROR / ERRNUM: .WORD 0 ; NSPMES: .ASCIZ /CLONE -- NO MORE DYNAMIC MEMORY/ ; INVMES: .ASCII /CLONE -- INVALID ITEM / ADRBUF: .ASCIZ / / .EVEN ; ; ; ; LIMIT: .LIMIT ;GET TASK ADDRESS LIMITS ; FREEHD: .WORD 0,0 ; EXTDPB: EXTK$ POOLSZ/32. CRWDPB: CRAW$ WDB MAPDPB: MAP$ WDB UNMDPB: UMAP$ WDB ; WDB: WDBBK$ DYNAPR,DYNWSZ,0,0,0, ; .END