/****************************************************************************
**
**  Name:  memory.c
**
**  Description:
**     This is the memory server code of the Thunderbird.
**
**  Status:  PRELIMINARY | CODED 
**
**  $Log:   S:/tbird/mt2_186/mem/memory.c_v  $
** 
**    Rev 1.2   31 Jan 1997 13:45:18   Judy
** modified for mem search syntax check
** 
**    Rev 1.1   13 Jan 1997 10:32:38   Judy
** (1) memtest report error message
** (2) memory window read wrong data in physical mode
** 
**    Rev 1.0   16 Dec 1996 13:50:08   Judy
** Initial revision.
** 
**    Rev 1.70   26 Sep 1994 12:18:40   marilyn
** Fixed bug in invalidateCache where the physical offset was used to
** search the linear caches.
** 
**    Rev 1.69   22 Sep 1994 08:11:52   marilyn
** Fixed problem in MemSearch routine when two different desciptors
** were used as input.
** 
**    Rev 1.68   15 Aug 1994 13:39:12   ernie
** Added support for memory translation in firmware.  This is needed
** for situations where contiguous linear pages are not mapped to
** contiguous physical pages.  Also fixed the search memory response
** address to work for phase 2.
** 
**    Rev 1.67   21 Jul 1994 16:45:36   marilyn
** Fixed bug in processVerifyError where the default address descriptor
** was combined with a physical offset and the text was formatted as
** a virtual address when it wasn't.
** 
**    Rev 1.66   21 Jul 1994 10:51:44   marilyn
** Revised the interface to AdrGetSegmentSelector.
** 
**    Rev 1.65   27 Jun 1994 10:47:12   marilyn
** Search will attempt to return a virtual address if the incoming address
** is virtual.  As a default a linear address is returned.  THIS IS A
** PHASE 1 KLUDGE.
** 
**    Rev 1.64   18 May 1994 09:50:20   marilyn
** Updated for 386 beta.
** 
**    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/mt2_186/mem/memory.c_v   1.2   31 Jan 1997 13:45:18   Judy  $
**
**  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  _SDS2ABI_
#include "sds2abi.h"
#endif

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

#ifndef _TBIRDMEM_
#include "tbirdmem.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(); \
	 (VOID)EnlEventNotify(EVENT_MEM_EDIT); \
      } \
      return((retcode)); \
   }

		       /******************
			*                *
			*    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 = BYTE_SIZE;   /* For MemRead, MemFill, MemWrite */
BOOLEAN verifyWrites = TRUE;

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

PRIVATE
DESCRIPTOR fillAbortDesc = NULL,
	   fillSemaDesc = NULL,
	   fillAccessDesc = NULL,
	   fillVerifyDesc = NULL,
	   fillOffsetDesc = NULL,
	   fillSpaceDesc = NULL,
	   fillPhysicalDesc = 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,
	   copySrcPhysicalDesc= NULL,
	   copySrcSpaceDesc   = NULL,
	   copySrcTargetDesc  = NULL,
	   copyLengthDesc     = NULL,
	   copyDestOffsetDesc = NULL,
	   copyDestPhysicalDesc = 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 */
PRIVATE 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     *
			*                          *
			****************************/

RETCODE PRIVATE MemReadQuickLP(U32      offset,
			    BOOLEAN     physical,
			    ADDR_SPACE  space,
			    U16         length,
			    U8          *buffer,
			    ACCESS_SIZE size,
			    CACHE_OP    cacheOp);
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);
RETCODE PRIVATE MemXltAddrForFirmware(DESCRIPTOR addr, BOOLEAN *physical,
      U32 *offset);

		       /****************************
			*                          *
			*      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_PHYSICAL+fillBufIndex,
			 NULLPTR, &fillPhysicalDesc))
      !=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_PHYSICAL+copyBufIndex,
			 NULLPTR, &copySrcPhysicalDesc))
      !=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_PHYSICAL+copyBufIndex,
			 NULLPTR, &copyDestPhysicalDesc))
      !=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 AdrDoRangesOverlap 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((fillPhysicalDesc!=NULL) && (err = SdUnRegister(fillPhysicalDesc))!=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;
   BOOLEAN physical;
   if((err = AdrGetAddrSpace(startAddr, &space)) != GOOD) return(err);
   if((err = MemXltAddrForFirmware(startAddr, &physical, &offset))!=GOOD)
      return(err);
   return(MemReadQuickLP(offset,physical,space,length,buffer,size,cacheOp));
}

RETCODE EXPORT MemReadQuick(U32       offset,
			    ADDR_SPACE  space,
			    U16         length,
			    U8          *buffer,
			    ACCESS_SIZE size,
			    CACHE_OP    cacheOp) {
   return(MemReadQuickLP(offset,FALSE,space,length,buffer,size,cacheOp));
}

RETCODE PRIVATE MemReadQuickLP(U32      offset,
			    BOOLEAN     physical,
			    ADDR_SPACE  space,
			    U16         length,
			    U8          *buffer,
			    ACCESS_SIZE size,
			    CACHE_OP    cacheOp) {
   RETCODE err;
   U16 index, minHit, testIndex;
   U32 seg, off;
   if ((err = BkProcessorMustBeHalted()) != GOOD) return(err);
   while(length > 0) {
      U32 blockSize;
      BOOLEAN timedOut,done;
      blockSize = (length > SIZE_DUMP) ? SIZE_DUMP:length;
      if (physical) {
         off = (offset & 0xffff);
         if ((off + blockSize) > 0xffff)
            blockSize = 0x10000 - off;
      } 
      done = FALSE;
      /*
      **  If cache enabled and the sub-range is covered by a valid
      **  dump buffer, read data from there into buffer
      */
      if ((!physical) &&            /* Physical memory is never cached */
	    ((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 (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 = SdnWriteMember(SDN_DUMP_PHYSICAL+index,(U8*)&physical,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;
      seg = offset >> 16;
      off = offset & 0xffffl;
      if ((off = off + blockSize) > 0xffff)
         offset = ((seg + 0x1000) << 16) + (off & 0xffff);
      else
         offset += blockSize;
      length -= blockSize;
   }
   return(GOOD);
}
#pragma warn .sig

/***************************************************************************
**
**  MemProcessVerifyError
**
*****************************************************************************/
RETCODE EXPORT MemProcessVerifyError() {
   
   U32 verifyOffset, expectedData, actualData;
   U16 addrSpace;
   S8 verBuf[ADDR_BUFF_SZ], spaceBuf[SPACE_BUFF_SZ];
   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);
   
   AdrCreateAddressWithType(ADDR_PHYSICAL,&addr);
   AdrSetAddrOffset(addr, verifyOffset);
   AdrConvAddressToTextWithParams(addr, TRUE, TRUE, verBuf);
   AdrCremateAddress(&addr);

   /* format message */
   memset(spaceBuf, '\0', SPACE_BUFF_SZ);
   AdrGetSpaceStr(addrSpace,spaceBuf);
   wsprintf(verifyErrorString,
      "address: %s %s, expected: 0x%lX, actual: 0x%lX",
      verBuf, spaceBuf, expectedData, actualData);

   /* 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;
   BOOLEAN    physical;
   
   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return(err);

   originalLength = length;
   if((err = AdrGetAddrSpace(startAddr, &addrSpace)) != GOOD)
      return(err);
   if((err = SdWriteMember(fillSpaceDesc,(U8 FAR *)&addrSpace,GOOD))!=GOOD)
      return(err);
   if((err = MemXltAddrForFirmware(startAddr, &physical, &addrOffset))!=GOOD)
      return(err);
   if((err = SdWriteMember(fillPhysicalDesc,(U8*)&physical,GOOD))!=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    err, firstErr=GOOD;
U32 startOffset;
BOOLEAN    overlap;
BOOLEAN physical;
EMULATION_STATE runaccState;
U32 regSave[2];

   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;
   if (fillLength == 0) return(GOOD);
   if ((err=MemXltAddrForFirmware(startAddr,&physical,&startOffset)) != GOOD)
      return(err);
   if ((err = Sds2AbiRunaccStart(&runaccState,regSave)) != GOOD) return(err);
   if ( (err=Sds2AbiMemFill(startOffset,fillLength,pattern,patternLength,
        accessSize)) != GOOD) return(err);
   if ((err = Sds2AbiRunaccFinish(runaccState,regSave)) != GOOD) return(err);

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

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;
   BOOLEAN    physical;
   
   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 = MemXltAddrForFirmware(startAddr, &physical, &addrOffset))!=GOOD)
      return(err);
   if((err = AdrGetAddrSpace(startAddr, &addrSpace)) != GOOD)
      return(err);
   if((err = SdWriteMember(fillSpaceDesc, (U8 FAR *)&addrSpace, GOOD))
      !=GOOD) return(err);
   if((err = SdWriteMember(fillPhysicalDesc, (U8 FAR *)&physical, 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) {
RETCODE    err;
U16 segment;
U32 seg;
ADDR_SEGSEL_TYPE segType;
U32 startOffset, length, foundOffset;
ADDR_COMPARE compare;
BOOLEAN physical;
EMULATION_STATE runaccState;
U32 regSave[2];


   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;
   if (patLen > SIZE_SEARCH) return(ER_MEM_PAT_LEN);
   if ((err = AdrComparePhysicalAddresses(firstAddr, secondAddr, 
	 &compare))!=GOOD) return(err);
   if (compare==FIRST_ADDR_GREATER) return (ER_ADR_END_ADDR_TOO_SMALL);
   *found = FALSE;
   if ((err = SdnWriteMember(SDN_SEARCH_FOUND,(U8*)found,GOOD)) != GOOD)
	  return(err);
   if ((err=MemXltAddrForFirmware(firstAddr,&physical,&startOffset)) != GOOD)
      return(err);
   if((err = SdnWriteMemberIfChanged(SDN_SEARCH_PHYSICAL, (U8*)&physical,GOOD))
      !=GOOD) return(err);
   if ((err = AdrPhysicalRangeOfAddresses(firstAddr, secondAddr, 
	 &length))!=GOOD) return(err);
   if ((err = Sds2AbiRunaccStart(&runaccState,regSave)) != GOOD) return(err);
   if ( (err=Sds2AbiMemSearch(startOffset,length,pattern,patLen,found)) 
          != GOOD) return(err);
   if ((err = Sds2AbiRunaccFinish(runaccState,regSave)) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_SEARCH_FOUND, (U8*)found)) != GOOD) return(err);
   if (*found) {
      if ((err = SdnReadMember(SDN_SEARCH_OFFSET, (U8*)&foundOffset)) != GOOD)
	     return(err);
      if (physical == FALSE) {
         AdrGetAddrSegmentSelector(firstAddr, &segType, &segment);
         seg = (U32)segment;
         foundOffset -= seg*16;
         if((err = SdnWriteMember(SDN_SEARCH_OFFSET, (U8*)&foundOffset, GOOD))
             !=GOOD) return(err);
      }
      if ((err = AdrSetAddrOffset(firstAddr, foundOffset)) != GOOD) 
     return(err);
   }
   return(GOOD);
}

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

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

   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_PHYSICAL, (U8*)&physical,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) {
      U32 startOffset;
      if ((err = SdnReadMember(SDN_SEARCH_OFFSET, (U8*)&foundOffset)) != GOOD)
	 return(err);
      if ((err = AdrGetAddrOffset(startAddr, &startOffset)) != GOOD)
	 return(err);
      if ((err = AdrSetAddrOffset(firstAddr, startOffset+foundOffset-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) {

RETCODE    err, firstErr=GOOD;
U32 srcOffset, destOffset;
BOOLEAN     overlap;
BOOLEAN physical;
EMULATION_STATE runaccState;
U32 regSave[2];

   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;
   if (length == 0) return(GOOD);
   if ((err=MemXltAddrForFirmware(srcDesc,&physical,&srcOffset)) != GOOD)
      return(err);
   if ((err=MemXltAddrForFirmware(destDesc,&physical,&destOffset)) != GOOD)
      return(err);
   if ((err = Sds2AbiRunaccStart(&runaccState,regSave)) != GOOD) return(err);
   if ( (err=Sds2AbiMemCopy(srcOffset,length,srcTarget,destOffset)) != GOOD)
      return(err);
   if ((err = Sds2AbiRunaccFinish(runaccState,regSave)) != GOOD) return(err);
//
// 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);
}


#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;
   BOOLEAN     srcPhysical;
   BOOLEAN     destPhysical;
   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 = MemXltAddrForFirmware( srcDesc, &srcPhysical, &srcAddrOffset))
      != GOOD) return(err);
   if((err = SdWriteMember(copySrcOffsetDesc, (U8 FAR *)&srcAddrOffset, GOOD))
      !=GOOD) return(err);
   if((err = SdWriteMember(copySrcPhysicalDesc, (U8 FAR *)&srcPhysical, GOOD))
      !=GOOD) return(err);

   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 = MemXltAddrForFirmware( destDesc, &destPhysical, &destAddrOffset))
      != GOOD) return(err);
   if((err = SdWriteMember(copyDestOffsetDesc, (U8 FAR *)&destAddrOffset,GOOD))
      !=GOOD) return(err);
   if((err = SdWriteMember(copyDestPhysicalDesc, (U8 FAR *)&destPhysical,GOOD))
      !=GOOD) return(err);

   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,
              U16 *retData1,
              U16 *retData2) {
RETCODE    err;
U32 srcOffset, destOffset;
BOOLEAN physical;
EMULATION_STATE runaccState;
U32 regSave[2];

   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;
   if (length == 0) return(GOOD);
   if ((err=MemXltAddrForFirmware(src,&physical,&srcOffset)) != GOOD)
      return(err);
   if ((err=MemXltAddrForFirmware(dest,&physical,&destOffset)) != GOOD)
      return(err);
   if ((err = Sds2AbiRunaccStart(&runaccState,regSave)) != GOOD) return(err);
   if ( (err=Sds2AbiMemCompare(srcOffset,destOffset,length,result,retAddr1,
      retAddr2, retData1, retData2)) != GOOD) return(err);
   if ((err = Sds2AbiRunaccFinish(runaccState,regSave)) != GOOD) return(err);
   return GOOD;
}

#pragma argsused
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
----------------------------------------------------------------------------*/
RETCODE EXPORT MemChecksum(DESCRIPTOR            src,
			   U32                   length,
			   ACCESS_SIZE           sumSize,
			   U32                   *sum) {
   RETCODE    err;
   U32        offset;
   BOOLEAN physical;
   EMULATION_STATE runaccState;
   U32 regSave[2];
   
   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;

   if (length == 0) return(GOOD);
   if ((err=MemXltAddrForFirmware(src,&physical,&offset)) != GOOD)
      return(err);
   if ((err = Sds2AbiRunaccStart(&runaccState,regSave)) != GOOD) return(err);
   if ( (err=Sds2AbiMemChecksum(offset, length, sum)) != GOOD)
      return(err);
   if ((err = Sds2AbiRunaccFinish(runaccState,regSave)) != GOOD) return(err);
   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,
		       BOOLEAN    *result,
		       LPSTR      retAddr) {
   RETCODE    err, firstErr=GOOD;
   U32        offset, retOffset;
   U16 segment;
   DESCRIPTOR retDesc;
   ADDR_SEGSEL_TYPE segType;
   U8 *buffPtr;
   BOOLEAN    overlap;
   BOOLEAN physical;
   EMULATION_STATE runaccState;
   U32 regSave[2];
   
   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;

   if (length == 0) return(GOOD);
   if ((err=MemXltAddrForFirmware(src,&physical,&offset)) != GOOD)
      return(err);
   if ((err = Sds2AbiRunaccStart(&runaccState,regSave)) != GOOD) return(err);
//   if ( (err=Sds2AbiMemTest(offset, length, result, &retOffset)) != GOOD)
//      return(err);
   Sds2AbiMemTest(offset, length, result, &retOffset);
   if ((err = Sds2AbiRunaccFinish(runaccState,regSave)) != GOOD) return(err);

   if (*result == FALSE) {
      AdrCreateAddressWithType(ADDR_PHYSICAL,&retDesc);
      AdrSetAddrOffset(retDesc, retOffset);
      AdrConvAddressToTextWithParams(retDesc, TRUE, TRUE, retAddr);
      AdrCremateAddress(&retDesc);
   }

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

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

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

/*------------------------------------------------------------------------
** MemSetAccessSize
----------------------------------------------------------------------------*/
#pragma argsused
RETCODE EXPORT MemSetAccessSize(ACCESS_SIZE size) {
RETCODE err;
   if ( (err=Sds2AbiSetAccessSize(size)) != GOOD) return(err);
   accessSize = size;
   return(GOOD);
}

/*------------------------------------------------------------------------
** MemGetAccessSize
----------------------------------------------------------------------------*/
RETCODE EXPORT MemGetAccessSize(ACCESS_SIZE FAR *size) {
RETCODE err;
   if ( (err=Sds2AbiGetAccessSize(&accessSize)) != GOOD) return(err);
   *size = accessSize;
   return(GOOD);
}

/*------------------------------------------------------------------------
** MemSetVerifyWrites
----------------------------------------------------------------------------*/
RETCODE EXPORT MemSetVerifyWrites(BOOLEAN verify) {
RETCODE err;
   if ((err=Sds2AbiSetVerify(verify)) != GOOD) return(err);
   verifyWrites = verify;
   return(GOOD);
}

/*------------------------------------------------------------------------
** MemGetVerifyWrites
----------------------------------------------------------------------------*/
RETCODE EXPORT MemGetVerifyWrites(BOOLEAN FAR *verify) {
RETCODE err;
   if ((err=Sds2AbiGetVerify(&verifyWrites)) != GOOD) return(err);
   *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;
   BOOLEAN physical;

   /* 09/22/94 marilyn:
   ** Only linear offsets are stored in the mem cache buffers,
   ** so for physical offsets you can't invalidate anything.
   */
   if((err = MemXltAddrForFirmware(addr, &physical, &offset)) != GOOD)
      return(err);
   if (physical)  return GOOD;
   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);
}

RETCODE PRIVATE MemXltAddrForFirmware(DESCRIPTOR addr, BOOLEAN *physical,
      U32 *offset) {
   RETCODE err;
   ADDR_TYPE addrType;
   ADDR_SEGSEL_TYPE segType;
   U16 seg;
   U32 addrSeg, tmpOffset;
   PROC_SYSTEM_TYPE systemType;

   ProcReturnSystemType(&systemType);
   if ((err = AdrGetAddrType(addr, &addrType)) != GOOD) return(err);
   if (systemType == PROC_MICEPACK) {
      if (addrType == ADDR_PHYSICAL) {
         AdrGetAddrPhysicalOffset(addr, &tmpOffset);
         *physical = TRUE;
         *offset = ((tmpOffset&0xffff0000L)<<12) + (tmpOffset&0xffffL);
      } else {   
         *physical = FALSE;
         AdrGetAddrOffset(addr, &tmpOffset);
         AdrGetAddrSegmentSelector(addr, &segType, &seg);
         addrSeg = (U32)seg;
         *offset  = (addrSeg << 16) + tmpOffset;
      }
      return GOOD;
   }
   if (addrType == ADDR_PHYSICAL) {
      *physical = TRUE;
      err = AdrGetAddrPhysicalOffset(addr, offset);
   } else {
      *physical = FALSE;
      err = AdrGetAddrLinearOffset(addr, offset);
   }
   return(err);
}

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