-- SpaceA.Mesa Last Edited by Curry on October 1, 1980

DIRECTORY
AltoDefsUSING [PageSize],
FSPDefsUSING [
AddToNewZone,
DestroyZone,
FreeNode,
MakeNewZone,
MakeNode,
NoRoomInZone,
NodeOverhead,
ZoneOverhead,
ZonePointer],
InlineDefs,
IODefs,
Space,
SegmentDefs,
StringDefs,
SystemDefs;

SpaceA: PROGRAM
IMPORTS
InlineDefs,
IODefs,
FSPDefs,
SegmentDefs,
StringDefs,
SystemDefs
EXPORTS Space = PUBLIC

BEGIN OPEN AltoDefs, SegmentDefs, Space; -- Free Storage Package --


myHeap:FSPDefs.ZonePointer ← NIL;
Machine: SegmentDefs.MachineType =
SegmentDefs.GetMemoryConfig[].AltoType;
DMachine: BOOLEAN = (Machine = D0) OR (Machine = Dorado);
CurrentBase, RefBase:PageNumber ← DefaultBase2;
Base2:PageNumber ← DefaultBase2;
Base3:PageNumber ← DefaultBase3;
Base4:PageNumber ← Base3 - 1;
Base5:PageNumber ← Base4 - 1;

HeapZone:PROCEDURE RETURNS [POINTER] =
BEGIN RETURN[myHeap] END;

InitHeap:PROCEDURE[np:CARDINAL] =
BEGIN OPEN SystemDefs, FSPDefs;
IF myHeap # NIL THEN EraseHeap[];
myHeap ← MakeNewZone[
AllocateResidentPages[np],
np*AltoDefs.PageSize,
FreePages];
RETURN
END;

EraseHeap:PROCEDURE =
BEGIN
FSPDefs.DestroyZone[myHeap];
myHeap ← NIL;
RETURN
END;

GetSpace:PROCEDURE[nwords:CARDINAL] RETURNS[p:POINTER] =
BEGIN OPEN SystemDefs, FSPDefs;
np:CARDINAL;
IF myHeap = NIL THEN InitHeap[1];
p ← MakeNode[myHeap, nwords !
NoRoomInZone => BEGIN
np ← PagesForWords
[nwords + ZoneOverhead + NodeOverhead];
AddToNewZone[
myHeap,
AllocateResidentPages[np],
np*AltoDefs.PageSize,
FreePages];
RESUME
END];
RETURN
END;

FreeSpace:PROCEDURE[p:POINTER] =
BEGIN FSPDefs.FreeNode[myHeap, p]; RETURN END;

GetSpaceLong:PROCEDURE[nwords:CARDINAL]
RETURNS[lp:LONG POINTER]=
BEGIN OPEN SegmentDefs;
IF DMachine THEN lp ←
LongDataSegmentAddress[NewDataSegment
[DefaultXMBase, (nwords+255)/256 ]]
ELSE lp ← SystemDefs.AllocateSegment[nwords];
RETURN[ lp ];
END;

OldGetSpaceLong:PROCEDURE[nwords:CARDINAL]
RETURNS[lp:LONG POINTER]=
BEGIN OPEN SegmentDefs;
RefBase ← CurrentBase;
IF DMachine THEN lp ←
LongDataSegmentAddress[NewDataSegment
[CurrentBase, (nwords+255)/256 ! InsufficientVM =>
BEGIN
CurrentBase ← CurrentBase - 1;
IF CurrentBase < Base5 THEN CurrentBase ← Base2;
IF CurrentBase = RefBase
THEN ERROR
ELSE RETRY;
END ] ]
ELSE lp ← SystemDefs.AllocateSegment[nwords];
RETURN[ lp ];
END;

FreeSpaceLong:PROCEDURE[lp:LONG POINTER]=
BEGIN OPEN SegmentDefs;
IF DMachine THEN DeleteDataSegment [LongVMtoDataSegment[lp]]
ELSE SystemDefs.FreeSegment[InlineDefs.LowHalf[lp]];
END;

GetString:PROCEDURE[nchars:CARDINAL] RETURNS [s:STRING] =
BEGIN
s ← GetSpace[StringDefs.WordsForString[nchars]];
s↑ ← [length:0, maxlength:nchars, text: ];
RETURN
END;

FreeString:PROCEDURE[s:STRING] = LOOPHOLE[FreeSpace];

CopyString:PROCEDURE [s: STRING, longer: CARDINAL ← 0]
RETURNS [STRING] = BEGIN
ns: STRING;
IF s = NIL THEN RETURN
[IF longer = 0 THEN NIL ELSE GetString[longer]];
ns ← GetString[s.length + longer];
InlineDefs.COPY[from: @s.text, to: @ns.text,
nwords: (s.length + 1)/2];
ns.length ← s.length;
RETURN[ns];
END;
CheckLongStorage:PROCEDURE[str:STRING ← "?"] =
BEGIN
bank,npages:CARDINAL;
lp:LONG POINTER ← GetSpaceLong[1];
FreeSpaceLong[lp];
bank ← InlineDefs.HighHalf[lp];
npages ← InlineDefs.BITSHIFT[ InlineDefs.LowHalf[lp],-8 ];
IODefs.WriteLine[" "];
IODefs.WriteDecimal[LOOPHOLE[npages]];
IODefs.WriteString[" pages available in bank "];
IODefs.WriteDecimal[LOOPHOLE[bank]];
IODefs.WriteString[" at "];
IODefs.WriteString[str];
IODefs.WriteLine[" .... Ready?"];
[] ← IODefs.ReadChar[];
END;

END.