Google
 

Trailing-Edge - PDP-10 Archives - decuslib10-08 - 43,50512/corbli.mac
There are no other files named corbli.mac in the archive.
	TITLE	CORBLI
	ENTRY	CORRES,CORGET,CORFRE
	TWOSEG
	RELOC	400000
;**Special version of CORMGT for use with BLISS
;**
;** Skip returns have been eliminated
;** The routines return 0 if they get an error
;** CORGET expects one argument PUSHed onto the stack (Length of block)
;** CORFRE expects 2 arguments PUSHed onto the stack:
;**		PUSHed first: the address of the block to free
;**		PUSHed second: the length of the block to free
	RADIX	10
T1=	1		; SCRATCH AC
T2=	2
T3=	3
LEN=	6		; LENGTH OF CURRENT BLOCK
BLK=	7		; ADDRESS OF CURRENT BLOCK
BLP=	8		; ADDRESS OF PREVIOUS BLOCK IN CHAIN
BLN=	9		; ADDRESS OF NEXT BLOCK IN CHAIN
P=	15		; PUSHDOWN LIST POINTER

SAVEND==	9		; LAST AC TO BE SAVED AND RESTORED
; RESET STORAGE
ALINI::			;Another name for the same thing
CORRES:	SETZM	FREPTR		; NO MORE FREE STORAGE CHAIN
	SETZM	NEXT		; NO MORE "NEXT" POINTER
	SETZM	SAVJBFF		; Clear saved .JBFF
	HLRZ	T1,.JBSA##	; Get first free location
	MOVEM	T1,FREEOK	; Save it away
	POPJ	P,

; ALLOCATE CORE STORAGE
CORGET:	PUSH	P,[0]		; INDICATE CORGET
	SKIPA

; RELEASE A STORAGE BLOCK
CORFRE:	PUSH	P,[1]		; INDICATE CORFRE

COM:	MOVEM	SAVEND,ACS+SAVEND ; SAVE AC'S TO SAVEND
	MOVE	SAVEND,[XWD 0,ACS]
	BLT	SAVEND,ACS+SAVEND-1
;	HLRZ	LEN,T1		; GET LENGTH OF BLOCK
;	HRRE	BLK,T1		; GET ADDR OF BLOCK (FOR FREE)
;Change for BLISS-36C argument passing
	HRRE	LEN,-2(P)	; Length is always the last argument
	HRRZ	BLK,-3(P)	; Addr for FREE, garbage otherwise
	POP	P,T1		; GET ENTRY INDICATOR
	JRST	.+1(T1)		; BRANCH BASED ON ENTRY
	JRST	GET		; CALL TO CORGET
	JRST	FREE		; CALL TO CORFRE
; COME HERE ON ALLOCATION REQUEST.  AT THIS POINT, 
;	LEN CONTAINS THE SIZE OF THE DESIRED BLOCK
GET:	MOVEI	BLN,FREPTR	; POINT TO FREE STORAGE CHAIN

; COME HERE TO LOOK AT THE FIRST (NEXT) BLOCK IN THE FREE STORAGE
; CHAIN.  WE MUST FIND THE FIRST BLOCK IN THE CHAIN WHICH IS
; LARGE ENOUGH TO HOLD THE DESIRED REQUEST.
GTL:	MOVE	BLP,BLN		; PREVIOUS BLOCK = OLD NEW BLOCK
	HRRZ	BLN,0(BLN)	; GET ADDRESS OF NEXT BLOCK IN CHAIN
	JUMPE	BLN,GTX		; GO EXPAND CORE AT END OF CHAIN
	HLRZ	T1,0(BLN)	; GET SIZE OF NEW BLOCK
	CAMLE	LEN,T1		; IS IT BIG ENOUGH?
	JRST	GTL		; GO FOR NEXT BLOCK IF NOT

; AT THIS POINT, WE HAVE FOUND A SUITABLE BLOCK.  THE ACS ARE:
;	BLN	POINTS TO THE SUITABLE BLOCK
;	BLP	POINTS TO THE PRECEDING BLOCK IN THE CHAIN
;	T1	CONTAINS THE LENGTH OF THE BLOCK POINTED TO BY BLN
;	LEN	CONTAINS THE SIZE OF THE DESIRED BLOCK.
; FURTHERMORE, WE KNOW AT THIS POINT THAT LEN IS LESS THAN OR
; EQUAL TO T1.
	MOVE	BLK,BLN		; THIS IS THE BLOCK ADDRESS WE WILL RETURN
;** Make it zero out left half and return only address
;** We know the length already
	HRRZM	BLK,AC1		; STORE INTO RETURN AC T1
	SUB	T1,LEN		; GET LENGTH REMAINING IN BLN BLOCK AFTER
				; WE REMOVE WHAT WE WANT.
	JUMPG	T1,GTLG		; GO IF THERE IS SOMETHING LEFT

; IF CONTROL COMES HERE, THEN THE CURRENT BLOCK IS EXACTLY THE SIZE
; REQUESTED BY THE CALLER. WE MUST SIMPLY REMOVE IT FROM THE CHAIN.
	HRRZ	T2,0(BLK)	; GET ADDRESS OF FOLLOWING BLOCK
	HRRM	T2,0(BLP)	; STORE AS "NEXT" POINTER FOR PRECEDING BLOCK

; NOW WE NEED ONLY UPDATE THE "NEXT" LOCATION.  THIS LOCATION CONTAINS
; THE ADDRESS OF THE FIRST LOCATION BEYOND THE LAST BLOCK IN
; THE FREE CHAIN.  IF WE HAVE GIVEN AWAY THE LAST BLOCK IN THE
; CHAIN, THEN "NEXT" MUST BE MODIFIED.
	ADD	BLK,LEN		; GET ADDR OF END OF CURRENT BLOCK
	CAME	NEXT		; WERE WE AT END OF CHAIN?
	JRST	RET		; JUST RETURN IF NOT
	HLRZ	T1,0(BLP)	; GET LENGTH OF PRECEDING BLOCK
	ADD	T1,BLP		; AND FIND END OF IT
	SKIPE	FREPTR		; BUT IS THE FREE CHAIN NOW EMPTY?
	SETZM	T1		; THEN "NEXT" = 0 IN THAT CASE
	MOVEM	T1,NEXT		; SET CORRECT ADDR FOR NEXT
	JRST	RET		; RETURN TO CALLER
; COME HERE IF WE HAVE FOUND A BLOCK WHICH IS LARGER THAN THE
; DESIRED SIZE.  AT THIS POINT,
;	BLN	CONTAINS POINTER TO THE FOUND FREE BLOCK
;	BLP	POINTS TO THE PRECEDING BLOCK IN THE CHAIN
;	BLK	SAME AS BLN
;	T1	LENGTH REMAINING FOR THE BLN BLOCK AFTER REMOVING
;		THE BLOCK WE ARE GIVING AWAY
;	LEN	THE LENGTH OF THE BLOCK WE ARE GIVING AWAY.
GTLG:	ADDM	LEN,0(BLP)	; ADJUST POINTER IN PRECEDING BLOCK
	HRRZ	BLN,0(BLP)	; BLN NOW POINTS TO NEW SHORTENED BLOCK
	HRL	T1,0(BLK)	; GET ADDRESS OF FOLLOWING BLOCK
	MOVSM	T1,0(BLN)	; STORE LENGTH/NEXT FOR SHORTENED BLOCK
	JRST	RET		; RETURN TO CALLER

; COME HERE WHEN THE END OF THE FREE CHAIN IS REACHED, INDICATING
; THAT THERE IS NO FREE BLOCK WHICH IS LARGE ENOUGH TO SATISFY
; THE REQUEST.
; WE SIMPLY ALLOCATE STORAGE FROM THE END OF CORE, INDICATED BY
; THE .JBFF POINTER, AND WE EXPAND CORE IF NECESSARY.
GTX:	SKIPN	BLK,SAVJBFF	; Use saved JBFF value if any
	 HRRZ	BLK,.JBFF##	; GET ADDRESS WE WILL RETURN
	MOVE	T1,BLK		; COPY IT OVER
	ADD	T1,LEN		; THIS WILL BE NEW .JBFF VALUE
	CAILE	T1,-1		; CHECK FOR SEGMENT OVERFLOW
	JRST	NOCORE		; WE'VE RUN OUT OF STORAGE
	MOVE	T2,T1		; COPY NEW END OF CORE POINTER
	SOS	T2		; DECREMENT TO GET LAST LOC WANTED
	CAMG	T2,.JBREL##	; DO WE HAVE TO EXPAND CORE?
	JRST	.+3		; SKIP EXPANSION IF NOT
	CORE	T2,		; EXPAND CORE
	JRST	NOCORE		; EXPANSION FAILED
	SKIPE	SAVJBFF		; Save in saved JBFF if used
	 JRST	[MOVEM T1,SAVJBFF
		 JRST  .+2]	; Don't overwrite the real .JBFF in this case
	MOVEM	T1,.JBFF##	; SET NEW .JBFF
;** Make left half of AC1 0 so we return only address
	HRRZM	BLK,AC1		; CHANGE RETURN AC
	JRST	RET		; RETURN TO CALLER
; COME HERE TO RETURN A BLOCK OF STORAGE TO THE FREE CHAIN.
; AT THIS POINT, 
;	BLK	POINTS TO THE BLOCK TO BE RETURNED
;	LEN	CONTAINS THE LENGTH OF THE BLOCK BEING FREED
FREE:	CAMG	BLK,FREEOK	; IS ADDRESS TOO CLOSE TO ZERO?
	JRST	BADFRE		; BAD IF SO
	SKIPN	T1,SAVJBFF	;Use saved JBFF if any
	 MOVE	T1,.JBFF##	;use real one
	CAML	BLK,T1		; HAS .JBFF ALREADY BEEN CHANGED?
	JRST	RET		; NOTHING TO DO IF SO

; WE MUST LOOP THROUGH THE EXISTING CHAIN OF FREE BLOCKS TO
; DETERMINE WHERE THE BLOCK BEING FREED SHOULD GO.
	MOVEI	BLN,FREPTR	; POINT TO BEGINNING OF CHAIN

; COME HERE TO GET FIRST (NEXT) BLOCK IN FREE CHAIN
FRL:	MOVE	BLP,BLN		; MOVE UP ONE BLOCK
	HRRZ	BLN,0(BLN)	; GET ADDR OF NEXT
	JUMPE	BLN,.+3		; SKIP TEST IF END OF CHAIN
	CAMGE	BLN,BLK		; IS THIS THE RIGHT POSITION?
	JRST	FRL		; LOOP FOR NEXT IF NOT

; WE COME HERE WHEN WE HAVE THE CORRECT POSITION OF THE BLOCK
; BEING FREED.  EITHER THE BLOCK IS TO BE INSERTED BETWEEN
; THE TWO BLOCKS POINTED TO BY BLP AND BLN, OR ELSE WE HAVE
; REACHED THE END OF THE CHAIN, AND THE NEW BLOCK GOES ONTO THE
; END OF THE CHAIN.  IN THE LATTER CASE, BLP POINTS TO THE LAST
; BLOCK IN THE CHAIN, AND BLN IS ZERO.

; WE MUST NOW CHECK TO SEE WHETHER THE BLOCK BEING FREED LIES
; BETWEEN THE TWO BLOCKS, OR WHETHER IT OVERLAPS ONE OF THE
; BLOCKS ON THE CHAIN.  IF IT OVERLAPS, THEN AN ILLEGAL ARGUMENT
; WAS PASSED TO THE ROUTINE.
	HLRZ	T1,0(BLP)	; GET LENGTH OF PRECEDING BLOCK
	ADD	T1,BLP		; COMPUTE END OF PRECEDING BLOCK
	CAMLE	T1,BLK		; DOES CURRENT BLOCK OVERLAP THIS?
	JRST	BADFRE		; BLOCKS OVERLAP -- ERROR
	MOVE	T2,BLK		; GET ADDR OF BLOCK BEING FREED
	ADD	T2,LEN		; COMPUTE ADDR OF END OF BLOCK
	JUMPE	BLN,.+3		; IF END OF CHAIN, DON'T TEST FOR OVERLAP
	CAMLE	T2,BLN		; FREED BLOCK OVERLAP NEXT BLOCK?
	JRST	BADFRE		; OVERLAP -- THIS IS AN ERROR

; AT THIS POINT, WE HAVE VERIFIED THAT THE BLOCK BEING RETURNED
; IS LEGAL, AND WE CAN NOW INSERT THE FREED BLOCK INTO
; THE FREE BLOCK CHAIN.
	HRLM	LEN,0(BLK)	; SET LENGTH OF FREED BLOCK
	HRRM	BLN,0(BLK)	; NEW BLOCK POINTS TO NEXT BLOCK
	HRRM	BLK,0(BLP)	; PRECEDING BLOCK POINTS TO NEW BLOCK
; WE HAVE NOW INSERTED THE FREED BLOCK, BUT ONE MORE CHECK HAS TO BE
; MADE.  IT IS POSSIBLE THAT THE FREED BLOCK CAN BE COMBINED WITH
; THE PRECEDING BLOCK, OR THE NEXT BLOCK, OR BOTH, TO FORM ONE BIG
; BLOCK.  AT THIS POINT,
;	BLP	POINTS TO THE PRECEDING
;	T1	POINTS TO THE FIRST LOCATION BEYOND THE PRECEDING BLOCK
;	BLK	POINTS TO THE NEW BLOCK
;	T2	POINTS TO THE FIRST LOCATION BEYOND THE NEW BLOCK
;	BLN	POINTS TO THE NEXT BLOCK IN THE CHAIN, OR IS ZERO
;		IF THE NEW BLOCK HAS GONE AT THE END OF THE CHAIN
;	LEN	IS THE LENGTH OF THE CURRENT BLOCK
	CAME	T1,BLK		; END OF PRECEDING BLOCK = START OF
				; NEW BLOCK?
	JRST	FRCH		; GO IF NOT
	MOVSS	LEN		; PUT LENGTH OF NEW BLOCK INTO LEFT HALF
	ADDM	LEN,0(BLP)	; INCREASE LENGTH OF PRECEDING BLOCK
	HRRM	BLN,0(BLP)	; PRECEDING BLOCK NOW POINTS TO NEXT BLOCK
	MOVE	BLK,BLP		; NEW BLOCK IS NOW THE COMBINED BLOCK

; NOW CHECK TO SEE IF THE NEW BLOCK CAN BE COMBINED WITH THE
; NEXT BLOCK.
FRCH:	CAME	T2,BLN		; END OF NEW BLOCK = START OF NEXT?
	JRST	FRCE		; GO IF NOT
	HLLZ	LEN,0(BLN)	; GET LENGTH OF NEXT BLOCK
	ADDM	LEN,0(BLK)	; INCREASE LENGTH OF NEW BLOCK
	HRRZ	T1,0(BLN)	; GET BLOCK POINTED TO BY NEXT BLOCK
	HRRM	T1,0(BLK)	; TAKE NEXT BLOCK OUT OF THE CHAIN

; THE CHAIN IS NOW CORRECT, AND ONLY ONE ADDITIONAL DETAIL MUST BE
; CLEANED UP.  THE LOCATION "NEXT" POINTS TO THE LOCATION OF MEMORY
; WHICH IS ONE BEYOND THE LAST BLOCK ON THE FREE CHAIN.  THIS
; WILL HAVE TO BE UPDATED NOW IF THE NEW BLOCK WAS PUT ONTO THE
; END OF THE CHAIN.  SINCE T2 POINTS TO THE FIRST LOCATION AFTER THE
; END OF THE NEW BLOCK, WE MAY TEST FOR THIS SITUATION BY SEEING
; WHETHER T2 EXCEEDS NEXT.
FRCE:	CAML	T2,NEXT		; SHOULD NEXT BE UPDATED?
	MOVEM	T2,NEXT		; UPDATE NEXT
;	JRST	RET
; COME HERE TO GIVE A NORMAL RETURN TO THE CALLER
;**RET:;Skip returns are a NO-NO!
;***	AOS	(P)		; INCREMENT RETURN ADDRESS

; COME HERE TO GIVE AN ERROR RETURN TO THE CALLER.

; WE MUST NOW CHECK TO SEE WHETHER IT IS TIME TO FREE UP STORAGE.
; WE MUST DO THIS IF .JBFF HAS BECOME LESS THAN OR EQUAL
; TO "NEXT", THE LOCATION FOLLOWING THE END OF THE FREE CHAIN.
; IF .JBFF HAS BECOME SMALLER, THEN WE REMOVE THE LAST BLOCK ON
; THE FREE CHAIN, RECOMPUTE "NEXT", SET .JBFF TO POINT TO
; THE BEGINNING OF THE BLOCK JUST RELEASED, AND EXECUTE A CORE
; UUO TO TELL THE MONITOR THAT WE DON'T WANT ANYTHING AFTER .JBFF.

; IT MAY BE DESIRABLE AT SOME POINT TO REWRITE THIS SECTION OF CODE
; TO FIGURE OUT WHETHER A CORE UUO IS REALLY NECESSARY. THIS WILL
; REQUIRE SOME KA/KI DEPENDING CODE.
RETER:	;**In case of error, return 0
	SETZM	AC1

RET:
	SKIPN	T2,SAVJBFF	;Use saved JBFF if in use
	 MOVE	T2,.JBFF##	;Use real one
	SKIPE	T1,NEXT		; GET "NEXT" VALUE, AND SKIP IF
				; FREE CHAIN IS EMPTY
	CAMGE	T1,T2		; LESS THAN .JBFF?
	JRST	RETC		; NOTHING TO DO

; WE MUST NOW FIND THE LAST BLOCK ON THE FREE CHAIN, SO THAT WE
; CAN RELEASE IT.
	MOVEI	BLN,FREPTR	; POINT TO CHAIN HEADER

; COME HERE TO MOVE UP TO FIRST (NEXT) FREE BLOCK IN CHAIN
RETL:	HRRZ	BLK,0(BLN)	; CURRENT BLOCK = BLOCK AFTER NEXT
	JUMPE	BLK,RETLA	; GO IF END OF CHAIN
	MOVE	BLP,BLN		; MOVE UP ONE BLOCK
	MOVE	BLN,BLK
	JRST	RETL		; AND LOOP BACK FOR NEXT

; WHEN CONTROL COMES HERE, BLP AND BLN POINT, RESPECTIVELY, TO THE
; LAST TWO BLOCKS ON THE FREE CHAIN.
RETLA:	HLLZS	0(BLP)		; PREVIOUS BLOCK IS NEW END OF CHAIN
	SKIPE	SAVJBFF		;Use saved .JBFF if in use
	 JRST	[MOVEM BLN,SAVJBFF
		 JRST .+2]	;Do not modify real one
	MOVEM	BLN,.JBFF##	; RESET .JBFF TO BEGINNING OF BLOCK
	SOS	BLN		; DECREMENT TO GET LAST LOC WANTED
	CORE	BLN,		; REDUCE SIZE OF CORE STORAGE
	JFCL			; SHOULD NEVER HAPPEN
	HLRZ	T1,0(BLP)	; GET LENGTH OF PRECEDING BLOCK
	ADD	T1,BLP		; GET LOCATION AFTER END OF BLOCK
	MOVEM	T1,NEXT		; AND STORE AS NEW VALUE OF "NEXT"
	SKIPN	FREPTR		; BUT IS FREE CHAIN EMPTY?
	SETZM	NEXT		; IF SO, THEN NEXT = 0

; WE NEED NOW ONLY RETURN TO THE CALLER, AFTER RESTORING HIS ACS.
RETC:	MOVSI	SAVEND,ACS	; SET BLT POINTER
	BLT	SAVEND,SAVEND	; RESTORE ALL REGISTERS
	POPJ	P,		; RETURN TO CALLER
	SUBTTL	ERROR MESSAGES

; COME HERE WHEN NO CORE IS AVAILABLE TO SATISFY CORGET REQUEST.
NOCORE:;	OUTSTR	[ASCIZ	/
;?CORNOC INSUFFICIENT STORAGE FOR CORGET REQUEST
;/]
;**Error message removed, routine will handle problem
	JRST	RETER

; COME HERE WHEN BAD ARGUMENTS ARE PASSED TO CORFRE
BADFRE:	OUTSTR	[ASCIZ	/
%Attempt to FREE storage that has not been allocated
/]
	JRST	RETER
	SUBTTL	LITERALS
	LIT
	SUBTTL	STORAGE AREA

	RELOC			; RELOCATE TO LOW SEGMENT

; FREPTR HAS THE FORMAT
;	XWD	0,ADDR OF FIRST BLOCK ON FREE CHAIN
; WHERE THE "ADDR" IS ZERO IF THE FREE CHAIN IS EMPTY.
; THE ELEMENTS OF THE FREE CHAIN ARE ORDERED BY INCREASING CORE
; ADDRESS.  THE FIRST WORD OF EACH ELEMENT OF THE FREE CHAIN
; HAS THE FORMAT
;	XWD	LENGTH OF THIS ELEMENT, ADDR OF NEXT ELEMENT
; WHERE THE "ADDR" IS ZERO FOR THE LAST ELEMENT OF THE FREE CHAIN.
; THE CORMGT ROUTINE AUTOMATICALLY COMBINES ADJACENT BLOCKS INTO
; ONE BIG BLOCK WHERE NECESSARY.
FREPTR:	BLOCK	1		; FREE CHAIN POINTER

; Saved value of .JBFF.  Set this up if playing "games" with .JBFF
; to build buffers or whatever.  CORBLI will read (and possibly modify)
; SAVJBFF instead of .JBFF if it is non-zero.  
; SAVJBFF MUST BE ZEROED if you don't want it to be believed.
SAVJBFF:: BLOCK	1		; Saved value of .JBFF


; LOCATION "NEXT" CONTAINS THE ADDRESS OF THE LOCATION FOLLOWING
; THE LAST BLOCK IN THE FREE CHAIN.  WE KEEP THIS AROUND SO THAT
; WE HAVE A QUICK WAY OF CHECKING WHETHER SOMEBODY ELSE HAS
; REDUCED .JBFF WITHOUT OUR KNOWING IT.  IF THE FREE CHAIN
; IS EMPTY, THEN LOCATION NEXT CONTAINS ZERO.
NEXT:	BLOCK	1		; NEXT LOC AFTER FREE CHAIN

; THE FOLLOWING IS THE SAVE AREA FOR THE ACS.
ACS:	BLOCK	SAVEND		; AC SAVE AREA
AC1=ACS+T1

; THE FOLLOWING LOCATION IS USED TO CHECK FOR ILLEGAL ARGUMENTS
; TO CORFRE. It is initialized from JOBSA[LH].
FREEOK::BLOCK	1		; NO FREE BLOCK CAN LIE BEFORE HERE.
	END