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 >
Pascal/Delphi Source File  |  1989-06-01  |  24KB  |  809 lines

  1. (***************************************************************************)
  2. (***************************************************************************)
  3. (**                                                                       **)
  4. (**            TaVram.PAS - Ta Virtual Ram - Turbo Pascal Unit            **)
  5. (**                                                                       **)
  6. (**                              Version 1.0                              **)
  7. (**                                                                       **)
  8. (**                   (written under version 5.0 of TP)                   **)
  9. (**                                                                       **)
  10. (**                                                                       **)
  11. (**                                                                       **)
  12. (**         Copyright 1989 - By Thomas Astin - All rights reserved.       **)
  13. (**                                                                       **)
  14. (**         Thomas Astin  (Compuserve  73407,3427)                        **)
  15. (**         3451 Vinton Ave.  #9                                          **)
  16. (**         L.A.,   CA   90034                                            **)
  17. (**                                                                       **)
  18. (** Description:  Virtual heap manager for Turbo Pascal.                  **)
  19. (**                                                                       **)
  20. (** Revision history:                                                     **)
  21. (**                                                                       **)
  22. (***************************************************************************)
  23. (***************************************************************************)
  24.  
  25. { $DEFINE DEBUG}     {-Debug mode}
  26. {$DEFINE ERRORMSG}   {-Include error messages}
  27. {$DEFINE USEINLINE}  {-Use Inline code for VRamHandleOnHeap}
  28. {$DEFINE HIDDEN}     {-Use for hidden Vram/Vfree files}
  29. { $DEFINE USELONG}   {-Use LongInt for TimesUsed}
  30.  
  31. {$IFDEF USEINLINE}
  32. {$UNDEF USELONG}     {-Cannot use LongInt w/Inline}
  33. {$ENDIF}
  34.  
  35. {$IFDEF DEBUG}
  36. {$UNDEF HIDDEN}
  37. {$R-,S-}
  38. {$ELSE}
  39. {$R+,S+}
  40. {$ENDIF}
  41.  
  42. Unit TaVRam;
  43. Interface
  44. uses
  45.   Dos,
  46.   GrabHeap;
  47. const
  48.   DeRefIntVect = $66;
  49.   MaxVRamBuffer = 4096;
  50.   VRamNil = 0;
  51.   VRamSegSig = $FFFF; {-Signature indicates a VRam pointer}
  52.   VRamHeapFilename = 'VRAM.$$$';
  53.   VRamFreeFilename = 'VFREE.$$$';
  54. type
  55.   VRamBufferPtr = ^VRamBufferArray;
  56.   VRamBufferArray = Array[1..MaxVRamBuffer] of byte;
  57.   VRamFreeRecord = Record
  58.     StartBlock,
  59.     EndBlock : Word;
  60.   end;
  61.   VRamBlockSizeRecord = Record
  62.     BSize : Word;
  63.     Fill  : Array[1..16-SizeOf(Word)] of Byte;
  64.   end;
  65.   VRamHeapDescRecPtr = ^VRamHeapDescRec;
  66.   VRamHeapDescRec = Record
  67.     PrevHeapRecP,
  68.     NextHeapRecP : VRamHeapDescRecPtr;
  69.     TimesUsed :
  70.       {$IFDEF USELONG}
  71.       Longint; {-count of times dereferenced}
  72.       {$ELSE}
  73.       Word;
  74.       {$ENDIF}
  75.     RealP : Pointer; {-pointer to VRam block on heap}
  76.     VRamHandle : Word;
  77.     DataSize : Word;
  78.     Locked : Boolean;
  79.   end;
  80.   IntRegisterRecord = Record
  81.     BP, ES, DS, DI, SI, DX, CX, BX, AX, IP, CS, Flags : Word;
  82.   end;
  83. var
  84.   AdjustHeapPtrAfterFreeMem : Boolean;
  85.   UseVRam : Boolean;
  86.   PageVRam : Boolean;
  87.   VRamMaxHeapToUse : LongInt;
  88.   VRamHeapUsed : LongInt;
  89.  
  90. function VRamPageOutOldest : Boolean;
  91. procedure VRamPageOutFreeMem(Size : Word);
  92. procedure VRamGetMem(var P: Pointer; Size: Word);
  93. procedure VRamFreeMem(var P : Pointer; Size: Word);
  94.  
  95. {-Make life easier for the programmer}
  96. procedure VRamOn;
  97. Inline(
  98.   $C6/$06/>USEVRAM/$01);{            mov    BYTE PTR [>UseVRam],1}
  99.  
  100. procedure VRamOff;
  101. Inline(
  102.   $C6/$06/>USEVRAM/$00);{            mov    BYTE PTR [>UseVRam],0}
  103.  
  104. procedure VRamPageOn;
  105. Inline(
  106.   $C6/$06/>PAGEVRAM/$01);{           mov    BYTE PTR [>PageVRam],1}
  107.  
  108. procedure VRamPageOff;
  109. Inline(
  110.   $C6/$06/>PAGEVRAM/$00);{           mov    BYTE PTR [>PageVRam],0}
  111.  
  112. Implementation
  113. const
  114.   MaxVRamError = 4;
  115. type
  116.   VRamMsgStr = String[80];
  117.   VRamMsgArray = Array[1..MaxVRamError] of VRamMsgStr;
  118. const
  119.   VRamDeallocError   = 1;
  120.   VRamPageoutError   = 2;
  121.   VRamAllocError     = 3;
  122.   VRamAllocFreeError = 4;
  123.   {$IFDEF ERRORMSG}
  124.   VRamMessage : VRamMsgArray = ('Attempt to deallocate bad virtual heap descriptor.',
  125.                                 'Attempt to page out when nothing to page.',
  126.                                 'Not able allocate a virtual pointer.',
  127.                                 'Not able to allocate a virtual free list entry.');
  128.   {$ENDIF}
  129. var
  130.   VRamFreePtr : LongInt;
  131.   VRamHeapPtr : LongInt;
  132.   VRamDescListHead : VRamHeapDescRecPtr;
  133.   VRamDescListTail : VRamHeapDescRecPtr;
  134.   VRamHeapFile : File;
  135.   VRamFreeFile : File of VRamFreeRecord;
  136.   SaveExitProc : Pointer;
  137.   SaveDeRefIntVect : Pointer;
  138.  
  139. procedure IntsOn;
  140. inline($FB);
  141.  
  142. procedure IntsOff;
  143. inline($FA);
  144.  
  145. procedure HaltProg(Msg: String; EC : Byte);
  146.  {-Generic halt program routine}
  147. begin
  148.   writeln;
  149.   writeln('VRam error : ',Msg);
  150.   writeln('Program aborted.');
  151.   Halt(EC);
  152. end;
  153.  
  154. procedure Abort(VRamErrorNum : Byte);
  155.  {-Abort program with number (with or w/o messages)}
  156. {$IFNDEF ERRORMSG}
  157. var
  158.   NStr : String[3];
  159. {$ENDIF}
  160. begin
  161.   {$IFNDEF ERRORMSG}
  162.   Str(VRamErrorNum:2,NStr);
  163.   {$ENDIF}
  164.   HaltProg( {$IFDEF ERRORMSG}
  165.             VRamMessage[VRamErrorNum]
  166.             {$ELSE}
  167.             NStr
  168.             {$ENDIF}
  169.             ,VRamErrorNum);
  170. end;
  171.  
  172. procedure VRamClose;
  173.  {-Close and Erase files VRam files}
  174. begin
  175.   Close(VRamHeapFile);
  176.   Close(VRamFreeFile);
  177.   {$IFNDEF DEBUG}
  178.   Erase(VRamHeapFile);
  179.   Erase(VRamFreeFile);
  180.   {$ENDIF}
  181. end;
  182.  
  183. {$F+}
  184. procedure VRamExitProc;
  185.  {-VRam exit proc: close files and return int vect}
  186. begin
  187.   ExitProc:=SaveExitProc;
  188.   SetIntVec(DeRefIntVect,SaveDeRefIntVect);
  189.   VRamClose;
  190. end;
  191. {$F-}
  192.  
  193. procedure OrigGetMem(var P : Pointer; Size : Word);
  194.  {-Temporarily return TP's normal heap routines and do a GetMem}
  195. begin
  196.   SystemHeapControl;
  197.   GetMem(P, Size);
  198.   CustomHeapControl(@VRamGetMem, @VRamFreeMem);
  199. end;
  200.  
  201. procedure OrigFreeMem(var P : Pointer; Size : Word);
  202.  {-Temporarily return TP's normal heap routines and do a FreeMem}
  203. begin
  204.   SystemHeapControl;
  205.   FreeMem(P, Size);
  206.   CustomHeapControl(@VRamGetMem, @VRamFreeMem);
  207. end;
  208.  
  209. procedure InsertRealHeapRecord(var RealHP : VRamHeapDescRecPtr);
  210.  {-Insert VRam Heap Description record into the linked list}
  211. begin
  212.   if VRamDescListHead=nil then begin
  213.     VRamDescListHead:=RealHP;
  214.     VRamDescListTail:=RealHP;
  215.     with RealHP^ do begin
  216.       NextHeapRecP:=nil;
  217.       PrevHeapRecP:=nil;
  218.     end;
  219.   end
  220.   else
  221.     with RealHP^ do begin
  222.       NextHeapRecP:=VRamDescListTail;
  223.       PrevHeapRecP:=nil;
  224.       VRamDescListTail^.PrevHeapRecP:=RealHP;
  225.       VRamDescListTail:=RealHP;
  226.     end;
  227. end;
  228.  
  229.  
  230. procedure VRamDeallocateRealHeap(RealHP : VRamHeapDescRecPtr);
  231.  {-Remove a VRamHeapDescRec from the linked list}
  232.  {-Free the memory associated with it}
  233. begin
  234.   if RealHP=nil then
  235.     Exit;
  236.   {Remove RealHP from the linked list}
  237.   if RealHP^.NextHeapRecP=nil then
  238.     VRamDescListHead:=RealHP^.PrevHeapRecP
  239.   else
  240.     RealHP^.NextHeapRecP^.PrevHeapRecP:=RealHP^.PrevHeapRecP;
  241.   if RealHP^.PrevHeapRecP=nil then
  242.     VRamDescListTail:=RealHP^.NextHeapRecP
  243.   else
  244.     RealHP^.PrevHeapRecP^.NextHeapRecP:=RealHP^.NextHeapRecP;
  245.  
  246.   {Free it from the heap real heap}
  247.   With RealHP^ do begin
  248.     OrigFreeMem(RealP,DataSize);
  249.     Dec(VRamHeapUsed,DataSize);
  250.   end;
  251.  
  252.   {Now free the actual description record}
  253.   OrigFreeMem(Pointer(RealHP),SizeOf(VRamHeapDescRec));
  254.   Dec(VRamHeapUsed,SizeOf(VRamHeapDescRec));
  255. end;
  256.  
  257. function VRamSaveRealHeapData(RealHP : VRamHeapDescRecPtr) : Boolean;
  258.  {-Save the data buffer contents from Real Heap to VRamHeapFile}
  259. begin
  260.   VRamSaveRealHeapData:=False;
  261.   if RealHP<>nil then
  262.     with RealHP^ do begin
  263.       {-seek & skip status block}
  264.       Seek(VRamHeapFile,VRamHandle+1);
  265.       {-write data on heap}
  266.       BlockWrite(VRamHeapFile,RealP^,DataSize div 16);
  267.       VRamSaveRealHeapData:=True;
  268.     end;
  269. end;
  270.  
  271. function VRamPageOutOldest : Boolean;
  272.  {-if unlocked page(s) exist then page out the least used}
  273. var
  274.   CurHP,
  275.   LowestHP : VRamHeapDescRecPtr;
  276. begin
  277.   VRamPageOutOldest:=False;
  278.  
  279.   {if there is nothing there then exit}
  280.   if VRamDescListHead=nil then
  281.     Exit;
  282.  
  283.   {LowestHP will hold the lowest so far}
  284.   LowestHP:=VRamDescListHead;
  285.  
  286.   {Make sure lowest is not locked}
  287.   while (LowestHP^.Locked) and (LowestHP^.PrevHeapRecP<>nil) do
  288.     LowestHP:=LowestHP^.PrevHeapRecP;
  289.   if LowestHP^.Locked then
  290.     Exit;
  291.  
  292.   {CurHP holds the current one being checked}
  293.   CurHP:=LowestHP^.PrevHeapRecP;
  294.  
  295.   {while the current one is not nil do ...}
  296.   while CurHP<>nil do begin
  297.  
  298.     {if the current one has been used less than the lowest, then lowest=current}
  299.     if (CurHP^.TimesUsed<LowestHP^.TimesUsed) and (not CurHP^.Locked) then
  300.       LowestHP:=CurHP;
  301.  
  302.     {check the next one in the chain}
  303.     CurHP:=CurHP^.PrevHeapRecP;
  304.   end;
  305.  
  306.   {Page out the lowest in the list. Abort if failure.}
  307.   if not VRamSaveRealHeapData(LowestHP) then
  308.     Abort(VRamDeallocError);
  309.  
  310.   {Now deallocate real heap space}
  311.   VRamDeallocateRealHeap(LowestHP);
  312.  
  313.   {return success to the caller}
  314.   VRamPageOutOldest:=True;
  315. end;
  316.  
  317. procedure VRamPageOutFreeMem(Size : Word);
  318.  {-A governed page out routine.  Page out until Size byte free on Real Heap}
  319. begin
  320.   while ((VRamHeapUsed+Size>VRamMaxHeapToUse) or (MaxAvail<Size)) and PageVRam do
  321.     if not VRamPageOutOldest then
  322.       Abort(VRamPageoutError);
  323. end;
  324.  
  325. function VRamAllocateRealHeap(Handle : Word; HeapSize : Word) : VRamHeapDescRecPtr;
  326.  {-Allocate a Real Heap data area and VRamHeapDescRec}
  327.  {-Insert the VRamHeapDescRec into the linked list, set it up, and return it}
  328. var
  329.   NewVRamRecP : VRamHeapDescRecPtr;
  330. begin
  331.   VRamAllocateRealHeap:=nil;
  332.   {Allocate memory on real heap for P}
  333.   {First, page out until there is enough heap space}
  334.   VRamPageOutFreeMem(SizeOf(VRamHeapDescRec));
  335.  
  336.   {Now that there is enough heap, allocate the description record}
  337.   OrigGetMem(Pointer(NewVRamRecP),SizeOf(VRamHeapDescRec));
  338.   Inc(VRamHeapUsed,SizeOf(VRamHeapDescRec));
  339.  
  340.  
  341.   {now do the same for the actual data}
  342.   VRamPageOutFreeMem(HeapSize);
  343.  
  344.   {Insert it into the linked list}
  345.   InsertRealHeapRecord(NewVRamRecP);
  346.  
  347.   {Setup heap description record, allocate the data area on real heap}
  348.   with NewVRamRecP^ do begin
  349.     OrigGetMem(RealP,HeapSize);
  350.     Inc(VRamHeapUsed,HeapSize);
  351.     TimesUsed:=0;
  352.     DataSize:=HeapSize;
  353.     Locked:=False;
  354.     {the handle is the start data block number in VRamHeapFile}
  355.     VRamHandle:=Handle;
  356.   end;
  357.   VRamAllocateRealHeap:=NewVRamRecP;
  358. end;
  359.  
  360. function VRamHandleOnHeap(H : Word) : VRamHeapDescRecPtr;
  361.  {-If the passed handle is on the Real Heap then return a pointer to}
  362.  {-its decsription block.}
  363. var
  364.   VRamDescP : VRamHeapDescRecPtr;
  365.   X : Word;
  366. begin
  367.   VRamHandleOnHeap:=nil;
  368.   VRamDescP:=VRamDescListHead;
  369.  
  370. {$IFNDEF USEINLINE}
  371.   while VRamDescP<>nil do
  372.     if VRamDescP^.VRamHandle<>H then
  373.       VRamDescP:=VRamDescP^.PrevHeapRecP
  374.     else begin
  375.       Inc(VRamDescP^.TimesUsed);
  376.       VRamHandleOnHeap:=VRamDescP;
  377.       Exit;
  378.     end;
  379.  
  380. {$ELSE}
  381.  
  382.   Inline(
  383.                            {While:}
  384.     $8B/$7E/<VRAMDESCP/    {              mov     di,[bp+<VRamDescP]}
  385.     $0B/$46/<VRAMDESCP+2/  {              or      ax,[bp+<VRamDescP+2]}
  386.     $74/$25/               {              jz      DescPNil                 ;is VRamDescP=nil?}
  387.     $8E/$46/<VRAMDESCP+2/  {              mov     es,[bp+<VRamDescP+2]}
  388.     $26/                   {              es:}
  389.     $8B/$45/$0E/           {              mov     ax,[di+$0e]}
  390.     $3B/$46/<H/            {              cmp     ax,[bp+<H]}
  391.     $74/$0D/               {              je      FoundHandle}
  392.     $26/                   {              es:}
  393.     $C4/$05/               {              les     ax,[di]}
  394.     $8C/$C2/               {              mov     dx,es}
  395.     $89/$46/<VRAMDESCP/    {              mov     [bp+<VRamDescP],ax}
  396.     $89/$56/<VRAMDESCP+2/  {              mov     [bp+<VRamDescP+2],dx}
  397.     $EB/$DF/               {              jmp     While}
  398.                            {FoundHandle:}
  399.     $26/                   {              es:}
  400.     $FF/$45/$08/           {              inc     word ptr [di+$08]}
  401.     $8C/$C2/               {              mov     dx,es}
  402.     $89/$7E/<VRAMHANDLEONHEAP/ {              mov     [bp+<VRamHandleOnHeap],di}
  403.     $89/$56/<VRAMHANDLEONHEAP+2);{              mov     [bp+<VRamHandleOnHeap+2],dx}
  404.                            {DescPNil:}
  405.  
  406. {$ENDIF}
  407. end;
  408.  
  409. function VRamPageIn(Handle : Word) : Pointer;
  410.  {-Page in data (if necessary) associated with handle and return a}
  411.  {-Pointer to the data (NOT the VRamHeapDescRec)}
  412. var
  413.   VBSizeRec : VRamBlockSizeRecord;
  414.   VRamDescP : VRamHeapDescRecPtr;
  415.   ActRead  : Word;
  416. begin
  417.   VRamPageIn:=nil;
  418.   VRamDescP:=VRamHandleOnHeap(Handle);
  419.   if VRamDescP=nil then begin
  420.     Seek(VRamHeapFile,Handle);
  421.     BlockRead(VRamHeapFile,VBSizeRec,1);
  422.     with VBSizeRec do begin
  423.       VRamDescP:=VRamAllocateRealHeap(Handle,BSize);
  424.       Seek(VRamHeapFile,Handle+1);
  425.       BlockRead(VRamHeapFile,VRamDescP^.RealP^,BSize div 16,ActRead);
  426.       if (BSize div 16)=ActRead then
  427.         VRamPageIn:=VRamDescP^.RealP;
  428.     end;
  429.   end
  430.   else
  431.     VRamPageIn:=VRamDescP^.RealP;
  432. end;
  433.  
  434. function VRamFreeBlockSize(VFR : VRamFreeRecord) : Word;
  435.  {-Return the size of the free block described in VFR}
  436. begin
  437.   With VFR do
  438.     VRamFreeBlockSize:=(EndBlock-StartBlock+1)*16;
  439. end;
  440.  
  441. function VRamFreeBlockAvail(BSize : Word) : Word;
  442.  {-Return free record number of a size that is usable, 0 if none}
  443. var
  444.   R : Word;
  445.   VFR : VRamFreeRecord;
  446. begin
  447.   VRamFreeBlockAvail:=VRamNil;
  448.  
  449.   {if the free list has entries then check it}
  450.   if VRamFreePtr<>0 then begin
  451.     R:=0;
  452.     Seek(VRamFreeFile,R);
  453.     While (R<=VRamFreePtr) do begin
  454.  
  455.       {get free entry}
  456.       Read(VRamFreeFile,VFR);
  457.  
  458.       {is it >= needed size?}
  459.       if VRamFreeBlockSize(VFR)>=BSize then begin
  460.  
  461.         {yes, so return it to the caller}
  462.         VRamFreeBlockAvail:=R;
  463.         Exit;
  464.       end;
  465.       Inc(R);
  466.     end;
  467.   end;
  468. end;
  469.  
  470. function VRamAllocateFreeBlock(FileAllocateSize : Word) : Word;
  471.  {-Allocate a free block. Return VRamNil (0) if not successful.}
  472.  {-Otherwise, return the starting block number}
  473. var
  474.   FB : Word;
  475.   VFR : VRamFreeRecord;
  476.   VBSizeRec : VRamBlockSizeRecord;
  477. begin
  478.   VRamAllocateFreeBlock:=VRamNil;
  479.  
  480.   {get a free block entry or return nil}
  481.   FB:=VRamFreeBlockAvail(FileAllocateSize);
  482.  
  483.   {if there was one then...}
  484.   if FB<>VRamNil then
  485.     With VFR do begin
  486.  
  487.       {Get free block}
  488.       Seek(VRamFreeFile,FB);
  489.       Read(VRamFreeFile,VFR);
  490.  
  491.       {Return the start of space in VRamHeapFile to the caller}
  492.       VRamAllocateFreeBlock:=StartBlock;
  493.  
  494.       {-Mark file with block size }
  495.       VBSizeRec.BSize:=FileAllocateSize;
  496.       Seek(VRamHeapFile,StartBlock);
  497.       BlockWrite(VRamHeapFile,VBSizeRec,1);
  498.  
  499.       {Adjust free block to reflect new size, close block if all used}
  500.       {add to the StartBlock the size of the block allocated, and...}
  501.       Inc(StartBlock,(FileAllocateSize div 16)+1);
  502.  
  503.       {if its greater then close the free entry (all used)}
  504.       if StartBlock>EndBlock then
  505.  
  506.         {block all used, so make this free entry available for use in future}
  507.         FillChar(VFR,SizeOf(VFR),0);
  508.  
  509.       {Write changes of free entry to VRamFreeFile}
  510.       Seek(VRamFreeFile,FB);
  511.       Write(VRamFreeFile,VFR);
  512.     end;
  513. end;
  514.  
  515. function VRamAllocateBlock(FileAllocateSize : Word) : Word;
  516.  {-Allocate block of VRamHeapFile}
  517. var
  518.   VBSizeRec : VRamBlockSizeRecord;
  519. begin
  520.   {-Mark file with block size (including size block) }
  521.   VBSizeRec.BSize:=FileAllocateSize;
  522.   Seek(VRamHeapFile,VRamHeapPtr);
  523.   BlockWrite(VRamHeapFile,VBSizeRec,1);
  524.  
  525.   {-Return block number and inc VRamHeapPtr}
  526.   VRamAllocateBlock:=VRamHeapPtr;
  527.   {Plus one for BSize block}
  528.   Inc(VRamHeapPtr,(FileAllocateSize Div 16)+1);
  529. end;
  530.  
  531. {$F+}
  532. procedure VRamGetMem(var P: Pointer; Size: Word);
  533.  {-Replacement for TP's GetMem.  If UseVRam then allocate a spot in the}
  534.  {-VRamHeapFile either by appending or using a "free spot."}
  535.  {-In the case of UseVRam=False return a normal TP pointer to a spot on}
  536.  {-the real heap.  If UseVRam=True return a special VRam Pointer w/handle.}
  537. var
  538.   Handle : Word;
  539.   HeapSize : Word;
  540.   NewVRamRecP : VRamHeapDescRecPtr;
  541. begin
  542.   if UseVRam then begin
  543.  
  544.     HeapSize:=((Size div 16)+1) * 16;
  545.  
  546.     {Try to find a free entry that meets our BSize...}
  547.       {add 16 for the status record}
  548.     Handle:=VRamAllocateFreeBlock(HeapSize);
  549.  
  550.     {if no space was available then allocate a new block on the VRamHeap}
  551.     if Handle=VRamNil then
  552.       { Try to allocate a new spot}
  553.       Handle:=VRamAllocateBlock(HeapSize);
  554.  
  555.     {if nothing was found all together then abort}
  556.     if Handle=VRamNil then
  557.       Abort(VRamAllocError);
  558.  
  559.     NewVRamRecP:=VRamAllocateRealHeap(Handle,HeapSize);
  560.     P:=Ptr(VRamSegSig,Handle);
  561.   end
  562.   else begin
  563.     if (MaxAvail<Size) and (VRamHeapUsed>=Size) then
  564.       VRamPageOutFreeMem(Size);
  565.     OrigGetMem(P, Size);
  566.   end;
  567. end;
  568. {$F-}
  569.  
  570. function AllocateFreelistEntry(S, E : Word) : boolean;
  571.  {-Insert a new free record or update an existing one to mark avail space}
  572. var
  573.   VFRec : VRamFreeRecord;
  574.   R : Word;
  575. begin
  576.   AllocateFreeListEntry:=False;
  577.  
  578.   {First see if the list is empty}
  579.   if VRamFreePtr<>VRamNil then begin
  580.  
  581.     {scan free list for an adjacent entry}
  582.     R:=0;
  583.     Seek(VRamFreeFile,R);
  584.     while R<VRamFreePtr do begin
  585.       Read(VRamFreeFile,VFRec);
  586.  
  587.       {is this entry 'behind' our free block?}
  588.       if (VFRec.EndBlock+1)=S then begin
  589.  
  590.         {yes, so extend the existing block forwards}
  591.         VFRec.EndBlock:=E;
  592.         Seek(VRamFreeFile,R);
  593.         Write(VRamFreeFile,VFRec);
  594.         AllocateFreeListEntry:=True;
  595.         Exit;
  596.       end
  597.       else
  598.  
  599.         {not 'behind', so is it in 'front' of our free block?}
  600.         if E=(VFRec.StartBlock-1) then begin
  601.  
  602.           {yes, so extend the existing block backwards}
  603.           VFRec.StartBlock:=S;
  604.           Seek(VRamFreeFile,R);
  605.           Write(VRamFreeFile,VFRec);
  606.           AllocateFreeListEntry:=True;
  607.           Exit;
  608.         end;
  609.       Inc(R);
  610.     end;
  611.   end;
  612.  
  613.   {we haven't exited so we must allocate a new entry}
  614.   with VFRec do begin
  615.     StartBlock:=S;
  616.     EndBlock:=E;
  617.   end;
  618.   Seek(VRamFreeFile,VRamFreePtr);
  619.   Write(VRamFreeFile,VFRec);
  620.   Inc(VRamFreePtr);
  621.   AllocateFreeListEntry:=True;
  622. end;
  623.  
  624. procedure VRamAdjustHeapPtrFreeList;
  625.  {-Remove free space just below VRamHeapPtr and decrement VRamHeapPtr}
  626. var
  627.   R : Word;
  628.   VFR : VRamFreeRecord;
  629.   FoundOne : Boolean;
  630. begin
  631.   {if there are free entries then...}
  632.   If VRamFreePtr<>VRamNil then
  633.     repeat
  634.       FoundOne:=False;
  635.       R:=0;
  636.       Seek(VRamFreeFile,R);
  637.       while R<VRamFreePtr do begin
  638.         Read(VRamFreeFile,VFR);
  639.         with VFR do
  640.  
  641.           {if this free entry is in use and the EndBlock+1=VRamHeapPtr then...}
  642.           if (StartBlock<>VRamNil) and (EndBlock+1=VRamHeapPtr) then begin
  643.  
  644.             {Adjust heap ptr and clear the free record (not in use)}
  645.             VRamHeapPtr:=StartBlock;
  646.             FillChar(VFR,SizeOf(VFR),0);
  647.             Seek(VRamFreeFile,R);
  648.             Write(VRamFreeFile,VFR);
  649.  
  650.             {yes, we FoundOne, so search from beginning again}
  651.             FoundOne:=True;
  652.           end;
  653.         Inc(R);
  654.       end;
  655.     Until not FoundOne;
  656. end;
  657.  
  658.  
  659. {$F+}
  660. procedure VRamFreeMem(var P : Pointer; Size: Word);
  661.  {-Replacement for FreeMem.  Check first to see if P is a special VRam}
  662.  {-Pointer or if it is a normal TP pointer.  If special, then call our}
  663.  {-special routines to deallocate it, otherwise just do a normal FreeMem}
  664. var
  665.   VBSizeRec : VRamBlockSizeRecord;
  666.   Handle,
  667.   EndBlock : Word;
  668. begin
  669.   {Check for VRam signature}
  670.   if Seg(P^)=VRamSegSig then begin
  671.  
  672.     {get data size record number (handle) from offset}
  673.     Handle:=Ofs(P^);
  674.     VRamDeallocateRealHeap(VRamHandleOnHeap(Handle));
  675.  
  676.  
  677.     {Get data size. (the data follows the data size record)}
  678.     Seek(VRamHeapFile,Handle);
  679.     BlockRead(VRamHeapFile,VBSizeRec,1);
  680.  
  681.     {Compute end block}
  682.     EndBlock:=Handle+(VBSizeRec.BSize Div 16);
  683.  
  684.     {Compare it against the HeapPtr }
  685.     if EndBlock+1>=VRamHeapPtr then begin
  686.  
  687.       {This free spot is JUST below the heap so just decrement HeapPtr}
  688.       VRamHeapPtr:=Handle;
  689.  
  690.  
  691.   {if FreeBlocks exist below the HeapPtr then adjust accordingly}
  692.       if AdjustHeapPtrAfterFreeMem then
  693.         VRamAdjustHeapPtrFreeList;
  694.     end
  695.     else
  696.  
  697.       {-The block is in the middle of the Heap so add a free entry}
  698.       if not AllocateFreeListEntry(Handle,EndBlock) then
  699.         Abort(VRamAllocFreeError);
  700.  
  701.   end
  702.   else
  703.     OrigFreeMem(P, Size);
  704.   P:=nil;
  705. end;
  706. {$F-}
  707.  
  708. {$F+}
  709. procedure VRamInterruptProc(BP : Word); interrupt;
  710.  {-This routine gets called whenever a pointer is dereferenced (^).}
  711.  {-This feature will only work when the program is compiled with }
  712.  {-a patched TPC.EXE compiler and the $P+ directive is in effect}
  713.  {-For more information download HEAP.ARC from CIS}
  714. var
  715.   IntRegs : IntRegisterRecord absolute BP;
  716.   DeRefPtr : Pointer;
  717. begin
  718.   IntsOn;
  719.   with IntRegs do
  720.     {Is a VRam ptr being dereferenced?}
  721.     if IntRegs.ES=VRamSegSig then begin
  722.       DeRefPtr:=VRamPageIn(DI);
  723.       ES:=Seg(DeRefPtr^);
  724.       DI:=Ofs(DeRefPtr^);
  725.     end;
  726. end;
  727. {$F-}
  728.  
  729. function VRamLock(P : Pointer) : Boolean;
  730.  {-Lock a VRam pointer from leaving the real heap (if it is currently there)}
  731. var
  732.   VRamDescP : VRamHeapDescRecPtr;
  733. begin
  734.   VRamLock:=False;
  735.   if Seg(P)=VRamSegSig then begin
  736.     VRamDescP:=VRamHandleOnHeap(Ofs(P));
  737.     if VRamDescP<>nil then begin
  738.       VRamDescP^.Locked:=True;
  739.       VRamLock:=True;
  740.     end;
  741.   end;
  742. end;
  743.  
  744. function VRamUnLock(P : Pointer) : Boolean;
  745.  {-Unlock a previously locked VRam pointer}
  746. var
  747.   VRamDescP : VRamHeapDescRecPtr;
  748. begin
  749.   VRamUnLock:=False;
  750.   if Seg(P)=VRamSegSig then begin
  751.     VRamDescP:=VRamHandleOnHeap(Ofs(P));
  752.     if VRamDescP<>nil then begin
  753.       VRamDescP^.Locked:=False;
  754.       VRamUnLock:=True;
  755.     end;
  756.   end;
  757. end;
  758.  
  759. procedure InitVRam;
  760.  {-Initialization called before program start}
  761. begin
  762.   {-Allocate VRAM }
  763.   Assign(VRamHeapFile,VRamHeapFilename);
  764.  
  765.   {$IFDEF HIDDEN}
  766.   Rewrite(VRamHeapFile);
  767.   Close(VRamHeapFile);
  768.   SetFAttr(VRamHeapFile,Hidden);
  769.   Reset(VRamHeapFile,16);
  770.   {$ELSE}
  771.   Rewrite(VRamHeapFile,16);
  772.   {$ENDIF}
  773.  
  774.   {-Allocate VFREE (freelist) buffer}
  775.   Assign(VRamFreeFile,VRamFreeFilename);
  776.  
  777.   {$IFDEF HIDDEN}
  778.   Rewrite(VRamFreeFile);
  779.   Close(VRamFreeFile);
  780.   SetFAttr(VRamFreeFile,Hidden);
  781.   Reset(VRamFreeFile);
  782.   {$ELSE}
  783.   Rewrite(VRamFreeFile);
  784.   {$ENDIF}
  785.  
  786.   {-Setup our custom heap control}
  787.   CustomHeapControl(@VRamGetMem,@VRamFreeMem);
  788.  
  789.   {-Setup DeRef int vector}
  790.   GetIntVec(DeRefIntVect,SaveDeRefIntVect);
  791.   SetIntVec(DeRefIntVect,@VRamInterruptProc);
  792.   SaveExitProc:=ExitProc;
  793.   ExitProc:=@VRamExitProc;
  794.  
  795.   VRamDescListHead:= nil;
  796.   VRamDescListTail:= nil;
  797.   VRamFreePtr:=0;
  798.   VRamHeapPtr:=1;
  799.   AdjustHeapPtrAfterFreeMem:=True;
  800.   UseVRam:=False;
  801.   PageVRam:=True;
  802.   VRamMaxHeapToUse:=700000; {all}
  803.   VRamHeapUsed:=0;
  804. end;
  805.  
  806. begin
  807.   InitVRam;
  808. end.
  809.