/****************************************************************************
**
**  Name:  sharefw.c
**
**  Description:
**     Shared Data Server portion specific to the host side.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_186/sds/sharefw.c_v  $
** 
**    Rev 1.4   09 Dec 1997 10:41:10   Winky
** 
**    Rev 1.1   16 Dec 1996 18:03:56   Judy
** To fix memory write error.
** To fix breakpoint setting error.
** 
**    Rev 1.0   16 Dec 1996 13:46:20   Judy
** Initial revision.
** 
**    Rev 1.0   27 Aug 1996 15:12:14   Judy
** Initial revision.
** 
**    Rev 1.0   14 Jun 1996 13:51:26   Judy
** Initial revision.
** 
**    Rev 1.78   15 Jun 1994 08:59:14   tom
** Merged 1.75.1.0 onto trunk.
** 
**    Rev 1.77   11 May 1994 13:36:02   ernie
** Changed version numbering scheme to include build id and ver string.
** 
**    Rev 1.76   11 May 1994 08:45:12   ernie
** 1. Changed probe initialization error box to ABORTRETRYIGNORE type so
**    that initialization errors can be ignored to allow PowerViews to
**    boot so that the problem can be debugged.
** 2. Added registration for RDWR command (used by dump loop and ramtst).
** 
**    Rev 1.75.1.0   17 May 1994 15:25:20   ernie
** Added serial number to load response packet.
** 
**    Rev 1.75   06 May 1994 14:51:22   ernie
** Updated loader to handle packet serial numbers
** 
**    Rev 1.74   23 Apr 1994 07:47:04   ernie
** Added handling for stuck RESET condition.
** 
**    Rev 1.73   21 Apr 1994 16:23:58   john
** Made changes for new SIM_VALID sd member, untested
** 
**    Rev 1.72   08 Apr 1994 11:30:12   john
** Changed the code for handling the 330/340/360 sim
** 
**    Rev 1.71   30 Mar 1994 10:59:22   ernie
** Added bdmspeed shared data member to support 25MHz 340
** 
**    Rev 1.70   28 Mar 1994 11:34:32   nghia
** Removed STRLIB.H include - un-needed.
** 
**    Rev 1.69   16 Mar 1994 09:59:40   tom
** Upload packet size different between network implementations: add entry
** point which returns specific size.
** 
**    Rev 1.68   03 Mar 1994 16:10:54   ernie
** 1. Merged branch 1.64.1.1.
** 2. Moved setting of commState in CHECKSUM: state to allow it
**    to be set back to the idle state even if comm errors occur.
** 
**    Rev 1.67   02 Mar 1994 16:11:44   john
** Added checks for more pod types
** 
**    Rev 1.66   13 Jan 1994 11:57:46   ernie
** Added setting of cpuType in addition to probeType when the ini file
** specifies the processor type.  This was creating problems for Sony
** when they used the ini file method of setting the processor type.
** 
**    Rev 1.65   21 Dec 1993 15:29:48   tom
** Network changes.
** 
**    Rev 1.64.1.1   03 Mar 1994 15:48:28   ernie
** Added a check of commError before using memberIndex.  If a comm error
** occurs, the memberIndex field could be trashed.  Using it could result
** in a gp fault.  Also changed the ack/nak logic to send back a NAK if
** such an error occurs.
**
**    Rev 1.64   17 Dec 1993 11:36:54   ernie
** Added capability to read PowerScope processor type from pwrviews.ini.
** This will be a workaround for users having trouble with "Unknown
** Processor Type" messages if the automatic detection algorithm fails
** for some reason.  Note that this is implemented for PowerScope only.
** 
**    Rev 1.63   17 Dec 1993 10:30:32   ernie
** Updated expected value for 68330 MBAR register test.
** 
**    Rev 1.62   01 Dec 1993 13:26:38   john
** Fixed base address for writing the MBAR for 340 test
** 
**    Rev 1.61   16 Nov 1993 16:25:24   paul
** Change processor detect for F333.  It now matches PP
** algorithm.
** 
**    Rev 1.60   12 Nov 1993 16:07:38   paul
** Change SIM address reporting for 360.  We must add 4K to MBAR
** value since SIM is 4K after MBAR.  This is for 360 only.
**
**    Rev 1.59   04 Nov 1993 14:57:18   ernie
** Changed processor type algorithm to correctly detect 68330
**
**    Rev 1.58   19 Oct 1993 14:05:14   tom
** Added parameter to FwLoadBreakpoints to overwrite enable check.
**
**    Rev 1.57   08 Oct 1993 16:31:10   tom
** 8928: Check for number of breakpoints exceeded when breakpoint set.
**
**    Rev 1.56   07 Oct 1993 13:16:22   ernie
** 1. Changed minimum probe version required for 360 to 2.0(3).
** 2. Implemented support for stepMask.
**
**    Rev 1.55   17 Aug 1993 14:00:30   tom
** Repaired corrupted file
** Restored ernie's changes from 29 Jul 1993 14:09:38
** Fixed byte order in opcode check
**
**    Rev 1.54   29 Jul 1993 13:46:38   ernie
** 1. Changed hc16 processor determination algorithm again.
** 2. Added handler for configcs which sets the sim address sd member.  This
**    member is used by the Toolbar show cycle menu item.
**
**    Rev 1.53   28 Jul 1993 17:45:56   ernie
** Fixed bug in TskCheckAbort code in powerscope loader
**
**    Rev 1.52   26 Jul 1993 13:14:24   paul
** Replace CHECK_ABORT with TskCheckAbort for esc key support
**
**    Rev 1.51   22 Jul 1993 07:25:52   ernie
** Added semaphore on BkptHit().  In one target, noise on FREEZE was causing
** multiple breakpoint bytes to be sent from the probe.  This was causing
** uncontrolled stack growth due to BkptHit calling InputAvailable calling
** BkptHit...  The semaphore will prevent this uncontrolled growth from
** crashing PowerViews.
**
**    Rev 1.50   21 Jul 1993 13:35:16   ernie
** 1. Changed algorithm for 68HC16Y1 processor type determination.
** 2. Added check of special probe version required for 68360.
**
**    Rev 1.49   19 Jul 1993 18:53:48   ernie
** Changed processor type algorithm for 68360
**
**    Rev 1.48   16 Jul 1993 11:58:54   ernie
** Removed obsolete includes error.h and sdserror.h
**
**    Rev 1.47   15 Jul 1993 16:55:00   ernie
** Added configcs command handler for PowerScope
**
**    Rev 1.46   14 Jul 1993 09:58:08   ernie
** Changed generic "can't initialize probe" error message to report
** the specific error.  This is important for pv 2.0 since one of the
** possible errors will be incompatible hardware.
**
**    Rev 1.45   13 Jul 1993 09:11:28   ernie
** 1. Added memory search.
** 2. Moved memory verify operation to 8751 level for efficiency.
** 3. Added bdmSpeed support to allow faster operation when clock > 1 MHz.
** 4. Changed PowerScope loader to conform to new shared data interface.
** 5. Conform to new versions.h version definition.
**
**    Rev 1.44   25 May 1993 14:10:46   paul
** Added memory copy
**
**    Rev 1.43   25 May 1993 11:42:28   ernie
** Set memberError to GOOD if one of the new packet headers is received.
** This fixes a bug where the old error would continue being returned
** for each subsequent packet transfer.
**
**    Rev 1.42   17 May 1993 07:30:28   ernie
** Reduced overhead of shared data packets by adding another pair
** of header bytes which indicate the error code is GOOD without having
** to transmit 4 00 bytes in each packet.  Also reduced the size of the
** shared data index, partial member offset and length to 16 bits.
**
**    Rev 1.41   13 May 1993 11:11:34   ernie
** Added _sdlog command support
**
**    Rev 1.40   05 May 1993 09:24:28   doug
** support demo version (no hardware) run-time
**
**    Rev 1.39   22 Apr 1993 09:39:52   doug
** added firmware version check and auto-detection (automatically detect
** if PowerPack or PowerScope is connected)
**
**    Rev 1.38   16 Apr 1993 14:56:30   nghia
** Revised err and err2 usage to keep the probe initialize looping.
**
**    Rev 1.37   16 Apr 1993 14:39:22   ernie
** Moved code to handle byte swapping and end-of-buffer conditions
** from memory server to firmware.  Now the firmware always accesses
** memory using the specified access size even if the start address or
** length do not match the access size.  Fills are done using read-
** modify-write and dumps by discarding bytes not in the requested range.
**
**    Rev 1.36   13 Apr 1993 17:18:28   nghia
** Revised call to ErrDisplayErrorEx() with a (S16 FAR *) for buttonid.
**       Without this cast, bogus error code might be pop off the stack for display
** ing (Fixed the misterious "File not found." bug).
** Revised the PowerScope Probe initialize to pass the err2 when error occurred.
**
**    Rev 1.35   06 Apr 1993 09:43:28   doug
** add dialog box to query for PowerPack or PowerScope if not in .ini file
**
**    Rev 1.34   01 Apr 1993 15:25:16   doug
** Shared data is now generic for all versions of PowerPack and PowerScope.
** Differences are handled with run-time checks.
**
**    Rev 1.33   22 Mar 1993 07:35:16   ernie
** Added dummy routines for set/get of berr retry state
**
**    Rev 1.32   10 Dec 1992 07:53:00   ernie
** Added total packet count to _commerrors command output
**
**    Rev 1.31   09 Dec 1992 10:00:38   ernie
** Moved registration of SdsCheckBreakCause to sharefw.c for PowerScope
**
**    Rev 1.30   04 Dec 1992 12:37:18   doug
** com port is now read from .ini and passed in
**
**    Rev 1.29   04 Dec 1992 09:25:24   doug
** add callback true to update member
**
**    Rev 1.28   03 Dec 1992 08:16:34   ernie
** Added parameter to WSComConfig to select DTR handshaking (for PwrScope)
**
**    Rev 1.27   02 Dec 1992 07:40:00   ernie
** Moved all comm related stuff from sharedat.c to sharefw.c for PwrScope
**
**    Rev 1.26   21 Nov 1992 14:57:52   courtney
** Check error code returned from WSComInit to see if user aborted
** com dialog, return something appropriate to caller.
**
**    Rev 1.25   03 Nov 1992 09:59:04   doug
** clean up cannot init probe error to conform to standard error text (ppr7226)
**
**    Rev 1.24   23 Oct 1992 12:56:52   ernie
** 1. Changed interface to WSComWrite and cleaned up code around calls.
** 2. Added CheckBreakCause to repeatedly call SdnReadMember() when
**    a breakpoint is hit so that register info, etc. packets can be
**    acknowledged faster.
**
**    Rev 1.23   22 Oct 1992 15:25:34   ernie
** Changed shared data upload to ask for the initial image in 256 byte
** chunks instead of all at once.  This allows more frequent error checking
** during the upload.
**
**    Rev 1.22   24 Sep 1992 10:38:08   doug
** use real error number now
**
**    Rev 1.21   27 Aug 1992 06:26:26   mindy
** Disable the shared data timer from being setup altogether by setting
** the timerReady flag to TRUE.  See ppr6204.rpt for why this was done.
**
**    Rev 1.20   25 Aug 1992 10:00:46   mindy
** changed call to start timer
**
**    Rev 1.19   14 Aug 1992 11:15:22   courtney
** Return proper error if com config returns FALSE.
**
**    Rev 1.18   14 Aug 1992 10:43:46   doug
** clean up warning messages now that strict warnings are issued
**
**    Rev 1.17   01 Aug 1992 16:51:32   courtney
** Added more error checking on return from Comm calls.
**
**    Rev 1.16   30 Jul 1992 15:27:12   doug
** use shared data error file
**
**    Rev 1.15   28 Jul 1992 07:20:22   doug
** check to see if probe initialized ok and if not, allow user to retry
**
**    Rev 1.14   08 Jun 1992 09:46:12   ernie
** Changed sdinit.h to sdtempl.h (all sd templates combined in 1 file)
**
**    Rev 1.13   14 May 1992 12:32:00   mindy
** removed GetERrorText
**
**    Rev 1.12   13 May 1992 16:52:12   mindy
** a) removed check of local variable in terminate routine - won't have
**    data segment libs already been closed.?
** b) Removed unused routines.
** c) SdatInternalError removed by errortext routine.
** d) added SdatGetErrorText routine.
**
**    Rev 1.11   11 May 1992 07:53:10   mindy
** added SdTErminateServer routine to kill timer when exiting
**
**    Rev 1.10   05 May 1992 14:00:14   mindy
** a) SdatInternalError now pops up a dialogue box. PPR5551.
** b) Use TMalloc/TFree not the global allocation stuff.  PPR5552
**
**    Rev 1.9   27 Mar 1992 15:12:46   courtney
** Cleanup.
**
**    Rev 1.8   25 Mar 1992 15:41:16   courtney
** Redesign of output routine SdatSendBytes to send an entire member.
**
**    Rev 1.7   11 Feb 1992 12:07:10   doug
** moved dummy code to new m030/dummyfw.c
**
**    Rev 1.6   11 Feb 1992 11:08:24   doug
** added read and write functions to simulate 1 Meg of memory (0 to 1Meg).
** Now, the dummy shared data reads and writes will match.  NOTE:  This
** is a 68030 solution, so this file will have to move to m030 eventually.
**
**    Rev 1.5   03 Feb 1992 15:42:48   doug
** time out now 1/2 second
**
**    Rev 1.4   17 Jan 1992 15:45:20   doug
** support for SDS version when no emulator connected
**
**    Rev 1.3   14 Jan 1992 11:22:24   ernie
** memory for shared data values is now allocated at run time.
**
**    Rev 1.2   31 Oct 1991 09:30:40   doug
** on initialization, read the shared data image from the box to initialize
** the host copy
**
**    Rev 1.1   30 Oct 1991 15:57:20   doug
** The shared data image (byte array) is now separated out of the shared
** data because a) it was going over 64k and b) the firmware did not want
** uninitialized data in the flash prom (and both sides have to use same
** scheme).
**
**    Rev 1.0   29 Jul 1991 08:54:42   jim
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/sds/sharefw.c_v   1.4   09 Dec 1997 10:41:10   Winky  $
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

/* !!! Windows */
#define _WINDOWS_

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#ifndef _BASEWIND_
#include "basewind.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 _SDPROC_
#include "sdproc.h"
#endif

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

#ifndef _SHAREDAT_
#include "sharedat.h"
#endif

#ifndef _WSCOM_
#include "wscom.h"
#endif

#ifndef __TIME_H
#include "time.h"
#endif

#ifndef _VERSIONS_
#include "versions.h"
#endif

#include "pdll.h"

#ifndef  _SDS2ABI_
#include "sds2abi.h"
#endif
#include "..\inc\mp_sharefw.h"

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

#define MEMBER_BUFFER_SIZE 512

#define INI_FILENAME "mp186.ini"
#define INI_SECTION_NAME "SystemInfo"
#define INI_BDM_SPEED "bdmSpeed"
#define INI_PROCESSOR_TYPE "PowerScope"

#define STATIC static

/*
** values for the types of packets
*/
#define SD_QRY 0x11  /* product type query */
#define SD_WR 0x55
#define SD_WR_GOOD 0x56
#define SD_WR_PART 0xaa
#define SD_WR_PART_GOOD 0xab
#define SD_ACK 0x33
#define SD_NAK 0xCC
#define SD_PRD_POWERPACK 0x22
#define SD_PRD_POWERSCOPE 0x44

typedef U32 ERROR_CODE;

static S8 logFileName[128] = {"sd.log"};
static BOOLEAN logging = FALSE;

STATIC U8 commAckFlag;
STATIC U32 maxCommRetry = 10;   /* number of times to retry sending packet */
#define SECOND (CLK_TCK)   /* from time.h */

#define M68332_TPU_ADDR 0xFFFE00L
#define M68332_TPU_MCR_DEFAULT 0x0080
#define M68331_GPT_ADDR 0xFFF900L
#define M68331_GPT_MCR_DEFAULT 0x0080
#define M68330_MBAR_ADDR 0x3FF02L
#define M68340_MBAR_ADDR 0x3FF02L
#define M68340_MBAR_BASE_ADDR 0x3FF00L
#define M68360_MBAR_ADDR 0x3FF02L
#define M68330_MBAR_TEST_VAL 0xFFFF
#define M68340_MBAR_TEST_VAL 0xFFFF
#define M68360_MBAR_TEST_VAL 0xFFFF
#define M68330_MBAR_EXP_VAL 0xF3FF
#define M68340_MBAR_EXP_VAL 0xF3FF
#define M68360_MBAR_EXP_VAL 0xFFFF
#define M68340_INTR_ADDR 0xFFFF0784L
#define M68340_INTR_TEST_VAL 0xffff
#define M68340_INTR_EXP_VAL 0x07ff
#define M68333_ADCMCR_ADDR 0xFFF700L   /* ADCMCR defines are from fwps.c */
#define M68333_ADCMCR_TEST_VAL 0xffff
#define M68333_ADCMCR_EXP_VAL 0xE080
#define M68HC16Y1_TPU_ADDR    0xffe00L
#define M68HC16Y1_TPU_MCR_DEFAULT 0x0080
#define M68HC16Z1_RAMBAL_ADDR   0xfffb06L
#define M68HC16Z1_RAMBAL_TEST_VAL 0xffff
#define M68HC16Z1_RAMBAL_EXP_VAL 0xfc00
#define M68HC16Z2_RAMBAL_EXP_VAL 0xfe00

STATIC U32 pktTimeout = (5*SECOND);   /* wait time for completion of packet */
STATIC U32 byteTimeout = (SECOND/2);
STATIC U32 commErrorH2BTotal = 0;
STATIC U32 commErrorB2HTotal = 0;
STATIC U32 commErrorH2BTimeout = 0;
STATIC U32 commErrorH2BRetries = 0;
STATIC U32 commErrorB2HTimeout = 0;
STATIC U32 commErrorB2HMissing = 0;
STATIC U32 commErrorB2HGarbled = 0;

#define PROBE_VERSION_FOR_RETRY 0x010400L // Version 1.4 is the first w/ retry
#define PROBE_VERSION_FOR_XBRKS 0x010400L // Version 1.4 is the first w/ xbrks
#define PROBE_VERSION_REQUIRED  0x020000L // Must have 2.0 to work with pv
#define PROBE_VERSION_FOR_360   0x020003L // Must have 2.03 for 360

BOOLEAN timerReady = TRUE;  /* !!! never set up timer */
FARPROC lpCallBack;

#define ID_RXTIMER 1        /* Receive Timer ID */
#define RX_ELLAPSE 500     /* Timer ellapse interval 1/2 second */

#ifndef _WINDOWS_
SEMAPHORE sdSemaphore;
#endif

S8 *sdSharedDataVal;
PROC_SYSTEM_TYPE systemType;

U32 ackTimeout=5*SECOND;   /* ack should be sent from box within this time */

typedef enum { ACK_NONE, ACK_ACK, ACK_NAK, ACK_HEADER } COMM_ACK;
COMM_ACK ackFlag;

typedef enum {
   BKPT_UNLOADED, BKPT_XBRK, BKPT_SWB, BKPT_STATUS_END=0x7fff
} BKPT_STATUS;

typedef struct BKPT_ENTRY_TAG {
   struct BKPT_ENTRY_TAG *next;
   struct BKPT_ENTRY_TAG *prev;
   U16 id;
   U16 opcode;
   U32 addr;
   ADDR_SPACE space;
   BKPT_STATUS status;
} BKPT_ENTRY;

BKPT_ENTRY *bkptHead = NULL;
BKPT_ENTRY *bkptTail = NULL;
BKPT_ENTRY *bkptFree = NULL;

BOOLEAN bkptEnable = FALSE;   /* Enables bkpt handler to run when emul stops*/
BOOLEAN bkptHitFlag = FALSE;  /* Set by bkpt handler when emul stops */

BREAK_CAUSE anticipatedCause;

typedef struct {
   U8 args;
   U8 results;
   BOOLEAN transmit;
   U16 command;
} BDM_INFO;

#define BDM_NOP       0    /* Same index for CPU16 and CPU32 */
#define BDM_GO        1    /* Same index for CPU16 and CPU32 */
#define BDM32_WRITE_B 2    /* Indices into BDM_INFO tables below */
#define BDM32_WRITE_W 3
#define BDM32_WRITE_L 4
#define BDM32_FILL_B  5
#define BDM32_FILL_W  6
#define BDM32_FILL_L  7
#define BDM32_READ_B  8
#define BDM32_READ_W  9
#define BDM32_READ_L 10
#define BDM32_DUMP_B 11
#define BDM32_DUMP_W 12
#define BDM32_DUMP_L 13
#define BDM32_RAREG  14
#define BDM32_WAREG  15
#define BDM32_RSREG  16
#define BDM32_WSREG  17

#define BDM16_WDMEM   2
#define BDM16_WPMEM   3
#define BDM16_RDMEM   4
#define BDM16_RPMEM   5
#define BDM16_RDREG   6
#define BDM16_WDREG   7
#define BDM16_RDMAC   8
#define BDM16_WRMAC   9
#define BDM16_RPCSP  10
#define BDM16_WPCSP  11
#define BDM16_RCCR   12
#define BDM16_WCCR   13
#define BDM16_REG_MASK (0x007f)    /* 2nd word of RDREG, WDREG commands */

static  BDM_INFO BDM32Table[] = {  /*Table is same order as above enum */
   { 1, 0, FALSE, 0x0000 },    /* nop */
   { 1, 0, FALSE, 0x0C00 },    /* go */
   { 4, 1, FALSE, 0x1800 },    /* write memory b */
   { 4, 1, FALSE, 0x1840 },    /* write memory w */
   { 5, 1, FALSE, 0x1880 },    /* write memory l */
   { 2, 1, FALSE, 0x1C00 },    /* fill memory b */
   { 2, 1, FALSE, 0x1C40 },    /* fill memory w */
   { 3, 1, FALSE, 0x1C80 },    /* fill memory l */
   { 3, 1, TRUE,  0x1900 },    /* read memory b */
   { 3, 1, TRUE,  0x1940 },    /* read memory w */
   { 3, 2, TRUE,  0x1980 },    /* read memory l */
   { 1, 1, TRUE,  0x1D00 },    /* dump memory b */
   { 1, 1, TRUE,  0x1D40 },    /* dump memory w */
   { 1, 2, TRUE,  0x1D80 },    /* dump memory l */
   { 1, 2, TRUE,  0x2180 },    /* read adreg    */
   { 3, 0, FALSE, 0x2080 },    /* write adreg   */
   { 1, 2, TRUE,  0x2580 },    /* read sysreg   */
   { 3, 0, FALSE, 0x2480 },    /* write sysreg  */
};

#define CMD_NOP (BDMTable[BDM_NOP].command)   /* Word to use as cmd filler */

/* low nibble of command word needed to access these specific registers */
#define SYSREG_SFC 0xe
#define SYSREG_DFC 0xf
#define SYSREG_ATEMP 0x8
#define SYSREG_RPC 0x0
#define SYSREG_SR  0xb

static BDM_INFO BDM16Table[] = {  /* Table is same order as above enum */
   { 1, 0, FALSE, 0x1789 },    /* nop */
   { 1, 0, FALSE, 0x1788 },    /* go */
   { 4, 1, FALSE, 0x1785 },    /* wdmem */
   { 4, 1, FALSE, 0x1787 },    /* wpmem */
   { 3, 1, TRUE,  0x1784 },    /* rdmem */
   { 3, 1, TRUE,  0x1786 },    /* rpmem */
   { 2, 7, TRUE,  0x1780 },    /* read reg */
   { 9, 0, FALSE, 0x1781 },    /* write reg */
   { 1, 6, TRUE,  0x178A },    /* read mac */
   { 7, 0, FALSE, 0x178B },    /* write mac */
   { 1, 4, TRUE,  0x1782 },    /* read pc/sp */
   { 5, 0, FALSE, 0x1783 },    /* write pc/sp */
   { 2, 1, TRUE,  0x1780 },    /* read ccr (follow cmd by 0001) */
   { 3, 0, FALSE, 0x1781 },    /* write ccr (follow cmd by 0001) */
};

static BDM_INFO *BDMTable = BDM32Table;   /* changed according to probe */

static BOOLEAN berrRetry = TRUE;
static BDM_SPEED bdmSpeed = BDM_FAST;
static U32 probeVersion = 0x000000;  /* major | minor | compat */

PROC_CPU cpuType;

#define MAX_XBRKS 4      /* Determined by 8751 firmware */
U16 numXbrks=0;   /* Number of execution breakpoints currently active */
U32 xbrkAddr[MAX_XBRKS];

#define STEP_TIMEOUT 5*SECOND
#define HALT_TIMEOUT 5*SECOND

#define lobyte(x)  ((x)&0xff)
#define hibyte(x)  (((x)>>8)&0xff)
#define loword(x)  ((U16)((x)&0xffff))
#define hiword(x)  ((U16)(((x)>>16)&0xffff))

/* probe command byte definitions...must match pwrscope.a31 */
#define PCMD_VERSION 0     // return probe type and version information
#define PCMD_RESET   1     // reset processor and enter bdm
#define PCMD_HALT    2     // halt processor and enter bdm
#define PCMD_GR      3     // reset processor and enter emulation
#define PCMD_SETSTEP 4     // set step flag (next go will do single step)
#define PCMD_CLRSTEP 5     // clr step flag (next go will do free run)
#define PCMD_BDM     6     // send bdm command to processor
#define PCMD_CAUSE   7     // retrieve cause of last break
#define PCMD_SETSIZE 8     // set default size for memory accesses
#define PCMD_WRITE   9     // write memory
#define PCMD_READ    0xA   // read memory
#define PCMD_WDMEM16 0xB   // write data memory, cpu16
#define PCMD_WPMEM16 0xC   // write prog memory, cpu16
#define PCMD_RDMEM16 0xD   // read data memory, cpu16
#define PCMD_RPMEM16 0xE   // read prog memory, cpu16
#define PCMD_WRITE_RETRY   0x0F  // memory commands with retry enabled
#define PCMD_READ_RETRY    0x10
#define PCMD_WDMEM16_RETRY 0x11
#define PCMD_WPMEM16_RETRY 0x12
#define PCMD_RDMEM16_RETRY 0x13
#define PCMD_RPMEM16_RETRY 0x14
#define PCMD_STEP_PBRK     0x15  // step until breakpoint
#define PCMD_STEP_PBRK16   0x16  // step until breakpoint, cpu16
#define PCMD_GET_VERIFY    0x17  // retrieve parameters about last vfy error
#define PCMD_FAST_BDM      0x40  // OR into any bdm command to enable fast bdm
#define PCMD_VERIFY        0x80  // OR into any write command to get verify

/* probe result errorcode definitions...must match pwrscope.a31 */
#define PERR_GOOD                0
#define PERR_BDM_RESET_TIMEOUT   0x20  // timeout waiting for bdm after reset
#define PERR_BDM_HALT_TIMEOUT    0x21  // timeout waiting for bdm after halt
#define PERR_BDM_NOT_READY       0x22  // bus cycle termination timeout
#define PERR_BDM_ILLEGAL         0x23  // bdm communication error
#define PERR_BDM_BERR            0x24  // bus error on memory cycle
#define PERR_BDM_RESET           0x25  // reset occurred during bdm transact
#define PERR_BDM_EMULATING       0x26  // can't do bdm while emulating
#define PERR_INVALID_SIZE        0x27  // invalid size specifier (internal)
#define PERR_BDM_BERR_TERM       0x29  // bus cycle internal termination
#define PERR_VERIFY              0x2A  // memory verify error
#define PERR_RESET_STUCK         0x2B  // reset stuck asserted

/* miscellaneous probe-related definitions...must match pwrscope.a31 */
#define PCOM_HEADER    0xA5      // sent as first byte of packet and result
#define PCOM_ACK       0x33      // packet or result received ok
#define PCOM_NAK       0xCC      // error receiving packet or result
#define PCOM_POWERON   0x77      // sent by probe at probe poweron
#define PCOM_BKPTHIT   0x66      // sent by probe when emulation stops
#define PCOM_STEPFAIL  0x88      // sent by probe when stepping hits error
#define PCOM_STEPBKPT  0x99      // sent by probe when stepping hits bkpt
#define PCOM_MAX_RETRIES 10      // number of retries on probe->host
#define PCOM_CHECKSUM     0      // all bytes in packet/result add up to this
#define PCMD_MAX_BDM     32      // maximum length of a bdm command packet
#define PCMD_MAX_LENGTH 270      // maxlen of any probe packet incl hdr,chksum
#define PCMD_MAX_READ    16      // max number of bytes in one read packet
#define PCMD_MAX_WRITE  128      // max number of bytes in one write packet

// Values possible from PCMD_CAUSE packet
#define RAW_CAUSE_BGND    0
#define RAW_CAUSE_BKPT    1

STATIC BOOLEAN demoVersion = FALSE;  // true if no hardware version is running

  /* Command bytes for loader */
#define LOAD_BYTE_COUNT   0xF1
#define LOAD_REPEAT_COUNT 0xF5
#define LOAD_SET_ADDRESS  0xF9
#define LOAD_NOP          0xFE
#define LOAD_EOF          0xFF

VERIFY_INFO loadVerifyInfo[NUM_LOAD];

/* These variables are used by step to save the value of SR.  If stepMask
   is TRUE, steps will disable interrupts by patching the interrupt mask
   bits of SR, then restoring the original value after the step. */
BOOLEAN SRModified;   /* Has SR been patched? */
U16 SRSave;           /* Saved value of SR register */

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

                        /****************************
                         *                          *
                         *     LOCAL PROTOTYPES     *
                         *                          *
                         ****************************/
VOID LogWrite(BOOLEAN fw, U16 n, U8 *bytes);
BOOL SharedDataComm(VOID);
RETCODE TransmitToBox(SD_TRANSMIT_MODE sync);

/* Shared data handling routines */
VOID FAR PASCAL SdFwInitProbe(DESCRIPTOR desc);
VOID FAR PASCAL SdFwGo(DESCRIPTOR desc);
VOID FAR PASCAL SdFwGr(DESCRIPTOR desc);
VOID FAR PASCAL SdFwStep(DESCRIPTOR desc);
VOID FAR PASCAL SdFwHalt(DESCRIPTOR desc);
VOID FAR PASCAL SdFwReset(DESCRIPTOR desc);
VOID FAR PASCAL SdFwBkpt(DESCRIPTOR desc);
VOID FAR PASCAL SdFwMemRead(DESCRIPTOR desc);
VOID FAR PASCAL SdFwMemFill(DESCRIPTOR desc);
VOID FAR PASCAL SdFwRdWrCommand(DESCRIPTOR desc);
VOID FAR PASCAL SdFwMemLoad(DESCRIPTOR desc);
VOID FAR PASCAL SdFwMemLoadCommand(DESCRIPTOR desc);
RETCODE FwLoadAction(U8 *data, VERIFY_INFO *verifyInfo);
RETCODE FwMemReadAction(DESCRIPTOR desc, MEMBER_INDEX *index);
RETCODE FwMemFillAction(DESCRIPTOR desc, MEMBER_INDEX *index);
VOID FAR PASCAL SdFwMemSearch(DESCRIPTOR desc);
RETCODE PRIVATE FwMemSearchAction(BOOLEAN *found);
RETCODE PRIVATE SearchMemForward(U32 *offset, ADDR_SPACE space, U32 length,
      U16 pLength, ACCESS_SIZE access, BOOLEAN not,
      U8 *data, BOOLEAN *found);
RETCODE PRIVATE SearchMemReverse(U32 *offset, ADDR_SPACE space, U32 length,
      U16 pLength, ACCESS_SIZE access, BOOLEAN not,
      U8 *data, BOOLEAN *found);
VOID FAR PASCAL SdFwMemCopy(DESCRIPTOR desc);
RETCODE PRIVATE FwMemCopyAction(DESCRIPTOR desc);
VOID FAR PASCAL SdFwBerrRetry(DESCRIPTOR desc);

/* Shared data handling routines for trace */
VOID FAR PASCAL SdFwTraceBoolean(DESCRIPTOR desc);
VOID FAR PASCAL SdFwEnableSequencer(DESCRIPTOR desc);
VOID FAR PASCAL SdFwSetTracing(DESCRIPTOR desc);
VOID FAR PASCAL SdFwTraceRead(DESCRIPTOR desc);
VOID FAR PASCAL SdFwConfigCS(DESCRIPTOR desc);
RETCODE PRIVATE TestForSim(U32 addr, BOOLEAN *found);

/* Supporting routines */
extern RETCODE Sds2AbiFwInit(VOID);
RETCODE FwPingProbe(VOID);
RETCODE FwReset(CPU_RESET typeOfReset);
RETCODE FwCpuReset(VOID);
RETCODE FwUpdateProbeVersion(VOID);
RETCODE FwLoadRegisters(VOID);
RETCODE FwLoadRegistersCpu16(VOID);
RETCODE FwLoadRegistersCpu32(VOID);
RETCODE FwUnloadRegisters(BOOLEAN patchPCSP);
RETCODE FwUnloadRegistersCpu16(VOID);
RETCODE FwUnloadRegistersCpu32(BOOLEAN patchPCSP);
RETCODE FwBkptAction(VOID);
BKPT_ENTRY *BkptFindById(U16 id);
BKPT_ENTRY *BkptFindByAddr(U32 addr);
RETCODE BkptDelete(U16 id);
RETCODE BkptAdd(BKPT_ENTRY bkpt);
RETCODE FwLoadBreakpoints(BOOLEAN loadNow);
RETCODE FwUnloadBreakpoints(VOID);
RETCODE FwPowerOn(VOID);
RETCODE FwBkptHit(U8 comByte);
RETCODE FwStep(U32 count);
RETCODE FwGo(EMULATION_STATE *emuState);
RETCODE FwGr(EMULATION_STATE *emuState);
RETCODE FwHalt(VOID);
RETCODE PRIVATE StepPreamble(VOID);
RETCODE PRIVATE StepPostamble(VOID);


RETCODE EXPORT FwFillMem(U32 offset, ADDR_SPACE space, U32 length,
       U32 pLength, ACCESS_SIZE access, BOOLEAN verify,
       VERIFY_INFO *verifyInfo, U8 *data);
RETCODE EXPORT FwReadMem(U32 offset, ADDR_SPACE space, U32 length,
       ACCESS_SIZE access, U8 *data);
RETCODE EXPORT FillMemAction(U32 offset, ADDR_SPACE space, U32 length,
       U32 pLength, ACCESS_SIZE access, BOOLEAN verify,
       VERIFY_INFO *verifyInfo, U8 *data);
RETCODE EXPORT ReadMemAction(U32 offset, ADDR_SPACE space, U32 length,
       ACCESS_SIZE access, U8 *data);
RETCODE EXPORT FwWriteVerifyErrorInfo(U32 offset, ADDR_SPACE space, U32 expected,
       U32 actual, VERIFY_INFO *verifyInfo);
RETCODE RunaccStart(EMULATION_STATE *emuState, U32 *regs);
RETCODE RunaccFinish(EMULATION_STATE emuState, U32 *regs);
RETCODE FwSaveFCRegs(U32 *regs);
RETCODE FwRestoreFCRegs(U32 *regs);

RETCODE ProbeTransact(U8 *data, U16 cmdLength, U8 *result, U16 resLength);
RETCODE RcvBytes(U8 *data, U16 length);
RETCODE BDMTransact(BDM_INFO info, VOID *results, ...);
U32 SwapDwordOrder(U32 input);
U16 SwapWordOrder(U16 input);

BOOLEAN IsM68HC16Z1(PROBE_TYPE *probeType);
BOOLEAN IsM68HC16Z2(PROBE_TYPE *probeType);
BOOLEAN IsM68HC16Y1(PROBE_TYPE *probeType);
BOOLEAN IsM68330(PROBE_TYPE *probeType);
BOOLEAN IsM68331(PROBE_TYPE *probeType);
BOOLEAN IsM68332(PROBE_TYPE *probeType);
BOOLEAN IsM68333(PROBE_TYPE *probeType);
BOOLEAN IsM68340(PROBE_TYPE *probeType);
BOOLEAN IsM68360(PROBE_TYPE *probeType);
RETCODE GetSystemType(PROC_SYSTEM_TYPE *systemType);

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

/*****************************************************************************
**
**    SdFwInitialize
**
*****************************************************************************/
RETCODE EXPORT SdFwInitialize(U16 hWnd, MEMBER_RESIDENCE residence,
      S16 *comPort) {
   RETCODE err = GOOD, err2 = GOOD;
   BOOLEAN true=TRUE,false=FALSE;
   RETCODE probeRetcode;
   DESCRIPTOR desc;
   FARPROC func;
   LOOP_VAR window;
   U8 major, minor, bugId, buildId;
   S16 id;
   U32	longPort;
   char	*stopString;
   PROCESSOR_FAMILY procFamily;
   PROBE_TYPE probeType;
   S8 buf[64];

   if (residence != MEMBER_HOST)
      return(ER_INTERNAL);

   if( (sdSharedDataVal=TMalloc(BYTES_IN_SHARED_DATA))==NULL)
      return(ER_OUT_OF_MEMORY);

   if((err = ProcReturnDemonstrationVersion(&demoVersion))!=GOOD)
      return(err);

   GetPrivateProfileString(INI_SECTION_NAME, INI_BDM_SPEED, "fast", buf,
      sizeof(buf), INI_FILENAME);
   if (stricmp(buf, "slow") == 0) bdmSpeed = BDM_SLOW;
   else bdmSpeed = BDM_FAST;

if(!demoVersion) {
   GetPrivateProfileString("Comm","type","",buf,sizeof(buf),INI_FILENAME);
   if (stricmp(buf, "MicrotekParallel") == 0) {
      GetPrivateProfileString("MicrotekParallel", "basePort", "0x200", buf,
		sizeof(buf), INI_FILENAME);
      stopString = NULL;
	  longPort = strtoul(buf, &stopString, 0);
	  if (longPort & 0xfffffc00L) return(ER_COM_OPEN);
	  *comPort = (S16)(longPort & 0x3f0);
   }
   else if (stricmp(buf, "Printer") == 0) {
      GetPrivateProfileString("Printer", "LPTPort", "", buf,
                sizeof(buf), INI_FILENAME);
      if (stricmp(buf, "LPT1") == 0) *comPort = 5;
      else if (stricmp(buf, "LPT2") == 0) *comPort = 6;
      else  *comPort = 7;
  }
  else {
      if (stricmp(buf, "Serial") == 0) {
      GetPrivateProfileString("Serial", "comPort", "", buf,
		sizeof(buf), INI_FILENAME);
      if (stricmp(buf, "com1") == 0) *comPort = 1;
      else if (stricmp(buf, "com2") == 0) *comPort = 2;
      else if (stricmp(buf, "com3") == 0) *comPort = 3;
      else  *comPort = 4;
      }
  }
/* First see if user has set the hardcoded processor type in mp186.ini */
  GetPrivateProfileString(INI_SECTION_NAME, "micepack", "80C186XL", buf,
     sizeof(buf), INI_FILENAME);
/*!!! This text->ID conversion should be in proc.dll, but was put in here
   ** temporarily so that only one DLL change could be shipped to a customer */
/* Winky 12/3/97 I80C186_MP --> I80C186XL_MP */
/*               I80C188_MP --> I80C188XL_MP */
  if (!stricmp(buf,"80C186")) { probeType=I80C186XL_MP;}
  else if (!stricmp(buf,"80C188")) { probeType=I80C188XL_MP;}
  else if (!stricmp(buf,"80C186XL")) { probeType=I80C186XL_MP;}
  else if (!stricmp(buf,"80C188XL")) { probeType=I80C188XL_MP;}
  else if (!stricmp(buf,"80C186EA")) { probeType=I80C186EA_MP;}
  else if (!stricmp(buf,"80L186EA")) { probeType=I80C186EA_MP;}
  else if (!stricmp(buf,"80C188EA")) { probeType=I80C188EA_MP;}
  else if (!stricmp(buf,"80L188EA")) { probeType=I80C188EA_MP;}
  else if (!stricmp(buf,"80C186EB")) { probeType=I80C186EB_MP;}
  else if (!stricmp(buf,"80L186EB")) { probeType=I80C186EB_MP;}
  else if (!stricmp(buf,"80C188EB")) { probeType=I80C188EB_MP;}
  else if (!stricmp(buf,"80L188EB")) { probeType=I80C188EB_MP;}
  else if (!stricmp(buf,"80C186EC")) { probeType=I80C186EC_MP;}
  else if (!stricmp(buf,"80L186EC")) { probeType=I80C186EC_MP;}
  else if (!stricmp(buf,"80C188EC")) { probeType=I80C188EC_MP;}
  else if (!stricmp(buf,"80L188EC")) { probeType=I80C188EC_MP;}
  if ((probeType & I80C186_FAMILY) == I80C186_FAMILY) { 
     procFamily = FAMILY_X86;
     cpuType = PROC_CPU_80186;
  }
  err = Sds2AbiLoadMicePackFw((U16)(*comPort), probeType);
  if (err != GOOD) return(err);
  systemType = PROC_MICEPACK;
/********************  MICEPACK**************************/
  if ((err = Sds2AbiInitCoreMembers()) != GOOD) return(err);
  func = MakeProcInstance((FARPROC) Sds2AbiSetMap, hLib);
  for (window=0; window<NUM_MAP_ENTRIES; window++) {
     if ((err = SdnRegister(SDN_MAP_COMMAND+window, func, &desc)) != GOOD)
       return(err);
  }
   /*** register probe fw control members */
  func = MakeProcInstance((FARPROC) SdFwInitProbe, hLib);
  if ((err=SdnRegister(SDN_PROBE_INIT,func,&desc)) != GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwGo, hLib);
  if ((err=SdnRegister(SDN_GO,func,&desc)) != GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwGr, hLib);
  if ((err=SdnRegister(SDN_GR,func,&desc)) != GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwStep, hLib);
  if ((err=SdnRegister(SDN_STEP,func,&desc)) != GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwHalt, hLib);
  if ((err=SdnRegister(SDN_HALT,func,&desc)) != GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwReset, hLib);
  if ((err=SdnRegister(SDN_RESET_CPU,func,&desc)) != GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwBkpt, hLib);
  if ((err=SdnRegister(SDN_BKPT_CMD,func,&desc)) != GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwBerrRetry, hLib);
  if ((err=SdnRegister(SDN_BERR_RETRY,func,&desc)) != GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwMemRead, hLib);
  for(window=0; window<NUM_DUMP; window++) {
     if ((err=SdnRegister(SDN_DUMP_LENGTH+window,func,&desc)) != GOOD)
         return(err);
  }
  func = MakeProcInstance((FARPROC) SdFwMemFill, hLib);
  for(window=0; window<NUM_FILL; window++) {
     if ((err=SdnRegister(SDN_FILL_COMMAND+window,func,&desc)) != GOOD)
        return(err);
  }
  func = MakeProcInstance((FARPROC) SdFwMemLoad, hLib);
  for(window=0; window<NUM_LOAD; window++) {
     if ((err=SdnRegister(SDN_LOAD_DATA+window,func,&desc)) != GOOD)
       return(err);
     loadVerifyInfo[window].offset = SDN_LVERIFY_OFFSET+window;
     loadVerifyInfo[window].space = SDN_LVERIFY_SPACE+window;
     loadVerifyInfo[window].expected = SDN_LVERIFY_EXPECTED+window;
     loadVerifyInfo[window].actual = SDN_LVERIFY_ACTUAL+window;
  }
  func = MakeProcInstance((FARPROC) SdFwMemLoadCommand, hLib);
  if ((err = SdnRegister(SDN_LOAD_COMMAND, func, &desc)) != GOOD)
     return(err);
  func = MakeProcInstance((FARPROC) SdFwMemSearch, hLib);
  if ((err=SdnRegister(SDN_SEARCH_COMMAND, func, &desc)) != GOOD)
     return(err);
  func = MakeProcInstance((FARPROC) SdFwMemCopy, hLib);
  if ((err=SdnRegister(SDN_COPY_COMMAND, func, &desc)) != GOOD)
     return(err);
  func = MakeProcInstance((FARPROC) SdFwRdWrCommand, hLib);
  if ((err=SdnRegister(SDN_RDWR_COMMAND, func, &desc)) != GOOD)
     return(err);
  /*** register on trace and trigger members in case they are called */
  func = MakeProcInstance((FARPROC) SdFwTraceBoolean, hLib);
  if ((err=SdnRegister(SDN_TRACE_GET_STATUS,func,&desc))!=GOOD)
     return(err);
  func = MakeProcInstance((FARPROC) SdFwTraceBoolean, hLib);
  if ((err=SdnRegister(SDN_CLEAR_TRACE,func,&desc))!=GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwEnableSequencer, hLib);
  if ((err=SdnRegister(SDN_ENABLE_SEQUENCER,func,&desc))!=GOOD)
     return(err);
  func = MakeProcInstance((FARPROC) SdFwSetTracing, hLib);
  if ((err=SdnRegister(SDN_SET_TRACING,func,&desc))!=GOOD) return(err);
  func = MakeProcInstance((FARPROC) SdFwTraceRead, hLib);
  if ((err=SdnRegister(SDN_TRACE_BUFF_LEN,func,&desc))!=GOOD)
       return(err);
  func = MakeProcInstance((FARPROC) SdFwConfigCS, hLib);
  if ((err=SdnRegister(SDN_CONFIG_CS_HW_CMD,func,&desc))!=GOOD)
      return(err);
  /*** set init probe member to initialize hardware using callback then
   ** check initialization status.  Allow user to retry init or abort.
  */
/*
   do {
      BOOLEAN timedOut;
      if ((err = SdnWriteCmdReadResponse(SDN_PROBE_INIT,(U8*)&true, GOOD,
        SDN_PRBINIT_RESP, 0, &timedOut)) != GOOD) return(err);
      if ((err2 = SdnReadMember(SDN_PRBINIT_RESP,(U8*)&err)) != GOOD)
        return(err);
      if (err != GOOD) {
         if((err2 = ErrDisplayErrorEx(err,FORCE_POPUP,MB_TYPE_RETRYCANCEL,
            (S16 FAR *)&id))!= GOOD)
            return(err2);
         if (id == IDCANCEL) return(ER_ABORT_SESSION);
       }
    } while (err != GOOD);
 */
} else { /* Demo Version */
   if((err = InitDummy())!=GOOD) return(err);
}
   if (systemType == PROC_MICEPACK) {
      if ((err=Sds2AbiFwInit()) != GOOD) return(err);
      return(FwUnloadRegisters(FALSE));
   }
   if ((err = SdnWriteMember(SDN_BDM_SPEED, (U8*)&bdmSpeed, GOOD)) != GOOD)
      return(err);
   return(GOOD);
}
/*****************************************************************************
**
**    SdTerminateServer
**
*****************************************************************************/
RETCODE EXPORT SdTerminateServer(VOID){
if(!demoVersion) {
   if (WSComClose() != TRUE)
      return (ER_SD_CLOSE);
}
   return(GOOD);
}

/*****************************************************************************
**
**    SdatGetExclusiveSdAccess
**
*****************************************************************************/
RETCODE EXPORT SdatGetExclusiveSdAccess(VOID) {
   return(GOOD);
}

/*****************************************************************************
**
**    SdatFreeExclusiveSdAccess
**
*****************************************************************************/
RETCODE EXPORT SdatFreeExclusiveSdAccess(VOID) {
   return(GOOD);
}

/*****************************************************************************
**
**    SdatInvokeCallBack
**
*****************************************************************************/
RETCODE EXPORT SdatInvokeCallback(CALLBACK updateFunc, DESCRIPTOR desc) {
   /* call the registered callback function */
   (*updateFunc)(desc); /* !!! warning */
   return(GOOD);
}

/****************************************************************************
**
**  SdatSendBytes
**
*****************************************************************************/
RETCODE EXPORT SdatSendBytes(U16 length, U8 FAR *data) {
   RETCODE err;
   U16 pktSize;
   if (demoVersion) return(GOOD);
   do {
      pktSize = min(PKT_SIZE, length);
      if ((err = WSComWrite(data, &pktSize)) != GOOD) return(err);
      length -= pktSize;
      data += pktSize;
   } while (length>0);
   return(GOOD);
}  /* SdatSendBytes */

/**************************** Communications ******************************/
/*
** Read all available bytes into buffer whenever called.  If complete
** member arrives, remove from buffer, update member, and call callbacks.
*/
typedef enum {
   COMM_CMD,
   COMM_MEMBER0, COMM_MEMBER1,
   COMM_ERROR0, COMM_ERROR1, COMM_ERROR2, COMM_ERROR3,
   COMM_OFFSET0, COMM_OFFSET1,
   COMM_LENGTH0, COMM_LENGTH1,
   COMM_DATA, COMM_CHECKSUM
} COMM_STATE;

/* static info about packet in progress. Saved in case retry is needed. */
STATIC LPSTR sdPacketData;
STATIC U8  sdPacketHeader[SDS_PARTIAL_HDRSIZE];
STATIC U16 sdPacketDataLength;
STATIC U16 sdPacketHeaderLength;
STATIC U8  sdPacketChecksum;
STATIC U16 sdPacketRetryCount;
STATIC BOOLEAN sdPacketInProgress = FALSE;
STATIC clock_t sdPacketStartTime;
STATIC RETCODE sdPacketError = GOOD;
STATIC FARPROC sdPacketCallback = NULL;

/****************************************************************************
**
**  SendFullMemberData
**
**  Description:
**     Sends a full member data update request to box.
**
**  Parameters:
**     input:
**        index:  index of shared data member
**        sync:   whether to wait for ACK or not
**        func:   function to call when async transmission complete
**     output:
**        none
**
*****************************************************************************/
RETCODE SendFullMemberData(MEMBER_INDEX index, SD_TRANSMIT_MODE sync,
                           FARPROC func) {
   if (demoVersion) {
      if (func) (*func)();
      return(GOOD);
   }
   if(systemType==PROC_POWERPACK) {
      while (sdPacketInProgress) InputAvailable();  /* Wait for previous */
      *((U16*)&sdPacketHeader[1]) = (U16)index;
      if (MEMBER_RETCODE(index) == GOOD) {
         sdPacketHeader[0] = SD_WR_GOOD;
         sdPacketHeaderLength = sizeof(sdPacketHeader[0]) + sizeof(U16);
      } else {
         sdPacketHeader[0] = SD_WR;
         *((U32*)&sdPacketHeader[3]) = MEMBER_RETCODE(index);
         sdPacketHeaderLength = sizeof(sdPacketHeader[0]) + sizeof(U16)
                                + sizeof(U32);
      }
      sdPacketData = MEMBER_DATA(index);
      sdPacketDataLength = (U16)MEMBER_NUM_BYTES(index);
      sdPacketCallback = func;
      return(TransmitToBox(sync));
   } else {
      if (func) (*func)();
      return(GOOD);
   }
}

/****************************************************************************
**
**  SendPartialMemberData
**
**  Description:
**     Sends a partial member data update request to box.
**
**  Parameters:
**     input:
**        index:  index of shared data member
**        offset:  offset where data is to be written
**        length:  number of bytes of data
**        sync:   whether to wait for ACK or not
**        func:   function to call when async transmission complete
**     output:
**        none
**
*****************************************************************************/
RETCODE SendPartialMemberData(MEMBER_INDEX index, MEMBER_OFFSET offset,
      MEMBER_SIZE length, SD_TRANSMIT_MODE sync, FARPROC func) {
   if (demoVersion) {
      if (func) (*func)();
      return(GOOD);
   }
   if(systemType==PROC_POWERPACK) {
      while (sdPacketInProgress) InputAvailable();  /* Wait for previous */
      *((U16*)&sdPacketHeader[1]) = (U16)index;
      if (MEMBER_RETCODE(index) == GOOD) {
         sdPacketHeader[0] = SD_WR_PART_GOOD;
         *((U16*)&sdPacketHeader[3]) = (U16)offset;
         *((U16*)&sdPacketHeader[5]) = (U16)length;
         sdPacketHeaderLength = sizeof(sdPacketHeader[0]) + 3*sizeof(U16);
      } else {
         sdPacketHeader[0] = SD_WR_PART;
         *((U32*)&sdPacketHeader[3]) = MEMBER_RETCODE(index);
         *((U16*)&sdPacketHeader[7]) = (U16)offset;
         *((U16*)&sdPacketHeader[9]) = (U16)length;
         sdPacketHeaderLength = sizeof(sdPacketHeader[0]) + 3*sizeof(U16)
                                + sizeof(U32);
      }
      sdPacketData = MEMBER_DATA(index) + (U16)offset;
      sdPacketDataLength = length;
      sdPacketCallback = func;
      return(TransmitToBox(sync));
   } else {
      if (func) (*func)();
      return(GOOD);
   }
}

RETCODE TransmitToBox(SD_TRANSMIT_MODE sync) {
   RETCODE err = GOOD;
   U16 i;
   if (logging) {
      U8 buf[32];
      memcpy((LPSTR)&buf[0], (LPSTR)&sdPacketHeader[0], sdPacketHeaderLength);
      memcpy((LPSTR)&buf[sdPacketHeaderLength], (LPSTR)sdPacketData,
         min(sizeof(buf)-sdPacketHeaderLength,sdPacketDataLength));
      LogWrite(FALSE, min(sizeof(buf),
         sdPacketHeaderLength+sdPacketDataLength), buf);
   }

   sdPacketChecksum=0;
   for(i=1; i<sdPacketHeaderLength; i++) sdPacketChecksum -= sdPacketHeader[i];
   for(i=0; i<sdPacketDataLength; i++) sdPacketChecksum -= sdPacketData[i];

   commAckFlag=0;
   // group into one packet if ethernet and they'll fit into the buffer
   if (!WSComAckRequired() && 
      (MEMBER_BUFFER_SIZE >= (sdPacketHeaderLength + sdPacketDataLength + 1))) {
      // send 3 parts of member at once
      U16 start = 0;
      U8 buf[MEMBER_BUFFER_SIZE];

      memcpy((LPSTR)&buf[0], (LPSTR)&sdPacketHeader[0], sdPacketHeaderLength);
      start += sdPacketHeaderLength;
      memcpy((LPSTR)&buf[start], (LPSTR)sdPacketData, sdPacketDataLength);
      start += sdPacketDataLength;
      memcpy((LPSTR)&buf[start], (LPSTR)&sdPacketChecksum, 1);
      start += 1;
      if ((err = SdatSendBytes(start, buf)) !=GOOD) return(err);
   }
   else {
      // send in 3 parts
      if ((err = SdatSendBytes(sdPacketHeaderLength, sdPacketHeader))
         !=GOOD) return(err);
      if ((err = SdatSendBytes(sdPacketDataLength, (U8*)sdPacketData))
         != GOOD) return(err);
      if ((err = SdatSendBytes(1, &sdPacketChecksum)) != GOOD) return(err);
   }
   sdPacketRetryCount = 0;
   // packet already sent if ack not required
   if (WSComAckRequired()) {
       sdPacketInProgress = TRUE;
   }
   sdPacketStartTime = clock();
   commErrorH2BTotal++;

   // Finish processing for network packet
   if (!WSComAckRequired()) {
      if (sync == SDS_ASYNC) {
         WSComFlush();
         // notify callback function that buffers have been sent
         if (sdPacketCallback)
            (*sdPacketCallback)();
      }
      return(GOOD);
   }

   // Finish processing for serial packet
   if (sync == SDS_SYNC)
      return(SdsAsyncWait());
   else
      return(GOOD);
}

RETCODE EXPORT SdsAsyncWait(VOID) {
   while (sdPacketInProgress) {
      InputAvailable();
   }
   return(sdPacketError);
}

/****************************************************************************
**
** SdServicePacket
**
** Called from InputAvailable().
**
** If a communication packet is in progress, check to see if ACK
** was received or if the timeout period has elapsed.  If ACK, set
** sdPacketError to GOOD and reset the sdPacketInProgress flag, else
** retry transmission.  If retry count exhausted, set sdPacketError
** to ER_COMM_RETRY_EXHAUSTED.
**
****************************************************************************/
VOID PRIVATE SdServicePacket(VOID) {
   RETCODE err=GOOD;
   if (sdPacketInProgress) {
      switch (commAckFlag) {
      case 0:
         if (clock() < sdPacketStartTime + pktTimeout) break;
         commErrorH2BTimeout++;
         err = ER_COMM_PACKET_TIMEOUT;
         /* fall thru to retry transmission */
      case SD_NAK:
         if (sdPacketRetryCount >= maxCommRetry) {
            sdPacketError = err ? err : ER_COMM_RETRY_EXHAUSTED;
            sdPacketInProgress = FALSE;
            break;
         }
         commErrorH2BRetries++;
         sdPacketRetryCount++;
         commAckFlag=0;
         err = SdatSendBytes(sdPacketHeaderLength, sdPacketHeader);
         if (!err) err = SdatSendBytes(sdPacketDataLength, (U8*)sdPacketData);
         if (!err) err = SdatSendBytes(1, &sdPacketChecksum);
         if (err != GOOD) {
            sdPacketError = err;
            sdPacketInProgress = FALSE;
            break;
         }
         sdPacketStartTime = clock();
         break;
      case SD_ACK:
         sdPacketError = GOOD;
         sdPacketInProgress = FALSE;
         break;
      }
      if (!sdPacketInProgress && sdPacketCallback) (*sdPacketCallback)();
   }
   return;
}

RETCODE SdatGetCommErrors(U32 *H2BTimeout,U32 *H2BRetries, U32 *B2HTimeout,
          U32 *B2HMissing,U32 *B2HGarbled,U32 *H2BTotal,U32 *B2HTotal) {
   *H2BTotal   = commErrorH2BTotal;
   *B2HTotal   = commErrorB2HTotal;
   *H2BTimeout = commErrorH2BTimeout;
   *H2BRetries = commErrorH2BRetries;
   *B2HTimeout = commErrorB2HTimeout;
   *B2HMissing = commErrorB2HMissing;
   *B2HGarbled = commErrorB2HGarbled;
   return(GOOD);
}

RETCODE SdatGetCommRetry(U32 *retry) {
   *retry = maxCommRetry;
   return(GOOD);
}

RETCODE SdatSetCommRetry(U32 retry) {
   maxCommRetry = retry;
   return(GOOD);
}

RETCODE SdatGetCommTimeout(U32 *timeout) {
   if(systemType==PROC_POWERPACK) {
      *timeout = byteTimeout;
   } else {
      *timeout = pktTimeout;
   }
   return(GOOD);
}

RETCODE SdatSetCommTimeout(U32 timeout) {
   if(systemType==PROC_POWERPACK) {
      byteTimeout = timeout;
   } else {
      pktTimeout = timeout;
   }
   return(GOOD);
}


/******************************* LOCAL *************************************/

/****************************************************************************
**
**  SharedDataComm
**
**  Description:
**     Invoke Windows timer to handle any input to shared data.  The timer
**     interrupt handler will wake this task up every regular interval.
**
**  Parameters:
**     input:
**        none
**     output:
**        none
**
*****************************************************************************/
BOOL SharedDataComm(VOID) {
if(!demoVersion) {
   /* Set Timer run once only */
   if (!timerReady) {
      lpCallBack = MakeProcInstance((FARPROC) SdatInputAvailable, hLib);
      /*  Set timer to call back the SdatInputAvailable function */
      if (!(timerReady = WSComRecvTimer(RX_ELLAPSE,lpCallBack))) {
         /* Fail to invoke timer */
         FreeProcInstance(lpCallBack);
         return (FALSE);
      }
      /* !!! When terminate program need to clean this up */
   }
}
   return (TRUE);
}

/**********************************************************************
**
**  SdatGetBerrRetry
**  SdatSetBerrRetry
**
************************************************************************/
#pragma argsused
RETCODE SdatGetBerrRetry(BOOLEAN *retry) {
   return(SdnReadMember(SDN_BERR_RETRY, retry));
}

#pragma argsused
RETCODE SdatSetBerrRetry(BOOLEAN retry) {
   if(retry && (systemType==PROC_POWERSCOPE)
         && (probeVersion < PROBE_VERSION_FOR_RETRY))
      return(ER_PROBE_VERSION_NO_RETRY);
   return(SdnWriteMember(SDN_BERR_RETRY, &retry, GOOD));
}

/*****************************************************************************
**
** Probe Interface Shared Data Server Command Handlers
**
*****************************************************************************/

/*****************************************************************************
**
** SdFwInitProbe
**
** Registered on SD_INIT_PROBE.  Initializes probe hardware by performing
** cpu reset operation, then determines chip type and probe version, then
** unloads registers using FwReset().
*****************************************************************************/
#pragma argsused
VOID FAR PASCAL SdFwInitProbe(DESCRIPTOR desc) {
   RETCODE err;
   err = FwUpdateProbeVersion();
   if (!err) err = FwReset(RESET_CPU_AND_UPDATE_STATUS);
   SdnWriteMember(SDN_PRBINIT_RESP,(U8*)&err,GOOD);
}

#pragma argsused
VOID FAR PASCAL SdFwGo(DESCRIPTOR desc) {
   RETCODE err,err2;
   EMULATION_STATE emuState=EM_HALTED;
   U32 pc, myCS;
   BOOLEAN emulChange=FALSE;
   if (((err = SdnReadMember(SDN_EMULATION_STATE,(U8*)&emuState)) == GOOD)
         && (emuState == EM_HALTED)
         && ((err = FwLoadRegisters()) == GOOD)) {
        /* Step first if current instruction has an active breakpoint */
      SdnReadMember(SDN_CS, (U8*)&myCS);
      SdnReadMember(SDN_EIP, (U8*)&pc);
//      pc += myCS*16;
      pc = (myCS << 16) + pc;
      if (BkptFindByAddr(pc)) {
         if ((err = FwStep(1)) == GOOD) emulChange = TRUE;
      }
      if (!err) err = FwLoadBreakpoints(FALSE);
   }
   if ((!err) && (emuState == EM_HALTED)) {
      if ((err = FwGo(&emuState)) == GOOD) emulChange = TRUE;
   }
   if (emulChange) {
      if (emuState == EM_HALTED) {
         err2 = FwUnloadRegisters(FALSE); /*Didn't go*/
         if (!err) err = err2;
      }
      err2 = SdnWriteMember(SDN_EMULATION_STATE,(U8*)&emuState,GOOD);
      if (!err) err = err2;
   }
   SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,err);
}

#pragma argsused
VOID FAR PASCAL SdFwGr(DESCRIPTOR desc) {
   RETCODE err;
   EMULATION_STATE emuState=EM_HALTED;
   if(((err = SdnReadMember(SDN_EMULATION_STATE,(U8*)&emuState)) == GOOD)
         && (emuState == EM_HALTED)) {
      err = FwLoadBreakpoints(FALSE);
   }
   if ((!err) && (emuState == EM_HALTED)) {
      err = FwGr(&emuState);
      if (!err) err = SdnWriteMember(SDN_EMULATION_STATE,(U8*)&emuState,GOOD);
   }
   SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,err);
}

VOID FAR PASCAL SdFwStep(DESCRIPTOR desc) {
   RETCODE err,err2;
   EMULATION_STATE emuState=EM_HALTED;
   U32 count;
   if (((err = SdReadMember(desc,(U8*)&count)) == GOOD)
         && ((err = SdnReadMember(SDN_EMULATION_STATE,(U8*)&emuState))==GOOD)
         && (emuState == EM_HALTED)) {
      emuState=EM_STEPPING;
      if (((err=SdnWriteMember(SDN_EMULATION_STATE,(U8*)&emuState,err))==GOOD)
            && ((err=SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,err))==GOOD)
            && ((err = FwLoadRegisters()) == GOOD)) {
         err = FwStep(count);
         if (!err) emuState = EM_HALTED;
      } else emuState = EM_HALTED;
   }
   err2 = FwUnloadRegisters(FALSE);
   if (!err) err=err2;
   SdnWriteMember(SDN_EMULATION_STATE,(U8*)&emuState,GOOD);
   SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,err);
}

#pragma argsused
VOID FAR PASCAL SdFwHalt(DESCRIPTOR desc) {
   RETCODE err;
   EMULATION_STATE emuState;
   time_t start;
   if(((err = SdnReadMember(SDN_EMULATION_STATE,(U8*)&emuState)) == GOOD)
         && (emuState != EM_HALTED)) {
      bkptHitFlag=FALSE;
      err = FwHalt();
      emuState = EM_HALTED;
      SdnWriteMember(SDN_EMULATION_STATE,(U8*)&emuState,GOOD);
      SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,err);
   }
}

VOID FAR PASCAL SdFwReset(DESCRIPTOR desc) {
   CPU_RESET typeOfReset=RESET_CPU_AND_UPDATE_STATUS;
   SdReadMember(desc, (U8*)&typeOfReset);  /* ignore error */
   FwReset(typeOfReset);
}

#pragma argsused
VOID FAR PASCAL SdFwBkpt(DESCRIPTOR desc) {
   RETCODE err;
   err = FwBkptAction();
   SdnWriteMember(SDN_BKPT_RESULT,(U8*)&err,err);
}

VOID FAR PASCAL SdFwMemRead(DESCRIPTOR desc) {
   RETCODE result;
   MEMBER_INDEX index;
   result=FwMemReadAction(desc,&index);
   SdnWriteMember(SDN_DUMP_RESULT+index,(U8*)&result,result);
}

RETCODE FwMemReadAction(DESCRIPTOR desc, MEMBER_INDEX *index) {
   RETCODE err,err2,result;
   U32 length;
   U32 offset;
   ADDR_SPACE space;
   ACCESS_SIZE access;
   U8 *data;

   if ((err = SdGetMemberIndex(desc, index))!=GOOD) return(err);
   if ((err = SdReadMember(desc, (U8*)&length))!=GOOD) return(err);
   if (length==0) return(GOOD);
   if (length>SIZE_DUMP) return(ER_MEMORY_BUFF_LEN);

   if ((err = SdnReadMember(SDN_DUMP_OFFSET+(*index), (U8*)&offset)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_DUMP_SPACE+(*index), (U8*)&space)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_DUMP_ACCESS+(*index), (U8*)&access)) != GOOD)
      return(err);
   if ((access!=BYTE_SIZE) && (access!=WORD_SIZE) && (access!=DWORD_SIZE))
      return(ER_INVALID_ACCESS);

   if((data = (U8*)TMalloc(length))==NULL) return(ER_OUT_OF_MEMORY);

   result = FwReadMem(offset, space, length, access, data);

   err = SdnWritePartialMember(SDN_DUMP_BUFFER+(*index),0,length,data,result);
   err2 = TFree((LPSTR)data);
   return(err?err:err2);
}

VOID FAR PASCAL SdFwMemFill(DESCRIPTOR desc) {
   RETCODE result;
   MEMBER_INDEX index;
   result=FwMemFillAction(desc,&index);
   SdnWriteMember(SDN_FILL_RESULTS+index,(U8*)&result,result);
}

RETCODE FwMemFillAction(DESCRIPTOR desc, MEMBER_INDEX *index) {
   RETCODE err,err2;
   U32 length, pLength;
   U32 offset;
   ADDR_SPACE space;
   ACCESS_SIZE access;
   BOOLEAN verify;
   U8 *data;
   VERIFY_INFO verifyInfo;

   if ((err = SdGetMemberIndex(desc, index))!=GOOD) return(err);
   if ((err = SdnReadMember(SDN_FILL_LENGTH+(*index),(U8*)&length))!=GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_FILL_PATLENGTH+(*index),(U8*)&pLength))!=GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_FILL_OFFSET+(*index),(U8*)&offset))!=GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_FILL_SPACE+(*index),(U8*)&space))!=GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_FILL_ACCESS+(*index),(U8*)&access))!=GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_FILL_VERIFY+(*index),(U8*)&verify))!=GOOD)
      return(err);
   if ((length == 0) || (pLength == 0)) return(GOOD);
   if (pLength>SIZE_FILL) return(ER_MEMORY_BUFF_LEN);
   if ((access!=BYTE_SIZE) && (access!=WORD_SIZE) && (access!=DWORD_SIZE))
      return(ER_INVALID_ACCESS);

   if((data = (U8*)TMalloc(pLength))==NULL) return(ER_OUT_OF_MEMORY);

   if((err=SdnReadPartialMember(SDN_FILL_BUFFER+(*index),0,pLength,data))
         ==GOOD) {
      verifyInfo.offset = SDN_VERIFY_OFFSET+(*index);
      verifyInfo.space = SDN_VERIFY_SPACE+(*index);
      verifyInfo.expected = SDN_VERIFY_EXPECTED+(*index);
      verifyInfo.actual = SDN_VERIFY_ACTUAL+(*index);
      err = FwFillMem(offset, space, length, pLength, access, verify,
         &verifyInfo,data);
   }
   err2 = TFree((LPSTR)data);
   return(err?err:err2);
}

/****************************************************************************
**
**  SdFwMemSearch
**
**  Description:
**     Shared data handling routine for searching memory.  Registered on
**     SDN_SEARCH_COMMAND member.
**
*****************************************************************************/
#pragma argsused
VOID FAR PASCAL SdFwMemSearch(DESCRIPTOR desc) {
   RETCODE result;
   BOOLEAN found;
   result=FwMemSearchAction(&found);
   SdnWriteMember(SDN_SEARCH_FOUND,(U8*)&found,result);
}

#define SEARCH_BUFFER_SIZE 256

RETCODE PRIVATE FwMemSearchAction(BOOLEAN *found) {
   RETCODE err,err2;
   U32 length, pLength;
   U32 offset;
   ADDR_SPACE space;
   ACCESS_SIZE access;
   BOOLEAN not,forward;
   EMULATION_STATE runaccState;
   U32 regSave[2];

   *found = FALSE;
   if ((err = SdnReadMember(SDN_SEARCH_LENGTH,(U8*)&length)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_SEARCH_PATLENGTH,(U8*)&pLength)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_SEARCH_OFFSET,(U8*)&offset)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_SEARCH_SPACE,(U8*)&space)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_SEARCH_ACCESS,(U8*)&access)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_SEARCH_NOT,(U8*)&not)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_SEARCH_FORWARD,(U8*)&forward)) != GOOD)
      return(err);
   if ((length == 0) || (pLength == 0)) return(GOOD);
   if (pLength>SIZE_SEARCH) return(ER_MEMORY_BUFF_LEN);
   if ((access!=BYTE_SIZE) && (access!=WORD_SIZE) && (access!=DWORD_SIZE))
      return(ER_INVALID_ACCESS);

   if ((err = RunaccStart(&runaccState,regSave)) != GOOD) return(err);
   if (forward)
      err = SearchMemForward(&offset,space,length,(U16)pLength,access,not,
         SdnData(SDN_SEARCH_PATTERN), found);
   else
      err = SearchMemReverse(&offset,space,length,(U16)pLength,access,not,
         SdnData(SDN_SEARCH_PATTERN), found);
   err2 = RunaccFinish(runaccState,regSave);
   if (!err) err = err2;
   if (!err) err = SdnWriteMember(SDN_SEARCH_OFFSET,(U8*)&offset,GOOD);
   return(err);
}

/***************************************************************************
**
** SearchMemForward
** SearchMemReverse
**
**    perform memory search function
**
*****************************************************************************/
RETCODE PRIVATE SearchMemForward(U32 *offset, ADDR_SPACE space, U32 length,
      U16 pLength, ACCESS_SIZE access, BOOLEAN not,
      U8 *data, BOOLEAN *found) {
   RETCODE err;
   U16 bufferOffset, bytesInBuffer, pIndex;
   U8 buffer[SEARCH_BUFFER_SIZE];
   BOOLEAN abortFromEsc;


   *found = FALSE;
   bufferOffset = *offset;
   pIndex = 0;
   bytesInBuffer=0;
   while (1) {
      U16 readLength = min(SEARCH_BUFFER_SIZE-bytesInBuffer, (U16)length);
      if ((err = ReadMemAction(bufferOffset+bytesInBuffer, space,
         readLength, access, buffer+bytesInBuffer)) != GOOD)
         return(err);
      bytesInBuffer += readLength;
      while (pIndex+pLength <= bytesInBuffer) {
         if (not == (memcmp(buffer+pIndex, data, pLength) != 0)) {
            *found = TRUE;
            *offset = bufferOffset + pIndex;
            break;
         }
         pIndex += not ? pLength : 1;
      }
      length -= pIndex;
      if (*found || (length < pLength)) break;
      memcpy(buffer, buffer+pIndex, bytesInBuffer-pIndex);
      bytesInBuffer -= pIndex;
      bufferOffset += pIndex;
      pIndex = 0;

      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) return err;
      if (abortFromEsc!=0) return ER_SEARCH_ABORT;

   }
   return(GOOD);
}

RETCODE PRIVATE SearchMemReverse(U32 *offset, ADDR_SPACE space, U32 length,
      U16 pLength, ACCESS_SIZE access, BOOLEAN not,
      U8 *data, BOOLEAN *found) {
   RETCODE err;
   U16 bufferOffset, bytesInBuffer, pIndex;
   U8 buffer[SEARCH_BUFFER_SIZE];
   U8 *bufferEnd = buffer + SEARCH_BUFFER_SIZE;
   BOOLEAN abortFromEsc;


   *found = FALSE;
   bufferOffset = *offset+length;
   pIndex = 0;
   bytesInBuffer=0;
   while (1) {
      U16 readLength = min(SEARCH_BUFFER_SIZE-bytesInBuffer, (U16)length);
      if ((err = ReadMemAction(bufferOffset-bytesInBuffer-readLength,
         space, readLength, access, bufferEnd-bytesInBuffer-readLength))
         != GOOD) return(err);
      bytesInBuffer += readLength;
      while (pIndex+pLength <= bytesInBuffer) {
         if (not == (memcmp(bufferEnd-pIndex-pLength, data, pLength) != 0)) {
            *found = TRUE;
            *offset = bufferOffset - pIndex - 1;  /* addr of end of pattern */
            break;
         }
         pIndex += not ? pLength : 1;
      }
      length -= pIndex;
      if (*found || (length < pLength)) break;
      memcpy(buffer+pIndex, buffer, bytesInBuffer-pIndex);
      bytesInBuffer -= pIndex;
      bufferOffset -= pIndex;
      pIndex = 0;

      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) return err;
      if (abortFromEsc!=0) return ER_SEARCH_ABORT;

   }
   return(GOOD);
}

/*****************************************************************************
**
** SdFwMemCopy
**
** Registered on SD_COPY_COMMAND.
**
*****************************************************************************/
VOID EXPORT SdFwMemCopy(DESCRIPTOR desc) {
   RETCODE result;
   result=FwMemCopyAction(desc);
   SdnWriteMember(SDN_COPY_RESULTS,(U8*)&result,result);
}

#pragma argsused
RETCODE PRIVATE FwMemCopyAction(DESCRIPTOR desc) {

   RETCODE     err;
   ADDR_SPACE  srcSpace;
   ADDR_SPACE  destSpace;
   U32         srcLength;
   U8          srcTarget;       // PScope does not use target
   U8          destTarget;
   U32         srcAddrOffset;
   U32         destAddrOffset;

   U32         blkLength;      // length of this block: either MCPY_BLOCK_SIZE
                               // or what is left over


   ACCESS_SIZE access;          // bus size
   BOOLEAN     verify;          // verify writes?
   VERIFY_INFO verifyInfo;


#define MCPY_BLOCK_SIZE  128


   BOOLEAN     increasingCopy;
   U32         currentSrcOffset;
   U32         currentDestOffset;
   U32         lengthLeft;
   // buffer for copy, plus pad area
   U8          memoryBlock[ MCPY_BLOCK_SIZE + 10];
   RETCODE     retcode;
   BOOLEAN abortFromEsc;



/* get the params into local variables
 * unpack source (addr/space/target)
 */
   if((err = SdnReadMember(SDN_COPY_SRC_OFFSET, (U8 FAR *)&srcAddrOffset))
      !=GOOD) return(err);

   if((err = SdnReadMember(SDN_COPY_SRC_SPACE, (U8 FAR *)&srcSpace))
         !=GOOD) return(err);

   if((err = SdnReadMember(SDN_COPY_SRC_TARG, (U8 FAR *)&srcTarget))
       !=GOOD) return(err);

   if((err = SdnReadMember(SDN_COPY_LENGTH, (U8 FAR *)&srcLength))
       !=GOOD) return(err);


/* unpack destination (addr/space/target)  */
   if((err = SdnReadMember(SDN_COPY_DES_OFFSET, (U8 FAR *)&destAddrOffset))
       !=GOOD) return(err);

   if((err = SdnReadMember(SDN_COPY_DES_SPACE, (U8 FAR *)&destSpace))
      !=GOOD) return(err);

   if((err = SdnReadMember(SDN_COPY_DES_TARG, (U8 FAR *)&destTarget))
       !=GOOD) return(err);
/* end-unpacking  */


   if ((err = SdnReadMember(SDN_COPY_ACCESS,(U8*)&access))!=GOOD)
      return(err);

   if ((err = SdnReadMember(SDN_COPY_VERIFY,(U8*)&verify))!=GOOD)
      return(err);

   verifyInfo.offset   = SDN_COPY_VFY_OFFSET;
   verifyInfo.space    = SDN_COPY_VFY_SPACE;
   verifyInfo.expected = SDN_COPY_VFY_EXPECTED;
   verifyInfo.actual   = SDN_COPY_VFY_ACTUAL;

/* ------------------------
 *    do the copy
 * ------------------------
 *  assume linear addresses
 *  use 256 byte blocks.  Any larger size is of no use since
 *  the 8751 buffers only 256 bytes anyway.
 *
 *  check for valid space,size, length==0
 */


   if (srcLength==0) return GOOD;
   if ((access!=BYTE_SIZE) && (access!=WORD_SIZE) && (access!=DWORD_SIZE))
      return(ER_INVALID_ACCESS);

   currentSrcOffset  = srcAddrOffset;
   currentDestOffset = destAddrOffset;
   lengthLeft        = srcLength;

/* do increasing move if end of dest overlaps source
 *          ssssssssss     source
 *     ddddddddd           destination
 * do DEcreasing move if end of source overlaps destination
 *    ssssssssss           source
 *       ddddddddd         destination
 */

   if( srcAddrOffset >= destAddrOffset)   {

    // copy in forward direction
    // position pointer at start
      increasingCopy     = TRUE;
      currentSrcOffset   = srcAddrOffset;
      currentDestOffset  = destAddrOffset;
   }
   else {
   // copy backward direction.  However, "Fill" will itself write
   // in forward direction only.  We must start at BLOCK_SIZE bytes
   // before last address of range, or srcLength bytes if length
   // is smaller than the block size
      increasingCopy = FALSE;
      currentSrcOffset  = srcAddrOffset  + srcLength
                             - ( min(srcLength, (U32) MCPY_BLOCK_SIZE ));
      currentDestOffset = destAddrOffset + srcLength
                             - ( min(srcLength, (U32) MCPY_BLOCK_SIZE ));
   }

/* --------------------------------------------------------
 * copy memory until end-of-range, or user-exit via escape.
 * --------------------------------------------------------
 */

   while(lengthLeft > 0)  {

      blkLength = min(lengthLeft, (U32) MCPY_BLOCK_SIZE );

      retcode = ReadMemAction(currentSrcOffset, srcSpace,
                   blkLength, access, memoryBlock);

      if(retcode!=GOOD)
         return retcode;   // user-exit via escape?

      retcode = FillMemAction(currentDestOffset, destSpace,
                   blkLength,         //  fill length
                   blkLength,         //  pLength is same size
                   access, verify,
                   &verifyInfo, memoryBlock);

      if(retcode!=GOOD)
         return retcode;

   // determine position of next block in memory space
   // and position the pointer to the start of the block
      lengthLeft        = lengthLeft -  blkLength ;

      if(increasingCopy == TRUE )  {
          currentSrcOffset  = currentSrcOffset   +  blkLength;
          currentDestOffset = currentDestOffset  +  blkLength;
      } else {
          currentSrcOffset  = currentSrcOffset
                                - min( lengthLeft, blkLength);
          currentDestOffset = currentDestOffset
                                - min( lengthLeft, blkLength);

      }

      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) return err;
      if (abortFromEsc!=0) return ER_COPY_ABORT;

   }  // end-while

/* transferred all blocks
 *  SDN_COPY_RESULTS are posted at higher level function
 */

   return(GOOD);
}

#pragma argsused
VOID FAR PASCAL SdFwRdWrCommand(DESCRIPTOR desc) {
   RETCODE err = ER_NOT_SUPPORTED;
   SdnWriteMember(SDN_RDWR_RESULT, (U8*)&err, err);
}

VOID FAR PASCAL SdFwMemLoad(DESCRIPTOR desc) {
   LOAD_RESULT loadResult;
   MEMBER_INDEX index;
   if (SdGetMemberIndex(desc, &index) != GOOD) return;
   loadResult.serialNumber = *((U32*)SdnData(SDN_LOAD_DATA+index));
   loadResult.retcode = FwLoadAction(SdnData(SDN_LOAD_DATA+index)+sizeof(U32),
      &loadVerifyInfo[(U16)index]);
   SdnWriteMember(SDN_LOAD_RESULT+index, (U8*)&loadResult, GOOD);
}

STATIC BOOLEAN loadVerify;
STATIC ACCESS_SIZE loadSize;

VOID FAR PASCAL SdFwMemLoadCommand(DESCRIPTOR desc) {
   RETCODE err,err2;
   static EMULATION_STATE runaccState;
   static U32 regSave[2];
   U32 newSpace[2];
   LOAD_COMMAND command;
   BOOLEAN verify;
   ADDR_SPACE space;
   ACCESS_SIZE size;
   err = SdReadMember(desc, (U8*)&command);
   if (!err) err = SdnReadMember(SDN_LOAD_VERIFY, (U8*)&verify);
   if (!err) err = SdnReadMember(SDN_LOAD_SPACE, (U8*)&space);
   if (!err) err = SdnReadMember(SDN_LOAD_ACCESS, (U8*)&size);
   if (!err) switch (command) {
      case LOAD_START:
         loadVerify = verify;
         loadSize = size;
         newSpace[0] = newSpace[1] = (U32)space;
         err = RunaccStart(&runaccState,regSave);
         err2 = FwRestoreFCRegs(newSpace);   /* Set SFC/DFC to space */
         if (!err) err = err2;
         break;
      case LOAD_FINISH:
      case LOAD_ABORT:
         err = RunaccFinish(runaccState,regSave);
         break;
      default:
         err = ER_UNKNOWN_LOAD_COMMAND;
         break;
   }
   SdnWriteMemberNoCallback(SDN_LOAD_COMMAND, (U8*)&command, err);
}

RETCODE FwLoadAction(U8 *data, VERIFY_INFO *verifyInfo) {
   RETCODE err=GOOD;
   U32 currentLoadAddr=0;
   U32 loadRepeatCount=1;
   U32 pLength, length;
   BOOLEAN  abortFromEsc;


   if ((loadSize!=BYTE_SIZE) && (loadSize!=WORD_SIZE)
      && (loadSize!=DWORD_SIZE)) return(ER_INVALID_ACCESS);
   while (!err && (*data != LOAD_EOF)) {

      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) break;
      if (abortFromEsc!=0) { err = ER_LOAD_ABORT; break; }

      if (*data < LOAD_BYTE_COUNT) {  /* simple enumerated write */
         pLength = (U32)(*data++);
      } else switch (*data++) {
         case LOAD_BYTE_COUNT:
            pLength = (U32)*data++;
            break;
         case LOAD_BYTE_COUNT+1:
            pLength = (U32)*(U16*)data;
            data += 2;
            break;
         case LOAD_BYTE_COUNT+3:
            pLength = *(U32*)data;
            data += 4;
            break;
         case LOAD_REPEAT_COUNT:
            loadRepeatCount = (U32)*data++;
            continue;
         case LOAD_REPEAT_COUNT+1:
            loadRepeatCount = (U32)*(U16*)data;
            data += 2;
            continue;
         case LOAD_REPEAT_COUNT+3:
            loadRepeatCount = *(U32*)data;
            data += 4;
            continue;
         case LOAD_SET_ADDRESS:
            ((U8*)&currentLoadAddr)[0] = *data++;
            continue;
         case LOAD_SET_ADDRESS+1:
            ((U16*)&currentLoadAddr)[0] = *(U16*)data;
            data += 2;
            continue;
         case LOAD_SET_ADDRESS+3:
            currentLoadAddr = *(U32*)data;
            data += 4;
            continue;
         case LOAD_NOP:
            continue;
         case LOAD_EOF:
            continue;
         default:
            err = ER_UNKNOWN_LOAD_COMMAND;
            break;
      }
      if (err) break;
      length = pLength*loadRepeatCount;
         /* SPACE_DONT_CARE indicates to not load SFC/DFC registers */
      err = FillMemAction(currentLoadAddr, SPACE_DONT_CARE,
            length, pLength, loadSize, loadVerify, verifyInfo, data);
      currentLoadAddr += length;
      data += (U16)pLength;
      loadRepeatCount = 1;
   }
   return((err == ER_FILL_ABORT) ? ER_LOAD_ABORT : err);
}

VOID FAR PASCAL SdFwBerrRetry(DESCRIPTOR desc) {
   SdReadMember(desc, &berrRetry);
}

/*****************************************************************************
**
** Trace system dummy shared data handlers
**
*****************************************************************************/
VOID FAR PASCAL SdFwTraceBoolean(DESCRIPTOR desc) {
   BOOLEAN false=FALSE;
   SdnWriteMember(desc,(U8*)&false,GOOD);
}

#pragma argsused
VOID FAR PASCAL SdFwEnableSequencer(DESCRIPTOR desc) {
   RETCODE err=GOOD;
   SdnWriteMember(SDN_ENABLE_SEQUENCER_ACK,(U8*)&err,GOOD);
}

#pragma argsused
VOID FAR PASCAL SdFwSetTracing(DESCRIPTOR desc) {
   BOOLEAN false=FALSE;
   SdnWriteMember(SDN_FW_TRACING_STATUS,(U8*)&false,GOOD);
}

#pragma argsused
VOID FAR PASCAL SdFwTraceRead(DESCRIPTOR desc) {
   U8 data=0;
   SdnWritePartialMember(SDN_TRACE_STORE,0,1,&data,GOOD);
}

#pragma argsused
VOID FAR PASCAL SdFwConfigCS(DESCRIPTOR desc) {
   RETCODE err;
   U32 sim=0ul;
   U32 mbar;
   BOOLEAN found, simValid=FALSE;
   PROBE_TYPE probeType;
   err = SdnReadMember(SDN_PROBE_TYPE, (U8*)&probeType);
   if (!err) switch (probeType) {
         case M68330_SH: case M68340_SH:
            err = FwReadMem(0x3ff00ul, SPACE_CPU, 4, DWORD_SIZE, (U8*)&mbar);
            if (err) break;
            sim = SwapDwordOrder(mbar) & 0xfffff000ul;
            if ((SwapDwordOrder(mbar) & 1ul) == 0) {
               SdnWriteMember(SDN_SIM_VALID, (U8 *)&simValid, GOOD);
               SdnWriteMember(SDN_SIM_ADDRESS, (U8*)&sim, GOOD);
               err = GOOD;
               SdnWriteMember(SDN_CONFIG_CS_HW_RESULT, (U8*)&err, GOOD);
               return;
            }
            break;

         case M68360_SH:
            err = FwReadMem(0x3ff00ul, SPACE_CPU, 4, DWORD_SIZE, (U8*)&mbar);
            if (err) break;
            sim = SwapDwordOrder(mbar) & 0xffffe000ul;  /* note != 330,340 */
            if ((SwapDwordOrder(mbar) & 1ul) == 0) {
               err = ER_SIM_UNREADABLE;

               /* The 360 is a special case wherein the MBAR does NOT point
                  to the SIM.  Instead, the SIM is addressed 4Kbytes
                  after MBAR.  So, we add 4K to MBAR to make SIM addr */
               sim += 0x1000ul;
               SdnWriteMember(SDN_SIM_VALID, (U8 *)&simValid, GOOD);
               SdnWriteMember(SDN_SIM_ADDRESS, (U8*)&sim, GOOD);
               SdnWriteMember(SDN_CONFIG_CS_HW_RESULT, (U8*)&err, GOOD);
               return;
            }
            sim = sim + 0x1000ul;
            break;
         case M68HC16Z1_SH: case M68HC16Z2_SH: case M68HC16Y1_SH:
            sim = 0xffa00ul;
            break;
         default:
            TestForSim(sim=0xfffa00ul, &found);
            if (!found) TestForSim(sim=0x7ffa00ul, &found);
            if (!found) err = ER_SIM_UNREADABLE;
   }
   if (err == ER_SIM_UNREADABLE)
      SdnWriteMember(SDN_SIM_VALID, (U8 *)&simValid, GOOD);
   else {
      simValid = TRUE;
      SdnWriteMember(SDN_SIM_VALID, (U8 *)&simValid, GOOD);
   }
   err = SdnWriteMember(SDN_SIM_ADDRESS, (U8*)&sim, GOOD);
   SdnWriteMember(SDN_CONFIG_CS_HW_RESULT, (U8*)&err, GOOD);
}

#define M332_CSPAR1_OFFSET 0x46
RETCODE PRIVATE TestForSim(U32 addr, BOOLEAN *found) {
   RETCODE err,err2;
   U16 testValue = 0xffff;
   U16 CSPAR1;
   *found = FALSE;
   if ((err = ReadMemAction(addr+M332_CSPAR1_OFFSET, SPACE_SD, 2, WORD_SIZE,
                            (U8*)&CSPAR1)) != GOOD) return(err);
   err = FillMemAction(addr+M332_CSPAR1_OFFSET, SPACE_SD, 2, 2, WORD_SIZE,
                       FALSE, NULL, (U8*)&testValue);
   err2 = ReadMemAction(addr+M332_CSPAR1_OFFSET, SPACE_SD, 2, WORD_SIZE,
                        (U8*)&testValue);
   if (!err) err = err2;
   err2 = FillMemAction(addr+M332_CSPAR1_OFFSET, SPACE_SD, 2, 2, WORD_SIZE,
                        FALSE, NULL, (U8*)&CSPAR1);
   if (!err) err = err2;
   *found = (SwapWordOrder(testValue) == 0x03ff);
   return(err);
}

/****************************************************************************
**
**  FwBxBkptAction
**
**  Description:
**     Performs breakpoint list manipulation
**
**  Parameters:
**        none
**
**  Theory:
**     The active breakpoints are kept in a linked list of structures
**     containing appropriate information about each breakpoint.  Memory
**     is allocated in 4K chunks to minimize waste.  When memory is
**     allocated, the 4K is carved up into breakpoint structures and
**     linked into a free list.  New breakpoints are unlinked from the
**     free list, filled in, and added to the active breakpoint list.
**     Once a memory allocation has occurred, the memory is never returned.
*****************************************************************************/
#define BYTES_PER_ALLOCATION 4096
#define BKPTS_PER_ALLOCATION (BYTES_PER_ALLOCATION / sizeof(BKPT_ENTRY))

RETCODE FwBkptAction(VOID) {
   RETCODE err;
   BKPT_CMD cmd;
   BKPT_ENTRY *bkptPtr, bkpt;
   if ((err = SdnReadMember(SDN_BKPT_CMD, (U8*)&cmd)) != GOOD) return(err);
   if (cmd == BKPT_NOP) return(GOOD);
   if (cmd == BKPT_CLEAR_ALL) {
      while (bkptHead)
         if ((err = BkptDelete(bkptHead->id)) != GOOD) return(err);
      return(GOOD);
   }
   if ((err = SdnReadMember(SDN_BKPT_ID, (U8*)&bkpt.id)) != GOOD) return(err);
   if (cmd == BKPT_CLEAR) return(BkptDelete(bkpt.id));
   if ((err = SdnReadMember(SDN_BKPT_ADDR,(U8*)&bkpt.addr)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_BKPT_SPACE,(U8*)&bkpt.space)) != GOOD)
      return(err);
   bkpt.status = BKPT_UNLOADED;

   if ((bkptPtr = BkptFindById(bkpt.id)) != NULL) {     /* update existing */
      bkptPtr->addr = bkpt.addr;
      bkptPtr->space = bkpt.space;
      bkptPtr->status = bkpt.status;
   } else {                               /* breakpoint not in table...add */
      if ((err = BkptAdd(bkpt)) != GOOD) return(err);
   }
   /* test for hardware breakpoint limit exceeded */
   err = FwLoadBreakpoints(TRUE);
   (void)FwUnloadBreakpoints();

   return(err);
}

BKPT_ENTRY *BkptFindById(U16 id) {
   BKPT_ENTRY *entry;
   for (entry=bkptHead; entry; entry=entry->next) {
      if (entry->id == id) return(entry);
   }
   return(NULL);
}

BKPT_ENTRY *BkptFindByAddr(U32 addr) {
   BKPT_ENTRY *entry;
   for (entry=bkptHead; entry; entry=entry->next) {
      if (entry->addr == addr) return(entry);
   }
   return(NULL);
}

RETCODE BkptDelete(U16 id) {
   BKPT_ENTRY *entry, *preventry;
   if (!bkptHead) return(ER_BKPT_NOT_FOUND);          /* no entries in list */
   entry = bkptHead;
     /* unlink from breakpoint list */
   if (entry->id == id) {                        /* first entry in list */
      if (entry->next == NULL) bkptTail = NULL;  /* only entry in list */
      else entry->next->prev = NULL;
      bkptHead = bkptHead->next;
   }
   else for (preventry=entry, entry=entry->next ; entry ; entry=entry->next) {
      if (entry->id == id) {
         if (entry->next == NULL) bkptTail = preventry;
         else entry->next->prev = preventry;
         preventry->next = entry->next;
         break;
      }
      preventry=entry;
   }
     /* if id was found, link entry into free list */
   if (entry && (entry->id == id)) {
      entry->next = bkptFree;
      bkptFree = entry;
      return(GOOD);
   }
   return(ER_BKPT_NOT_FOUND);
}

RETCODE BkptAdd(BKPT_ENTRY bkpt) {
   BKPT_ENTRY *entry;
   LOOP_VAR i;
   if (!bkptFree) {       /* No free entries...must allocate another page */
      if ((entry = (BKPT_ENTRY *) TMalloc(BYTES_PER_ALLOCATION)) == NULL)
         return(ER_MEM);
      for (i=0; i<BKPTS_PER_ALLOCATION-1; i++) entry[i].next = &entry[i+1];
      entry[BKPTS_PER_ALLOCATION-1].next = NULL;
      bkptFree = entry;
   }
     /* unlink one entry from free list */
   entry = bkptFree;
   bkptFree = bkptFree->next;
     /* Copy new breakpoint params */
   *entry = bkpt;
     /* link new entry to breakpoint list */
   if (!bkptHead) bkptTail = entry;
   else bkptHead->prev = entry;
   entry->prev = NULL;
   entry->next = bkptHead;
   bkptHead = entry;
   return(GOOD);
}

/*****************************************************************************
**
** Probe Interface Support Functions
**
*****************************************************************************/
/*
** bdm probe packet protocol:
**
**  command                   result
**    header byte    1          header byte    1
**    command        1          errorcode      1
**    <parameters>   n          <parameters>   n   (vary according to command)
**    checksum       1          checksum       1
**
** receiver sends ACK if all bytes received and checksum is ok; otherwise
** it sends NAK, requesting a transmission retry.
*/
/*****************************************************************************
**
** FwPingProbe
**
** description:
**    Send clrstep (essentially NOP) packet to probe to see if it's alive
**
** parameters:
**    none
*****************************************************************************/
RETCODE FwPingProbe(VOID) {
   U8 cmd = PCMD_CLRSTEP;
   return(ProbeTransact(&cmd,1,NULL,0));
}

/*****************************************************************************
**
** FwReset
**
** description:
**    Reset target processor and enter BDM mode.
**
** parameters:
**    none
*****************************************************************************/
RETCODE FwReset(CPU_RESET typeOfReset) {
   RETCODE err,err2;
   EMULATION_STATE emuState;
   U8 cmd = PCMD_RESET;
   U32 sim;
   BOOLEAN simValid = FALSE;
   PROBE_TYPE probeType;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwReset(typeOfReset));

   bkptEnable = FALSE;
   SRModified = FALSE;
   err = ProbeTransact(&cmd,1,NULL,0);
   err2 = FwUnloadRegisters(TRUE);
   if (!err) err = err2;
   err2 = FwUnloadBreakpoints();
   if (!err) err = err2;
   err2 = SdnReadMember(SDN_EMULATION_STATE,(U8*)&emuState);
   if (!err) err = err2;
   if (cpuType == PROC_CPU_CPU16) sim = 0xffa00ul;
   else {
      err2 = SdnReadMember(SDN_PROBE_TYPE, (U8*)&probeType);
      if (!err) err = err2;
      switch (probeType) {
         case M68330_SH: case M68340_SH: case M68360_SH:
            err2 = SdnWriteMember(SDN_SIM_VALID,(U8*)&simValid,GOOD);
            err2 = SdnWriteMember(SDN_SIM_ADDRESS,(U8*)&sim,GOOD);
            break;
         default:
            sim = 0xfffa00ul;
            simValid = TRUE;
            err2 = SdnWriteMember(SDN_SIM_VALID,(U8*)&simValid,GOOD);
            err2 = SdnWriteMember(SDN_SIM_ADDRESS,(U8*)&sim,GOOD);
            break;
      }
      if (!err) err = err2;
   }
   if (emuState!=EM_HALTED) {       /* Update cause if we were emulating */
      BREAK_CAUSE cause = CAUSE_RESET;
      err2 = SdnWriteMember(SDN_BREAK_CAUSE,(U8*)&cause,GOOD);
      if (!err) err = err2;
   }
   if (typeOfReset==RESET_CPU_AND_UPDATE_STATUS) {
      emuState = EM_HALTED;
      err2 = SdnWriteMember(SDN_EMULATION_STATE,(U8*)&emuState,GOOD);
      if (!err) err = err2;
      err2 = SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,err);
      if (!err) err = err2;
   }
   return(err);
}

/*****************************************************************************
**
** FwCpuReset
**
** description:
**    Send reset packet to probe to reset the processor.  Does not update
**    any registers or unload breakpoints; therefore should be used only
**    during initialization.
**
** parameters:
**    none
*****************************************************************************/
RETCODE FwCpuReset(VOID) {
   U8 cmd=PCMD_RESET;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwCpuReset());

   SRModified = FALSE;
   return(ProbeTransact(&cmd,1,NULL,0));
}

/*****************************************************************************
**
** FwUpdateProbeVersion
**
** description:
**    Send version packet to probe and write results to shared data members
**
** parameters:
**    none
*****************************************************************************/
RETCODE FwUpdateProbeVersion(VOID) {
   RETCODE err;
   U8 cmd=PCMD_VERSION;
   U8 result[7];
   PROBE_TYPE probeType = PROBE_NONE;
   BDM_INFO info;
   S8 buf[64];

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwUpdateProbeVersion());

   if ((err = FwCpuReset()) != GOOD) return(err);

   if ((err = ProbeTransact(&cmd,1,result,sizeof(result)))!=GOOD) return(err);

   switch ( ((U16)result[0]<<8) ) {
      case M683XX_FAMILY:
      case CPU32PLUS_FAMILY:
      case M68000_FAMILY:
      case M68040_FAMILY:
      case I80386_FAMILY:
         break;
      default:
         return(ER_PROC_TYPE_UNKNOWN);
   }

   probeVersion = ((U32)result[4] << 16) | ((U32)result[5] << 8)
      | ((U32)result[6]);
   if (probeVersion < PROBE_VERSION_REQUIRED) return(ER_PROBE_FW_VERSION);
   if ((err = SdatSetBerrRetry(TRUE)) != GOOD) return(err);

   /* First see if user has set the hardcoded processor type in mp186.ini */
   GetPrivateProfileString(INI_SECTION_NAME, INI_PROCESSOR_TYPE, "none", buf,
      sizeof(buf), INI_FILENAME);
   /*!!! This text->ID conversion should be in proc.dll, but was put in here
   ** temporarily so that only one DLL change could be shipped to a customer */
   if (!stricmp(buf,"68330"))  { probeType=M68330_SH;    cpuType=PROC_CPU_CPU32;}
   else if (!stricmp(buf,"68331"))    { probeType=M68331_SH;    cpuType=PROC_CPU_CPU32;}
   else if (!stricmp(buf,"68332"))    { probeType=M68332_SH;    cpuType=PROC_CPU_CPU32;}
   else if (!stricmp(buf,"68333"))    { probeType=M68333_SH;    cpuType=PROC_CPU_CPU32;}
   else if (!stricmp(buf,"68F333"))   { probeType=M68333_SH;    cpuType=PROC_CPU_CPU32;}
   else if (!stricmp(buf,"68334"))    { probeType=M68334_SH;    cpuType=PROC_CPU_CPU32;}
   else if (!stricmp(buf,"68340"))    { probeType=M68340_SH;    cpuType=PROC_CPU_CPU32;}
   else if (!stricmp(buf,"68360"))    { probeType=M68360_SH;    cpuType=PROC_CPU_CPU32;}
   else if (!stricmp(buf,"68HC16Y1")) { probeType=M68HC16Y1_SH; cpuType=PROC_CPU_CPU16;}
   else if (!stricmp(buf,"68HC16Z1")) { probeType=M68HC16Z1_SH; cpuType=PROC_CPU_CPU16;}
   else if (!stricmp(buf,"68HC16Z2")) { probeType=M68HC16Z2_SH; cpuType=PROC_CPU_CPU16;}
   else {         /* No or undefined processor in ini file -> autodetect */
      /* Send cpu16 and cpu32 nop commands to determine which is present */
      info = BDM32Table[BDM_NOP];
      info.results = 1;    /* Need one result word to check for legal */
      if ((err = BDMTransact(info, NULL, CMD_NOP)) == GOOD) {
         BDMTable = BDM32Table;
         cpuType = PROC_CPU_CPU32;
      } else {
         info = BDM16Table[BDM_NOP];
         info.results = 1;
         if ((err = BDMTransact(info, NULL, CMD_NOP)) != GOOD)
            return(ER_PROC_TYPE_UNKNOWN);
         BDMTable = BDM16Table;
         cpuType = PROC_CPU_CPU16;
      }
      
      /* find out which processor is installed...tests must be in this order */
      if (cpuType == PROC_CPU_CPU16) {
         if (  !IsM68HC16Y1(&probeType)
            && !IsM68HC16Z1(&probeType)
            && !IsM68HC16Z2(&probeType)) return(ER_PROC_TYPE_UNKNOWN);
      } else {
         if (  !IsM68333(&probeType)
            && !IsM68332(&probeType)
            && !IsM68331(&probeType)
            && !IsM68340(&probeType)
            && !IsM68330(&probeType)
            && !IsM68360(&probeType)) return(ER_PROC_TYPE_UNKNOWN);
      }
   }

   FwReset(ONLY_RESET_CPU);  /* Clear possible error from above memory reads */

   /* 68360 needs probe version 2.0(2) */
   if ((probeType == M68360_SH) && (probeVersion < PROBE_VERSION_FOR_360))
      return(ER_PROBE_FW_VERSION);

   if((err=SdnWriteMember(SDN_PROBE_TYPE,(U8*)&probeType,GOOD)) != GOOD)
      return(err);
   if((err=SdnWriteMember(SDN_PROBE_MAJOR_VERSION,&result[1],GOOD)) != GOOD)
      return(err);
   if((err=SdnWriteMember(SDN_PROBE_MINOR_VERSION,&result[2],GOOD)) != GOOD)
      return(err);
   if((err=SdnWriteMember(SDN_PROBE_COMPATIBILITY,&result[3],GOOD)) != GOOD)
      return(err);
   if((err=SdnWriteMember(SDN_FIRMWARE_MAJOR_VERSION,&result[4],GOOD))!=GOOD)
      return(err);
   if((err=SdnWriteMember(SDN_FIRMWARE_MINOR_VERSION,&result[5],GOOD))!=GOOD)
      return(err);
   if((err=SdnWriteMember(SDN_FIRMWARE_BUGID,&result[6],GOOD))!=GOOD)
      return(err);
   memset(buf,0,sizeof(buf));
   if((err=SdnWriteMember(SDN_FIRMWARE_VERSTRING,(U8*)buf,GOOD))!=GOOD)
      return(err);
   *buf = 0;
   if((err=SdnWriteMember(SDN_FIRMWARE_BUILDID,(U8*)&buf[0],GOOD))!=GOOD)
      return(err);

   return(GOOD);
}

/*****************************************************************************
**
** FwLoadRegisters
**
** description:
**    Read register contents from shared data and write into chip.
**
** parameters:
**    none
*****************************************************************************/
RETCODE FwLoadRegisters(VOID) {

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwLoadRegisters());
   else if (cpuType == PROC_CPU_CPU16) return(FwLoadRegistersCpu16());
   else return(FwLoadRegistersCpu32());
}

RETCODE FwLoadRegistersCpu16(VOID) {
   RETCODE err;
   U32 reg[7];

   if ((err = SdnReadMember(SDN_PCR,(U8*)(&reg[0]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_SP, (U8*)(&reg[1]))) != GOOD) return(err);
   if ((err = BDMTransact(BDMTable[BDM16_WPCSP], NULL,
      hiword(reg[0]),loword(reg[0]),   /* PK:PC */
      hiword(reg[1]),loword(reg[1])))  /* SK:SP */
      != GOOD) return(err);

   if ((err = SdnReadMember(SDN_CCR,(U8*)(&reg[0]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_EK, (U8*)(&reg[1]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_IZ, (U8*)(&reg[2]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_IY, (U8*)(&reg[3]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_IX, (U8*)(&reg[4]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_E,  (U8*)(&reg[5]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_D,  (U8*)(&reg[6]))) != GOOD) return(err);
   if ((err = BDMTransact(BDMTable[BDM16_WDREG],NULL,
      BDM16_REG_MASK,                                 /* mask word */
      loword(reg[0]),                                 /* CCR */
      (U16)(((reg[1]&0xFL)<<12) | ((reg[4]&0xF0000L)>>8)   /* EK:XK:YK:ZK */
            | ((reg[3]&0xF0000L)>>12) | ((reg[2]&0xF0000L)>>16)),
      loword(reg[2]),loword(reg[3]),loword(reg[4]),   /* IZ, IY, IX */
      loword(reg[5]),loword(reg[6])))                 /* E, D */
      != GOOD) return(err);

   if ((err = SdnReadMember(SDN_YM, (U8*)(&reg[0]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_XM, (U8*)(&reg[1]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_SL, (U8*)(&reg[2]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_AMH,(U8*)(&reg[3]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_AML,(U8*)(&reg[4]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_IR, (U8*)(&reg[5]))) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_HR, (U8*)(&reg[6]))) != GOOD) return(err);
   if ((err = BDMTransact(BDMTable[BDM16_WRMAC], NULL,
      (U16)((reg[0] & 0xFF) | ((reg[1] & 0xFF) << 8)),         /* XM:YM */
      (U16)(((reg[2] & 0x1) << 15) | (hiword(reg[3]) & 0xF)),  /*SL:AM[35:32]*/
      loword(reg[3]),loword(reg[4]),                    /* AM31..16,AM15..0 */
      loword(reg[5]),loword(reg[6]))) != GOOD)          /* IR, HR */
      return(err);
   return(GOOD);
}

RETCODE FwLoadRegistersCpu32(VOID) {
   static U16 regWriteTable[] = {    /* BDM register write commands */
      0x2480,0x208f,0x208e,    /* pc, a7, a6 */
      0x2080,0x2081,0x2082,0x2083,0x2084,0x2085,0x2086,0x2087,   /*d0-d7*/
      0x2088,0x2089,0x208a,0x208b,0x208c,0x208d,                 /*a0-a5*/
      0x248b,0x248d,0x248c,    /* sr,ssp,usp */
      0x248e,0x248f,0x248a };    /* sfc, dfc, vbr */
   RETCODE err;
   BDM_INFO info;
   LOOP_VAR i;
   U32 reg;
   info = BDMTable[BDM32_WAREG];
   for (i=0; i<NUM_REGISTERS; i++) {
      if (i==1) continue;   /* skip A7 "register", covered by ssp/usp */
      if ((err = SdnReadMember(SDN_PC+i, (U8*)&reg)) != GOOD) return(err);
      info.command = regWriteTable[i];
      if ((err = BDMTransact(info, NULL, hiword(reg), loword(reg))) != GOOD)
         return(err);
   }
   return(GOOD);
}

/*****************************************************************************
**
** FwUnloadRegisters
**
** description:
**    Extract register contents from chip and write to shared data members
**
** parameters:
**    none
*****************************************************************************/
RETCODE FwUnloadRegisters(BOOLEAN patchPCSP) {
   RETCODE err;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwUnloadRegisters(patchPCSP));

   if ((err = StepPostamble()) != GOOD) return(err);
   if (cpuType == PROC_CPU_CPU16) return(FwUnloadRegistersCpu16());
   else return(FwUnloadRegistersCpu32(patchPCSP));
}

RETCODE FwUnloadRegistersCpu16(VOID) {
   RETCODE err;
   U16 result[7];
   U32 reg;
   U16 pk;

   if ((err = BDMTransact(BDMTable[BDM16_RPCSP],result,CMD_NOP,CMD_NOP,
      CMD_NOP,CMD_NOP)) != GOOD) return(err);
   pk = SwapWordOrder(result[0])&0xf;
   reg = (((U32)pk) << 16) | ((U32)SwapWordOrder(result[1]));   /* PK:PC */
   if ((err = SdnWriteMember(SDN_PCR,(U8*)&reg,GOOD))!=GOOD) return(err);
   reg -= 6;
   if ((err = SdnWriteMember(SDN_IP,(U8*)&reg,GOOD))!=GOOD) return(err);
   reg = (((U32)SwapWordOrder(result[2]) & 0xf) << 16)
      | ((U32)SwapWordOrder(result[3]));   /* SK:SP */
   if ((err = SdnWriteMemberNoCallback(SDN_SP, (U8*)&reg,GOOD))!=GOOD)
       return(err);

   if ((err = BDMTransact(BDMTable[BDM16_RDREG],result,BDM16_REG_MASK,CMD_NOP,
      CMD_NOP,CMD_NOP,CMD_NOP,CMD_NOP,CMD_NOP,CMD_NOP)) != GOOD) return(err);
   reg = (U32)((SwapWordOrder(result[0]) & 0xfff0) | pk);
   if ((err = SdnWriteMemberNoCallback(SDN_CCR,(U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = ((U32)SwapWordOrder(result[1]) >> 12) & 0xF;
   if ((err = SdnWriteMemberNoCallback(SDN_EK, (U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = ((U32)SwapWordOrder(result[2]))
      | (((U32)SwapWordOrder(result[1]) & 0xF  ) << 16);   /* ZK:IZ */
   if ((err = SdnWriteMemberNoCallback(SDN_IZ, (U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = ((U32)SwapWordOrder(result[3]))
      | (((U32)SwapWordOrder(result[1]) & 0xF0 ) << 12);   /* YK:IY */
   if ((err = SdnWriteMemberNoCallback(SDN_IY, (U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = ((U32)SwapWordOrder(result[4]))
      | (((U32)SwapWordOrder(result[1]) & 0xF00) << 8 );   /* XK:IX */
   if ((err = SdnWriteMemberNoCallback(SDN_IX, (U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = (U32)(SwapWordOrder(result[5]));
   if ((err = SdnWriteMemberNoCallback(SDN_E,  (U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = (U32)(SwapWordOrder(result[6]));
   if ((err = SdnWriteMemberNoCallback(SDN_D,  (U8*)&reg,GOOD))!=GOOD)
       return(err);

   if ((err = BDMTransact(BDMTable[BDM16_RDMAC],result,CMD_NOP,CMD_NOP,
      CMD_NOP,CMD_NOP,CMD_NOP,CMD_NOP)) != GOOD) return(err);
   reg = (U32)(SwapWordOrder(result[0]));
   if ((err = SdnWriteMemberNoCallback(SDN_HR, (U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = (U32)(SwapWordOrder(result[1]));
   if ((err = SdnWriteMemberNoCallback(SDN_IR, (U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = ((U32)SwapWordOrder(result[2]));
   if ((err = SdnWriteMemberNoCallback(SDN_AML,(U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = (((U32)SwapWordOrder(result[4]) & 0xF) << 16)
      | ((U32)SwapWordOrder(result[3]));
   if ((err = SdnWriteMemberNoCallback(SDN_AMH,(U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = (U32)((SwapWordOrder(result[4]) >> 15) & 1);
   if ((err = SdnWriteMemberNoCallback(SDN_SL, (U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = (U32)(SwapWordOrder(result[5]) & 0xFF);
   if ((err = SdnWriteMemberNoCallback(SDN_YM, (U8*)&reg,GOOD))!=GOOD)
       return(err);
   reg = (U32)((SwapWordOrder(result[5]) >> 8) & 0xFF);
   if ((err = SdnWriteMemberNoCallback(SDN_XM, (U8*)&reg,GOOD))!=GOOD)
       return(err);

   return(GOOD);
}

RETCODE FwUnloadRegistersCpu32(BOOLEAN patchPCSP) {
   static U16 regReadTable[] = {    /* BDM register read commands */
      0x2580,0x218f,0x218e,    /* pc,a7,a6 */
      0x2180,0x2181,0x2182,0x2183,0x2184,0x2185,0x2186,0x2187,   /*d0-d7*/
      0x2188,0x2189,0x218a,0x218b,0x218c,0x218d,                 /*a0-a5*/
      0x258b,0x258d,0x258c,    /* sr,ssp,usp */
      0x258e,0x258f,0x258a,    /* sfc, dfc, vbr */
      0x2589,0x2581 };         /* far, pcc hidden registers */
   RETCODE err;
   BDM_INFO info;
   LOOP_VAR i;
   U32 reg;
   info = BDMTable[BDM32_RAREG];
   for (i=0; i<NUM_REGISTERS_INCLUDING_HIDDEN; i++) {
      info.command = regReadTable[i];
      if ((err = BDMTransact(info,&reg,CMD_NOP,CMD_NOP)) == GOOD) {
         reg = SwapDwordOrder(reg);
         if (patchPCSP && (reg&1)) {
            switch (i) {
               case SDN_PC-SDN_PC:
                  reg=0x400;        /* Set PC to 0x400 if odd (read failed) */
                  break;
               case SDN_A7-SDN_PC:
               case SDN_SSP-SDN_PC:
                  reg=0x1000;       /* Set SP to 0x1000 if odd (read failed)*/
                  break;
            }
         }
         if ((err = SdnWriteMemberNoCallback(SDN_PC+i,(U8*)&reg,GOOD))!=GOOD)
            break;
      }
      if (err) break;
   }
   return(GOOD);
}

/*****************************************************************************
**
** FwLoadBreakpoints
**
** description:
**    Replace user opcodes at breakpoint addresses by BGND instructions
**
** parameters:
**    none
*****************************************************************************/
RETCODE FwLoadBreakpoints(BOOLEAN loadNow) {
   RETCODE err,err2;
   BKPT_ENTRY *entry;
   U8 bkptOp[2];
   BOOLEAN enable;
   U32 FCRegs[2];

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwLoadBreakpoints(loadNow));

   bkptOp[0] =  (cpuType == PROC_CPU_CPU16) ? 0x37 : 0x4a;
   bkptOp[1] =  (cpuType == PROC_CPU_CPU16) ? 0xa6 : 0xfa;
   if ((err = SdnReadMember(SDN_BKPT_ENABLE, (U8*)&enable)) != GOOD)
      return(err);
   if (enable || loadNow) {
      /*
      ** We must save the DFC and SFC since this routine could be called
      ** after registers are loaded into the chip.  The FC registers are
      ** the only ones that are trashed by the memory read/write.
      */
      if ((err = FwSaveFCRegs(FCRegs)) != GOOD) return(err);
      numXbrks = 0;
      for (entry=bkptHead; entry; entry=entry->next) {
         /* First try setting swb.  If memory not writable, use hw bkpt.*/
         err = FwReadMem(entry->addr, entry->space, 2, WORD_SIZE,
               (U8*)&entry->opcode);
         if (!err) err=FillMemAction(entry->addr, entry->space,2,2,WORD_SIZE,
               TRUE, NULL, bkptOp);
         if (!err) entry->status = BKPT_SWB;
         else {  /* Write error... */
            if (probeVersion < PROBE_VERSION_FOR_XBRKS) {
               err = ER_PROBE_VERSION_NO_XBRKS;
               break;
            }
            if (numXbrks >= MAX_XBRKS) {
               err = ER_TOO_MANY_XBRKS;
               break;
            }
            xbrkAddr[numXbrks++] = entry->addr;
            entry->status = BKPT_XBRK;
            err = GOOD;
         }
      }
      err2 = FwRestoreFCRegs(FCRegs);
      if (!err) err = err2;
      if (err) FwUnloadBreakpoints();   /* Clear any bkpts set */
   }
   return(err);
}

/*****************************************************************************
**
** FwUnloadBreakpoints
**
** description:
**    Restore user memory contents at all breakpoint addresses
**
** parameters:
**    none
*****************************************************************************/
RETCODE FwUnloadBreakpoints(VOID) {
   RETCODE err=GOOD, err2;
   BKPT_ENTRY *entry;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwUnloadBreakpoints());

   numXbrks = 0;
   for (entry=bkptTail; entry; entry=entry->prev) {
      if (entry->status == BKPT_SWB) {
         err2 = FillMemAction(entry->addr, entry->space,2,2,WORD_SIZE,FALSE,
            NULL, (U8*)&entry->opcode);
         if (!err) err = err2;
      }
      entry->status = BKPT_UNLOADED;
   }
   return(GOOD);
}

/*****************************************************************************
**
** FwPowerOn
**
** description:
**    Called when probe sends power-on byte.  This function sends either
**    a RESET command or GR command packet, depending on SD_EMULATION_STATE.
**
** parameters:
**    none
*****************************************************************************/
RETCODE FwPowerOn(VOID) {
   RETCODE err;
   EMULATION_STATE emuState;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwPowerOn());

   if ((err = SdnReadMember(SDN_EMULATION_STATE,(U8*)&emuState)) != GOOD)
      return(err);
   if (emuState == EM_HALTED) return(FwReset(RESET_CPU_AND_UPDATE_STATUS));
   else return(FwGr(&emuState));
}

/*****************************************************************************
**
** FwBkptHit
**
** description:
**    Called when the probe stops emulation.  Unloads registers into shared
**    data members, updates SD_BREAK_CAUSE, and sets SD_EMULATION_STATE.
**
** parameters:
**    byte  comm byte received from probe (one of PCOM_BKPTHIT, PCOM_STEPBKPT,
**          or PCOM_STEPFAIL).
*****************************************************************************/
RETCODE FwBkptHit(U8 comByte) {
   static BOOLEAN bkptHitInProgress=FALSE;
   RETCODE err=GOOD,err2;
   EMULATION_STATE emuState;
   BDM_INFO info = BDMTable[BDM32_RSREG];
   U8 atemp[4];
   U32 PC;
   BREAK_CAUSE cause=CAUSE_NONE;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwBkptHit());

   info.command |= SYSREG_ATEMP;
   if (bkptHitInProgress) return(GOOD);
   bkptHitInProgress=TRUE;
   switch (comByte) {
      case PCOM_STEPFAIL:
         cause = CAUSE_STEPFAIL;
         break;
      case PCOM_STEPBKPT:
         if (anticipatedCause == CAUSE_HALT) cause = CAUSE_HALT;
         else cause = CAUSE_BKPT;
         break;
      default:
         if (cpuType == PROC_CPU_CPU16) {
            U8 cmd = PCMD_CAUSE;
            U8 rawCause;
            if ((err = ProbeTransact(&cmd,1,&rawCause,1)) != GOOD) break;
            if (rawCause == RAW_CAUSE_BKPT) {    /* BKPT PIN */
               if (anticipatedCause == CAUSE_HALT) cause = CAUSE_HALT;
               else cause = CAUSE_EXTERNAL;
            } else {    /* BGND or Dbl Bus Fault...check (IP-2) for BGND */
               U16 PCSP[4];
               U32 PC;
               U16 opcode;
               if ((err = BDMTransact(BDMTable[BDM16_RPCSP],PCSP,CMD_NOP,
                  CMD_NOP,CMD_NOP,CMD_NOP)) != GOOD) break;
               PC = (((U32)SwapWordOrder(PCSP[0]) & 0xf) << 16)
                  | ((U32)SwapWordOrder(PCSP[1]));
               err = ReadMemAction(PC-8,SPACE_SP,2,2,(U8*)&opcode);
               if ((!err) && (SwapWordOrder(opcode) == 0x37A6)) {
                  cause = CAUSE_BKPT;
                  err = BDMTransact(BDMTable[BDM16_WPCSP], NULL,
                        hiword(PC-2),loword(PC-2),
                        SwapWordOrder(PCSP[2]),SwapWordOrder(PCSP[3]));
               } else {
                  err = GOOD;
                  cause = CAUSE_DOUBLE_BUS_FAULT;
               }
            }
         } else if ((err = BDMTransact(info,&atemp,CMD_NOP,CMD_NOP)) == GOOD){
            switch (atemp[3]) {   /* examine lsb(atemp) for cause of BDM */
               case 0x00:         /* BKPT PIN */
                  if (anticipatedCause==CAUSE_HALT) cause = CAUSE_HALT;
                  else cause = CAUSE_EXTERNAL;
                  break;
               case 0x01: {      /* BGND INSTRUCTION: Adjust PC back 1 word */
                  BDM_INFO infoRPC = BDMTable[BDM32_RSREG];
                  BDM_INFO infoWPC = BDMTable[BDM32_WSREG];
                  infoRPC.command |= SYSREG_RPC;
                  infoWPC.command |= SYSREG_RPC;
                  cause = CAUSE_BKPT;
                  if ((err = BDMTransact(infoRPC,&PC,CMD_NOP,CMD_NOP))==GOOD){
                     PC = SwapDwordOrder(PC);
                     PC-=2;
                     err = BDMTransact(infoWPC,NULL,hiword(PC),loword(PC));
                  }
                  break;
               }
               default: {
                  U32 ssw = atemp[1] + (atemp[0] << 8);
                  cause = CAUSE_DOUBLE_BUS_FAULT;
                  err = SdnWriteMember(SDN_SSW,(U8*)&ssw,GOOD);
                  break;
               }
            }
         }
         break;
   }
   err = SdnWriteMember(SDN_BREAK_CAUSE,(U8*)&cause,err);
   err2 = FwUnloadRegisters(FALSE);
   if (!err) err = err2;
   err2 = FwUnloadBreakpoints();
   if (!err) err = err2;
   emuState=EM_HALTED;
   err2 = SdnWriteMember(SDN_EMULATION_STATE,(U8*)&emuState,GOOD);
   if (!err) err = err2;
   err = SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,err);
   bkptHitInProgress=FALSE;
   return(err);
}

RETCODE FwStep(U32 count) {
   RETCODE err;
   U8 cmd = PCMD_SETSTEP;
   BOOLEAN  abortFromEsc;
   BREAK_CAUSE cause = CAUSE_STEP;
   BOOLEAN stepMask;
   time_t start;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwStep(count));

   bkptEnable=FALSE;
   anticipatedCause=CAUSE_NONE;

   if ((err = SdnReadMember(SDN_STEP_MASK, (U8*)&stepMask)) != GOOD)
      return(err);

   while (count--) {
      if ((err = StepPreamble()) != GOOD) return(err);
      bkptHitFlag=FALSE;
      if ((err = ProbeTransact(&cmd,1,NULL,0)) != GOOD) return(err);
      if ((err = BDMTransact(BDMTable[BDM_GO],NULL)) != GOOD) return(err);
      start = clock();
      while (!bkptHitFlag) {
         InputAvailable();
         if (clock() > start+STEP_TIMEOUT) return(ER_STEP_TIMEOUT);
      }
      if ((err = StepPostamble()) != GOOD) return(err);
      if ((err = TskCheckAbort(&abortFromEsc)) != GOOD) return(err);
      if (abortFromEsc!=0) break;

   }
   if ((err = SdnWriteMember(SDN_BREAK_CAUSE,(U8*)&cause,GOOD)) != GOOD)
      return(err);
   return(GOOD);
}

RETCODE PRIVATE StepPreamble(VOID) {
   RETCODE err;
   BOOLEAN stepMask;
   if ((err = SdnReadMember(SDN_STEP_MASK, (U8*)&stepMask)) != GOOD)
      return(err);
   if (stepMask) {
      if (cpuType == PROC_CPU_CPU16) {
         BDM_INFO info = BDMTable[BDM16_RCCR];
         U16 result;
         if ((err = BDMTransact(info,&result,0x0001,CMD_NOP)) != GOOD)
            return(err);
         SRSave = result = SwapWordOrder(result) & 0xfff0;
         result |= 0x00E0;  /* set to level 7 */
         info = BDMTable[BDM16_WCCR];
         if ((err = BDMTransact(info, NULL, 0x0001, result)) != GOOD)
            return(err);
      } else {
         BDM_INFO info;
         U32 result;
         info = BDMTable[BDM32_RSREG];
         info.command |= SYSREG_SR;
         if ((err = BDMTransact(info, &result, CMD_NOP, CMD_NOP)) != GOOD)
            return(err);
         result = SwapDwordOrder(result);
         SRSave = (U16)(result & 0xffffL);
         result |= 0x0700;
         info = BDMTable[BDM32_WSREG];
         info.command |= SYSREG_SR;
         if ((err = BDMTransact(info, NULL, hiword(result), loword(result)))
            != GOOD) return(err);
      }
      SRModified = TRUE;
   }
   return(GOOD);
}

RETCODE PRIVATE StepPostamble(VOID) {
   RETCODE err;
   if (SRModified) {
      if (cpuType == PROC_CPU_CPU16) {
         BDM_INFO info = BDMTable[BDM16_RCCR];
         U16 result;
         if ((err = BDMTransact(info,&result,0x0001,CMD_NOP)) != GOOD)
            return(err);
         result = (SwapWordOrder(result) & 0xff10) | (SRSave & 0x00e0);
         info = BDMTable[BDM16_WCCR];
         if ((err = BDMTransact(info, NULL, 0x0001, result)) != GOOD)
            return(err);
      } else {
         BDM_INFO info;
         U32 result;
         info = BDMTable[BDM32_RSREG];
         info.command |= SYSREG_SR;
         if ((err = BDMTransact(info, &result, CMD_NOP, CMD_NOP)) != GOOD)
            return(err);
         result = ((U16)SwapDwordOrder(result) & 0xf8ff) | (SRSave & 0x0700);
         info = BDMTable[BDM32_WSREG];
         info.command |= SYSREG_SR;
         if ((err = BDMTransact(info, NULL, hiword(result), loword(result)))
            != GOOD) return(err);
      }
      SRModified=FALSE;
   }
   return(GOOD);
}

RETCODE FwGo(EMULATION_STATE *emuState) {
   RETCODE err;
   U8 cmd = PCMD_CLRSTEP;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwGo(emuState));

   bkptEnable=TRUE;
   anticipatedCause=CAUSE_NONE;
   *emuState = EM_HALTED;
   if ((err = ProbeTransact(&cmd,1,NULL,0)) != GOOD) return(err);
   if (numXbrks == 0) {
      if ((err = BDMTransact(BDMTable[BDM_GO],NULL)) == GOOD)
          *emuState = EM_RUNNING;
   } else {
      U8 xcmd[MAX_XBRKS*4+1];
      U16 i;
      if ((err = StepPreamble()) != GOOD) return(err);
      xcmd[0] = (cpuType == PROC_CPU_CPU16) ? PCMD_STEP_PBRK16 : PCMD_STEP_PBRK;
      if (bdmSpeed == BDM_FAST) xcmd[0] |= PCMD_FAST_BDM;
      for (i=0;i<numXbrks ;i++) *((U32*)&xcmd[i*4+1]) = xbrkAddr[i];
      for (   ;i<MAX_XBRKS;i++) *((U32*)&xcmd[i*4+1]) = 1L;  /*odd = disabled*/
      if ((err = ProbeTransact(xcmd, MAX_XBRKS*4+1, NULL, 0)) == GOOD)
         *emuState = EM_STEPPING;
   }
   return(err);
}

RETCODE FwGr(EMULATION_STATE *emuState) {
   RETCODE err;
   U8 cmd = PCMD_GR;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwGr(emuState));

   bkptEnable=TRUE;
   anticipatedCause=CAUSE_NONE;
   *emuState = EM_HALTED;
   if (numXbrks == 0) {
      if ((err = ProbeTransact(&cmd,1,NULL,0)) == GOOD) *emuState = EM_RUNNING;
      return(err);
   } else {
      U8 cmd = PCMD_RESET;
      bkptEnable = FALSE;
      if ((err = ProbeTransact(&cmd,1,NULL,0)) != GOOD) return(err);
      bkptEnable = TRUE;
      return(FwGo(emuState));
   }
}

RETCODE FwHalt(VOID) {
   RETCODE err;
   U8 cmd = PCMD_HALT;

   if (systemType == PROC_MICEPACK) return(Sds2AbiFwHalt());

   anticipatedCause=CAUSE_HALT;
   if ((err = ProbeTransact(&cmd,1,NULL,0)) != GOOD) return(err);
   return(GOOD);
}

/**************************************************************************
**
** FwFillMem
**
**************************************************************************/
RETCODE EXPORT FwFillMem(U32 offset, ADDR_SPACE space, U32 length,
       U32 pLength, ACCESS_SIZE access, BOOLEAN verify,
       VERIFY_INFO *verifyInfo, U8 *data) {
   RETCODE err,err2;
   EMULATION_STATE runaccState;
   U32 regSave[2];


   if (systemType == PROC_MICEPACK)
      return(Sds2AbiFwFillMem(offset, space, length, pLength, access, verify, verifyInfo, data));

   if ((err = RunaccStart(&runaccState,regSave)) != GOOD) return(err);
   err = FillMemAction(offset,space,length,pLength,access,verify,verifyInfo,
      data);
   err2 = RunaccFinish(runaccState,regSave);
   return(err?err:err2);
}

RETCODE EXPORT FillMemAction(U32 offset, ADDR_SPACE space, U32 length,
       U32 pLength, ACCESS_SIZE access, BOOLEAN verify,
       VERIFY_INFO *verifyInfo, U8 *data) {
   RETCODE err;
   U8 cmd[6+PCMD_MAX_WRITE];
   U8 temp[4];
   U16 pktLength,i;
   BOOLEAN  abortFromEsc;
   U32 misalignAmount, misalignLength, patOffset;
   BDM_INFO infoDFC=BDMTable[BDM32_WSREG];

   if (systemType == PROC_MICEPACK) {
/*      if (length != pLength)  fill operation and address is cs:ip */
         offset = ((offset&0xffff0000L)<<12)+(offset&0xffffL);
      return(Sds2AbiFillMemAction(offset, space, length, pLength, access, verify, verifyInfo, data));
   }
   if (cpuType == PROC_CPU_CPU16) {
                                               /* program space is word only */
      if ((space==SPACE_SP)||(space==SPACE_UP)) access = WORD_SIZE;
      if (access == DWORD_SIZE) access = WORD_SIZE;  /* no dword in cpu16 */
      cmd[0] = PCMD_SETSIZE;
   } else {
      if (space != SPACE_DONT_CARE) {
         infoDFC.command |= SYSREG_DFC;
         if ((err = BDMTransact(infoDFC,NULL,0,(U16)space)) != GOOD)
            return(err);
      }
      cmd[0] = PCMD_SETSIZE;
   }
   cmd[1] = (U8)access;
   if ((err = ProbeTransact(cmd,2,NULL,0)) != GOOD) return(err);

   if ((probeVersion >= PROBE_VERSION_FOR_RETRY) && berrRetry) {
      if (cpuType == PROC_CPU_CPU16)
         cmd[0] = ((space==SPACE_SP)||(space==SPACE_UP)) ? PCMD_WPMEM16_RETRY
                                                         : PCMD_WDMEM16_RETRY;
      else cmd[0] = PCMD_WRITE_RETRY;
   } else {
      if (cpuType == PROC_CPU_CPU16)
         cmd[0] = ((space==SPACE_SP)||(space==SPACE_UP)) ? PCMD_WPMEM16
                                                         : PCMD_WDMEM16;
      else cmd[0] = PCMD_WRITE;
   }
   if (verify) cmd[0] |= PCMD_VERIFY;
   if (bdmSpeed == BDM_FAST) cmd[0] |= PCMD_FAST_BDM;

   /*
   ** Phase 1: If request is not aligned, read entire item, change bytes,
   **   then write entire item.
   */
   misalignAmount = offset & ((U32)access-1);
   misalignLength = min(length, access-misalignAmount);
   patOffset = 0;
   if (misalignAmount > 0) {
      if ((err = ReadMemAction(offset-misalignAmount,space,access,access,temp))
         != GOOD) goto VERIFY;
      for ( ; patOffset<misalignLength; patOffset++)
        temp[(U16)(patOffset+misalignAmount)] = data[(U16)(patOffset%pLength)];
      pktLength = (U16)access;
      *((U32*)(cmd+1)) = offset-misalignAmount;
      cmd[5] = (U8)pktLength;
      memcpy(cmd+6,temp,access);          /* put data in packet */
      if ((err = ProbeTransact(cmd,6+pktLength,NULL,0)) != GOOD) goto VERIFY;
      length -= misalignLength;
      offset += misalignLength;
   }
   if (length == 0) goto VERIFY;
   /*
   ** Phase 2: Write bulk of range, up to last item boundary
   */
   misalignAmount = length & ((U32)access-1);  /* bytes after last boundary */
   misalignLength = length - misalignAmount;
   for ( ; misalignLength>0;
         length-=pktLength, misalignLength-=pktLength, offset+=pktLength) {
      U16 cmdIndex;
      U32 fillLength = pktLength = (U16)min(PCMD_MAX_WRITE, misalignLength);
      *((U32*)(cmd+1)) = offset;
      cmd[5] = (U8)pktLength;
      for (cmdIndex=6; fillLength>0;fillLength--,patOffset++) {
         cmd[cmdIndex++] = data[(U16)(patOffset%pLength)];
      }
      if ((err = ProbeTransact(cmd,6+pktLength,NULL,0)) != GOOD) goto VERIFY;

      if (misalignLength-pktLength > 0) {
         err = TskCheckAbort(&abortFromEsc);
         if(err!=GOOD) return err;
         if (abortFromEsc!=0)
            return(ER_FILL_ABORT);
      }


   }
   if (length == 0) goto VERIFY;
   /*
   ** Phase 3: Write final item by reading entire item, changing bytes in
   **   range, then writing entire item.
   */
   if ((err = ReadMemAction(offset,space,access,access,temp)) != GOOD)
      goto VERIFY;
   for (i=0; i<length; i++,patOffset++)
      temp[i] = data[(U16)(patOffset%pLength)];
   pktLength = (U16)access;
   *((U32*)(cmd+1)) = offset;
   cmd[5] = (U8)pktLength;
   memcpy(cmd+6,temp,access);          /* put data in packet */
   if ((err = ProbeTransact(cmd,6+pktLength,NULL,0)) != GOOD) goto VERIFY;

   /*
   ** Memory Verify.  Verify is done in the probe, but if a verify error
   ** occurs, we need to get the offset, exptected, and actual info.
   */
VERIFY:
   if ((err == ER_MEMORY_VERIFY) && verify) {
      RETCODE err2;
      U8 info[3];   /* offset, expected, actual */
      cmd[0] = PCMD_GET_VERIFY;
      if ((err2 = ProbeTransact(cmd,1,info,3)) != GOOD) return(err2);
      if ((err2 = FwWriteVerifyErrorInfo(offset+info[0], space,
         (U32)info[1], (U32)info[2], verifyInfo)) != GOOD) return(err2);
   }
   return(err);
}

/**************************************************************************
**
** FwReadMem
**
**************************************************************************/
RETCODE EXPORT FwReadMem(U32 offset, ADDR_SPACE space, U32 length,
                          ACCESS_SIZE access, U8 *data) {
   RETCODE err,err2;
   EMULATION_STATE runaccState;
   U32 regSave[2];

   if (systemType == PROC_MICEPACK)
      return(Sds2AbiFwReadMem(offset, space, length, access, data));

   if ((err = RunaccStart(&runaccState,regSave)) != GOOD) return(err);
   err = ReadMemAction(offset,space,length,access,data);
   err2 = RunaccFinish(runaccState,regSave);
   return(err?err:err2);
}

RETCODE EXPORT ReadMemAction(U32 offset, ADDR_SPACE space, U32 length,
                          ACCESS_SIZE access, U8 *data) {
   RETCODE err;
   U8 cmd[6];
   U8 temp[4];
   U16 pktLength;
   U32 misalignAmount, misalignLength;

   if (systemType == PROC_MICEPACK)
      return(Sds2AbiFwReadMem(offset, space, length, access, data));

   if (cpuType == PROC_CPU_CPU16) {
                                               /* program space is word only */
      if ((space==SPACE_SP)||(space==SPACE_UP)) access = WORD_SIZE;
      if (access == DWORD_SIZE) access = WORD_SIZE;  /* no dword in cpu16 */
   } else {
      if (space != SPACE_DONT_CARE) {
         BDM_INFO infoSFC = BDMTable[BDM32_WSREG];
         infoSFC.command |= SYSREG_SFC;
         if ((err = BDMTransact(infoSFC,NULL,0,(U16)space)) != GOOD)
            return(err);
      }
   }
   cmd[0] = PCMD_SETSIZE;
   cmd[1] = (U8)access;
   if ((err = ProbeTransact(cmd,2,NULL,0)) != GOOD) return(err);

   if ((probeVersion >= PROBE_VERSION_FOR_RETRY) && berrRetry) {
      if (cpuType == PROC_CPU_CPU16)
         cmd[0] = ((space==SPACE_SP)||(space==SPACE_UP)) ? PCMD_RPMEM16_RETRY
                                                         : PCMD_RDMEM16_RETRY;
      else cmd[0] = PCMD_READ_RETRY;
   } else {
      if (cpuType == PROC_CPU_CPU16)
         cmd[0] = ((space==SPACE_SP)||(space==SPACE_UP)) ? PCMD_RPMEM16
                                                         : PCMD_RDMEM16;
      else cmd[0] = PCMD_READ;
   }
   if (bdmSpeed == BDM_FAST) cmd[0] |= PCMD_FAST_BDM;

   /*
   ** Phase 1:  If start address is not aligned to boundary, read item
   **   at next lower boundary and extract bytes in requested range.
   */
   misalignAmount = offset & ((U32)access-1);
   misalignLength = min(length, access - misalignAmount);
   if (misalignAmount > 0) {
      pktLength = (U16)access;
      *((U32*)(cmd+1)) = offset-misalignAmount;
      cmd[5] = (U8)pktLength;
      if ((err = ProbeTransact(cmd,6,temp,pktLength)) != GOOD) return(err);
      memcpy(data,temp+(U16)misalignAmount,(U16)misalignLength);
      data += (U16)misalignLength;
      offset += misalignLength;
      length -= misalignLength;
   }
   if (length == 0) return(GOOD);
   /*
   ** Phase 2: Read bulk of request, up to the last boundary in the range
   */
   misalignAmount = length & ((U32)access-1);  /* bytes after last boundary */
   misalignLength = length - misalignAmount;
   for ( ; misalignLength>0; length-=pktLength,
          misalignLength-=pktLength, data+=pktLength, offset+=pktLength) {
      pktLength = (U16)min(PCMD_MAX_READ, misalignLength);
      *((U32*)(cmd+1)) = offset;
      cmd[5] = (U8)pktLength;
      if ((err = ProbeTransact(cmd,6,data,pktLength)) != GOOD) return(err);
   }
   if (length == 0) return(GOOD);
   /*
   **  Phase 3: Finally, read item covering the last few bytes if the end
   **    address is not aligned.
   */
   pktLength = (U16)min(PCMD_MAX_READ, access);
   *((U32*)(cmd+1)) = offset;
   cmd[5] = (U8)pktLength;
   if ((err = ProbeTransact(cmd,6,temp,pktLength)) != GOOD) return(err);
   memcpy(data,temp,(U16)length);

   return(GOOD);
}

/**************************************************************************
**
** FwWriteVerifyErrorInfo
**
** Description:
**    Write shared data members corresponding to memory verify information
**
** Parameters:
**    Input:
**       offset    address of verify error
**       space     space of verify error
**       expected  data expected
**       actual    data actually read from target
**       verifyInfo which shared data members to write (or NULL if none)
**
**************************************************************************/
RETCODE EXPORT FwWriteVerifyErrorInfo(U32 offset, ADDR_SPACE space, U32 expected,
                                 U32 actual, VERIFY_INFO *verifyInfo) {
   RETCODE err;
   if (verifyInfo == NULL) return(GOOD);
   if ((err = SdnWriteMember(verifyInfo->offset, (U8*)&offset, GOOD))
      != GOOD) return(err);
   if ((err = SdnWriteMember(verifyInfo->space, (U8*)&space, GOOD))
      != GOOD) return(err);
   if ((err = SdnWriteMember(verifyInfo->expected, (U8*)&expected, GOOD))
      != GOOD) return(err);
   if ((err = SdnWriteMember(verifyInfo->actual, (U8*)&actual, GOOD))
      != GOOD) return(err);
   return(GOOD);
}

RETCODE RunaccStart(EMULATION_STATE *emuState, U32 *regs) {
   RETCODE err;
   U8 cmd = PCMD_HALT;
   err = SdnReadMember(SDN_EMULATION_STATE,(U8*)emuState);
   if ((!err) && (*emuState != EM_HALTED)) {
      bkptEnable=FALSE;
      err = ProbeTransact(&cmd,1,NULL,0);
      if ((!err) && (regs!=NULL)) err = FwSaveFCRegs(regs);
   }
   return(err);
}

RETCODE RunaccFinish(EMULATION_STATE emuState, U32 *regs) {
   RETCODE err=GOOD;
   if (emuState != EM_HALTED) {
      if (regs!=NULL) err = FwRestoreFCRegs(regs);
      if (!err) err = FwGo(&emuState);
   }
   return(err);
}

RETCODE FwSaveFCRegs(U32 *regs) {
   return(GOOD);
}

RETCODE FwRestoreFCRegs(U32 *regs) {
   return(GOOD);
}

/*****************************************************************************
**
** ProbeTransact
**
** description:
**    Send specified cmd packet to probe.  Retry until ACK received.
**    Wait for and return response packet.
**    If no header byte received, return timeout error
**    If partial bytes received or invalid checksum, send NAK and wait again
**
** parameters:
**    data      ptr to command packet data bytes to transmit to probe
**                (does not include header or checksum)
**    cmdLength number of command bytes
**    result    pointer to memory to receive data portion of result
**                (does not include header, errorcode, or checksum)
**    resLength number of bytes of data expected in data portion of result
**                (not including header, errorcode, or checksum)
**
** packet format:
**    header   1
**    command  1
**    checksum 1
**    <data...>
**
*****************************************************************************/
RETCODE ProbeTransact(U8 *data, U16 cmdLength, U8 *result, U16 resLength) {
   RETCODE err;
   U8 bytes[PCMD_MAX_LENGTH];
   U8 ackByte;
   U16 num;
   U8 sum;
   U16 retry;
   time_t start;
   /*
   ** Compute and fill in checksum
   */
   sum = bytes[0] = PCOM_HEADER;    /* header */
   sum += bytes[1] = data[0];     /* command */
   for (num=1; num<cmdLength; num++) sum += bytes[num+2] = data[num];
   bytes[2] = PCOM_CHECKSUM-sum;
   num = cmdLength+2;    /* Total number of bytes to send (incl header, sum) */

   /*
   ** Send packet to probe
   */
   for (retry=0; retry<maxCommRetry; retry++) {
      ackFlag = ACK_NONE;
      if ((err = WSComWrite(bytes, &num)) != GOOD) return(err);
      start = clock();
      while (1) {
         InputAvailable();
         if (ackFlag != ACK_NONE) break;
         if (clock() > start+ackTimeout) {
            err = ER_COMM_PACKET_TIMEOUT;
            commErrorH2BTimeout++;
            break;
         }
      }
      if (ackFlag == ACK_NAK) {
         commErrorH2BRetries++;
         if ((!err) && (retry+1 == maxCommRetry)) err=ER_COMM_RETRY_EXHAUSTED;
      } else break;
   }
   if (err) return(err);
   else commErrorH2BTotal++;

   /*
   ** Packet transmitted successfully...now wait for response
   */
   for (retry=0; retry<PCOM_MAX_RETRIES; retry++) {
      ackByte=PCOM_NAK;
      start = clock();
      sum = PCOM_HEADER;
      while (ackFlag!=ACK_HEADER) {
         InputAvailable();
         if (ackFlag == ACK_HEADER) break;
         if (clock() > start+pktTimeout) {
            commErrorB2HTimeout++;
            return(ER_COMM_PACKET_TIMEOUT);
         }
      }

      if (RcvBytes(bytes,1) != GOOD) goto SendAck; /* errorcode */
      sum+=bytes[0];
      switch (bytes[0]) {
         case PERR_GOOD:              err = GOOD; break;
         case PERR_BDM_RESET_TIMEOUT: err = ER_WAIT_BDM_TIMEOUT; break;
         case PERR_BDM_HALT_TIMEOUT:  err = ER_WAIT_EMOFF_TIMEOUT; break;
         case PERR_BDM_NOT_READY:     err = ER_BUS_TIMEOUT; break;
         case PERR_BDM_ILLEGAL:       err = ER_ILLEGAL_CMD; break;
         case PERR_BDM_BERR:          err = ER_BUS_ERROR; break;
         case PERR_BDM_RESET:         err = ER_RESET_DURING_BDM; break;
         case PERR_BDM_EMULATING:     err = ER_ILLEGAL_WHILE_EMON; break;
         case PERR_INVALID_SIZE:      err = ER_INVALID_ACCESS; break;
         case PERR_BDM_BERR_TERM:     err = ER_INTERNAL_TERMINATION; break;
         case PERR_VERIFY:            err = ER_MEMORY_VERIFY; break;
         case PERR_RESET_STUCK:       err = ER_RESET_STUCK; break;
         default:                     err = ER_INTERNAL; break;
      }
      if (err == GOOD) {               /* receive data bytes in packet */
         U16 i;
         if (RcvBytes((U8*)result,resLength) != GOOD) goto SendAck;
         for (i=0; i<resLength; i++) sum+=((U8*)result)[i];
      }
      if (RcvBytes(bytes,1) != GOOD) goto SendAck;  /* chksum */
      sum+=bytes[0];
      if (sum==PCOM_CHECKSUM) ackByte=PCOM_ACK;
      else { ackByte=PCOM_NAK; commErrorB2HGarbled++; }
SendAck:
      if (ackByte==PCOM_NAK) ackFlag=ACK_ACK; /* wait again for header */
      num=1; WSComWrite(&ackByte,&num);       /* send ack or nak to box */
      if (ackByte==PCOM_ACK) break;           /* successful reception */
      if ((!err) && (retry+1==PCOM_MAX_RETRIES)) err=ER_COMM_RETRY_EXHAUSTED;
   }
   if (!err) commErrorB2HTotal++;
   return(err);
}

/*****************************************************************************
**
** RcvBytes
**
** description:
**    Wait for specified number of bytes to arrive at serial port.
**    Times out after pktTimeout if not all bytes received.
**
** parameters:
**    data      ptr to memory to recieve data bytes
**    length    number of bytes to receive
**
*****************************************************************************/
RETCODE RcvBytes(U8 *data, U16 length) {
   U16 i,num;
   time_t start = clock();
   for (i=0; i<length; i+=num) {
      num=length-i;
      WSComRead(data+i,&num);
      if (i+num>=length) break;
      if (clock() > start+pktTimeout) {
         commErrorB2HMissing++;
         return(ER_COMM_PACKET_TIMEOUT);
      }
   }
   return(GOOD);
}

RETCODE BDMTransact(BDM_INFO info, VOID *results, ...) {
   LOOP_VAR word;
   va_list argList;
   U16 BDMbytes = 2 + 2*info.args + 2*info.results;  /* incl cmd + bdm hdr */
   U16 BDMresults = (results && info.transmit) ? (2*info.results) : 0;
   U8 packet[PCMD_MAX_BDM];
   U8 *cmdPtr = packet;
   va_start(argList,results);
   *cmdPtr++ = PCMD_BDM | ((bdmSpeed == BDM_FAST) ? PCMD_FAST_BDM : 0);
   *cmdPtr++ = (info.args<<4) + (info.results) + ((info.transmit) ? 8 : 0) ;
   *cmdPtr++ = hibyte(info.command);
   *cmdPtr++ = lobyte(info.command);
   for (word=1; word<info.args+info.results; word++) {
      U16 arg = va_arg(argList,U16);
      *cmdPtr++ = hibyte(arg);
      *cmdPtr++ = lobyte(arg);
   }
   va_end(argList);
   return(ProbeTransact(packet, BDMbytes, results, BDMresults));
}

U32 SwapDwordOrder(U32 input) {
   U32 result;
   U8 *in, *out;
   in = (U8*)&input;
   out = (U8*)&result;
   out[0] = in[3];
   out[1] = in[2];
   out[2] = in[1];
   out[3] = in[0];
   return(result);
}

U16 SwapWordOrder(U16 input) {
   U16 result;
   U8 *in, *out;
   in = (U8*)&input;
   out = (U8*)&result;
   out[0] = in[1];
   out[1] = in[0];
   return(result);
}

/**********************************************************************
**
**  IsM683xx
**
**  Determines if the processor in circuit matches the requested
**  processor name (for cpu32 processors)
**
**  returns: true if processor matches
**  probeType (out): returns  M683XX_SH
**
** theory:
**   Reset processor to get default values in registers.
**   If 68F333 ADCMCR reads as default, return 68F333.
**   If 68332 TPU MCR address reads as default, processor is 68332.
**   If 68331 GPT MCR address reads as default, processor is 68331.
**   Write 0xFFFF to MBAR. If this reads back as 0xF3FF, return 68340.
**   Write 0xFFFF to MBAR. If this reads back as 0xF1FF, return 68330.
**   Write 0xFFFF to MBAR. If this reads back as 0xE3FF, return 68360.
**   Else return unknown.
***********************************************************************/

BOOLEAN IsM68330(PROBE_TYPE *probeType) {
   U16 data = SwapWordOrder(M68330_MBAR_TEST_VAL);
   VERIFY_INFO verifyInfo;

   FwCpuReset();   /* reset processor to power up defaults */
   if (FwFillMem(M68330_MBAR_ADDR, SPACE_CPU, 2, 2, WORD_SIZE,
       FALSE, &verifyInfo, (U8 *) &data) != GOOD) return(FALSE);
   if (FwReadMem(M68330_MBAR_ADDR, SPACE_CPU, 2, WORD_SIZE,
      (U8 *) &data) != GOOD) return(FALSE);
   if (SwapWordOrder(data) == M68330_MBAR_EXP_VAL) {
      *probeType = M68330_SH;
      return(TRUE);
   } else
      return(FALSE);
}

BOOLEAN IsM68331(PROBE_TYPE *probeType) {
   U16 data;

   FwCpuReset();   /* reset processor to power up defaults */
   if (FwReadMem(M68331_GPT_ADDR, SPACE_SD, 2, WORD_SIZE,
      (U8 *) &data) != GOOD) return(FALSE);
   if (SwapWordOrder(data) == M68331_GPT_MCR_DEFAULT) {
      *probeType = M68331_SH;
      return(TRUE);
   } else
      return(FALSE);
}

BOOLEAN IsM68332(PROBE_TYPE *probeType) {
   U16 data;

   FwCpuReset();   /* reset processor to power up defaults */
   if (FwReadMem(M68332_TPU_ADDR, SPACE_SD, 2, WORD_SIZE,
      (U8 *) &data) != GOOD) return(FALSE);
   if (SwapWordOrder(data) == M68332_TPU_MCR_DEFAULT) {
      *probeType = M68332_SH;
      return(TRUE);
   } else
      return(FALSE);
}

/* taken from fwps.c, with changes to mate with this file */
BOOLEAN IsM68333(PROBE_TYPE *probeType) {
   U16 data = SwapWordOrder(M68333_ADCMCR_TEST_VAL);
   VERIFY_INFO verifyInfo;

   FwCpuReset();   /* reset processor to power up defaults */
   if (FillMemAction(M68333_ADCMCR_ADDR, SPACE_SD, 2, 2, WORD_SIZE,
                          FALSE, &verifyInfo, (U8 *) &data) != GOOD) {
      FwCpuReset();  /* clear possible unterminated bus cycle */
      return(FALSE);
   }
   if (ReadMemAction(M68333_ADCMCR_ADDR, SPACE_SD, 2, WORD_SIZE,
      (U8 *) &data) != GOOD) {
      FwCpuReset();
      return(FALSE);
   }

   if (data == SwapWordOrder(M68333_ADCMCR_EXP_VAL) ) {
      *probeType = M68333_SH;
      return(TRUE);
   } else
      return(FALSE);
}



BOOLEAN IsM68340(PROBE_TYPE *probeType) {
   U16 data= SwapWordOrder(M68340_MBAR_TEST_VAL);
   VERIFY_INFO verifyInfo;

   FwCpuReset();   /* reset processor to power up defaults */
   if (FwFillMem(M68340_MBAR_ADDR, SPACE_CPU, 2, 2, WORD_SIZE,
      FALSE, &verifyInfo, (U8 *) &data) != GOOD) return(FALSE);

   if (FwReadMem(M68340_MBAR_ADDR, SPACE_CPU, 2, WORD_SIZE,
      (U8 *) &data) != GOOD) return(FALSE);

   if (SwapWordOrder(data) != M68340_MBAR_EXP_VAL) return(FALSE);

   FwCpuReset();  /* clear last value written to MBAR */
   /* MBAR matches, now check dma INTR */
   {
      U32 data32 = SwapDwordOrder(0xffff0001L); /* set up MBAR */
      if (FwFillMem(M68340_MBAR_BASE_ADDR, SPACE_CPU, 4, 4, DWORD_SIZE,
         FALSE, &verifyInfo, (U8 *) &data32) != GOOD) return(FALSE);
   }
   data = SwapWordOrder(M68340_INTR_TEST_VAL);
   if (FwFillMem(M68340_INTR_ADDR, SPACE_SD, 2, 2, WORD_SIZE,
      FALSE, &verifyInfo, (U8 *) &data) != GOOD) return(FALSE);
   if (FwReadMem(M68340_INTR_ADDR, SPACE_SD, 2, WORD_SIZE,
      (U8 *) &data) != GOOD) return(FALSE);
   if (SwapWordOrder(data) != M68340_INTR_EXP_VAL) return(FALSE);

   *probeType = M68340_SH;
   return(TRUE);
}

BOOLEAN IsM68360(PROBE_TYPE *probeType) {
   U16 data= SwapWordOrder(M68360_MBAR_TEST_VAL);
   VERIFY_INFO verifyInfo;

   FwCpuReset();   /* reset processor to power up defaults */
   if (FwFillMem(M68360_MBAR_ADDR, SPACE_CPU, 2, 2, WORD_SIZE,
      FALSE, &verifyInfo, (U8 *) &data) != GOOD) return(FALSE);

   if (FwReadMem(M68360_MBAR_ADDR, SPACE_CPU, 2, WORD_SIZE,
      (U8 *) &data) != GOOD) return(FALSE);

   if (SwapWordOrder(data) == M68360_MBAR_EXP_VAL) {
      *probeType = M68360_SH;
      return(TRUE);
   } else
      return(FALSE);
}

/**********************************************************************
**
**  IsM68HC16xx
**
**  Determines if the processor in circuit matches the requested
**  processor name (for cpu16 processors)
**
**  returns: true if processor matches
**  probeType (out): returns  M68HC16xx_SH
**
** theory:
**   Reset processor to get default values in registers.
**   Read memory at 0xfffe00 (tpu mcr) If value is 0080, processor is hc16y1.
**   Write 0xffff to RAMBAL.  Then read back.
**   If value is 0xFC00, processor is hc16z1 (1K ram)
**   If value is 0xFE00, processor is hc16z2 (2K ram)
**   Else return unknown.
***********************************************************************/
BOOLEAN IsM68HC16Y1(PROBE_TYPE *probeType) {
   U16 data;

   FwCpuReset();   /* reset processor to power up defaults */
   if (FwReadMem(M68HC16Y1_TPU_ADDR, SPACE_SD, 2, WORD_SIZE,
      (U8 *) &data) != GOOD) return(FALSE);
   if (SwapWordOrder(data) == M68HC16Y1_TPU_MCR_DEFAULT) {
      *probeType = M68HC16Y1_SH;
      return(TRUE);
   } else
      return(FALSE);
}

BOOLEAN IsM68HC16Z1(PROBE_TYPE *probeType) {
   U16 data=SwapWordOrder(M68HC16Z1_RAMBAL_TEST_VAL);
   FwCpuReset();   /* reset processor to power up defaults */
   if (FwFillMem(M68HC16Z1_RAMBAL_ADDR, SPACE_SD, 2, 2, WORD_SIZE,
      FALSE, NULL, (U8*)&data) != GOOD) return(FALSE);
   if (FwReadMem(M68HC16Z1_RAMBAL_ADDR, SPACE_SD, 2, WORD_SIZE,
      (U8*)&data) != GOOD) return(FALSE);
   if (SwapWordOrder(data) == M68HC16Z1_RAMBAL_EXP_VAL) {
      *probeType = M68HC16Z1_SH;
      return(TRUE);
   } else
       return(FALSE);
}

BOOLEAN IsM68HC16Z2(PROBE_TYPE *probeType) {
   U16 data=SwapWordOrder(M68HC16Z1_RAMBAL_TEST_VAL);
   FwCpuReset();   /* reset processor to power up defaults */
   if (FwFillMem(M68HC16Z1_RAMBAL_ADDR, SPACE_SD, 2, 2, WORD_SIZE,
      FALSE, NULL, (U8*)&data) != GOOD) return(FALSE);
   if (FwReadMem(M68HC16Z1_RAMBAL_ADDR, SPACE_SD, 2, WORD_SIZE,
      (U8*)&data) != GOOD) return(FALSE);
   if (SwapWordOrder(data) == M68HC16Z2_RAMBAL_EXP_VAL) {
      *probeType = M68HC16Z2_SH;
      return(TRUE);
   } else
       return(FALSE);
}

/*****************************************************************************
**
** InputAvailable
**
** description:
**    InputAvailable is called regularly by a timer.  This is used in
**    PowerScope to detect power-on initialization of probe and
**    breakpoint hit events.  Other probe communications are all
**    synchronous (i.e. in response to a command packet sent by the host).
**
** parameters:
**    none
*****************************************************************************/
static InputAvailableProcessing = 0;

VOID EXPORT InputAvailable(VOID) {
 if (demoVersion) return;
 if (systemType == PROC_MICEPACK) {
   EMULATION_STATE emuState;
   if (InputAvailableProcessing) return;
   InputAvailableProcessing++;
   lmemcpy((LPSTR)(&emuState), (LPSTR)(MEMBER_DATA(SDN_EMULATION_STATE)),
   (U16)MEMBER_NUM_BYTES(SDN_EMULATION_STATE));
   if (emuState == EM_RUNNING || emuState == EM_PENDING) {
      Sds2AbiInputAvailable();
   }
   InputAvailableProcessing--;
   return;
 }
 if(systemType==PROC_POWERPACK) {
   U16 num;
   U8 commByte;
   clock_t charClock;
   static clock_t lastCharClock=0;
   static COMM_STATE commState=COMM_CMD;
   static U8 commCmd;
   static BOOL commError;
   static U16 memberIndex;
   static U16 memberOffset;
   static U16 memberLength, bytesCollected;
   static ERROR_CODE memberError;
   static U8 FAR *dataPtr;
   static U8 FAR *sdInputBuf=NULL;
   static U8 inChecksum;
   static U8 lastAck=SD_ACK;

   if ((sdInputBuf==NULL)
      && ((sdInputBuf=(U8*)TMalloc((U32)BYTES_IN_SHARED_DATA)) == NULL))
      return;

   while (1) {
      charClock = clock();
      num=1;
      WSComRead(&commByte,&num);
      /*
      ** Ignore error from WSComRead.  Communication errors are now
      ** handled at the shared data packet level transparently to the user.
      ** The number of bytes returned is valid regardless of error status.
      */
      if (num==0) {
         if ((commState!=COMM_CMD) && (charClock>lastCharClock+byteTimeout)) {
               /* timeout waiting for packet completion */
            if (WSComAckRequired()) {
               U8 ackByte = SD_NAK;
               U16 length = 1;
               commState=COMM_CMD;                    /* resync at next cmd */
               WSComWrite(&ackByte, &length);   /* send SD_NAK to box */
               lastAck = ackByte;
               commErrorB2HMissing++;
            }
         }
         break;
      }
      lastCharClock = charClock;   /* last time a character was received */
      inChecksum += commByte;
      switch (commState) {
         case COMM_CMD:
            if ((commByte == SD_WR) || (commByte == SD_WR_PART)
                || (commByte == SD_WR_GOOD) || (commByte == SD_WR_PART_GOOD)) {
               commError = FALSE;
               commCmd = commByte;
               inChecksum = commByte;
               dataPtr = (U8 FAR*)sdInputBuf;
               bytesCollected = 0;
               commState++;
            } else if ((commByte == SD_ACK) || (commByte == SD_NAK)) {
               commAckFlag = commByte;
               SdServicePacket();
            }
            break;
         case COMM_MEMBER0:
            ((U8*)&memberIndex)[0] = commByte;
            commState++;
            break;
         case COMM_MEMBER1:
            ((U8*)&memberIndex)[1] = commByte;
            if (memberIndex >= NUM_OF_SD_MEMBERS) commError=TRUE;
            switch (commCmd) {
               case SD_WR:
               case SD_WR_PART:
                  commState = COMM_ERROR0;
                  break;
               case SD_WR_GOOD:
                  commState = COMM_DATA;
                  if (!commError) memberLength = MEMBER_NUM_BYTES(memberIndex);
                  memberOffset = 0;
                  memberError = GOOD;
                  break;
               case SD_WR_PART_GOOD:
                  commState = COMM_OFFSET0;
                  memberError = GOOD;
            }
            break;
         case COMM_ERROR0:
            ((U8*)&memberError)[0] = commByte;
            commState++;
            break;
         case COMM_ERROR1:
            ((U8*)&memberError)[1] = commByte;
            commState++;
            break;
         case COMM_ERROR2:
            ((U8*)&memberError)[2] = commByte;
            commState++;
            break;
         case COMM_ERROR3:
            ((U8*)&memberError)[3] = commByte;
            if (commCmd == SD_WR) {
               commState = COMM_DATA;
               if (!commError) memberLength = MEMBER_NUM_BYTES(memberIndex);
               else memberLength = 1;
               memberOffset = 0;
            }
            else commState = COMM_OFFSET0;
            break;
         case COMM_OFFSET0:
            ((U8*)&memberOffset)[0] = commByte;
            commState++;
            break;
         case COMM_OFFSET1:
            ((U8*)&memberOffset)[1] = commByte;
            commState++;
            break;
         case COMM_LENGTH0:
            ((U8*)&memberLength)[0] = commByte;
            commState++;
            break;
         case COMM_LENGTH1:
            ((U8*)&memberLength)[1] = commByte;
            commState++;
            break;
         case COMM_DATA:
            *dataPtr++ = commByte;
            if (++bytesCollected == memberLength) commState=COMM_CHECKSUM;
            break;
         case COMM_CHECKSUM: {
            U8 ackByte = (inChecksum == commCmd) ? SD_ACK : SD_NAK;
            U16 length = 1;
            if (commError) ackByte = SD_NAK;
            commState=COMM_CMD;
            if (WSComAckRequired()) {
               WSComWrite(&ackByte, &length);
               lastAck = ackByte;
               if (ackByte==SD_NAK) {
                  commErrorB2HGarbled++;
                  break;
               }
            }
            commErrorB2HTotal++;
            if (logging) {
               U8 buf[32];
               buf[0] = commCmd;
               *((U16*)(&buf[1])) = memberIndex;
               switch (commCmd) {
                  case SD_WR:
                     *((U32*)(&buf[3])) = memberError;
                     memcpy(&buf[7],sdInputBuf,min(sizeof(buf)-7,
                                                   (U16)memberLength));
                     LogWrite(TRUE, min(sizeof(buf),memberLength+7), buf);
                     break;
                  case SD_WR_GOOD:
                     memcpy(&buf[3],sdInputBuf,min(sizeof(buf)-3,
                                                   (U16)memberLength));
                     LogWrite(TRUE, min(sizeof(buf),memberLength+3), buf);
                     break;
                  case SD_WR_PART:
                     *((U32*)(&buf[3])) = memberError;
                     *((U16*)(&buf[7])) = memberOffset;
                     *((U16*)(&buf[9])) = memberLength;
                     memcpy(&buf[11],sdInputBuf,min(sizeof(buf)-11,
                                                    (U16)memberLength));
                     LogWrite(TRUE, min(sizeof(buf),memberLength+11), buf);
                     break;
                  case SD_WR_PART_GOOD:
                     *((U16*)(&buf[3])) = memberOffset;
                     *((U16*)(&buf[5])) = memberLength;
                     memcpy(&buf[7],sdInputBuf,min(sizeof(buf)-7,
                                                    (U16)memberLength));
                     LogWrite(TRUE, min(sizeof(buf),memberLength+7), buf);
                     break;
               }
            }
            if (UpdateMemberUsingIndex(memberIndex, memberOffset,
               memberLength, (U8 FAR *)sdInputBuf, memberError, TRUE) != GOOD)
               return;
            break;
         }
      } /* end switch */
   }  /* end while */
   SdServicePacket();
   return;
 } else { /* PowerScope */
   U16 num;
   U8 byte;
   while (1) {
      num=1;
      WSComRead(&byte,&num);
      if (num==0) break;
      switch (byte) {
         case PCOM_HEADER:
            if (ackFlag==ACK_ACK) ackFlag = ACK_HEADER;
            return;
         case PCOM_ACK:     ackFlag = ACK_ACK; break;
         case PCOM_NAK:     ackFlag = ACK_NAK; break;
         case PCOM_POWERON: FwPowerOn(); break;
         case PCOM_STEPFAIL:  case PCOM_STEPBKPT:  case PCOM_BKPTHIT:
            bkptHitFlag=TRUE;
            if (bkptEnable) FwBkptHit(byte);
            break;
         default: break;
      }
   }
  }
}

/*****************************************************************************
**
** GetSystemType
**
** description:
**    Get PowerPack or PowerScope type by reading .ini file.  If not set,
**    prompt user.
**
** parameters:
**    systemType (out):  type of system (PowerPack or PowerScope)
**
*****************************************************************************/
RETCODE GetSystemType(PROC_SYSTEM_TYPE *systemType) {
#define MAX_TYPE_STRING 32
   RETCODE err;
   U8 querybyteRcvd = SD_QRY;
   U8 byteRcvd;
   BOOLEAN done=FALSE;
   /*
   **  Send out query to find out what kind of box connected and try
   **  to get response.
   */
   if((err = SdatSendBytes(1, &querybyteRcvd))!=GOOD) return(err);
   do {
      if(RcvBytes(&byteRcvd, 1)!=GOOD) {
         WSComFlush();  /* flush queue */
         /* if timeout, assume PowerScope to support backwards compatibility
            of proms... will also fail again if assumption wrong. */
         *systemType = PROC_POWERSCOPE;
         done = TRUE;
      } else {
         if(byteRcvd==PCOM_POWERON) FwPowerOn();
         if(byteRcvd==SD_PRD_POWERPACK) {
            *systemType = PROC_POWERPACK;
            done = TRUE;
         }
         if(byteRcvd==SD_PRD_POWERSCOPE) {
            *systemType = PROC_POWERSCOPE;
            done = TRUE;
         }
      }
   } while(!done);
   return(GOOD);
}

VOID LogWrite(BOOLEAN fw, U16 n, U8 *bytes) {
   FILE *fp;
   if (!logging) return;
   if ((fp = fopen(logFileName,"a")) == NULL) return;
   fprintf(fp, fw ? "  fw: " : "host: ");
   fprintf(fp,"%02X %-20.20s ",bytes[0],
      MEMBER_NAME(*((U16*)(&bytes[1]))));
   switch (bytes[0]) {
      case SD_WR_PART:
         fprintf(fp,"%08lX %04X %04X ",*((U32*)(&bytes[3])),
                 *((U16*)(&bytes[7])),*((U32*)(&bytes[9])));
         n -= 11;
         bytes += 11;
         break;
      case SD_WR:
         fprintf(fp,"%08lX ",*((U32*)(&bytes[3])));
         n -= 7;
         bytes += 7;
         break;
      case SD_WR_GOOD:
         n -= 3;
         bytes += 3;
         break;
      case SD_WR_PART_GOOD:
         fprintf(fp," %04X %04X ",
                 *((U16*)(&bytes[3])),*((U32*)(&bytes[5])));
         n -= 7;
         bytes += 7;
         break;
   }
   while (n--) fprintf(fp,"%02X ",*bytes++);
   fprintf(fp,"\n");
   fclose(fp);
}

RETCODE SdatGetSdLog(BOOLEAN *log, LPSTR *filename) {
   *log = logging;
   *filename = logFileName;
   return(GOOD);
}

RETCODE SdatSetSdLog(BOOLEAN log, LPSTR filename) {
   RETCODE err=GOOD;
   FILE *fp;
   strncpy(logFileName,filename,sizeof(logFileName));
   if ((fp = fopen(logFileName,"a")) == NULL) err = ER_SDS_LOGFILE_OPEN;
   if (!err) {
      time_t t=time(NULL);
      if (!logging && log)
         fprintf(fp,"---------------- logfile opened %s",ctime(&t));
      else if (logging && !log)
         fprintf(fp,"---------------- logfile closed %s",ctime(&t));
      fclose(fp);
   }
   logging = log;
   return(err);
}

RETCODE SdatGetBdmSpeed(BDM_SPEED *speed) {
   *speed = bdmSpeed;
   return(GOOD);
}

RETCODE SdatSetBdmSpeed(BDM_SPEED speed) {
   bdmSpeed = speed;
   WritePrivateProfileString(INI_SECTION_NAME, INI_BDM_SPEED,
      (bdmSpeed == BDM_FAST) ? "fast" : "slow", INI_FILENAME);
   return(SdnWriteMember(SDN_BDM_SPEED, (U8*)&bdmSpeed, GOOD));
}

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