Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
7.8 kB
3
Indexable
Never
/*************************************************************
  This program shows how to use XMS.  In this example, we
  simulate a large array in XMS and show that it works by
  writing values into it and reading them out again.
  Compile in any model but HUGE and make sure you have
  HIMEM.SYS or another XMS manager loaded.
  Many thanks to Ray Duncan, whose book "Extending DOS"
  (written with many others) was very helpful.
************************************************************/

#ifdef __HUGE__
#error This example cannot be compiled in the huge memory model.
#endif

#include <dos.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <alloc.h>

#define TRUE 1
#define FALSE 0

// BLOCKSIZE will be the size of our real-memory buffer that
// we'll swap XMS through (must be a multiple of 1024, since
// XMS is allocated in 1K chunks.) Can be > 64K as implemented

#define BLOCKSIZE (1024L*64)

// XMSParms is a structure for copying information to and from
// real-mode memory to XMS memory

struct parmstruct
{
    // blocklength is the size in bytes of block to copy

    unsigned long blockLength;

     // sourceHandle is the XMS handle of source; 0 means that
     // sourcePtr will be a 16:16 real-mode pointer, otherwise
     // sourcePtr is a 32-bit offset from the beginning of the
     // XMS area that sourceHandle points to

     unsigned int sourceHandle;
     far void *sourcePtr;

     // destHandle is the XMS handle of destination; 0 means that
     // destPtr will be a 16:16 real-mode pointer, otherwise
     // destPtr is a 32-bit offset from the beginning of the XMS
     // area that destHandle points to

     unsigned int destHandle;
    far void *destPtr;
} XMSParms;

// XMSFunc is a function pointer we'll use to call into the XMS manager
void far (*XMSFunc) (void);

// XMSBuf is the real-mode memory buffer for transfers to and
// from XMS.  Make it a huge * instead of a far * if BLOCKSIZE is >= 64K
unsigned long huge *XMSBuf;

// XMSHandle is the handle we'll use to refer to our
// XMS allocation
// when talking to the XMS manager
unsigned int XMSHandle;

// a flag which says whether the current buffer has been written into or not
char curBlockDirty=FALSE;

// the part of our XMS allocation that is currently copied into real memory
int curBlock=-1;

// returns TRUE if XMS present, FALSE otherwise
char XMSCheck()
{
     _AX=0x4300;
     geninterrupt(0x2F);
     return (_AL==0x80);
}

// GetXMSEntry sets XMSFunc to the XMS Manager entry point
// so we can call it later

void GetXMSEntry(void)
{
     _AX=0x4310;
     geninterrupt(0x2F);
     XMSFunc= (void (far *)(void)) MK_FP(_ES,_BX);
}

// XMSSize returns the total kilobytes available, and the size
// in kilobytes of the largest available block

void XMSSize(int *kbAvail, int *largestAvail)
{
     _AH=8;
     (*XMSFunc)();
     *largestAvail=_DX;
     *kbAvail=_AX;
}

char GetBuf(void)
{
     XMSBuf=(unsigned long far *) farmalloc(BLOCKSIZE);
     if (XMSBuf==NULL)
     {
          printf("Couldn't allocate %u bytes for real-memory buffer\n",
               BLOCKSIZE);
          return FALSE;
     }
     return TRUE;
}

char AllocXMS(unsigned long numberBytes)
{
     int numBlocks;
     // divide by BLOCKSIZE to get number of blocks
     numBlocks=(int) (numberBytes/BLOCKSIZE);
     if ((numberBytes%BLOCKSIZE) != 0) ++numBlocks;
     _DX=(int) (numBlocks*(BLOCKSIZE/1024));
     _AH=9;
     (*XMSFunc)();
     if (_AX==0)
     {
          printf("Could not allocate %u %u-byte blocks of XMS\n",
               numBlocks,BLOCKSIZE);
          return FALSE;

     }
     XMSHandle=_DX;
     return TRUE;
}

// CleanUp() frees up the XMS handle that we allocated

void CleanUp(void)
{
     printf("Freeing XMS Handle.\n");
     _DX=XMSHandle;
     _AH=0x0A;
     (*XMSFunc)();
}

// GetCorrectBlock() makes sure that the current block stored
// in the buffer XMSBuf is the correct block by swapping the
// current block out and bringing in a new block

void GetCorrectBlock(unsigned int block)
{
     // curBlockDirty is checked for an optimization:  we write
     // out the current buffer back out to XMS only if it's
     // "dirty" (been written into).
     if (curBlockDirty)
     {
          // write dirty block from XMSBuf out to XMS
          printf("Writing out used block %d\n", curBlock);
          XMSParms.sourceHandle=0;
          XMSParms.sourcePtr=XMSBuf;
          XMSParms.destHandle=XMSHandle;
          XMSParms.destPtr=(void far *) (((long)curBlock) *
                                             BLOCKSIZE);
          XMSParms.blockLength=BLOCKSIZE;
          // pass a pointer to the parameters structure to
          // the XMS Manager
          _SI=FP_OFF(&XMSParms);
          _AH=0x0B;
          (*XMSFunc)();
          if (_AX==0)
          {
               printf("Error writing block %d!\n",curBlock);
               CleanUp();
			   exit(0);
          }
     }
     // fetch block from XMS into XMSBuf buffer
     printf("Getting XMS block %d\n",block);
     XMSParms.sourceHandle=XMSHandle;
     XMSParms.sourcePtr=(void far *) (((long)block) * BLOCKSIZE);
     XMSParms.destHandle=0;
     XMSParms.destPtr=XMSBuf;
     XMSParms.blockLength=BLOCKSIZE;
     _SI=FP_OFF(&XMSParms);
     _AH=0x0B;
     (*XMSFunc)();
     if (_AX==0)
     {
          printf("Error reading block %d!\n",block);
          CleanUp();
		  exit(0);
     }
     curBlockDirty=FALSE;
     curBlock=block;
}

// PutVal() puts a value into the "big array" using
// GetCorrectBlock() to swap the buffer to/from XMS
// if necessary

// You could improve performance in PutVal() and GetVal() by
// using bit-shifts instead of divides, and by using the '&'
// operator instead of '%' to find the position in XMSBuf.

void PutVal(unsigned long loc, unsigned long val)
{
     unsigned int block;
     block=(int) (loc/(BLOCKSIZE/sizeof(long)));
     if (block != curBlock) GetCorrectBlock(block);

     // note that the current block in XMSBuf has been used so
     // we won't forget to write it out later
     curBlockDirty=TRUE;

     // the buffer holds BLOCKSIZE bytes,
     // or BLOCKSIZE/sizeof(long) long's)

     XMSBuf[loc % (BLOCKSIZE/sizeof(long)) ] = val;
}

// GetVal() returns the value from a point in the "big array"
// using GetCorrectBlock() to swap buffer to/from XMS if
// necessary

long GetVal(unsigned long loc)
{
     unsigned int block;
     block=(int) (loc/(BLOCKSIZE/sizeof(long)));
     if (block != curBlock) GetCorrectBlock(block);
     return( XMSBuf[loc % (BLOCKSIZE/sizeof(long)) ] );
}

int main()
{
     int kbAvail,largestAvail;
     unsigned long i;

     if (XMSCheck) printf("XMS Available ...\n");
     else
     {
          printf("XMS Not Available\n");
          return(1);
     }

     GetXMSEntry();

     XMSSize(&kbAvail,&largestAvail);
     printf("Kilobytes Available: %d; Largest block: %dK\n",
               kbAvail,largestAvail);

     if (!GetBuf())
          { printf("Error allocating buffer!\n");  return(1); }

     // We'll allocate space for 50,000 Long's (200,000 bytes)
     // in our simulated array.

     if (!AllocXMS(sizeof(long)*50000L))
          return(1);

     // put a lot of values in our simulated array, and read
     // them back to make sure that they're out there

     for (i=0; i<50000L; i++)
          PutVal(i,i);
     for (i=0; i<50000L; ++i)
          if (GetVal(i)!=i)
          { printf("Error: %lu != %lu\n",i,GetVal(i)); break; }

     CleanUp();
	 
	 printf("DONE: Any key to quit...\n");
	 
	 getch();
	 
     return(0);
}

Leave a Comment