(* * * * * * * * * * * * * * * * * * *
 *
 * _vm.pas
 *
 *  External definitions for the virtual memory module
 *
 * * * * * * * * * * * * * * * * * * *)

unit _vm;

INTERFACE

uses    _globals;

(*
 *  Define some error codes
 *)
const
    VMErrOK=            0;
    VMErrEMS=           1;
    VMErrXMS=           2;
    VMErrDisk=          3;
    VMErrNoConv=        4;
    VMErrBadWire=       5;
    VMErrNotWired=      6;
    VMErrBounds=        7;


(*
 *  Define the functions
 *)
type
    VM_Vm= object
        function        init(
                            maxSpace:       DWord)
                            : Boolean;
        function        shutdown
                            : Boolean;
        end;

    VM_VmBlk= object

        handle:         DWord;

        function        alloc(
                            size:           DWord)
                            : Boolean;
        function        free
                            : Boolean;
        function        wire(
                            areaOffset:     DWord;
                            areaSize:       DWord;
                            var areaAddress: Pointer)
                            : Boolean;
        function        unwire(
                            areaOffset:     DWord;
                            areaSize:       DWord;
                            dirty:          Boolean)
                            : Boolean;
        end;


IMPLEMENTATION

uses    _ems,
        _xms;

const
    (*
     *  First let's define some important constants:
     *)
    VM_PAGE_SIZE=           16384;
    VM_PAGE_SHIFT=          14;
    VM_PAGE_OFFSET_MASK=    VM_PAGE_SIZE-1;
    VM_PAGE_NUM_MASK=       not VM_PAGE_OFFSET_MASK;

    VM_MAX_BUFF_SPACE=      131072;

type
    (*
     *  Define the types of secondary memory
     *)
    VM_SecondaryKind= (
        VM_SEC_UNALLOCATED,
        VM_SEC_DISK,
        VM_SEC_XMS,
        VM_SEC_EMS);

    (*
     *  Define the queues on which we may find a physical page.
     *)
    VM_SecondaryQueue= (
        VM_Q_FREE,
        VM_Q_LRU,
        VM_Q_WIRED);

    (*
     *  Define all of the pointer types
     *)
    VM_QueueElemPtr=   ^VM_QueueELem;
    VM_FreeAreaPtr=    ^VM_FreeArea;
    VM_ConvBuffPtr=    ^VM_ConvBuff;
    VM_EmsBuffPtr=     ^VM_EmsBuff;
    VM_XmsBuffPtr=     ^VM_XmsBuff;
    VM_EmsPagePtr=     ^VM_EmsPage;
    VM_XmsPagePtr=     ^VM_XmsPage;
    VM_DiskPagePtr=    ^VM_DiskPage;
    VM_VmPagePtr=      ^VM_VmPage;
    VM_VmBlockPtr=     ^VM_VmBlock;
    VM_VmPageArrPtr=   ^VM_VmPageArr;
    VM_PagePtr=        ^VM_Page;

    (*
     *  Define what a virtual memory page is:
     *)
    VM_Page=            array[0..VM_PAGE_SIZE-1] of Byte;

    (*
     *  Define a generic queue element
     *)
    VM_QueueElem= object
        next:           Pointer;
        prev:           Pointer;

        procedure       enqueTail(
                            head:       Pointer;
                            tail:       Pointer);
        procedure       enqueHead(
                            head:       Pointer;
                            tail:       Pointer);
        procedure       deque(
                            head:       Pointer;
                            tail:       Pointer);
        end;



    (*
     *  Define a free area descriptor
     *)
    VM_FreeArea= object (VM_QueueElem)
        handle:         DWord;          { EMS/XMS Buff addr (if appropriate) }
        start:          DWord;          { Start Address }
        size:           DWord;          { Size of Area  }
        end;


    (*
     *  Define a conventional memory buffer descriptor.
     *)
    VM_ConvBuff= object (VM_QueueElem)
        buffSize:       Word;           { Size in pages }
        address:        Pointer;        { Address of buffer }

        vmBlock:        VM_VmBlockPtr;  { Where the pages are from }
        startPage:      Word;           { First page in buffer }
        wiredPages:     Word;           { Number of wired pages }
        end;

    (*
     *  Define an EMS buffer descriptor.
     *)
    VM_EmsBuff= object (VM_QueueElem)

        buffSize:       Word;           { Size in pages }
        handle:         EMS_EmBlk;      { EMS handle }

        useCount:       Word;           { Number of pages in use }
        end;

    
    (*
     *  Define an XMS buffer descriptor.
     *)
    VM_XmsBuff= object (VM_QueueElem)

        buffSize:       Word;           { Size in pages }
        handle:         XMS_XmBlk;      { XMS handle }

        useCount:       Word;           { Number of pages in use }
        end;

    (*
     *  Define the various secondary memory page descriptors
     *)
    VM_EmsPage= object (VM_QueueElem)

        vmPage:         VM_VmPagePtr;   { Corresponding VM page }

        emsBuff:        VM_EmsBuffPtr;  { EMS buffer descriptor }
        pageNum:        Word;           { Page in buffer }

        secondaryQueue: VM_SecondaryQueue; { Queue page is on }
        end;

    VM_XmsPage= object (VM_QueueElem)

        vmPage:         VM_VmPagePtr;   { Corresponding VM page }

        xmsBuff:        VM_XmsBuffPtr;  { XMS buffer descriptor }
        pageNum:        Word;           { Offset into buffer }

        secondaryQueue: VM_SecondaryQueue; { Queue page is on }
        end;


    VM_DiskPage= object (VM_QueueElem)

        vmPage:         VM_VmPagePtr;   { Corresponding VM page }

        pageNum:        Word;           { Offset into file (in pages) }
        end;

    (*
     *  Define a vitual memory page
     *)
    VM_SecondaryPage= record 
       case Word of
            1: (disk:   VM_DiskPagePtr;);{ Disk secondary page }
            2: (xms:    VM_XmsPagePtr;);{ XMS secondary page }
            3: (ems:    VM_EmsPagePtr;);{ EMS secondary page }
        end;

    VM_VmPage= record

        pageNum:        Word;           { Number of page in VM block }

        secondaryKind:  VM_SecondaryKind;  { Type of secondary }

        sec:            VM_SecondaryPage;{ Secondary Page }                       

        convBuff:       VM_ConvBuffPtr; { Conventional memory buffer }
        offset:         DWord;          { Offset in buffer }

        wired:          Word;           { Wire count }

        dirty:          Boolean;        { Page modified }
        end;

    VM_VmPageArr=       array[0..0] of VM_VmPage;
   
    (*
     *  Define a virtual memory block.
     *)
    VM_VmBlock= object (VM_QueueElem)

        size:           Word;           { Size in pages }
        pages:          VM_VmPageArrPtr;{ Virtual pages }
        end;


    (*
     *  Define the EMS Descriptor
     *)
    VM_EmsDesc= record
        pageFrame:      EMS_PageFrame;  { Address of Page Frame }

        contents:       array [0..EMS_PAGE_FRAME_SIZE-1] of
                            VM_EmsPagePtr; { Pages in Page frame }

        mruPage:        VM_EmsPagePtr;  { Page LRU queue }
        lruPage:        VM_EmsPagePtr;

        firstWired:     VM_EmsPagePtr;  { Wired page list }
        lastWired:      VM_EmsPagePtr;

        firstFree:      VM_FreeAreaPtr; { Free page chain }
        lastFree:       VM_FreeAreaPtr;

        firstBuff:      VM_EmsBuffPtr;  { Buffer queue }
        lastBuff:       VM_EmsBuffPtr;

        pageBuffHandle: EMS_EmBlk;      { One page handle for buffering }

        emsBlockSize:   Word;           { Preferred block size }
        end;

    (*
     *  Define the XMS descriptor.
     *)
    VM_XmsDesc= record

        mruPage:        VM_XmsPagePtr;  { Page LRU queue }
        lruPage:        VM_XmsPagePtr;

        firstWired:     VM_XmsPagePtr;  { Wired page list }
        lastWired:      VM_XmsPagePtr;

        firstFree:      VM_FreeAreaPtr; { Free page chain }
        lastFree:       VM_FreeAreaPtr;

        firstBuff:      VM_XmsBuffPtr;  { Buffer queue }
        lastBuff:       VM_XmsBuffPtr;

        xmsBlockSize:   Word;           { Preferred block size }
        end;

    (*
     *  Define the Disk descriptor.
     *)
    VM_DiskDesc=   record

        firstPage:      VM_DiskPagePtr; { Page queue }
        lastPage:       VM_DiskPagePtr;

        firstFree:      VM_FreeAreaPtr; { Free page chain }
        lastFree:       VM_FreeAreaPtr;

        channel:        File of VM_Page;{ File channel }

        fileSize:       DWord;          { Current size of file }
        end;

    (*
     *  Define the conventional memory descriptor.
     *)
    VM_ConvDesc= record

        mruBuff:        VM_ConvBuffPtr; { Buffer LRU chain }
        lruBuff:        VM_ConvBuffPtr;
    
        firstWired:     VM_ConvBuffPtr; { Wired buffer list }
        lastWired:      VM_ConvBuffPtr;

        spaceAvail:     DWord;          { maxSpace - Memory allocated for buffers }
        end;

const
    PFABUFF: VM_ConvBuffPtr=    (VM_ConvBuffPtr(-1));

(*
 *  Declare some extern functions
 *)
procedure       vm_addFree(
                    handle:             DWord;
                    start:              DWord;
                    size:               DWord;
                    var head:           VM_FreeAreaPtr;
                    var tail:           VM_FreeAreaPtr);
                    forward;

procedure       vm_freeVmPage(
                    vmPage:             VM_VmPagePtr);
                    forward;

procedure       vm_freeEmsPage(
                    emsPage:            VM_EmsPagePtr);
                    forward;

procedure       vm_freeXmsPage(
                    xmsPage:            VM_XmsPagePtr);
                    forward;

procedure       vm_freeDiskPage(
                    diskPage:           VM_DiskPagePtr);
                    forward;

procedure       vm_freeConvBuff(
                    convBuff:           VM_ConvBuffPtr);
                    forward;

procedure       vm_freeEmsBuff(
                    emsBuff:            VM_EmsBuffPtr);
                    forward;

procedure       vm_freeXmsBuff(
                    XmsBuff:            VM_XmsBuffPtr);
                    forward;

function        vm_faultInPages(
                    var vmBlock:        VM_VmBlock;
                    startPage:          Word;
                    endPage:            Word)
                    : Boolean;
                    forward;

function        vm_faultToEMS(
                    var vmBlock:        VM_VmBlock;
                    startPage:          Word;
                    endPage:            Word)
                    : Boolean;
                    forward;

function        vm_faultToXMS(
                    var vmBlock:        VM_VmBlock;
                    startPage:          Word;
                    endPage:            Word)
                    : Boolean;
                    forward;

function        vm_faultToDisk(
                    var vmBlock:        VM_VmBlock;
                    startPage:          Word;
                    endPage:            Word)
                    : Boolean;
                    forward;

function        vm_tryMapPFA(
                    var vmBlock:        VM_VmBlock;
                    startPage:          Word;
                    endPage:            Word)
                    : Boolean;
                    forward;

function        vm_tryMapConv(
                    var vmBlock:        VM_VmBlock;
                    startPage:          Word;
                    endPage:            Word)
                    : Boolean;
                    forward;

procedure       vm_getEMSPages(
                    number:             Word;
                    var chain:          VM_EmsPagePtr);
                    forward;

procedure       vm_getXMSPages(
                    number:             Word;
                    var chain:          VM_XmsPagePtr);
                    forward;

procedure       vm_getDiskPages(
                    number:             Word;
                    var chain:       VM_DiskPagePtr);
                    forward;

procedure       vm_promoteToEMS(
                    var vmPage:         VM_VmPage;
                    var emsPage:        VM_EmsPage);
                    forward;

procedure       vm_promoteToXMS(
                    var vmPage:         VM_VmPage;
                    var xmsPage:        VM_XmsPage);
                    forward;

procedure       vm_promoteToDisk(
                    var vmPage:         VM_VmPage;
                    var diskPage:       VM_DiskPage);
                    forward;

procedure       vm_demoteFromEMS(
                    var emsPage:        VM_EmsPage);
                    forward;

procedure       vm_demoteFromXMS(
                    var xmsPage:        VM_XmsPage);
                    forward;

procedure       vm_flushVmPage(
                    var vmPage:         VM_VmPage);
                    forward;

procedure       vm_loadVmPage(
                    var vmPage:         VM_VmPage;
                    var convBuff:       VM_ConvBuff);
                    forward;

function        vm_freeLRUConvBuff
                    : Boolean;
                    forward;

procedure       vm_moveSecPageToWired(
                    var vmPage:         VM_VmPage);
                    forward;

procedure       vm_dequeSecPage(
                    var vmPage:         VM_VmPage);
                    forward;

procedure       vm_fatal(
                    errorMsg:           String);
                    forward;

(*
 *  Now declare global data
 *)

var
    ems:                EMS_Ems;
    xms:                Xms_Xms;
    em:                 VM_EmsDesc;
    xm:                 VM_XmsDesc;
    disk:               VM_DiskDesc;
    conv:               VM_ConvDesc;

    firstVmBlock:       VM_VmBlockPtr;
    lastVmBlock:        VM_VmBlockPtr;

    emsPresent:         Boolean;
    xmsPresent:         Boolean;

    logFile:            Text;

{$I VMINIT}
{$I VMALLOC}
{$I VMWIRE}
{$I VMUTIL}

begin
    Assign(logFile, 'logfile');
    ReWrite(logFile);
end.

