/***************************************************************************
*	NAME:  IWADDR.C $Revision: 1.2 $
**	COPYRIGHT:
**	"Copyright (c) 1994,1995 by e-Tek Labs"
**
**       "This software is furnished under a license and may be used,
**       copied, or disclosed only in accordance with the terms of such
**       license and with the inclusion of the above copyright notice.
**       This software or any other copies thereof may not be provided or
**       otherwise made available to any other person. No title to and
**       ownership of the software is hereby transfered."
****************************************************************************
* $Log: iwaddr.c $
* Revision 1.2  1995/05/08 04:40:45  sdsmith
* Revision 1.1  1995/02/23 11:07:01  unknown
* Initial revision
***************************************************************************/

#include <dos.h>
#include "iw.h"
#include "iwl.h"
#include "globals.h"

#define	ADDR_HIGH(x) ((unsigned short)(((x)>>7)&0x7fffL))
#define	ADDR_LOW(x)  ((unsigned short)(((x)&0x7fL)<<9))
#define ADDR_UPPER(x) ((unsigned char)((x>>22)&3))
#define	FADDR_HIGH(x) ((unsigned short)(((x)>>11)&0x7fffL))
#define	FADDR_LOW(x)  ((unsigned short)(((x)&0x7ffL)<<5))
#define FADDR_UPPER(x) ((unsigned char)((x>>26)&3))

#ifdef _MSC_VER
#pragma optimize("",off)
#endif

/***************************************************************************

FUNCTION DEFINITION:
iwl_convert_to_16bit - convert a DRAM address for 16 bit data

DESCRIPTION:
iwl_convert_to_16bit shifts the least significant 22 bits of a physical
DRAM address for 16 bit data by shifting right by 1.  The new 22 bit
address is rejoined with the upper two bits to form the new address.

RETURNS: long - DRAM address for 16 bit data
*/
long 	iwl_convert_to_16bit( 
  long address ) /* DRAM address to convert */
{
	return(address>>1);
}

/***************************************************************************

FUNCTION DEFINITION:
iwl_make_physical_address - convert accumulator to physical address

DESCRIPTION:
iwl_make_physical_address converts the high and low voice acculumator
values to a 20 bit physical DRAM address.  If the data being played is
16 bit data, the conversion is performed.

RETURNS: long - physical address
*/
long	iwl_make_physical_address( 
  unsigned short low,  /* low accumulator address */
  unsigned short high, /* high accumulator address */
  unsigned short mode) /* address mode 16 or 8 bit */
{
	unsigned short	lower_16, upper_16;
	long	unsigned ret_address, bit_19_20;

	upper_16 = (high & 0x1fff) >> 9;
	lower_16 = ((high & 0x01ff) << 7) | ((low >> 9) & 0x007f);

	ret_address = ((unsigned long)upper_16<<16) + lower_16;
	if( mode & 0x01 ) {
		bit_19_20 = ret_address & 0xC0000;
		ret_address <<= 1;
		ret_address &= 0x3ffff;
		ret_address |= bit_19_20;
	}
	return( ret_address );
}

/***************************************************************************

FUNCTION DEFINITION:
iwl_set_addr_regs - set a pair of address registers for a voice.

DESCRIPTION:
iwl_set_addr_regs sets the address registers specified to the address
requested.

The address is first converted to the high and low portions.

The porth and portl parameters identify the address registers to be set.
They should be one of:
  SET_START_HIGH
  SET_START_LOW
  SET_END_HIGH
  SET_END_LOW
  SET_ACC_HIGH
  SET_ACC_LOW

RETURNS: void
*/
void iwl_set_addr_regs(
  int voice,          /* voice to set addresses */
  unsigned long addr, /* address to set */
  int portl,          /* low address register */
  int porth)          /* high address register */
{
    register unsigned short low, high;

    ENTER;
    high = ADDR_HIGH(addr);
    low = ADDR_LOW(addr);
    IWL_SET_PAGE(voice);
    IWL_OUT_W(porth, high);
    IWL_OUT_W(portl, low);
    if (portl == SET_ACC_LOW) {
	IWL_OUT_B(SET_UPPER_ADDR, ADDR_UPPER(addr));
    }
    LEAVE;
}


/***************************************************************************

FUNCTION DEFINITION:
iwl_set_addr_f_regs - set a pair of address registers for a voice.

DESCRIPTION:
iwl_set_addr_f_regs sets the address registers specified to the address
requested.  The supplied address is a 24 bit integer address and a 4 bit
fractional address.

The address is first converted to the high and low portions.

The porth and portl parameters identify the address registers to be set.
They should be one of:
  SET_START_HIGH
  SET_START_LOW
  SET_END_HIGH
  SET_END_LOW
  SET_ACC_HIGH
  SET_ACC_LOW

RETURNS: void
*/
void iwl_set_addr_f_regs(
  int voice,          /* voice to set addresses */
  unsigned long addr, /* address to set */
  int portl,          /* low address register */
  int porth)          /* high address register */
{
	register unsigned short low, high;

	ENTER;
	high = FADDR_HIGH(addr);
	low = FADDR_LOW(addr);
	IWL_SET_PAGE(voice);
	IWL_OUT_W(porth, high);
	IWL_OUT_W(portl, low);
	if (portl == SET_ACC_LOW) {
	    IWL_OUT_B(SET_UPPER_ADDR, FADDR_UPPER(addr));
	}
	LEAVE;
}
