/****************************************************************************
**
**  Name:  addr.c
**
**  Description:
**     Address server handles virtual, linear, and physical addresses.
**
** Copyright (C) 1994 Microtek International.  All rights reserved.
**
**  $Log:   S:/tbird/mt2_186/addr/addr.c_v  $
** 
**    Rev 1.4   23 Jul 1997 08:55:38   Judy
** 
**    Rev 1.3   31 Jan 1997 13:49:00   Judy
** added address string checking in converter function
** 
**    Rev 1.2   28 Jan 1997 15:35:06   Judy
** fixed a bug of phy address limit
** 
**    Rev 1.1   20 Dec 1996 18:12:46   Judy
** 
**    Rev 1.0   16 Dec 1996 16:15:46   Judy
** Initial revision.
** 
**    Rev 1.96   17 Oct 1994 11:57:02   marilyn
** Fixed some bugs in ConvTextToAddress to handle the optional printing of
** the ldt part of the address.  Also address strings are truncated at 
** the first encountered space.
** 
**    Rev 1.95   13 Oct 1994 17:14:42   marilyn
** Fixed ppr 9859 where overflow was occuring in setting the range length
** and ppr 9787 where old pc descriptors which referenced the cs
** were still using cslimit even though the cs had changed.  Now check
** all address descriptors referencing segment registers to see if they
** are the current value, if they aren't they are treated as USE_VALUE
** descriptors and are read from memory.
** 
**    Rev 1.94   12 Oct 1994 15:12:56   marilyn
** Fixed bug in ConvPointerToAddress, ppr  9830.
** 
**    Rev 1.93   10 Oct 1994 16:53:02   marilyn
** Fixed pprs 9764, 9795, 9832, 9837.
** 
**    Rev 1.92   29 Sep 1994 09:11:14   marilyn
** Added a check for the dead address descriptor in all exported routines.
** 
**    Rev 1.91   26 Sep 1994 16:42:54   marilyn
** Fixed ppr 9750, and fixed some bugs when using ldt override in 
** protected mode.
** 
**    Rev 1.90   26 Sep 1994 12:15:02   marilyn
** Removed segment descriptor caching since it caused more problems than
** a 5% performance benefit was worth.  Also fixed problem in GetLdtSelector
** where in protected mode the ldt or gdt bit wasn't being checked.
** 
**    Rev 1.89   22 Sep 1994 08:55:58   marilyn
** Fixed bug in GetSegmentLimits.  Modified to use hidden segment registers
** for limit and access rights.  Also fixed ppr 9682.  The GetSegmentDescCopy
** routine was reading memory with CACHE_BYPASS causing severe degradation
** in performance.  Also increased efficiency by storing the last used
** segment descriptor for multiple call operations.
** 
**    Rev 1.88   19 Sep 1994 09:53:12   marilyn
** Added new interface AdrPhysicalRangeOfAddresses.  Fixed pprs 9615,9616,
** 9636, 9646, and 9650 which were protected mode related bugs.
** 
**    Rev 1.87   08 Sep 1994 16:35:48   marilyn
** Fixed the following bugs found during protected mode integration:
**    fixed PAGING_ENABLED_MASK, it was the wrong value,
**    Added linear to virtual address translation courtesy of the symbol server,
**    In ConvertPointerToAddress, SMALL and LARGE ptr types default to DEF_DS,
**    fixed LDT/GDT limit off by 1 byte,
**    register edits now update both pmode and paging status.
** 
**    Rev 1.86   23 Aug 1994 17:46:36   marilyn
** Fixed bug in ConvertAddressToPointer.
** 
**    Rev 1.85   23 Aug 1994 09:27:44   marilyn
** fixed bug in ConvPointerToAddress.
** 
**    Rev 1.84   19 Aug 1994 16:44:52   marilyn
** Enabled protected mode support for pmode and pagingOn.
** 
**    Rev 1.83   18 Aug 1994 10:32:22   marilyn
** Fixed TOO_LARGE error to return type differentiated exceeds max errors.
** 
**    Rev 1.82   17 Aug 1994 10:07:54   marilyn
** Fixed bug where P and L designations were being accepted anywhere
** in the address instead of only on the end.  Exported a private routine
** to get a copy of the segment selector descriptor, AdrGetSegmentDescCopy.
** 
**    Rev 1.81   10 Aug 1994 10:43:08   marilyn
** Fixed PPR 9492 which was a bug in AddrToPhysical routine where upper
** unused bits of the physical address were not being masked off from the
** equivalent linear address.  Also added support for _addrdump cli
** command.
** 
**    Rev 1.80   03 Aug 1994 10:05:52   marilyn
** In CreateAddress and DestroyAddress initialized the cli buffer used for
** the address debugging command.  This should help with debugging.
** 
**    Rev 1.79   28 Jul 1994 16:18:08   marilyn
** IsInRange functions return false if segments don't match.
** 
**    Rev 1.78   21 Jul 1994 10:53:30   marilyn
** Added AdrTranslateAddrMode interface.
** 
**    Rev 1.77   13 Jul 1994 09:56:52   marilyn
** Added a couple of new interfaces and changed the ldt and segment
** U32s to U16s.
** 
**    Rev 1.76   08 Jul 1994 16:08:44   marilyn
** Changed maxOutputChars for physical and linear addressed to include
** the postfixed P or L.  Changed AddressToText routine to take this into
** account when formatting addresses.  Also updated ConvertPointerToAddress
** routine to fully support protected mode.
** 
**    Rev 1.75   30 Jun 1994 11:24:44   marilyn
** Fixed bug where segments were exceeding 16 bit values.
** 
**    Rev 1.74   27 Jun 1994 13:41:58   marilyn
** In AdjustRange, made a change when moving the range to high memory
** so that the end offset of the range is checked for boundary conditions
** to ensure that the entire range fits in valid memory addresses and the
** range length is preserved.
** 
**    Rev 1.73   27 Jun 1994 10:44:20   marilyn
** CopyAddress no longer returns an error if the source and destination
** descriptors are equal but returns GOOD.
** 
**    Rev 1.72   23 Jun 1994 14:43:46   marilyn
** Fixed bug in ConvTextToAddress, changed ConvAddressToText to default to
** no 0x prefix, fixed bug in IsAddrInPhysicalRange.
** 
**    Rev 1.71   20 Jun 1994 15:29:40   marilyn
** Changed a private interface to an exportable one, GetSegmentSelectorBase.
** 
**    Rev 1.70   20 Jun 1994 12:26:40   marilyn
** ConvTextToAddress no longer overwrites an existent segment for
** an input offset.
** 
**    Rev 1.69   20 Jun 1994 11:36:40   marilyn
** Implemented register base saving.
** 
**    Rev 1.68   16 Jun 1994 14:52:34   nghia
** Merged 1.57.1.0 to trunk.
** Put back in rev 1.65 changes to trunk.
** 
**    Rev 1.67   15 Jun 1994 10:32:22   marilyn
** Fixed bug in GetSpaceString where it didn't handle SPACE_DEFAULT.
** 
**    Rev 1.66   14 Jun 1994 17:16:52   marilyn
** Added checks for ADDR_USE_DEF_DS in a couple of places.
**
**    Rev 1.65   14 Jun 1994 16:57:56   nghia
** Revised AddrAddToAddressOverflow() to set address offset to maxOutputAddr 
** when the overflow condition occurs.
** Added AdrIsAddrInDasmRange() interface (used by the Source window only).
** 
**    Rev 1.64   14 Jun 1994 16:46:34   marilyn
** Modified several routines to utilize MaxOutputOffset instead of
** MaxInputOffset.  These were all routines dealing with ranges and
** values stored in the address descriptor.  Also modified the
** default descriptor to use ADDR_USE_DEF_DS and the actual pmode.
** 
**    Rev 1.63   10 Jun 1994 15:35:26   marilyn
** Two new interfaces and miscellaneous bug fixes for 386 build 4.
** 
**    Rev 1.62   03 Jun 1994 09:22:36   marilyn
** Added new interface AdrGetAddressLimits
** 
**    Rev 1.61   18 May 1994 09:46:38   marilyn
** Added GetPhysicalAddrOffset and other minor changes for 386 beta.
** 
**    Rev 1.60   10 May 1994 17:01:26   marilyn
** Damn typo.
** 
**    Rev 1.59   10 May 1994 16:56:28   marilyn
** Updated GetAddrSpace to filter out return of SPACE_DEFAULT and return
** the specific space instead.  Also added GetAddrPhysicalOffset.
** 
**    Rev 1.58   10 May 1994 15:37:22   ernie
** 1. Added initialization step for pMode.
** 2. Changed handling for address mode MODE_CURRENT.  When handling address
**    functions needing to know the address mode, a TranslateAddrMode
**    function is now called to convert MODE_CURRENT to the current pMode.
**    Prior to this, calls to these functions would error out.
** 
**    Rev 1.57.1.0   31 May 1994 17:14:42   nghia
** Added support for HC16 var index regiter.
** Make cpu to be global variable.
** 
**    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 strtoU32DefRadix 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_186/addr/addr.c_v   1.4   23 Jul 1997 08:55:38   Judy  $
**
*****************************************************************************/

		       /****************************
			*                          *
			*       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 __MEM_H
#include <mem.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

#ifndef __ADDRINI__
#include "addrini.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 */
   U16 ldt;
   U16 addrSegSel;
   ADDR_TYPE type;
   ADDR_MODE mode;
   ADDR_SPACE space;
   ADDR_SEGSEL_TYPE segSelType;
   BOOLEAN rangeActive;
   BOOLEAN symbolUsage;
   BOOLEAN activeDesc;
} ADDR_DESCRIPTOR;

typedef struct {
   U16 addrSegSel;
   U16 ldt;
   SEGMENT_DESCRIPTOR segDesc;
} SEGMENT_CACHE;

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 SEGMENT_TYPE_MASK 0x00000F00L
#define SEGMENT_PRESENT_MASK 0x00008000L
#define GRANULARITY_MASK 0x00800000L
#define OPERATION_SIZE_MASK 0x00400000L
#define EXPAND_DN_SEG_MASK 0x000C
#define EXPAND_DN_SEG 0x0004
#define PAGE_PRESENT_MASK 0x0001
#define MAX_DEBUG_BUF  80
#define PAGING_ENABLED_MASK 0x80000000L


/* 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"}};

SEGMENT_CACHE descCache;


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

extern HANDLE cliServerHandle;
extern HANDLE hLib;

extern BOOLEAN usedIndexExtReg;  // defined in ADDRINI.C
extern CHAR extRegName[];
extern REG_ID extRegId;

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

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

/* 
** 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;
PROC_CPU procCpu;

PRIVATE ENDIAN_TYPE endianType;
PRIVATE REG_ID      LDTBaseId;
PRIVATE REG_ID      LDTRRegId;
PRIVATE REG_ID      GDTBaseId;
PRIVATE REG_ID      CR3regId;
PRIVATE REG_ID      CR0regId;
PRIVATE REG_ID      LDTLimitId;
PRIVATE REG_ID      GDTLimitId;
PRIVATE REG_ID      CSregId;
PRIVATE REG_ID      CSBaseRegId;
PRIVATE REG_ID      CSLimitRegId;
PRIVATE REG_ID      CSARRegId;
PRIVATE REG_ID      DSregId;
PRIVATE REG_ID      DSBaseRegId;
PRIVATE REG_ID      DSLimitRegId;
PRIVATE REG_ID      DSARRegId;
PRIVATE REG_ID      ESregId;
PRIVATE REG_ID      ESBaseRegId;
PRIVATE REG_ID      ESLimitRegId;
PRIVATE REG_ID      ESARRegId;
PRIVATE REG_ID      FSregId;
PRIVATE REG_ID      FSBaseRegId;
PRIVATE REG_ID      FSLimitRegId;
PRIVATE REG_ID      FSARRegId;
PRIVATE REG_ID      GSregId;
PRIVATE REG_ID      GSBaseRegId;
PRIVATE REG_ID      GSLimitRegId;
PRIVATE REG_ID      GSARRegId;
PRIVATE REG_ID      SSregId;
PRIVATE REG_ID      SSBaseRegId;
PRIVATE REG_ID      SSLimitRegId;
PRIVATE REG_ID      SSARRegId;

/* 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 GetSegSelFromText(LPSTR segSelStr,
				  ADDR_SEGSEL_TYPE *segType,
				  U16 *segment);
RETCODE PRIVATE GetSegmentBaseRegister(DESCRIPTOR desc, 
				       U32 *segBase);
RETCODE PRIVATE GetSegmentLimitRegister(DESCRIPTOR desc,
					U32 *segLimitReg);
RETCODE PRIVATE GetSegmentAccessRegister(DESCRIPTOR desc,
					 U32 *segAccessReg);
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);
ADDR_MODE PRIVATE GetAddrMode(PMODE inputPmode);
ADDR_MODE PRIVATE TranslateAddrMode(ADDR_MODE addrMode);
U32 PRIVATE strtoU32DefRadix(const CHAR *s, CHAR **endPtr);
U16 PRIVATE strtoU16DefRadix(const CHAR *s, CHAR **endPtr);
RETCODE PRIVATE GetSegment(DESCRIPTOR desc,U16 *segment, LPSTR segStr);
RETCODE PRIVATE GetSegmentFromText(LPSTR text, ADDR_SEGSEL_TYPE *segType);
RETCODE PRIVATE GetSegmentRegister(ADDR_SEGSEL_TYPE type, U16 *segsel);
RETCODE PRIVATE CheckSegments(ADDR_DESCRIPTOR *desc1,
			      ADDR_DESCRIPTOR *desc2);
RETCODE PRIVATE X86GetMaxOffset(DESCRIPTOR desc,
				U32 FAR *maxInputAddress);
BOOLEAN PRIVATE X86IsProtectedMode(ADDR_MODE mode);
RETCODE PRIVATE GetExceedsMaxError(DESCRIPTOR desc);
VOID PRIVATE FlushDescCache(VOID);
RETCODE PRIVATE GetLdtSelectorBaseAndLimit(DESCRIPTOR desc,
					  U32 *base, U32 *limit);


			/***************************
			 *                          *
			 *      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,reg;
   RETCODE err, firstErr;
   
   numAddrCreated = 0L;
   numAddrDestroyed = 0L;

   firstErr = ProcReturnByteOrder(&endianType);

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

   err = ProcReturnCpu(&procCpu);
   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 on BKPT_HALTED to update pMode 
      ** and other processor dependent globals
      */
      adrCallback = MakeProcInstance((FARPROC)AdrCallback,hLib);
      err = EnlRegister(EVENT_BKPT_HALTED,(EVCALLBACK)adrCallback,
	    &descEvt);
      /* register for callback on CPU_EDIT to update paging, pmode,
      */
      err = EnlRegister(EVENT_CPU_EDIT,(EVCALLBACK)adrCallback,
	    &descEvt);
      if (GOOD == firstErr)
	 firstErr = err;
      /* Read initial value of pmode from shared data server */
      if ((err = SdnReadMember(SDN_PMODE,(LPU8)&pMode)) != GOOD)
	 return err;

      err = CpuFindRegisterId((LPU8)"LDTR",&LDTRRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      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)"CR0",&CR0regId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"CS",&CSregId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"DS",&DSregId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"ES",&ESregId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"FS",&FSregId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"GS",&GSregId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"SS",&SSregId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"CSBASE",&CSBaseRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"DSBASE",&DSBaseRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"ESBASE",&ESBaseRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"FSBASE",&FSBaseRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"GSBASE",&GSBaseRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"SSBASE",&SSBaseRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"CSLIMIT",&CSLimitRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"DSLIMIT",&DSLimitRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"ESLIMIT",&ESLimitRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"FSLIMIT",&FSLimitRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"GSLIMIT",&GSLimitRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"SSLIMIT",&SSLimitRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"CSAR",&CSARRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"DSAR",&DSARRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"ESAR",&ESARRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"FSAR",&FSARRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"GSAR",&GSARRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      err = CpuFindRegisterId((LPU8)"SSAR",&SSARRegId);
      if (GOOD == firstErr)
	 firstErr = err;
      
      /* determine if paging is enabled */
      err = CpuGetRegister(CR0regId,&reg);
      if (GOOD == firstErr)
	 firstErr = err;
      if (reg & PAGING_ENABLED_MASK)
	 pagingOn =  TRUE;
      else
	 pagingOn = FALSE;
   }
   /* initialize 68HC16 - index extension register usage */
   if ((procCpu == PROC_CPU_CPU16) && (err = GetCpu16IndexRegUsed()) != GOOD)
      return err;
   
   return firstErr;
}

/**************************************************************************
**
**  AdrCreateAddress
**
***************************************************************************/
RETCODE EXPORT AdrCreateAddress(DESCRIPTOR FAR *desc) {
   #define DESC ((ADDR_DESCRIPTOR *)*desc)
   CHAR buff[MAX_DEBUG_BUF];
   RETCODE err=GOOD;

   memset(buff,'\0',MAX_DEBUG_BUF);
   if((*desc = (DESCRIPTOR)TMalloc(sizeof(ADDR_DESCRIPTOR)))==NULL)
      return ER_OUT_OF_MEMORY;
   memset(DESC,'\0',sizeof(ADDR_DESCRIPTOR));

   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;
	 DESC->activeDesc = TRUE;
	 break;
      case FAMILY_X86:
	 DESC->type = ADDR_VIRTUAL;
	 DESC->mode = GetAddrMode(pMode);       
	 DESC->space = SPACE_USER;
	 DESC->ldt = 0L;
	 DESC->symbolUsage = FALSE;
	 DESC->segSelType = ADDR_USE_DEF_DS;
	 if ((err = GetSegmentRegister(DESC->segSelType,&DESC->addrSegSel))
	       != GOOD) {
	    TFree((LPSTR)*desc);
	    return err;
	 }
	 DESC->addrOffset = 0L;
	 DESC->rangeActive = FALSE;
	 DESC->rangeLength = 0L;
	 DESC->activeDesc = TRUE;
	 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;
	 DESC->activeDesc = TRUE;
	 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) {
      AdrCremateAddress(desc);
      return err;
   }
   if ((err = AdrTranslateSpace(space, &addrSpace)) != GOOD) {
      AdrCremateAddress(desc);
      return err;
   }
   if ((err = AdrSetAddrSpace(*desc,addrSpace)) != GOOD) {
      AdrCremateAddress(desc);
      return err;
   }
   return GOOD;

}

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

   RETCODE err=GOOD;
   CHAR buff[MAX_DEBUG_BUF];

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

   memset(buff,'\0',MAX_DEBUG_BUF);
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   ((A_D)desc)->activeDesc = FALSE;
   err = TFree((LPSTR)desc);
   if (GOOD != err)
      return err;
   numAddrDestroyed++;
   if(addrDebug) {
      wsprintf(buff, "...Destroying address descriptor %ld",numAddrDestroyed);
      SendMessageToCli(buff, cliServerHandle);
   }
   return GOOD;
}

/****************************************************************************
**
**  AdrCremateAddress
**
*****************************************************************************/
RETCODE EXPORT AdrCremateAddress(DESCRIPTOR FAR *desc) {

   RETCODE err;

   if ((err = AdrDestroyAddress(*desc)) != GOOD)
      return err;
   *desc = NULL;
   return GOOD;
}

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

   *spaces = NULL;
   *spaceCount = 0;
   *spaceLen = 0;
   switch (procCpu) {
      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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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) {
      if (space == SPACE_DEFAULT) {
	 /* Phase I: default to SPACE_USER
	 ** Need to get the current PMODE to figure out the current SPACE 
	 */
	 ((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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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, U16 FAR *ldt) {

   RETCODE err;
   U32 tempLdt;
   U16 segment;
   CHAR segStr[SPACE_BUFF_SZ];

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if (FAMILY_68K == procFamily)
      return(ER_ADR_NOT_MOTOROLA_USAGE);
   else {
      if ((X86IsProtectedMode(((A_D)desc)->mode)) &&
	   (((A_D)desc)->ldt == 0)) {  /* use current LDTR or GDTR */
	 /* examine segment selector to determine GDT or LDT */
	 /* we have to check LDT for validity. */
	 if ((err = GetSegment(desc,&segment,segStr)) != GOOD)
	    return err;
	 if ((segment & TABLE_INDICATOR_MASK) == LDT_INDICATOR) {
	    if ((err = CpuGetRegister(LDTRRegId,&tempLdt)) != GOOD)
	       return err;
	    if (tempLdt == 0)
	       return ER_ADR_LDT_INVALID;
	    else
	       *ldt =  (U16)(0x0000FFFF & tempLdt);
	 }
	 else {
	    /* use GDTR */
	    /* 09/16/94 Marilyn: 
	    ** an index of 0 refers to the null selector.  The processor
	    ** does not generate an exception when a segment register is
	    ** loaded with a null descriptor, other than CS or SS.  It 
	    ** will generate an exception when a segment register holding 
	    ** a null selector is used to access memory.  This feature is 
	    ** often used to initialize unused segment registers. 
	    ** Server will not circumvent the null selector.
	    */
	    *ldt = ((A_D)desc)->ldt; 
	 }
      }
      else
	 *ldt = ((A_D)desc)->ldt;
   }
   return GOOD;
}

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

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   *useSymbols = ((A_D)desc)->symbolUsage;
   return(GOOD);
}

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

   if (procFamily == FAMILY_68K)
      return AdrConvAddressToTextWithParams(desc,TRUE,TRUE,str);
   else
      return AdrConvAddressToTextWithParams(desc,FALSE,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;
   U16  maxOutputAddrCharWidth=0;
   U16  prevCharsWidth=0;
   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;
   U16                segmentValue;
   U32                ldtreg;    
   CHAR               segStr[SPACE_BUFF_SZ];
#ifndef ADR_UAE
   if (0L == inputAddrDesc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)inputAddrDesc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   segStr[0] = '\0';
   strPtr = str;
   *str = '\0';
   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((LPSTR)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) {
	    if(funcDesc == NULL_SYMBOL)
	       funcDesc = moduleDesc; //Hera
	    err = SymMapAddr2LinenumStmt(inputAddrDesc,
					 moduleDesc,
					 funcDesc, //Hera
					 &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 {
      switch (((A_D)inputAddrDesc)->type) {
	 case ADDR_VIRTUAL:
	    // if desc->ldt != 0 && desc->ldt != LDTR then show it too
	    // get current LDTR value
	    // only show ldt for protected mode addresses.
	    if (((A_D)inputAddrDesc)->ldt != 0)  {
		 /** allow in any mode **
		 **  && X86IsProtectedMode(((A_D)inputAddrDesc)->mode)) {
		 */
	       if ((err = CpuGetRegister(LDTRRegId,&ldtreg)) != GOOD)
		  return err;
	       if (ldtreg != ((A_D)inputAddrDesc)->ldt) {  // show it too
		  if (with0X)
		     strPtr = stpcpy(strPtr, "0x");
		  if (leadZeroFill) {
		     sprintf(strPtr, "%*.*X",4,4,
			   ((A_D)inputAddrDesc)->ldt);
		  } else {
		     sprintf(strPtr, "%X", ((A_D)inputAddrDesc)->ldt);
		  }
		  strcat(strPtr,":");
		  strPtr += strlen(strPtr);
	       }
	       else {
		  /* 10/14/94 Marilyn:
		  ** since we are not printing out the default ldt we
		  ** must decrement the maxOuputNumDigits to reflect a
		  ** length without the ldt specified.  When we do 
		  ** print it the length is accounted for in prevChars.
		  */
		  maxOutputAddrCharWidth -= 5; /* 0000: */
	       }
	    }
	    // do the segment or the selector
	    if ((err = GetSegment(inputAddrDesc,&segmentValue,segStr))
		  != GOOD)
	       return err;
	    if (*segStr != '\0') {
	       sprintf(strPtr, "%2.2s", segStr);
	    }
	    else {
	       if (with0X)
		  strPtr = strcat(strPtr, "0x");
	       strPtr += strlen(strPtr);
	       if (leadZeroFill) {
		  sprintf(strPtr, "%*.*X",4,4,segmentValue);
	       } else {
		  sprintf(strPtr, "%X", segmentValue);
	       }
	    }
	    strcat(strPtr,":");
	    prevCharsWidth = strlen(str);
	    // do the offset
	    if (with0X)
	       strPtr = strcat(strPtr, "0x");
	    strPtr += strlen(strPtr);
	    if (leadZeroFill) {
	       /* maxOutputAddrCharWidth is the number of chars required
	       ** for the entire address not including any 0x prefixes.
	       ** So to print only the offset
	       ** part we must subtract the length of the segment and the
	       ** colon chars.
	       */
	       sprintf(strPtr, "%*.*lX", 
				maxOutputAddrCharWidth - prevCharsWidth,
				maxOutputAddrCharWidth - prevCharsWidth,
				(((A_D)inputAddrDesc)->addrOffset));
	    } else {
	       sprintf(strPtr, "%lX", (((A_D)inputAddrDesc)->addrOffset));
	    }
	    break;
	 case ADDR_LINEAR:
	    offset = ((A_D)inputAddrDesc)->addrOffset;
	    if (leadZeroFill) {
	       if (procFamily == FAMILY_X86) {
		  sprintf(strPtr, "%*.*lX", maxOutputAddrCharWidth-1,
				   maxOutputAddrCharWidth-1,
				   offset);
	       }
	       else {
		  sprintf(strPtr, "%*.*lX", maxOutputAddrCharWidth,
				   maxOutputAddrCharWidth,
				   offset);
	       }
	    } else {
	       sprintf(strPtr, "%lX", offset);
	    }
	    if (procFamily == FAMILY_X86) {
	       /* append linear address notation */
	       strcat(strPtr,"P"); /* for 186 should be as physical addr */
	    }
	    break;
	 case ADDR_PHYSICAL:
	    offset = ((A_D)inputAddrDesc)->addrOffset;
	    if (leadZeroFill) {
	       if (procFamily == FAMILY_X86) {
		  sprintf(strPtr, "%*.*lX", maxOutputAddrCharWidth-1,
				   maxOutputAddrCharWidth-1,
				   offset);
	       }
	       else {
		  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 = AdrCremateAddress(&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;

#ifndef ADR_UAE
   if (0L == rangeDesc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)rangeDesc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   *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 - 1L;
      if ((err = AdrConvAddressToTextWithParams(tmpDesc,with0X,
	    leadZeroFill,strPtr)) != GOOD) {
	 AdrCremateAddress(&tmpDesc);
	 return err;
      }
      if ((err = AdrCremateAddress(&tmpDesc)) != GOOD)
	 return err;
   }
   return GOOD;
}

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

   RETCODE err = GOOD;
   DESCRIPTOR tmpDesc;
   LPSTR   strPtr = str;
   MEM_ADDR_CLASS     memoryClass;
   SYM_TYPE_TYPE      symbolType;
   U32                symbolOffset;
   SYM_DESCRIPTOR     outputSymbol, funcDesc, moduleDesc;
   SEG_INFO segInfo;
   int index;

#ifndef ADR_UAE
   if (0L == rangeDesc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)rangeDesc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   *str = '\0';
   memset(&segInfo,0,sizeof(SEG_INFO));
   if (!((A_D)rangeDesc)->rangeActive) 
      return (AdrConvAddressToTextWithParams(rangeDesc,with0X,
	    leadZeroFill,str));
   if (GOOD != (err = SymMapAddr2Symbol(rangeDesc,
     				        &memoryClass,
					&symbolType,
					&symbolOffset,
					&outputSymbol,
					&funcDesc,
					&moduleDesc)))
	 return err;
   if (moduleDesc != NULL_SYMBOL)
      SymGetSegInfo(moduleDesc, &segInfo);
   if (segInfo.segNum == 0 || moduleDesc == NULL_SYMBOL)
      AdrConvAddrRangeToText(rangeDesc, with0X, leadZeroFill, whichPart, str);
   else {
      for (index = 0 ;index < segInfo.segNum; index++) {
	 if ((whichPart == RANGE_START) || (whichPart == RANGE_BOTH)) {
	    ((A_D)rangeDesc)->addrSegSel = segInfo.segment[index];
	    ((A_D)rangeDesc)->addrOffset = segInfo.beginAddr[index];
	    ((A_D)rangeDesc)->rangeLength = segInfo.endAddr[index]-segInfo.beginAddr[index]+1;
         }
         if ((err = AdrConvAddressToTextWithParams(rangeDesc,with0X,
	      leadZeroFill,strPtr)) != GOOD)
	    return err;
         if (whichPart == RANGE_BOTH) 
         strcat(strPtr,"..");
         if ((whichPart == RANGE_END) || (whichPart == RANGE_BOTH)) {
	    if (*str != '\0')
	       strPtr = str + strlen(str);
            if ((err = AdrDuplicateAddress(rangeDesc,&tmpDesc)) != GOOD)
	       return err;
            ((A_D)tmpDesc)->addrOffset = ((A_D)rangeDesc)->addrOffset +
	                                 ((A_D)rangeDesc)->rangeLength - 1L;
            if ((err = AdrConvAddressToTextWithParams(tmpDesc,with0X,
	       leadZeroFill,strPtr)) != GOOD) {
	    AdrCremateAddress(&tmpDesc);
	    return err;
	    }
	    strcat(str," ");
	    strPtr = str + strlen(str);
	    if ((err = AdrCremateAddress(&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) {

      if (procFamily == FAMILY_68K)
	 return AdrConvAddressToTextWithParams(desc,TRUE,FALSE,text);
      else
	 return AdrConvAddressToTextWithParams(desc,FALSE,FALSE,text);
}  /* end of AdrConvAddressToTextNoFill */


/****************************************************************************
**
**  AdrConvTextToAddress
**
**  The descriptor passed in will be modified to match the attibutes of
**  the supplied 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 80
   
   RETCODE           err = GOOD;
   U32               tempU32=0L;
   U16               tempU16=0;
   S8                *endPtr=NULL;
   SYM_DESCRIPTOR    moduleDesc;
   LINENUM_TYPE      actualLinenum;
   COLUMN_RANGE_TYPE actualColumnRange;
   DESCRIPTOR        tmpDesc=NULL;
   LPSTR             token[MAXTOKEN];
   U8                tCount=0;
   CHAR              buf[MAXBUFF] = "";
   LPSTR             bufPtr=NULL;
   U16               i, textSize = 0;
   REG_ID            regId;
   LPSTR             tokenPtr,typePtr=NULL;
   BOOLEAN           rangeCovered;
   ADDR_SEGSEL_TYPE  segType;
   SYM_TYPE_TYPE     symType;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   while (isspace((S16)*text)) {  /* skip over spaces; requires int */
      text++;
   }
   /* 10/14/94 Marilyn
   ** check for any rogue spaces in the string.  Truncate the string 
   ** at the first space.
   */
   if ((tokenPtr = _fstrpbrk(text," "))  != NULL)
       *tokenPtr = '\0';
   /* 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); 
   */
   textSize = strlen(text);
   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,
			    &symType)))
	 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( AdrCremateAddress(&tmpDesc));
   }
   /* establish number of tokens  - 3 max: ldtr:gs:eax  for prot modes
   **                               2 max: seg:offset for other modes 
   ** 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,":");
      }
      if (tCount <= 1)  // with one : should be at least 2 tokens
	 return ER_ADR_INVALID_ADDRESS_STR;
   } /* only one token, just an offset */
   else {
      token[tCount++] = text;
   }
   /* process all the tokens, preprocess any register names to values */
   /* segment registers will set the segment type of the descriptor */
   /* 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++) {
      /* 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;
	    bufPtr += (strlen(bufPtr) + 1);
	 }
	 else { /* a register name! */
	    segType = ADDR_USE_VALUE;
	    if (tCount > 1) {
	       if ((err = GetSegmentFromText((LPSTR)token[i],
		     &segType)) != GOOD)
		  return err;
	    }
	    if (segType == ADDR_USE_VALUE) {
	       /* did not find a segment register */
	       if ((err = CpuGetRegisterValueText(regId,0,bufPtr)) != GOOD)
		  return err;
	    }
	    else { /* save the segment register string as the token */
	       stpcpy(bufPtr,token[i]);
	    }
	    token[i] = bufPtr;
	    bufPtr += (strlen(bufPtr) + 1);
	 }
      }
      else  { /* must be a value */
	 /* copy token[i] into buf */
	 stpcpy(bufPtr,token[i]);
	 token[i] = bufPtr;
	 bufPtr += (strlen(bufPtr) + 1);
      }
   }  /* end for */

   switch (tCount) {
      case 3:  /* ldt:selector:offset*/
	 if (procFamily != FAMILY_X86)
	    return ER_ADR_INVALID_ADDRESS_STR;
	 /* allow invalid descriptors to be created **
	 ** if (!X86IsProtectedMode(GetAddrMode(pMode)))
	 **    return ER_ADR_INVALID_ADDRESS_STR;
	 */
	 if ((err = AdrSetAddrType(desc,ADDR_VIRTUAL)) != GOOD)
	    return err;
	 tempU16 = strtoU16DefRadix(token[0], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetLdtSelector(desc,tempU16)) != GOOD)
	    return err;
	 /* turn segment string into a U16 */
	 tempU16 = 0;
	 if ((err = GetSegSelFromText(token[1],&segType,&tempU16)) != GOOD)
	    return err;
	 if ((err = AdrSetAddrSegmentSelector(desc,segType,
	       &tempU16)) != GOOD)
	    return err;
	 tempU32 = strtoU32DefRadix(token[2], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrOffset(desc,tempU32)) != GOOD)
	    return err;
	 break;
      case 2:  /* segment:offset or selector:offset */
	 if (procFamily != FAMILY_X86)
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrType(desc,ADDR_VIRTUAL)) != GOOD)
	    return err;
	 /* use ldt of the supplied desc, either specific one or implied by
	 ** ldt equal to 0 for current ldtr
	 */
	 /* turn segment string into a U32 */
	 if ((err = GetSegSelFromText(token[0],&segType,&tempU16)) != GOOD)
	    return err;
	 if ((err = AdrSetAddrSegmentSelector(desc,segType,
	       &tempU16)) != GOOD)
	    return err;
	 tempU32 = strtoU32DefRadix(token[1], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrOffset(desc,tempU32)) != GOOD)
	    return err;
	 break;
      case 1:  /* offset: can be virtual, linear, or physical */
	 if (procFamily == FAMILY_X86) {
	    if ((typePtr = _fstrpbrk(token[0],"Pp")) != NULL) {
	       /* now check for a null character after the "Pp"
	       ** so that something like "apple" is not accepted as
	       ** a valid physical address
	       */
	       if (*(typePtr+1) != '\0')
		  return ER_ADR_INVALID_ADDRESS_STR;
	       /* physical offset type */
	       if ((err = AdrSetAddrType(desc,ADDR_PHYSICAL)) != GOOD)
		  return err;
	       *typePtr = '\0';
	    }
	    else if ((typePtr = _fstrpbrk(token[0],"Ll")) != NULL) {
	       /* now check for a null character after the "Ll"
	       ** so that something like "clear" is not accepted as
	       ** a valid linear address
	       */
	       if (*(typePtr+1) != '\0')
		  return ER_ADR_INVALID_ADDRESS_STR;
	       /* 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 (stricmp(text,"eip") == 0)  {
		  if ((err = AdrSetAddrSegmentSelector(desc,ADDR_USE_CS,NULL)) 
			!= GOOD)
		     return err;
	       }
	    }
	 }
	 else {     /* FAMILY_68K */
	    if ((err = AdrSetAddrType(desc,ADDR_LINEAR)) != GOOD)
	       return err;
	 }
	 tempU32 = strtoU32DefRadix(token[0], &endPtr);
	 if (*endPtr != '\0')
	    return ER_ADR_INVALID_ADDRESS_STR;

// added address string limit checking. gene 1/31/97 
         if ( (((A_D)desc)->type == ADDR_PHYSICAL) && (tempU32 > 0xFFFFFl) )
            return ER_ADR_INVALID_ADDRESS_STR;
         if ( (((A_D)desc)->type == ADDR_VIRTUAL) && (tempU32 > 0xFFFFl) )
	    return ER_ADR_INVALID_ADDRESS_STR;
	 if ((err = AdrSetAddrOffset(desc,tempU32)) != 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 (procCpu) {
      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:
	 if (inputText[0] == '\0')
	    return GOOD;
	 //!! otherwise, check the case in 386 way
      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 (procCpu) {
      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 maxOutputAddr;
   RETCODE err=GOOD;

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

   if ((tmpAddrOffset > maxOutputAddr) || 
	 (tmpAddrOffset < ((A_D)desc)->addrOffset))
     err = (ER_ADR_RESULT_OVERFLOW) ;
   ((A_D)desc)->addrOffset = tmpAddrOffset;
   return err;  
}

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

   U32 tmpAddrOffset;
   U32 maxOutputAddr;
   RETCODE err=GOOD;

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

   if (tmpAddrOffset > maxOutputAddr)
      err =  (GetExceedsMaxError(desc1));

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


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

   U32 tmpAddrOffset;
   U32 maxOutputAddr;
   RETCODE err;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if ((err = AdrGetMaxOutputAddrOffset(desc,&maxOutputAddr)) != GOOD)
      return err;
   tmpAddrOffset = ((A_D)desc)->addrOffset + value;
      // Address offset addition overflow - set to maxOutputAddr
   if ( (((A_D)desc)->type) == ADDR_VIRTUAL) {
      if (tmpAddrOffset > 0xffffL) {
         ((A_D)desc)->addrOffset = 0xffffL;      
         return ER_ADR_RESULT_OVERFLOW;
      }
   } else {
      if ((tmpAddrOffset > maxOutputAddr) || 
	 (tmpAddrOffset < ((A_D)desc)->addrOffset))
      {
        tmpAddrOffset = maxOutputAddr;
	return ER_ADR_RESULT_OVERFLOW;
      }
   }
   ((A_D)desc)->addrOffset = tmpAddrOffset;
   return GOOD; 
}

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

   RETCODE err = GOOD;

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

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

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

   RETCODE err=GOOD;

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

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

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

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif

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

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

#ifndef ADR_UAE
   if ((0L == desc1) || (0L == desc2))
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc1)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)desc2)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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)
      if ((err = CheckSegments((A_D)desc1,(A_D)desc2)) != GOOD)
	 return err;
   *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;
   if (!((A_D)desc1)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)desc2)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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);
   return GOOD;
}

/************************************************************************
**
**  AdrCompareAddressText
**
************************************************************************/
RETCODE EXPORT AdrCompareAddressText(DESCRIPTOR desc1, DESCRIPTOR desc2,
				     BOOLEAN FAR *identical) {

   return (AdrAreAddrsIdentical(desc1,desc2,identical));

}

/************************************************************************
**
**  AdrAreAddrsIdentical
**
**************************************************************************/
RETCODE EXPORT AdrAreAddrsIdentical(DESCRIPTOR addr1, DESCRIPTOR addr2,
				    BOOLEAN FAR *identical) {
#ifndef ADR_UAE
   if ((0L == addr1) || (0L == addr2))
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)addr1)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)addr2)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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) {
   RETCODE err;

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

#ifdef SPACE_CHECKED
      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;
	 }
      }
#endif

   }
   else {

      if (((A_D)desc1)->space != ((A_D)desc2)->space)
	 return ER_ADR_DIFFER_SPACES;
      if (((A_D)desc1)->type == ADDR_VIRTUAL)
	 if ((err = CheckSegments((A_D)desc1,(A_D)desc2)) != GOOD)
	    return err;
   }

   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 */


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

#ifndef ADR_UAE
   if ((0L == desc1) || (0L == desc2))
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc1)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)desc2)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif

   /* check for type */
   if (((A_D)desc1)->type != ADDR_PHYSICAL) {
      if ((err = AddrToPhysical(desc1,&physOffset1)) != GOOD)
	 return err;
   }
   else
      physOffset1 = ((A_D)desc1)->addrOffset;
   /* check for type */
   if (((A_D)desc2)->type != ADDR_PHYSICAL) {
      if ((err = AddrToPhysical(desc2,&physOffset2)) != GOOD)
	 return err;
   }
   else
      physOffset2 = ((A_D)desc2)->addrOffset;
   /* check for same space if 68K uP */
   if (FAMILY_68K == procFamily) {

#ifdef SPACE_CHECKED
      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;
	 }
      }
#endif

   }
   else {

      if (((A_D)desc1)->space != ((A_D)desc2)->space)
	 return ER_ADR_DIFFER_SPACES;
   }

   if (physOffset2 < physOffset1) {
      *numBytes = physOffset1 - physOffset2 + 1;

   } else {
      *numBytes = physOffset2 - physOffset1 + 1;
   }
   return(GOOD) ;
}  /* end of AdrPhysicalRangeOfAddresses */

/****************************************************************************
**
** AdrIsAddrInRange(1)
**
** 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 AdrIsAddrInRange1(DESCRIPTOR inputAddr,
			        DESCRIPTOR rangeAddr,
			        BOOLEAN FAR *isInRange)  {
   RETCODE err;
   U32 startTmp,endTmp,segTmp;
   U32 physRangeStart,
       inputStart;
   SEG_INFO segInfo;
   int index;

   MEM_ADDR_CLASS memoryClass;
   SYM_TYPE_TYPE  symbolType;
   U32            offset;
   SYM_DESCRIPTOR outputSymbol;
   SYM_DESCRIPTOR funcDescriptor;
   SYM_DESCRIPTOR moduleDescriptor;
   *isInRange = FALSE;

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

#ifndef ADR_UAE
   if ((0L == inputAddr)|| (0L == rangeAddr))
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)rangeAddr)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)inputAddr)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif

   if(!RANGE_DESC->rangeActive)
      return ER_ADR_NOT_RANGE_TYPE;
   if(RANGE_DESC->type != INPUT_DESC->type) {
      return(ER_ADR_DIFFER_TYPES);
   }
   if(FAMILY_68K == procFamily){
#ifdef SPACE_CHECKED
      if((SPACE_DONT_CARE == (INPUT_DESC->space)) ||
        (SPACE_DONT_CARE == (RANGE_DESC->soace))) {
      }else {
         if((INPUT_DESC->space) != (RANGE_DESC->space)){
	    return ER_ADR_DIFFER_SPACES;
      }
#endif
    }
   else {
       if (INPUT_DESC->space != RANGE_DESC->space)
	  return ER_ADR_DIFFER_SPACES;

       SymMapAddr2Symbol(rangeAddr,
                         &memoryClass,
                         &symbolType,
                         &offset,
                         &outputSymbol,
                         &funcDescriptor,
		         &moduleDescriptor);
      if (moduleDescriptor != NULL_SYMBOL) {
	 if (INPUT_DESC->type != ADDR_PHYSICAL) {
            if ((err = AddrToPhysical(inputAddr,&inputStart)) != GOOD)
	       return err;
            }
         else
            inputStart = INPUT_DESC->addrOffset;
         SymGetSegInfo(moduleDescriptor, &segInfo);
         for (index = 0; index < segInfo.segNum; index++) {
	    segTmp = segInfo.segment[index];
	    if (INPUT_DESC->addrSegSel == segTmp) {
               segTmp = segTmp << 4;
               startTmp = segTmp + (U32)(segInfo.beginAddr[index]);
               endTmp = segTmp + (U32)(segInfo.endAddr[index]);
	       if (startTmp <= inputStart && inputStart <= endTmp) {
	          *isInRange = TRUE;
	          return GOOD;
	       }
            }
	 }
      }
      if (INPUT_DESC->type == ADDR_VIRTUAL)
         if ((CheckSegments(INPUT_DESC,RANGE_DESC)) != GOOD) {
            *isInRange = FALSE; 
	     return GOOD;
	 }
   }
   if (!(*isInRange)){
      *isInRange = (!RANGE_DESC->rangeLength ||
	            !((INPUT_DESC->addrOffset < RANGE_DESC->addrOffset) ||
                    (INPUT_DESC->addrOffset >
	       (RANGE_DESC->addrOffset + (RANGE_DESC->rangeLength - 1L)))));
   }
   return GOOD;
} /* end of AdrisAddrInRange1*/

/****************************************************************************
**
** 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)  {

#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 - 1L);
#endif
      
#ifndef ADR_UAE
   if ((0L == inputAddr) || (0L == rangeAddr))
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)inputAddr)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)rangeAddr)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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);
   }

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

#ifdef SPACE_CHECKED
      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;
      }
#endif

   }
   else {
      if (INPUT_DESC->space != RANGE_DESC->space)
	 return ER_ADR_DIFFER_SPACES;
      if (INPUT_DESC->type == ADDR_VIRTUAL)
	 if ((CheckSegments(INPUT_DESC,RANGE_DESC)) != GOOD) {
	    *isInRange = FALSE; 
	    return GOOD;
	 }
   }

   /* 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?
   */
   *isInRange = (!RANGE_DESC->rangeLength ||
		 !((INPUT_DESC->addrOffset < RANGE_DESC->addrOffset) ||
		   (INPUT_DESC->addrOffset >
		   (RANGE_DESC->addrOffset + (RANGE_DESC->rangeLength - 1L)))));
   return GOOD;
} /* end of AdrIsAddrInRange */
/****************************************************************************
**
** AdrIsAddrInDasmRange
**
** THIS ROUTINE IS USED BY THE SOURCE WINDOW ONLY.
** Test for inside range:
**    input >= start of range AND
**    input < end of range which is equivalent to
**    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 AdrIsAddrInDasmRange(DESCRIPTOR inputAddr, DESCRIPTOR rangeAddr,
				BOOLEAN FAR *isInRange)  {

#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 - 1L);
#endif
      
#ifndef ADR_UAE
   if ((0L == inputAddr) || (0L == rangeAddr))
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)inputAddr)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)rangeAddr)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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);
   }

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

#ifdef SPACE_CHECKED
      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;
      }
#endif

   }
   else {
      if (INPUT_DESC->space != RANGE_DESC->space)
	 return ER_ADR_DIFFER_SPACES;
      if (INPUT_DESC->type == ADDR_VIRTUAL)
	 if ((CheckSegments(INPUT_DESC,RANGE_DESC)) != GOOD) {
	    *isInRange = FALSE;
	    return GOOD;
	 }
   }

   /* 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?
   */
   *isInRange = (!RANGE_DESC->rangeLength ||
		 !((INPUT_DESC->addrOffset < RANGE_DESC->addrOffset) ||
		   (INPUT_DESC->addrOffset >=
		    (RANGE_DESC->addrOffset +
		     (RANGE_DESC->rangeLength - 1L)))));
   return GOOD;
} /* end of AdrIsAddrInDasmRange */

/*************************************************************************
**
** 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 startTmp,endTmp,segTmp;
   U32 physRangeStart,
       inputStart;
   SEG_INFO segInfo;
   int index;
   MEM_ADDR_CLASS memoryClass;
   SYM_TYPE_TYPE symbolType;
   U32           offset;
   SYM_DESCRIPTOR outputSymbol;
   SYM_DESCRIPTOR funcDescriptor;
   SYM_DESCRIPTOR moduleDescriptor;
   *isInRange = FALSE;

#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;
   if (!((A_D)inputAddr)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)rangeAddr)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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?
   */
   SymMapAddr2Symbol(rangeAddr,
                     &memoryClass,
                     &symbolType,
                     &offset,
                     &outputSymbol,
                     &funcDescriptor,
		     &moduleDescriptor);

   if (moduleDescriptor != NULL_SYMBOL) {
      SymGetSegInfo(moduleDescriptor, &segInfo);
      for (index = 0; index < segInfo.segNum; index++) {
         segTmp = segInfo.segment[index];
         segTmp = segTmp << 4;
         startTmp = segTmp + (U32)(segInfo.beginAddr[index]);
         endTmp = segTmp + (U32)(segInfo.endAddr[index]);
         if (startTmp <= inputStart && inputStart <= endTmp)
	    *isInRange = TRUE;
      }
   }
   if (!(*isInRange)){
      *isInRange = (!RANGE_DESC->rangeLength ||
       		    !((inputStart < physRangeStart) ||
		   (inputStart >
		   (physRangeStart + (RANGE_DESC->rangeLength - 1L)))));
   }
   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;
   if (!((A_D)rangeAddr1)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)rangeAddr2)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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);
   }

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

#ifdef SPACE_CHECKED
      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;
	 }
      }
#endif

   }
   else {
      if (RANGE_DESC1->space != RANGE_DESC2->space)
	 return ER_ADR_DIFFER_SPACES;
      if (RANGE_DESC1->type == ADDR_VIRTUAL)
	 if ((CheckSegments(RANGE_DESC1,RANGE_DESC2)) != GOOD) {
	    *isEqual = FALSE;
	    return GOOD;
	 }
   }

   *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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   switch (direction) {
      case ADDR_RANGE_LOW :
	 /* move range to low memory either numBytes or
	 ** as much as possible while maintaining the length
	 */
	 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 while maintaining the length
	 */
	 if ((err = AdrGetMaxOutputAddrOffset(desc,&maxOffset)) != GOOD)
	    return err;
	 if ((err = AdrGetEndAddrOffset(desc, &endRangeOffset)) != GOOD)
	    return err;
     if (((A_D)desc)->type == ADDR_VIRTUAL) {
        maxOffset = 0xffffL;
     }
	 if ((maxOffset - endRangeOffset) < numBytes) {
	    ((A_D)desc)->addrOffset = maxOffset -
				       (((A_D)desc)->rangeLength + 1L);
	 }
	 else {
	    if ((err = AdrAddToAddress(desc,numBytes)) != GOOD)
	       return err;
	 }
	 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 - 1L);
	    ((A_D)desc)->addrOffset = 0L;
	    ((A_D)desc)->rangeLength = endRangeOffset + 1L;
	 }
	 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
		  + 1L;
	 }
	 break;
      case ADDR_RANGE_EXPAND_BOTH:
	 if (AdrSubtractFromAddress(desc,numBytes) ==
		ER_ADR_RESULT_UNDERFLOW) {
	    endRangeOffset = ((A_D)desc)->addrOffset +
				       (((A_D)desc)->rangeLength - 1L);
	    ((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 + 1L;
	    }
	 }
	 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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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 (GetExceedsMaxError(desc));
   }
   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;
   SEG_INFO segInfo;

   MEM_ADDR_CLASS memoryClass;
   SYM_TYPE_TYPE  symbolType;
   U32            offset;
   SYM_DESCRIPTOR outputSymbol;
   SYM_DESCRIPTOR funcDescriptor;
   SYM_DESCRIPTOR moduleDescriptor;
   U16 segTmp;

#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;
   if (!((A_D)range1)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)range2)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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)
      if ((CheckSegments(RANGE_1,RANGE_2)) != GOOD) {
	 *overlap = FALSE;
	 return GOOD;
      }*/

   /* 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) - 1L);
   startAddr2 = RANGE_2->addrOffset;
   endAddr2   = startAddr2 + ((RANGE_2->rangeLength) - 1L);
   SymMapAddr2Symbol(range1,
                     &memoryClass,
                     &symbolType,
                     &offset,
                     &outputSymbol,
                     &funcDescriptor,
		     &moduleDescriptor);
   if (moduleDescriptor != NULL_SYMBOL) {
       int index;
       SymGetSegInfo(moduleDescriptor, &segInfo);
       for (index = 0; index < segInfo.segNum; index++) {
          segTmp = segInfo.segment[index];
	  if (RANGE_2->addrSegSel == segTmp) {
	       startAddr1 = (U32)segInfo.beginAddr[index];
	       endAddr1 = (U32)segInfo.endAddr[index];
	       *overlap = ((startAddr1 <= startAddr2) ?
	          (!(endAddr1 < startAddr2) || (endAddr2 < startAddr1)) :
	          (!(endAddr2 < startAddr1) || (endAddr1 < startAddr2)));
               if(*overlap)
	          return GOOD;
	  }
       }   
   }
   if (RANGE_1->type == ADDR_VIRTUAL)
      if ((CheckSegments(RANGE_1,RANGE_2)) != GOOD) {
	 *overlap = FALSE;
	 return GOOD;
      }
   startAddr1 = RANGE_1->addrOffset;
   endAddr1   = startAddr1 + ((RANGE_1->rangeLength) - 1L);

   /*
   ** 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;
   if (!((A_D)range1)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)range2)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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) - 1L);
   
   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) - 1L);

   /* 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;
   if (!((A_D)rangeDesc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)inputDesc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if ((err = AdrGetMaxInputAddrOffset(desc,&maxInputAddr)) != GOOD)
      return err;
   if (((A_D)desc)->addrOffset > maxInputAddr)
      return (GetExceedsMaxError(desc));
   if (((A_D)desc)->addrOffset == maxInputAddr) { 
      *numBytes = 0;      
   } 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;
   if (!((A_D)sourceDesc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
   if (!((A_D)destinationDesc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if (sourceDesc == destinationDesc)
      return GOOD;
   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;
   if (!((A_D)desc1)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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;
   SYM_DESCRIPTOR module;
   DESCRIPTOR  tmpDesc;
   LINENUM_TYPE  linenum;
   COLUMN_RANGE_TYPE   column;
   LINENUM_DESCRIPTOR line;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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)  {
	   /*
	   **  Mapping from linear to virtual is handled via
	   **  the symbol server.  
	   */
	    if ((err = AdrDuplicateAddress(desc,&tmpDesc)) != GOOD)
	       return err;
	    if ((err = SymTranslateLinearToVirtual(desc,
						   tmpDesc)) != GOOD)
	       return err;
	    if ((err = AdrCopyAddress(tmpDesc,desc)) != GOOD)
	       return err;
	    *rangeCovered = TRUE; 
	    if ((err = AdrCremateAddress(&tmpDesc)) != GOOD)
	       return err;
	    return GOOD;
	 }
	 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
**
*****************************************************************************/
RETCODE EXPORT AdrConvertPointerToAddress(DESCRIPTOR desc,
					  U8 pointerSize,
					  COMPLEX_TYPE pointerType) {

   RETCODE err;
   U32 offsetValue=0;
   U16 segmentValue=0;
   BOOLEAN segmentRead=FALSE;
   CHAR buf[6];

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if (!((pointerSize == 2) || (pointerSize == 4) || (pointerSize == 6)))
      return ER_ADR_INVALID_PTR_SIZE;
   /* clear mem read buffer */
   memset(buf,'\0',6);

   /* get the pointer value out of target memory */
   if ((err = MemReadSizedNoAlloc(desc, (U16)pointerSize,(U8*)buf,
				  BYTE_SIZE, CACHE_USE)) != GOOD)
      return(err);
 
   switch (pointerSize) {
      case 2:
	 if (pointerType == TY_SMALL_PTR) 
	    offsetValue = MemSwapBytesInWord(*(U16 *)buf);
	 else
	    return ER_ADR_INVALID_PTR_SIZE;
	 break;
      case 4:
	 if (pointerType == TY_LARGE_PTR) {
	    offsetValue = MemSwapBytesInLong(*(U32 *)buf);
	 }
	 else if (pointerType == TY_16_16_PTR) {
	    offsetValue = MemSwapBytesInWord(*(U16 *)buf);
	    segmentValue = MemSwapBytesInWord(*(U16 *)(buf + 2));
	    segmentRead = TRUE;
	 }
	 else
	    return ER_ADR_INVALID_PTR_SIZE;
	 break;
      case 6:
	 if (pointerType == TY_16_32_PTR) {
	    offsetValue = MemSwapBytesInLong(*(U32 *)buf);
	    segmentValue = MemSwapBytesInWord(*(U16 *)(buf + 4));
	    segmentRead = TRUE;
	 }
	 else
	    return ER_ADR_INVALID_PTR_SIZE;
	 break;
   }
   /* 05/24/94 - Nghia
   ** handle 68HC16 pointer dereference using index extension registers
   */
   if ((procCpu == PROC_CPU_CPU16) && (pointerType == TY_SMALL_PTR) && 
       usedIndexExtReg) {
      U32 extRegVal = 0L;
      // Get the 20bit index extension register value -
      // mask all bits except the 4 bits extension and
      // set to the dereferenced address
      if ((err = CpuGetRegister(extRegId, (U32 FAR *)&extRegVal)) != GOOD)
	 return err;
      // mask off the lower bits of the register value
      extRegVal &= 0x000f0000L;
      // set the extension bits for the offsetValue
      offsetValue |= extRegVal; 
   }
   /* put address back into original descriptor */
   ((A_D)desc)->addrOffset = offsetValue;
   if (segmentRead) {
      ((A_D)desc)->addrSegSel = segmentValue;
      ((A_D)desc)->segSelType = ADDR_USE_VALUE;
   }
   else if ((pointerType == TY_SMALL_PTR) || (pointerType == TY_LARGE_PTR)) {
      ((A_D)desc)->segSelType = ADDR_USE_DEF_DS;
      if ((err = GetSegmentRegister(((A_D)desc)->segSelType,
           &segmentValue)) != GOOD)
         return err;
      ((A_D)desc)->addrSegSel = segmentValue;
   }
   return(GOOD);
}  /* end of AdrConvertPointerToAddress */

/****************************************************************************
**
**  AdrConvertAddressToPointer
**
*****************************************************************************/
RETCODE EXPORT AdrConvertAddressToPointer(DESCRIPTOR desc,
					  U8 pointerSize,
					  COMPLEX_TYPE pointerType,
					  LPU8 ptrBuf) {

   RETCODE err;
   CHAR buf[6];

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if (!((pointerSize == 2) || (pointerSize == 4) || (pointerSize == 6)))
      return ER_ADR_INVALID_PTR_SIZE;
   memset(buf,'\0',sizeof(buf));
 
   switch (pointerSize) {
      case 2:
	 if (pointerType == TY_SMALL_PTR) 
	    *(U16 *)buf = (U16)((A_D)desc)->addrOffset;
	 else
	    return ER_ADR_INVALID_PTR_SIZE;
	 break;
      case 4:
	 if (pointerType == TY_LARGE_PTR) {
	    *(U32 *)buf = (U32)((A_D)desc)->addrOffset;
	 }
	 else if (pointerType == TY_16_16_PTR) {
	    *(U16 *)buf = (U16)((A_D)desc)->addrOffset;
	    *(U16 *)(buf + 2) = (U16)((A_D)desc)->addrSegSel;
	 }
	 else
	    return ER_ADR_INVALID_PTR_SIZE;
	 break;
      case 6:
	 if (pointerType == TY_16_32_PTR) {
	    *(U32 *)buf = (U32)((A_D)desc)->addrOffset;
	    *(U16 *)(buf + 4) = (U16)((A_D)desc)->addrSegSel;
	 }
	 else
	    return ER_ADR_INVALID_PTR_SIZE;
	 break;
   }
   if (ptrBuf != NULL)
      movmem(buf,ptrBuf,sizeof(buf));
   return(GOOD);
}  /* end of AdrConvertAddressToPointer */

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

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   *active = ((A_D)desc)->rangeActive;
   return(GOOD);
}

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

   RETCODE err=GOOD;
   U32 maxOutputAddr;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   /*if (((A_D)desc)->addrOffset > offset)
      return(ER_ADR_END_ADDR_TOO_SMALL); Hera 5/8/97*/

   /*  allow creation of invalid descriptors **
   /* check that it doesn't go over max address boundary **
   ** if ((err = AdrGetMaxOutputAddrOffset(desc,&maxOutputAddr)) != GOOD)
   **    return err;
   ** if (offset > maxOutputAddr) {
   **    err =  (GetExceedsMaxError(desc));
   **    ((A_D)desc)->rangeLength = maxOutputAddr - 
   **          ((A_D)desc)->addrOffset + 1L;
   ** }
   ** else
   */
   ((A_D)desc)->rangeLength = offset - ((A_D)desc)->addrOffset + 1L;
   ((A_D)desc)->rangeActive = TRUE;
   return(err);
}

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

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

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

   U32 rangeMinusOne;
   RETCODE err;
   U32 maxOutputAddr;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if ((err = AdrGetMaxOutputAddrOffset(desc,&maxOutputAddr)) != 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 - 1L;
      /* now matches maxOutputAddr in representation */
   /* check that it doesn't go over max address boundary */
   if (rangeMinusOne > maxOutputAddr)
      return ER_ADR_ADDRESS_TOO_LARGE;
 
   if ((maxOutputAddr - ((A_D)desc)->addrOffset) < rangeMinusOne)
      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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   *numBytes = ((A_D)desc)->rangeLength;
   return(GOOD);
}

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

   RETCODE err;
   U32 maxOutputAddr;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   /* allow invalid descriptors to be created **
   ** if ((err = AdrGetMaxOutputAddrOffset(desc,
   **       &maxOutputAddr)) != GOOD)
   **    return err;
   ** if (offset > maxOutputAddr)
   **    return (GetExceedsMaxError(desc));
   */
   ((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;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   *offset = ((A_D)desc)->addrOffset;
   return(GOOD);
}

/****************************************************************************
**
**  AdrGetAddrSegment
**
*****************************************************************************/
RETCODE EXPORT AdrGetAddrSegment(DESCRIPTOR desc, U16 FAR *segment) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   *segment = ((A_D)desc)->addrSegSel;
   return(GOOD);
}

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

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   return(AddrToPhysical(desc,offset));
}

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

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   return(AddrToLinear(desc,offset));
}
/****************************************************************************
**
**  AdrGetAddrSegmentSelector
**
*****************************************************************************/
RETCODE EXPORT
AdrGetAddrSegmentSelector(DESCRIPTOR desc,
			  ADDR_SEGSEL_TYPE FAR *type,
			  U16 FAR *segsel) {

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#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,
			  U16 *segsel) {
   RETCODE err;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if (FAMILY_68K == procFamily)
      return(ER_ADR_NOT_MOTOROLA_USAGE);
   else {
     ((A_D)desc)->segSelType = type;
     // if a value is provided use it otherwise go read the register
     // for the current value
     if (segsel != NULL)
	((A_D)desc)->addrSegSel = *segsel;
     else {
	return (GetSegmentRegister(type,&((A_D)desc)->addrSegSel));
     }
   }
   return GOOD;
}

/**************************************************************************
**
** AdrGetMaxInputAddrOffset
**
**  NOTE: For Moto processors desc can be NULL
**
************************************************************************/
RETCODE EXPORT AdrGetMaxInputAddrOffset(DESCRIPTOR desc,
					U32 FAR *maxInputAddress)  {
   RETCODE err;
   
#ifndef ADR_UAE
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   switch (procCpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
	 *maxInputAddress = 0xFFFFFFFFL;
	 break;
      case PROC_CPU_CPU16:
	 *maxInputAddress = 0x000FFFFFL;
	 break;
      case PROC_CPU_68000:
	 break;
      case PROC_CPU_68040:
	 break;
      case PROC_CPU_80186:
      case PROC_CPU_80386:
      case PROC_CPU_80486:
#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
	 return (X86GetMaxOffset(desc,
				 maxInputAddress));
   }
   return GOOD;
}


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

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   switch (procCpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
	 if ((err = ProcReturnSpecificProcessor(&proc))
		!= GOOD) return(err);
	 switch (proc) {
	    case M68331_TB: case M68331_SH:
	    case M68332_TB: case M68332_SH:
	    case M68333_TB: case M68333_SH:
	    case M68334_TB: case M68334_SH:
	       *maxOutputAddress = 0x00FFFFFFL;
	       break;
	    default:
	       *maxOutputAddress = 0xFFFFFFFFL;
	       break;
	 }
	 break;
      default:
	 return AdrGetMaxInputAddrOffset(desc, maxOutputAddress);
   }
   return GOOD;
}

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

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   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;

#ifndef ADR_UAE
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   switch (procCpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
	 *maxInputAddrDigits = 8;
	 break;
      case PROC_CPU_CPU16:
	 *maxInputAddrDigits = 5;
	 break;
      case PROC_CPU_68000:
	 break;
      case PROC_CPU_68040:
	 break;
      case PROC_CPU_80186:
	 if (((A_D)desc)->segSelType != ADDR_USE_VALUE)
	    *maxInputAddrDigits = 7;
	 else
	    *maxInputAddrDigits = 9;
#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 (TranslateAddrMode(((A_D)desc)->mode)) {
		  case MODE_REAL:
		  case MODE_V86:
		     if (((A_D)desc)->segSelType != ADDR_USE_VALUE)
			*maxInputAddrDigits = 7;
		     else
			*maxInputAddrDigits = 9;
		     break;
		  case MODE_SMM:
		  case MODE_PROT16:
		  case MODE_PROT32:
		     if (((A_D)desc)->ldt != 0) {
			if (((A_D)desc)->segSelType != ADDR_USE_VALUE)
			   *maxInputAddrDigits = 16;
			else
			   *maxInputAddrDigits = 18;
		     }
		     else {
			if (((A_D)desc)->segSelType != ADDR_USE_VALUE)
			   *maxInputAddrDigits = 11;
			else
			   *maxInputAddrDigits = 13;
		     }
		     break;
		  }
	       break;
	    case ADDR_LINEAR:
	       /* includes the L postfix */
	       *maxInputAddrDigits = 9;
	       break;
	    case ADDR_PHYSICAL:
	       /* includes the P postfix */
	       if ((err = ProcReturnSpecificProcessor(&proc)) != GOOD)
		  return err;
	       switch (proc) {
		  case I80386DX_TB: case I80386DX_SH:
		     *maxInputAddrDigits = 9;
		     break;
		  case I80386SX_TB: case I80386SX_SH:
		     *maxInputAddrDigits = 7;
		     break;
		  case I80386CX_TB: case I80386CX_SH:
		  case I80386EX_TB: case I80386EX_SH:
		     *maxInputAddrDigits = 8;
		     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;
   
#ifndef ADR_UAE
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   switch (procCpu) {
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
	 if ((err = ProcReturnSpecificProcessor(&specificProcessor))
		!= GOOD) return(err);
	 switch (specificProcessor) {
	    case M68331_TB: case M68331_SH:
	    case M68332_TB: case M68332_SH:
	    case M68333_TB: case M68333_SH:
	    case M68334_TB: case M68334_SH:
	       *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;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   /* if virtual address type don't bother to mask the segment
   ** maximum since it could be full 32 bits.
   */
   if (((A_D)desc)->type == ADDR_VIRTUAL)
      return GOOD;
   /* check for odd address boundary */
   if ((procFamily == FAMILY_68K) && (((A_D)desc)->addrOffset % 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 */
   ((A_D)desc)->addrOffset &= maxInputAddr;
   /* change the end offset as well */    
   if (((A_D)desc)->rangeActive) {
      if ((err = AdrGetEndAddrOffset(desc, &offset)) != GOOD)
	 return err;
      if (offset > maxInputAddr)
      return (AdrSetEndAddrOffset(desc, maxInputAddr));
   }         
   return(GOOD);
}

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

   U32 reg = 0L;
   PMODE oldpMode=pMode;

   switch (eventNum) {
      case EVENT_BKPT_HALTED:
      case EVENT_CPU_EDIT:
	 // Read SDN_PMODE to update
	 if (SdnReadMember(SDN_PMODE,(LPU8)&pMode) != GOOD)
	    pMode = PMODE_END;
	 if (oldpMode != pMode)
	    EnlEventNotify(EVENT_ADR_PMODE_CHANGED);
	 if (CpuGetRegister(CR0regId,&reg) != GOOD)
	    pagingOn = FALSE;
	 else {
	    if (reg & PAGING_ENABLED_MASK)
	       pagingOn = TRUE;
	    else
	       pagingOn = FALSE;
	 }
	 break;
   }
   return GOOD;
}             

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

   *pmode = pMode;
   if (pmodeStr != NULL) {
      *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;
}

/**************************************************************************
**
** AdrGetAddressLimits
**
*************************************************************************/
RETCODE EXPORT AdrGetAddressLimits(DESCRIPTOR desc,
				   U32 FAR *lowerLimit,
				   U32 FAR *upperLimit)  {
   RETCODE err;
   PROBE_TYPE proc;

#ifndef ADR_UAE
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   *lowerLimit = 0;
   *upperLimit = 0;
   switch (procCpu) {
      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 (TranslateAddrMode(((A_D)desc)->mode)) {
		  case MODE_PROT16:
		  case MODE_PROT32:  /* segment limit */
		     if ((err = GetSegmentLimits(desc,lowerLimit,
			   upperLimit)) != GOOD)
			return err;
		     break;
		  default:
		     return AdrGetMaxOutputAddrOffset(desc,upperLimit);
	       }
	       break;
	    default:
	       return AdrGetMaxOutputAddrOffset(desc,upperLimit);
	 }
	 break;
      default:
	 return AdrGetMaxOutputAddrOffset(desc, upperLimit);
   }
   return GOOD;
}


/****************************************************************************
**
** AdrGetSegmentSelectorBase 
**
** NOTE: For use with protected mode addresses only.
**
***************************************************************************/
RETCODE EXPORT AdrGetSegmentSelectorBase(DESCRIPTOR desc, U32 FAR *base) {

   SEGMENT_DESCRIPTOR segDesc;
   BOOLEAN lookupByValue = FALSE;
   U16 segmentValue = 0;
   RETCODE err;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if (((A_D)desc)->segSelType != ADDR_USE_VALUE) {
      /* check if the current segment register specified matches
      ** the descriptor in value.  If it does then read from
      ** the segment's base register, otherwise look up the
      ** base as if it were a value
      */
      if ((err = GetSegmentRegister(((A_D)desc)->segSelType,
	     &segmentValue)) != GOOD)
	 return err;
      if (((A_D)desc)->addrSegSel != segmentValue)
	 lookupByValue = TRUE;
   }
   /* find base address for segment */
   if ( (((A_D)desc)->segSelType == ADDR_USE_VALUE) || lookupByValue ) {
      if ((err = AdrGetSegmentDescCopy(desc,&segDesc)) != GOOD)
	 return err;
      if (!segDesc.segmentPresent)
	 return ER_ADR_SEGMENT_INVALID;
      *base = (((U32)(segDesc.base31_24) << 24) +
	       ((U32)(segDesc.base23_16) << 16) +
		(U32)(segDesc.base15_0));
   }
   else { /* use Base register of the segment register */
      return (GetSegmentBaseRegister(desc,base));
   }
   return GOOD;
}

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

   PMODE useMode;
   SEGMENT_DESCRIPTOR segDesc;
   U32 accessRights=0L;
   U32 opSize=0L;
   RETCODE err;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if (procFamily == FAMILY_X86) {
      if ((((A_D)desc)->type == ADDR_VIRTUAL)  && 
	    X86IsProtectedMode(((A_D)desc)->mode)) {
	 switch (((A_D)desc)->segSelType) {
	    case ADDR_USE_DS:
	    case ADDR_USE_DEF_DS:
	    case ADDR_USE_CS:
	    case ADDR_USE_ES:  
	    case ADDR_USE_FS: 
	    case ADDR_USE_GS:
	    case ADDR_USE_SS:
	       /* check the access register for default size */
	       if ((err = GetSegmentAccessRegister(desc,&accessRights)) != GOOD)
		  return err;
	       opSize = accessRights & OPERATION_SIZE_MASK;
	       break;
	    case ADDR_USE_VALUE:
	    default:
	       /* check the descriptor for default size */
	       if ((err = AdrGetSegmentDescCopy(desc,&segDesc)) != GOOD)
		  return err;
	       opSize = segDesc.opSize;
	       break;
	 }
	 if (opSize)  /* D bit 0 = 16 bit, 1 = 32 bit */
	    *size = ADDR_USE_32;
	 else
	    *size = ADDR_USE_16;
      }
      else {   // physical, linear addresses, and virtual non protected mode
	 useMode = GetPmode(((A_D)desc)->mode);
	 switch (useMode) {
	    case PMODE_P32:
	       *size = ADDR_USE_32;
	       break;
	    case PMODE_REAL:
	    case PMODE_V86:
	    case PMODE_SMM:
	    case PMODE_P16:
	    default:
	       *size = ADDR_USE_16;
	       break;
	 }
      }
   }
   else  { /* procFamily 68K */
      switch (procCpu) {
	 case PROC_CPU_CPU32:
	 case PROC_CPU_CPU32P:
	    *size = ADDR_USE_32;
	    break;
	 case PROC_CPU_CPU16:
	    *size = ADDR_USE_16;
	    break;
      }
   }
   return GOOD;
}

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

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

/***************************************************************************
**
**  AdrGetAddrDescToText
**
***************************************************************************/
RETCODE AdrGetAddrDescToText(DESCRIPTOR desc, LPSTR buf) {
   
   LPSTR tmpPtr=buf;  
   U16 segValue=0;
   CHAR segStr[20];
   RETCODE err;
   BOOLEAN savedState;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   /* save the state so we can dump even dead ones */
   savedState = ((A_D)desc)->activeDesc;
   ((A_D)desc)->activeDesc = TRUE;
   *buf = '\0';
   *segStr = '\0';
   sprintf(buf, "Address Descriptor ");
   tmpPtr += strlen(tmpPtr);
   if ((err = AdrConvAddrRangeToText(desc,FALSE,TRUE,RANGE_BOTH,
	 tmpPtr)) != GOOD)
      return err;
   strcat(buf,"\r\n");  
   tmpPtr += strlen(tmpPtr);
   sprintf(tmpPtr,"====================================\r\n");
   tmpPtr += strlen(tmpPtr);
   if (savedState)
      sprintf(tmpPtr,"Status: Active Descriptor\r\n");
   else
      sprintf(tmpPtr,"Status: ** WARNING ** DESTROYED DESCRIPTOR !!!\r\n");
   tmpPtr += strlen(tmpPtr);
   if (procFamily == FAMILY_X86) {
      // do the ldt
      sprintf(tmpPtr,"Ldt: %X\r\n",((A_D)desc)->ldt);
      tmpPtr += strlen(tmpPtr);
      // do the segment
      sprintf(tmpPtr,"Segment: ");
      tmpPtr += strlen(tmpPtr);
      if ((err = GetSegment(desc,&segValue,segStr))
	    != GOOD)
	 return err;
      if (*segStr != '\0') {
	 sprintf(tmpPtr, "%2.2s = ", segStr);
	 tmpPtr += strlen(tmpPtr);
      }
      sprintf(tmpPtr, "%*.*X\r\n",4,4,segValue);
      tmpPtr += strlen(tmpPtr);
      // do the segment type
      switch (((A_D)desc)->segSelType) {
	 case ADDR_USE_VALUE:
	    sprintf(tmpPtr,"Segment Type: ADDR_USE_VALUE\r\n");
	    break;
	 case ADDR_USE_DS:
	    sprintf(tmpPtr,"Segment Type: ADDR_USE_DS\r\n");
	    break;
	 case ADDR_USE_DEF_DS:
	    sprintf(tmpPtr,"Segment Type: ADDR_USE_DEF_DS\r\n");
	    break;
	 case ADDR_USE_CS:   
	    sprintf(tmpPtr,"Segment Type: ADDR_USE_CS\r\n");
	    break;
	 case ADDR_USE_ES:
	    sprintf(tmpPtr,"Segment Type: ADDR_USE_ES\r\n");
	    break;
	 case ADDR_USE_FS:
	    sprintf(tmpPtr,"Segment Type: ADDR_USE_FS\r\n");
	    break;
	 case ADDR_USE_GS:
	    sprintf(tmpPtr,"Segment Type: ADDR_USE_GS\r\n");
	    break;
	 case ADDR_USE_SS:
	    sprintf(tmpPtr,"Segment Type: ADDR_USE_SS\r\n");
	    break;
      }
      tmpPtr += strlen(tmpPtr);
   }
   // do the offset
   sprintf(tmpPtr,"Offset: %lX\r\n",((A_D)desc)->addrOffset);
   tmpPtr += strlen(tmpPtr);
   // do the space
   sprintf(tmpPtr,"Space: ");
   tmpPtr += strlen(tmpPtr);
   if ((err = AdrGetSpaceStr(((A_D)desc)->space,tmpPtr)) != GOOD)
      return err;
   strcat(tmpPtr,"\r\n");
   tmpPtr += strlen(tmpPtr);
   // do the address type
   switch (((A_D)desc)->type) {
      case ADDR_VIRTUAL:
	 sprintf(tmpPtr,"Type: Virtual\r\n");
	 break;
      case ADDR_LINEAR:
	 sprintf(tmpPtr,"Type: Linear\r\n");
	 break;
      case ADDR_PHYSICAL:
	 sprintf(tmpPtr,"Type: Physical\r\n");
	 break;
   }
   tmpPtr += strlen(tmpPtr);
   // do the address mode
   switch(((A_D)desc)->mode) {
      case MODE_CURRENT:
	 sprintf(tmpPtr,"Mode: Current\r\n");
	 break;
      case MODE_REAL:
	 sprintf(tmpPtr,"Mode: Real\r\n");
	 break;
      case MODE_PROT16:
	 sprintf(tmpPtr,"Mode: Protected 16\r\n");
	 break;
      case MODE_PROT32:
	 sprintf(tmpPtr,"Mode: Protected 32\r\n");
	 break;
      case MODE_V86:
	 sprintf(tmpPtr,"Mode: Virtual 86\r\n");
	 break;
      case MODE_SMM:
	 sprintf(tmpPtr,"Mode: SMM\r\n");
	 break;
      case MODE_NONE:
      default:
	 sprintf(tmpPtr,"Mode: None\r\n");
	 break;
   }
   tmpPtr += strlen(tmpPtr);
   // do the symbolics
   if (((A_D)desc)->symbolUsage)
      sprintf(tmpPtr,"Symbols: TRUE\r\n");
   else
      sprintf(tmpPtr,"Symbols: FALSE\r\n");
   tmpPtr += strlen(tmpPtr);
   // do the range
   if (((A_D)desc)->rangeActive) 
      sprintf(tmpPtr,"Range Active: TRUE\r\n");
   else
      sprintf(tmpPtr,"Range Active: FALSE\r\n");
   tmpPtr += strlen(tmpPtr);
   // do the  range length
   sprintf(tmpPtr,"Range Length: %lX",((A_D)desc)->rangeLength);
   
   /* restore the active state */
   ((A_D)desc)->activeDesc = savedState;
   return GOOD;
   
}

/****************************************************************************
**
** AdrGetSegmentDescCopy
**
***************************************************************************/
RETCODE EXPORT  AdrGetSegmentDescCopy(DESCRIPTOR desc,
				      SEGMENT_DESCRIPTOR *segDesc) {
   RETCODE err;
   U32 tableBase;
   U32 tableLimit;
   U16 index;
   U32 segment;
   CHAR  segStr[SPACE_BUFF_SZ];
   DESCRIPTOR addr;
   U32 segDescOffset;
   BOOLEAN rangeCovered;

#ifndef ADR_UAE
   if (0L == desc)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (!((A_D)desc)->activeDesc)
      return ER_ADR_DESC_NOT_ACTIVE;
#endif
   if ((err = GetSegment(desc,(U16 *)&segment,segStr)) != GOOD)
      return err;
   /* mask out 13 bit descriptor table index */
   index = ((U16)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 */
	 if ((err = GetLdtSelectorBaseAndLimit(desc,&tableBase,
		 &tableLimit)) != GOOD)
	    return err;
      }
      else {
	 /* use current LDTR value */
	 if ((err = CpuGetRegister(LDTBaseId,&tableBase)) != GOOD)
	    return err;
	 if ((err = CpuGetRegister(LDTLimitId,&tableLimit)) != GOOD)
	    return err;
      }
      if (tableBase == 0)
	 return ER_ADR_LDT_INVALID;
   }
   else {
      /* use GDTR */
      /* 09/16/94 Marilyn: 
      ** an index of 0 refers to the null selector.  The processor
      ** does not generate an exception when a segment register is
      ** loaded with a null descriptor, other than CS or SS.  It 
      ** will generate an exception when a segment register holding 
      ** a null selector is used to access memory.  This feature is 
      ** often used to initialize unused segment registers. 
      ** Server will not circumvent the null selector.
      ** 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 */
   /* 09/15/94 Marilyn : if the selector (protected mode) 
   ** was a segment register then there is no need to verify the limit, 
   ** since the segment register was verified when loaded.
   */
   switch (GetPmode(((A_D)desc)->mode)) {
      case PMODE_SMM:
      case PMODE_P16:
      case PMODE_P32:
	 if (*segStr == NULL)  {  // not a segment register
	    if (segDescOffset > 
		  (tableBase+tableLimit-sizeof(SEGMENT_DESCRIPTOR)+1))
	       return ER_ADR_DESCTBL_LIMIT_EXCEEDED;
	 }
	 break;
      case PMODE_V86:
      case PMODE_REAL:
      default:
	 if (segDescOffset > 
	       (tableBase+tableLimit-sizeof(SEGMENT_DESCRIPTOR)+1))
	    return ER_ADR_DESCTBL_LIMIT_EXCEEDED;
	 break;
   }
   /* Set up address to read target memory */
   if ((err = AdrCreateAddressWithType(ADDR_LINEAR,&addr)) != GOOD)
      return err;
   if ((err = AdrSetAddrOffset(addr,segDescOffset)) != GOOD)
      return err;
   if ((err = MemReadSizedNoAlloc(addr,sizeof(SEGMENT_DESCRIPTOR),
	 (LPU8)segDesc, BYTE_SIZE, CACHE_USE)) != GOOD)
      return err;
   if ((err = AdrCremateAddress(&addr)) != GOOD)
      return err;
   return GOOD;

}


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

/****************************************************************************
**
** GetLdtSelectorBaseAndLimit
**
***************************************************************************/
RETCODE PRIVATE  GetLdtSelectorBaseAndLimit(DESCRIPTOR desc,
				      U32 *base, U32 *limit) {
   RETCODE err;
   U32 tableBase;
   U32 tableLimit;
   U32 tmpLimit;
   U16 index;
   SEGMENT_DESCRIPTOR segDesc;
   DESCRIPTOR addr;
   U32 segDescOffset;
   BOOLEAN rangeCovered;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   /* mask out 13 bit descriptor table index */
   index = ((U16)((A_D)desc)->ldt & TABLE_INDEX_MASK) >> 3;
   /* should always be the GDT */
   if ((err = CpuGetRegister(GDTBaseId,&tableBase)) != GOOD)
      return err;
   if ((err = CpuGetRegister(GDTLimitId,&tableLimit)) != GOOD)
      return err;
   /* calculate descriptor location in GDT table */
   segDescOffset = ((index * sizeof(SEGMENT_DESCRIPTOR)) + tableBase);
   /* check for an offset beyond GDT limits */
   if (segDescOffset > 
	 (tableBase+tableLimit-sizeof(SEGMENT_DESCRIPTOR)+1))
      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;
   if ((err = MemReadSizedNoAlloc(addr,sizeof(SEGMENT_DESCRIPTOR),
	 (LPU8)&segDesc, BYTE_SIZE, CACHE_USE)) != GOOD)
      return err;
   if ((err = AdrCremateAddress(&addr)) != GOOD)
      return err;
   if (!segDesc.segmentPresent)
      return ER_ADR_SEGMENT_INVALID;
   *base = (((U32)(segDesc.base31_24) << 24) +
	    ((U32)(segDesc.base23_16) << 16) +
	     (U32)(segDesc.base15_0));
   tmpLimit = (((U32)(segDesc.limit19_16) << 16) + 
		(U32)segDesc.limit15_0);
   *limit = (segDesc.granularity ? (((U32)tmpLimit << 12) + 0xFFF)
	    : tmpLimit);
   return GOOD;

}

/**************************************************************************
**
** X86GetMaxOffset
**
** NOTE: segDesc may be NULL for non protected modes
**
************************************************************************/
RETCODE PRIVATE X86GetMaxOffset(DESCRIPTOR desc,
				U32 FAR *maxInputAddress)  {
   RETCODE err;
   PROBE_TYPE proc;
   U32 min;
   
   *maxInputAddress = 0L;
   switch (procCpu) {
      case PROC_CPU_80186:
	 *maxInputAddress = 0x000FFFFFL;
	 break;
      case PROC_CPU_80386:
	 switch (((A_D)desc)->type) {
	    case ADDR_VIRTUAL:
	       switch (TranslateAddrMode(((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:
	       if ((err = ProcReturnSpecificProcessor(&proc)) != GOOD)
		  return err;
	       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:
	 break;
   }
   return GOOD;
}

/*************************************************************************
**
** GetSegSelFromText
**
**************************************************************************/
RETCODE PRIVATE GetSegSelFromText(LPSTR segSelStr,
				  ADDR_SEGSEL_TYPE *segType,
				  U16 *segment) {
   RETCODE err;
   LPSTR typePtr;
   U32 tempU32=0L;
   S8 *endPtr=NULL;

   *segment = 0;
   *segType = ADDR_USE_VALUE;
   if (segSelStr == NULL) 
      return ER_ADR_INVALID_ADDRESS_STR;
   if ( ((typePtr = _fstrpbrk(segSelStr,"Gg")) != NULL) &&
	  (*(typePtr+1) == '\0') ) {
      /* GDT index */
      *typePtr = '\0';
      tempU32 = strtoul(segSelStr, &endPtr, 0);   /* decimal indexed */
      if (*endPtr != 0)
	 return ER_ADR_INVALID_ADDRESS_STR;
      *segment = (U16)(((U32)(tempU32 & 0x0000ffff) << 3) + GDT_INDICATOR);
   }
   else if ( ((typePtr = _fstrpbrk(segSelStr,"Ll")) != NULL) &&
	      (*(typePtr+1) == '\0') ) {
      /* LDT index */
      *typePtr = '\0';
      tempU32 = strtoul(segSelStr, &endPtr, 0);   /* decimal indexed */
      if (*endPtr != 0)
	 return ER_ADR_INVALID_ADDRESS_STR;
      *segment = (U16)(((U32)(tempU32 & 0x0000ffff) << 3) + LDT_INDICATOR);
   }
   else {
      if ((err = GetSegmentFromText(segSelStr,segType)) != GOOD)
	 return err;
      if (*segType == ADDR_USE_VALUE) {
	 *segment = strtoU16DefRadix(segSelStr, &endPtr);
	 if (*endPtr != 0)
	    return ER_ADR_INVALID_ADDRESS_STR;
      }
      else {
	 if ((err = GetSegmentRegister(*segType, segment)) != GOOD)
	    return err;
      }
   }
   return GOOD;
}

/****************************************************************************
**
** GetSegmentLimits 
**
**  Utilize the hidden segment registers for any address descriptor referencing
**  a segment register.  
**
***************************************************************************/
RETCODE PRIVATE GetSegmentLimits(DESCRIPTOR desc,
				 U32 *minLimit, 
				 U32 *maxLimit) {

   SEGMENT_DESCRIPTOR segDesc;
   U32 tmpLimit = 0L;
   U32 accessRights = 0L;
   U32 granularity = 0L;
   U32 segmentType = 0L;
   BOOLEAN lookupByValue=FALSE;
   U16 segmentValue=0;
   RETCODE err;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   if (((A_D)desc)->segSelType != ADDR_USE_VALUE) {
      /* check if the current segment register specified matches
      ** the descriptor in value.  If it does then read from
      ** the segment's hidden register, otherwise look up the
      ** info as if it were a value descriptor.
      */
      if ((err = GetSegmentRegister(((A_D)desc)->segSelType,
	     &segmentValue)) != GOOD)
	 return err;
      if (((A_D)desc)->addrSegSel != segmentValue)
	 lookupByValue = TRUE;
   }
   if ((((A_D)desc)->segSelType == ADDR_USE_VALUE) || lookupByValue) {
      if ((err = AdrGetSegmentDescCopy(desc,&segDesc)) != GOOD)
	 return err;
      if (!segDesc.segmentPresent)
	 return ER_ADR_SEGMENT_INVALID;
      tmpLimit = (((U32)(segDesc.limit19_16) << 16) + 
		   (U32)segDesc.limit15_0);
      segmentType = segDesc.segmentType;
      granularity = segDesc.granularity;
   }
   else {
      if ((err = GetSegmentLimitRegister(desc,&tmpLimit)) != GOOD)
	 return err;
      if ((err = GetSegmentAccessRegister(desc,&accessRights)) != GOOD)
	 return err;
      if (!(accessRights & SEGMENT_PRESENT_MASK))
	 return ER_ADR_SEGMENT_INVALID;
      granularity = segmentType = accessRights;
      granularity &= GRANULARITY_MASK;
      segmentType &= SEGMENT_TYPE_MASK;
      segmentType >>= 8;
   }
   /* check for expand down data segment */
   if ((segmentType & EXPAND_DN_SEG_MASK) == EXPAND_DN_SEG) { 
      *minLimit = (granularity ? (((U32)tmpLimit << 12) + 0xFFF) + 1
	    : tmpLimit + 1);
      *maxLimit = 0xFFFFFFFFL;
   }
   else {
      *minLimit = 0L;
      *maxLimit = (granularity ? (((U32)tmpLimit << 12) + 0xFFF)
	    : tmpLimit);
   }
   return GOOD;
}


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

   U32 segmentBase;
   U16 segment;
   CHAR segStr[SPACE_BUFF_SZ];
   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 (((A_D)desc)->segSelType == ADDR_USE_VALUE) {
      if ((err = GetSegment(desc,&segment,segStr)) != GOOD)
	 return err;
      segmentBase = (U32)segment;
      segmentBase &= 0x0000ffff;
      *linearAddr = ((U32)segmentBase << 4) + ((A_D)desc)->addrOffset;
   }
   else {  /* use Base register of the segment register */
      if ((err = GetSegmentBaseRegister(desc,&segmentBase)) != GOOD)
	 return err;
      *linearAddr = segmentBase + ((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 = AdrGetSegmentSelectorBase(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) {
      AdrCremateAddress(&addr);
      return err;
   }
   if ((err = MemReadSizedNoAlloc(addr,sizeof(U32),(LPU8)&tableBase,
	 BYTE_SIZE,CACHE_USE_AND_LOCK)) != GOOD) {
      AdrCremateAddress(&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) {
      AdrCremateAddress(&addr);
      return err;
   }
   if ((err = MemReadSizedNoAlloc(addr,sizeof(U32),(LPU8)&pageFrame,
	 BYTE_SIZE,CACHE_USE_AND_LOCK)) != GOOD)  {
      AdrCremateAddress(&addr);
      return err;
   }
   if ((pageFrame & PAGE_PRESENT_MASK) == 0)
      return ER_ADR_PAGE_UNAVAILABLE;
   /* compute physical address */
   *physAddr = (pageFrame & 0xFFFFF000L) + offset;
   if ((err = AdrCremateAddress(&addr)) != GOOD)
      return err;
   return GOOD;
}

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

   U32 linearAddr;
   U32 maxOutput;
   RETCODE err;
   PMODE useMode;
   ADDR_TYPE saveType;

   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);
      saveType = ((A_D)desc)->type;
      ((A_D)desc)->type = ADDR_PHYSICAL;
      if ((err = X86GetMaxOffset(desc,&maxOutput)) != GOOD)  
	 return err;
      ((A_D)desc)->type = saveType;
      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;
	 /* already a physical address since linear = physical
	 ** just mask off unused upper bits.
	 */
	 *physAddr &= maxOutput;
      }
      else if (useMode == PMODE_REAL)  {
	 if (((A_D)desc)->type == ADDR_VIRTUAL) {
	    if ((err = RealToLinear(desc,physAddr)) != GOOD)
	       return err;
	 }
	 else   
	    *physAddr = ((A_D)desc)->addrOffset;
	 /* already a physical address since linear = physical
	 ** just mask off unused upper bits.
	 */
	 *physAddr &= maxOutput;
      }
      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 
	       *physAddr = ((A_D)desc)->addrOffset;
	    /* already a physical address since linear = physical
	    ** just mask off unused upper bits.
	    */
	    *physAddr &= maxOutput;
	 }
      }
      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   
	       *physAddr = ((A_D)desc)->addrOffset & maxOutput;
	    /* already a physical address since linear = physical
	    ** just mask off unused upper bits.
	    */
	    *physAddr &= maxOutput;
	 }
      }
   }
   else if (procFamily == FAMILY_68K) {
      switch (procCpu) {
	 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 (procCpu) {
	 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;
   }
}


/*********************************************************************
**
**  GetAddrMode
**
********************************************************************/
ADDR_MODE PRIVATE GetAddrMode(PMODE inputPmode) {

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

/****************************************************************************
**
** TranslateAddrMode
**
** If input addrMode is MODE_CURRENT, use pMode to determine return addrMode.
***************************************************************************/
ADDR_MODE PRIVATE TranslateAddrMode(ADDR_MODE addrMode) {
   switch (addrMode) {
      case MODE_REAL : 
      case MODE_PROT16 :
      case MODE_PROT32 :
      case MODE_V86 :
      case MODE_SMM :
      case MODE_NONE :
	 return(addrMode);
      case MODE_CURRENT :
      default :
	 switch(pMode) {
	    case PMODE_SMM:  return(MODE_SMM);
	    case PMODE_P16:  return(MODE_PROT16);
	    case PMODE_P32:  return(MODE_PROT32);
	    case PMODE_V86:  return(MODE_V86);
	    case PMODE_REAL:
	    default:         return(MODE_REAL);
	 }
   }
}

/*********************************************************************
**
**  X86IsProtectedMode
**
*********************************************************************/
BOOLEAN PRIVATE X86IsProtectedMode(ADDR_MODE mode) {

   switch (TranslateAddrMode(mode)) {
      case MODE_PROT16:
      case MODE_PROT32: 
	 return TRUE;
      case MODE_SMM:
      case MODE_REAL:
      case MODE_V86:
      default:
	 return FALSE;
   }
}

/****************************************************************************
**
** GetSegment
**
***************************************************************************/
RETCODE PRIVATE GetSegment(DESCRIPTOR desc,U16 *segment,LPSTR segStr) {

   U16 segmentValue=0;
   BOOLEAN lookupByValue=FALSE;
   RETCODE err;

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   *segment = 0;
   *segStr = '\0';
   if (((A_D)desc)->segSelType != ADDR_USE_VALUE) {
      /* check if the current segment register specified matches
      ** the descriptor in value.  If it does then read from
      ** the segment's hidden register, otherwise look up the
      ** info as if it were a value descriptor.
      */
      if ((err = GetSegmentRegister(((A_D)desc)->segSelType,
	     &segmentValue)) != GOOD)
	 return err;
      if (((A_D)desc)->addrSegSel != segmentValue)
	 lookupByValue = TRUE;
   }
   switch (((A_D)desc)->segSelType) {
      case ADDR_USE_DS:
      case ADDR_USE_DEF_DS:
	 *segment = ((A_D)desc)->addrSegSel;
	 if ((segStr != NULL) && !lookupByValue)
	    strcpy(segStr,"DS");
	 break;
      case ADDR_USE_CS:
	 *segment = ((A_D)desc)->addrSegSel;
	 if ((segStr != NULL) && !lookupByValue)
	    strcpy(segStr,"CS");
	 break;
      case ADDR_USE_ES:  /* use stack segment */
	 *segment = ((A_D)desc)->addrSegSel;
	 if ((segStr != NULL) && !lookupByValue)
	    strcpy(segStr,"ES");
	 break;
      case ADDR_USE_FS:  /* use stack segment */
	 *segment = ((A_D)desc)->addrSegSel;
	 if ((segStr != NULL)  && !lookupByValue)
	    strcpy(segStr,"FS");
	 break;
      case ADDR_USE_GS:  /* use stack segment */
	 *segment = ((A_D)desc)->addrSegSel;
	 if ((segStr != NULL)  && !lookupByValue)
	    strcpy(segStr,"GS");
	 break;
      case ADDR_USE_SS:  /* use stack segment */
	 *segment = ((A_D)desc)->addrSegSel;
	 if ((segStr != NULL) && !lookupByValue)
	    strcpy(segStr,"SS");
	 break;
      case ADDR_USE_VALUE:
      default:
	 *segment = ((A_D)desc)->addrSegSel;
	  break;

   }
    return GOOD;
}

/****************************************************************************
**
** GetSegmentFromText
**
***************************************************************************/
RETCODE PRIVATE GetSegmentFromText(LPSTR text, ADDR_SEGSEL_TYPE *segType) {

   *segType = ADDR_USE_VALUE;
   if (text != NULL) {
      if (stricmp(text,"cs") == 0)
	 *segType = ADDR_USE_CS;
      else if (stricmp(text,"ds") == 0)
	 *segType = ADDR_USE_DS;
      else if (stricmp(text, "es") == 0)
	 *segType = ADDR_USE_ES;
      else if (stricmp(text, "fs") == 0)
	 *segType = ADDR_USE_FS;
      else if (stricmp(text, "gs") == 0)
	 *segType = ADDR_USE_GS;
      else if (stricmp(text, "ss") == 0)
	 *segType = ADDR_USE_SS;
   }
   return GOOD;
}

/****************************************************************************
**
**  GetSegmentRegister
**
*****************************************************************************/
RETCODE PRIVATE GetSegmentRegister(ADDR_SEGSEL_TYPE type,
				   U16 *segSel) {
   U32 tempSeg;  
   RETCODE err=GOOD;

   if (FAMILY_68K == procFamily)
      return(ER_ADR_NOT_MOTOROLA_USAGE);
   switch (type) {
      case ADDR_USE_VALUE:
	 tempSeg = 0;
	 break;
      case ADDR_USE_CS:
	 err = CpuGetRegister(CSregId,&tempSeg);
	 break;
      case ADDR_USE_DS:
      case ADDR_USE_DEF_DS:
	 err = CpuGetRegister(DSregId,&tempSeg);
	 break;
      case ADDR_USE_ES:
	 err = CpuGetRegister(ESregId,&tempSeg);
	 break;
      case ADDR_USE_FS:
	 err = CpuGetRegister(FSregId,&tempSeg);
	 break;
      case ADDR_USE_GS:
	 err = CpuGetRegister(GSregId,&tempSeg);
	 break;
      case ADDR_USE_SS:
	 err = CpuGetRegister(SSregId,&tempSeg);
	 break;
   }
   *segSel = (U16)(tempSeg & 0x0000ffff);
   return err;
}

/****************************************************************************
**
**  GetSegmentBaseRegister
**
*****************************************************************************/
RETCODE PRIVATE GetSegmentBaseRegister(DESCRIPTOR desc,
				       U32 *segBase) {

   if (FAMILY_68K == procFamily)
      return(ER_ADR_NOT_MOTOROLA_USAGE);
   switch (((A_D)desc)->segSelType) {
      case ADDR_USE_CS:
	 return(CpuGetRegister(CSBaseRegId,segBase));
      case ADDR_USE_DS:
      case ADDR_USE_DEF_DS:
	 return(CpuGetRegister(DSBaseRegId,segBase));
      case ADDR_USE_ES:
	 return(CpuGetRegister(ESBaseRegId,segBase));
      case ADDR_USE_FS:
	 return(CpuGetRegister(FSBaseRegId,segBase));
      case ADDR_USE_GS:
	 return(CpuGetRegister(GSBaseRegId,segBase));
      case ADDR_USE_SS:
	 return(CpuGetRegister(SSBaseRegId,segBase));
      case ADDR_USE_VALUE:
      default:
	 *segBase = 0L;
	 break;
   }
   return GOOD;
}

/****************************************************************************
**
** GetSegmentLimitRegister
**
**  Utilize the hidden segment registers for any address descriptor referencing
**  a segment register.  
**
***************************************************************************/
RETCODE PRIVATE GetSegmentLimitRegister(DESCRIPTOR desc,
					U32 *segLimitRegister) {

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   *segLimitRegister = 0L;
   switch (((A_D)desc)->segSelType) {
      case ADDR_USE_DS:
      case ADDR_USE_DEF_DS:
	 return(CpuGetRegister(DSLimitRegId,segLimitRegister));
      case ADDR_USE_CS:
	 return(CpuGetRegister(CSLimitRegId,segLimitRegister));
      case ADDR_USE_ES:  
	 return(CpuGetRegister(ESLimitRegId,segLimitRegister));
      case ADDR_USE_FS: 
	 return(CpuGetRegister(FSLimitRegId,segLimitRegister));
      case ADDR_USE_GS:
	 return(CpuGetRegister(GSLimitRegId,segLimitRegister));
      case ADDR_USE_SS:
	 return(CpuGetRegister(SSLimitRegId,segLimitRegister));
      case ADDR_USE_VALUE:
      default:
	 break;
   }
   return GOOD;
}

/****************************************************************************
**
** GetSegmentAccessRegister
**
**  Utilize the hidden segment registers for any address descriptor referencing
**  a segment register.  
**
***************************************************************************/
RETCODE PRIVATE GetSegmentAccessRegister(DESCRIPTOR desc,
					 U32 *segAccessRegister) {

   if (desc == 0L)
      return ER_ADR_INVALID_DESCRIPTOR;
   *segAccessRegister = 0L;
   switch (((A_D)desc)->segSelType) {
      case ADDR_USE_DS:
      case ADDR_USE_DEF_DS:
	 return(CpuGetRegister(DSARRegId,segAccessRegister));
      case ADDR_USE_CS:
	 return(CpuGetRegister(CSARRegId,segAccessRegister));
      case ADDR_USE_ES:  
	 return(CpuGetRegister(ESARRegId,segAccessRegister));
      case ADDR_USE_FS: 
	 return(CpuGetRegister(FSARRegId,segAccessRegister));
      case ADDR_USE_GS:
	 return(CpuGetRegister(GSARRegId,segAccessRegister));
      case ADDR_USE_SS:
	 return(CpuGetRegister(SSARRegId,segAccessRegister));
      case ADDR_USE_VALUE:
      default:
	 break;
   }
   return GOOD;
}

/************************************************************************
**
**  strtoU32DefRadix
**
**************************************************************************/
U32 PRIVATE strtoU32DefRadix(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));

}

/************************************************************************
**
**  strtoU16DefRadix
**
**************************************************************************/
U16 PRIVATE strtoU16DefRadix(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 ((U16)(strtoul(stringPtr,endPtr,16) & 0x0000ffff));
   }
   return ((U16)(strtoul(s,endPtr,defaultRadix) & 0x0000ffff));

}

/************************************************************************
**
**  CheckSegments
**
**************************************************************************/
RETCODE PRIVATE CheckSegments(ADDR_DESCRIPTOR *desc1,
			      ADDR_DESCRIPTOR *desc2) {
   RETCODE err;

#ifndef ADR_UAE
   if ((0L == desc1) || (0L == desc2))
      return ER_ADR_INVALID_DESCRIPTOR;
#endif
   if ((desc1->type == ADDR_LINEAR) && (desc2->type == ADDR_LINEAR))
      return GOOD;
   if ((desc2->type == ADDR_PHYSICAL) && (desc2->type == ADDR_PHYSICAL))
      return GOOD;

   if ((desc1->type != ADDR_VIRTUAL) || (desc2->type != ADDR_VIRTUAL))
      return ER_ADR_DIFFER_SEGMENTS;
   if (desc1->addrSegSel != desc2->addrSegSel)
      return ER_ADR_DIFFER_SEGMENTS;
   return GOOD;
}

/*******************************************************************
**
** GetExceedsMaxError
**
********************************************************************/
RETCODE PRIVATE GetExceedsMaxError(DESCRIPTOR desc) {

   switch (((A_D)desc)->type) {
      case ADDR_VIRTUAL:
	 return ER_ADR_OFFSET_EXCEEDS_MAX;
      case ADDR_LINEAR:
	 return ER_ADR_LINEAR_EXCEEDS_MAX;
      case ADDR_PHYSICAL:
      default:
	 return ER_ADR_PHYS_EXCEEDS_MAX;
  }
  
}

/*********************************************************************
**
**  FlushDescCache
**
**********************************************************************/
VOID PRIVATE FlushDescCache(VOID) {

   descCache.addrSegSel = 0;
   descCache.ldt = 0;
   memset(&descCache.segDesc,'\0',sizeof(SEGMENT_DESCRIPTOR));
}
#ifdef __cplusplus
}
#endif

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

