home *** CD-ROM | disk | FTP | other *** search
- #include "..\MEMORY\MEMORY.HPP"
- #include <dos.h>
-
- // ------------------------------------------------------------------
- // File: EMS.CPP
- // Path: ...\REHACK\MEMORY\EMS.CPP
- // Version: 0.01
- // Author: Pat Reilly
- // CIS Id: 71333,2764
- // Created On: 6/28/93
- // Modified On:
- // Description: EmsMemory class for REHACK. See MEMORY.TXT for
- // more details.
- // Tabs: 4
- // ------------------------------------------------------------------
-
- static word MaxEmsPages = 0U;
-
- bool EmsMemory::isInitialized = false;
- EmsMemory* EmsMemory::head = 0;
- long EmsMemory::lastAddr = 0L;
- word EmsMemory::handle = 0U;
- bool EmsMemory::framePageInUse[EmsPagesPerFrame] = { true,true,true,true };
- word EmsMemory::frameSeg = 0U;
-
- // Function to free up all used EMS pages when program exits.
- void ClearEms()
- {
- if( EmsMemory::handle != 0 )
- {
- _DX = EmsMemory::handle;
- _AH = 0x45;
- asm int 0x67;
- }
- }
-
- #pragma exit ClearEms
-
- EmsMemory::EmsMemory()
- {
- init();
- }
-
- EmsMemory::EmsMemory(word sz)
- {
- init();
- allocate(sz);
- }
-
- bool EmsMemory::allocate(word sz)
- {
- // Fail if memory allocated or sz == 0 or EMS not available.
- if( handle == 0 || memsize != 0 || sz == 0 )
- return false;
-
- // We allocated a bunch of EMS pages - use a first-fit algorithm to
- // allocate a sub-region.
- memsize = 0;
- long aAddr = 0;
- EmsMemory* parent = head;
-
- // If this is the first allocation, see if it can fit.
- if( head == 0 )
- {
- if( sz > lastAddr )
- return false;
- }
-
- // There's other allocations - search for first fit.
- else
- {
- // First, look in-between blocks.
- while( parent->next != 0 )
- {
- aAddr = parent->addr + parent->memsize;
- if( fitsInto( aAddr, parent->next->addr, sz) )
- break;
- parent = parent->next;
- }
- // If not, check between last block & end of EMS
- if( parent->next == 0 )
- {
- aAddr = parent->addr+parent->memsize;
- if( !fitsInto( aAddr, lastAddr, sz) )
- aAddr = -1L;
- }
-
- // If we didn't find a place, it *could* be because we were trying
- // to allocate a sub-block on a non-page (16K) boundary - try
- // again, but this time 'round' the locations up to the next
- // page boundary.
- if( aAddr < 0 )
- {
- for( parent = head; parent->next != 0; parent = parent->next )
- {
- aAddr = nextPageAddr( parent->addr+parent->memsize );
- if( fitsInto(aAddr, parent->next->addr, sz) )
- break;
- }
- if( parent->next == 0 )
- {
- aAddr = nextPageAddr( parent->addr+parent->memsize );
- if( !fitsInto(aAddr, lastAddr, sz) )
- return false;
- }
- }
- }
-
- // Update the linked list.
- if( parent == 0 )
- {
- next = 0;
- head = this;
- }
- else
- {
- next = parent->next;
- parent->next = this;
- }
-
- addr = aAddr;
- memsize = sz;
- return true;
- }
-
- void EmsMemory::free()
- {
- EmsMemory *ptr;
-
- // Ignore if not allocated or is locked.
- if( memsize == 0 || lockflag != 0 )
- return;
-
- // Remove from the linked list.
- if( head == this )
- head = head->next;
- else
- for( ptr = head; ptr->next; ptr = ptr->next )
- if( ptr->next == this )
- {
- ptr->next = ptr->next->next;
- break;
- }
- addr = 0;
- next = 0;
- memsize = 0;
- }
-
- void far *EmsMemory::lock()
- {
- // Fail if its not allocated.
- if( memsize == 0 )
- return 0;
-
- // If it isn't already locked (IE in the frame pages) then we have to
- // try and 'allocate' enough frame pages to fit the pages which
- // enclose this block, then lock our pages into the frame pages.
- if( !lockflag )
- {
- word st = pageOf(addr);
- word end = pageOf( nextPageAddr(addr+memsize) );
- framePage = availableFramePage(end-st);
- if(framePage < 0 || framePage >= EmsPagesPerFrame )
- return 0;
- mapPagesToFrame(framePage, st, end-st );
- }
- lockflag++;
- return (char far *)framePageAddr(framePage)+(addr-pageAddr(pageOf(addr)));
- }
-
- void EmsMemory::unlock()
- {
- // Ignore if the block isn't locked.
- if( !lockflag )
- return;
-
- lockflag--;
- // If its now unlocked, unmap it from the frame pages.
- if( lockflag == 0 )
- {
- word st = pageOf(addr);
- word end = pageOf( nextPageAddr(addr+memsize) );
- unmapFramePages( framePage, end-st );
- }
- }
-
- long EmsMemory::memAvail()
- {
- if( handle == 0 )
- return 0L;
-
- // Return the total amount of EMS we allocated and subtract out the
- // memory used by each block in the linked list.
- long l = lastAddr;
- EmsMemory *ptr;
-
- for( ptr = head; ptr != 0; ptr = ptr->next )
- l -= ptr->memsize;
- return l;
- }
-
- long EmsMemory::maxAvail()
- {
- if( handle == 0 )
- return 0L;
-
- long tmp, l = 0;
- EmsMemory *ptr;
-
- if( head == 0 )
- l = lastAddr;
- else
- {
- for( ptr = head; ptr->next != 0; ptr = ptr->next )
- {
- tmp = ptr->next->addr - ptr->addr - ptr->memsize;
- if( tmp > l )
- l = tmp;
- }
- tmp = lastAddr - ptr->addr - ptr->memsize;
- if( tmp > l )
- l = tmp;
- }
- return l;
- }
-
- void EmsMemory::init()
- {
- word pages;
-
- // Only initialize once.
- if( !isInitialized )
- {
- isInitialized = true;
-
- // Ensure that the INT 67h ISR is not null.
- if( getvect(0x67) == 0 )
- return;
-
- _AH = 0x40;
- asm int 0x67;
- if( _AH )
- return;
-
- _AH = 0x41;
- asm int 0x67;
- if( _AH )
- return;
-
- frameSeg = _BX;
- // Only allocate MaxEmsPages. If this value is < 4 (min), allocate
- // all available EMS pages.
- pages = MaxEmsPages;
- if( pages < 4 )
- {
- _AH = 0x42;
- asm int 0x67;
- pages = _BX;
- }
-
- // There have to be 4 pages available (64K) to use EMS.
- if( pages < 4 )
- return;
-
- _BX = pages;
- _AH = 0x43;
- asm int 0x67;
- if( _AH ) return;
-
- handle = _DX;
- lastAddr = (long)pages * EmsPageSize;
- }
- }
-
- bool EmsMemory::fitsInto(long addr, long next, word sz)
- {
- // First, ensure that the area between addr and next is at least sz.
- if(next <= addr || next-addr < sz)
- return false;
-
- // But we ALSO have to be able to map its pages into the frame buffer.
- word st = pageOf(addr);
- word end = pageOf(addr+sz-1);
- if( end-st+1 > EmsPagesPerFrame )
- return false;
- return true;
- }
-
- long EmsMemory::nextPageAddr( long addr )
- {
- long l = (long)pageOf(addr)*EmsPageSize;
- if( l < addr )
- l += EmsPageSize;
- return l;
- }
-
- word EmsMemory::pageOf( long addr )
- {
- return (word)(addr / EmsPageSize);
- }
-
- long EmsMemory::pageAddr(word page)
- {
- return (long)page * EmsPageSize;
- }
-
- int EmsMemory::availableFramePage(word count)
- {
- if(count < 1 || count > EmsPagesPerFrame || handle == 0 )
- return -1;
- int st, i;
- st = 0;
- while(st < EmsPagesPerFrame)
- {
- for(i = 0; i < count && st+i < EmsPagesPerFrame; i++)
- if(framePageInUse[st+i])
- break;
- if(i >= count)
- break;
- }
- if( st >= EmsPagesPerFrame)
- st = -1;
- return st;
- }
-
- void EmsMemory::mapPagesToFrame(int st, word page, word count)
- {
- if(st < 0 || count < 1 || st+count > EmsPagesPerFrame || handle == 0 )
- return;
-
- while(count)
- {
- _DX = handle;
- _BX = page;
- _AL = st;
- _AH = 0x44;
- asm int 0x67;
- framePageInUse[st++] = true;
- page++;
- count--;
- }
- }
-
- void FAR* EmsMemory::framePageAddr(int page)
- {
- if( handle == 0 )
- return 0;
- else
- return MK_FP(frameSeg+1024*(word)page, 0);
- }
-
- void EmsMemory::unmapFramePages(int st, word count)
- {
- if( handle == 0 )
- return;
-
- while(count)
- {
- if(framePageInUse[st])
- {
- _DX = handle;
- _BX = 0xFFFF;
- _AL = st;
- _AH = 0x44;
- asm int 0x67;
- framePageInUse[st++] = false;
- }
- count--;
- }
- }
-