home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
RBBS in a Box Volume 1 #2
/
RBBS_vol1_no2.iso
/
add2
/
tavram.zip
/
TAVRAM.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1989-06-01
|
24KB
|
809 lines
(***************************************************************************)
(***************************************************************************)
(** **)
(** TaVram.PAS - Ta Virtual Ram - Turbo Pascal Unit **)
(** **)
(** Version 1.0 **)
(** **)
(** (written under version 5.0 of TP) **)
(** **)
(** **)
(** **)
(** Copyright 1989 - By Thomas Astin - All rights reserved. **)
(** **)
(** Thomas Astin (Compuserve 73407,3427) **)
(** 3451 Vinton Ave. #9 **)
(** L.A., CA 90034 **)
(** **)
(** Description: Virtual heap manager for Turbo Pascal. **)
(** **)
(** Revision history: **)
(** **)
(***************************************************************************)
(***************************************************************************)
{ $DEFINE DEBUG} {-Debug mode}
{$DEFINE ERRORMSG} {-Include error messages}
{$DEFINE USEINLINE} {-Use Inline code for VRamHandleOnHeap}
{$DEFINE HIDDEN} {-Use for hidden Vram/Vfree files}
{ $DEFINE USELONG} {-Use LongInt for TimesUsed}
{$IFDEF USEINLINE}
{$UNDEF USELONG} {-Cannot use LongInt w/Inline}
{$ENDIF}
{$IFDEF DEBUG}
{$UNDEF HIDDEN}
{$R-,S-}
{$ELSE}
{$R+,S+}
{$ENDIF}
Unit TaVRam;
Interface
uses
Dos,
GrabHeap;
const
DeRefIntVect = $66;
MaxVRamBuffer = 4096;
VRamNil = 0;
VRamSegSig = $FFFF; {-Signature indicates a VRam pointer}
VRamHeapFilename = 'VRAM.$$$';
VRamFreeFilename = 'VFREE.$$$';
type
VRamBufferPtr = ^VRamBufferArray;
VRamBufferArray = Array[1..MaxVRamBuffer] of byte;
VRamFreeRecord = Record
StartBlock,
EndBlock : Word;
end;
VRamBlockSizeRecord = Record
BSize : Word;
Fill : Array[1..16-SizeOf(Word)] of Byte;
end;
VRamHeapDescRecPtr = ^VRamHeapDescRec;
VRamHeapDescRec = Record
PrevHeapRecP,
NextHeapRecP : VRamHeapDescRecPtr;
TimesUsed :
{$IFDEF USELONG}
Longint; {-count of times dereferenced}
{$ELSE}
Word;
{$ENDIF}
RealP : Pointer; {-pointer to VRam block on heap}
VRamHandle : Word;
DataSize : Word;
Locked : Boolean;
end;
IntRegisterRecord = Record
BP, ES, DS, DI, SI, DX, CX, BX, AX, IP, CS, Flags : Word;
end;
var
AdjustHeapPtrAfterFreeMem : Boolean;
UseVRam : Boolean;
PageVRam : Boolean;
VRamMaxHeapToUse : LongInt;
VRamHeapUsed : LongInt;
function VRamPageOutOldest : Boolean;
procedure VRamPageOutFreeMem(Size : Word);
procedure VRamGetMem(var P: Pointer; Size: Word);
procedure VRamFreeMem(var P : Pointer; Size: Word);
{-Make life easier for the programmer}
procedure VRamOn;
Inline(
$C6/$06/>USEVRAM/$01);{ mov BYTE PTR [>UseVRam],1}
procedure VRamOff;
Inline(
$C6/$06/>USEVRAM/$00);{ mov BYTE PTR [>UseVRam],0}
procedure VRamPageOn;
Inline(
$C6/$06/>PAGEVRAM/$01);{ mov BYTE PTR [>PageVRam],1}
procedure VRamPageOff;
Inline(
$C6/$06/>PAGEVRAM/$00);{ mov BYTE PTR [>PageVRam],0}
Implementation
const
MaxVRamError = 4;
type
VRamMsgStr = String[80];
VRamMsgArray = Array[1..MaxVRamError] of VRamMsgStr;
const
VRamDeallocError = 1;
VRamPageoutError = 2;
VRamAllocError = 3;
VRamAllocFreeError = 4;
{$IFDEF ERRORMSG}
VRamMessage : VRamMsgArray = ('Attempt to deallocate bad virtual heap descriptor.',
'Attempt to page out when nothing to page.',
'Not able allocate a virtual pointer.',
'Not able to allocate a virtual free list entry.');
{$ENDIF}
var
VRamFreePtr : LongInt;
VRamHeapPtr : LongInt;
VRamDescListHead : VRamHeapDescRecPtr;
VRamDescListTail : VRamHeapDescRecPtr;
VRamHeapFile : File;
VRamFreeFile : File of VRamFreeRecord;
SaveExitProc : Pointer;
SaveDeRefIntVect : Pointer;
procedure IntsOn;
inline($FB);
procedure IntsOff;
inline($FA);
procedure HaltProg(Msg: String; EC : Byte);
{-Generic halt program routine}
begin
writeln;
writeln('VRam error : ',Msg);
writeln('Program aborted.');
Halt(EC);
end;
procedure Abort(VRamErrorNum : Byte);
{-Abort program with number (with or w/o messages)}
{$IFNDEF ERRORMSG}
var
NStr : String[3];
{$ENDIF}
begin
{$IFNDEF ERRORMSG}
Str(VRamErrorNum:2,NStr);
{$ENDIF}
HaltProg( {$IFDEF ERRORMSG}
VRamMessage[VRamErrorNum]
{$ELSE}
NStr
{$ENDIF}
,VRamErrorNum);
end;
procedure VRamClose;
{-Close and Erase files VRam files}
begin
Close(VRamHeapFile);
Close(VRamFreeFile);
{$IFNDEF DEBUG}
Erase(VRamHeapFile);
Erase(VRamFreeFile);
{$ENDIF}
end;
{$F+}
procedure VRamExitProc;
{-VRam exit proc: close files and return int vect}
begin
ExitProc:=SaveExitProc;
SetIntVec(DeRefIntVect,SaveDeRefIntVect);
VRamClose;
end;
{$F-}
procedure OrigGetMem(var P : Pointer; Size : Word);
{-Temporarily return TP's normal heap routines and do a GetMem}
begin
SystemHeapControl;
GetMem(P, Size);
CustomHeapControl(@VRamGetMem, @VRamFreeMem);
end;
procedure OrigFreeMem(var P : Pointer; Size : Word);
{-Temporarily return TP's normal heap routines and do a FreeMem}
begin
SystemHeapControl;
FreeMem(P, Size);
CustomHeapControl(@VRamGetMem, @VRamFreeMem);
end;
procedure InsertRealHeapRecord(var RealHP : VRamHeapDescRecPtr);
{-Insert VRam Heap Description record into the linked list}
begin
if VRamDescListHead=nil then begin
VRamDescListHead:=RealHP;
VRamDescListTail:=RealHP;
with RealHP^ do begin
NextHeapRecP:=nil;
PrevHeapRecP:=nil;
end;
end
else
with RealHP^ do begin
NextHeapRecP:=VRamDescListTail;
PrevHeapRecP:=nil;
VRamDescListTail^.PrevHeapRecP:=RealHP;
VRamDescListTail:=RealHP;
end;
end;
procedure VRamDeallocateRealHeap(RealHP : VRamHeapDescRecPtr);
{-Remove a VRamHeapDescRec from the linked list}
{-Free the memory associated with it}
begin
if RealHP=nil then
Exit;
{Remove RealHP from the linked list}
if RealHP^.NextHeapRecP=nil then
VRamDescListHead:=RealHP^.PrevHeapRecP
else
RealHP^.NextHeapRecP^.PrevHeapRecP:=RealHP^.PrevHeapRecP;
if RealHP^.PrevHeapRecP=nil then
VRamDescListTail:=RealHP^.NextHeapRecP
else
RealHP^.PrevHeapRecP^.NextHeapRecP:=RealHP^.NextHeapRecP;
{Free it from the heap real heap}
With RealHP^ do begin
OrigFreeMem(RealP,DataSize);
Dec(VRamHeapUsed,DataSize);
end;
{Now free the actual description record}
OrigFreeMem(Pointer(RealHP),SizeOf(VRamHeapDescRec));
Dec(VRamHeapUsed,SizeOf(VRamHeapDescRec));
end;
function VRamSaveRealHeapData(RealHP : VRamHeapDescRecPtr) : Boolean;
{-Save the data buffer contents from Real Heap to VRamHeapFile}
begin
VRamSaveRealHeapData:=False;
if RealHP<>nil then
with RealHP^ do begin
{-seek & skip status block}
Seek(VRamHeapFile,VRamHandle+1);
{-write data on heap}
BlockWrite(VRamHeapFile,RealP^,DataSize div 16);
VRamSaveRealHeapData:=True;
end;
end;
function VRamPageOutOldest : Boolean;
{-if unlocked page(s) exist then page out the least used}
var
CurHP,
LowestHP : VRamHeapDescRecPtr;
begin
VRamPageOutOldest:=False;
{if there is nothing there then exit}
if VRamDescListHead=nil then
Exit;
{LowestHP will hold the lowest so far}
LowestHP:=VRamDescListHead;
{Make sure lowest is not locked}
while (LowestHP^.Locked) and (LowestHP^.PrevHeapRecP<>nil) do
LowestHP:=LowestHP^.PrevHeapRecP;
if LowestHP^.Locked then
Exit;
{CurHP holds the current one being checked}
CurHP:=LowestHP^.PrevHeapRecP;
{while the current one is not nil do ...}
while CurHP<>nil do begin
{if the current one has been used less than the lowest, then lowest=current}
if (CurHP^.TimesUsed<LowestHP^.TimesUsed) and (not CurHP^.Locked) then
LowestHP:=CurHP;
{check the next one in the chain}
CurHP:=CurHP^.PrevHeapRecP;
end;
{Page out the lowest in the list. Abort if failure.}
if not VRamSaveRealHeapData(LowestHP) then
Abort(VRamDeallocError);
{Now deallocate real heap space}
VRamDeallocateRealHeap(LowestHP);
{return success to the caller}
VRamPageOutOldest:=True;
end;
procedure VRamPageOutFreeMem(Size : Word);
{-A governed page out routine. Page out until Size byte free on Real Heap}
begin
while ((VRamHeapUsed+Size>VRamMaxHeapToUse) or (MaxAvail<Size)) and PageVRam do
if not VRamPageOutOldest then
Abort(VRamPageoutError);
end;
function VRamAllocateRealHeap(Handle : Word; HeapSize : Word) : VRamHeapDescRecPtr;
{-Allocate a Real Heap data area and VRamHeapDescRec}
{-Insert the VRamHeapDescRec into the linked list, set it up, and return it}
var
NewVRamRecP : VRamHeapDescRecPtr;
begin
VRamAllocateRealHeap:=nil;
{Allocate memory on real heap for P}
{First, page out until there is enough heap space}
VRamPageOutFreeMem(SizeOf(VRamHeapDescRec));
{Now that there is enough heap, allocate the description record}
OrigGetMem(Pointer(NewVRamRecP),SizeOf(VRamHeapDescRec));
Inc(VRamHeapUsed,SizeOf(VRamHeapDescRec));
{now do the same for the actual data}
VRamPageOutFreeMem(HeapSize);
{Insert it into the linked list}
InsertRealHeapRecord(NewVRamRecP);
{Setup heap description record, allocate the data area on real heap}
with NewVRamRecP^ do begin
OrigGetMem(RealP,HeapSize);
Inc(VRamHeapUsed,HeapSize);
TimesUsed:=0;
DataSize:=HeapSize;
Locked:=False;
{the handle is the start data block number in VRamHeapFile}
VRamHandle:=Handle;
end;
VRamAllocateRealHeap:=NewVRamRecP;
end;
function VRamHandleOnHeap(H : Word) : VRamHeapDescRecPtr;
{-If the passed handle is on the Real Heap then return a pointer to}
{-its decsription block.}
var
VRamDescP : VRamHeapDescRecPtr;
X : Word;
begin
VRamHandleOnHeap:=nil;
VRamDescP:=VRamDescListHead;
{$IFNDEF USEINLINE}
while VRamDescP<>nil do
if VRamDescP^.VRamHandle<>H then
VRamDescP:=VRamDescP^.PrevHeapRecP
else begin
Inc(VRamDescP^.TimesUsed);
VRamHandleOnHeap:=VRamDescP;
Exit;
end;
{$ELSE}
Inline(
{While:}
$8B/$7E/<VRAMDESCP/ { mov di,[bp+<VRamDescP]}
$0B/$46/<VRAMDESCP+2/ { or ax,[bp+<VRamDescP+2]}
$74/$25/ { jz DescPNil ;is VRamDescP=nil?}
$8E/$46/<VRAMDESCP+2/ { mov es,[bp+<VRamDescP+2]}
$26/ { es:}
$8B/$45/$0E/ { mov ax,[di+$0e]}
$3B/$46/<H/ { cmp ax,[bp+<H]}
$74/$0D/ { je FoundHandle}
$26/ { es:}
$C4/$05/ { les ax,[di]}
$8C/$C2/ { mov dx,es}
$89/$46/<VRAMDESCP/ { mov [bp+<VRamDescP],ax}
$89/$56/<VRAMDESCP+2/ { mov [bp+<VRamDescP+2],dx}
$EB/$DF/ { jmp While}
{FoundHandle:}
$26/ { es:}
$FF/$45/$08/ { inc word ptr [di+$08]}
$8C/$C2/ { mov dx,es}
$89/$7E/<VRAMHANDLEONHEAP/ { mov [bp+<VRamHandleOnHeap],di}
$89/$56/<VRAMHANDLEONHEAP+2);{ mov [bp+<VRamHandleOnHeap+2],dx}
{DescPNil:}
{$ENDIF}
end;
function VRamPageIn(Handle : Word) : Pointer;
{-Page in data (if necessary) associated with handle and return a}
{-Pointer to the data (NOT the VRamHeapDescRec)}
var
VBSizeRec : VRamBlockSizeRecord;
VRamDescP : VRamHeapDescRecPtr;
ActRead : Word;
begin
VRamPageIn:=nil;
VRamDescP:=VRamHandleOnHeap(Handle);
if VRamDescP=nil then begin
Seek(VRamHeapFile,Handle);
BlockRead(VRamHeapFile,VBSizeRec,1);
with VBSizeRec do begin
VRamDescP:=VRamAllocateRealHeap(Handle,BSize);
Seek(VRamHeapFile,Handle+1);
BlockRead(VRamHeapFile,VRamDescP^.RealP^,BSize div 16,ActRead);
if (BSize div 16)=ActRead then
VRamPageIn:=VRamDescP^.RealP;
end;
end
else
VRamPageIn:=VRamDescP^.RealP;
end;
function VRamFreeBlockSize(VFR : VRamFreeRecord) : Word;
{-Return the size of the free block described in VFR}
begin
With VFR do
VRamFreeBlockSize:=(EndBlock-StartBlock+1)*16;
end;
function VRamFreeBlockAvail(BSize : Word) : Word;
{-Return free record number of a size that is usable, 0 if none}
var
R : Word;
VFR : VRamFreeRecord;
begin
VRamFreeBlockAvail:=VRamNil;
{if the free list has entries then check it}
if VRamFreePtr<>0 then begin
R:=0;
Seek(VRamFreeFile,R);
While (R<=VRamFreePtr) do begin
{get free entry}
Read(VRamFreeFile,VFR);
{is it >= needed size?}
if VRamFreeBlockSize(VFR)>=BSize then begin
{yes, so return it to the caller}
VRamFreeBlockAvail:=R;
Exit;
end;
Inc(R);
end;
end;
end;
function VRamAllocateFreeBlock(FileAllocateSize : Word) : Word;
{-Allocate a free block. Return VRamNil (0) if not successful.}
{-Otherwise, return the starting block number}
var
FB : Word;
VFR : VRamFreeRecord;
VBSizeRec : VRamBlockSizeRecord;
begin
VRamAllocateFreeBlock:=VRamNil;
{get a free block entry or return nil}
FB:=VRamFreeBlockAvail(FileAllocateSize);
{if there was one then...}
if FB<>VRamNil then
With VFR do begin
{Get free block}
Seek(VRamFreeFile,FB);
Read(VRamFreeFile,VFR);
{Return the start of space in VRamHeapFile to the caller}
VRamAllocateFreeBlock:=StartBlock;
{-Mark file with block size }
VBSizeRec.BSize:=FileAllocateSize;
Seek(VRamHeapFile,StartBlock);
BlockWrite(VRamHeapFile,VBSizeRec,1);
{Adjust free block to reflect new size, close block if all used}
{add to the StartBlock the size of the block allocated, and...}
Inc(StartBlock,(FileAllocateSize div 16)+1);
{if its greater then close the free entry (all used)}
if StartBlock>EndBlock then
{block all used, so make this free entry available for use in future}
FillChar(VFR,SizeOf(VFR),0);
{Write changes of free entry to VRamFreeFile}
Seek(VRamFreeFile,FB);
Write(VRamFreeFile,VFR);
end;
end;
function VRamAllocateBlock(FileAllocateSize : Word) : Word;
{-Allocate block of VRamHeapFile}
var
VBSizeRec : VRamBlockSizeRecord;
begin
{-Mark file with block size (including size block) }
VBSizeRec.BSize:=FileAllocateSize;
Seek(VRamHeapFile,VRamHeapPtr);
BlockWrite(VRamHeapFile,VBSizeRec,1);
{-Return block number and inc VRamHeapPtr}
VRamAllocateBlock:=VRamHeapPtr;
{Plus one for BSize block}
Inc(VRamHeapPtr,(FileAllocateSize Div 16)+1);
end;
{$F+}
procedure VRamGetMem(var P: Pointer; Size: Word);
{-Replacement for TP's GetMem. If UseVRam then allocate a spot in the}
{-VRamHeapFile either by appending or using a "free spot."}
{-In the case of UseVRam=False return a normal TP pointer to a spot on}
{-the real heap. If UseVRam=True return a special VRam Pointer w/handle.}
var
Handle : Word;
HeapSize : Word;
NewVRamRecP : VRamHeapDescRecPtr;
begin
if UseVRam then begin
HeapSize:=((Size div 16)+1) * 16;
{Try to find a free entry that meets our BSize...}
{add 16 for the status record}
Handle:=VRamAllocateFreeBlock(HeapSize);
{if no space was available then allocate a new block on the VRamHeap}
if Handle=VRamNil then
{ Try to allocate a new spot}
Handle:=VRamAllocateBlock(HeapSize);
{if nothing was found all together then abort}
if Handle=VRamNil then
Abort(VRamAllocError);
NewVRamRecP:=VRamAllocateRealHeap(Handle,HeapSize);
P:=Ptr(VRamSegSig,Handle);
end
else begin
if (MaxAvail<Size) and (VRamHeapUsed>=Size) then
VRamPageOutFreeMem(Size);
OrigGetMem(P, Size);
end;
end;
{$F-}
function AllocateFreelistEntry(S, E : Word) : boolean;
{-Insert a new free record or update an existing one to mark avail space}
var
VFRec : VRamFreeRecord;
R : Word;
begin
AllocateFreeListEntry:=False;
{First see if the list is empty}
if VRamFreePtr<>VRamNil then begin
{scan free list for an adjacent entry}
R:=0;
Seek(VRamFreeFile,R);
while R<VRamFreePtr do begin
Read(VRamFreeFile,VFRec);
{is this entry 'behind' our free block?}
if (VFRec.EndBlock+1)=S then begin
{yes, so extend the existing block forwards}
VFRec.EndBlock:=E;
Seek(VRamFreeFile,R);
Write(VRamFreeFile,VFRec);
AllocateFreeListEntry:=True;
Exit;
end
else
{not 'behind', so is it in 'front' of our free block?}
if E=(VFRec.StartBlock-1) then begin
{yes, so extend the existing block backwards}
VFRec.StartBlock:=S;
Seek(VRamFreeFile,R);
Write(VRamFreeFile,VFRec);
AllocateFreeListEntry:=True;
Exit;
end;
Inc(R);
end;
end;
{we haven't exited so we must allocate a new entry}
with VFRec do begin
StartBlock:=S;
EndBlock:=E;
end;
Seek(VRamFreeFile,VRamFreePtr);
Write(VRamFreeFile,VFRec);
Inc(VRamFreePtr);
AllocateFreeListEntry:=True;
end;
procedure VRamAdjustHeapPtrFreeList;
{-Remove free space just below VRamHeapPtr and decrement VRamHeapPtr}
var
R : Word;
VFR : VRamFreeRecord;
FoundOne : Boolean;
begin
{if there are free entries then...}
If VRamFreePtr<>VRamNil then
repeat
FoundOne:=False;
R:=0;
Seek(VRamFreeFile,R);
while R<VRamFreePtr do begin
Read(VRamFreeFile,VFR);
with VFR do
{if this free entry is in use and the EndBlock+1=VRamHeapPtr then...}
if (StartBlock<>VRamNil) and (EndBlock+1=VRamHeapPtr) then begin
{Adjust heap ptr and clear the free record (not in use)}
VRamHeapPtr:=StartBlock;
FillChar(VFR,SizeOf(VFR),0);
Seek(VRamFreeFile,R);
Write(VRamFreeFile,VFR);
{yes, we FoundOne, so search from beginning again}
FoundOne:=True;
end;
Inc(R);
end;
Until not FoundOne;
end;
{$F+}
procedure VRamFreeMem(var P : Pointer; Size: Word);
{-Replacement for FreeMem. Check first to see if P is a special VRam}
{-Pointer or if it is a normal TP pointer. If special, then call our}
{-special routines to deallocate it, otherwise just do a normal FreeMem}
var
VBSizeRec : VRamBlockSizeRecord;
Handle,
EndBlock : Word;
begin
{Check for VRam signature}
if Seg(P^)=VRamSegSig then begin
{get data size record number (handle) from offset}
Handle:=Ofs(P^);
VRamDeallocateRealHeap(VRamHandleOnHeap(Handle));
{Get data size. (the data follows the data size record)}
Seek(VRamHeapFile,Handle);
BlockRead(VRamHeapFile,VBSizeRec,1);
{Compute end block}
EndBlock:=Handle+(VBSizeRec.BSize Div 16);
{Compare it against the HeapPtr }
if EndBlock+1>=VRamHeapPtr then begin
{This free spot is JUST below the heap so just decrement HeapPtr}
VRamHeapPtr:=Handle;
{if FreeBlocks exist below the HeapPtr then adjust accordingly}
if AdjustHeapPtrAfterFreeMem then
VRamAdjustHeapPtrFreeList;
end
else
{-The block is in the middle of the Heap so add a free entry}
if not AllocateFreeListEntry(Handle,EndBlock) then
Abort(VRamAllocFreeError);
end
else
OrigFreeMem(P, Size);
P:=nil;
end;
{$F-}
{$F+}
procedure VRamInterruptProc(BP : Word); interrupt;
{-This routine gets called whenever a pointer is dereferenced (^).}
{-This feature will only work when the program is compiled with }
{-a patched TPC.EXE compiler and the $P+ directive is in effect}
{-For more information download HEAP.ARC from CIS}
var
IntRegs : IntRegisterRecord absolute BP;
DeRefPtr : Pointer;
begin
IntsOn;
with IntRegs do
{Is a VRam ptr being dereferenced?}
if IntRegs.ES=VRamSegSig then begin
DeRefPtr:=VRamPageIn(DI);
ES:=Seg(DeRefPtr^);
DI:=Ofs(DeRefPtr^);
end;
end;
{$F-}
function VRamLock(P : Pointer) : Boolean;
{-Lock a VRam pointer from leaving the real heap (if it is currently there)}
var
VRamDescP : VRamHeapDescRecPtr;
begin
VRamLock:=False;
if Seg(P)=VRamSegSig then begin
VRamDescP:=VRamHandleOnHeap(Ofs(P));
if VRamDescP<>nil then begin
VRamDescP^.Locked:=True;
VRamLock:=True;
end;
end;
end;
function VRamUnLock(P : Pointer) : Boolean;
{-Unlock a previously locked VRam pointer}
var
VRamDescP : VRamHeapDescRecPtr;
begin
VRamUnLock:=False;
if Seg(P)=VRamSegSig then begin
VRamDescP:=VRamHandleOnHeap(Ofs(P));
if VRamDescP<>nil then begin
VRamDescP^.Locked:=False;
VRamUnLock:=True;
end;
end;
end;
procedure InitVRam;
{-Initialization called before program start}
begin
{-Allocate VRAM }
Assign(VRamHeapFile,VRamHeapFilename);
{$IFDEF HIDDEN}
Rewrite(VRamHeapFile);
Close(VRamHeapFile);
SetFAttr(VRamHeapFile,Hidden);
Reset(VRamHeapFile,16);
{$ELSE}
Rewrite(VRamHeapFile,16);
{$ENDIF}
{-Allocate VFREE (freelist) buffer}
Assign(VRamFreeFile,VRamFreeFilename);
{$IFDEF HIDDEN}
Rewrite(VRamFreeFile);
Close(VRamFreeFile);
SetFAttr(VRamFreeFile,Hidden);
Reset(VRamFreeFile);
{$ELSE}
Rewrite(VRamFreeFile);
{$ENDIF}
{-Setup our custom heap control}
CustomHeapControl(@VRamGetMem,@VRamFreeMem);
{-Setup DeRef int vector}
GetIntVec(DeRefIntVect,SaveDeRefIntVect);
SetIntVec(DeRefIntVect,@VRamInterruptProc);
SaveExitProc:=ExitProc;
ExitProc:=@VRamExitProc;
VRamDescListHead:= nil;
VRamDescListTail:= nil;
VRamFreePtr:=0;
VRamHeapPtr:=1;
AdjustHeapPtrAfterFreeMem:=True;
UseVRam:=False;
PageVRam:=True;
VRamMaxHeapToUse:=700000; {all}
VRamHeapUsed:=0;
end;
begin
InitVRam;
end.