PRODUCT : Borland C++ NUMBER : 1300 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 1/6 TITLE : Example of how to access expanded (EMS) memory. /************************************************************ This program demonstrates the use of EMS (expanded memory.) In this program, we use EMS to store a simulated array of 50,000 long ints. Compile in any memory model. It is not optimized, for purposes of clarity. Many thanks to Ray Duncan for his lucid exposition of EMS in "Extending DOS" ************************************************************/ #include #include #include #include #include #include #define TRUE 1 #define FALSE 0 #define EMS_INT 0x67 #define PAGESIZE 16384 int EMSHandle; int pageMap[4] = { -1, -1, -1, -1 }; int pageFrame; // Function to test for existence of EMS. If coding a TSR or // ISR, you will be unable to call DOS and therefore must check // if the name EMMXXXX0 is at offset 10 from the entrypoint to // the EM Manager pointed to by vector 0x67 char EMSExists(void) { int handle,devInfo,outputStatus; // The expanded memory manager if present should show up // as a filename if ((handle=open("EMMXXXX0",O_RDONLY|O_BINARY)) == -1) return FALSE; devInfo=ioctl(handle,0); // if bit 7 is 0 it is a file if ((devInfo & 0x80) == 0) { printf("Found File EMMXXXX0?!?\n"); PRODUCT : Borland C++ NUMBER : 1300 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 2/6 TITLE : Example of how to access expanded (EMS) memory. close(handle); return FALSE; } outputStatus=ioctl(handle,7); if (outputStatus==0) { printf("EMM present but not responding\n"); close(handle); return FALSE; } // file handle for EMS manager is useless for anything // further, so we'll just close it. close(handle); return TRUE; } // Assuming EMS is present, it may still not be functional // due to a hardware error or who knows what, so we have // a function to check whether the expanded memory manager // is ready to do its business. char EMSFunctional(void) { _AH=0x40; geninterrupt(EMS_INT); if (_AH==0) return FALSE; else return TRUE; } // EMSSize() finds out the total and available pages of EMS void EMSSize(int *pagesTotal, int *pagesAvail) { _AH=0x42; geninterrupt(0x67); *pagesAvail=_BX; *pagesTotal=_DX; } // EMSAlloc() tries to allocate the number of pages corresponding // to the size in bytes of the allocation requested. char EMSAlloc(unsigned long bytes) PRODUCT : Borland C++ NUMBER : 1300 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 3/6 TITLE : Example of how to access expanded (EMS) memory. { int numPages; numPages=(int) (bytes/PAGESIZE); if (bytes%PAGESIZE != 0) ++numPages; _BX=numPages; _AH=0x43; geninterrupt(EMS_INT); EMSHandle=_DX; if (_AH!=0) { printf("Allocation of %d pages failed\n",numPages); return FALSE; } else { printf("Allocated %d pages\n",numPages); return TRUE; } } // CleanUp() tries to deallocate our EMS allocation void CleanUp(void) { _AH=0x45; _DX=EMSHandle; geninterrupt(EMS_INT); if (_AH!=0) printf("Deallocation failed!\n"); } void EMSRemap(int logpage) { // the mapping scheme we're using is that the physical page // mapping for a logical page is the logical page mod 4 printf("Mapping logical page %d\n",logpage); // ask to map logical page _BX into physical page (0->3) _AL _AL=logpage&3; _BX=logpage; _DX=EMSHandle; _AH=0x44; geninterrupt(EMS_INT); if (_AH!=0) { PRODUCT : Borland C++ NUMBER : 1300 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 4/6 TITLE : Example of how to access expanded (EMS) memory. printf("Mapping failed!\n"); CleanUp(); exit(1); } pageMap[logpage&3]=logpage; } // GetEMSPageFrame finds the segment that the page frame lives // at and stores it in pageFrame for use by PutVal and GetVal void GetEMSPageFrame(void) { _AH=0x41; geninterrupt(EMS_INT); pageFrame=_BX; if (_AH!=0) { printf("Cannot get page frame!\n"); CleanUp(); exit(1); } } // PutVal() puts a value into the array, asking for a page to be // remapped if the correct page isn't in memory. // With both PutVal() and GetVal(), the code could be optimized // considerably by using bitshifts instead of multiplies. And, // a real application would probably be coded to check less // often for the page being present. void PutVal(unsigned long loc, unsigned long val) { unsigned int logPage; // logical page unsigned long far * physLoc; // loc*sizeof(long) is the byte address of the item; we // divide by PAGESIZE to figure out which logical page // it's on logPage= (int) (loc*sizeof(long)/PAGESIZE); // logical page mod 4 is our scheme to map a logical page // to a physical page. pageMap tells us which logical // page is being kept in each physical page. PRODUCT : Borland C++ NUMBER : 1300 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 5/6 TITLE : Example of how to access expanded (EMS) memory. if (pageMap[logPage&3]!=logPage) EMSRemap(logPage); // the offset in the EMS buffer will be sizeof(long) times // the array index, mod 64K; the segment of the EMS buffer // is of course pageFrame. physLoc= (unsigned long far *) MK_FP(pageFrame,(loc*sizeof(long))&65535U); *physLoc=val; } // GetVal() gets a value from the 'array', asking for a page to // be remapped if the correct page isn't in memory. unsigned long GetVal(unsigned long loc) { unsigned int logPage; unsigned long far * physLoc; logPage= (int) (loc*sizeof(long)/PAGESIZE); if (pageMap[logPage&3]!=logPage) EMSRemap(logPage); physLoc= (unsigned long far *) MK_FP(pageFrame,(loc*sizeof(long))&65535U); return *physLoc; } int main(void) { int pagesAvail,pagesTotal; unsigned long i; if (EMSExists()) printf("Found EMS\n"); else { printf("No EMS"); return(1); } if (EMSFunctional) printf("EMS Working\n"); else { printf("EMS present but malfunctioning\n"); return(1); } EMSSize(&pagesTotal,&pagesAvail); printf("EMS Pages -- Total: %u, Available %u (%uK)\n", pagesTotal,pagesAvail,pagesAvail*16); PRODUCT : Borland C++ NUMBER : 1300 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 6/6 TITLE : Example of how to access expanded (EMS) memory. // allocate enough space in EMS for 50,000 long ints if (!EMSAlloc(sizeof(long)*50000L)) return(1); GetEMSPageFrame(); printf("Page frame at segment 0x%4X\n",pageFrame); // Test our EMS functions by storing and retrieving // 50,000 long ints for (i=0; i<50000L; ++i) PutVal(i,i); for (i=0; i<50000L; ++i) if (GetVal(i)!=i) { printf("%d != %d\n",GetVal(i),i); break; } CleanUp(); return(0); } DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.