/****************************************************************************
**
**  Name:  memory.c
**
**  Description:
**     This is the memory server code of the Thunderbird.
**
**  Status:  PRELIMINARY | CODED 
**
**  $Log:   S:/tbird/arcppc/mem/memory.c_v  $
** 
**    Rev 1.4   19 Aug 1997 15:43:58   cjchen
** 
**    Rev 1.3   28 Jul 1997 09:56:46   cjchen
** 
**    Rev 1.2   17 Mar 1997 15:40:58   kevin
** removed "space" from output
** 
**    Rev 1.1   22 Jan 1997 16:19:58   kevin
** added PowerPC family cases
** 
**    Rev 1.0   15 Jan 1997 14:18:26   kevin
** Initial revision.
** 
**    Rev 1.0   03 Jun 1996 11:03:48   gene
** Initial revision.
** 
**    Rev 1.0   24 Jan 1996 15:37:04   kevin
** Initial revision.
** 
**    Rev 1.10   23 Jan 1996 09:03:26   kevin
** MemSetAccessSize will not write accessSize to SDN_LOAD_ACCESS any more
** 
**    Rev 1.9   18 Jan 1996 15:02:14   kevin
** gene's fix
** 
**    Rev 1.7   22 Dec 1995 16:29:58   kevin
** fixed runaccess and verify error problem
** 
**    Rev 1.4   22 Nov 1995 16:36:58   kevin
** gene's modification
** 
**    Rev 1.3   22 Nov 1995 14:25:44   gene
** change memtest, memchecksum
** 
**    Rev 1.2   20 Nov 1995 11:24:40   gene
** init rev for mem win checksum
** 
**    Rev 1.2   17 Nov 1995 13:48:44   kevin
** modified memsetverify()
** 
**    Rev 1.1   16 Nov 1995 11:30:58   kevin
** didn't check space while notification
** 
**    Rev 1.9   13 Oct 1995 15:09:54   kevin
** made srcRange0 and srcRange1 visiable outside this file
** 
**    Rev 1.8   27 Sep 1995 13:45:24   gene
** modified format of verify message
** 
**    Rev 1.5   14 Sep 1995 17:08:34   kevin
** 
**    Rev 1.4   14 Sep 1995 17:05:32   kevin
** solved word boundary problem of checksum function
** 
**    Rev 1.3   14 Sep 1995 16:22:48   kevin
** added checksum
** 
**    Rev 1.2   14 Sep 1995 08:54:26   kevin
** set load size equal to access size
** 
**    Rev 1.1   13 Sep 1995 17:00:26   kevin
** set default access size to be word and set load size to be access size
** 
**    Rev 1.0   07 Sep 1995 09:13:58   gene
** Initial revision.
** 
**    Rev 1.63   08 Apr 1994 14:57:04   nghia
** Fixed bug for PV 2.2:
** - Revised all memory operations to use AdrDoPhysicalRangesOverlap() to
** ensure that any memory modification that map into the source phsyical
** range will be notified.
** - Removed unused copySemaDesc variable - compiler warning.
** 
**    Rev 1.62   06 Oct 1993 16:37:30   tom
** 8802, 8929, 8918: report verify errors, propogate mem write event
** 
**    Rev 1.61   03 Aug 1993 17:14:54   nghia
** Fixed PPR 8735:
** - Rev. 1.60 changed the MEM_EDIT to MEM_HALTED which cause DASM_HALTED event
** to be sent to the Source window.  Since LDR_MEM_CHANGED is sent before
** LDR_LOAD_COMPLETE event, the Source does not retrieve symbol information yet
** and symbol server already received the new symbols, this cause the error
** "Address is within source module, but cannot find."
** - Revised source window to flush cache.
** - Undo the rev. 60.
** 
**    Rev 1.60   28 Jul 1993 14:14:26   nghia
** Changed EVENT_LDR_MEMCHANGED to generate EVENT_MEM_HALTED to propagate
** event thru the DASM server.
** 
**    Rev 1.59   26 Jul 1993 08:50:54   ernie
** Changed callback for EVENT_LDR_MEMCHANGED to propagate EVENT_MEM_EDIT.
** Previously, the EVENT_LDR_LOADCOMPLETE indirectly caused EVENT_MEM_EDIT,
** but as of pv 1.5f, this no longer occurred.
** 
**    Rev 1.58   21 Jul 1993 11:09:06   ernie
** Added check in cache hit alogrithm for wrap around 0
** 
**    Rev 1.57   16 Jul 1993 10:34:42   ernie
** Changed abortFromEsc from U16 to BOOLEAN
** 
**    Rev 1.56   13 Jul 1993 09:29:06   ernie
** Added new event EVENT_LDR_MEMCHANGED.  This is sent by the loader when
** loading is complete and caused memory to be changed (i.e. not nocode).
** This is used by memory.c to flush memory caches.
** 
**    Rev 1.55   25 Jun 1993 17:27:10   paul
** Change CHECK_ABORT to TskCheckAbort
** 
**    Rev 1.54   09 Jun 1993 09:03:58   ernie
** Moved memory search to firmware for added speed
** 
**    Rev 1.53   25 May 1993 17:36:08   paul
** Add memory copy functions
** 
**    Rev 1.52   25 May 1993 13:42:54   ernie
** Added support for cache locking
** 
**    Rev 1.51   25 May 1993 11:55:22   ernie
** Added memory caching of shared data dump buffers
** 
**    Rev 1.50   16 Apr 1993 14:36:46   ernie
** Moved memory access size headaches to firmware.  Now the buffer
** in the fill and dump shared data members are organized as ascending
** byte address order instead of little-endian format.  All necessary
** byte swapping is done by the firmware.
** 
**    Rev 1.49   22 Mar 1993 07:51:46   ernie
** Cleaned up verify error formatting.  Previously, even the expected and
** actual data fields were being printed using AdrConvertAddrToText().  Now
** these use sprintf to print simple hex.
** 
**    Rev 1.48   15 Dec 1992 13:34:26   ernie
** 1. Implemented memory access size.
** 2. Cleaned up MemWrite memory leaks in error cases.
** 
**    Rev 1.47   03 Dec 1992 14:17:54   doug
** free address descriptor (memory leak ppr6450)
** 
**    Rev 1.46   02 Dec 1992 15:28:20   doug
** free memory if MemRead fails
** 
**    Rev 1.45   19 Nov 1992 10:48:10   john
** Implemented memory search check abort.
** Fixed a bug where an error message always caused a popup, even in the
** cli.
** 
**    Rev 1.44   10 Nov 1992 15:24:40   john
** Due to the current use of the memread interface, a valid memory
** buffer must be allocated regardless of whether or not the read
** instruction completes without an error.
** 
**    Rev 1.43   29 Oct 1992 14:38:22   john
** removed tfree calls on error in memread. Caller handles
** 
**    Rev 1.42   22 Oct 1992 16:43:12   john
** removed leading zeros from actual/expected data printout
** 
**    Rev 1.41   20 Oct 1992 11:03:32   john
** Added MemGetVerifyErrorString.  This routine passes a string
** containing the location and data associated with a verify error.
** This is used by the presenters to display the verify error data.
** 
**    Rev 1.40   16 Oct 1992 17:06:28   john
** backed out previous changes, rmv'd memfill call to memwrite
** 
**    Rev 1.39   06 Oct 1992 12:55:56   john
** Memfill is now being called with a tmalloc'd buffer.  This
** accomodates the call to memwrite if the start and end address are the
** same.  I added all of the TFree calls needed to do proper cleanup of
** the input buffer.
** 
**    Rev 1.38   05 Oct 1992 11:16:06   john
** Fixed a boundary problem that occured when a search pattern
** overlapped the 1k search block.
** 
**    Rev 1.37   25 Sep 1992 15:49:12   john
** reimplemented reverse search
** 
**    Rev 1.36   18 Sep 1992 15:13:14   john
** fixed memory search to allow very large ranges
** 
**    Rev 1.35   16 Sep 1992 14:43:02   john
** Added MemSetAccessSize2 to set the actual bus access size for memory
** transfers.  MemSetAccessSize just returned an error when the size was
** set to anything but byte access.
** 
**    Rev 1.34   16 Sep 1992 11:41:56   john
** fixed mem fill verify error problem
** 
**    Rev 1.33   14 Sep 1992 15:38:26   john
** Fixed addr/memory leaks on error conditions.
** Changed mem write to free the buffer passed it as spec'd in the .h
** file. 
** 
**    Rev 1.32   08 Sep 1992 12:05:56   john
** updated events
** 
**    Rev 1.31   03 Sep 1992 13:14:26   ernie
** Added set of accessSize in fill command
** 
**    Rev 1.30   25 Aug 1992 10:45:30   brucea
** Fixed PPR5840 - can now abort from fill command
** 
**    Rev 1.29   20 Aug 1992 20:24:56   brucea
** Bug fix in MemSetSourceRange
** 
**    Rev 1.28   20 Aug 1992 11:20:26   doug
** only byte access size is supported for now
** 
**    Rev 1.27   19 Aug 1992 18:50:46   brucea
** Changed: MemSetSourceRanges to MemSetSourceRange and the interface
** 
**    Rev 1.26   18 Aug 1992 18:19:20   brucea
** Created: MemInitOnce to be called from Actor after all initialization done
**    because of loader dependency problem
** #if 0'ed out TerminateServer
** 
**    Rev 1.25   17 Aug 1992 16:47:28   brucea
** Added: check in MemWrite and MemFill that the address range is modifying
**    memory inside the src windows.  Generates event if so.
** Added: MemSetSourceRanges so source presenter can update ranges to compare
**    with
** Made procFamily a PRIVATE
** Removed compiler warnings
** 
**    Rev 1.24   30 Jul 1992 09:24:42   brucea
** Added: extern HANDLE hLib
** Made MemCallback an exported function in order for callbacks to work correctly
** Using MakeProcInstance to register all callbacks
** 
**    Rev 1.23   28 Jul 1992 19:49:26   brucea
** Removed: variables no longer in use
** Modified: variable types to remove compiler warnings of loss of significance
** 
**    Rev 1.22   24 Jul 1992 16:30:30   brucea
** Fixed bug in MemInitServer: #ifdef becomes #if 0
** 
**    Rev 1.21   22 Jul 1992 16:11:42   doug
** a) convert to generic shared data server
** b) added routines to set/get size and verify
** 
**    Rev 1.20   21 Jul 1992 11:52:10   brucea
** Changed: processor dependent lines to calls to proc.h functions
** Merged: remaining used functions in present.c were put into this file
** Changed: name InitServer to MemInitServer
** 
**    Rev 1.19   19 Jul 1992 22:21:24   brucea
** Added: #include "bkroot.h"
** 
**    Rev 1.18   23 Jun 1992 14:26:14   courtney
** Revised breakpoint call to be BkProcessorMustBeHalted (from bkroot.dll).
** 
**    Rev 1.17   15 Jun 1992 09:48:02   brucea
** Added: call to BxProcessorMustBeHalted to MemRead, MemWrite, MemFill,
**    MemSearch
** Removed: compiler warnings
** 
**    Rev 1.16   15 May 1992 15:42:02   brucea
** Changed: error for out of memory to ER_OUT_OF_MEMORY
** 
**    Rev 1.15   20 Mar 1992 06:34:28   mindy
** pattern length in shared data is a dword.
** 
**    Rev 1.14   06 Mar 1992 09:39:50   doug
** added memory search
** 
**    Rev 1.13   28 Feb 1992 15:02:58   doug
** unregister shared data descriptors
** 
**    Rev 1.12   28 Feb 1992 11:28:50   brucea
** Added: #include "enlib.h"
** Fixed: ReadPartialMember to SdReadPartialMember and added passed params
** Removed: TFree from MemWrite and MemFill
** 
**    Rev 1.11   28 Feb 1992 07:53:50   doug
** memory read must return pointer
** 
**    Rev 1.10   28 Feb 1992 07:32:44   doug
** update to name chosen by Bruce
** 
**    Rev 1.9   28 Feb 1992 07:23:20   doug
** added fill command
** 
**    Rev 1.8   27 Feb 1992 17:43:54   doug
** Simple memory read and write
** 
**    Rev 1.7   30 Jan 1992 15:11:48   jim
** Removed sdgen.h and replaced it with sdinit.h.
** 
**    Rev 1.6   29 Jan 1992 16:40:20   courtney
** Revised interface calls to shared data server.
** 
**    Rev 1.5   27 Jan 1992 13:17:54   courtney
** Revised Write/subsequent Read of shared data members to use
** SdWriteCmdReadResponse call.  Retry hence gets moved internal
** to shared data server.
** 
**    Rev 1.4   25 Jan 1992 11:10:32   tom
** Pass address to AdrCreateAddress.
** 
**    Rev 1.3   24 Jan 1992 17:46:00   doug
** address pointer problem fix!!!
** 
**    Rev 1.2   23 Jan 1992 16:23:36   doug
** do not wait for acknowledgement from box before continuing
** 
**    Rev 1.1   15 Jan 1992 15:36:04   tom
** Fixed LibMain declaration.
** 
**    Rev 1.0   14 Jan 1992 13:50:10   tom
** Initial revision.
**
**  $Header:   S:/tbird/arcppc/mem/memory.c_v   1.4   19 Aug 1997 15:43:58   cjchen  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

#ifndef _BKPTEXEC_
#include "bkptexec.h"
#endif

#ifndef _BKROOT_
#include "bkroot.h"
#endif

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

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

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

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

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

#ifndef _PVTASK_
#include "pvtask.h"
#endif

#ifndef _SDPROBE_
#include "sdprobe.h"
#endif

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

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

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

#ifndef  _SDS2ABI_
#include "sds2abi.h"
#endif

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


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

#define NULL_CONTEXT 0L
#define KBYTE 1024L

/* prior to returning error code, check for and process memory verify error */
#define RETURN_WITH_MEM_VERIFY_CHECK(retcode) \
   { \
      if ((retcode)==ER_MEMORY_VERIFY) { \
         (VOID)MemProcessVerifyError(); \
      } \
      return((retcode)); \
   }
//         (VOID)EnlEventNotify(EVENT_MEM_EDIT); \

                       /******************
                        *                *
                        *    TYPEDEFS    *
                        *                *
                        ******************/

/* private and generic information for each memory presenter */
typedef struct MEM_CONTEXT_TAG {

   /* set equal to pointer to structure; test when accessing structure for */
   /* validity check */
   DESCRIPTOR sessionId;

   struct MEM_CONTEXT_TAG *nextContext;  /* forward link */
   struct MEM_CONTEXT_TAG *prevContext;  /* backward link */

   DESCRIPTOR inputAddr;            /* user-entered "goto" address */
   MEM_DISPLAY_SIZE_TYPE viewSize;  /* U8, U16, or U32 */
   MEM_RADIX_TYPE radix;            /* octal, decimal, hex */
   BOOLEAN asciiOn;                 /* view ascii or not */

}  MEM_CONTEXT;

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern HANDLE hLib;

ACCESS_SIZE accessSize = WORD_SIZE;   /* For MemRead, MemFill, MemWrite */
BOOLEAN verifyWrites = TRUE;
extern DESCRIPTOR srcRange0, srcRange1;

                       /***************************
                        *                         *
                        *    PRIVATE VARIABLES    *
                        *                         *
                        ***************************/

PRIVATE
DESCRIPTOR fillAbortDesc = NULL,
           fillSemaDesc = NULL,
           fillAccessDesc = NULL,
           fillVerifyDesc = NULL,
           fillOffsetDesc = NULL,
           fillSpaceDesc = NULL,
           fillLengthDesc = NULL,
           fillPatLenDesc = NULL,
           fillBufferDesc = NULL,
           fillCommandDesc = NULL,
           fillResultsDesc = NULL,
           verifyOffsetDesc = NULL,
           verifySpaceDesc = NULL,
           verifyExpectedDesc = NULL,
           verifyActualDesc = NULL,

           copyAbortDesc      = NULL,
           copyAccessDesc     = NULL,
           copyVerifyDesc     = NULL,
           copySrcOffsetDesc  = NULL,
           copySrcSpaceDesc   = NULL,
           copySrcTargetDesc  = NULL,
           copyLengthDesc     = NULL,
           copyDestOffsetDesc = NULL,
           copyDestSpaceDesc  = NULL,
           copyDestTargetDesc = NULL,
           copyCommandDesc    = NULL,
           copyResultsDesc    = NULL,

           copyVerifyOffsetDesc   = NULL,
           copyVerifySpaceDesc    = NULL,
           copyVerifyExpectedDesc = NULL,
           copyVerifyActualDesc   = NULL;

           

// indicates which fill/copy buffer was assigned
PRIVATE MEMBER_INDEX fillBufIndex;
PRIVATE MEMBER_INDEX copyBufIndex;   // note: not used...placeholder


/* handle to TMalloc'ed data; 0 if no stacks yet allocated */
PRIVATE MEM_CONTEXT *firstMemContext;

/* used to update src windows if mem changes inside these target addresses */
/* NOTE: if more ranges are added for checking, the design should create an
   array and use array indexing in MemSetSourceRange.  Also, the MEM_SRC_ID
   in tbirdmem.h should be changed to some max value and used as an array
   index max bounds */
DESCRIPTOR srcRange0, srcRange1;

/* processor-specific variables */
PRIVATE PROCESSOR_FAMILY procFamily;
ENDIAN_TYPE endian;

/* Read memory cache control */
U16 dumpCacheHit[NUM_DUMP];

/*-------------------------------------------------------------
  used to determine when to the fill/copy commands are done
--------------------------------------------------------------*/
PRIVATE BOOLEAN memFillDoneSpinFlag;
PRIVATE BOOLEAN memCopyDoneSpinFlag;
PRIVATE BOOLEAN memSearchDoneSpinFlag;


                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

PRIVATE VOID FAR PASCAL MemFillCallback(DESCRIPTOR desc);
PRIVATE VOID FAR PASCAL MemCopyCallback(DESCRIPTOR desc);
PRIVATE VOID FAR PASCAL MemSearchCallback(DESCRIPTOR desc);
RETCODE EXPORT MemWriteSizedNoFree(DESCRIPTOR startAddr, U16 length,
      LPU8 buffer, ACCESS_SIZE size);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
/*------------------------------------------------------------------------
** MemInitServer
**
** Purpose:
**    Initialize all the PRIVATE variables used in this module; only called
**    once when DLL loaded.  Also registers to receive event notification
----------------------------------------------------------------------------*/
RETCODE MemInitServer(VOID)  {
   
   DESCRIPTOR   descEvt;  /* unused return param from EnlRegister */
   RETCODE      err;
   FARPROC      lpMemCallback, lpMemProc;
   DESCRIPTOR   dummyDesc;
   U16 i;

/* NOTE: NO ADDRESS FUNCTIONS CAN BE CALLED IN THIS FUNCTION BECAUSE
   OF LOAD ORDER - THANK MICROSOFT'S INEPTITUDE */

   if (GOOD != (err = ProcReturnProcFamily(&procFamily))) /* fill in static */
      return err;

   if((err = ProcReturnByteOrder(&endian)) != GOOD) return(err);

   firstMemContext = NULL_CONTEXT;

   lpMemCallback = MakeProcInstance((FARPROC) MemCallback, hLib);
   /* register to receive events from ... */
   if ((err = EnlRegister(EVENT_CPU_HALTED, (EVCALLBACK) lpMemCallback, 
                          &descEvt))!=GOOD)
      return err;

   if ((err = EnlRegister(EVENT_MAP_EDIT, (EVCALLBACK) lpMemCallback, 
                          &descEvt))!=GOOD)
      return err;

   if ((err = EnlRegister(EVENT_LDR_MEMCHANGED, (EVCALLBACK) lpMemCallback, 
                          &descEvt))!=GOOD)
      return err;

/* @@@!!! THESE WILL BE NEEDED WHEN SYMBOLIC DISASSEMBLY OF MEMORY IS ADDED */

#if 0

   if ((err = EnlRegister(EVENT_SYMBOL_INIT_LOAD,
                            (EVCALLBACK) lpMemCallback,
                            &descEvt))!=GOOD)
      return err;
   if ((err = EnlRegister(EVENT_SYMBOL_DELETED,
                            (EVCALLBACK) lpMemCallback,
                            &descEvt))!=GOOD)
      return err;
#endif

   /* Grab and hoard all shared data dump buffers */
   for (i=0;i<NUM_DUMP;i++) {
      if((err = SdRegisterSemaphore(SD_DUMP_SEMAPHORE,NULLPTR,&dummyDesc))
         != GOOD) return(err);
   }
   if ((err = MemCacheInvalidate()) != GOOD) return(err);

   /* get descriptors for commonly used shared data members */
   if((err = SdRegisterSemaphore(SD_FILL_SEMAPHORE, NULLPTR, &fillSemaDesc))
      !=GOOD) return(err);
   if((err = SdGetMemberIndex(fillSemaDesc, (MEMBER_INDEX FAR *)&fillBufIndex))
      !=GOOD) return(err);

   if((err = SdnRegister(SDN_FILL_ABORT+fillBufIndex,
                         NULLPTR, &fillAbortDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_FILL_ACCESS+fillBufIndex,
                         NULLPTR, &fillAccessDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_FILL_VERIFY+fillBufIndex,
                         NULLPTR, &fillVerifyDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_FILL_OFFSET+fillBufIndex,
                         NULLPTR, &fillOffsetDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_FILL_SPACE+fillBufIndex,
                         NULLPTR, &fillSpaceDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_FILL_LENGTH+fillBufIndex,
                         NULLPTR, &fillLengthDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_FILL_PATLENGTH+fillBufIndex,
                         NULLPTR, &fillPatLenDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_FILL_BUFFER+fillBufIndex,
                         NULLPTR, &fillBufferDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_FILL_COMMAND+fillBufIndex,
                         NULLPTR, &fillCommandDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_FILL_RESULTS+fillBufIndex,
                         NULLPTR, &fillResultsDesc))
      !=GOOD) return(err);

   /* set up callback for Fill command */
   lpMemProc = MakeProcInstance((FARPROC) MemFillCallback, hLib);
   if((err = SdnRegister(SDN_FILL_RESULTS + fillBufIndex,
                         lpMemProc,
                         &dummyDesc))!=GOOD)
      return(err);

   if((err = SdnRegister(SDN_VERIFY_OFFSET, NULLPTR, &verifyOffsetDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_VERIFY_SPACE, NULLPTR, &verifySpaceDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_VERIFY_EXPECTED, NULLPTR, &verifyActualDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_VERIFY_ACTUAL, NULLPTR, &verifyExpectedDesc))
      !=GOOD) return(err);

  //----------------------------------------------------------
  //   COPY command
  //   NOTE: since there is only ONE array of SM members for copy
  //         we do not need to follow FILL operation:
  //             SdRegisterSemaphore(SD_FILL_SEMAPHORE,...)
  //             SdGetMemberIndex(fillSemaDesc....)
  //  bug in the program that generates SD.C (in SDS directory)
  //  does not properly generate strings for single cases
  //   (Talk to Ernie for more on this). 
  //----------------------------------------------------------

   copyBufIndex = 0;    // for multiple copy SDM arrays.
// --------------------------------------------------
   if((err = SdnRegister(SDN_COPY_ABORT+copyBufIndex,
                         NULLPTR, &copyAbortDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_ACCESS+copyBufIndex,
                         NULLPTR, &copyAccessDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_VERIFY+copyBufIndex,
                         NULLPTR, &copyVerifyDesc))
      !=GOOD) return(err);
// --------------------------------------------------
   if((err = SdnRegister(SDN_COPY_SRC_OFFSET+copyBufIndex,
                         NULLPTR, &copySrcOffsetDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_SRC_SPACE+copyBufIndex,
                         NULLPTR, &copySrcSpaceDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_SRC_TARG+copyBufIndex,
                         NULLPTR, &copySrcTargetDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_LENGTH+copyBufIndex,
                         NULLPTR, &copyLengthDesc))
      !=GOOD) return(err);
// --------------------------------------------------
   if((err = SdnRegister(SDN_COPY_DES_OFFSET+copyBufIndex,
                         NULLPTR, &copyDestOffsetDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_DES_SPACE+copyBufIndex,
                         NULLPTR, &copyDestSpaceDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_DES_TARG+copyBufIndex,
                         NULLPTR, &copyDestTargetDesc))
      !=GOOD) return(err);

// --------------------------------------------------
   if((err = SdnRegister(SDN_COPY_COMMAND,
                         NULLPTR, &copyCommandDesc))
      !=GOOD) return(err);


   if((err = SdnRegister(SDN_COPY_RESULTS+copyBufIndex,
                         NULLPTR, &copyResultsDesc))
      !=GOOD) return(err);
// --------------------------------------------------

   if((err = SdnRegister(SDN_COPY_VFY_OFFSET+copyBufIndex,
                         NULLPTR, &copyVerifyOffsetDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_VFY_SPACE+copyBufIndex,
                         NULLPTR, &copyVerifySpaceDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_VFY_EXPECTED+copyBufIndex,
                         NULLPTR, &copyVerifyExpectedDesc))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_COPY_VFY_ACTUAL+copyBufIndex,
                         NULLPTR, &copyVerifyActualDesc))
      !=GOOD) return(err);


// set up callback for Copy command
//   MakeProcInstance is not required in DLLs
//
   lpMemProc = MakeProcInstance((FARPROC) MemCopyCallback, hLib);
   if((err = SdnRegister(SDN_COPY_RESULTS + copyBufIndex,
      lpMemProc, &dummyDesc))!=GOOD) return(err);
   lpMemProc = MakeProcInstance((FARPROC) MemSearchCallback, hLib);
   if((err = SdnRegister(SDN_SEARCH_FOUND, lpMemProc, &dummyDesc))!=GOOD)
      return(err);

   return GOOD;
}  /* end of MemInitServer */


/*------------------------------------------------------------------------
** MemFillCallback
**
** Purpose:
** Purpose:
**    Allow MemFill() to be notified when the operation completes
----------------------------------------------------------------------------*/
#pragma argsused
VOID FAR PASCAL MemFillCallback(DESCRIPTOR desc)  {

   memFillDoneSpinFlag = TRUE;
   return;
}

/*------------------------------------------------------------------------
** MemCopyCallback
**
** Purpose:
**    Allow MemCopy() to be notified when the operation completes
----------------------------------------------------------------------------*/
#pragma argsused
VOID FAR PASCAL MemCopyCallback(DESCRIPTOR desc)  {

   memCopyDoneSpinFlag = TRUE;
   return;
}


/*------------------------------------------------------------------------
** MemSearchCallback
**
** Purpose:
**    Allow MemSearch() to be notified when the operation completes
----------------------------------------------------------------------------*/
#pragma argsused
VOID FAR PASCAL MemSearchCallback(DESCRIPTOR desc)  {
   memSearchDoneSpinFlag = TRUE;
   return;
}


/*------------------------------------------------------------------------
** MemInitOnce
**
** Purpose:
**    This is kludge code which initializes address descriptors; it should 
**    be in MemInitServer but Windows cannot load DLLs in the right order.
----------------------------------------------------------------------------*/
RETCODE EXPORT MemInitOnce(VOID)  {
   
   RETCODE err;

   if (GOOD != (err = AdrCreateAddress(&srcRange0)))
      return err;

   /* NOTE: default is range off; this will cause
   ** the AdrDoPhysicalRangesOverlap() to return FALSE, the desired value
   */   
   if (GOOD != (err = AdrCreateAddress(&srcRange1))) {
      AdrDestroyAddress(srcRange0);
   }
   return err;
}  /* end of MemInitOnce */


/*------------------------------------------------------------------------
**  MemCallback
**
**  Purpose:
**     Is called when event that the memory server has registered on occurs
----------------------------------------------------------------------------*/
RETCODE EXPORT MemCallback(U32 eventNum) {
   RETCODE err=GOOD, err2=GOOD;
   switch (eventNum) {
      case EVENT_CPU_HALTED:
         /* notify interested parties that the memory has changed */
         err = MemCacheInvalidate();
         err2 = EnlEventNotify(EVENT_MEM_HALTED);
         break;

      case EVENT_MAP_EDIT:
         /* notify interested parties the memory has changed */
         err = MemCacheInvalidate();
         err2 = EnlEventNotify(EVENT_MEM_EDIT);
         break;

      case EVENT_LDR_MEMCHANGED:
         err = MemCacheInvalidate();
         err2 = EnlEventNotify(EVENT_MEM_EDIT);
         break;

      /* default is to return GOOD */
   }
   return(err?err:err2);
}  /* end of MemCallback */


/*------------------------------------------------------------------------
** MemOpenSession
**
** Purpose:
**   Allocates memory for a memory context, initializes it, then links it with
**   the other context linked list.
----------------------------------------------------------------------------*/
RETCODE EXPORT MemOpenSession(DESCRIPTOR FAR *memSessionId)  {

   MEM_CONTEXT *contextPtr;
   RETCODE     err;

   contextPtr = (MEM_CONTEXT *)TMalloc(sizeof(MEM_CONTEXT));
   if (!(contextPtr))
      return ER_OUT_OF_MEMORY;

   /* return the descriptor in output param */
   *memSessionId = (DESCRIPTOR)contextPtr;

   /* init all bytes to 0, then fill in non-zero values */
   /* all BOOLEANs set to FALSE, all descriptors set to 0 */
   memset(contextPtr, 0, sizeof(MEM_CONTEXT));

   /* insert addr of context memory into context for later validity check */
   contextPtr->sessionId = *memSessionId;

   contextPtr->viewSize = MEM_U8;
   contextPtr->radix =    MEM_HEX;
   contextPtr->asciiOn =  TRUE;

   /* create an address so that no special code for adding new address */
   if (GOOD != (err = AdrCreateAddress(&(contextPtr->inputAddr)))) {
      TFree((LPSTR)contextPtr);
      return err;
   }

   /* add to front of linked list */
   if (firstMemContext == NULL_CONTEXT)  {
      firstMemContext = contextPtr;
      /* nextContext and prevContext have already been initialized to 0 */
   } else {
      /* link in new context at front of list */
      /* set new context next pointer to what the first context pointer
         presently points to */
      (contextPtr->nextContext) = firstMemContext;

      /* set existing context previous pointer to the new context */
      firstMemContext->prevContext = contextPtr;

      /* set firstMemContext pointer to the new context */
      firstMemContext = contextPtr;

      /* notice that the new context previous pointer remains zero (null) */
   }
   return GOOD;
}  /* end of MemOpenSession */


/*------------------------------------------------------------------------
** MemCloseSession
**
** Purpose:
**   Removes stack context from linked list (and relinks list), then frees the
**   memory.
----------------------------------------------------------------------------*/
RETCODE EXPORT MemCloseSession(DESCRIPTOR memSessionId)  {

   RETCODE err;
   MEM_CONTEXT *contextPtr;

   contextPtr = (MEM_CONTEXT *)memSessionId;
   if ((contextPtr->sessionId) != memSessionId)
      return ER_MEM_INVALID_DESCRIPTOR;
   if((err = AdrDestroyAddress(contextPtr->inputAddr))!=GOOD) return(err);

   /* remove context from doubly linked list before freeing the memory */
   if (firstMemContext == contextPtr) {
      /* context is first in list */
      firstMemContext = (contextPtr->nextContext);
   } else {
      /* reattach previous pointer of next neighbor context if it exists */
      if (contextPtr->nextContext != NULL_CONTEXT) {
         /* there is a next neighbor */
         ((MEM_CONTEXT *)(contextPtr->nextContext))->prevContext =
         contextPtr->prevContext;
      }
      /* reattach previous neighbor's next context to next neighbor */
      ((MEM_CONTEXT *)(contextPtr->prevContext))->nextContext =
      contextPtr->nextContext;
   }
   if ((err = TFree((LPSTR)contextPtr)) != GOOD) return err;
   return GOOD;
}  /* end of MemCloseSession */


#if 0  // to be added at some future date
/*------------------------------------------------------------------------
** TerminateServer
**
** Purpose:
**    Closes any allocated memory
----------------------------------------------------------------------------*/
RETCODE EXPORT TerminateServer(VOID)  {
   RETCODE err;

   /* @@@!!! needs to walk the linked list and TFree all entries */
   
   /* unregister shared data members */
   if((fillAbortDesc!=NULL) && (err = SdUnRegister(fillAbortDesc))!=GOOD)
      return(err);
   if((fillSemaDesc!=NULL) && (err = SdUnRegister(fillSemaDesc))!=GOOD)
      return(err);
   if((fillAccessDesc!=NULL) && (err = SdUnRegister(fillAccessDesc))!=GOOD)
      return(err);
   if((fillVerifyDesc!=NULL) && (err = SdUnRegister(fillVerifyDesc))!=GOOD)
      return(err);
   if((fillOffsetDesc!=NULL) && (err = SdUnRegister(fillOffsetDesc))!=GOOD)
      return(err);
   if((fillSpaceDesc!=NULL) && (err = SdUnRegister(fillSpaceDesc))!=GOOD)
      return(err);
   if((fillLengthDesc!=NULL) && (err = SdUnRegister(fillLengthDesc))!=GOOD)
      return(err);
   if((fillPatLenDesc!=NULL) && (err = SdUnRegister(fillPatLenDesc))!=GOOD)
      return(err);
   if((fillBufferDesc!=NULL) && (err = SdUnRegister(fillBufferDesc))!=GOOD)
      return(err);
   if((fillCommandDesc!=NULL) && (err = SdUnRegister(fillCommandDesc))!=GOOD)
      return(err);
   if((fillResultsDesc!=NULL) && (err = SdUnRegister(fillResultsDesc))!=GOOD)
      return(err);

   if((verifyOffsetDesc!=NULL) && (err = SdUnRegister(verifyOffsetDesc))
      !=GOOD) return(err);
   if((verifySpaceDesc!=NULL) && (err = SdUnRegister(verifySpaceDesc))!=GOOD)
      return(err);
   if((verifyExpectedDesc!=NULL) && (err = SdUnRegister(verifyExpectedDesc))
      !=GOOD) return(err);
   if((verifyActualDesc!=NULL) && (err = SdUnRegister(verifyActualDesc))
      !=GOOD) return(err);

   return GOOD;
}  /* end of TerminateServer */
#endif


/*--------------------------------------------------------------------------
**  MemRead
----------------------------------------------------------------------------*/
#pragma warn -sig
RETCODE EXPORT MemRead(DESCRIPTOR  startAddr,
                       U16         length,
                       LPU8        *buffer,
                       CACHE_OP    cacheOp) {
   return(MemReadSized(startAddr,length,buffer,accessSize,cacheOp));
}

RETCODE EXPORT MemReadSized(DESCRIPTOR  startAddr,
                            U16         length,
                            LPU8        *buffer,
                            ACCESS_SIZE size,
                            CACHE_OP    cacheOp) {
   U8 *buffPtr;
   if((buffPtr = (U8*)TMalloc((U32)length))==0) return(ER_OUT_OF_MEMORY);
   *buffer = buffPtr;
   return(MemReadSizedNoAlloc(startAddr,length,buffPtr,size,cacheOp));
}

RETCODE EXPORT MemReadSizedNoAlloc(DESCRIPTOR  startAddr,
                            U16         length,
                            U8          *buffer,
                            ACCESS_SIZE size,
                            CACHE_OP    cacheOp) {
   RETCODE err;
   ADDR_SPACE space;
   U32 offset;
   U32 regValue;
   if (procFamily == FAMILY_68K || procFamily == FAMILY_POWERPC) {
      if((err = AdrGetAddrSpace(startAddr, &space)) != GOOD) return(err);
   }
   if((err = AdrGetAddrOffset(startAddr, &offset))!=GOOD) return(err);
   /*
   CpuGetRegister(R_IMMR,&regValue);
   regValue=regValue & 0xfffffff0;
   if (((offset < regValue) && ((offset+length) < (regValue+64*1024))) ||
      ((offset > regValue) && ((offset+length) > (regValue+64*1024))))
      return(MemReadQuick(offset,space,length,buffer,size,cacheOp));
   if ((offset >= regValue) && ((offset+length) <= (regValue+64*1024)))
      return(MemReadQuick(regValue+64*1024,space,length,buffer,size,cacheOp));
   if (offset<regValue) {
      err=MemReadQuick(offset,space,(regValue-offset),buffer,size,cacheOp);
      err=MemReadQuick(regValue+64*1024,space,(length-regValue+offset),buffer+regValue-offset,
         size,cacheOp);
   }
   if (offset>regValue)
      err=MemReadQuick(regValue+64*1024,space,length,buffer,size,cacheOp);
   return err;
   */
   return(MemReadQuick(offset,space,length,buffer,size,cacheOp));

}


RETCODE EXPORT MemReadQuick(U32         offset,
                            ADDR_SPACE  space,
                            U16         length,
                            U8          *buffer,
                            ACCESS_SIZE size,
                            CACHE_OP    cacheOp) {
   RETCODE err;
   U16 index, minHit, testIndex;
   if ((err = BkProcessorMustBeHalted()) != GOOD) return(err);
   while(length > 0) {
      U32 blockSize;
      BOOLEAN timedOut,done;
      blockSize = (length > SIZE_DUMP) ? SIZE_DUMP:length;
      done = FALSE;
      /*
      **  If cache enabled and the sub-range is covered by a valid
      **  dump buffer, read data from there into buffer
      */
      if ((cacheOp == CACHE_USE) || (cacheOp == CACHE_USE_AND_LOCK))
         for (index=0; index<NUM_DUMP; index++) {
            if (dumpCacheHit[index] > 0) {
               U32 cOffset = *((U32*)SdnData(SDN_DUMP_OFFSET+index));
               if (offset < cOffset) continue;
               if (offset+blockSize < offset) continue;  /* request wraps 0 */
               if (offset+blockSize >
                   cOffset + *((U32*)SdnData(SDN_DUMP_LENGTH+index))) continue;
               if (procFamily == FAMILY_68K || procFamily == FAMILY_POWERPC) {
                  if (space != *((ADDR_SPACE*)SdnData(SDN_DUMP_SPACE+index)))
                     continue;
               }
               if (buffer) {
                  if ((err = SdnReadPartialMember(SDN_DUMP_BUFFER+index,
                     offset-cOffset,blockSize,buffer)) != GOOD) return(err);
                  buffer += blockSize;
               }
               done = TRUE;
               break;
            }
         }
      if (!done) {
         /*
         ** Range was not satisfied by cache...read from memory.
         ** Reuse dump buffer with lowest hit count.
         */
         for (minHit=0xffff,testIndex=0; testIndex<NUM_DUMP; testIndex++) {
            if (dumpCacheHit[testIndex] < minHit) {
               index = testIndex;
               if ((minHit = dumpCacheHit[index]) == 0) break;
            }
         }
         dumpCacheHit[index]=0;  /* Invalidate cache for this buffer */
         if((err = SdnWriteMemberIfChanged(SDN_DUMP_SPACE+index, (U8*)&space,
            GOOD)) != GOOD) return(err);
         if((err = SdnWriteMemberIfChanged(SDN_DUMP_ACCESS+index, (U8*)&size,
            GOOD)) != GOOD) return(err);

         if((err = SdnWriteMember(SDN_DUMP_OFFSET+index, (U8*)&offset, GOOD))
            != GOOD) return(err);
         if((err = SdnWriteCmdReadResponse(SDN_DUMP_LENGTH+index,
            (U8*)&blockSize,GOOD, SDN_DUMP_RESULT+index, 0, &timedOut))!=GOOD)
            return(err);
         if (buffer) {
            if((err = SdnReadPartialMember(SDN_DUMP_BUFFER+index, 0, blockSize,
               buffer)) != GOOD) return(err);
            buffer += blockSize;
         }
      }
      if (cacheOp == CACHE_USE_AND_LOCK) dumpCacheHit[index] = 1000;
      else dumpCacheHit[index]++;
      offset += blockSize;
      length -= blockSize;
   }
   return(GOOD);
}
#pragma warn .sig

/***************************************************************************
**
**  MemProcessVerifyError
**
*****************************************************************************/
RETCODE EXPORT MemProcessVerifyError() {
   
//   U32 verifyOffset, expectedData, actualData;
//   U16 addrSpace;
   BAD_MEMORY verifyErrorInfo;
   S8 verBuf[ADDR_BUFF_SZ], spaceBuf[4];
   DESCRIPTOR addr;
   CHAR verifyErrorString[E_ERRSIZE];
   
   /* collect information */
//   SdnReadMember(SDN_VERIFY_OFFSET,(U8 *)&verifyOffset);
//   SdnReadMember(SDN_VERIFY_EXPECTED,(U8 *)&expectedData);
//   SdnReadMember(SDN_VERIFY_ACTUAL,(U8 *)&actualData);
//   SdnReadMember(SDN_VERIFY_SPACE,(U8 *)&addrSpace);

   iceGetVerifyErrorInfo(&verifyErrorInfo);
   
   AdrCreateAddress(&addr);
   AdrSetAddrOffset(addr, verifyErrorInfo.offset);
   AdrConvAddressToTextWithParams(addr, TRUE, TRUE, verBuf);
   AdrDestroyAddress(addr);

   wsprintf(spaceBuf," ");
   /* format message */
/*************************
   switch (verifyErrorInfo.space) {
      case SPACE_UNDEF0:
         wsprintf(spaceBuf,"U0 ");
      break;
      case SPACE_UD:
         wsprintf(spaceBuf,"UD ");
      break;
      case SPACE_UP:
         wsprintf(spaceBuf,"UP ");
      break;
      case SPACE_UNDEF3:
         wsprintf(spaceBuf,"U3 ");
      break;
      case SPACE_UNDEF4:
         wsprintf(spaceBuf,"U4 ");
      break;
      case SPACE_SD:
         wsprintf(spaceBuf,"SD ");
      break;
      case SPACE_SP:
         wsprintf(spaceBuf,"SP ");
      break;
      case SPACE_CPU:
         wsprintf(spaceBuf,"CPU");
      break;
      case SPACE_DONT_CARE:
         wsprintf(spaceBuf,"   ");
      break;
   }
*************************/

   wsprintf(verifyErrorString,
      "address: %s %s, expected: 0x%04lX, actual: 0x%04lX",
      verBuf, spaceBuf, verifyErrorInfo.expected, verifyErrorInfo.actual);

   /* send error text in error text server */
   ErrSaveMemoryVerifyInfo((LPSTR)verifyErrorString);
   
   return(GOOD);
}

/*--------------------------------------------------------------------------
**  MemWrite
----------------------------------------------------------------------------*/
#pragma warn -sig
RETCODE EXPORT MemWrite(DESCRIPTOR startAddr, U16 length, LPU8 buffer) {
   return(MemWriteSized(startAddr,length,buffer,accessSize));
}

RETCODE EXPORT MemWriteSized(DESCRIPTOR startAddr, U16 length,
      LPU8 buffer, ACCESS_SIZE size) {
   RETCODE err,err2;
   err = MemWriteSizedNoFree(startAddr,length,buffer,size);
   err2 = TFree((LPSTR)buffer);
   return(err?err:err2);
}

RETCODE EXPORT MemWriteSizedNoFree(DESCRIPTOR startAddr, U16 length,
      LPU8 buffer, ACCESS_SIZE size) {
   RETCODE    err, firstErr;
   ADDR_SPACE addrSpace;
   U32        addrOffset;
   LPU8       buffPtr = buffer;
   BOOLEAN    overlap;
   U16        originalLength;

   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return(err);

   originalLength = length;

   if (FAMILY_68K == procFamily || procFamily == FAMILY_POWERPC) {
      if((err = AdrGetAddrSpace(startAddr, &addrSpace)) != GOOD)
         return(err);
      if((err = SdWriteMember(fillSpaceDesc,(U8 FAR *)&addrSpace,GOOD))!=GOOD)
         return(err);
   }
   if((err = AdrGetAddrOffset(startAddr, &addrOffset))!=GOOD)
      return(err);

   if((err = SdWriteMember(fillVerifyDesc, (U8 FAR *)&verifyWrites,GOOD))
      !=GOOD) return(err);

   while(length != 0) {
      U32 blockSize;  /* must be U32 */
      BOOLEAN timedOut;
      U8 fill = TRUE;

      blockSize = (length > SIZE_FILL) ? SIZE_FILL:length;

      if((err = SdWriteMember(fillAccessDesc, (U8 FAR *)&size,GOOD))
         !=GOOD) return(err);
      if((err = SdWriteMember(fillOffsetDesc, (U8 FAR *)&addrOffset, GOOD))
         !=GOOD) return(err);
      if((err = SdWriteMember(fillLengthDesc, (U8 FAR *)&blockSize, GOOD))
         !=GOOD) return(err);
      if((err = SdWriteMember(fillPatLenDesc, (U8 FAR *)&blockSize, GOOD))
         !=GOOD) return(err);
      if((err = SdWritePartialMember(fillBufferDesc, (MEMBER_OFFSET)0,
         (MEMBER_SIZE)blockSize, buffPtr, GOOD))!=GOOD) 
            return(err);
      if((err = SdWriteCmdReadResponse(fillCommandDesc, (VOID FAR *)&fill,
         GOOD, fillResultsDesc, 0, &timedOut))!=GOOD) 
            RETURN_WITH_MEM_VERIFY_CHECK(err);
      buffPtr += blockSize;
      addrOffset += blockSize;
      length -= blockSize;
   }
   firstErr = EnlEventNotify(EVENT_MEM_EDIT);

   /* check two src ranges for memwrite address included; send
      out indiviual events if so */
   err = AdrSetAddrRangeLength(startAddr, originalLength);
   if (firstErr == GOOD) firstErr = err;
   err = AdrDoPhysicalRangesOverlap(startAddr, srcRange0, &overlap);
   if (firstErr == GOOD) firstErr = err;
   if (overlap) {
      err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC0_RANGE);
      if (firstErr == GOOD) firstErr = err;
   }
   err = AdrDoPhysicalRangesOverlap(startAddr, srcRange1, &overlap);
   if (firstErr == GOOD) firstErr = err;
   if (overlap) {
      err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC1_RANGE);
      if (firstErr == GOOD) firstErr = err;
   }

   err = MemCacheInvalidateRange(startAddr);
   if (firstErr == GOOD) firstErr = err;

   return(firstErr);
}  /* end of MemWrite */
#pragma warn .sig


/*--------------------------------------------------------------------------
**  MemFill
----------------------------------------------------------------------------*/
RETCODE EXPORT MemFill(DESCRIPTOR startAddr,
                       U32        fillLength,
                       LPU8       pattern,
                       U16        patternLength) {
  return(MemFillSized(startAddr,fillLength,pattern,patternLength,accessSize));
}

RETCODE EXPORT MemFillSized(DESCRIPTOR  startAddr,
                            U32         fillLength,
                            LPU8        pattern,
                            U16         patternLength,
                            ACCESS_SIZE size) {

   RETCODE    err, resultsErr, firstErr = GOOD;
   ADDR_SPACE addrSpace;
   U32        addrOffset;
   U8         fill = TRUE;
   U32        pLength = (U32) patternLength;
   BOOLEAN    overlap, true = TRUE;
   BOOLEAN    abortFromEsc;

   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;

   if (patternLength > SIZE_FILL) return(ER_MEM_PAT_LEN);
   
   if (fillLength == 0) return(GOOD);
   if (patternLength == 0) return(GOOD);

   if((err = SdWriteMember(fillVerifyDesc, (U8 FAR *)&verifyWrites,GOOD))
      !=GOOD) return(err);

   if((err = AdrGetAddrOffset(startAddr, &addrOffset))!=GOOD)
      return(err);

   if (FAMILY_68K == procFamily || procFamily == FAMILY_POWERPC) {
      if((err = AdrGetAddrSpace(startAddr, &addrSpace)) != GOOD)
         return(err);
      if((err = SdWriteMember(fillSpaceDesc, (U8 FAR *)&addrSpace, GOOD))
         !=GOOD) return(err);
   }

   if (fillLength > 0) {
      if((err = SdWriteMember(fillAccessDesc, (U8 *)&size,GOOD))!=GOOD)
         return(err);
      if((err = SdWriteMember(fillOffsetDesc, (U8 FAR *)&addrOffset, GOOD))
         !=GOOD) return(err);
      if((err = SdWriteMember(fillLengthDesc, (U8 FAR *)&fillLength, GOOD))
         !=GOOD) return(err);
      if((err = SdWritePartialMember(fillBufferDesc, (MEMBER_OFFSET)0,
         (MEMBER_SIZE)pLength, pattern, GOOD))!=GOOD)
            return(err);
      if((err = SdWriteMember(fillPatLenDesc, (U8*)&pLength,GOOD))!=GOOD)
         return(err);

   /* clear any ESC previously hit */
      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) return err;
      // abortFromEsc is ignored here


      memFillDoneSpinFlag = FALSE;
         /* fire off the fill */
      err = SdWriteMember(fillCommandDesc, (U8*)&fill, GOOD);
      if (GOOD == firstErr) firstErr = err;
      while (!memFillDoneSpinFlag) {  /* callback will set TRUE */
         U32 dummy;
         /* must do any read to cause the data to be checked and the callback
            made.  Fill verify is a bad choice since the member holds the 
            value from the previous fill. */
         err = SdnReadMember(SDN_NUM_SHARED_DATA_BYTES, (U8*)&dummy);
         if (GOOD == firstErr) firstErr = err;

         err = TskCheckAbort(&abortFromEsc);
         if(err!=GOOD) {
            SdnWriteMember(SDN_FILL_ABORT+fillBufIndex,(U8*)&true,GOOD);
            return(err);
         }
         if (abortFromEsc) {
            err = SdnWriteMember(SDN_FILL_ABORT+fillBufIndex,(U8*)&true,GOOD);
            if (GOOD == firstErr) firstErr = err;
         }
      }
      err = SdReadMember(fillResultsDesc, (VOID FAR *)&resultsErr);
      if (GOOD == firstErr) firstErr = err;
      if (GOOD == firstErr) firstErr = resultsErr;
   }

/*
** Perform notifications that memory changed
*/
   err = EnlEventNotify(EVENT_MEM_EDIT);
   if (GOOD == firstErr) firstErr = err;

   /* check two src ranges for memwrite address included; send
      out indiviual events if so */
   err = AdrSetAddrRangeLength(startAddr, fillLength);
   if (GOOD == firstErr) firstErr = err;

   err = AdrDoPhysicalRangesOverlap(startAddr, srcRange0, &overlap);
   if (GOOD == firstErr) firstErr = err;
   if (overlap) {
      err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC0_RANGE);
      if (GOOD == firstErr) firstErr = err;
   }
   err = AdrDoPhysicalRangesOverlap(startAddr, srcRange1, &overlap);
   if (GOOD == firstErr) firstErr = err;
   if (overlap) {
      err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC1_RANGE);
      if (GOOD == firstErr) firstErr = err;
   }

   err = MemCacheInvalidateRange(startAddr);
   if (firstErr == GOOD) firstErr = err;

   RETURN_WITH_MEM_VERIFY_CHECK(firstErr);
}   /* end of MemFill */


/*--------------------------------------------------------------------------
**  MemSearch
----------------------------------------------------------------------------*/
RETCODE EXPORT MemSearch(DESCRIPTOR  firstAddr,
                         DESCRIPTOR  secondAddr,
                         BOOLEAN     not,
                         LPU8        pattern,
                         U16         patLen,
                         BOOLEAN FAR *found) {
   return(MemSearchSized(firstAddr,secondAddr,not,pattern,patLen,
          found,accessSize));
}

RETCODE EXPORT MemSearchSized(DESCRIPTOR  firstAddr,
                         DESCRIPTOR  secondAddr,
                         BOOLEAN     not,
                         LPU8        pattern,
                         U16         patLen,
                         BOOLEAN FAR *found,
                         ACCESS_SIZE size) {
   RETCODE err;
   ADDR_COMPARE compare;
   U32 length, offset;
   BOOLEAN forward;
   U32 pLength = (U32)patLen;
   BOOLEAN true = TRUE;
   BOOLEAN   abortFromEsc;
   
   if ((err = BkProcessorMustBeHalted()) != GOOD) return(err);
   if (pLength > SIZE_SEARCH) return(ER_MEM_PAT_LEN);
   *found = FALSE;
   if ((err = AdrCompareAddresses(firstAddr, secondAddr, &compare))!=GOOD)
      return(err);
   if (compare==SECOND_ADDR_GREATER) {
      if((err = AdrRangeOfAddresses(firstAddr, secondAddr, &length))!=GOOD)
         return(err);
      if ((err = AdrGetAddrOffset(firstAddr, &offset)) != GOOD) return(err);
      forward = TRUE;
   } else {
      if((err = AdrRangeOfAddresses(secondAddr, firstAddr, &length))!=GOOD)
         return(err);
      if ((err = AdrGetAddrOffset(secondAddr, &offset)) != GOOD) return(err);
      forward = FALSE;
   }

   if (length == 0) return(GOOD);
   if (pLength == 0) return(GOOD);

   if (procFamily == FAMILY_68K || procFamily == FAMILY_POWERPC) {
      ADDR_SPACE space;
      if((err = AdrGetAddrSpace(firstAddr, &space)) != GOOD) return(err);
      if((err = SdnWriteMemberIfChanged(SDN_SEARCH_SPACE, (U8*)&space, GOOD))
         !=GOOD) return(err);
   }
   if((err = SdnWriteMemberIfChanged(SDN_SEARCH_OFFSET, (U8*)&offset, GOOD))
      !=GOOD) return(err);
   if((err = SdnWriteMemberIfChanged(SDN_SEARCH_ACCESS, (U8*)&size, GOOD))
      !=GOOD) return(err);
   if((err = SdnWriteMemberIfChanged(SDN_SEARCH_LENGTH, (U8*)&length, GOOD))
      !=GOOD) return(err);
   if((err = SdnWriteMemberIfChanged(SDN_SEARCH_PATLENGTH,(U8*)&pLength,GOOD))
      !=GOOD) return(err);
   if((err = SdnWriteMemberIfChanged(SDN_SEARCH_NOT, (U8*)&not, GOOD))
      !=GOOD) return(err);
   if((err = SdnWriteMemberIfChanged(SDN_SEARCH_FORWARD, (U8*)&forward, GOOD))
      !=GOOD) return(err);
   if((err = SdnWritePartialMember(SDN_SEARCH_PATTERN, 0, pLength, pattern,
      GOOD)) != GOOD) return(err);


   /* clear any ESC previously hit */
   err = TskCheckAbort(&abortFromEsc);
   if(err!=GOOD) return err;
   // abortFromEsc is ignored here


   memSearchDoneSpinFlag = FALSE;
   if((err = SdnWriteMember(SDN_SEARCH_COMMAND, (U8*)&true, GOOD))
      !=GOOD) return(err);
   while (!memSearchDoneSpinFlag) {
      U32 dummy;
      if ((err = SdnReadMember(SDN_NUM_SHARED_DATA_BYTES, (U8*)&dummy))
         != GOOD) return(err);


      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) {
         SdnWriteMember(SDN_SEARCH_ABORT,(U8*)&true,GOOD);
         return err;
      }
      if (abortFromEsc) {
         if ((err = SdnWriteMember(SDN_SEARCH_ABORT,(U8*)&true,GOOD)) != GOOD)
            return(err);
      }
   }
   if ((err = SdnReadMember(SDN_SEARCH_FOUND, (U8*)found)) != GOOD) return(err);
   if (*found) {
      if ((err = SdnReadMember(SDN_SEARCH_OFFSET, (U8*)&offset)) != GOOD)
         return(err);
      if ((err = AdrSetAddrOffset(firstAddr, offset)) != GOOD) return(err);
   }
   return(GOOD);
}  /* end of MemSearch */
                     
    
/*--------------------------------------------------------------------------
**  MemCopy
**   unpack data from descriptors and  place in
**   shared data members.
**  descriptors hold:  offset and space
**  target is defined as SIZE_BOOL in sdtempl.h, or BYTE size
**  
----------------------------------------------------------------------------*/

RETCODE EXPORT MemCopy(DESCRIPTOR  srcDesc,
                       U32         length,
                       BOOLEAN     srcTarget,
                       DESCRIPTOR  destDesc,
                       BOOLEAN     destTarget) {

   return(MemCopySized(srcDesc,length,srcTarget,destDesc, destTarget, accessSize));
}


#pragma argsused
RETCODE EXPORT MemCopySized(DESCRIPTOR  srcDesc,
                            U32         length,
                            BOOLEAN     srcTarget,
                            DESCRIPTOR  destDesc,
                            BOOLEAN     destTarget,
                            ACCESS_SIZE size)  {

//  don't forget to check for touching src range1,2
//  and generating event
   RETCODE     err, resultsErr, firstErr = GOOD;
   ADDR_SPACE  srcSpace;
   ADDR_SPACE  destSpace;
   U32         srcAddrOffset;
   U32         destAddrOffset;
   U8          copy = TRUE;        // is SIZE_BIT in SDS (byte)
   BOOLEAN     overlap, true = TRUE;
   BOOLEAN     abortFromEsc;


   if(length == 0)   return GOOD;

// check for emu running
   if (GOOD != (err = BkProcessorMustBeHalted()))
      return err;

// define bus access type (ACCESS_SIZE)
   if((err = SdWriteMember(copyAccessDesc, (U8 FAR *)&size,GOOD))!=GOOD)
      return(err);

// set verify mode from the global variable
   if((err = SdWriteMember(copyVerifyDesc, (U8 FAR *)&verifyWrites,GOOD))
      !=GOOD) return(err);


// unpack source (addr/space/target)
   if((err = AdrGetAddrOffset( srcDesc, &srcAddrOffset))!=GOOD)
      return(err);
   if((err = SdWriteMember(copySrcOffsetDesc, (U8 FAR *)&srcAddrOffset, GOOD))
      !=GOOD) return(err);

   if (FAMILY_68K == procFamily || procFamily == FAMILY_POWERPC) {
      if((err = AdrGetAddrSpace(srcDesc, &srcSpace)) != GOOD)
         return(err);
      if((err = SdWriteMember(copySrcSpaceDesc, (U8 FAR *)&srcSpace, GOOD))
         !=GOOD) return(err);
   }

   if((err = SdWriteMember(copySrcTargetDesc, (U8 FAR *)&srcTarget, GOOD))
       !=GOOD) return(err);

// length
   if((err = SdWriteMember(copyLengthDesc, (U8 FAR *)&length, GOOD))
       !=GOOD) return(err);

// unpack destination (addr/space/target)
   if((err = AdrGetAddrOffset( destDesc, &destAddrOffset))!=GOOD)
      return(err);
   if((err = SdWriteMember(copyDestOffsetDesc, (U8 FAR *)&destAddrOffset, GOOD))
       !=GOOD) return(err);


   if (FAMILY_68K == procFamily || procFamily == FAMILY_POWERPC) {
      if((err = AdrGetAddrSpace(destDesc, &destSpace)) != GOOD)
         return(err);
      if((err = SdWriteMember(copyDestSpaceDesc, (U8 FAR *)&destSpace, GOOD))
         !=GOOD) return(err);
   }
   if((err = SdWriteMember(copyDestTargetDesc, (U8 FAR *)&destTarget, GOOD))
       !=GOOD) return(err);
// end-unpacking



// ----------------------------------------------------------------------
// do the command and wait for completion
// 1.  In PowerPack,  SdWriteMember will exit after write, and control
//     will follow while{} to completion.
// 2.  In PowerScope,  while{} loop does not need to be here.
//     SdWriteMember will NOT exit after its "write", instead thread of
//     control will follow SDS changes and various callbacks, the copy,
//     then more callbacks, to completion.  At exit of SdWriteMember,
//     memCopyDoneSpinFlag will already have been set.
// ----------------------------------------------------------------------


   /* clear any ESC previously hit */
      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) return err;
      // abortFromEsc is ignored here


      memCopyDoneSpinFlag = FALSE;

      err = SdWriteMember(copyCommandDesc, (U8*)&copy, GOOD);

      if (GOOD == firstErr) firstErr = err;

   // Wait for completion, but allow escape
   //
   // 1.   the callback function MemCopyCallback() will set the
   //      memCopyDoneSpinFlag to true when copy completes
   // 2.   We must do any read (SdReadMember) to cause the data to
   //      be checked and the callback made.
   //      Copy verify is a bad choice since the member holds the 
   //      value from the previous copy.
      while (!memCopyDoneSpinFlag) {
         U32 dummy;
         err = SdnReadMember(SDN_NUM_SHARED_DATA_BYTES, (U8*)&dummy);
         if (GOOD == firstErr) firstErr = err;

         err = TskCheckAbort(&abortFromEsc);
         if(err!=GOOD) {
            SdnWriteMember(SDN_COPY_ABORT+copyBufIndex,(U8*)&true,GOOD);
            return(err);
         }
         if (abortFromEsc!=0) {
            err = SdnWriteMember(SDN_COPY_ABORT+copyBufIndex,(U8*)&true,GOOD);
            if (GOOD == firstErr) firstErr = err;
         }
      }

      err = SdReadMember(copyResultsDesc, (VOID FAR *)&resultsErr);
      if (GOOD == firstErr) firstErr = err;
      if (GOOD == firstErr) firstErr = resultsErr;


//
// Perform notifications that memory changed
//  ...copied from fill
//
   err = EnlEventNotify(EVENT_MEM_EDIT);
   if (GOOD == firstErr) firstErr = err;

   /* check two src ranges for memwrite address included; send
      out indiviual events if so */
   err = AdrSetAddrRangeLength(destDesc, length);
   if (GOOD == firstErr) firstErr = err;

   err = AdrDoPhysicalRangesOverlap(destDesc, srcRange0, &overlap);
   if (GOOD == firstErr) firstErr = err;
   if (overlap) {
      err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC0_RANGE);
      if (GOOD == firstErr) firstErr = err;
   }
   err = AdrDoPhysicalRangesOverlap(destDesc, srcRange1, &overlap);
   if (GOOD == firstErr) firstErr = err;
   if (overlap) {
      err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC1_RANGE);
      if (GOOD == firstErr) firstErr = err;
   }

   err = MemCacheInvalidateRange(destDesc);
   if (firstErr == GOOD) firstErr = err;

   RETURN_WITH_MEM_VERIFY_CHECK(firstErr);
}

/*--------------------------------------------------------------------------
**  MemCompare
----------------------------------------------------------------------------*/
RETCODE EXPORT MemCompare(DESCRIPTOR src,  DESCRIPTOR dest, U32 length,
                          BOOLEAN *result, U32 *retAddr1,   U32 *retAddr2,
                          U32 *retData1,   U32 *retData2) {
   RET_ADDR   retA1, retA2;
   RETCODE    err;
   EMULATION_STATE runaccState;
   U32 regSave[2];
   ADDR srcAddr, destAddr;

   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;
   if (length == 0) return(GOOD);
   if ((err=AdrGetAddrOffset(src,&(srcAddr.pos))) != GOOD)  return(err);
   if ((err=AdrGetAddrOffset(dest,&(destAddr.pos))) != GOOD)  return(err);
   if ((err=AdrGetAddrSpace(src,&srcAddr.space)) != GOOD)  return(err);
   if ((err=AdrGetAddrSpace(dest,&destAddr.space)) != GOOD)  return(err);
   if ((err=Sds2AbiRunaccStart(&runaccState,regSave)) != GOOD) return(err);
   if ((err= Sds2AbiMemCompare(srcAddr,destAddr,length,&retA1,&retA2,result)) != GOOD) 
      return(err);
   if ((err = Sds2AbiRunaccFinish(runaccState,regSave)) != GOOD) return(err);
   if (*result == FALSE) {   
      *retAddr1 = retA1.addr ;
      *retData1 = retA1.actual ;
      *retAddr2 = retA2.addr ;
      *retData2 = retA2.actual ;
   }
   return GOOD;
}

RETCODE EXPORT MemCompareSized(DESCRIPTOR src,
                               DESCRIPTOR dest,
                               U32 length,
                               BOOLEAN *result,
                               ACCESS_SIZE size) {
   return(ER_MEM_NOT_IMPLEMENTED);
}


/*--------------------------------------------------------------------------
**  MemMove
----------------------------------------------------------------------------*/
RETCODE EXPORT MemMove(DESCRIPTOR src,
                       DESCRIPTOR dest,
                       U32 length) {
   return(MemMoveSized(src,dest,length,accessSize));
}

#pragma argsused
RETCODE EXPORT MemMoveSized(DESCRIPTOR src,
                            DESCRIPTOR dest,
                            U32 length,
                            ACCESS_SIZE size) {
   /* don't forget to check for touching src range1,2 and generating event */
   return(ER_MEM_NOT_IMPLEMENTED);
}

/*--------------------------------------------------------------------------
**  MemChecksum 09/13/95 add
----------------------------------------------------------------------------*/
RETCODE EXPORT MemChecksum(DESCRIPTOR            src,
                           U32                   length,
                           U16                   sumSize,
                           U32                   FAR *sum) {
   RETCODE    err;
   EMULATION_STATE runaccState;
   U32 regSave[2], tmpSum;
   ADDR addr;
   
   if (GOOD != (err = BkProcessorMustBeHalted()))   /*check for emu running*/ 
      return err;

   if (length == 0) return(GOOD);
   if ((err=AdrGetAddrOffset(src,&addr.pos)) != GOOD) return(err) ;
   if ((err=AdrGetAddrSpace(src,&addr.space)) != GOOD) return(err) ;
   if ((err = Sds2AbiRunaccStart(&runaccState,regSave)) != GOOD) return(err);
   if (sumSize!=1) 
      if ((addr.pos%2)!=0) {
         addr.pos--; 
         length++;
      }

   if ( (err=Sds2AbiMemChecksum(addr, length, &tmpSum)) != GOOD)
      return(err);
   if ((err = Sds2AbiRunaccFinish(runaccState,regSave)) != GOOD) return(err);
   *sum = tmpSum;
   return (GOOD);
}

#pragma argsused
RETCODE EXPORT MemChecksumSized(DESCRIPTOR            src,
                                U32                   length,
                                MEM_DISPLAY_SIZE_TYPE itemSize,
                                U16                   sumSize,
                                SUM_MODE              mode,
                                U32                   *sum,
                                ACCESS_SIZE           size) {
   return(ER_MEM_NOT_IMPLEMENTED);
}

/*--------------------------------------------------------------------------
**  MemTest
----------------------------------------------------------------------------*/
RETCODE EXPORT MemTest(DESCRIPTOR src,
                       U32        length,
                       ADDR       FAR *retAddress) {
   RETCODE    err, firstErr=GOOD;
   U32        offset; 
   EMULATION_STATE runaccState;
   U32 regSave[2];
   BOOLEAN overlap;
   ADDR addr, tmpAddr;
   
   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;

   if (length == 0) return(GOOD);
   if ((err=AdrGetAddrOffset(src,&offset)) != GOOD) return(err) ;
   if ((err = Sds2AbiRunaccStart(&runaccState,regSave)) != GOOD) return(err);
   if ((err = AdrGetAddrSpace(src,&addr.space)) != GOOD) return(err);
   addr.pos = offset;
   if ( (err=iceTest(addr, length, &tmpAddr)) != GOOD)
      firstErr = iceMapError(err) ;
   if ((err = Sds2AbiRunaccFinish(runaccState,regSave)) != GOOD)
   if (GOOD == firstErr) firstErr = err;
   retAddress->pos = tmpAddr.pos;
   retAddress->space = tmpAddr.space;

/*********************************************************************
** Perform notifications that memory changed
*/
   
   err = EnlEventNotify(EVENT_MEM_EDIT);
   if (GOOD == firstErr) firstErr = err;

   err = AdrSetAddrRangeLength(src, length);
   if (GOOD == firstErr) firstErr = err;

   err = AdrDoPhysicalRangesOverlap(src, srcRange0, &overlap);
   if (GOOD == firstErr) firstErr = err;
   if (overlap) {
      err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC0_RANGE);
      if (GOOD == firstErr) firstErr = err;
   }
   err = AdrDoPhysicalRangesOverlap(src, srcRange1, &overlap);
   if (GOOD == firstErr) firstErr = err;
   if (overlap) {
      err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC1_RANGE);
      if (GOOD == firstErr) firstErr = err;
   }

   err = MemCacheInvalidateRange(src);
   if (firstErr == GOOD) firstErr = err;
/****************** end of notifications *****************************/

   return(firstErr);
}   /* end of MemTest */

#pragma argsused
RETCODE EXPORT MemTestSized(DESCRIPTOR src,
                            U32        length,
                            BOOLEAN    *result,
                            ACCESS_SIZE size) {
   return(ER_MEM_NOT_IMPLEMENTED);
}

/*------------------------------------------------------------------------
** MemSetAccessSize
----------------------------------------------------------------------------*/
#pragma argsused
RETCODE EXPORT MemSetAccessSize(ACCESS_SIZE size) {
RETCODE err = GOOD;
   accessSize = size;
//   if ((err = SdnWriteMember(SDN_LOAD_ACCESS, (U8*)&accessSize, GOOD))
//      != GOOD) return(err);
   if ((err = iceSetAccessSize(size)) != GOOD) return(err);

   return(err);
}

/*------------------------------------------------------------------------
** MemGetAccessSize
----------------------------------------------------------------------------*/
RETCODE EXPORT MemGetAccessSize(ACCESS_SIZE FAR *size) {
   *size = accessSize;
   return(GOOD);
}

/*------------------------------------------------------------------------
** MemSetVerifyWrites
----------------------------------------------------------------------------*/
RETCODE EXPORT MemSetVerifyWrites(BOOLEAN verify) {
   RETCODE err;
   U16 tempVerify;

   verifyWrites = verify;
   tempVerify = verify;
   if ((err = SdnWriteMember(SDN_FILL_VERIFY, (U8 FAR *)&verifyWrites,GOOD)) != GOOD)
      return err;
   if ((err = Sds2AbiSetVerify(tempVerify)) != GOOD)
      return err;
   return(GOOD);
}

/*------------------------------------------------------------------------
** MemGetVerifyWrites
----------------------------------------------------------------------------*/
RETCODE EXPORT MemGetVerifyWrites(BOOLEAN FAR *verify) {
   *verify = verifyWrites;
   return(GOOD);
}

/*--------------------------------------------------------------------------
** MemSetSourceRange
**
** Remove address descriptors of previous range and save new descriptors in
** PRIVATE vars
----------------------------------------------------------------------------*/
RETCODE EXPORT
MemSetSourceRange(DESCRIPTOR addrRangeDesc, MEM_SRC_ID srcID) {

   RETCODE err;       

   if (0L == addrRangeDesc)
      return ER_MEM_INVALID_DESCRIPTOR;
   switch (srcID) {
      case MEM_SRC_ID_0:
         err = AdrDestroyAddress(srcRange0);
         srcRange0 = addrRangeDesc;
         break;

      case MEM_SRC_ID_1:
         err = AdrDestroyAddress(srcRange1);
         srcRange1 = addrRangeDesc;
         break;

      default:
         err = ER_MEM_INVALID_SRC_ID;
   }
   return err; 
}  /* end of MemSetSourceRange */

/*--------------------------------------------------------------------------
** MemCacheInvalidate
** MemCacheInvalidateRange
**
----------------------------------------------------------------------------*/
RETCODE EXPORT MemCacheInvalidate(VOID) {
   U16 index;
   for (index=0; index<NUM_DUMP; index++) dumpCacheHit[index] = 0;
   return(GOOD);
}

RETCODE EXPORT MemCacheInvalidateRange(DESCRIPTOR addr) {
   RETCODE err;
   U16 index;
   U32 offset;
   U32 length;
   ADDR_SPACE space;
   if((err = AdrGetAddrOffset(addr, &offset))!=GOOD) return(err);
   if((err = AdrGetAddrRangeLength(addr, &length))!=GOOD) return(err);
   if((err = AdrGetAddrSpace(addr, &space)) != GOOD) return(err);
   for (index=0; index<NUM_DUMP; index++) {
      if (dumpCacheHit[index] > 0) {
         if (offset+length <= *((U32*)SdnData(SDN_DUMP_OFFSET+index)))
            continue;
         if (offset >= *((U32*)SdnData(SDN_DUMP_OFFSET+index))
            + *((U32*)SdnData(SDN_DUMP_LENGTH+index))) continue;
//         if (space != *((ADDR_SPACE*)SdnData(SDN_DUMP_SPACE+index)))
//            continue;
         dumpCacheHit[index] = 0;
      }
   }
   return(GOOD);
}

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