home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / pascal / rehack / memory / ems.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-29  |  7.4 KB  |  371 lines

  1. #include "..\MEMORY\MEMORY.HPP"
  2. #include <dos.h>
  3.  
  4. // ------------------------------------------------------------------
  5. // File:        EMS.CPP
  6. // Path:        ...\REHACK\MEMORY\EMS.CPP
  7. // Version:        0.01
  8. // Author:        Pat Reilly
  9. // CIS Id:        71333,2764
  10. // Created On:    6/28/93
  11. // Modified On:
  12. // Description:    EmsMemory class for REHACK. See MEMORY.TXT for
  13. //                more details.
  14. // Tabs:        4
  15. // ------------------------------------------------------------------
  16.  
  17. static word MaxEmsPages = 0U;
  18.  
  19. bool EmsMemory::isInitialized = false;
  20. EmsMemory* EmsMemory::head = 0;
  21. long EmsMemory::lastAddr = 0L;
  22. word EmsMemory::handle = 0U;
  23. bool EmsMemory::framePageInUse[EmsPagesPerFrame] = { true,true,true,true };
  24. word EmsMemory::frameSeg = 0U;
  25.  
  26. // Function to free up all used EMS pages when program exits.
  27. void ClearEms()
  28. {
  29.     if( EmsMemory::handle != 0 )
  30.         {
  31.         _DX = EmsMemory::handle;
  32.         _AH = 0x45;
  33.         asm    int 0x67;
  34.         }
  35. }
  36.  
  37. #pragma exit ClearEms
  38.  
  39. EmsMemory::EmsMemory()
  40. {
  41.     init();
  42. }
  43.  
  44. EmsMemory::EmsMemory(word sz)
  45. {
  46.     init();
  47.     allocate(sz);
  48. }
  49.  
  50. bool EmsMemory::allocate(word sz)
  51. {
  52.     // Fail if memory allocated or sz == 0 or EMS not available.
  53.     if( handle == 0 || memsize != 0 || sz == 0 )
  54.         return false;
  55.  
  56.     // We allocated a bunch of EMS pages - use a first-fit algorithm to
  57.     //    allocate a sub-region.
  58.     memsize = 0;
  59.     long aAddr = 0;
  60.     EmsMemory* parent = head;
  61.  
  62.     // If this is the first allocation, see if it can fit.
  63.     if( head == 0 )
  64.         {
  65.         if( sz > lastAddr )
  66.             return false;
  67.         }
  68.  
  69.     // There's other allocations - search for first fit.
  70.     else
  71.         {
  72.         // First, look in-between blocks.
  73.         while( parent->next != 0 )
  74.             {
  75.             aAddr = parent->addr + parent->memsize;
  76.             if( fitsInto( aAddr, parent->next->addr, sz) )
  77.                 break;
  78.             parent = parent->next;
  79.             }
  80.         // If not, check between last block & end of EMS
  81.         if( parent->next == 0 )
  82.             {
  83.             aAddr = parent->addr+parent->memsize;
  84.             if( !fitsInto( aAddr, lastAddr, sz) )
  85.                 aAddr = -1L;
  86.             }
  87.  
  88.         // If we didn't find a place, it *could* be because we were trying
  89.         //    to allocate a sub-block on a non-page (16K) boundary - try
  90.         //    again, but this time 'round' the locations up to the next
  91.         //    page boundary.
  92.         if( aAddr < 0 )
  93.             {
  94.             for( parent = head; parent->next != 0; parent = parent->next )
  95.                 {
  96.                 aAddr = nextPageAddr( parent->addr+parent->memsize );
  97.                 if( fitsInto(aAddr, parent->next->addr, sz) )
  98.                     break;
  99.                 }
  100.             if( parent->next == 0 )
  101.                 {
  102.                 aAddr = nextPageAddr( parent->addr+parent->memsize );
  103.                 if( !fitsInto(aAddr, lastAddr, sz) )
  104.                     return false;
  105.                 }
  106.             }
  107.         }
  108.  
  109.     // Update the linked list.
  110.     if( parent == 0 )
  111.         {
  112.         next = 0;
  113.         head = this;
  114.         }
  115.     else
  116.         {
  117.         next = parent->next;
  118.         parent->next = this;
  119.         }
  120.  
  121.     addr = aAddr;
  122.     memsize = sz;
  123.     return true;
  124. }
  125.  
  126. void EmsMemory::free()
  127. {
  128.     EmsMemory *ptr;
  129.  
  130.     // Ignore if not allocated or is locked.
  131.     if( memsize == 0 || lockflag != 0 )
  132.         return;
  133.  
  134.     // Remove from the linked list.
  135.     if( head == this )
  136.         head = head->next;
  137.     else
  138.         for( ptr = head; ptr->next; ptr = ptr->next )
  139.             if( ptr->next == this )
  140.                 {
  141.                 ptr->next = ptr->next->next;
  142.                 break;
  143.                 }
  144.     addr = 0;
  145.     next = 0;
  146.     memsize = 0;
  147.     }
  148.  
  149. void far *EmsMemory::lock()
  150. {
  151.     // Fail if its not allocated.
  152.     if( memsize == 0 )
  153.         return 0;
  154.  
  155.     // If it isn't already locked (IE in the frame pages) then we have to
  156.     //    try and 'allocate' enough frame pages to fit the pages which
  157.     //    enclose this block, then lock our pages into the frame pages.
  158.     if( !lockflag )
  159.         {
  160.         word st = pageOf(addr);
  161.         word end = pageOf( nextPageAddr(addr+memsize) );
  162.         framePage = availableFramePage(end-st);
  163.         if(framePage < 0 || framePage >= EmsPagesPerFrame )
  164.             return 0;
  165.         mapPagesToFrame(framePage, st, end-st );
  166.         }
  167.     lockflag++;
  168.     return (char far *)framePageAddr(framePage)+(addr-pageAddr(pageOf(addr)));
  169.     }
  170.  
  171. void EmsMemory::unlock()
  172. {
  173.     // Ignore if the block isn't locked.
  174.     if( !lockflag )
  175.         return;
  176.  
  177.     lockflag--;
  178.     // If its now unlocked, unmap it from the frame pages.
  179.     if( lockflag == 0 )
  180.         {
  181.         word st = pageOf(addr);
  182.         word end = pageOf( nextPageAddr(addr+memsize) );
  183.         unmapFramePages( framePage, end-st );
  184.         }
  185.     }
  186.  
  187. long EmsMemory::memAvail()
  188. {
  189.     if( handle == 0 )
  190.         return 0L;
  191.  
  192.     // Return the total amount of EMS we allocated and subtract out the
  193.     //    memory used by each block in the linked list.
  194.     long l = lastAddr;
  195.     EmsMemory *ptr;
  196.  
  197.     for( ptr = head; ptr != 0; ptr = ptr->next )
  198.         l -= ptr->memsize;
  199.     return l;
  200. }
  201.  
  202. long EmsMemory::maxAvail()
  203. {
  204.     if( handle == 0 )
  205.         return 0L;
  206.  
  207.     long tmp, l = 0;
  208.     EmsMemory *ptr;
  209.  
  210.     if( head == 0 )
  211.         l = lastAddr;
  212.     else
  213.         {
  214.         for( ptr = head; ptr->next != 0; ptr = ptr->next )
  215.             {
  216.             tmp = ptr->next->addr - ptr->addr - ptr->memsize;
  217.             if( tmp > l )
  218.                 l = tmp;
  219.             }
  220.         tmp = lastAddr - ptr->addr - ptr->memsize;
  221.         if( tmp > l )
  222.             l = tmp;
  223.         }
  224.     return l;
  225. }
  226.  
  227. void EmsMemory::init()
  228. {
  229.     word pages;
  230.  
  231.     // Only initialize once.
  232.     if( !isInitialized )
  233.         {
  234.         isInitialized = true;
  235.  
  236.         // Ensure that the INT 67h ISR is not null.
  237.         if( getvect(0x67) == 0 )
  238.             return;
  239.  
  240.         _AH = 0x40;
  241.         asm    int 0x67;
  242.         if( _AH )
  243.             return;
  244.  
  245.         _AH = 0x41;
  246.         asm int 0x67;
  247.         if( _AH )
  248.             return;
  249.  
  250.         frameSeg = _BX;
  251.         // Only allocate MaxEmsPages. If this value is < 4 (min), allocate
  252.         //    all available EMS pages.
  253.         pages = MaxEmsPages;
  254.         if( pages < 4 )
  255.             {
  256.             _AH = 0x42;
  257.             asm int 0x67;
  258.             pages = _BX;
  259.             }
  260.  
  261.         // There have to be 4 pages available (64K) to use EMS.
  262.         if( pages < 4 )
  263.             return;
  264.  
  265.         _BX = pages;
  266.         _AH = 0x43;
  267.         asm int 0x67;
  268.         if( _AH )    return;
  269.  
  270.         handle = _DX;
  271.         lastAddr = (long)pages * EmsPageSize;
  272.         }
  273. }
  274.  
  275. bool EmsMemory::fitsInto(long addr, long next, word sz)
  276. {
  277.     // First, ensure that the area between addr and next is at least sz.
  278.     if(next <= addr || next-addr < sz)
  279.         return false;
  280.  
  281.     // But we ALSO have to be able to map its pages into the frame buffer.
  282.     word st = pageOf(addr);
  283.     word end = pageOf(addr+sz-1);
  284.     if( end-st+1 > EmsPagesPerFrame )
  285.         return false;
  286.     return true;
  287. }
  288.  
  289. long EmsMemory::nextPageAddr( long addr )
  290. {
  291.     long l = (long)pageOf(addr)*EmsPageSize;
  292.     if( l < addr )
  293.         l += EmsPageSize;
  294.     return l;
  295. }
  296.  
  297. word EmsMemory::pageOf( long addr )
  298. {
  299.     return (word)(addr / EmsPageSize);
  300. }
  301.  
  302. long EmsMemory::pageAddr(word page)
  303. {
  304.     return (long)page * EmsPageSize;
  305. }
  306.  
  307. int EmsMemory::availableFramePage(word count)
  308. {
  309.     if(count < 1 || count > EmsPagesPerFrame || handle == 0 )
  310.         return -1;
  311.     int st, i;
  312.     st = 0;
  313.     while(st < EmsPagesPerFrame)
  314.         {
  315.         for(i = 0; i < count && st+i < EmsPagesPerFrame; i++)
  316.             if(framePageInUse[st+i])
  317.                 break;
  318.         if(i >= count)
  319.             break;
  320.         }
  321.     if( st >= EmsPagesPerFrame)
  322.         st = -1;
  323.     return st;
  324. }
  325.  
  326. void EmsMemory::mapPagesToFrame(int st, word page, word count)
  327. {
  328.     if(st < 0 || count < 1 || st+count > EmsPagesPerFrame || handle == 0 )
  329.         return;
  330.  
  331.     while(count)
  332.         {
  333.         _DX = handle;
  334.         _BX = page;
  335.         _AL = st;
  336.         _AH = 0x44;
  337.         asm int 0x67;
  338.         framePageInUse[st++] = true;
  339.         page++;
  340.         count--;
  341.         }
  342. }
  343.  
  344. void FAR* EmsMemory::framePageAddr(int page)
  345. {
  346.     if( handle == 0 )
  347.         return 0;
  348.     else
  349.         return MK_FP(frameSeg+1024*(word)page, 0);
  350. }
  351.  
  352. void EmsMemory::unmapFramePages(int st, word count)
  353. {
  354.     if( handle == 0 )
  355.         return;
  356.  
  357.     while(count)
  358.         {
  359.         if(framePageInUse[st])
  360.             {
  361.             _DX = handle;
  362.             _BX = 0xFFFF;
  363.             _AL = st;
  364.             _AH = 0x44;
  365.             asm int 0x67;
  366.             framePageInUse[st++] = false;
  367.             }
  368.         count--;
  369.         }
  370. }
  371.