/****************************************************************************
**
**  Name:  addr.c
**
**  Description:
**     Address server handles virtual, linear, and physical addresses.
**
** Copyright (C) 1994 Microtek International.  All rights reserved.
**
**  $Log:   S:/tbird/mt2_68k/addr/addr.c_v  $
** 
**    Rev 1.0   13 Feb 1997 08:38:56   gene
** Initial revision.
** 
**    Rev 1.11   20 Sep 1996 09:54:12   kevin
** addrConvAddresstoText[forReg] is able to handle string with up to 100 char
** 
**    Rev 1.10   27 May 1996 13:43:04   kevin
** got rid of redundancy
** 
**    Rev 1.9   24 May 1996 17:20:26   kevin
** added 302 case
** 
**    Rev 1.8   21 Mar 1996 17:17:58   kevin
** 
** fixed address string space problem
** 
**    Rev 1.7   12 Jan 1996 10:52:14   kevin
** added 307 and 328 cases to getmaxaddressdigits
** 
**    Rev 1.6   20 Dec 1995 15:15:26   kevin
** if spaces are different, will not return equal.
** 
**    Rev 1.5   14 Dec 1995 09:24:06   kevin
** 
**    Rev 1.4   14 Dec 1995 09:18:46   kevin
** trivial bug
** 
**    Rev 1.3   14 Dec 1995 09:09:02   kevin
** not to convert register names to addresses
** 
**    Rev 1.2   01 Dec 1995 10:51:08   kevin
** joyce's modification
** 
**    Rev 1.1   24 Nov 1995 13:46:02   kevin
** support 68307 and 68328
** 
**    Rev 1.0   07 Sep 1995 09:57:08   gene
** Initial revision.
** 
**    Rev 1.57   05 May 1994 18:00:04   nghia
** Fixed GPF bug: input address text > 80 character long will overrun the
** local buffer.  - Any input text > 80 consider to be an invalid string.
** 
**    Rev 1.56   22 Apr 1994 15:22:08   marilyn
** Fixed bug in PointerDerefence routine.
** 
**    Rev 1.55   11 Apr 1994 09:53:54   marilyn
** Fixed bug in SetCurrentAddrSpace.
** 
**    Rev 1.54   08 Apr 1994 14:50:12   nghia
** Added AdrDoPhysicalRangesOverlap().
** Fixed bug in Ranges overlap checking : handles both a1 < a2 & a1 > a2 cases.
** 
**    Rev 1.53   06 Apr 1994 16:32:04   nghia
** Added AdrSetCurrentAddrSpace() to set the current address space for the
** input address descriptor. Revise the #define for A_D to be a type, so
** that type casting while debugging can be done.
** Removed some direct type cast to ADDR_DESCRIPTOR.
** Added AdrMaskAddrMSB() - Moved from Actor to server for portability.
** 
**    Rev 1.52   30 Mar 1994 11:33:30   john
** Added changes for 360
** 
**    Rev 1.51   30 Mar 1994 09:42:00   marilyn
** Modified AdrGetLdtSelector to never return a 0.
** 
**    Rev 1.50   28 Mar 1994 12:09:02   marilyn
** Added use of strtoulDefRadix so that address text always defaults to HEX.
** 
**    Rev 1.49   22 Mar 1994 10:30:36   marilyn
** Updated with final x86 addressing support.
** 
**    Rev 1.47   28 Feb 1994 17:07:18   marilyn
** Moved maxOutput routines to the address server from proc server. Updated
** interfaces.  Removed linear address dependencies and updated interfaces for 
** Intel processor support.  Not all Intel support is implemented yet.
** 
**    Rev 1.46   23 Sep 1993 10:49:40   nghia
** Filter out ER_NO_LINENUMS_ADDED to support address convertion for ASM module
** which does not have line number information.
** 
**    Rev 1.45   25 May 1993 11:49:50   ernie
** Streamlined AdrConvertPointerToAddress()
** 
**    Rev 1.44   23 Mar 1993 09:26:04   doug
** merged John's generic 340 change
** 
**    Rev 1.43.1.1   01 Mar 1993 13:13:24   john
** added subtract that does not check for underflow
** 
**    Rev 1.43.1.0   25 Feb 1993 16:09:38   john
** No change.
** 
**    Rev 1.43   18 Dec 1992 18:23:26   brucea
** Fixed up problems with output in AdrConvAddressToTextWithParams; refer
**    to header for description
** Removed: compiler warnings
** 
**    Rev 1.42   15 Dec 1992 13:01:34   ernie
** Converted from old MemRead call to new MemReadSized
** 
**    Rev 1.41   03 Dec 1992 07:31:02   brucea
** Modified AdrConvAddressToTextWithParams to output the function information
**    in parens after the #module#line#col+<offset> information.  This was done
**    so that the user would not confuse the output with the symbolic input
**    for a symbol.  The function offset is from the start of the function.
** Fixed bug in the above function to output the correct offset from the start
**    of the module.
** 
**    Rev 1.40   02 Dec 1992 15:19:26   doug
** MemRead returns the buffer even if there is an error; free memory
** 
**    Rev 1.39   15 Oct 1992 18:36:22   brucea
** Changed: calculation of maxOutputAddrCharWidth to call proc.dll directly
** Added: ANDing address offset before converting to text string in 
**    AdrConvAddressToText and ..WithParams.
**    sprintf puts out 8 digits if number big enough even
**    when specification is equivalent to %6.6lX
** 
**    Rev 1.38   16 Sep 1992 10:06:52   brucea
** Rearranged ADDR_DESCRIPTOR structure for better compaction and code generation
** 
**    Rev 1.37   03 Sep 1992 12:47:00   brucea
** Added: conditional code for generating invalid descriptor or UAEing
**    Conditional code enabled with #define ADR_UAE
** 
**    Rev 1.36   31 Aug 1992 09:19:14   brucea
** Added: AdrGetAllocCounts for debug purposes
** 
**    Rev 1.35   27 Aug 1992 14:50:52   doug
** add display of create/destroy (debug_addr on)
** 
**    Rev 1.34   27 Aug 1992 13:42:38   brucea
** Changed: Initialize an addr descriptor using L constants
** Fixed bug: AdrDoRangesOverlap - comparison return was NOT what it should have
**    been
** 
**    Rev 1.33   25 Aug 1992 10:48:34   brucea
** Added: AdrIsValidCodeAddress
** 
**    Rev 1.32   20 Aug 1992 20:26:38   brucea
** Fixed: SymGetAddrFromName call parameter
** 
**    Rev 1.31   18 Aug 1992 18:12:54   brucea
** Added: AdrConvAddressToTextWithParams, AdrDoRangesOverlap
** 
**    Rev 1.30   14 Aug 1992 17:43:10   brucea
** Added: support for maxInputAddr and maxOutputAddr
** Added: support for the number of created and destroyed addresses with
**    debug_addr CLI command
** 
**    Rev 1.29   13 Aug 1992 19:29:02   brucea
** Changed: #if 1 to #if 0 to make the code load
** 
**    Rev 1.28   13 Aug 1992 11:38:56   brucea
** Added: test for desc == 0L in all functions that have one or more
** Removed compiler warnings
** 
**    Rev 1.27   10 Aug 1992 09:02:46   brucea
** Fixed: AdrIsAddrInRange - changed compare to > rather than >=
** 
**    Rev 1.26   28 Jul 1992 17:16:24   brucea
** Added: conditional compilation with SPACE_CHECKED #define'd or #undef'ined
**    to test for space field
** Vary number of output address characters based on maxAddrCharWidth
** Test for any input address for > maxAddr before setting address offset or
**    range
** Any ->space code is surrounded by check for the processor in FAMILY_68K
** Removed code that dealt with logical/physical addresses
** 
**    Rev 1.25   27 Jul 1992 14:51:18   brucea
** Added: maxAddrCharWidth calculation
**        SPACE_DONT_CARE, only output number of chars of largest address
** 
** 
**    Rev 1.24   23 Jul 1992 09:32:58   brucea
** Added: checks for exceeding maximum address
** Added: if (FAMILY_68K == procFamily) around all uses of Moto SPACE,
**    address mode field, and functions not available for Moto uPs.
** Added: error ER_ADR_RESULT_UNDERFLOW
** 
**    Rev 1.23   19 Jul 1992 22:16:10   brucea
** Added: #include "proc.h" for processor independence
** Moved: ADDR_DESCRIPTOR into .c file and out of .h
** Removed: processor-specific definitions and functions.  Now call proc
**    routines.
** Modified: AdrInitAddressServer to get the info from proc routines.
** Modified: functions which declared a local variable in order to cast
**    were removed and access via descriptor done thru (A_D) macro cast
** Implemented: AdrConvAddressToTextNoFill to convert address to symbol name
**    if symbolUsage == ON
** Removed: code which deals with logical-to-physical address translation
** 
** 
**    Rev 1.22   10 Jul 1992 19:38:16   brucea
** Added: Removal of leading "spaces" in AdrConvTextToAddress, removed #if 0
** Added: set rangeActive TRUE in AdrSetEndAddrOffset and AdrSetAddrRangeLength
** 
** 
**    Rev 1.21   16 Jun 1992 14:19:50   brucea
** Switched back to calling the symbol server function (a change was made
** in Actor to load the symbol server before the address server).
** 
**    Rev 1.20   15 Jun 1992 11:49:20   brucea
** Removed: call to symbol table; won't load
** 
**    Rev 1.19   15 Jun 1992 09:38:24   brucea
** Switched on call to SymGetAddrFromName in AdrConvTextToAddress; requires
**    change in DLL load order in Actor code
** 
**    Rev 1.18   09 Jun 1992 09:21:12   brucea
** Fixed: AdrRangeOfAddresses so the range returned is an absolute value (before
**    the change, it returned an error)
** 
**    Rev 1.17   15 May 1992 15:54:24   brucea
** Removed: include of addr030.h
**          addr030.h, .c are no longer used.
** Copied: all code from addr030 that was called by addr.c into addr.c.  Most
**    was in-lined because they were only called in one place.
** Removed: code which dealt with logical-to-physical (and visa-versa)
**    translation
** 
**    Rev 1.16   11 May 1992 11:23:38   brucea
** Temporary fix: put #if 0 around call to SymGetAddrFromName in function
**    AdrConvTextToAddress because it causes the product to fail to load (UAEs
**    inexplicibly).  This should be removed and tested each release to see if
**    the load problem has been somewhere, somehow fixed.
** Added: AdrCopyAddress function
** 
** 
**    Rev 1.15   20 Apr 1992 11:31:28   brucea
** Modified: AdrConvTextToAddress to call SymGetAddrFromName if entry is
**    symbolic (starts with #).  Ignores symbolUsage flag.
** 
**    Rev 1.14   26 Mar 1992 18:03:10   brucea
** Changed: AdrConvAddressToText and ...NoFill to output 0x in front of hex value
** 
**    Rev 1.13   19 Mar 1992 16:46:12   brucea
** Added: function AdrIsAddrInRange
** 
**    Rev 1.12   05 Mar 1992 18:02:08   doug
** need storage for number of bytes
** 
**    Rev 1.11   02 Mar 1992 13:51:08   brucea
** Added: #include <stdlib.h> and <string.h> to fix return error from strtoul
** Fixed: in AdrConvertAddress, added casting of DESCRIPTORs for memcpy params
** 
**    Rev 1.10   28 Feb 1992 15:25:56   brucea
** Fixed: access to MemRead which requires TFree'ing the buffer passed to it
** 
**    Rev 1.9   27 Feb 1992 22:16:18   brucea
** Added: initialization of endianType
** Removed: parameter to AdrInitAddressServer
** Changed: init of symbolUsage to FALSE
** Added: AdrGetAddressToTextLength, AdrConvAddressToTextNoFill,
**        AdrConvertToPhysical, AdrGetEndianType, AdrGetMaxAddress
** Modified: AdrConvertSameAddress, AdrDuplicateAddress
** 
**    Rev 1.8   17 Feb 1992 16:30:42   brucea
** Modified: set default logicalEqualsPhysical flag to TRUE
** Fixed: AdrConvAddressToText and AdrConvTextToAddress for the non-symbolic case
** Fixed: AdrRemainingBytes to return a value of 0 to represent 2^32
** Defined: MAX_ADDR
** 
**    Rev 1.7   30 Jan 1992 18:45:16   brucea
** Added #include for addr030.h and removed local definitions
** Added #include for tbirdmem.h, used for MemRead function
** Made module-level variables PRIVATE
** Added variable and routines (AdrGetLogicalEqualsPhysicalFlag and
**    AdrSetLogicalEqualsPhysicalFlag) to set and get <logicalEqualsPhysical>.
** It is tested before calling AddrAddrToPhysical to save execution time
** Added error return for TFree call.
** Cleaned up AdrSetAddrMode, AdrAddToAddress, AdrSubFromAddr
** Added local var to provide lower functions a near pointer call rather
**   than a far call required by the Adr interface; e.g. AdrRangeOfAddresses
** Changed AdrConvertPointerToAddress to AdrGetPointerFromAddress and
**   implemented it.  It calls MemRead to get the value of the pointer and
**   also AddrConvertEndian to form it into the correct "endian" for the host.
** 
**    Rev 1.6   25 Jan 1992 16:50:44   brucea
** Bug fixes
** 
**    Rev 1.5   25 Jan 1992 16:07:34   brucea
** Added addrerrs.h include and moved all the local errors into it
** Added new call: AdrCreateAddressWithType
** Modified: AdrSetAddrType to simply store the passed type in type field
** Renamed the old AdrSetAddrType to AdrConvertSameAddress
** Removed code which called symbol server; needs a new call interface
** Fixed AdrConvertAddress to first clone first address to second, then
**   it does the address translation
**
** 
**    Rev 1.4   24 Jan 1992 16:57:56   brucea
** Modifying AdrCreateAddress to initialize to ADDR_LOGICAL, set symbol
** usage to TRUE (as per addr.h spec)
** Installed (from Doug version of addr.c) AdrDuplicateAddress and
** AdrGetPointerFromAddress.  AdrGetPointerFromAddress is not implemented.
** 
**    Rev 1.3   24 Jan 1992 10:50:44   doug
** Fixed bug where handle was being put back into pointer and causing DLL
** to bomb.  Converting to TMalloc/TFree as part of fix to match the dummy
** address server (latest) by using the commented code.
** 
**    Rev 1.2   21 Jan 1992 13:13:20   doug
** removed EXPORT where not needed
** 
**    Rev 1.1   14 Jan 1992 12:05:00   tom
** New revision from Hsinchu.
** 
**  $Header:   S:/tbird/mt2_68k/addr/addr.c_v   1.0   13 Feb 1997 08:38:56   gene  $
**
*****************************************************************************/

		       /****************************
			*                          *
			*       INCLUDE FILES      *
			*                          *
			****************************/
#ifndef _ADDR_
#include "addr.h"
#endif

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef __CTYPE_H
#include <ctype.h>
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _PROC_
#include "proc.h"
#endif

#ifndef __STDLIB_H
#include <stdlib.h>
#endif

#ifndef __STRING_H
#include <string.h>
#endif

#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif

#ifndef _TBIRDMEM_
#include "tbirdmem.h"
#endif

#ifndef _ENLIB_
#include "enlib.h"
#endif

#ifndef _EVENTS_
#include "events.h"
#endif

#ifndef _SSHARED_
#include "sshared.h"
#endif

#ifndef _SDNUM_
#include "sdnum.h"
#endif

#ifndef _CPU_
#include "cpu.h"
#endif

			/****************************
			 *                          *
			 *     LOCAL DEFINITIONS    *
			 *                          *
			 ****************************/

#undef ADR_UAE

#ifdef __cplusplus
extern "C" {
#endif

#undef max
#define max(a,b)   (((a) > (b)) ? (a) : (b))

typedef struct {
   U32 addrOffset;
   U32 rangeLength; /* number of bytes in range, if range active */
   U32 ldt;
   U32 addrSegSel;
   ADDR_TYPE type;
   ADDR_MODE mode;
   ADDR_SPACE space;
   ADDR_SEGSEL_TYPE segSelType;
   BOOLEAN rangeActive;
   BOOLEAN symbolUsage;
} ADDR_DESCRIPTOR;


typedef struct {
   unsigned limit15_0:16;
   unsigned base15_0:16;
   unsigned base23_16:8,
	    segmentType:4,
	    descType:1,
	    descPrivLevel:2,
	    segmentPresent:1;
   unsigned limit19_16:4,
	    dummy:2,
	    opSize:1,
	    granularity:1,
	    base31_24:8;
} SEGMENT_DESCRIPTOR;

typedef struct {
   ADDR_SPACE space;
   LPSTR      spaceStr;
} ADDR_SPACE_ENTRY;

/* Used for casting opaque input DESCRIPTOR to pointer to an address struct.*/
/* Put parentheses around A_D when using. */
/* Use typedef to force compiler generate A_D type for typecast debugging */
typedef ADDR_DESCRIPTOR* A_D;

#pragma warn -use
PRIVATE A_D forceCompilerGenerateType = NULL;


#define GDT_INDICATOR 0x0000
#define LDT_INDICATOR 0x0004
#define TABLE_INDICATOR_MASK 0x0004
#define TABLE_INDEX_MASK 0xFFF8
#define CODE_OR_DATA_SEGMENT 1
#define SYSTEM_SEGMENT 0
#define EXPAND_DN_SEG_MASK 0x000C
#define EXPAND_DN_SEG 0x0004
#define PAGE_PRESENT_MASK 0x0001


/* Any changes to the space strings must also include corresponding
** changes to the space mapping arrays 
*/
#define MAX_MOTO32_SPACES 5
const CHAR motoCpu32SpaceStr[MAX_MOTO32_SPACES*5] = "UP\0UD\0SP\0SD\0CPU\0";
ADDR_SPACE_ENTRY motoCpu32Spaces[MAX_MOTO32_SPACES] = {
{SPACE_UP, "UP"},
{SPACE_UD, "UD"},
{SPACE_SP, "SP"},
{SPACE_SD, "SD"},
{SPACE_CPU, "CPU"}};


#define MAX_MOTO16_SPACES 2
const CHAR motoCpu16SpaceStr[MAX_MOTO16_SPACES*10] = "data\0program\0";
ADDR_SPACE_ENTRY motoCpu16Spaces[MAX_MOTO16_SPACES] = {
{SPACE_SD, "data"},
{SPACE_SP, "program"}};

#define MAX_INTEL_SPACES 3
const CHAR intelSpaceStr[MAX_INTEL_SPACES*5] = "user\0smm\0io\0";
ADDR_SPACE_ENTRY intelSpaces[MAX_INTEL_SPACES] = {
{SPACE_USER, "user"},
{SPACE_SMM, "smm"},
{SPACE_IO, "io"}};


			/*****************************
			 *                           *
			 *     EXTERNAL VARIABLES    *
			 *                           *
			 *****************************/

extern HANDLE cliServerHandle;
extern HANDLE hLib;

			/****************************
			 *                          *
			 *     LOCAL VARIABLES      *
			 *                          *
			 ****************************/

/* Current processor mode */
PMODE pMode = PMODE_END;

/* phase 1 REAL mode only
** should key off of register changed events and check
** the CR0 register bit 31 for paging state
*/
BOOLEAN pagingOn = FALSE;

/* total number of address created/destroyed since the beginning of time */
U32 numAddrCreated;    
U32 numAddrDestroyed;
BOOLEAN addrDebug = FALSE;

PROCESSOR_FAMILY procFamily;

PRIVATE ENDIAN_TYPE endianType;
PRIVATE PROC_CPU    cpu;
PRIVATE REG_ID      LDTBaseId;
PRIVATE REG_ID      GDTBaseId;
PRIVATE REG_ID      CR3regId;
PRIVATE REG_ID      LDTLimitId;
PRIVATE REG_ID      GDTLimitId;
PRIVATE REG_ID      CSregId;
PRIVATE REG_ID      SSregId;
PRIVATE REG_ID      DSregId;

/* used to AND with addr to check lower bits for valid instruction boundary */
PRIVATE U32 staticMask;
PRIVATE U16 staticBytesPerInstr;

U16 defaultRadix = 16;      /*  All address text defaults to HEX */

			 /***************************
			 *                          *
			 *    FUNCTION PROTOTYPES   *
			 *                          *
			 ****************************/

RETCODE SendMessageToCli(S8 FAR *msgPtr, HANDLE cliHandle);
RETCODE PRIVATE GetSegmentDescCopy(DESCRIPTOR desc,
				  SEGMENT_DESCRIPTOR *segDesc);
RETCODE PRIVATE GetSegSelFromText(LPSTR segSelStr, U32 *segment);
RETCODE PRIVATE GetSegmentBase(DESCRIPTOR desc,U32 *base);
RETCODE PRIVATE GetSegmentLimits(DESCRIPTOR desc,U32 *minLimit,
				U32 *maxLimit);
RETCODE PRIVATE RealToLinear(DESCRIPTOR desc, U32 *linearAddr);
RETCODE PRIVATE ProtToLinear(DESCRIPTOR desc, U32 *linearAddr);
RETCODE PRIVATE LinearToPhysical(U32 linearAddr, U32 *physAddr);
RETCODE PRIVATE AddrToPhysical(DESCRIPTOR desc, U32 *physAddr);
RETCODE PRIVATE AddrToLinear(DESCRIPTOR desc, U32 *linearAddr);
PMODE PRIVATE GetPmode(ADDR_MODE addrMode);
U32 PRIVATE strtoulDefRadix(const CHAR *s, CHAR **endPtr);
RETCODE PRIVATE GetSegment(DESCRIPTOR desc,U32 *segment);

			 /***************************
			 *                          *
			 *      EXECUTABLE CODE     *
			 *                          *
			 ****************************/


/*------------------------------------------------------------------------
** Address representation:
**
**    The end address of an address range always points to the last
**    byte; i.e. that byte is INCLUDED in the range.
**    Thus, the size of a range is:
**        end_addr - start_addr + 1
-------------------------------------------------------------------------*/
/*************************************************************************
**
** AdrInitAddressServer
**
** This routine calls functions in proc.h to get processor-dependent
** parameters
**
** NOTE: this routine sets the processor-specific parameters and thus
**       requires calls to PROC.DLL to get those params
**********************************************************************/
RETCODE EXPORT AdrInitAddressServer(VOID) {

   FARPROC adrCallback;
   U32 descEvt,i;
   RETCODE err, firstErr;
   
   numAddrCreated = 0L;
   numAddrDestroyed = 0L;

   firstErr = ProcReturnByteOrder(&endianType);

   err = ProcReturnProcFamily(&procFamily);
   if (GOOD == firstErr)
      firstErr = err;

   err = ProcReturnCpu(&cpu);
   if (GOOD == firstErr)
      firstErr = err;

   err = ProcReturnBytesPerInstr(&staticBytesPerInstr);
   if (GOOD == firstErr)
      firstErr = err;

   /* now set up mask to test lower address bits for illegal odd boundary */
   switch (staticBytesPerInstr) {
      case 1: staticMask = 0L;
	 break;

      case 2: staticMask = 1L;
	 break;

      case 3:   /* illegal */
      case 4: staticMask = 3L;

      default:
	 staticMask = 0L;
   }
   if (procFamily == FAMILY_X86) {
      /* register for callback at BKPT_HALTED to update pMode */
      adrCallback = MakeProcInstance((FARPROC)AdrCallback,hLib);
      err = EnlRegister(EVENT_BKPT_HALTED,(EVCALLBACK)adrCallback,
	    &descEvt);
      if (GOOD == firstErr)
	 firstErr = err;

      /* check to see status of paging */
      pagingOn = FALSE;     /* phase 1 REAL mode only */

      err = CpuFindRegisterId((LPU8)"LDTBASE",&LDTBaseId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"LDTLIMIT",&LDTLimitId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"GDTBASE",&GDTBaseId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"GDTLIMIT",&GDTLimitId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"CR3",&CR3regId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"CS",&CSregId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"SS",&SSregId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"DS",&DSregId);
      if (GOOD == firstErr)
	 firstErr = err;

   }
   return firstErr;
}

/**************************************************************************
**
**  AdrCreateAddress
**
***************************************************************************/
RETCODE EXPORT AdrCreateAddress(DESCRIPTOR FAR *desc) {
   S8 buff[80];

#define DESC ((ADDR_DESCRIPTOR *)*desc)

   if((*desc = (DESCRIPTOR)TMalloc(sizeof(ADDR_DESCRIPTOR)))==NULL)
      return ER_OUT_OF_MEMORY;

   numAddrCreated++;
   if(addrDebug) {
      wsprintf(buff, "...Creating address descriptor %ld", numAddrCreated);
      SendMessageToCli(buff, cliServerHandle);
   }

   switch (procFamily) {
      case FAMILY_68K:
	 DESC->type = ADDR_LINEAR;
	 DESC->mode = MODE_NONE;
	 DESC->space = SPACE_SD;
	 DESC->ldt = 0L;
	 DESC->symbolUsage = FALSE;
	 DESC->segSelType = ADDR_USE_VALUE;
	 DESC->addrSegSel = 0L;
	 DESC->addrOffset = 0L;
	 DESC->rangeActive = FALSE;
	 DESC->rangeLength = 0L;
	 break;
      case FAMILY_X86:
	 DESC->type = ADDR_VIRTUAL;
	 DESC->mode = MODE_CURRENT;
	 DESC->space = SPACE_USER;
	 DESC->ldt = 0L;
	 DESC->symbolUsage = FALSE;
	 DESC->segSelType = ADDR_USE_DS;
	 DESC->addrSegSel = 0L;
	 DESC->addrOffset = 0L;
	 DESC->rangeActive = FALSE;
	 DESC->rangeLength = 0L;
	 break;
      case FAMILY_UNKNOWN:
	 DESC->type = ADDR_LINEAR;
	 DESC->mode = MODE_NONE;
	 DESC->space = SPACE_DEFAULT;
	 DESC->ldt = 0L;
	 DESC->symbolUsage = FALSE;
	 DESC->segSelType = ADDR_USE_VALUE;
	 DESC->addrSegSel = 0L;
	 DESC->addrOffset = 0L;
	 DESC->rangeActive = FALSE;
	 DESC->rangeLength = 0L;
	 break;
   }
   return(GOOD);
}

/****************************************************************************
**
** AdrGetAllocCounts
**
*****************************************************************************/
RETCODE EXPORT
AdrGetAllocCounts(U32 FAR *lpAddrsCreated, U32 FAR *lpAddrsDestroyed)  {

   *lpAddrsCreated = numAddrCreated;
   *lpAddrsDestroyed = numAddrDestroyed;
   return GOOD;
}  /* end of AdrGetAllocCounts */

 /****************************************************************************
**
**  AdrCreateAddressWithType
**
*****************************************************************************/
RETCODE EXPORT
AdrCreateAddressWithType(ADDR_TYPE type, DESCRIPTOR FAR *desc)  {

   RETCODE err;
   
   if ((err = AdrCreateAddress(desc)) != GOOD)
      return err;
   ((A_D)desc)->type = type;
   return GOOD;
}

/****************************************************************************
**
**  AdrCreateAddressFromText
**
*****************************************************************************/
RETCODE EXPORT
AdrCreateAddressFromText(LPSTR string, LPSTR space, DESCRIPTOR FAR *desc) {

  RETCODE err;
  ADDR_SPACE addrSpace;
   
   if ((err = AdrCreateAddress(desc)) != GOOD)
      return err;
   if ((err = AdrConvTextToAddress(*desc,string)) != GOOD) {
      AdrDestroyAddress(*desc);
      return err;
   }
   if ((err = AdrTranslateSpace(space, &addrSpace)) != GOOD) {
      AdrDestroyAddress(*desc);
      return err;
   }
   if ((err = AdrSetAddrSpace(*desc,addrSpace)) != GOOD) {
      AdrDestroyAddress(*desc);
      return err;
   }
   return GOOD;

}

/****************************************************************************
**
**  AdrDestroyAddress
**
*****************************************************************************/
RETCODE EXPORT AdrDestroyAddress(DESCRIPTOR desc) {

   RETCODE err;
   S8 buff[80];

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif

   err = TFree((LPSTR)desc);
   if (GOOD != err)
      return err;
   numAddrDestroyed++;
   if(addrDebug) {
      wsprintf(buff, "...Destroying address descriptor %ld",numAddrDestroyed);
      SendMessageToCli(buff, cliServerHandle);
   }
   return GOOD;
}

/**************************************************************************
**
**  AdrReturnSpaces
**
***************************************************************************/
RETCODE EXPORT AdrReturnSpaces(LPSTR FAR *spaces,
			       U16 FAR *spaceCount, U16 *spaceLen) {
   LOOP_VAR i;

   *spaces = NULL;
   *spaceCount = 0;
   *spaceLen = 0;
   switch (cpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_68000:
      case PROC_CPU_68040:
	 *spaces = (LPSTR)motoCpu32SpaceStr;
	 *spaceCount = MAX_MOTO32_SPACES;
	 break;
      case PROC_CPU_CPU16:
	 *spaces = (LPSTR)motoCpu16SpaceStr;
	 *spaceCount = MAX_MOTO16_SPACES;
	 break;
      case PROC_CPU_80186:
	 break;
      case PROC_CPU_80386:
	 *spaces = (LPSTR)intelSpaceStr;
	 *spaceCount = MAX_INTEL_SPACES;
	 break;
      case PROC_CPU_80486:
	 break;
   }
   for (i=0;i<*spaceCount;i++)
      *spaceLen += strlen(*spaces+*spaceLen)+1;
   return GOOD;

}

/****************************************************************************
**
**  AdrSetAddrType
**
*****************************************************************************/
RETCODE EXPORT AdrSetAddrType(DESCRIPTOR desc, ADDR_TYPE type) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   ((A_D)desc)->type = type;
   return(GOOD);
}

/****************************************************************************
**
**  AdrGetAddrType
**
*****************************************************************************/
RETCODE EXPORT AdrGetAddrType(DESCRIPTOR desc, ADDR_TYPE FAR *type) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   *type = ((A_D)desc)->type;
   return(GOOD);
}

/****************************************************************************
**
**  AdrSetAddrMode
**
*****************************************************************************/
RETCODE EXPORT AdrSetAddrMode(DESCRIPTOR desc, ADDR_MODE mode) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (procFamily == FAMILY_68K) {
      if (MODE_NONE == mode) {
	 ((A_D)desc)->mode = mode;
	 return(GOOD);
      }
      else
	 return ER_ADR_MODE_INVALID;
   } else if (procFamily == FAMILY_X86) {
      if ((mode == MODE_CURRENT) || (mode == MODE_REAL) ||
	    (mode == MODE_PROT16) || (mode == MODE_PROT32) ||
	    (mode == MODE_V86) || (mode == MODE_SMM)) {
	 ((A_D)desc)->mode = mode;
	 return (GOOD);
      }
      else
	 return ER_ADR_MODE_INVALID;
   }
   else
      ((A_D)desc)->mode = mode;

   return GOOD;
}

/****************************************************************************
**
**  AdrGetAddrMode
**
*****************************************************************************/
RETCODE EXPORT AdrGetAddrMode(DESCRIPTOR desc, ADDR_MODE FAR *mode) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   *mode = ((A_D)desc)->mode;
   return(GOOD);
}

/****************************************************************************
**
**  AdrSetAddrSpace
**
*****************************************************************************/
RETCODE EXPORT AdrSetAddrSpace(DESCRIPTOR desc, ADDR_SPACE space) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (procFamily == FAMILY_68K) {
      if (space == SPACE_DEFAULT) {
	 ((A_D)desc)->space = SPACE_SD;
	 return GOOD;
      }
      else if ((space == SPACE_UD) || (space == SPACE_UP) ||
	    (space == SPACE_SD) || (space == SPACE_SP) ||
	    (space == SPACE_CPU) || (space == SPACE_DONT_CARE)) {
	 ((A_D)desc)->space = space;
	 return GOOD;
      }
      else
	 return ER_ADR_SPACE_INVALID;
   } else if (procFamily == FAMILY_X86) {
      /* Phase I: default to SPACE_USER
      ** Need to get the current PMODE to figure out the current SPACE 
      */
      if (space == SPACE_DEFAULT) {
	 ((A_D)desc)->space = SPACE_USER;
	 return GOOD;
      }
      else if ((space == SPACE_USER) || (space == SPACE_SMM) ||
	    (space == SPACE_IO)) {
	 ((A_D)desc)->space = space;
	 return GOOD;
      }
      else
	 return ER_ADR_SPACE_INVALID;
   }
   return GOOD;
}

/****************************************************************************
**
**  AdrGetAddrSpace
**
*****************************************************************************/
RETCODE EXPORT AdrGetAddrSpace(DESCRIPTOR desc, ADDR_SPACE FAR *space) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (((A_D)desc)->space == SPACE_DEFAULT) {
      if (procFamily == FAMILY_68K) 
	 *space = SPACE_SD;           
      else if (procFamily == FAMILY_X86)
	 *space = SPACE_USER;
   }
   *space = ((A_D)desc)->space;
   return(GOOD);
}


/****************************************************************************
**
** AdrSetCurrentAddrSpace
**
***************************************************************************/
RETCODE EXPORT AdrSetCurrentAddrSpace(DESCRIPTOR desc) {

   /* set the current address space for the input address descriptor */
   return AdrSetAddrSpace(desc, SPACE_DEFAULT);
}

/****************************************************************************
**
**  AdrGetLdtSelector
**
*****************************************************************************/
RETCODE EXPORT AdrGetLdtSelector(DESCRIPTOR desc, U32 FAR *ldt) {

   RETCODE err;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (FAMILY_68K == procFamily)
      return(ER_ADR_NOT_MOTOROLA_USAGE);
   else {
      if (((A_D)desc)->ldt == 0) {  /* use current LDTR */
	 if ((err = CpuGetRegister(LDTBaseId,ldt)) != GOOD)
	    return err;
	 if (ldt == 0)
	    return ER_ADR_LDT_INVALID;
      }
      else
	 *ldt = ((A_D)desc)->ldt;
   }
   return GOOD;
}

/****************************************************************************
**
**  AdrSetLdtSelector
**
*****************************************************************************/
RETCODE EXPORT AdrSetLdtSelector(DESCRIPTOR desc, U32 ldt) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (FAMILY_68K == procFamily)
      return(ER_ADR_NOT_MOTOROLA_USAGE);
   else
      ((A_D)desc)->ldt = ldt;
   return GOOD;
}

/****************************************************************************
**
**  AdrSetAddrSymbolUsage
**
*****************************************************************************/
RETCODE EXPORT AdrSetAddrSymbolUsage(DESCRIPTOR desc, BOOLEAN useSymbols) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   ((A_D)desc)->symbolUsage = useSymbols;
   return(GOOD);
}

/****************************************************************************
**
**  AdrGetAddrSymbolUsage
**
*****************************************************************************/
RETCODE EXPORT
AdrGetAddrSymbolUsage(DESCRIPTOR desc, BOOLEAN FAR *useSymbols) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   *useSymbols = ((A_D)desc)->symbolUsage;
   return(GOOD);
}

/****************************************************************************
**
**  AdrConvAddressToText 
**
*****************************************************************************/
RETCODE EXPORT AdrConvAddressToText(DESCRIPTOR desc, LPSTR str) {

   return AdrConvAddressToTextWithParams(desc,TRUE,TRUE,str);

}  /* end of AdrConvAddressToText */


/****************************************************************************
**
** AdrConvAddressToTextWithParams
**
** Symbolic output description:
**    if module valid, output #<module name>
**    if memory class is code
**       if output symbol is label, put label name
**       if public label
**          calculate offset from requested addr
**       output #<line>#<column> info
**       if offset != 0, display offset
**    else
**       output variable name (no function info)
**       calculate and output offset from beginning of var
**    if function desc valid, output (<func name>+<offset from top of func>)
*****************************************************************************/
RETCODE EXPORT
AdrConvAddressToTextWithParams(DESCRIPTOR inputAddrDesc,
			       BOOLEAN    with0X,
			       BOOLEAN    leadZeroFill,
			       LPSTR      str) {

   RETCODE err, firstErr = GOOD;
   LPSTR   strPtr;

   DESCRIPTOR addrRangeDesc = 0L;
   U32  maxOutputAddr;
   U16  maxOutputAddrCharWidth;
   U32  offset;

   
   DESCRIPTOR         nameDesc;      /* TMalloc'ed string ptr */
   MEM_ADDR_CLASS     memoryClass;
   SYM_TYPE_TYPE      symbolType;
   U32                symbolOffset, addrOffset;
   SYM_DESCRIPTOR     outputSymbol, funcDesc, moduleDesc;
   LINENUM_TYPE       linenum;
   COLUMN_RANGE_TYPE  columnRange;
   LINENUM_DESCRIPTOR nextIndex;
   U8                 n;
   U32                tableBase,segmentValue;

#ifndef ADR_UAE
   if (0L == inputAddrDesc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   strPtr = str;
   if ((err = AdrGetMaxOutputAddrOffset(inputAddrDesc,&maxOutputAddr))
	 != GOOD) return err;

   if ((err = AdrGetMaxOutputAddrDigits(inputAddrDesc,
	 &maxOutputAddrCharWidth)) != GOOD) return err;

   if (((A_D)inputAddrDesc)->symbolUsage == ON) {
      /* get basic static symbol info for requested address */
      if (GOOD != (err = SymMapAddr2Symbol(inputAddrDesc,
					   &memoryClass,
					   &symbolType,
					   &symbolOffset,
					   &outputSymbol,
					   &funcDesc,
					   &moduleDesc)))
	 return err;
      /* need local address */
      if (GOOD != (err = AdrCreateAddress(&addrRangeDesc)))
	 return(err);

      if (NULL_SYMBOL != moduleDesc) {
	 /*---------------*/
	 /* handle module */
	 /*---------------*/
	 *strPtr = '#';
	 strPtr++;
	 /* get module name */
	 if (GOOD != (err = SymGetSymbolName(moduleDesc, &nameDesc)))
	    goto CLEANUP_1;
	 strPtr = stpcpy(strPtr, (LPSTR)nameDesc);

	 if (GOOD != (err = TFree((LPSTR)nameDesc)))
	    goto CLEANUP_1;
      }
      /* not using symbol offset info; clear so can be used and tested */
      addrOffset = 0L;
      if (CODE_ADDR == memoryClass) {
	 /* insert #label if type is label */
	 if ((SYM_LABEL == symbolType) || (SYM_PUBLIC_LABEL == symbolType)) {
	    *strPtr++ = '#';
	    if (GOOD != (err = SymGetSymbolName(outputSymbol, &nameDesc)))
	       goto CLEANUP_1;
	    strPtr = stpcpy(strPtr, (LPSTR)nameDesc);

	    if (GOOD != (err = TFree((LPSTR)nameDesc)));
	       goto CLEANUP_1;
	 }
	 /*---------------------*/
	 /* handle public label */
	 /*---------------------*/
	 /* if public label, calculate offset from start of label */
	 if (SYM_PUBLIC_LABEL == symbolType) {

	    if (GOOD != (err = SymCalcSymbolOffset(outputSymbol,
						   inputAddrDesc,
						   &addrOffset)))
	       goto CLEANUP_1;
	 }
	 /*-------------------------*/
	 /* now insert #line#column */
	 /*-------------------------*/
	 if (NULL_SYMBOL != moduleDesc) {
	    err = SymMapAddr2LinenumStmt(inputAddrDesc,
					 moduleDesc,
					 &linenum,
					 &columnRange,
					 addrRangeDesc,
					 &nextIndex);
	    if (GOOD != err) {
	       /* NOTES: 09/22/93 - Nghia
	       ** Filter out ER_NO_LINENUMS_ADDED for ASM module which does
	       ** not have line number info, but does have valid address
	       ** range - Reset err to GOOD to fall thru
	       */
	       err = (err == ER_NO_LINENUMS_ADDED) ? GOOD : err;
	       if (ER_ADDRESS_NOT_FOUND != err)
		  goto CLEANUP_1;
	       /* fall thru if no linenum found to complete the output */
	    } else {  /* no error */
	       /* output #line#column */
	       if (linenum) { /* only if not 0 */
		  n = sprintf(strPtr, "#%u", linenum);
		  strPtr += n;
		  if (columnRange.columnStart) { /* only if not 0 */
		     n = sprintf(strPtr, "#%hu", columnRange.columnStart);
		     strPtr += n;
		  }
	       }
	    }
	 }
      } else {  /* data address */ 
	 *strPtr++ = '#';
	 if (GOOD != (err = SymGetSymbolName(outputSymbol, &nameDesc)))
	    goto CLEANUP_1;
	 strPtr = stpcpy(strPtr, (LPSTR)nameDesc);
	 if (GOOD != (err = TFree((LPSTR)nameDesc)))
	    goto CLEANUP_1;
	 if (GOOD != (err = SymCalcSymbolOffset(outputSymbol,
						inputAddrDesc,
						&addrOffset)))
	    goto CLEANUP_1;
      }
      /* output offset if non-zero */
      if (0L != addrOffset) {
	 /* output offset in hex and decimal */
	 n = sprintf(strPtr, "+0x%lX [%ld]", addrOffset, addrOffset);
	 strPtr += n;
      }
      /*-----------------*/
      /* handle function */
      /*-----------------*/
      if (NULL_SYMBOL != funcDesc) {
	 /* insert (function <funcName+<funcOffset>) */
	 /* if offset is 0 or negative, ignore */
	 if (GOOD != (err = SymGetSymbolName(funcDesc, &nameDesc)))
	    goto CLEANUP_1;
	 n = sprintf(strPtr, " (function %s", (LPSTR)nameDesc);
	 strPtr += n;
	 
	 if (GOOD != (err = TFree((LPSTR)nameDesc)))
	    goto CLEANUP_1;

	 if (CODE_ADDR == memoryClass) {
	    if (GOOD != (err = SymCalcSymbolOffset(funcDesc,
						   inputAddrDesc,
						   &addrOffset)))
	       goto CLEANUP_1;
	    if (addrOffset > 0L) {
	       n = sprintf(strPtr, "+0x%lX [%ld]", addrOffset, addrOffset);
	       strPtr += n;
	    }
	 }
	 *strPtr = ')';
	 strPtr++;
      }
      *strPtr = '\0';  /* terminate with null */
      goto CLEANUP_1;  /* done */

   /* not symbolic, output hex value */
   } else {
      if (with0X)
	 strPtr = stpcpy(strPtr, "0x");
      switch (((A_D)inputAddrDesc)->type) {
	 case ADDR_VIRTUAL:
	    // if desc->ldt != 0 && desc->ldt != LDTR then show it too
	    // get current LDTR value
	    if ( ((A_D)inputAddrDesc)->ldt != 0) {
	       if ((err = CpuGetRegister(LDTBaseId,&tableBase)) != GOOD)
		  return err;
	       if (tableBase != ((A_D)inputAddrDesc)->ldt) {  // show it too
		  if (leadZeroFill) {
		     sprintf(strPtr, "%*.*lX",4,4,
			   ((A_D)inputAddrDesc)->ldt);
		  } else {
		     sprintf(strPtr, "%lX", ((A_D)inputAddrDesc)->ldt);
		  }
		  strcat(strPtr,":");
		  if (with0X)
		     strPtr = strcat(strPtr, "0x");
		  strPtr += strlen(strPtr);
	       }
	    }
	    // do the segment
	    if ((err = GetSegment(inputAddrDesc,&segmentValue)) != GOOD)
	       return err;
	    if (leadZeroFill) {
	       sprintf(strPtr, "%*.*lX",4,4,segmentValue);
	    } else {
	       sprintf(strPtr, "%lX", segmentValue);
	    }
	    strcat(strPtr,":");
	    if (with0X)
	       strPtr = strcat(strPtr, "0x");
	    // do the offset
	       strPtr += strlen(strPtr);
	    if (leadZeroFill) {
	       sprintf(strPtr, "%*.*lX", maxOutputAddrCharWidth,
				   maxOutputAddrCharWidth,
				   (((A_D)inputAddrDesc)->addrOffset &
				   maxOutputAddr));
	    } else {
	       sprintf(strPtr, "%lX", (((A_D)inputAddrDesc)->addrOffset &
					maxOutputAddr));
	    }
	    break;
	 case ADDR_LINEAR:
	    offset = ((A_D)inputAddrDesc)->addrOffset & maxOutputAddr;
	    if (leadZeroFill) {
	       sprintf(strPtr, "%*.*lX", maxOutputAddrCharWidth,
				   maxOutputAddrCharWidth,
				   offset);
	    } else {
	       sprintf(strPtr, "%lX", offset);
	    }
	    if (procFamily == FAMILY_X86) {
	       /* append linear address notation */
	       strcat(strPtr,"L");
	    }
	    break;
	 case ADDR_PHYSICAL:
	    offset = ((A_D)inputAddrDesc)->addrOffset & maxOutputAddr;
	    if (leadZeroFill) {
	       sprintf(strPtr, "%*.*lX", maxOutputAddrCharWidth,
				   maxOutputAddrCharWidth,
				   offset);
	    } else {
	       sprintf(strPtr, "%lX", offset);
	    }
	    if (procFamily == FAMILY_X86) {
	       /* append physical address notation */
	       strcat(strPtr,"P");
	    }
	    break;
      }
      return(GOOD);
   }

CLEANUP_1:
   firstErr = err;
   err = AdrDestroyAddress(addrRangeDesc);  /* always alloc'ed */
   if (GOOD == firstErr)
      firstErr = err;
   return firstErr;
}  /* end of AdrConvAddressToTextWithParams */

/****************************************************************************
**
** AdrConvAddrRangeToText
**
*****************************************************************************/
RETCODE EXPORT
AdrConvAddrRangeToText(DESCRIPTOR rangeDesc,
		       BOOLEAN    with0X,
		       BOOLEAN    leadZeroFill,
		       ADDR_RANGE_COMP  whichPart,
		       LPSTR      str) {

   RETCODE err = GOOD;
   DESCRIPTOR tmpDesc;
   LPSTR   strPtr = str;

   *str = '\0';
   if (!((A_D)rangeDesc)->rangeActive) 
      return (AdrConvAddressToTextWithParams(rangeDesc,with0X,
	    leadZeroFill,str));
   if ((whichPart == RANGE_START) || (whichPart == RANGE_BOTH)) {
      if ((err = AdrConvAddressToTextWithParams(rangeDesc,with0X,
	    leadZeroFill,str)) != GOOD)
	 return err;
   }
   if (whichPart == RANGE_BOTH) 
      strcat(str,"..");
   if ((whichPart == RANGE_END) || (whichPart == RANGE_BOTH)) {
      if (*str != '\0')
	 strPtr += strlen(str);
      if ((err = AdrDuplicateAddress(rangeDesc,&tmpDesc)) != GOOD)
	 return err;
      ((A_D)tmpDesc)->addrOffset = ((A_D)rangeDesc)->addrOffset +
	     ((A_D)rangeDesc)->rangeLength - 1;
      if ((err = AdrConvAddressToTextWithParams(tmpDesc,with0X,
	    leadZeroFill,strPtr)) != GOOD) {
	 AdrDestroyAddress(tmpDesc);
	 return err;
      }
      if ((err = AdrDestroyAddress(tmpDesc)) != GOOD)
	 return err;
   }
   return GOOD;
}

/****************************************************************************
**
**  AdrGetAddressToTextLength
**
*****************************************************************************/
RETCODE EXPORT AdrGetAddressToTextLength(DESCRIPTOR desc, U8 FAR *length) {

   RETCODE err;

   S8 tmpStr[ADDR_BUFF_SZ];
   
   if ((err = AdrConvAddressToTextWithParams(desc,TRUE,TRUE,
	 (LPSTR)tmpStr)) != GOOD)
      return err;
   *length = strlen(tmpStr);
   return GOOD;
}


/****************************************************************************
**
**  AdrConvAddressToTextNoFill
**
*****************************************************************************/
RETCODE EXPORT AdrConvAddressToTextNoFill(DESCRIPTOR desc, LPSTR text) {

      return AdrConvAddressToTextWithParams(desc,TRUE,FALSE,text);
}  /* end of AdrConvAddressToTextNoFill */


/****************************************************************************
**
**  AdrConvTextToAddress
**
**  The descriptor passed in will be modified to match the attibutes of
**  the supplied text. ( only address text )
**
**     Supported formats are as follows:
**
**     INTEL formats:
**          <offset>L            Linear address
**          <offset>P            Physical address
**          (#module)#symbol     Symbolic segment:offset interpreted
**                               as Virtual address
**          <ldt>:<segment>:<offset>  Virtual address with specific LDT
**          <segment>:<offset>        Virtual address using current LDT
**          <offset>                  Virtual address assuming current
**                                        LDT and DS
**
**     MOTOROLA formats:
**          (#module)#symbol    Symbolic offset interpreted as Linear address
**          <offset>            Linear address assuming default SD space
**
**
*****************************************************************************/
RETCODE EXPORT AdrConvTextToAddress(DESCRIPTOR desc, LPSTR text) {

#define MAXTOKEN 5
#define MAXBUFF 100
   
   RETCODE           err = GOOD;
   U32               localAddr;
   S8                *endPtr,*endTextPtr;
   SYM_DESCRIPTOR    moduleDesc;
   LINENUM_TYPE      actualLinenum;
   COLUMN_RANGE_TYPE actualColumnRange;
   DESCRIPTOR        tmpDesc;
   LPSTR             token[MAXTOKEN];
   U8                tCount=0;
   CHAR              buf[MAXBUFF] = "";
   LPSTR             bufPtr;
   U16               i, textSize = 0;
   REG_ID            regId;
   LPSTR             tokenPtr,typePtr;
   BOOLEAN           rangeCovered;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   while (isspace((S16)*text)) {  /* skip over spaces; requires int */
      text++;
   }
   textSize = strlen(text);
   endTextPtr = text + textSize - 1;
   while (isspace((S16)*endTextPtr)) {
      endTextPtr--;
   }
   *(endTextPtr+1) = NULL;

   /* 05/05/94 - Nghia
   ** Make sure that the src string will not overrun the dest string
   ** when collecting token into buf - Should use TMALLOC to allocate buf[].
   **    buf = TMalloc(strlen(text)+1); 
   */
   if ((textSize == 0) || (textSize > MAXBUFF))
      return ER_ADR_INVALID_ADDRESS_STR;
   
   bufPtr = buf;
   if (strncmp(text,"#",1) == GOOD) {  /* symbolic input */
      /* pass off to symbol table to convert to address */
      if (GOOD != (err =
	 SymGetAddrFromName(text,
			    SYM_UNKNOWN_ADDR,
			    &moduleDesc,
			    &tmpDesc,          /* created and filled out */
			    &actualLinenum,
			    &actualColumnRange)))
	 return err;
      /* default address descriptor from the symbol table.  Use
      ** the passed desc type as the type for the symbol address.
      ** tmpDesc alloc'ed, user passed desc alloc'ed
      */
      if (((A_D)desc)->type == ((A_D)tmpDesc)->type)  {
	 if ((err = AdrCopyAddress(tmpDesc, desc)) != GOOD)
	    return err;
      }
      else {  /* translate to passed desc type */
	 if ((err = AdrConvertAddress(tmpDesc,((A_D)desc)->type,
	       &rangeCovered)) != GOOD)
	    return err;
	 if ((err = AdrCopyAddress(tmpDesc, desc)) != GOOD)
	    return err;
      }
      return( AdrDestroyAddress(tmpDesc));
   }
   /* establish number of tokens  - 3 max: ldtr:gs:eax */
   /* look for : designator which indicates more than 1 token */
   if (_fstrpbrk(text,":") != NULL) {   /* multiple tokens */
      tokenPtr = _fstrtok(text,":");
      while ((tokenPtr != NULL) && (tCount < MAXTOKEN)) {
	 token[tCount++] = tokenPtr;
	 tokenPtr = _fstrtok(NULL,":");
      }
   } /* only one token, just an offset */
   else {
      token[tCount++] = text;
   }
   /* process all the tokens, preprocess any register names to values */
   /* if isalpha(text) attempt to convert to a register. If it */
   /* fails then assume hex text. Collect new tokens in buf */
   for (i = 0; i < tCount; i++) {
      stpcpy(bufPtr,token[i]);
      token[i] = bufPtr;
   }
//      / * check for register name * /
//      if (isalpha((S16)(*token[i]))) {
//         if (CpuFindRegisterId((LPU8)token[i],&regId) != GOOD) {
//           / * not a regname so must be hex text * /
//           stpcpy(bufPtr,token[i]);
//           token[i] = bufPtr;
//         }
//         else { / * a register name! * /
//            if ((err = CpuGetRegisterValueText(regId,0,bufPtr)) != GOOD)
//               return err;
//            token[i] = bufPtr;
//            bufPtr += (strlen(bufPtr) + 1);
//         }
//      }
//      else  { / * must be a value * /
//         / * copy token[i] into buf * /
//         stpcpy(bufPtr,token[i]);
//         token[i] = bufPtr;
//      }
//   }  / * end for * /

   switch (tCount) {
      case 3:  /* ldt:segment:offset*/
	 if (procFamily != FAMILY_X86)
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrType(desc,ADDR_VIRTUAL)) != GOOD)
	    return err;
	 localAddr = strtoulDefRadix(token[0], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetLdtSelector(desc,localAddr)) != GOOD)
	    return err;
	 /* turn segment string into a U32 */
	 if ((err = GetSegSelFromText(token[1],&localAddr)) != GOOD)
	    return err;
	 if ((err = AdrSetAddrSegmentSelector(desc,
		 ADDR_USE_VALUE,localAddr)) != GOOD)
	    return err;
	 localAddr = strtoulDefRadix(token[2], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrOffset(desc,localAddr)) != GOOD)
	    return err;
	 break;
      case 2:  /* segment:offset */
	 if (procFamily != FAMILY_X86)
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrType(desc,ADDR_VIRTUAL)) != GOOD)
	    return err;
	 /* use current ldt */
	 if ((err = AdrSetLdtSelector(desc,0L)) != GOOD)
	    return err;
	 /* turn segment string into a U32 */
	 if ((err = GetSegSelFromText(token[0], &localAddr)) != GOOD)
	    return err;
	 if ((err = AdrSetAddrSegmentSelector(desc,
		 ADDR_USE_VALUE,localAddr)) != GOOD)
	    return err;
	 localAddr = strtoulDefRadix(token[1], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrOffset(desc,localAddr)) != GOOD)
	    return err;
	 break;
      case 1:  /* offset: can be virtual, linear, or physical */
	 if (procFamily == FAMILY_X86) {
	    if ((typePtr = _fstrpbrk(token[0],"Pp")) != NULL) {
	       /* physical offset type */
	       if ((err = AdrSetAddrType(desc,ADDR_PHYSICAL)) != GOOD)
		  return err;
	       *typePtr = '\0';
	    }
	    else if ((typePtr = _fstrpbrk(token[0],"Ll")) != NULL) {
	       /* linear offset type */
	       if ((err = AdrSetAddrType(desc,ADDR_LINEAR)) != GOOD)
		  return err;
	       *typePtr = '\0';
	    }
	    else {
	       if ((err = AdrSetAddrType(desc,ADDR_VIRTUAL)) != GOOD)
		  return err;
	       if ((err = AdrSetAddrSegmentSelector(desc,
		       ADDR_USE_DS,0)) != GOOD)
		  return err;
	    }
	 }
	 else {     /* FAMILY_68K */
	    if ((err = AdrSetAddrType(desc,ADDR_LINEAR)) != GOOD)
	       return err;
	 }
	 localAddr = strtoulDefRadix(token[0], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrOffset(desc,localAddr)) != GOOD)
	    return err;
	 break;
   }  /* end switch */
   return GOOD;
}

/****************************************************************************
**
**  AdrConvTextToAddressForReg
**
**  The descriptor passed in will be modified to match the attibutes of
**  the supplied text. ( include register name )
**
**     Supported formats are as follows:
**
**     INTEL formats:
**          <offset>L            Linear address
**          <offset>P            Physical address
**          (#module)#symbol     Symbolic segment:offset interpreted
**                               as Virtual address
**          <ldt>:<segment>:<offset>  Virtual address with specific LDT
**          <segment>:<offset>        Virtual address using current LDT
**          <offset>                  Virtual address assuming current
**                                        LDT and DS
**
**     MOTOROLA formats:
**          (#module)#symbol    Symbolic offset interpreted as Linear address
**          <offset>            Linear address assuming default SD space
**
**
*****************************************************************************/
RETCODE EXPORT AdrConvTextToAddressForReg(DESCRIPTOR desc, LPSTR text) {

#define MAXTOKEN 5
#define MAXBUFF 100
   
   RETCODE           err = GOOD;
   U32               localAddr;
   S8                *endPtr,*endTextPtr;
   SYM_DESCRIPTOR    moduleDesc;
   LINENUM_TYPE      actualLinenum;
   COLUMN_RANGE_TYPE actualColumnRange;
   DESCRIPTOR        tmpDesc;
   LPSTR             token[MAXTOKEN];
   U8                tCount=0;
   CHAR              buf[MAXBUFF] = "";
   LPSTR             bufPtr;
   U16               i, textSize = 0;
   REG_ID            regId;
   LPSTR             tokenPtr,typePtr;
   BOOLEAN           rangeCovered;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   while (isspace((S16)*text)) {  /* skip over spaces; requires int */
      text++;
   }
   textSize = strlen(text);
   endTextPtr = text + textSize - 1;
   while (isspace((S16)*text)) {
      endTextPtr--;
   }
   *(endTextPtr+1) = NULL;

   /* 05/05/94 - Nghia
   ** Make sure that the src string will not overrun the dest string
   ** when collecting token into buf - Should use TMALLOC to allocate buf[].
   **    buf = TMalloc(strlen(text)+1); 
   */
   if ((textSize == 0) || (textSize > MAXBUFF))
      return ER_ADR_INVALID_ADDRESS_STR;
   
   bufPtr = buf;
   if (strncmp(text,"#",1) == GOOD) {  /* symbolic input */
      /* pass off to symbol table to convert to address */
      if (GOOD != (err =
	 SymGetAddrFromName(text,
			    SYM_UNKNOWN_ADDR,
			    &moduleDesc,
			    &tmpDesc,          /* created and filled out */
			    &actualLinenum,
			    &actualColumnRange)))
	 return err;
      /* default address descriptor from the symbol table.  Use
      ** the passed desc type as the type for the symbol address.
      ** tmpDesc alloc'ed, user passed desc alloc'ed
      */
      if (((A_D)desc)->type == ((A_D)tmpDesc)->type)  {
	 if ((err = AdrCopyAddress(tmpDesc, desc)) != GOOD)
	    return err;
      }
      else {  /* translate to passed desc type */
	 if ((err = AdrConvertAddress(tmpDesc,((A_D)desc)->type,
	       &rangeCovered)) != GOOD)
	    return err;
	 if ((err = AdrCopyAddress(tmpDesc, desc)) != GOOD)
	    return err;
      }
      return( AdrDestroyAddress(tmpDesc));
   }
   /* establish number of tokens  - 3 max: ldtr:gs:eax */
   /* look for : designator which indicates more than 1 token */
   if (_fstrpbrk(text,":") != NULL) {   /* multiple tokens */
      tokenPtr = _fstrtok(text,":");
      while ((tokenPtr != NULL) && (tCount < MAXTOKEN)) {
	 token[tCount++] = tokenPtr;
	 tokenPtr = _fstrtok(NULL,":");
      }
   } /* only one token, just an offset */
   else {
      token[tCount++] = text;
   }
   /* process all the tokens, preprocess any register names to values */
   /* if isalpha(text) attempt to convert to a register. If it */
   /* fails then assume hex text. Collect new tokens in buf */
   for (i = 0; i < tCount; i++) {
      stpcpy(bufPtr,token[i]);
      token[i] = bufPtr;
      /* check for register name */
      if (isalpha((S16)(*token[i]))) {
	 if (CpuFindRegisterId((LPU8)token[i],&regId) != GOOD) {
	   /* not a regname so must be hex text */
	   stpcpy(bufPtr,token[i]);
	   token[i] = bufPtr;
	 }
	 else { /* a register name! */
	    if ((err = CpuGetRegisterValueText(regId,0,bufPtr)) != GOOD)
	       return err;
	    token[i] = bufPtr;
	    bufPtr += (strlen(bufPtr) + 1);
	 }
      }
      else  { /* must be a value */
	 /* copy token[i] into buf */
	 stpcpy(bufPtr,token[i]);
	 token[i] = bufPtr;
      }
   }  /* end for */

   switch (tCount) {
      case 3:  /* ldt:segment:offset*/
	 if (procFamily != FAMILY_X86)
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrType(desc,ADDR_VIRTUAL)) != GOOD)
	    return err;
	 localAddr = strtoulDefRadix(token[0], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetLdtSelector(desc,localAddr)) != GOOD)
	    return err;
	 /* turn segment string into a U32 */
	 if ((err = GetSegSelFromText(token[1],&localAddr)) != GOOD)
	    return err;
	 if ((err = AdrSetAddrSegmentSelector(desc,
		 ADDR_USE_VALUE,localAddr)) != GOOD)
	    return err;
	 localAddr = strtoulDefRadix(token[2], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrOffset(desc,localAddr)) != GOOD)
	    return err;
	 break;
      case 2:  /* segment:offset */
	 if (procFamily != FAMILY_X86)
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrType(desc,ADDR_VIRTUAL)) != GOOD)
	    return err;
	 /* use current ldt */
	 if ((err = AdrSetLdtSelector(desc,0L)) != GOOD)
	    return err;
	 /* turn segment string into a U32 */
	 if ((err = GetSegSelFromText(token[0], &localAddr)) != GOOD)
	    return err;
	 if ((err = AdrSetAddrSegmentSelector(desc,
		 ADDR_USE_VALUE,localAddr)) != GOOD)
	    return err;
	 localAddr = strtoulDefRadix(token[1], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrOffset(desc,localAddr)) != GOOD)
	    return err;
	 break;
      case 1:  /* offset: can be virtual, linear, or physical */
	 if (procFamily == FAMILY_X86) {
	    if ((typePtr = _fstrpbrk(token[0],"Pp")) != NULL) {
	       /* physical offset type */
	       if ((err = AdrSetAddrType(desc,ADDR_PHYSICAL)) != GOOD)
		  return err;
	       *typePtr = '\0';
	    }
	    else if ((typePtr = _fstrpbrk(token[0],"Ll")) != NULL) {
	       /* linear offset type */
	       if ((err = AdrSetAddrType(desc,ADDR_LINEAR)) != GOOD)
		  return err;
	       *typePtr = '\0';
	    }
	    else {
	       if ((err = AdrSetAddrType(desc,ADDR_VIRTUAL)) != GOOD)
		  return err;
	       if ((err = AdrSetAddrSegmentSelector(desc,
		       ADDR_USE_DS,0)) != GOOD)
		  return err;
	    }
	 }
	 else {     /* FAMILY_68K */
	    if ((err = AdrSetAddrType(desc,ADDR_LINEAR)) != GOOD)
	       return err;
	 }
	 localAddr = strtoulDefRadix(token[0], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrOffset(desc,localAddr)) != GOOD)
	    return err;
	 break;
   }  /* end switch */
   return GOOD;
}
/***************************************************************************
**
**  AdrTranslateSpace
**
************************************************************************/
RETCODE EXPORT AdrTranslateSpace(LPSTR inputText, ADDR_SPACE FAR *space) {

   LOOP_VAR i;

   *space = SPACE_DEFAULT;
   if (inputText == NULL)
      return GOOD;                
   switch (cpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_68000:
      case PROC_CPU_68040:
	 for (i=0;i<MAX_MOTO32_SPACES;i++) {
	    if (stricmp(inputText,motoCpu32Spaces[i].spaceStr) == GOOD) {
	       *space = motoCpu32Spaces[i].space;
	       return GOOD;
	    }
	 }
	 return ER_ADR_SPACE_INVALID;
      case PROC_CPU_CPU16:
	 for (i=0;i<MAX_MOTO16_SPACES;i++) {
	    if (stricmp(inputText,motoCpu16Spaces[i].spaceStr) == GOOD) {
	       *space = motoCpu16Spaces[i].space;
	       return GOOD;
	    }
	 }
	 return ER_ADR_SPACE_INVALID;
      case PROC_CPU_80186:
	 break;
      case PROC_CPU_80386:
	 for (i=0;i<MAX_INTEL_SPACES;i++) {
	    if (stricmp(inputText,intelSpaces[i].spaceStr) == GOOD) {
	       *space = intelSpaces[i].space;
	       return GOOD;
	    }
	 }
	 return ER_ADR_SPACE_INVALID;
      case PROC_CPU_80486:
	 break;
   }

   return GOOD;
}

/**************************************************************************
**
** AdrGetSpaceStr
**
***************************************************************************/
RETCODE EXPORT AdrGetSpaceStr(ADDR_SPACE space, LPSTR spaceString) { \

   LOOP_VAR i;

   *spaceString = '\0';
   switch (cpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_68000:
      case PROC_CPU_68040:
	 if (space == SPACE_DEFAULT)
	    space = SPACE_SD;
	 for (i=0;i<MAX_MOTO32_SPACES;i++) {
	    if (space == motoCpu32Spaces[i].space) {
	       lstrcpy(spaceString,motoCpu32Spaces[i].spaceStr);
	       return GOOD;
	    }
	 }
	 return ER_ADR_SPACE_INVALID;
      case PROC_CPU_CPU16:
	 if (space == SPACE_DEFAULT)
	    space = SPACE_SD; 
	 for (i=0;i<MAX_MOTO16_SPACES;i++) {
	    if (space == motoCpu16Spaces[i].space) {
	       lstrcpy(spaceString,motoCpu16Spaces[i].spaceStr);
	       return GOOD;
	    }
	 }
	 return ER_ADR_SPACE_INVALID;
      case PROC_CPU_80386:
	 if (space == SPACE_DEFAULT)
	    space = SPACE_USER;
	 for (i=0;i<MAX_INTEL_SPACES;i++) {
	    if (space == intelSpaces[i].space) {
	       lstrcpy(spaceString,intelSpaces[i].spaceStr);
	       return GOOD;
	    }
	 }
	 return ER_ADR_SPACE_INVALID;
   }
   return GOOD;
}

/****************************************************************************
**
**  AdrAddToAddress
**
*****************************************************************************/
RETCODE EXPORT AdrAddToAddress(DESCRIPTOR desc, U32 value) {

   U32 tmpAddrOffset;
   U32 maxInputAddr;
   RETCODE err;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((err = AdrGetMaxInputAddrOffset(desc,&maxInputAddr)) != GOOD)
      return err;
   tmpAddrOffset = ((A_D)desc)->addrOffset + value;

   if (tmpAddrOffset > maxInputAddr)
      return ER_ADR_ADDRESS_TOO_LARGE;

   if (tmpAddrOffset < ((A_D)desc)->addrOffset)
      return(ER_ADR_RESULT_OVERFLOW) ;
   ((A_D)desc)->addrOffset = tmpAddrOffset;
   return GOOD;
}

/****************************************************************************
**
**  AdrAddAddressTogether
**
*****************************************************************************/
RETCODE EXPORT AdrAddAddressTogether(DESCRIPTOR desc1, DESCRIPTOR desc2) {

   U32 tmpAddrOffset;
   U32 maxInputAddr;
   RETCODE err;

#ifndef ADR_UAE
   if ((desc1 == 0L) || (desc2 == 0L))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((err = AdrGetMaxInputAddrOffset(desc1,&maxInputAddr)) != GOOD)
      return err;
   tmpAddrOffset = ((A_D)desc1)->addrOffset + ((A_D)desc2)->addrOffset;

   if (tmpAddrOffset > maxInputAddr)
      return ER_ADR_ADDRESS_TOO_LARGE;

   if (tmpAddrOffset < ((A_D)desc1)->addrOffset)
      return(ER_ADR_RESULT_OVERFLOW) ;
   ((A_D)desc1)->addrOffset = tmpAddrOffset;
   return GOOD;
}


/****************************************************************************
**
**  AdrSubtractFromAddress
**
*****************************************************************************/
RETCODE EXPORT AdrSubtractFromAddress(DESCRIPTOR desc, U32 value) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (value > ((A_D)desc)->addrOffset)
      return(ER_ADR_RESULT_UNDERFLOW) ;

   ((A_D)desc)->addrOffset -= value ;
   return(GOOD) ;
}

/****************************************************************************
**
**  AdrSubtractAddresses
**
*****************************************************************************/
RETCODE EXPORT AdrSubtractAddresses(DESCRIPTOR desc1, DESCRIPTOR desc2) {


#ifndef ADR_UAE
   if ((desc1 == 0L) || (desc2 == 0L))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (((A_D)desc2)->addrOffset > ((A_D)desc1)->addrOffset)
      return(ER_ADR_RESULT_UNDERFLOW) ;

   ((A_D)desc1)->addrOffset -= ((A_D)desc2)->addrOffset;
   return GOOD;
}

/****************************************************************************
**
**  AdrSubtractFromAddressUnderflow
**
*****************************************************************************/
RETCODE EXPORT AdrSubtractFromAddressUnderflow(DESCRIPTOR desc, U32 value) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif

   ((A_D)desc)->addrOffset -= value ;
   return(GOOD) ;
}

/****************************************************************************
**
**  AdrCompareAddresses
**
*****************************************************************************/
RETCODE EXPORT AdrCompareAddresses(DESCRIPTOR desc1, DESCRIPTOR desc2,
				   ADDR_COMPARE FAR *result) {

#ifndef ADR_UAE
   if ((0L == desc1) || (0L == desc2))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (((A_D)desc1)->type != ((A_D)desc2)->type)
      return ER_ADR_DIFFER_TYPES;
//   if (((A_D)desc1)->space != ((A_D)desc2)->space)
//      return ER_ADR_DIFFER_SPACES;
   if ((((A_D)desc1)->type == ADDR_VIRTUAL) &&
	  (((A_D)desc1)->addrSegSel != ((A_D)desc2)->addrSegSel))
      return ER_ADR_DIFFER_SEGMENTS;
   *result = (((A_D)desc1)->addrOffset > ((A_D)desc2)->addrOffset)
      ? FIRST_ADDR_GREATER:
      ((((A_D)desc2)->addrOffset > ((A_D)desc1)->addrOffset)
      ? SECOND_ADDR_GREATER: EQUAL_ADDRS);
   return GOOD;
}

/****************************************************************************
**
**  AdrComparePysicalAddresses
**
*****************************************************************************/
RETCODE EXPORT AdrComparePhysicalAddresses(DESCRIPTOR desc1,
					   DESCRIPTOR desc2,
					   ADDR_COMPARE FAR *result) {
   U32 physAddr1;
   U32 physAddr2;
   RETCODE err;

#ifndef ADR_UAE
   if ((0L == desc1) || (0L == desc2))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   /* Compare Physical addresses does not need to check for space */
   if (((A_D)desc1)->type != ADDR_PHYSICAL)  {
      if ((err = AddrToPhysical(desc1,&physAddr1)) != GOOD)
	 return err;
   }
   else
      physAddr1 = ((A_D)desc1)->addrOffset;
   if (((A_D)desc2)->type != ADDR_PHYSICAL) {
      if ((err = AddrToPhysical(desc2,&physAddr2)) != GOOD)
	 return err;
   }
   else
      physAddr2 = ((A_D)desc2)->addrOffset;
   *result = (physAddr1 > physAddr2) ? FIRST_ADDR_GREATER :
      ((physAddr2 > physAddr1) ? SECOND_ADDR_GREATER : EQUAL_ADDRS);
   if (((A_D)desc1)->space != ((A_D)desc2)->space)
      *result = FIRST_ADDR_GREATER;
   return GOOD;
}

/************************************************************************
**
**  AdrAreAddrsIdentical
**
**************************************************************************/
RETCODE EXPORT AdrAreAddrsIdentical(DESCRIPTOR addr1, DESCRIPTOR addr2,
				    BOOLEAN FAR *identical) {
#ifndef ADR_UAE
   if ((0L == addr1) || (0L == addr2))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif

   *identical = (_fmemcmp((void *)addr1,(void *)addr2,
	 sizeof(ADDR_DESCRIPTOR)) == 0);
   return GOOD;
}

/****************************************************************************
**
** AdrRangeOfAddresses
**
** NOTE: a numBytes value of 0 represents 0x100000000 (i.e. 2^32)
*****************************************************************************/
RETCODE EXPORT AdrRangeOfAddresses(DESCRIPTOR desc1, DESCRIPTOR desc2,
				   U32 FAR *numBytes) {

#ifndef ADR_UAE
   if ((0L == desc1) || (0L == desc2))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   /* check for same type */
   if (((A_D)desc1)->type != ((A_D)desc2)->type) {
      return(ER_ADR_DIFFER_TYPES);
   }
#ifdef SPACE_CHECKED
   /* check for same space if 68K uP */
   if (FAMILY_68K == procFamily) {

      if ((SPACE_DONT_CARE == (((A_D)desc1)->space)) ||
	  (SPACE_DONT_CARE == (((A_D)desc2)->space))) {
      /* go to next block; skip else test */

      } else {
	// if ((((A_D)desc1)->space) != (((A_D)desc2)->space)) {
	//    return ER_ADR_DIFFER_SPACES;
	 }
      }
   }
   else {
      if (((A_D)desc1)->space != ((A_D)desc2)->space)
	 return ER_ADR_DIFFER_SPACES;
      if ((((A_D)desc1)->type == ADDR_VIRTUAL) &&
	    (((A_D)desc1)->addrSegSel != ((A_D)desc2)->addrSegSel))
	 return ER_ADR_DIFFER_SEGMENTS;
   }
#endif

   if (((A_D)desc2)->addrOffset < ((A_D)desc1)->addrOffset) {
      *numBytes = ((A_D)desc1)->addrOffset - ((A_D)desc2)->addrOffset + 1;
   } else {
      *numBytes = ((A_D)desc2)->addrOffset - ((A_D)desc1)->addrOffset + 1;
   }
   return(GOOD) ;
}  /* end of AdrRangeOfAddresses */


/****************************************************************************
**
** AdrIsAddrInRange
**
** Test for inside range:
**    input >= start of range AND
**    input <= end of range which is equivalent to
*        input < (start + length)
**    OR
**    range is the max value; ie. 2^32, which is represented by a value of 0
**        (any address would fit inside a max range)
*****************************************************************************/
RETCODE EXPORT AdrIsAddrInRange(DESCRIPTOR inputAddr, DESCRIPTOR rangeAddr,
				BOOLEAN FAR *isInRange)  {
U32 TopRange, maxInputAddr;
#define RANGE_DESC ((A_D)rangeAddr)
#define INPUT_DESC ((A_D)inputAddr)

#ifdef ADR_DEBUG
/* used for debugging code */
U32 inputStart, rangeStart, rangeEnd;
   inputStart = INPUT_DESC->addrOffset;
   rangeStart = RANGE_DESC->addrOffset;
   rangeEnd =   RANGE_DESC->addrOffset + RANGE_DESC->rangeLength - 1;
#endif
      
#ifndef ADR_UAE
   if ((0L == inputAddr) || (0L == rangeAddr))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (!RANGE_DESC->rangeActive)
      return ER_ADR_NOT_RANGE_TYPE;
   /* check for same type */
   if (RANGE_DESC->type != INPUT_DESC->type) {
      return(ER_ADR_DIFFER_TYPES);
   }

#ifdef SPACE_CHECKED
   /* check for same space if 68K uP */
   if (FAMILY_68K == procFamily) {
      if ((SPACE_DONT_CARE == (INPUT_DESC->space)) ||
	  (SPACE_DONT_CARE == (RANGE_DESC->space))) {
      /* go to next block; skip else test */
      } else {
	 // if ((INPUT_DESC->space) != (RANGE_DESC->space))
	 //    return ER_ADR_DIFFER_SPACES;
      }
   }
   else {
      if (INPUT_DESC->space != RANGE_DESC->space)
	 return ER_ADR_DIFFER_SPACES;
      if ((INPUT_DESC->type == ADDR_VIRTUAL) &&
	    (INPUT_DESC->addrSegSel != RANGE_DESC->addrSegSel))
	 return ER_ADR_DIFFER_SEGMENTS;
   }
#endif

   /* test: input addr >= range start addr AND < range length) OR
   ** max length (rangeLength = 0 ==> 2^32 range size) *
   ** *isInRange = (((INPUT_DESC->addrOffset >= RANGE_DESC->addrOffset) &&
   **    ((RANGE_DESC->addrOffset) + (RANGE_DESC->rangeLength)) >
   **    INPUT_DESC->addrOffset)
   **    || (!RANGE_DESC->rangeLength));
   */
   /* more efficient test : is range max range? (rangeLength == 0) OR
   ** is input descriptor outside the range?
   */
   AdrGetMaxInputAddrOffset(RANGE_DESC,&maxInputAddr);
   TopRange = RANGE_DESC->addrOffset + RANGE_DESC->rangeLength;
   if (RANGE_DESC->addrOffset > TopRange || TopRange > maxInputAddr)
      TopRange = maxInputAddr;
   *isInRange = (!RANGE_DESC->rangeLength ||
		 !((INPUT_DESC->addrOffset < RANGE_DESC->addrOffset) ||
		   (INPUT_DESC->addrOffset >= TopRange)) );
   return GOOD;
} /* end of AdrIsAddrInRange */

/*************************************************************************
**
** AdrIsPhysicalAddrInRange
**
** Test for inside range:
**    input >= start of range AND
**    input <= end of range which is equivalent to
**        input < (start + length)
**    OR
**    range is the max value; ie. 2^32, which is represented by a value of 0
**        (any address would fit inside a max range)
**************************************************************************/
RETCODE EXPORT AdrIsPhysicalAddrInRange(DESCRIPTOR inputAddr,
					DESCRIPTOR rangeAddr,
					BOOLEAN FAR *isInRange)  {
   RETCODE err;
   U32 physRangeStart,
       inputStart;

#define RANGE_DESC ((A_D)rangeAddr)
#define INPUT_DESC ((A_D)inputAddr)

#ifdef ADR_DEBUG
/* used for debugging code */
U32 inputStart, rangeStart;
   inputStart = INPUT_DESC->addrOffset;
   rangeStart = RANGE_DESC->addrOffset;
#endif
      
#ifndef ADR_UAE
   if ((0L == inputAddr) || (0L == rangeAddr))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (!RANGE_DESC->rangeActive)
      return ER_ADR_NOT_RANGE_TYPE;

   /* check for type */
   if (RANGE_DESC->type != ADDR_PHYSICAL) {
      if ((err = AddrToPhysical(rangeAddr,&physRangeStart)) != GOOD)
	 return err;
   }
   else
      physRangeStart = RANGE_DESC->addrOffset;
   if (INPUT_DESC->type != ADDR_PHYSICAL) {
      if ((err = AddrToPhysical(inputAddr,&inputStart)) != GOOD)
	 return err;
   }
   else
      inputStart = INPUT_DESC->addrOffset;

   /* test: input addr >= range start addr AND < range length) OR
   ** max length (rangeLength = 0 ==> 2^32 range size)  *
   ** *isInRange = (((inputStart >= physRangeStart) &&
   **    ((physRangeStart) + (RANGE_DESC->rangeLength)) > inputStart)
   **    || (!RANGE_DESC->rangeLength));
   */ 
   /* more efficient test : is range max range? (rangeLength == 0) OR
   ** is input descriptor outside the range?
   */
   *isInRange = (!RANGE_DESC->rangeLength ||
		 !((INPUT_DESC->addrOffset < RANGE_DESC->addrOffset) ||
		   (INPUT_DESC->addrOffset >=
		   (RANGE_DESC->addrOffset + RANGE_DESC->rangeLength))) );
   return GOOD;
} /* end of AdrIsPhysicalAddrInRange */

/****************************************************************************
**
**  AdrIsAddrRangeEqual
**
*****************************************************************************/
RETCODE EXPORT
AdrIsAddrRangeEqual(DESCRIPTOR rangeAddr1,
		    DESCRIPTOR rangeAddr2,
		    BOOLEAN FAR *isEqual)  {

#define RANGE_DESC1 ((A_D)rangeAddr1)
#define RANGE_DESC2 ((A_D)rangeAddr2)

#ifndef ADR_UAE
   if ((0L == rangeAddr1) || (0L == rangeAddr2))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((!RANGE_DESC1->rangeActive) || (!RANGE_DESC2->rangeActive))
      return ER_ADR_NOT_RANGE_TYPE;
   if (RANGE_DESC1->type != RANGE_DESC2->type) {
      return(ER_ADR_DIFFER_TYPES);
   }

#ifdef SPACE_CHECKED
   /* check for same space if 68K uP */
   if (FAMILY_68K == procFamily) {

      if ((SPACE_DONT_CARE == (RANGE_DESC1->space)) ||
	  (SPACE_DONT_CARE == (RANGE_DESC2->space))) {
      /* go to next block; skip else test */

      } else {
	//  if ((RANGE_DESC1->space) != (RANGE_DESC2->space)) {
	//     return ER_ADR_DIFFER_SPACES;
	 }
      }
   }
   else {
      if (RANGEDESC1->space != RANGE_DESC2->space)
	 return ER_ADR_DIFFER_SPACES;
      if ((RANGE_DESC1->type == ADDR_VIRTUAL) &&
	    (RANGE_DESC1->addrSegSel != RANGE_DESC2->addrSegSel))
	 return ER_ADR_DIFFER_SEGMENTS;
   }
#endif

   *isEqual = ((RANGE_DESC1->addrOffset == RANGE_DESC2->addrOffset) &&
       (RANGE_DESC1->rangeLength == RANGE_DESC2->rangeLength));
   return GOOD;
} /* end of AdrIsAddrRangeEqual */

/***************************************************************************
**
** AdrAdjustRange
**
***************************************************************************/
RETCODE EXPORT AdrAdjustRange(DESCRIPTOR desc, U32 numBytes,
			      U32 rangeLength,
			      ADDR_ADJ_RANGE_TYPE direction) {

   RETCODE err;
   U32 maxOffset = 0;
   U32 endRangeOffset = 0;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   switch (direction) {
      case ADDR_RANGE_LOW :
	 /* move range to low memory either numBytes or
	 ** as much as possible
	 */
	 if (AdrSubtractFromAddress(desc,numBytes) ==
	       ER_ADR_RESULT_UNDERFLOW) 
	    ((A_D)desc)->addrOffset = 0L;
	 break;
      case ADDR_RANGE_HIGH:
	 /* move range to high memory either numBytes or
	 ** as much as possible
	 */
	 if (AdrAddToAddress(desc,numBytes) == ER_ADR_RESULT_OVERFLOW) {
	    if ((err = AdrGetMaxOutputAddrOffset(desc,&maxOffset)) != GOOD)
	       return err;
	    ((A_D)desc)->addrOffset = maxOffset -
				       ((A_D)desc)->rangeLength + 1;
	 }
	 break;
      case ADDR_RANGE_EXPAND_LOW:
	 /* expand range towards low memory by numBytes or
	 ** as much as possible.
	 */
	 if (AdrSubtractFromAddress(desc,numBytes) == 
	       ER_ADR_RESULT_UNDERFLOW) {
	    endRangeOffset = ((A_D)desc)->addrOffset +
				       ((A_D)desc)->rangeLength - 1;
	    ((A_D)desc)->addrOffset = 0L;
	    ((A_D)desc)->rangeLength = endRangeOffset + 1;
	 }
	 break;
      case ADDR_RANGE_EXPAND_HIGH:
	 /* expand range towards high memory by numBytes or
	 ** as much as possible
	 */
	 if (AdrSetAddrRangeLength(desc,
	       ((A_D)desc)->rangeLength+numBytes) ==
	       ER_ADR_ADDRESS_TOO_LARGE) {
	    if ((err = AdrGetMaxOutputAddrOffset(desc,&maxOffset)) != GOOD)
	       return err;
	    ((A_D)desc)->rangeLength = maxOffset - ((A_D)desc)->addrOffset
		  + 1;
	 }
	 break;
      case ADDR_RANGE_EXPAND_BOTH:
	 if (AdrSubtractFromAddress(desc,numBytes) ==
		ER_ADR_RESULT_UNDERFLOW) {
	    endRangeOffset = ((A_D)desc)->addrOffset +
				       ((A_D)desc)->rangeLength - 1;
	    ((A_D)desc)->addrOffset = 0L;
	 }
	 if (AdrSetAddrRangeLength(desc,
	       ((A_D)desc)->rangeLength+(numBytes*2)) ==
	       ER_ADR_ADDRESS_TOO_LARGE) {
	    if (((A_D)desc)->addrOffset == 0L) { /* go for max range */
	       if ((err = AdrSetAddrRangeLength(desc,0)) != GOOD)
		  return err;
	    }
	    else  {
	       if ((err = AdrGetMaxOutputAddrOffset(desc,&maxOffset))
		      != GOOD)
		  return err;
	       ((A_D)desc)->rangeLength = maxOffset -
		     ((A_D)desc)->addrOffset + 1;
	    }
	 }
	 break;
   }
   ((A_D)desc)->rangeActive = TRUE;
   /* if not a max range and not maxed out on the high end and there was
   ** more range requested go ahead and give it
   */
   if ((rangeLength != 0) && (maxOffset == 0) &&
	 (((A_D)desc)->rangeLength < rangeLength))
      if ((err = AdrSetAddrRangeLength(desc,rangeLength)) != GOOD)
	 return err;
   return GOOD;
}

/****************************************************************************
**
** AdrIsValidCodeAddress
**
*****************************************************************************/
RETCODE EXPORT
AdrIsValidCodeAddress(DESCRIPTOR  desc,
		      BOOLEAN FAR *isValid)  {

   U32 maxInputAddr;
   RETCODE err;
#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((err = AdrGetMaxInputAddrOffset(desc,&maxInputAddr)) != GOOD)
      return err;
   *isValid = TRUE;
   if ((((A_D)desc)->addrOffset) & staticMask) { /* ls addr bits not 0; err */
      *isValid = FALSE;
   }
   if ((((A_D)desc)->addrOffset) > maxInputAddr) {
      *isValid = FALSE;
      return ER_ADR_ADDRESS_TOO_LARGE;
   }
   return GOOD;
}  /* end of AdrIsValidCodeAddress */

/****************************************************************************
**
** AdrDoRangesOverlap
**
**   If either address is NOT a range, FALSE is returned
**
*****************************************************************************/
RETCODE EXPORT AdrDoRangesOverlap(DESCRIPTOR range1,
				  DESCRIPTOR range2,
				  BOOLEAN FAR *overlap) {

   U32 startAddr1, endAddr1;
   U32 startAddr2, endAddr2;
   
#define RANGE_1 ((A_D)range1)
#define RANGE_2 ((A_D)range2)

   *overlap = FALSE;    /* default return value */
#ifndef ADR_UAE
   if ((0L == range1) || (0L == range2))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ( (!RANGE_1->rangeActive) || (!RANGE_2->rangeActive) ||
	(0L == (RANGE_1->rangeLength)) || (0L == (RANGE_2->rangeLength)) ) {
      return GOOD;
   }
   if (RANGE_1->type != RANGE_2->type)
      return ER_ADR_DIFFER_TYPES;
//   if (RANGE_1->space != RANGE_2->space)
//      return ER_ADR_DIFFER_SPACES;
   if ((RANGE_1->type == ADDR_VIRTUAL) &&
	  (RANGE_1->addrSegSel != RANGE_2->addrSegSel))
      return ER_ADR_DIFFER_SEGMENTS;

   /* note: subtract 1 from range length first to prevent underflow;
   ** range length always 1 or greater
   */
   startAddr1 = RANGE_1->addrOffset;
   endAddr1   = startAddr1 + ((RANGE_1->rangeLength) - 1);
   startAddr2 = RANGE_2->addrOffset;
   endAddr2   = startAddr2 + ((RANGE_2->rangeLength) - 1);

   /*
   ** Ranges are overlapped if they meet one of the 5 conditions below:
   ** 1.  r1 [---------]
   **     r2 [---------]
   **
   ** 2.  r1 [---------]
   **     r2     [---------]
   **
   ** 3.  r1     [---------]
   **     r2 [----------]
   **
   ** 4.  r1     [-----]
   **     r2  [------------]
   **
   ** 5.  r1  [-------------]
   **     r2     [------]
   */
   /* handle both (range1 < range2) || (range1 > range2) */
   *overlap = ((startAddr1 <= startAddr2) ?
	       (!(endAddr1 < startAddr2) || (endAddr2 < startAddr1)) :
	       (!(endAddr2 < startAddr1) || (endAddr1 < startAddr2)));

   return GOOD;
}  /* end of AdrDoRangesOverlap */

/****************************************************************************
**
** AdrDoPhysicalRangesOverlap
**
**   If either address is NOT a range, FALSE is returned
**
*****************************************************************************/
RETCODE EXPORT AdrDoPhysicalRangesOverlap(DESCRIPTOR range1,
					  DESCRIPTOR range2,
					  BOOLEAN FAR *overlap) {
   U32 startAddr1, endAddr1;
   U32 startAddr2, endAddr2;
   RETCODE err;

#define RANGE1 ((A_D)range1)
#define RANGE2 ((A_D)range2)

   *overlap = FALSE;    /* default return value */
#ifndef ADR_UAE
   if ((0L == range1) || (0L == range2))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ( (!RANGE1->rangeActive) || (!RANGE2->rangeActive) ||
	(0L == (RANGE1->rangeLength)) || (0L == (RANGE2->rangeLength)) ) {
      return GOOD;
   }
   
   /* Convert to physical addresses before check ranges overlap */
   if (RANGE1->type != ADDR_PHYSICAL) {
      if ((err = AddrToPhysical(range1,&startAddr1)) != GOOD)
	 return err;
   }
   else
      startAddr1 = RANGE1->addrOffset;
   /* compute the end address of range1 */
   endAddr1 = startAddr1 + ((RANGE1->rangeLength) - 1);
   
   if (RANGE2->type != ADDR_PHYSICAL) {
      if ((err = AddrToPhysical(range2,&startAddr2)) != GOOD)
	 return err;
   }
   else
      startAddr2 = RANGE2->addrOffset;
   /* compute the end address of range2 */
   endAddr2 = startAddr2 + ((RANGE2->rangeLength) - 1);

   /* Notes: subtract 1 from range length first to prevent underflow 
   ** range length always 1 or greater
   */
   /*
   ** Ranges are overlapped if they meet one of the 5 conditions below:
   ** 1.  r1 [---------]
   **     r2 [---------]
   **
   ** 2.  r1 [---------]
   **     r2     [---------]
   **
   ** 3.  r1     [---------]
   **     r2 [----------]
   **
   ** 4.  r1     [-----]
   **     r2  [------------]
   **
   ** 5.  r1  [-------------]
   **     r2     [------]
   */
   /* handle both (range1 < range2) || (range1 > range2) */
   *overlap = ((startAddr1 <= startAddr2) ?
	       (!(endAddr1 < startAddr2) || (endAddr2 < startAddr1)) :
	       (!(endAddr2 < startAddr1) || (endAddr1 < startAddr2)));
   return GOOD;

}  /* end of AdrDoPhysicalRangesOverlap */

/****************************************************************************
**
**  AdrRemainingBytesInRange
**
*****************************************************************************/
RETCODE EXPORT AdrRemainingBytesInRange(DESCRIPTOR rangeDesc,
					DESCRIPTOR inputDesc,
					U32 FAR *numBytes) {
   RETCODE err;
   U32 endRangeOffset;
   BOOLEAN isInRange = FALSE;

#ifndef ADR_UAE
   if ((rangeDesc == 0L) || (inputDesc == 0L))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((err = AdrIsAddrInRange(inputDesc, rangeDesc,&isInRange)) != GOOD)
      return err;
   if (isInRange) {
      if ((err = AdrGetEndAddrOffset(rangeDesc,&endRangeOffset)) != GOOD)
	 return err;
      *numBytes = endRangeOffset - ((A_D)inputDesc)->addrOffset + 1;
   }
   else
      *numBytes = ((A_D)rangeDesc)->rangeLength;                            

   return(GOOD);
}

/****************************************************************************
**
**  AdrRemainingBytes
**
*****************************************************************************/
RETCODE EXPORT AdrRemainingBytes(DESCRIPTOR desc, U32 FAR *numBytes) {

   U32 maxInputAddr;
   RETCODE err;


#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((err = AdrGetMaxInputAddrOffset(desc,&maxInputAddr)) != GOOD)
      return err;
   if (((A_D)desc)->addrOffset == 0) { 
      *numBytes = 0;            /* 0 represents max value */
   } else {
      *numBytes = maxInputAddr - ((A_D)desc)->addrOffset + 1;
   }
   return(GOOD);
}


/****************************************************************************
**
**  AdrCopyAddress
**
*****************************************************************************/
RETCODE EXPORT AdrCopyAddress(DESCRIPTOR sourceDesc,
			      DESCRIPTOR FAR destinationDesc) {

#ifndef ADR_UAE
   if ((0L == sourceDesc) || (0L == destinationDesc))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (sourceDesc == destinationDesc)
      return ER_ADR_INVALID_DESCRIPTOR;
   memcpy((A_D)destinationDesc, (A_D)sourceDesc, sizeof(ADDR_DESCRIPTOR));
   return(GOOD);
}  /* end of AdrCopyAddress */


/****************************************************************************
**
**  AdrDuplicateAddress
**
*****************************************************************************/
RETCODE EXPORT AdrDuplicateAddress(DESCRIPTOR desc1,
				   DESCRIPTOR FAR *desc2) {

   RETCODE err;

#ifndef ADR_UAE
   if (0L == desc1)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if((err = AdrCreateAddress(desc2))!=GOOD)
      return(err);
   memcpy((A_D)*desc2, (A_D)desc1, sizeof(ADDR_DESCRIPTOR));
   return(GOOD);
}

/****************************************************************************
**
** AdrConvertAddress
**
*****************************************************************************/
RETCODE EXPORT AdrConvertAddress(DESCRIPTOR desc, ADDR_TYPE type,
				 BOOLEAN FAR *rangeCovered) {
   RETCODE err = GOOD;
   U32 newOffset;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   *rangeCovered = TRUE;
   switch (((A_D)desc)->type) {
      case ADDR_VIRTUAL:
	 if (type == ADDR_LINEAR) {
	    /* virtual -> linear */
	    if ((err = AddrToLinear(desc,&newOffset)) != GOOD)
	       return err;
	 }
	 else if (type == ADDR_PHYSICAL) {
	    /* virtual -> linear -> physical */
	   if ((err = AddrToPhysical(desc,&newOffset)) != GOOD)
	      return err;
	 }
	 else
	    return GOOD;
	 ((A_D)desc)->type = type;
	 if ((err = AdrSetAddrOffset(desc,newOffset)) != GOOD)
	    return err;
	 break;
      case ADDR_LINEAR:
	 if (type == ADDR_VIRTUAL)  {
	    *rangeCovered = FALSE;
	    return ER_ADR_LINEAR_TO_VIRTUAL_INVALID; /* phase 3 */
	 }
	 else if (type == ADDR_PHYSICAL) {
	    /* linear -> physical */
	    if ((err =  AddrToPhysical(desc,&newOffset)) != GOOD)
	       return err;
	 }
	 else
	    return GOOD;
	 ((A_D)desc)->type = type;
	 if ((err = AdrSetAddrOffset(desc,newOffset)) != GOOD)
	    return err;
	 break;
      case ADDR_PHYSICAL:
	 if ((type == ADDR_LINEAR) || (type == ADDR_VIRTUAL)) {
	    *rangeCovered = FALSE;
	    return ER_ADR_PHYS_TO_LINEAR_NOT_SUPPORTED;
	 }
	 else
	    return GOOD;
   }
   return GOOD;
}

/****************************************************************************
**
**  AdrConvertPointerToAddress
**
**  ** NOTE: There are two kinds of Intel 4 byte pointers, 16:16 and
**           32 bit offset.  Not sure right now how to handle this.
**           Probably some clues in OMF386 loader.  May have to modify
**           the interface to include pointer type in conjunction with
**           pointer size.  Worry about it in phase 2.
**
*****************************************************************************/
RETCODE EXPORT AdrConvertPointerToAddress(DESCRIPTOR desc, U8 pointerSize) {

   RETCODE err;
   U32 offsetValue=0;
   U16 segmentValue=0;
   CHAR buf[6];
   U32 maxInputAddr;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (!((pointerSize == 2) || (pointerSize == 4) || (pointerSize == 6)))
      return ER_ADR_INVALID_PTR_SIZE;
   if ((err = AdrGetMaxInputAddrOffset(desc,&maxInputAddr)) != GOOD)
      return err;

   /* get the pointer value out of target memory */
   memset(buf,'\0',6);
   if ((err = MemReadSizedNoAlloc(desc, (U16)pointerSize,(U8*)buf,
	 BYTE_SIZE, CACHE_USE)) != GOOD)
      return(err);
   switch (pointerSize) {
      case 2:
	 offsetValue = MemSwapBytesInWord(*(U16 *)buf);
	 break;
      case 4:
	 offsetValue = MemSwapBytesInLong(*(U32 *)buf);
	 break;
      case 6:
	 offsetValue = MemSwapBytesInLong(*(U32 *)buf);
	 segmentValue = MemSwapBytesInWord(*(U16 *)(buf +
					   sizeof(offsetValue)));
	 break;
   }
   /* check for greater than max address */
   if (offsetValue > maxInputAddr) {  /* don't save address if invalid */
      return(ER_ADR_ADDRESS_TOO_LARGE);
   } else {
      /* put address back into original descriptor */
      ((A_D)desc)->addrOffset = offsetValue;
      ((A_D)desc)->addrSegSel = segmentValue;
      if (segmentValue != 0)
	 ((A_D)desc)->segSelType = ADDR_USE_VALUE;
   }
   return(GOOD);
}  /* end of AdrConvertPointerToAddress */

/****************************************************************************
**
**  AdrSetRangeActive
**
*****************************************************************************/
RETCODE EXPORT AdrSetRangeActive(DESCRIPTOR desc, BOOLEAN active) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   ((A_D)desc)->rangeActive = active;
   return(GOOD);
}

/****************************************************************************
**
**  AdrGetRangeActive
**
*****************************************************************************/
RETCODE EXPORT AdrGetRangeActive(DESCRIPTOR desc, BOOLEAN FAR *active) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   *active = ((A_D)desc)->rangeActive;
   return(GOOD);
}

/****************************************************************************
**
**  AdrSetEndAddrOffset
**
*****************************************************************************/
RETCODE EXPORT AdrSetEndAddrOffset(DESCRIPTOR desc, U32 offset) {

   RETCODE err;
   U32 maxInputAddr;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((err = AdrGetMaxInputAddrOffset(desc,&maxInputAddr)) != GOOD)
      return err;
   if (((A_D)desc)->addrOffset > offset)
      return(ER_ADR_END_ADDR_TOO_SMALL);

   /* check that it doesn't go over max address boundary */
   if (offset > maxInputAddr)
      return ER_ADR_ADDRESS_TOO_LARGE;
   ((A_D)desc)->rangeLength = offset - ((A_D)desc)->addrOffset + 1;
   ((A_D)desc)->rangeActive = TRUE;
   return(GOOD);
}

/****************************************************************************
**
**  AdrGetEndAddrOffset
**
*****************************************************************************/
RETCODE EXPORT AdrGetEndAddrOffset(DESCRIPTOR desc, U32 FAR *offset) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   *offset = ((A_D)desc)->addrOffset + ((A_D)desc)->rangeLength - 1;
   return(GOOD);
}

/****************************************************************************
**
**  AdrSetAddrRangeLength
**
*****************************************************************************/
RETCODE EXPORT AdrSetAddrRangeLength(DESCRIPTOR desc, U32 numBytes) {

   U32 rangeMinusOne;
   RETCODE err;
   U32 maxInputAddr;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((err = AdrGetMaxInputAddrOffset(desc,&maxInputAddr)) != GOOD)
      return err;
   /* 0 range is max; start address must be 0 for this range to be valid */
   if ((numBytes == 0L) && (((A_D)desc)->addrOffset != 0L))
      return ER_ADR_ADDRESS_TOO_LARGE;

   rangeMinusOne = numBytes - 1;
      /* now matches maxInputAddr in representation */
   /* check that it doesn't go over max address boundary */
   if (rangeMinusOne > maxInputAddr)
      return ER_ADR_ADDRESS_TOO_LARGE;

   if ((((A_D)desc)->addrOffset + rangeMinusOne) > maxInputAddr)
      return ER_ADR_ADDRESS_TOO_LARGE;

   /* check for wrap-around condition of start address + range */
   if (max(((A_D)desc)->addrOffset, rangeMinusOne) < rangeMinusOne)
      return ER_ADR_ADDRESS_TOO_LARGE;
   ((A_D)desc)->rangeLength = numBytes;
   ((A_D)desc)->rangeActive = TRUE;
   return(GOOD);
}

/****************************************************************************
**
**  AdrGetAddrRangeLength
**
*****************************************************************************/
RETCODE EXPORT AdrGetAddrRangeLength(DESCRIPTOR desc, U32 FAR *numBytes) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   *numBytes = ((A_D)desc)->rangeLength;
   return(GOOD);
}

/****************************************************************************
**
**  AdrSetAddrOffset
**
*****************************************************************************/
RETCODE EXPORT AdrSetAddrOffset(DESCRIPTOR desc, U32 offset) {

   RETCODE err;
   U32 maxInputAddr;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((err = AdrGetMaxInputAddrOffset(desc,&maxInputAddr)) != GOOD)
      return err;
   if (offset > maxInputAddr)
      return ER_ADR_ADDRESS_TOO_LARGE;
   ((A_D)desc)->addrOffset = offset;
   return(GOOD);
}

/****************************************************************************
**
**  AdrGetAddrOffset
**
*****************************************************************************/
RETCODE EXPORT AdrGetAddrOffset(DESCRIPTOR desc, U32 FAR *offset) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   *offset = ((A_D)desc)->addrOffset;
   return(GOOD);
}

/****************************************************************************
**
**  AdrGetAddrSegmentSelector
**
*****************************************************************************/
RETCODE EXPORT
AdrGetAddrSegmentSelector(DESCRIPTOR desc,
			  ADDR_SEGSEL_TYPE *type,
			  U32 *segsel) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (FAMILY_68K == procFamily)
      return(ER_ADR_NOT_MOTOROLA_USAGE);
   else {
     *type = ((A_D)desc)->segSelType;
     *segsel = ((A_D)desc)->addrSegSel;
   }
   return GOOD;
}

/****************************************************************************
**
**  AdrSetAddrSegmentSelector
**
*****************************************************************************/
RETCODE EXPORT
AdrSetAddrSegmentSelector(DESCRIPTOR desc,
			  ADDR_SEGSEL_TYPE type,
			  U32 segsel) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if (FAMILY_68K == procFamily)
      return(ER_ADR_NOT_MOTOROLA_USAGE);
   else {
     ((A_D)desc)->segSelType = type;
     ((A_D)desc)->addrSegSel = segsel;
   }
   return GOOD;
}

/**************************************************************************
**
** AdrGetMaxInputAddrOffset
**
************************************************************************/
RETCODE EXPORT AdrGetMaxInputAddrOffset(DESCRIPTOR desc,
					U32 FAR *maxInputAddress)  {
   RETCODE err;
   PROBE_TYPE proc;
   U32 min;
   
   if ((err = ProcReturnSpecificProcessor(&proc)) != GOOD)
      return err;
   switch (cpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
	 *maxInputAddress = 0xFFFFFFFFL;
	 break;
      case PROC_CPU_CPU16:
	 *maxInputAddress = 0x000FFFFFL;
	 break;
      case PROC_CPU_68000:
           if (proc == M68302_MP || proc == M68307_MP || proc == M68328_MP)
	    *maxInputAddress = 0x00FFFFFFL;
	 else
	    *maxInputAddress = 0xFFFFFFFFL;
	 break;
      case PROC_CPU_68040:
	 break;
      case PROC_CPU_80186:
#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
	 break;
      case PROC_CPU_80386:
#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
	 switch (((A_D)desc)->type) {
	    case ADDR_VIRTUAL:
	       switch (((A_D)desc)->mode) {
		  case MODE_SMM:
		     *maxInputAddress = 0xFFFFFFFFL;
		     break;
		  case MODE_REAL:
		  case MODE_V86:
		     *maxInputAddress = 0x0000FFFFL;
		     break;
		  case MODE_PROT16:
		  case MODE_PROT32:  /* segment limit */
		     if ((err = GetSegmentLimits(desc,&min,maxInputAddress))
			    != GOOD)
			return err;
		     break;
		  }
	       break;
	    case ADDR_LINEAR:
	       *maxInputAddress = 0xFFFFFFFFL;
	       break;
	    case ADDR_PHYSICAL:
	       switch (proc) {
		  case I80386DX_TB: case I80386DX_SH:
		     *maxInputAddress = 0xFFFFFFFFL;
		     break;
		  case I80386SX_TB: case I80386SX_SH:
		     *maxInputAddress = 0x00FFFFFFL;
		     break;
		  case I80386CX_TB: case I80386CX_SH:
		  case I80386EX_TB: case I80386EX_SH:
		     *maxInputAddress = 0x03FFFFFFL;
		     break;
	       }
	       break;
	 }
	 break;
      case PROC_CPU_80486:
#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
	 break;
   }
   return GOOD;
}


/**************************************************************************
**
** AdrGetMaxOutputAddrOffset
**
*************************************************************************/
RETCODE EXPORT AdrGetMaxOutputAddrOffset(DESCRIPTOR desc,
					 U32 FAR *maxOutputAddress)  {
   RETCODE err;
   PROBE_TYPE proc;

   switch (cpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
           *maxOutputAddress = 0xFFFFFFFFL;
	 break;
      default:
	 return AdrGetMaxInputAddrOffset(desc, maxOutputAddress);
   }
   return GOOD;
}

/**************************************************************************
**
** AdrGetMaxOutputAddress
**
***************************************************************************/
RETCODE EXPORT AdrGetMaxOutputAddress(DESCRIPTOR desc,
				      DESCRIPTOR FAR *maxDesc) {
   RETCODE err;
   U32 maxOffset;

   if ((err = AdrDuplicateAddress(desc,maxDesc)) != GOOD)
      return err;
   if ((err = AdrGetMaxOutputAddrOffset(desc,&maxOffset)) != GOOD)
      return err;
   ((A_D)maxDesc)->addrOffset = maxOffset;
   return GOOD;
}

/*************************************************************************
**
** AdrGetMaxInputAddrDigits
**
*************************************************************************/
RETCODE EXPORT AdrGetMaxInputAddrDigits(DESCRIPTOR desc,
					U16 FAR *maxInputAddrDigits)  {
   RETCODE err;
   PROBE_TYPE proc;

   if ((err = ProcReturnSpecificProcessor(&proc)) != GOOD)
      return err;
   switch (cpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
	 *maxInputAddrDigits = 8;
	 break;
      case PROC_CPU_CPU16:
	 *maxInputAddrDigits = 5;
	 break;
      case PROC_CPU_68000:
           if (proc == M68302_MP || proc == M68307_MP || proc == M68328_MP)
	    *maxInputAddrDigits = 6;
	 else
	    *maxInputAddrDigits = 8;
	 break;
      case PROC_CPU_68040:
	 break;
      case PROC_CPU_80186:
#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
	 break;
      case PROC_CPU_80386:
#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
	 switch (((A_D)desc)->type) {
	    case ADDR_VIRTUAL:
	       switch (((A_D)desc)->mode) {
		  case MODE_SMM:
		     *maxInputAddrDigits = 13;
		     break;
		  case MODE_REAL:
		  case MODE_V86:
		     *maxInputAddrDigits = 9;
		     break;
		  case MODE_PROT16:
		     *maxInputAddrDigits = 9;
		     break;
		  case MODE_PROT32:
		     *maxInputAddrDigits = 13;
		     break;
		  }
	       break;
	    case ADDR_LINEAR:
	       *maxInputAddrDigits = 8;
	       break;
	    case ADDR_PHYSICAL:
	       switch (proc) {
		  case I80386DX_TB: case I80386DX_SH:
		     *maxInputAddrDigits = 8;
		     break;
		  case I80386SX_TB: case I80386SX_SH:
		     *maxInputAddrDigits = 6;
		     break;
		  case I80386CX_TB: case I80386CX_SH:
		  case I80386EX_TB: case I80386EX_SH:
		     *maxInputAddrDigits = 7;
		     break;
	       }
	       break;
	 }
	 break;
      case PROC_CPU_80486:
#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
	 break;

      }
   return GOOD;
}


/*************************************************************************
**
** AdrGetMaxOutputAddrDigits
**
************************************************************************/
RETCODE EXPORT AdrGetMaxOutputAddrDigits(DESCRIPTOR desc,
					 U16 FAR *maxOutputAddrDigits)  {
   RETCODE err;
   PROBE_TYPE specificProcessor;
   
   switch (cpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
	 if ((err = ProcReturnSpecificProcessor(&specificProcessor))
		!= GOOD) return(err);
	 switch (specificProcessor) {
	    case M68307_MP: case M68328_MP:
              case M68302_MP:
	       *maxOutputAddrDigits = 6;
	       break;
	    default:
	       *maxOutputAddrDigits = 8;
	       break;
	 }
	 break;
      default:
	 return AdrGetMaxInputAddrDigits(desc, maxOutputAddrDigits);
   }
   return GOOD;
}

/*************************************************************************
**
** AdrMaskAddrMSB
**
************************************************************************/
RETCODE EXPORT AdrMaskAddrMSB(DESCRIPTOR desc) {
   RETCODE err;
   U32 offset, maxInputAddr;

   if ((err = AdrGetAddrOffset(desc, &offset)) != GOOD)
      return err;
   /* check for odd address boundary */
   if ((offset % 2) != 0)
      return ER_ADDR_ODD_ADDRESS;
   
   if ((err = AdrGetMaxInputAddrOffset(desc,&maxInputAddr)) != GOOD)
      return err;
   
   /* mask off the upper bits and set the new offset */
   if ((err = AdrSetAddrOffset(desc, (offset & maxInputAddr))) != GOOD)
      return err;
   /* change the end offset as well */    
   if (((A_D)desc)->rangeActive) {
      if ((err = AdrGetEndAddrOffset(desc, &offset)) != GOOD)
	 return err;
      if ((err = AdrSetEndAddrOffset(desc, (offset & maxInputAddr))) != GOOD)
	 return err;
   }         
   return(GOOD);
}

/*************************************************************************
**
**  AdrCallback :
**
**  Return function for event callback.
**
****************************************************************************/
RETCODE EXPORT AdrCallback(U32 eventNum) {

   switch (eventNum) {
      case EVENT_BKPT_HALTED:
	 // Read SD_PMODE to update
	 // SdnReadMember(PMODE)
	 // if (SdnReadMember(SDN_PMODE,(LPU8)&pMode) != GOOD)
	 //   pMode = PMODE_END;
	 pMode = PMODE_REAL;   /* phase 1 REAL mode only */
	 break;
   }
   return GOOD;
}             

/****************************************************************************
**
** AdrGetPmode
**
***************************************************************************/
RETCODE EXPORT AdrGetPmode(PMODE FAR *pmode, LPSTR pmodeStr) {

   *pmode = pMode;
   *pmodeStr = '\0';
   switch (pMode) {
      case PMODE_REAL:
	 strcpy(pmodeStr,"REAL");
	 break;
      case PMODE_V86:
	 strcpy(pmodeStr,"V86");
	 break;
      case PMODE_P16:
	 strcpy(pmodeStr,"PROT16");
	 break;
      case PMODE_P32:
	 strcpy(pmodeStr,"PROT32");
	 break;
      case PMODE_SMM:
	 strcpy(pmodeStr,"SMM");
	 break;
      case PMODE_END:
	 strcpy(pmodeStr,"NONE");
	 break;
   }
   return GOOD;
}

/****************************************************************************
**                        PRIVATE ROUTINES                                 **
****************************************************************************/

/*************************************************************************
**
** GetSegSelFromText
**
**************************************************************************/
RETCODE PRIVATE GetSegSelFromText(LPSTR segSelStr, U32 *segment) {

   LPSTR typePtr;
   U32 localAddr;
   S8 *endPtr;

   *segment = 0L;
   if (segSelStr == NULL) 
      return ER_ADR_INVALID_ADDRESS_STR;
   if ((typePtr = _fstrpbrk(segSelStr,"Gg")) != NULL) {
      /* GDT index */
      *typePtr = '\0';
      localAddr = strtoul(segSelStr, &endPtr, 0);   /* decimal indexed */
      if (*endPtr != 0)
	 return ER_ADR_INVALID_ADDRESS_STR;
      *segment = ((localAddr << 3) + GDT_INDICATOR);
   }
   else if ((typePtr = _fstrpbrk(segSelStr,"Ll")) != NULL) {
      /* LDT index */
      *typePtr = '\0';
      localAddr = strtoul(segSelStr, &endPtr, 0);   /* decimal indexed */
      if (*endPtr != 0)
	 return ER_ADR_INVALID_ADDRESS_STR;
      *segment = ((localAddr << 3) + LDT_INDICATOR);
   }
   else {
      localAddr = strtoulDefRadix(segSelStr, &endPtr);
      if (*endPtr != 0)
	 return ER_ADR_INVALID_ADDRESS_STR;
      *segment = localAddr;
   }
   return GOOD;
}

/****************************************************************************
**
** GetSegmentDescCopy
**
***************************************************************************/
RETCODE PRIVATE GetSegmentDescCopy(DESCRIPTOR desc,
				   SEGMENT_DESCRIPTOR *segDesc) {
   RETCODE err;
   U32 tableBase;
   U32 tableLimit;
   U32 index;
   U32 segment;
   DESCRIPTOR addr;
   U32 segDescOffset;
   BOOLEAN rangeCovered;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   /* mask out 13 bit descriptor table index */
   if ((err = GetSegment(desc,&segment)) != GOOD)
      return err;
   index = (segment & TABLE_INDEX_MASK) >> 3;
   /* examine segment selector to determine GDT or LDT */
   if ((segment & TABLE_INDICATOR_MASK) == LDT_INDICATOR) {
      if (((A_D)desc)->ldt != 0) {
	 /* use specified ldt */
	 tableBase = ((A_D)desc)->ldt;
      }
      else {
	 /* use current LDTR value */
	 if ((err = CpuGetRegister(LDTBaseId,&tableBase)) != GOOD)
	    return err;
      }
      if (tableBase == 0)
	 return ER_ADR_LDT_INVALID;
      if ((err = CpuGetRegister(LDTLimitId,&tableLimit)) != GOOD)
	 return err;
   }
   else {
      /* use GDTR */
      if (index == 0)  /* NULL descriptor */
	 return ER_ADR_NULL_GDT_DESCRIPTOR;
      if ((err = CpuGetRegister(GDTBaseId,&tableBase)) != GOOD)
	 return err;
      if ((err = CpuGetRegister(GDTLimitId,&tableLimit)) != GOOD)
	 return err;
   }
   /* calculate descriptor location in table */
   segDescOffset = ((index * sizeof(SEGMENT_DESCRIPTOR)) + tableBase);
   /* check for an offset beyond LDT or GDT limits */
   if (segDescOffset > (tableBase + tableLimit - sizeof(SEGMENT_DESCRIPTOR)))
      return ER_ADR_DESCTBL_LIMIT_EXCEEDED;

   /* Set up address to read target memory */
   if ((err = AdrCreateAddressWithType(ADDR_LINEAR,&addr)) != GOOD)
      return err;
   if ((err = AdrSetAddrOffset(addr,segDescOffset)) != GOOD)
      return err;
   /* might as well do it now so mem doesn't call back */
   if ((err = AdrConvertAddress(addr,ADDR_PHYSICAL,&rangeCovered)) != GOOD)
      return err;
   if ((err = MemReadSizedNoAlloc(addr,sizeof(SEGMENT_DESCRIPTOR),
	 (LPU8)segDesc, BYTE_SIZE, CACHE_BYPASS)) != GOOD)
      return err;
   if ((err = AdrDestroyAddress(addr)) != GOOD)
      return err;
   return GOOD;

}

/****************************************************************************
**
** GetSegmentBase 
**
***************************************************************************/
RETCODE PRIVATE GetSegmentBase(DESCRIPTOR desc,U32 *base) {

   SEGMENT_DESCRIPTOR segDesc;
   RETCODE err;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   /* find base address for segment */
   if ((err = GetSegmentDescCopy(desc,&segDesc)) != GOOD)
      return err;
   if (!segDesc.segmentPresent)
      return ER_ADR_SEGMENT_INVALID;
   if (segDesc.descType == CODE_OR_DATA_SEGMENT)
      *base = ((segDesc.base31_24 << 24)+(segDesc.base23_16 << 16)+
	    segDesc.base15_0);
   else
      return ER_ADR_SEGMENT_USE_INVALID;
   return GOOD;
}

/****************************************************************************
**
** GetSegmentLimits 
**
***************************************************************************/
RETCODE PRIVATE GetSegmentLimits(DESCRIPTOR desc, U32 *minLimit,
				 U32 *maxLimit) {

   SEGMENT_DESCRIPTOR segDesc;
   U32 tmpLimit = 0;
   RETCODE err;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   /* find limit for segment */
   if ((err = GetSegmentDescCopy(desc,&segDesc)) != GOOD)
      return err;
   tmpLimit = ((segDesc.limit19_16 << 16) + segDesc.limit15_0);
   /* check for expand down data segment */
   if ((segDesc.segmentType & EXPAND_DN_SEG_MASK) == EXPAND_DN_SEG) { 
      *minLimit = (segDesc.granularity ? ((tmpLimit << 12) + 0xFFF)+1
	    : tmpLimit+1);
      *maxLimit = 0xFFFFFFFFL;
   }
   else {
      *minLimit = 0L;
      *maxLimit = (segDesc.granularity ? ((tmpLimit << 12) + 0xFFF)
	    : tmpLimit);
   }
   return GOOD;
}


/****************************************************************************
**
** RealToLinear : address offset translation for Intel
**
***************************************************************************/
RETCODE PRIVATE RealToLinear(DESCRIPTOR desc, U32 *linearAddr) {

   U32 segmentBase;
   RETCODE err;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   if ( (GetPmode(((A_D)desc)->mode) == PMODE_REAL) &&
	 (((A_D)desc)->addrOffset > 0x0000FFFFL) )
      return ER_ADR_EXCEEDS_ADR_LIMIT;
   if ((err = GetSegment(desc,&segmentBase)) != GOOD)
      return err;
   *linearAddr = (segmentBase << 4) + ((A_D)desc)->addrOffset;
   return GOOD;
}

/****************************************************************************
**
** ProtToLinear : address offset translation for Intel
**
***************************************************************************/
RETCODE PRIVATE ProtToLinear(DESCRIPTOR desc, U32 *linearAddr) {

   U32 segmentBase;
   U32 minOffset,maxOffset;
   RETCODE err;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   else {
      if ((err = GetSegmentBase(desc,&segmentBase)) != GOOD)
	 return err;
      if ((err = GetSegmentLimits(desc,&minOffset,&maxOffset)) != GOOD)
	 return err;
      if ( (((A_D)desc)->addrOffset >= minOffset) &&
	   (((A_D)desc)->addrOffset <= maxOffset) )
	 *linearAddr = segmentBase + ((A_D)desc)->addrOffset;
      else
	 return ER_ADR_EXCEEDS_SEG_LIMIT;
   }
   return GOOD;
}

/****************************************************************************
**
** LinearToPhysical : address offset translation for Intel
**
***************************************************************************/
RETCODE  PRIVATE LinearToPhysical(U32 linearAddr, U32 *physAddr) {

   DESCRIPTOR addr;
   RETCODE err;
   U32 directoryBase;
   U32 directoryEntry;
   U32 tableBase;
   U32 tableEntry;
   U32 pageFrame;
   U32 directoryIndex,    /* linear address 10 bit directory index */
       tableIndex,        /* linear address 10 bit table index */
       offset;            /* linear address 12 bit page frame offset */

   /* break apart the linear address into its parts */
   offset = linearAddr & 0x00000FFFL;
   tableIndex = (linearAddr & 0x003FFFFFL) >> 12;
   directoryIndex = linearAddr >> 22;
   /* Find page directory entry */
   if ((err = CpuGetRegister(CR3regId,&directoryBase)) != GOOD)
      return err;
   /* concatenate with scaled index */
   directoryEntry = (directoryBase & 0xFFFFF000L) +
	 (directoryIndex * sizeof(directoryEntry));
   /* Read entry in page directory */
   if ((err = AdrCreateAddressWithType(ADDR_PHYSICAL,&addr)) != GOOD)
      return err;
   if ((err = AdrSetAddrOffset(addr, directoryEntry)) != GOOD) {
      AdrDestroyAddress(addr);
      return err;
   }
   if ((err = MemReadSizedNoAlloc(addr,sizeof(U32),(LPU8)&tableBase,
	 BYTE_SIZE,CACHE_USE_AND_LOCK)) != GOOD) {
      AdrDestroyAddress(addr);
      return err;
   }
   if ((tableBase & PAGE_PRESENT_MASK) == 0)
      return ER_ADR_PAGE_UNAVAILABLE;
   /* Find page table entry */
   tableEntry = (tableBase & 0xFFFFF000L) + (tableIndex*sizeof(tableEntry));
   if ((err = AdrSetAddrOffset(addr, tableEntry)) != GOOD) {
      AdrDestroyAddress(addr);
      return err;
   }
   if ((err = MemReadSizedNoAlloc(addr,sizeof(U32),(LPU8)&pageFrame,
	 BYTE_SIZE,CACHE_USE_AND_LOCK)) != GOOD)  {
      AdrDestroyAddress(addr);
      return err;
   }
   if ((pageFrame & PAGE_PRESENT_MASK) == 0)
      return ER_ADR_PAGE_UNAVAILABLE;
   /* compute physical address */
   *physAddr = (pageFrame & 0xFFFFF000L) + offset;
   if ((err = AdrDestroyAddress(addr)) != GOOD)
      return err;
   return GOOD;
}

/****************************************************************************
**
** AddrToPhysical : address offset translation for Intel and Motorola
**
***************************************************************************/
RETCODE  PRIVATE AddrToPhysical(DESCRIPTOR desc, U32 *physAddr) {

   U32 linearAddr;
   RETCODE err;
   PMODE useMode;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (((A_D)desc)->type == ADDR_PHYSICAL) {
      *physAddr = ((A_D)desc)->addrOffset;
      return GOOD;
   }
   if (procFamily == FAMILY_X86) {
      useMode = GetPmode(((A_D)desc)->mode);
      if (useMode == PMODE_END)
	 return ER_ADR_PMODE_UNAVAILABLE;
      if (useMode == PMODE_SMM) {
	 if (((A_D)desc)->type == ADDR_VIRTUAL) {
	    if ((err = RealToLinear(desc,physAddr)) != GOOD)
	       return err;
	 }
	 else /* already a linear address */
	    *physAddr = ((A_D)desc)->addrOffset;
      }
      else if (useMode == PMODE_REAL)  {
	 if (((A_D)desc)->type == ADDR_VIRTUAL) {
	    if ((err = RealToLinear(desc,physAddr)) != GOOD)
	       return err;
	 }
	 else  /* already a linear address */
	    *physAddr = ((A_D)desc)->addrOffset;
      }
      else if (useMode == PMODE_V86) {
	 if (pagingOn) {
	    if (((A_D)desc)->type == ADDR_VIRTUAL) {
	       if ((err = RealToLinear(desc,&linearAddr)) != GOOD)
		  return err;
	    }
	    else
	       linearAddr = ((A_D)desc)->addrOffset;
	    if ((err = LinearToPhysical(linearAddr,physAddr)) != GOOD)
	       return err;
	 }
	 else  {
	    if (((A_D)desc)->type == ADDR_VIRTUAL) {
	       if ((err = RealToLinear(desc,physAddr)) != GOOD)
		  return err;
	    }
	    else  /* already a linear address */
	       *physAddr = ((A_D)desc)->addrOffset;
	 }
      }
      else {  /* protected mode */
	 if (pagingOn) {
	    if (((A_D)desc)->type == ADDR_VIRTUAL) {
	       if ((err = ProtToLinear(desc,&linearAddr)) != GOOD)
		  return err;
	    }
	    else  /* already a linear address */
	       linearAddr = ((A_D)desc)->addrOffset;
	    if ((err = LinearToPhysical(linearAddr,physAddr)) != GOOD)
		return err;
	 }
	 else  {
	    if (((A_D)desc)->type == ADDR_VIRTUAL) {
	       if ((err = ProtToLinear(desc,physAddr)) != GOOD)
		  return err;
	    }
	    else  /* already a linear address */
	       *physAddr = ((A_D)desc)->addrOffset;
	 }
      }
   }
   else if (procFamily == FAMILY_68K) {
      switch (cpu) {
	 case PROC_CPU_CPU32:
	 case PROC_CPU_CPU32P:
	 case PROC_CPU_CPU16:
	 case PROC_CPU_68000:
	 case PROC_CPU_68040:    /* NO MMU */
	    *physAddr = ((A_D)desc)->addrOffset;
      }
   }
   return GOOD;
}

/****************************************************************************
**
** AddrToLinear : address offset translation for Intel
**
***************************************************************************/
RETCODE PRIVATE AddrToLinear(DESCRIPTOR desc, U32 *linearAddr) {

   RETCODE err;
   PMODE useMode;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (((A_D)desc)->type == ADDR_LINEAR) {
      *linearAddr = ((A_D)desc)->addrOffset;
      return GOOD;
   }
   if (((A_D)desc)->type == ADDR_PHYSICAL)
      return ER_ADR_PHYS_TO_LINEAR_NOT_SUPPORTED;
   if (procFamily == FAMILY_X86) {
      useMode = GetPmode(((A_D)desc)->mode);
      if (useMode == PMODE_END)
	 return ER_ADR_PMODE_UNAVAILABLE;
      if (useMode == PMODE_SMM) {
	 if ((err = RealToLinear(desc,linearAddr)) != GOOD)
	    return err;
      }
      else if (useMode == PMODE_REAL) {
	 if ((err = RealToLinear(desc,linearAddr)) != GOOD)
	    return err;
      }
      else if (useMode == PMODE_V86) {
	 if ((err = RealToLinear(desc,linearAddr)) != GOOD)
	    return err;
      }
      else  { /* protected mode */
	 if ((err = ProtToLinear(desc,linearAddr)) != GOOD)
	    return err;
      }
   }
   else if (procFamily == FAMILY_68K) {
      switch (cpu) {
	 case PROC_CPU_CPU32:
	 case PROC_CPU_CPU32P:
	 case PROC_CPU_CPU16:
	 case PROC_CPU_68000:
	 case PROC_CPU_68040:    /* NO MMU */
	    *linearAddr = ((A_D)desc)->addrOffset;
      }
   }
   return GOOD;
}

/*********************************************************************
**
**  GetPmode
**
********************************************************************/
PMODE PRIVATE GetPmode(ADDR_MODE addrMode) {

   switch (addrMode) {
      case MODE_REAL : return PMODE_REAL;
      case MODE_PROT16 : return PMODE_P16;
      case MODE_PROT32 : return PMODE_P32;
      case MODE_V86 : return PMODE_V86;
      case MODE_SMM : return PMODE_SMM;
      case MODE_NONE :
      case MODE_CURRENT :
      default :  return pMode;
   }
}

/****************************************************************************
**
** GetSegment
**
***************************************************************************/
RETCODE PRIVATE GetSegment(DESCRIPTOR desc,U32 *segment) {

   RETCODE err;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   switch (((A_D)desc)->segSelType) {
      case ADDR_USE_VALUE:
	 *segment = ((A_D)desc)->addrSegSel;
	  break;
      case ADDR_USE_CS:  /* use code segment */
	 if ((err = CpuGetRegister(CSregId,segment)) != GOOD)
	    return err;
	 break;
      case ADDR_USE_SS:  /* use stack segment */
	 if ((err = CpuGetRegister(SSregId,segment)) != GOOD)
	    return err;
	 break;
      case ADDR_USE_DS:
      default:
	 if ((err = CpuGetRegister(DSregId,segment)) != GOOD)
	    return err;
	 break;
   }
   return GOOD;
}

/*************************************************************************
**
** AdrGetDefaultSize :
**
***************************************************************************/
RETCODE EXPORT AdrGetDefaultSize(DESCRIPTOR desc,ADDR_OP_SIZE *size) {

   PMODE useMode;
   SEGMENT_DESCRIPTOR segDesc;
   RETCODE err;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (procFamily == FAMILY_X86) {
      if (((A_D)desc)->type == ADDR_VIRTUAL) {
	 /* check the descriptor for default size */
	 if ((err = GetSegmentDescCopy(desc,&segDesc)) != GOOD)
	    return err;
	 if (segDesc.opSize == ADDR_USE_16)
	    *size = ADDR_USE_16;
	 else
	    *size = ADDR_USE_32;
      }
      else {
	 useMode = GetPmode(((A_D)desc)->mode);
	 switch (useMode) {
	    case PMODE_REAL:
	    case PMODE_V86:
	    case PMODE_SMM:
	    case PMODE_P16:
	       *size = ADDR_USE_16;
	       break;
	    case PMODE_P32:
	       *size = ADDR_USE_32;
	       break;
	    default:
	       *size = ADDR_USE_16;
	       break;
	 }
      }
   }
   else  { /* procFamily 68K */
      switch (cpu) {
	 case PROC_CPU_CPU32:
	 case PROC_CPU_CPU32P:
	    *size = ADDR_USE_32;
	    break;
	 case PROC_CPU_CPU16:
	    *size = ADDR_USE_16;
	    break;
      }
   }
   return GOOD;
}

/************************************************************************
**
**  strtoulDefRadix
**
**************************************************************************/
U32 PRIVATE strtoulDefRadix(const CHAR *s, CHAR** endPtr) {

   CHAR *firstChar;
   CHAR *secondChar;
   CHAR *stringPtr;

   firstChar = (CHAR *)s;
   secondChar = (CHAR *)(s + sizeof(CHAR));
   if ((*firstChar == '0') &&
	 ((*secondChar == 'x') || (*secondChar == 'X'))) {
      stringPtr = (CHAR *)(s + (2*sizeof(CHAR)));
      return (strtoul(stringPtr,endPtr,16));
   }
   return (strtoul(s,endPtr,defaultRadix));

}

#ifdef __cplusplus
}
#endif

/************************* E O F ***********************************/

