#ifdef __WATCOMC__
#include <conio.h>
#endif
#ifdef __HIGHC__
#include <dos.h>
#include <conio.h>
#endif
#include "iwprotos.h"
#include "iwdefs.h"
//
extern IWAVE iw;
//
//#############################################################################
//  FILE   : iwmem.c
//
//  REMARKS: This file contains the definitions of a DDK family of functions
//           dedicated to manage the DRAM or Local Memory connected to the
//           InterWave IC.
//
//  UPDATE: 6/05/95 --- Update for BCC32
//          7/12/95 --- Modified IwaveMemCfg to flag non-configuous RAM
//#############################################################################
//  FUNCTION: IwaveMemInit
//
//  PROFILE : This function initializes the Local Memory so that memory
//            allocation and de-allocation can be performed. Note that in
//            GF1 mode, the greatest chunk of memory that can be
//            allocated can be no more than 256KB. An application can
//            reserve a certain amount of LM, which must be >= 0 bytes and
//            <= 256KB in GF1 mode. In Enhanced Mode, such limitations do
//            not exist.
//
//########################################################################
BOOL IwaveMemInit(void)
{
   DWORD dram_size;
   DWORD dram_avail;
   DWORD app_mem;

	dram_size = ((DWORD)(iw.size_mem)*1024L); // Size of DRAM in bytes
   
   if (iw.smode)                      // Enhanced Mode 
   {
	 app_mem = iw.reserved_mem+1L;     // Align with even byte
    app_mem &=-2L;
	 dram_avail = dram_size - app_mem; // DRAM left to work with
    iw.free_mem = app_mem;            // Addr. of first free block 
    IwaveWriteLong(iw.free_mem+NEXT_OFFSET,NO_NEXT);
    IwaveWriteLong(iw.free_mem+PREV_OFFSET,NO_PREV);
    IwaveWriteLong(iw.free_mem+SIZE_OFFSET,dram_avail);
   }
	else // GF1 Mode
   {
    if (iw.reserved_mem > (DWORD)(256L*1024L))
        return(ILLEGAL_SIZE);

	 app_mem = iw.reserved_mem+31L;         // Align to 32-byte edge
    app_mem &=-32L;
	 dram_avail = dram_size - app_mem;      // LM left for samples
	 iw.free_mem = app_mem;                 // Addr. of first free block
    
    IwaveWriteLong(iw.free_mem+NEXT_OFFSET,NO_NEXT);
    IwaveWriteLong(iw.free_mem+PREV_OFFSET,NO_PREV);
    IwaveWriteLong(iw.free_mem+SIZE_OFFSET,dram_avail);

//##########################################################
//  Split LM into blocks no greater than 256KB
//  as GF1 can not play 16-bit data beyond
//  256KB.
//###########################################################
    if (dram_avail > (DWORD)(256L*1024L))
     {
       (void)IwaveMemAlloc(dram_avail);

       if (dram_avail>(DWORD)(256L*3L*1024L))
           (void)IwaveMemFree(GF1_POOL,(DWORD)(256L*3L*1024L));

       if (dram_avail>(DWORD)(256L*2L*1024L))
           (void)IwaveMemFree(GF1_POOL,(DWORD)(256L*2L*1024L));
       
       (void)IwaveMemFree(GF1_POOL,(DWORD)(256L*1L*1024L));
       (void)IwaveMemFree(GF1_POOL-app_mem,app_mem);
     }
    } // GUS Mode 
 return(TRUE);     
}
//########################################################################
//  FUNCTION: IwaveMemFree
//
//  PROFILE : This function releases or de-allocates blocks of local memory
//            that were allocated with IwaveMemAlloc. The block is
//            retuned to the free-block chain. As a last step, the function
//            will merge together all adjacent free blocks into a single
//            block. The function will return TRUE if successful or FALSE if
//            the Local Memory has been corrupted.
//
//  INPUT   : The function takes the following arguments:
//
//            size     - the number of bytes to free.
//            blk_addr - the address of the block to free up
//
//########################################################################
BOOL
IwaveMemFree(DWORD   size, ADDRESS blk_addr)
{
   ADDRESS addr_ptr;
   ADDRESS prev_free;
   ADDRESS next_free;
   BOOL     mem_ok = FALSE;

//#############################################################
// Round up Specified Size to either a 32-byte boundary
// or an even byte boundary depending on the mode of
// operation.
//#############################################################

   if (iw.smode)
    {
	  size += 1L;             // Enhanced Mode
     size &= -2L;
    }
   else
    {                        // GUS Mode 
     size +=31L;
     size &= -32L;
    }

    addr_ptr = iw.free_mem;        /* point to a free LM block */

    if (addr_ptr == MEM_EXHAUSTED)  /* no free LM available */
      {
//###########################################
// Point to block about to be freed
//###########################################

       iw.free_mem = blk_addr;
       IwaveWriteLong(blk_addr+NEXT_OFFSET, NO_NEXT);
       IwaveWriteLong(blk_addr+PREV_OFFSET, NO_PREV);
       IwaveWriteLong(blk_addr+SIZE_OFFSET, size);
      }
    else /* Return memory block to free pool */
     {
      while (addr_ptr!=NO_NEXT && !mem_ok)
        {
         next_free = IwaveReadLong(addr_ptr+NEXT_OFFSET);
         prev_free = IwaveReadLong(addr_ptr+PREV_OFFSET);
         if (blk_addr < addr_ptr)
           {
            if (prev_free == NO_PREV)    /* no previous free block */
               iw.free_mem = blk_addr;  /* point to this free block */
            else
               IwaveWriteLong(prev_free+NEXT_OFFSET, blk_addr);

 //########################################################################
 //                  Return Block to free chain.
 //########################################################################

                IwaveWriteLong(blk_addr+NEXT_OFFSET, addr_ptr);
                IwaveWriteLong(blk_addr+PREV_OFFSET, prev_free);
                IwaveWriteLong(blk_addr+SIZE_OFFSET, size);
                IwaveWriteLong(addr_ptr+PREV_OFFSET, blk_addr);
                mem_ok = TRUE;
        }
        else

                if (next_free == NO_NEXT)       /* no free block ahead */
                {
                 IwaveWriteLong(addr_ptr+NEXT_OFFSET, blk_addr);
                 IwaveWriteLong(blk_addr+NEXT_OFFSET, NO_NEXT);
                 IwaveWriteLong(blk_addr+PREV_OFFSET, addr_ptr);
                 IwaveWriteLong(blk_addr+SIZE_OFFSET, size);
                 mem_ok = TRUE;
					 }
//###########################################################
//         Try next block
//###########################################################

        addr_ptr = IwaveReadLong(addr_ptr+NEXT_OFFSET);

        } /* while loop */

} /* Outer "if" Statement */

//############################################################
// If Local Memory is not corrupted, proceed to merge
// adjacent blocks of free Local Memory.
//############################################################
	if (mem_ok)
		 IwaveMemMerge();

	return(mem_ok);
}
//########################################################################
//
// FUNCTION: IwaveMemMerge
//
// PROFILE: This function combines adjacent memory blocks available for
//          for allocation by IwaveMemAlloc. This function is normally
//          called by IwaveMemFree during memory deallocation.
//
//########################################################################
void IwaveMemMerge(void)
{
	 ADDRESS blk_size;
	 ADDRESS next_size;
	 ADDRESS next_next;
    ADDRESS addr_ptr;
    ADDRESS next_free;

	 addr_ptr = iw.free_mem;    /* start at the beginning */

	 while( addr_ptr != NO_NEXT )
	 {
			next_free = IwaveReadLong(addr_ptr+NEXT_OFFSET);
			blk_size = IwaveReadLong(addr_ptr+SIZE_OFFSET);
			if ((addr_ptr + blk_size)==next_free) /* adjacent free blocks */
			 {
			  next_next = IwaveReadLong(next_free+NEXT_OFFSET);
			  next_size = IwaveReadLong(next_free+SIZE_OFFSET);
			  blk_size += next_size;
			  IwaveWriteLong(addr_ptr+SIZE_OFFSET,blk_size);
			  IwaveWriteLong(addr_ptr+NEXT_OFFSET,next_next);

			  if ( next_next != NO_NEXT )
				  IwaveWriteLong(next_next+PREV_OFFSET,addr_ptr);
			  else
				  break; /* End of free chain reached */
			 }
			else
			  addr_ptr=IwaveReadLong(addr_ptr+NEXT_OFFSET);
	 }
}
//########################################################################
//
//  FUNCTION: IwaveMemAlloc
//
//  PROFILE : This function allocates a block of memory requested by an
//            application. The requested size in bytes will be rounded up
//            to the next 32-byte boundary when the InterWave is in GUS
//            mode or to an even byte when in enhanced mode. The function
//            returns the memory address where the block is to start if
//            successful. Otherwise, it returns ALLOC_FAILURE.
//
//  INPUT   : The input to this function is as follows:
//
//            size  - size in bytes of the block to allocate
//
//########################################################################
ADDRESS IwaveMemAlloc(DWORD size)
{
  DWORD block_size;
  DWORD size_left;
  ADDRESS curr_addr;
  ADDRESS next;
  ADDRESS prev;

  if (iw.smode)  /* Enhanced Mode */
  {
   size += 1L;
   size &=-2L;
  }
  else		        /* GF1 Mode */
  {
   size +=31L;
   size &=-32L;
  }

  curr_addr = iw.free_mem;	/* addr. of first free block */

  while (curr_addr!=NO_NEXT)
  {
   block_size=IwaveReadLong(curr_addr+SIZE_OFFSET);
   
   if (block_size >= size)
     {
     size_left = block_size - size;
     if (size_left < MEM_HEADER_SIZE)
        {
//########################################################################
// Since left-over space is less than the size of a
//	memory header, just take entire block
//########################################################################

         next=IwaveReadLong(curr_addr+NEXT_OFFSET);
         prev=IwaveReadLong(curr_addr+PREV_OFFSET);

         if (next!=NO_NEXT)
            IwaveWriteLong(next+PREV_OFFSET,prev);
         
         if (prev!=NO_PREV)
            IwaveWriteLong(prev+NEXT_OFFSET,next);
         else
//########################################################################
//        Point to first free block again
//########################################################################

            iw.free_mem = next;
         return(curr_addr);
        }
      else
        {
//########################################################################
//	  Break this block up into two and take upper block
//########################################################################

         IwaveWriteLong(curr_addr+SIZE_OFFSET,size_left);
         return(curr_addr+size_left);
        }
    } /* outer "if" */
//########################################################################
// Since last free block was not big enough, look at the next
//########################################################################

    curr_addr=IwaveReadLong(curr_addr+NEXT_OFFSET);

  } /* while loop */
 return(ALLOC_FAILURE);
}
//########################################################################
//
//  FUNCTION: IwaveMaxAlloc
//
//  PROFILE : This function returns the size of the greatest block of memory
//            that can be still be allocated. When in GF1 mode, this size
//            can not be greater than 256KB. This function can be used to
//            determine if there is a block of memory big enough available
//            to honor an application's request.
//
//########################################################################
DWORD IwaveMaxAlloc(void)
{
	DWORD   size=0L;
	DWORD   block_size;
	ADDRESS curr_addr;

	curr_addr = iw.free_mem; 	/* Start with first block */

	while (curr_addr!=NO_NEXT)
	{
	  block_size = IwaveReadLong(curr_addr+SIZE_OFFSET);
	  if (block_size > size)
			size = block_size;

	  curr_addr = IwaveReadLong(curr_addr+NEXT_OFFSET);
	}
  return(size);
}
//########################################################################
//
//  FUNCTION: IwaveMemAvail
//
//  PROFILE : This function returns the total amount of memory in the free
//            chain.
//
//########################################################################
DWORD IwaveMemAvail(void)     
{
	DWORD   size=0L;
	DWORD   block_size;
	ADDRESS curr_addr;

	curr_addr = iw.free_mem; 	// Start with first block 
	
	while (curr_addr!=NO_NEXT)
	{
          block_size=IwaveReadLong(curr_addr+SIZE_OFFSET);
	  size+=block_size;
	  curr_addr = IwaveReadLong(curr_addr+NEXT_OFFSET);
	}
  return(size);
}
//########################################################################
//
//  FUNCTION: IwaveMemCfg
//
//  PROFILE : This function determines the amount of DRAM from its
//            configuration accross all banks. It sets the configuration
//            into register LMCFI and stores the total amount of DRAM
//            into iw.size_mem (Kbytes).
//
//            The function first places the IC in enhanced mode to allow
//            full access to all DRAM locations. Then it selects full
//            addressing span (LMCFI[3:0]=0x0C). Finally, it determines
//            the amount of DRAM in each bank and from this the actual
//            configuration.
//
//            Note that if a configuration other than one indicated in
//            the manual is implemented, this function will select
//            full addressing span (LMCFI[3:0]=0xC).
//
//########################################################################
void IwaveMemCfg(DWORD *lpbanks)
{
  DWORD bank[4]={0L,0L,0L,0L};
  DWORD addr=0L, base=0L, cnt=0L;
  BYTE i, reg, ram=FALSE;
  WORD lmcfi;
//
  ENTER_CRITICAL;
  _poke(iw.igidxr,0x99);
  reg=_peek(iw.i8dp);                     // image of sgmi
  _poke(iw.igidxr,0x19);
  _poke(iw.i8dp,(BYTE)(reg|0x01));        // enable enhaced mode
  _poke(iw.igidxr,_LMCFI);                // select LM Conf Reg
  lmcfi=_peekw(iw.i16dp)&0xFFF0;
  _pokew(iw.i16dp,lmcfi|0x000C);          // max addr span
//
//  Clear every RAM_STEPth location
//
	 while(addr < RAM_MAX)
	  {
			IwaveMemPoke(addr,0x00);
			addr+=RAM_STEP;
	  }
//
//  Determine amount of RAM in each bank
//
  for (i=0; i<4; i++)
  {
	IwaveMemPoke(base,0xAA);               // mark start of bank
	IwaveMemPoke(base+1L,0x55);            
	if ((IwaveMemPeek(base)==0xAA)&&(IwaveMemPeek(base+1L)==0x55))
		  ram=TRUE;
	if (ram)
	 {
		while(cnt<BANK_MAX)
		{
		 bank[i]+=RAM_STEP;
		 cnt+=RAM_STEP;
		 addr=base+cnt;
		 if(IwaveMemPeek(addr)==0xAA) break;
		}
	 }
    if (lpbanks!=NULL)
     {
	   *lpbanks=bank[i];
	   lpbanks++;
     }
	 bank[i]=bank[i]>>10;
	 base+=BANK_MAX;
	 cnt=0L;
	 ram=FALSE;
  }
//
 iw.flags&=~DRAM_HOLES;
 _poke(iw.igidxr,_LMCFI);
 if (bank[0]==256&&bank[1]==0&&bank[2]==0&&bank[3]==0)
	  _pokew(iw.i16dp,lmcfi);
 else
  if (bank[0]==256&&bank[1]==256&&bank[2]==0&&bank[3]==0)
	  _pokew(iw.i16dp,lmcfi|0x01);
  else
	if (bank[0]==256&&bank[1]==256&&bank[2]==256&&bank[3]==256)
		 _pokew(iw.i16dp,lmcfi|0x02);
	else
	 if (bank[0]==256&&bank[1]==1024&&bank[2]==0&&bank[3]==0)
		  _pokew(iw.i16dp,lmcfi|0x03);
	 else
	  if (bank[0]==256&&bank[1]==1024&&bank[2]==1024&&bank[3]==1024)
			_pokew(iw.i16dp,lmcfi|0x04);
	  else
		if (bank[0]==256&&bank[1]==256&&bank[2]==1024&&bank[3]==0)
			 _pokew(iw.i16dp,lmcfi|0x05);
		else
		 if (bank[0]==256&&bank[1]==256&&bank[2]==1024&&bank[3]==1024)
			  _pokew(iw.i16dp,lmcfi|0x06);
		 else
		  if (bank[0]==1024&&bank[1]==0&&bank[2]==0&&bank[3]==0)
				_pokew(iw.i16dp,lmcfi|0x07);
		  else
			if (bank[0]==1024&&bank[1]==1024&&bank[2]==0&&bank[3]==0)
				 _pokew(iw.i16dp,lmcfi|0x08);
			else
			 if (bank[0]==1024&&bank[1]==1024&&bank[2]==1024&&bank[3]==1024)
				  _pokew(iw.i16dp,lmcfi|0x09);
			 else
			  if (bank[0]==4096&&bank[1]==0&&bank[2]==0&&bank[3]==0)
					_pokew(iw.i16dp,lmcfi|0x0A);
			  else
				if (bank[0]==4096&&bank[1]==4096&&bank[2]==0&&bank[3]==0)
					_pokew(iw.i16dp,lmcfi|0x0B);
				else                     // Flag the non-contiguous config of memory
					iw.flags|=DRAM_HOLES;
//
 _poke(iw.igidxr,0x19);              // restore sgmi
 _poke(iw.i8dp,reg);
  LEAVE_CRITICAL;
}
//########################################################################
//
//  FUNCTION: IwavePokeBlock
//
//  PROFILE : This function can be used to write entire blocks of data
//            to local memory. It starts by enabling the auto-increment
//            feature of the InterWave whereby each write will cause
//            the local memory address to be incremented appropriately.
//
//            This function will transfer the data to local memory by
//            8-bit accesses via LMBDR.
//
//########################################################################
void
IwavePokeBlock(BYTE  far *block,       /* pointer to data block */
					DWORD len,              /* length of block */
               ADDRESS addr)           /* local-memory base address */
    
{
  BYTE lmci;
  DWORD i;


//###################################################
//  Set up LM address counter
//###################################################
  ENTER_CRITICAL;
  _poke(iw.igidxr,_LMALI);                    /* select LMALI */
  _pokew(iw.i16dp,(WORD)addr);                /* Lower 16 bits of addr. */
  _poke(iw.igidxr,_LMAHI);                    /* select LMAHI */
  _poke(iw.i8dp,(BYTE)(addr>>16));

  _poke(iw.igidxr,_LMCI);                       /* select LMCI */
  lmci = _peek(iw.i8dp);
  _poke(iw.i8dp,(BYTE)((lmci|AUTOI)&DRAM_IO));  /* set LMCI */
 
  for (i=1L; i<=len; i++)                       /* Poke block in */
       _poke(iw.lmbdr,*block++);

  _poke(iw.i8dp,lmci);                           /* restore LMCI */
  LEAVE_CRITICAL;
}
//########################################################################
//
//  FUNCTION: IwavePokeBlockW
//
//  PROFILE : This function can be used to write entire blocks of data
//            to local memory. It starts by enabling the auto-increment
//            feature of the InterWave IC whereby each write will cause
//            the local memory address to be incremented appropriately.
//
//            Data will be placed in memory in 16-bit accesses via the
//            LMSBAI register.
//
//########################################################################
void
IwavePokeBlockW(WORD  far *block,       /* pointer to data block */
					 DWORD len,              /* length of block */
                ADDRESS addr)           /* local-memory base address */
      
{
  BYTE lmci;
  DWORD i;

  ENTER_CRITICAL;
  _poke(iw.igidxr,_LMCI);                      /* select LMCI */
  lmci = _peek(iw.i8dp);
  _poke(iw.i8dp,(BYTE)((lmci|AUTOI)&DRAM_IO)); /* set LMCI */

//############################################
// Set up LM Address Counter
//############################################

  _poke(iw.igidxr,_LMALI);          /* select LMALI */
  _pokew(iw.i16dp,(WORD)addr);      /* Lower 16 bits of addr. */
  _poke(iw.igidxr,_LMAHI);          /* select LMAHI */
  _poke(iw.i8dp,(BYTE)(addr>>16));

  _poke(iw.igidxr,0x51);            /* select LMSBAI */
  
  for (i=1L; i<=len; i++)				/* Poke block in */
       _pokew(iw.i16dp,*block++);

  _poke(iw.igidxr,_LMCI);           /* select LMCI */
  _poke(iw.i8dp,lmci);              /* restore LMCI */
  LEAVE_CRITICAL;
}
//########################################################################
//
//  FUNCTION: IwavePeekBlock
//
//  PROFILE : This function can be used to read entire blocks of data
//            from local memory. It starts by enabling the auto-increment
//            feature of the InterWave whereby each write will cause
//            the local memory address to be incremented appropriately.
//
//            This function transfers the data by 8-bit accesses via the
//            LMBDR register.
//
//########################################################################
void
IwavePeekBlock(BYTE  far *block,   /* pointer to data block */
					DWORD len,          /* length of block */
					ADDRESS addr)       /* local-memory base address */

{
  BYTE lmci;
  DWORD i;

  ENTER_CRITICAL;

//################################################
//  Set up LM address counter
//################################################

  _poke(iw.igidxr,_LMALI);            /* select LMALI */
  _pokew(iw.i16dp,(WORD)addr);        /* Lower 16 bits of addr. */
  _poke(iw.igidxr,_LMAHI);            /* select LMAHI */
  _poke(iw.i8dp,(BYTE)(addr>>16));

  _poke(iw.igidxr,_LMCI);              /* select LMCI */
  lmci = _peek(iw.i8dp);
  _poke(iw.i8dp,(BYTE)((lmci|AUTOI)&DRAM_IO)); 

  for (i=1L; i<=len; i++)               /* Peek block */
		 *block++=_peek(iw.lmbdr);

  _poke(iw.i8dp,lmci);                 /* restore LMCI */
  LEAVE_CRITICAL;
}
//########################################################################
//
//  FUNCTION: IwavePeekBlockW
//
//  PROFILE : This function can be used to read entire blocks of data
//            from local memory. It starts by enabling the auto-increment
//            feature of the InterWave whereby each write will cause
//            the local memory address to be incremented appropriately.
//
//            This function transfers the data by 16-bit access via the
//            LMSBAI register.
//
//########################################################################
void
IwavePeekBlockW(WORD  far *block,   /* pointer to data block */
                DWORD len,          /* length of block */
                ADDRESS addr)       /* local-memory base address */

{
  BYTE lmci;
  DWORD i;

  ENTER_CRITICAL;
  _poke(iw.igidxr,_LMCI);                     /* select LMCI */
  lmci = _peek(iw.i8dp);
  _poke(iw.i8dp,(BYTE)((lmci|AUTOI)&DRAM_IO)); /* set LMCI */

//#############################################
//  Set up Address Counter
//#############################################

  _poke(iw.igidxr,_LMALI);            /* select LMALI */
  _pokew(iw.i16dp,(WORD)addr);        /* Lower 16 bits of addr. */
  _poke(iw.igidxr,_LMAHI);            /* select LMAHI */
  _poke(iw.i8dp,(BYTE)(addr>>16));

  _poke(iw.igidxr,0x51);              /* Select LMSBAI */
  for (i=1L; i<=len; i++)             /* Peek block */
	    *block++=_peekw(iw.i16dp);

  _poke(iw.igidxr,_LMCI);             /* select LMCI */
  _poke(iw.i8dp,lmci);                /* restore LMCI */
  LEAVE_CRITICAL;
}
//########################################################################
//   FUNCTION : IwaveMemPoke
//
//   PROFILE  : This function writes a byte of data to local memory (LM)
//              in an expansion card containing the InterWave IC.
//########################################################################
void IwaveMemPoke(ADDRESS addr, BYTE datum)
{
 PORT p3xr;
 p3xr=iw.p3xr;

#if defined(__WATCOMC__) || defined(__BC32__) || defined(__HIGHC__)
	 _poke(iw.igidxr,0x43);             /* Select LMALI */
	 _pokew(iw.i16dp,(WORD)addr);       /* Lower 16 bits of LM */
	 _poke(iw.igidxr,0x44);             /* Select LMAHI */
	 _poke(iw.i8dp,(BYTE)(addr>>16));   /* Upper 8 bits of LM */
	 _poke(iw.lmbdr,datum);             /* Write byte to LMBDR */
#else
#ifdef __SC__
	 asm {
		  pushf               ; /* Save flags */
		  cli                 ; /* No interrupts - Critical work */
		  push EBX
		  push ES             ;
#ifdef __SC_PROTECT__
        mov EBX,[addr]      ; /* EBX contains the LM address */
#else
		  les BX,[addr]       ; /* ES:BX contains the LM address */
#endif
		  mov DX,p3xr         ; /* Load P3XR address in DX */
		  add DX,03h          ; /* DX = P3XR+3 (IGIDXR) */
		  mov AL,43h          ;
		  out DX,AL           ; /* Select LMALI (IGDIXR=0x43) */
		  mov AX,BX           ; /* Load 16 lower bits of LM location */
		  inc DX              ; /* DX = P3XR+4 (LMALI) */
		  out DX,AX           ; /* Set lower 16 bits of LM Address */
		  dec DX              ; /* DX = P3XR+3 (IGIDXR) again */
		  mov AL,44h          ;
		  out DX,AL           ; /* Select LMAHI (IGIDXR=0x44) */
#ifdef __SC_PROTECT__
		  shr EBX,16
		  mov AX,BX
#else
		  mov AX,ES           ; /* Load upper bits of address */
#endif
		  inc DX              ;
		  inc DX              ; /* DX = P3XR+5 (LMAHI) */
		  out DX,AL           ; /* Set upper 8-bits */
		  inc DX              ;
		  inc DX              ; /* DX = P3XR+7 (LMBDR) */
		  mov AL,datum        ; /* Load data to be sent */
		  out DX,AL           ; /* Write data byte to LMBDR */
		  pop ES              ;
		  pop EBX
		  popf                ; /* Restore flags */
		  }
#else
	 asm {
		  pushf               ; /* Save flags */
		  cli                 ; /* No interrupts - Critical work */
		  push ES             ;
		  les BX,[addr]       ; /* ES:BX contains the LM place to write to */
		  mov DX,p3xr         ; /* Load P3XR address in DX */
		  add DX,03h          ; /* DX = P3XR+3 (IGIDXR) */
		  mov AL,43h          ;
		  out DX,AL           ; /* Select LMALI (IGDIXR=0x43) */
		  mov AX,BX           ; /* Load 16 lower bits of LM location */
		  inc DX              ; /* DX = P3XR+4 (LMALI) */
		  out DX,AX           ; /* Set lower 16 bits of LM Address */
		  dec DX              ; /* DX = P3XR+3 (IGIDXR) again */
		  mov AL,44h          ;
		  out DX,AL           ; /* Select LMAHI (IGIDXR=0x44) */
		  mov AX,ES           ; /* Load upper bits of address */
		  inc DX              ;
		  inc DX              ; /* DX = P3XR+5 (LMAHI) */
		  out DX,AL           ; /* Set upper 8-bits */
		  inc DX              ;
		  inc DX              ; /* DX = P3XR+7 (LMBDR) */
		  mov AL,datum        ; /* Load data to be sent */
		  out DX,AL           ; /* Write data byte to LMBDR */
		  pop ES              ;
		  popf                ; /* Restore flags */
		  }
#endif
#endif
}
//########################################################################
//
//   FUNCTION : IwaveMemPokeW
//
//   PROFILE  : This function writes a word of data to local memory in a
//              card containing the InterWave IC.
//########################################################################
void IwaveMemPokeW(ADDRESS addr, WORD data)
{
 PORT p3xr;

 p3xr=iw.p3xr;

#if defined(__WATCOMC__) || defined(__BC32__) || defined(__HIGHC__)
	 _poke(iw.igidxr,0x43);                /* Select LMALI */
	 _pokew(iw.i16dp,(WORD)addr);          /* Lower 16 bits of LM */
	 _poke(iw.igidxr,0x44);                /* Select LMAHI */
	 _poke(iw.i8dp,(BYTE)(addr>>16));      /* Upper 8 bits of LM */
	 _poke(iw.igidxr,0x51);                /* Select LMSBAI */
	 _pokew(iw.i16dp,data);                /* Write word to LMSBAI */
#else
#ifdef __SC__
	 asm
      {
		  pushf               ; /* Save flags */
        cli                 ; /* No interrupts - Critical work */
		  push EBX
		  push ES
#ifdef __SC_PROTECT__
		  mov EBX,[addr]
#else
		  les BX,[addr]       ; /* ES:BX contains the LM address */
#endif
        mov DX,p3xr         ; /* Load P3XR address in DX */
        add DX,03h          ; /* DX = P3XR+3 (IGIDXR) */
        mov AL,43h          ;
        out DX,AL           ; /* Select LMALI (IGDIXR=0x43) */
        inc DX              ; /* DX = P3XR+4 (LMALI) */
        mov AX,BX           ; /* Load 16 lower bits of LM location */            
        out DX,AX           ; /* Set lower 16 bits of LM Address  */              
        dec DX              ; /* DX = P3XR+3 (IGDXR) again */
        mov AL,44h          ;
		  out DX,AL           ; /* Select LMAHI (IGIDXR=0x44) */
#ifdef __SC_PROTECT__
		  shr EBX,16
		  mov AX,BX
#else
		  mov AX,ES           ; /* Load upper bits of LM address */
#endif
		  inc DX              ;
        inc DX              ; /* DX = P3XR+5 (LMAHI) */
        out DX,AL           ; /* Set upper 8-bits */
        dec DX              ;
        dec DX              ; /* DX = P3XR+3 (IGIDXR) */
        mov AL,51h          ;
		  out DX,AL           ; /* Select LMSBAI (16-bit Data Reg.) */
		  inc DX              ; /* DX = P3XR+4 (LMSBAI) */
        mov AX,data         ; /* Load data to be sent */
        out DX,AX           ; /* Write data word to LMSBAI */
        pop ES					 ;
        pop EBX				 ;
        popf                ; /* Restore flags */
		}
#else
	 asm
      {
		  pushf               ; /* Save flags */
        cli                 ; /* No interrupts - Critical work */
        push ES				 ;
        les BX,[addr]       ; /* ES:BX contains the LM place to write to */
        mov DX,p3xr         ; /* Load P3XR address in DX */
        add DX,03h          ; /* DX = P3XR+3 (IGIDXR) */
        mov AL,43h          ;
        out DX,AL           ; /* Select LMALI (IGDIXR=0x43) */
        inc DX              ; /* DX = P3XR+4 (LMALI) */
        mov AX,BX           ; /* Load 16 lower bits of LM location */            
        out DX,AX           ; /* Set lower 16 bits of LM Address  */              
        dec DX              ; /* DX = P3XR+3 (IGDXR) again */
        mov AL,44h          ;
        out DX,AL           ; /* Select LMAHI (IGIDXR=0x44) */
        mov AX,ES           ; /* Load upper bits of address */
        inc DX					 ;
        inc DX              ; /* DX = P3XR+5 (LMAHI) */
        out DX,AL           ; /* Set upper 8-bits */
        dec DX					 ;
        dec DX              ; /* DX = P3XR+3 (IGIDXR) */
        mov AL,51h          ;
		  out DX,AL           ; /* Select LMSBAI (16-bit Data Reg.) */
		  inc DX              ; /* DX = P3XR+4 (LMSBAI) */
        mov AX,data         ; /* Load data to be sent */
        out DX,AX           ; /* Write data word to LMSBAI */
        pop ES					 ;
        popf                ; /* Restore flags */
       }
#endif
#endif
}
//########################################################################
//
//   FUNCTION : IwaveMemPeek
//
//   PROFILE  : This function reads a byte of data from local memory in a
//              card containing the InterWave IC. It does so via LMBDR and
//              the user must specify a local memery address to read from
//              via argument "addr".
//
//########################################################################
BYTE IwaveMemPeek(ADDRESS addr)
{
 PORT p3xr;

 p3xr=iw.p3xr;

#if defined(__WATCOMC__) || defined(__HIGHC__) || defined(__BC32__)
    _poke(iw.igidxr,0x43);             /* Select LMALI */
    _pokew(iw.i16dp,(WORD)addr);       /* Lower 16 bits of LM */
    _poke(iw.igidxr,0x44);             /* Select LMAHI */
    _poke(iw.i8dp,(BYTE)(addr>>16));   /* Upper 8 bits of LM */
    return(_peek(iw.lmbdr));           /* return byte from LMBDR */
#else
#ifdef __SC__
    asm{
        pushf               ; /* Save flags */
        cli                 ; /* No interrupts - Critical work */
		  push EBX
		  push ES
#ifdef __SC_PROTECT__
		  mov EBX,[addr]
#else
		  les BX,[addr]       ; /* ES:BX contains the LM place to read from */
#endif
		  mov DX,p3xr         ; /* Load P3XR address in DX */
        add DX,03h          ; /* DX = P3XR+3 (IGIDXR) */
        mov AL,43h          ;
        out DX,AL           ; /* Select LMALI (IGDIXR=0x43) */
        mov AX,BX           ; /* Load 16 lower bits of LM location */
        inc DX              ; /* DX = P3XR+4 (LMALI) */
        out DX,AX           ; /* Set lower 16 bits of LM address */
        dec DX              ; /* DX = P3XR+3 (IGDXR) */
        mov AL,44h          ;
        out DX,AL           ; /* Select LMAHI (IGIDXR=0x44) */
        inc DX              ;
		  inc DX              ; /* DX = P3XR+5 (LMAHI) */
#ifdef __SC_PROTECT__
		  shr EBX,16			 ;
		  mov AX,BX				 ;
#else
		  mov AX,ES           ; /* Load upper bits of LM address */
#endif
        out DX,AL           ; /* Set upper 8-bits */
        inc DX					 ;
        inc DX              ; /* DX = P3XR+7 (LMBDR) */
        in  AL,DX           ; /* Read data byte from LMBDR into AL */
        pop ES					 ;
        pop EBX				 ;
        popf                ; /* Restore flags */
	 }
#else
    asm{
        pushf               ; /* Save flags */
        cli                 ; /* No interrupts - Critical work */
		  push ES				 ;
        les BX,[addr]       ; /* ES:BX contains the LM place to read from */
        mov DX,p3xr         ; /* Load P3XR address in DX */
        add DX,03h          ; /* DX = P3XR+3 (IGIDXR) */
        mov AL,43h          ;
        out DX,AL           ; /* Select LMALI (IGDIXR=0x43) */
        mov AX,BX           ; /* Load 16 lower bits of LM location */
        inc DX              ; /* DX = P3XR+4 (LMALI) */
        out DX,AX           ; /* Set lower 16 bits of LM address */
        dec DX              ; /* DX = P3XR+3 (IGDXR) */
        mov AL,44h          ;
        out DX,AL           ; /* Select LMAHI (IGIDXR=0x44) */
        inc DX					 ;
        inc DX              ; /* DX = P3XR+5 (LMAHI) */
        mov AX,ES           ; /* Load upper bits of LM address */
        out DX,AL           ; /* Set upper 8-bits */
        inc DX					 ;
        inc DX              ; /* DX = P3XR+7 (LMBDR) */
        in  AL,DX           ; /* Read data byte from LMBDR into AL */
        pop ES					 ;
        popf                ; /* Restore flags */
    }
#endif
#endif
}
//########################################################################
//
//   FUNCTION : IwaveMemPeekW
//
//   PROFILE  : This function reads a word of data from local memory (LM)
//              card containing the InterWave IC.
//
//########################################################################
WORD IwaveMemPeekW(ADDRESS addr)
{
 PORT p3xr;

 p3xr=iw.p3xr;

#if defined(__WATCOMC__) || defined(__HIGHC__) || defined(__BC32__)
    _poke(iw.igidxr,0x43);                /* Select LMALI */
    _pokew(iw.i16dp,(WORD)addr);          /* Lower 16 bits of LM */
	 _poke(iw.igidxr,0x44);                /* Select LMAHI */
	 _poke(iw.i8dp,(BYTE)(addr>>16));      /* Upper 8 bits of LM */
	 _poke(iw.igidxr,0x51);                /* Select LMSBAI */
	 return(_peekw(iw.i16dp));             /* Read word from LMSBAI */
#else
#ifdef __SC__
	 asm{
		  pushf               ; /* Save flags */
		  cli                 ; /* No interrupts - Critical work */
		  push EBX
		  push ES
#ifdef __SC_PROTECT__
		  mov EBX,[addr]
#else
		  les BX,[addr]       ; /* ES:BX contains the LM address */
#endif
		  mov DX,p3xr         ; /* Load P3XR address in DX */
		  add DX,03h          ; /* DX = P3XR+3 (IGIDXR) */
		  mov AL,43h
		  out DX,AL           ; /* Select LMALI (IGDIXR=0x43) */
		  mov AX,BX           ; /* Load 16 lower bits of LM location */
		  inc DX              ; /* DX = P3XR+4 (LMALI) */
		  out DX,AX           ; /* Set lower 16 bits of LM address */
		  dec DX              ; /* DX = P3XR+3 (IGDXR) */
		  mov AL,44h			 ;
		  out DX,AL           ; /* Select LMAHI (IGIDXR=0x44) */
		  inc DX              ;
		  inc DX              ; /* DX = P3XR+5 (LMAHI) */
#ifdef __SC_PROTECT__
		  shr EBX,16			 ;
		  mov AX,BX				 ;
#else
		  mov AX,ES           ; /* Load upper bits of LM address */
#endif
		  out DX,AL           ; /* Set upper 8-bits */
		  dec DX					 ;
		  dec DX              ; /* DX = P3XR+3 (IGIDXR) */
		  mov AL,51h			 ;
		  out DX,AL           ; /* Select LMSBDI (16-bit Data Reg.) */
		  inc DX              ; /* DX = P3XR+4 (LMSBDI) */
		  in  AX,DX           ; /* Read data word from LMSBDI */
		  pop ES					 ;
		  pop EBX				 ;
		  popf                ; /* Restore flags */
		}
#else
	 asm{
		  pushf               ; /* Save flags */
		  cli                 ; /* No interrupts - Critical work */
		  push ES				 ;
		  les BX,[addr]       ; /* ES:BX contains the LM place to write to */
		  mov DX,p3xr         ; /* Load P3XR address in DX */
		  add DX,03h          ; /* DX = P3XR+3 (IGIDXR) */
		  mov AL,43h			 ;
		  out DX,AL           ; /* Select LMALI (IGDIXR=0x43) */
		  mov AX,BX           ; /* Load 16 lower bits of LM location */
		  inc DX              ; /* DX = P3XR+4 (LMALI) */
		  out DX,AX           ; /* Set lower 16 bits of LM address */
		  dec DX              ; /* DX = P3XR+3 (IGDXR) */
		  mov AL,44h			 ;
		  out DX,AL           ; /* Select LMAHI (IGIDXR=0x44) */
		  inc DX					 ;
		  inc DX              ; /* DX = P3XR+5 (LMAHI) */
		  mov AX,ES           ; /* Load upper bits of LM address */
		  out DX,AL           ; /* Set upper 8-bits */
		  dec DX					 ;
		  dec DX              ; /* DX = P3XR+3 (IGIDXR) */
		  mov AL,51h			 ;
		  out DX,AL           ; /* Select LMSBDI (16-bit Data Reg.) */
		  inc DX              ; /* DX = P3XR+4 (LMSBDI) */
		  in  AX,DX           ; /* Read data word from LMSBDI */
		  pop ES					 ;
		  popf                ; /* Restore flags */
		}
#endif
#endif
}
//########################################################################
//
//  FUNCTION: IwaveMemSize
//
//  PROFILE: This function returns the number of Kbytes available as
//           local memory attached to the InterWave IC. The value returned
//           by this function reflects the actual amount of DRAM that can
//           be accessed based on the mode of operation of the InterWave.
//           This is determined by SGMI[ENH].
//
//########################################################################
WORD IwaveMemSize(void)
{
  BYTE datum = 0x55;
  ADDRESS local = 0L;
//
  _poke(iw.igidxr,_LMCI);
  _poke(iw.i8dp,_peek(iw.i8dp)&0xFD);   // DRAM I/O cycles selected
//
  while(TRUE)
  {
	 IwaveMemPoke(local,datum);
    IwaveMemPoke(local+1L,datum+1);
	 if (IwaveMemPeek(local)!=datum||IwaveMemPeek(local+1L)!=(datum+1)||IwaveMemPeek(0L)!=0x55)
		  break;
	 local+=RAM_STEP;
	 datum++;
  }
 return((WORD)(local>>10));
}
//########################################################################
//
//  FUNCTION: IwaveWriteLong
//
//  PROFILE: This function acts as an internal utility used by DDK function
//           in the LM management family to write addresses to LM. The
//           function is used when creting or modifying the LM headers that
//           go along with the free memory blocks in memory.
//
//  INPUT  : The arguments to this function are as follows:
//
//            local_addr - local memory address to write to
//            local_data - the data to be written (4 bytes)
//
//########################################################################
void IwaveWriteLong(ADDRESS local_addr, DWORD local_data)
{
        BYTE far *ptr;
        BYTE i;

        ptr = (BYTE far *)&local_data;

        for (i=0; i<4; i++)
             IwaveMemPoke(local_addr++,*ptr++);
}
//########################################################################
//
//  FUNCTION: IwaveReadLong
//
//  PROFILE : This function acts as an internal utility used by DDK functions
//            in the LM management family to read addresses from LM. The
//            function is used when reading the addresses in the LM headers
//            that are part of the free memory chain of blocks in memory.
//
//  INPUT   : The arguments to this function are as follows:
//
//            local_addr - local memory address to read from
//
//########################################################################
DWORD IwaveReadLong(ADDRESS local_addr)
{       
        DWORD long_data;
        BYTE far *ptr;
        BYTE i;

        ptr = (BYTE far *)&long_data;

        for (i=0; i<4; i++)
             *ptr++=IwaveMemPeek(local_addr++);

        return(long_data);
}
