/****************************************************************************
**
**  Name:  memcli.c
**
**  Description:
**     This is the memory server code of the Thunderbird.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_68k/mem/memcli.c_v  $
** 
**    Rev 1.3   11 Dec 1997 09:31:08   hera
** 
**    Rev 1.2   10 Dec 1997 13:29:24   hera
** for test report ID:129
** 
**    Rev 1.1   18 Mar 1997 10:09:26   gene
** 
**    Rev 1.0   13 Feb 1997 08:54:54   gene
** Initial revision.
** 
**    Rev 1.13   11 Jan 1996 09:44:30   kevin
** modified memcliramtst()
** 
**    Rev 1.12   08 Dec 1995 11:06:34   kevin
** modify keywordcheck()   strncmpi -> stricmp
** 
**    Rev 1.11   22 Nov 1995 16:36:38   kevin
** gene's modification
** 
**    Rev 1.10   17 Nov 1995 14:44:46   kevin
** changed MCE16A to MCE16B
** 
**    Rev 1.9   16 Nov 1995 11:30:12   kevin
** added notification
** 
**    Rev 1.8   15 Nov 1995 15:00:54   kevin
** modify selftest 
** 
**    Rev 1.7   13 Oct 1995 15:11:04   kevin
** added notifications into ramtest()
** 
**    Rev 1.6   22 Sep 1995 17:26:22   kevin
** delete cpu space KeywordCheck
** 
**    Rev 1.5   22 Sep 1995 11:14:58   gene
** added checksum() space and compare
** 
**    Rev 1.2   15 Sep 1995 14:50:58   gene
** added selftest
** 
**    Rev 1.1   14 Sep 1995 16:23:00   kevin
** added checksum
** 
**    Rev 1.0   07 Sep 1995 09:13:56   gene
** Initial revision.
** 
**    Rev 1.43   02 May 1994 10:45:18   marilyn
** Fixed ppr 9304, uninitialized addrSpace in fill and search routines.
** 
**    Rev 1.42   16 Jul 1993 11:53:38   ernie
** Removed error.h include.  All errors now in errcodec.h
** 
**    Rev 1.41   14 Jul 1993 16:27:36   tom
** PPR 8278: Dump with backwards addresses now dumps from smaller to larger.
** 
**    Rev 1.40   13 Jul 1993 07:07:22   doug
** Use generic syntax error.
** 
**    Rev 1.39   25 Jun 1993 17:27:48   paul
** Change CHECK_ABORT to TskCheckAbort
** 
**    Rev 1.38   25 May 1993 11:54:40   ernie
** Changed interface to MemRead()
** 
**    Rev 1.37   17 Mar 1993 13:18:48   john
** Checked in memory space changes for Mindy
** 
**    Rev 1.36   06 Jan 1993 11:32:28   ernie
** Implemented cli data size for write, fill, and search
** 
**    Rev 1.35   15 Dec 1992 13:32:00   ernie
** Removed code for write word now that access size support is implemented.
** 
**    Rev 1.34   02 Dec 1992 10:23:56   john
** added error message for word size transfers
** 
**    Rev 1.33   03 Nov 1992 11:08:28   john
** fixed memory cleanup bug
** 
**    Rev 1.32   22 Oct 1992 15:01:10   john
** fixed address display for cli dump command
** 
**    Rev 1.31   20 Oct 1992 11:00:40   john
** moved report verify error to memory.c to provide a more generic
** method of reporting the error.  This allows presenters as well as
** servers to display the data to the user.
** 
**    Rev 1.30   16 Oct 1992 17:07:04   john
** backed out previous changes
** 
**    Rev 1.29   06 Oct 1992 12:52:52   john
** Changed the pattern buffer to a TMalloc'd buffer.  This was done
** because memfill may or may not call memwrite.  Memwrite expects a
** tmalloc'd buffer to free after the successful write.  Memfill frees a
** tmalloc'd buffer like memwrite.
** 
**    Rev 1.28   18 Sep 1992 09:18:38   john
** added code to make writemem use word size bus accesses
** 
**    Rev 1.27   16 Sep 1992 10:44:18   john
** Added word write command
** 
**    Rev 1.26   14 Sep 1992 15:34:56   john
** Added a verify error printout.
** Fixed address/memory descriptor leaks.
** Changed cli write to alloc memory sent to memwrite.  (as spec'd)
** 
**    Rev 1.25   08 Sep 1992 12:06:26   john
** added memory verify printout (untested)
** 
**    Rev 1.24   03 Sep 1992 13:10:50   brucea
** Fixed: max argument bug in MemCliFillMemory
**        Added CLEANUP code
** 
** 
**    Rev 1.23   19 Aug 1992 18:52:20   brucea
** Removed: check for error from SendMessage since it doesn't return one
** 
**    Rev 1.22   18 Aug 1992 18:56:48   brucea
** Changed: AdrConvAddressToText to ...WithParams
** 
**    Rev 1.21   17 Aug 1992 16:43:28   brucea
** Changed: wsprintf to sprintf
** Removed compiler warnings
** 
**    Rev 1.20   08 Aug 1992 11:17:02   tom
** New CLI registration
** 
**    Rev 1.19   03 Aug 1992 06:33:00   mindy
** default to SD if no address space given
** 
**    Rev 1.18   28 Jul 1992 19:47:58   brucea
** Removed: variables no longer in use
** Cast vars which report (from compiler) a potential loss of significance
** 
**    Rev 1.17   22 Jul 1992 16:10:16   doug
** a) added verify command
** b) size with no parameters now displays current setting
** 
**    Rev 1.16   21 Jul 1992 11:57:04   brucea
** Added: #include "proc.h" and modified processor-dependent calls to include
**    an if() to test for processor first
** 
**    Rev 1.15   15 Jun 1992 09:45:40   brucea
** Rewrote: MemCliDumpMemory to support byte, word, long, dword parameter which
**    displays the output in those memory sizes
** 
**    Rev 1.14   20 May 1992 11:29:44   mindy
** initCServer needs to return GOOD if no errors
** 
**    Rev 1.13   15 May 1992 15:38:50   brucea
** Removed: local macro defines
** Cleaned: SendCliMessage error generation
** 
** 
**    Rev 1.12   12 May 1992 19:23:38   brucea
** Fixed: ppr5477 bug in MemCliDumpMemory
** Added: MemCliSetMemSize to set probe memory write size to byte, word, or long
** 
**    Rev 1.11   17 Mar 1992 09:56:30   brucea
** Fixed: MemCliSearchMemory bug in which access to an address descriptor
**    occurred after it was destroyed.
** 
**    Rev 1.10   06 Mar 1992 09:39:42   doug
** added memory search
** 
**    Rev 1.9   03 Mar 1992 10:21:52   doug
** destroy the address descriptor after using
** 
**    Rev 1.8   02 Mar 1992 17:54:10   doug
** memory is returned in buff... use that to get data!
** 
**    Rev 1.7   28 Feb 1992 15:02:14   doug
** a) changed names to match .res
** b) use strtoul instead of sscanf
** 
**    Rev 1.6   28 Feb 1992 11:57:16   doug
** need prototype for freeing memory
** 
**    Rev 1.5   28 Feb 1992 11:23:34   doug
** typo on line length; there are only 3 commands
** 
**    Rev 1.4   28 Feb 1992 11:22:24   doug
** simple read, write, and fill
** 
**    Rev 1.3   14 Feb 1992 12:47:10   doug
** a) ifdef'ed out debug statements
** b) fixed boundary error on byte check
** 
**    Rev 1.2   24 Jan 1992 17:48:26   doug
** Fixed cli interface desc.
** 
**    Rev 1.1   23 Jan 1992 16:22:18   doug
** a) new error numbers
** b) new output for CLI
** c) check for maximum fill length
** 
**    Rev 1.0   14 Jan 1992 13:49:46   tom
** Initial revision.
**
**  $Header:   S:/tbird/mt2_68k/mem/memcli.c_v   1.3   11 Dec 1997 09:31:08   hera  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

#ifndef _ADDR_
#include "addr.h"
#endif

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

#ifndef _CLISRV_
#include "clisrv.h"
#endif

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

#ifndef _MEMCLI_
#include "memcli.h"
#endif

#ifndef _MEMLOCAL_
#include "memlocal.h"
#endif

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

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

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

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

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

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

#ifndef __STDLIB_H
#include "stdlib.h"
#endif

#ifndef __STDIO_H
#include "stdio.h"
#endif

#ifndef __STRING_H
#include "string.h"
#endif

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

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

#ifndef  _SD_ABI_DEF_
#include "..\abi68k\sdabidef.h"
#endif

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

HANDLE cliServerHandle = (HANDLE)NULL;  /* force definition here */
STATIC ADDR_SPACE addrSpace;
STATIC ACCESS_SIZE dataSize;
STATIC BOOLEAN sizeKeyword;
STATIC BOOLEAN spaceKeyword;

#define LINE_LENGTH 16 /* number of bytes on a display line */

#define BYTE_TEXT "byte"
#define WORD_TEXT "word"
#define LONG_TEXT "long"
#define DWORD_TEXT "dword"
#define UNKNOWN_TEXT "unknown"
#define ON_TEXT "on"
#define OFF_TEXT "off"
//#define CPU_TEXT "cpu"
#define UD_TEXT "ud"
#define UP_TEXT "up"
#define SD_TEXT "sd"
#define SP_TEXT "sp"

#define SPACE_BUF_SIZE 4
#define VERIFY_ERROR_TEXT_SIZE 41

typedef union {
   U32  U32Val;
   U16  U16Val[2];
   U8   U8Val[4];
} DATA_UNION;

extern DESCRIPTOR srcRange0, srcRange1;

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

BOOLEAN PRIVATE KeywordCheck(LPSTR str);
VOID DiagnosticMTAT2(U16 diagStatus);
RETCODE SendCliMessageNo(HANDLE cliHandle, LPSTR msgPtr);

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

RETCODE SendCliMessage(HANDLE cliHandle, LPSTR msgPtr) {

   HANDLE               msgBufHandle;
   CSERVER_RESULTS FAR  *msgBufPtr;
   U16                  msgTextSize, loop ;

   msgTextSize = lstrlen(msgPtr);
   if ((msgBufHandle =
      GlobalAlloc(GMEM_MOVEABLE,
                  (sizeof(CSERVER_RESULTS) + msgTextSize + 2)))
      == (HANDLE)NULL) {
      return(ER_OUT_OF_MEMORY);
   }
   else if((msgBufPtr=(CSERVER_RESULTS *)GlobalLock(msgBufHandle)) == NULL) {
      GlobalFree(msgBufHandle);
      return(ER_WINDOWS_MEMLOCK);
   }
   msgBufPtr->target               = 0;    /*@@ CLI: not yet def'ed @@*/
   msgBufPtr->variantCode          = CLI_SERVER_RESULTS;
   msgBufPtr->resultTextLength     = msgTextSize; /* message string length */
   for (loop = 0; loop < msgTextSize; loop++ ) {
      msgBufPtr->messageText[loop]  =  *msgPtr++;
   }
   msgBufPtr->messageText[msgTextSize+1] = 0 ;

   SendMessage(cliHandle, CLI_SERVER_RESULTS,
               msgBufHandle, CLI_SERVER_RESULTS);
   return GOOD;
}

/**************************************************************************
**
** InitCServer
**
** Description: Initialize the commands for the Memory Server.
**
** Parameters:
**    input:
**       cliHandle:  CLI Server Handle
**       dllHandle:  DLL Handle.
**
**    output:
**       return a 1 to indicate success
**
***************************************************************************/
RETCODE EXPORT
InitCServer(HANDLE cliHandle, HANDLE dllHandle) {

   CSERVER_NEW_REGISTRATION FAR *msgBufPtr;

   cliServerHandle = cliHandle;
   msgBufPtr =
      (CSERVER_NEW_REGISTRATION FAR *)TMalloc(sizeof(CSERVER_VARIABLE_VALUE));
   if (msgBufPtr == NULL) {
      return(ER_OUT_OF_MEMORY);
   }
   msgBufPtr->stringResourceHandle = dllHandle;

   msgBufPtr->serverNameIndex = 30;
   msgBufPtr->dllNameIndex = 31;
   msgBufPtr->numberOfCommandsIndex = 32;
   msgBufPtr->commandStartIndex = 33;
   SendMessage(cliHandle, CLI_NEW_SVR_REGISTRATION, CLI_NEW_SVR_REGISTRATION,
      (DWORD)msgBufPtr);
   TFree((LPSTR)msgBufPtr);
   return(GOOD);
}

/***************************************************************************
**
** MemCliDumpMemory
**
** Description:
**    Cli interface to the read (dump) memory content
**
** Syntax:
**    mem_dump addr1 [addr2] [BYTE|WORD|LONG|DWORD]
**
** Input:
**    cmdString
**    argc
**    argv
**
** Output: no parameters
**
*****************************************************************************/
RETCODE EXPORT MemCliDumpMemory(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE    err;
   RETCODE    firstErr = GOOD;
   U32        bytesLeft;
   DESCRIPTOR addr1Desc, addr2Desc;
   U32        bytesToEnd;
   BOOLEAN    firstAddrFound=FALSE;
   PROCESSOR_FAMILY procFamily;
   LOOP_VAR   args;
   BOOLEAN    abortFromEsc;



   if ((argc < 2) || (argc > 5))
      return(ER_CLI_SYNTAX);

   /* !!! this should be replaced with a call to the map server to get
      the type of memory at the address requested.  How should it handle
      large dumps where the map size may change within the request??? */
   dataSize = WORD_SIZE;  /* set default memory display type */
   addrSpace = SPACE_SD;
   
   /* remove processor dependency */
   if (GOOD != (err = ProcReturnProcFamily(&procFamily))) return err;
   if((err = AdrCreateAddress(&addr1Desc))!=GOOD) return(err);
   if (GOOD != (err = AdrCreateAddress(&addr2Desc))) {
      AdrDestroyAddress(addr1Desc);
      return err;
   }

   for( args = 1; args < argc; args++ ) {
      if( !KeywordCheck(&(cmdString[(U16)argv[args]])) ) {
        DESCRIPTOR *adrDesc;
         if( firstAddrFound == FALSE ) adrDesc = &addr1Desc;
         else adrDesc = &addr2Desc;
         firstAddrFound++;
         if((err=AdrConvTextToAddress(*adrDesc,&cmdString[(U16)argv[args]]))
            != GOOD) goto CLEANUP_1;
      }
   }
   /* set up default size of dump */
   bytesLeft = LINE_LENGTH;
   if( firstAddrFound == 0 ) {
      err = ER_CLI_SYNTAX;
      goto CLEANUP_1;
   }
   if((err=AdrSetAddrSpace(addr1Desc, addrSpace))!=GOOD) goto CLEANUP_1;
   if( firstAddrFound == 2 ) {
      ADDR_COMPARE addrCompareResult;
      if((err=AdrSetAddrSpace(addr2Desc, addrSpace))!=GOOD) goto CLEANUP_1;
      /* extract difference between two addresses */
      if(GOOD!=(err=AdrRangeOfAddresses(addr1Desc,addr2Desc,&bytesLeft)))
         goto CLEANUP_1;
      /* now put the smallest address in addr1Desc */
      if((err=AdrCompareAddresses(addr1Desc,addr2Desc,&addrCompareResult))
         != GOOD ) goto CLEANUP_1;

      if (FIRST_ADDR_GREATER == addrCompareResult) {
         /* switch the two values while preserving them */
         DESCRIPTOR addrTempDesc;

         addrTempDesc = addr2Desc;
         addr2Desc = addr1Desc;
         addr1Desc = addrTempDesc;
      }
   }
   /* adjust number of bytes to make even with the requested type (size) */
   switch (dataSize) {
      case WORD_SIZE:
         if (bytesLeft & 0x1L)  /* if odd, increment */
            bytesLeft++;
         break;
   
      case DWORD_SIZE:
         if (bytesLeft & 0x3L)  {
            /* round up to even 4 */
            bytesLeft = (bytesLeft & 0xFFFFFFFCL) + 4L;
         }
   }
   if (0L == bytesLeft)  /* only occurs if entering large address range */
      bytesLeft = 0xFFFFFFFFL;
   /* correct for size of remaining memory when close to the end of memory */
   if (GOOD != (err = AdrRemainingBytes(addr1Desc, &bytesToEnd)))
      goto CLEANUP_1;
   if (0L == bytesToEnd) { /* 0 means largest value; convert */
      bytesToEnd = 0xFFFFFFFFL;
   }
   bytesLeft = min(bytesLeft, bytesToEnd);

  /* clear any ESC previously hit */
   err = TskCheckAbort(&abortFromEsc);
   if(err!=GOOD) goto CLEANUP_1;



   while (TRUE) {
      LPU8 buff;
      S8   outputBuff[(LINE_LENGTH * 3) + 15];  /* few extra for safety */
      U16  blockSize;
      U16  i;
      LPSTR strPtr, tmpPtr;
      U8   ch;
      DATA_UNION dataUnion;

      blockSize = min(bytesLeft, LINE_LENGTH);

      /* MemRead TMallocs buff */
      if((err = MemRead(addr1Desc, blockSize, &buff,CACHE_BYPASS))!=GOOD) {
         TFree((LPSTR)buff);
         goto CLEANUP_1;
      }

      /* !!! what about displaying address space in address now??*/
      if((err = AdrConvAddressToTextWithParams(addr1Desc,
                                               TRUE,
                                               TRUE,
                                               outputBuff))!=GOOD) {
         TFree((LPSTR)buff);
         goto CLEANUP_1;
      }
      /* find end */
      strPtr = outputBuff;
      while (*strPtr)
         strPtr++;
      /* now points to null termination */
      /* insert 2 spaces */
      *strPtr++ = ' ';
      *strPtr++ = ' ';

      dataUnion.U32Val = 0L;
      for(i=0; i<blockSize; ) {
         S8 text[10];
         U8 diff;
         diff = blockSize - i;
         
         if (diff < 4) {  /* only one compare for common case */
            if (diff < 2) {
               dataSize = BYTE_SIZE;
            } else {
               if (DWORD_SIZE == dataSize)   /* only switch if was in long */
                  dataSize = WORD_SIZE;
            }
         }
         /* convert byte(s) to ascii */
         switch (dataSize) {
            case BYTE_SIZE:
               sprintf(text, "%02hX ", buff[i++]);
               break;

            case WORD_SIZE:
               dataUnion.U8Val[3] = buff[i++];
               dataUnion.U8Val[2] = buff[i++];
               sprintf(text, "%04X ", dataUnion.U16Val[1]); 
               break;
   
            case DWORD_SIZE:
               dataUnion.U8Val[3] = buff[i++];
               dataUnion.U8Val[2] = buff[i++];
               dataUnion.U8Val[1] = buff[i++];
               dataUnion.U8Val[0] = buff[i++];
               sprintf(text, "%08lX ", dataUnion.U32Val); 
               break;
         }
         /* copy to output buffer */
         tmpPtr = text;
         while ((ch = *tmpPtr++) > '\0') {
            *strPtr++ = ch;
         }
      } /* end of for */
      /* terminate with null */
      *strPtr = '\0';

      SendCliMessage(cliServerHandle, (LPSTR)outputBuff);
      if((TFree((LPSTR)buff))!=GOOD)
         goto CLEANUP_1;

      if (bytesLeft > blockSize) {
         bytesLeft -= blockSize;
      } else {
         break;  /* exit while loop when no more data to output */
      }
      if((err = AdrAddToAddress(addr1Desc, (U32)blockSize))!=GOOD)
         goto CLEANUP_1;

      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) goto CLEANUP_1;
      if (abortFromEsc!=0) {
         err = ER_ABORT_FROM_ESC;
         goto CLEANUP_1;
      }
   }  /* end of while (TRUE) */

CLEANUP_1:
   firstErr = err;
   err = AdrDestroyAddress(addr2Desc);

CLEANUP_2:
   if (!firstErr) firstErr = err;
   err = AdrDestroyAddress(addr1Desc);
   if (!firstErr) firstErr = err;
   return firstErr;
}  /* end of MemCliDumpMemory */


/***************************************************************************
**
**  MemCliWriteMemory
**
**  Status:  PRELIMINARY
**
**  description:
**     Cli interface to the write memory content
**
**  input:
**     <none>
**
**  output:
**     message:
**     <none> :
**
*****************************************************************************/
RETCODE EXPORT MemCliWriteMemory(LPSTR cmdString, U32 argc, U32 argv[]) {
   U16         patLength = 0;
   RETCODE     err,writeErr;
   U32         tempData,tempAddr;
   DESCRIPTOR  desc;
   U16         i,byte;
   U8          *pattern;
   char        *endptr;

   if(argc < 2) return(ER_CLI_SYNTAX);
   if(argc > MAX_CLI_FILL_LENGTH+2) return(ER_MEM_PAT_LEN);

   /* get fill start addr with argv 2 */
   if((err = AdrCreateAddress(&desc))!=GOOD) return(err);
   if((err=AdrConvTextToAddress(desc,&cmdString[(U16)argv[1]])) != GOOD){
      AdrDestroyAddress(desc);
      return(err);
   }
   
   /* malloc a block of memory for memwrite to free */
   pattern =(U8 *) TMalloc(MAX_CLI_FILL_LENGTH);
   if (pattern == NULL) return(ER_OUT_OF_MEMORY);
   dataSize = BYTE_SIZE;
   addrSpace = SPACE_SD;

   /* last tokens in cmd line are for data size specifier and addr space */
   while( KeywordCheck(&cmdString[(U16)argv[(U16)argc-1]]) ) argc--;
   if((err=AdrSetAddrSpace(desc, addrSpace))!=GOOD) {
      AdrDestroyAddress(desc);
      TFree((LPSTR) pattern);
      return(err);
   }
   
   for (i = 2; i < argc; i++) { /* get data into pattern array */
      tempData = strtoul(&cmdString[(U16)argv[i]], &endptr, 0);
      if(*endptr!='\0') {
         AdrDestroyAddress(desc);
         TFree( (LPSTR) pattern);
         return(ER_CLI_SYNTAX);
      }
      if(((dataSize == BYTE_SIZE) && (tempData >= 0x100L))
           || ((dataSize == WORD_SIZE) && (tempData >= 0x10000L))) {
         AdrDestroyAddress(desc);
         TFree((LPSTR) pattern);
         return((dataSize==BYTE_SIZE) ? ER_MEM_DATA_GREATER_THAN_BYTE
                                      : ER_MEM_DATA_GREATER_THAN_WORD);
      }
      for (byte=0; byte<dataSize; byte++)
         pattern[patLength++] = ((U8*)&tempData)[dataSize-byte-1];
   }
   writeErr = MemWrite(desc, patLength, (LPU8)pattern);
   /* destroy the address descriptor regardless
      of the success/failure of the memwrite call */
   if((err = AdrDestroyAddress(desc))!=GOOD) return(err);
   
   if (!writeErr)
      SendCliMessage(cliServerHandle, (LPSTR)"Write successful.");

   return(writeErr);
}

/***************************************************************************
**
**  MemCliFillMem
**
**  Status:  PRELIMINARY
**
**  description:
**     Cli interface to the fill memory content
**     Syntax: fill <address> <address> <data>...
**
**  input:
**     standard command input parameters
**
**  output:
**     <none> :
**
*****************************************************************************/
RETCODE EXPORT MemCliFillMemory(LPSTR cmdString, U32 argc, U32 argv[]) {
   U16        patLength = 0;
   RETCODE    firstErr, err;
   U32        tempData;
   DESCRIPTOR desc1, desc2;
   ADDR_COMPARE result;
   U16        i,byte;
   U32        fillLength;
   U8         pattern[MAX_CLI_FILL_LENGTH];
   char       *endptr;

   dataSize = BYTE_SIZE;
   addrSpace = SPACE_SD;

   if(argc < 4) return(ER_CLI_SYNTAX);
   if(argc > MAX_CLI_FILL_LENGTH+3)
      return(ER_MEM_PAT_LEN);

   if((err = AdrCreateAddress(&desc1))!=GOOD) return(err);
   if((err = AdrCreateAddress(&desc2))!=GOOD) {
      err = AdrDestroyAddress(desc1);
      return(err);
   }
   /* get starting address into offset of addr desc. */
   if((err=AdrConvTextToAddress(desc1,&cmdString[(U16)argv[1]])) != GOOD)
      goto CLEANUP;

   /* decode ending address - want to use address conv routines
      to get address's value since we want to support symbolics here too */
   if((err=AdrConvTextToAddress(desc2,&cmdString[(U16)argv[2]])) != GOOD)
      goto CLEANUP;
   
   if((err=AdrCompareAddresses(desc1, desc2, &result))!= GOOD) goto CLEANUP;
   
   if( result == FIRST_ADDR_GREATER) {
      err = ER_MEM_END_LESS_THAN_START;
      goto CLEANUP;
   }
   
   if((err=AdrRangeOfAddresses(desc1, desc2, &fillLength))!=GOOD)
      goto CLEANUP;

   /* last tokens in cmd line are for data size specifier and addr space */
   while( KeywordCheck(&cmdString[(U16)argv[(U16)argc-1]]) ) argc--;
   if((err=AdrSetAddrSpace(desc1, addrSpace))!=GOOD) goto CLEANUP;

   for (i = 3; i < argc; i++) { /* get data into pattern array */
      tempData = strtoul(&cmdString[(U16)argv[i]], &endptr, 0);
      if(*endptr!='\0') {
         err = ER_CLI_SYNTAX;
         goto CLEANUP;
      }
      if(((dataSize == BYTE_SIZE) && (tempData >= 0x100L))
           || ((dataSize == WORD_SIZE) && (tempData >= 0x10000L))) {
         err = (dataSize==BYTE_SIZE) ? ER_MEM_DATA_GREATER_THAN_BYTE
                                     : ER_MEM_DATA_GREATER_THAN_WORD;
         goto CLEANUP;
      }
      for (byte=0; byte<dataSize; byte++)
         pattern[patLength++] = ((U8*)&tempData)[dataSize-byte-1];
   }

   if ((err = MemFill(desc1, fillLength, (LPU8)pattern, patLength)) != GOOD) {
      goto CLEANUP;
   }
   SendCliMessage(cliServerHandle, (LPSTR)"Fill successful.");
   err = GOOD;

CLEANUP:
   firstErr = err;
   err = AdrDestroyAddress(desc1);
   err = AdrDestroyAddress(desc2);
   if (GOOD == firstErr)
      firstErr = err;
   return firstErr;
}

/***************************************************************************
**
**  MemCliSearchMem
**
**  Status:  PRELIMINARY
**
**  description:
**     Cli interface to the fill memory content
**
**  input:
**     <none>
**
**  output:
**     message:
**     <none> :
**
*****************************************************************************/
RETCODE EXPORT MemCliSearchMemory(LPSTR cmdString, U32 argc, U32 argv[]) {
   U16        patLength = 0;
   RETCODE    err, tmpErr = GOOD;
   U32        tempData;
   DESCRIPTOR desc1, desc2;
   U16        i,byte;
   U8         pattern[MAX_CLI_FILL_LENGTH];
   char       *endptr;
   BOOLEAN    not = FALSE, found;

   dataSize = BYTE_SIZE;
   addrSpace = SPACE_SD;

   if(argc < 3) return(ER_CLI_SYNTAX);
   if(argc > MAX_CLI_FILL_LENGTH+3) return(ER_MEM_PAT_LEN);

   if((err = AdrCreateAddress(&desc1))!=GOOD) return(err);
   if((err = AdrCreateAddress(&desc2))!=GOOD) {
      AdrDestroyAddress(desc1);
      return(err);
   }
   if((err=AdrConvTextToAddress(desc1,&cmdString[(U16)argv[1]])) != GOOD)
      goto CLEANUP;
   if((err=AdrConvTextToAddress(desc2,&cmdString[(U16)argv[2]])) != GOOD)
      goto CLEANUP;
   
   /* last tokens in cmd line are for data size specifier and addr space */
   while( KeywordCheck(&cmdString[(U16)argv[(U16)argc-1]]) ) argc--;
   if((err=AdrSetAddrSpace(desc1, addrSpace))!=GOOD) goto CLEANUP;

   for (i = 3; i < argc; i++) { /* get data into pattern array */
      if(strncmpi(&cmdString[(U16)argv[i]], "not",
            strlen(&cmdString[(U16)argv[i]]))==0) {
         not = TRUE;
      } else {
         tempData = strtoul(&cmdString[(U16)argv[i]], &endptr, 0);
         if(*endptr!='\0') {
            err=ER_CLI_SYNTAX;
            goto CLEANUP;
         }
         if(((dataSize == BYTE_SIZE) && (tempData >= 0x100L))
              || ((dataSize == WORD_SIZE) && (tempData >= 0x10000L))) {
            err=(dataSize==BYTE_SIZE) ? ER_MEM_DATA_GREATER_THAN_BYTE
                                      : ER_MEM_DATA_GREATER_THAN_WORD;
            goto CLEANUP;
         }
         for (byte=0; byte<dataSize; byte++)
            pattern[patLength++] = ((U8*)&tempData)[dataSize-byte-1];
      }
   }
   if((err = MemSearch(desc1, desc2, not, (LPU8)pattern, patLength,
         (BOOLEAN FAR *)&found)) == GOOD) {
      if(found) {
         S8 addrText[ADDR_BUFF_SZ];
         S8 text[ADDR_BUFF_SZ+20];
         if((err = AdrConvAddressToTextWithParams(desc1,
                                                  TRUE,
                                                  FALSE,
                                                  (LPSTR)addrText))==GOOD) {
            sprintf(text, "Pattern found at %s.", addrText);
            SendCliMessage(cliServerHandle, (LPSTR)text);
         }
      } else {
         SendCliMessage(cliServerHandle, (LPSTR)"Pattern not found.");
      }
   }
CLEANUP:
   tmpErr = err;
   err = AdrDestroyAddress(desc1);
   if (!tmpErr) tmpErr = err;
   err = AdrDestroyAddress(desc2);
   if (!tmpErr) tmpErr = err;
   return(tmpErr);
}

/***************************************************************************
**
** MemCliSetMemSize
**
** Description:
**    Cli interface to the set the global parameter for the size of data
**    when sent to the probe
**
** Input:
**    cmdString:
**    argc:
**    argv:
**
** Output: None
**
*****************************************************************************/
RETCODE EXPORT MemCliSetMemSize(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE      err;
   S8           text[32];

   if (argc==1) {
      if((err = MemGetAccessSize(&dataSize))!=GOOD) return(err);
      sprintf(text, "%s",
         (dataSize==BYTE_SIZE)  ? BYTE_TEXT:
         (dataSize==WORD_SIZE)  ? WORD_TEXT:
         (dataSize==DWORD_SIZE) ? DWORD_TEXT:
                                    UNKNOWN_TEXT);
      SendCliMessage(cliServerHandle, (LPSTR)text);
      return(GOOD);
   }

   if ((argc > 2) || (argc < 2))
      return ER_CLI_SYNTAX;
   if( !KeywordCheck(&(cmdString[(U16)argv[1]])) )
      return ER_CLI_SYNTAX;
   return(MemSetAccessSize(dataSize));
}  /* end of MemCliSetMemSize */

   
/***************************************************************************
**
** MemCliSetVerify
**
** Description:
**    Cli interface to the set the global parameter for verifying memory
**    writes.
**
** Input:
**    cmdString:
**    argc:
**    argv:
**
** Output: None
**
*****************************************************************************/
RETCODE EXPORT MemCliSetVerify(LPSTR cmdString, U32 argc, U32 argv[]) {
   LPSTR   lpParam;
   RETCODE err;
   BOOLEAN verify;
   S8      text[32];

   if (argc==1) {
      if((err = MemGetVerifyWrites(&verify))!=GOOD) return(err);
      sprintf(text, "%s", verify ? ON_TEXT:OFF_TEXT);
      SendCliMessage(cliServerHandle, (LPSTR)text);
      return(GOOD);
   }
   if ((argc > 2) || (argc < 2))
      return ER_CLI_SYNTAX;
   lpParam = &(cmdString[(U16)argv[1]]);
   if        (strncmpi(lpParam, ON_TEXT, strlen(lpParam))==0) {
      verify = TRUE;
   } else if (strncmpi(lpParam, OFF_TEXT, strlen(lpParam))==0) {
      verify = FALSE;
   } else return ER_CLI_SYNTAX;
   return(MemSetVerifyWrites(verify));
}  /* end of MemCliSetVerify */

/************************************************************************
**
**  KeywordCheck()
**
************************************************************************/
BOOLEAN PRIVATE KeywordCheck(LPSTR str) {
//   U8 paramLen = strlen(str);
   BOOLEAN found = TRUE;
   sizeKeyword = TRUE ;
   spaceKeyword = TRUE ;
   
   if (stricmp(str, BYTE_TEXT)==0) {
      dataSize = BYTE_SIZE;
   } else if (stricmp(str, WORD_TEXT)==0) {
      dataSize = WORD_SIZE;
   } else if (stricmp(str, LONG_TEXT)==0) {
      dataSize = DWORD_SIZE;
   } else if (stricmp(str, DWORD_TEXT)==0) {
      dataSize = DWORD_SIZE;
   } else
      sizeKeyword = FALSE ;
   
   if (!sizeKeyword)
      if (stricmp(str, UD_TEXT)==0) {
         addrSpace = SPACE_UD;
      } else if (stricmp(str, UP_TEXT)==0) {
         addrSpace = SPACE_UP;
      } else if (stricmp(str, SD_TEXT)==0) {
         addrSpace = SPACE_SD;
      } else if (stricmp(str, SP_TEXT)==0) {
         addrSpace = SPACE_SP;
      } else
         spaceKeyword = FALSE ;
   else
     spaceKeyword = FALSE ;

   found = sizeKeyword || spaceKeyword ;
   return(found);
}

/***************************************************************************
**
** MemCliChecksum
**
** Description:
**    Cli interface to the checksum command
**
** Syntax:
**    checksum <address1> <address2> [<space>]
**
*****************************************************************************/
RETCODE EXPORT MemCliChecksum(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE    err;
   RETCODE    firstErr = GOOD;
   U32        bytesLeft;
   DESCRIPTOR addr1Desc, addr2Desc;
   U32        bytesToEnd;
   BOOLEAN    firstAddrFound=FALSE;
   LOOP_VAR   args;
   char outputBuff[80], spaceText[4] = "sd";
   ACCESS_SIZE size;
   U32 checksum;

   MemGetAccessSize(&size);
   iceSetAccessSize(size);
   if ((argc < 3) || (argc > 4))
      return(ER_CLI_SYNTAX);

   if((err = AdrCreateAddress(&addr1Desc))!=GOOD) return(err);
   if (GOOD != (err = AdrCreateAddress(&addr2Desc))) {
      AdrDestroyAddress(addr1Desc);
      return err;
   }
   addrSpace = SPACE_SD ;
   for(args = 1; args < argc; args++) {
      if (!KeywordCheck(&(cmdString[(U16)argv[args]]))) {
         DESCRIPTOR *adrDesc;
         if( firstAddrFound == FALSE ) adrDesc = &addr1Desc;
         else adrDesc = &addr2Desc;
         firstAddrFound++;
         if((err=AdrConvTextToAddress(*adrDesc,&cmdString[(U16)argv[args]]))
            != GOOD) goto CLEANUP_1;
      } else
         if (spaceKeyword && args==3 )
            strcpy(spaceText,&(cmdString[(U16)argv[args]]));
         else {
            err=ER_CLI_SYNTAX;
            goto CLEANUP_1;
         }
   }

   if((err=AdrSetAddrSpace(addr1Desc, addrSpace))!=GOOD) goto CLEANUP_1;
   if((err=AdrSetAddrSpace(addr2Desc, addrSpace))!=GOOD) goto CLEANUP_1;
   if( firstAddrFound == 0 ) {
      err = ER_CLI_SYNTAX;
      goto CLEANUP_1;
   }
   if( firstAddrFound == 2 ) {
      ADDR_COMPARE addrCompareResult;
      /* extract difference between two addresses */
      if(GOOD!=(err=AdrRangeOfAddresses(addr1Desc,addr2Desc,&bytesLeft)))
         goto CLEANUP_1;
      /* now put the smallest address in addr1Desc */
      if((err=AdrCompareAddresses(addr1Desc,addr2Desc,&addrCompareResult))
         != GOOD ) goto CLEANUP_1;
      if (FIRST_ADDR_GREATER == addrCompareResult) {
         AdrDestroyAddress(addr2Desc);
         AdrDestroyAddress(addr1Desc);
         return(ER_CLI_SYNTAX);
      }
   }
   if (0L == bytesLeft)  /* only occurs if entering large address range */
      bytesLeft = 0xFFFFFFFFL;
   /* correct for size of remaining memory when close to the end of memory */
   if (GOOD != (err = AdrRemainingBytes(addr1Desc, &bytesToEnd)))
      goto CLEANUP_1;
   if (0L == bytesToEnd) { /* 0 means largest value; convert */
      bytesToEnd = 0xFFFFFFFFL;
   }
   bytesLeft = min(bytesLeft, bytesToEnd);

   MemChecksum(addr1Desc, bytesLeft, size, (U32 FAR *)&checksum);
   if (size == BYTE_SIZE) {
      sprintf(outputBuff, "Checksum is 0x%lx  %s", checksum&0x000000FF, strupr(spaceText));
   } else {
      sprintf(outputBuff, "Checksum is 0x%lx  %s", checksum&0x0000FFFF, strupr(spaceText));
   }    
   SendCliMessage(cliServerHandle, outputBuff);
   err=GOOD;

CLEANUP_1:
   firstErr = err;
   err = AdrDestroyAddress(addr2Desc);
   if (!firstErr) firstErr = err;
   err = AdrDestroyAddress(addr1Desc);
   if (!firstErr) firstErr = err;
   return firstErr;
}  /* end of MemCliChecksum */

/***************************************************************************
**
**  MemCliSelfTest
**
**  Status:  PRELIMINARY
**
**  description:
**     Cli interface to the self-test of MICEpack
**
**     Syntax:
**        selftest
**
**  input:
**     <none>
**
**  output:
**     <none> :
**
*****************************************************************************/
#define NO_TRACE_MODULE -28
#define NO_EMM -45
#define MCE16A_FAIL -54
#define EMM_FAIL -55
#define TRACE_MODULE_FAIL -56

U16 testSeq[] = { 1,     2,    3,    4,    5,    7};
               /*MCE16D, EMM1, EMM2, EMM3, EMM4, TRACE_BOARD */
CHAR *testFunction[] = {"MCE16D","emulation memory bank1",
   "emulation memory bank2","emulation memory bank3",
   "emulation memory bank4","trace module"};

RETCODE EXPORT MemCliSelfTest(LPSTR cmdString, U32 argc, U32 argv[]) {

   S16 result;
   U8 lp;
   CHAR outputBuff[80];

   if(argc > 1) return(ER_CLI_SYNTAX);

   iceSelfTest(START_TEST);
   for (lp = 0; lp < sizeof(testSeq)/sizeof(testSeq[0]); lp++) {
      result = iceSelfTest(testSeq[lp]);
      switch (result) {
      case MCE16A_FAIL:
      case EMM_FAIL:
      case TRACE_MODULE_FAIL:
         sprintf(outputBuff,"  Test %s -- Fail", testFunction[lp]);
         break;
      case NO_EMM :
         sprintf(outputBuff,"  No emulation memory");
         lp = 5;
         break;
      case NO_TRACE_MODULE :
         sprintf(outputBuff,"  No trace module");
         break;
      default :
         sprintf(outputBuff,"  Test %s -- Good", testFunction[lp]);
         break;
      }
      SendCliMessage(cliServerHandle, outputBuff);
   }
   iceSelfTest(0);
   return (GOOD);
}

/***************************************************************************
**
** MemCliRamtst
**
** Description:
**    Cli interface to the ramtst command
**
** Syntax:
**    ramtst <address1> <address2> [<space>]
**
*****************************************************************************/
RETCODE EXPORT MemCliRamtst(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE    err;
   RETCODE    firstErr = GOOD;
   U32        bytesLeft;
   DESCRIPTOR addr1Desc, addr2Desc;
   U32        bytesToEnd;
   BOOLEAN    firstAddrFound=FALSE;
   LOOP_VAR   args;
   char outputBuff[80];
   char spaceText[4] = "sd" ;
   ADDR retAddr;

   if ((argc < 2) || (argc > 5))
      return(ER_CLI_SYNTAX);

   addrSpace = SPACE_SD;
   
   if((err = AdrCreateAddress(&addr1Desc))!=GOOD) return(err);
   if (GOOD != (err = AdrCreateAddress(&addr2Desc))) {
      AdrDestroyAddress(addr1Desc);
      return err;
   }

   for(args = 1; args < argc; args++) {
      if( !KeywordCheck(&(cmdString[(U16)argv[args]])) ) {
         DESCRIPTOR *adrDesc;
         if( firstAddrFound == FALSE ) adrDesc = &addr1Desc;
         else adrDesc = &addr2Desc;
         firstAddrFound++;
         if((err=AdrConvTextToAddress(*adrDesc,&cmdString[(U16)argv[args]]))
            != GOOD) goto CLEANUP_1;
      }
      else
         strcpy(spaceText,&(cmdString[(U16)argv[args]]));
   }
   if( firstAddrFound == 0 ) {
      err = ER_CLI_SYNTAX;
      goto CLEANUP_1;
   }
   if((err=AdrSetAddrSpace(addr1Desc, addrSpace))!=GOOD) goto CLEANUP_1;
   if( firstAddrFound == 2 ) {
      ADDR_COMPARE addrCompareResult;
      if((err=AdrSetAddrSpace(addr2Desc, addrSpace))!=GOOD) goto CLEANUP_1;
      /* extract difference between two addresses */
      if(GOOD!=(err=AdrRangeOfAddresses(addr1Desc,addr2Desc,&bytesLeft)))
         goto CLEANUP_1;
      /* now put the smallest address in addr1Desc */
      if((err=AdrCompareAddresses(addr1Desc,addr2Desc,&addrCompareResult))
         != GOOD ) goto CLEANUP_1;
      if (FIRST_ADDR_GREATER == addrCompareResult) {
         /* switch the two values while preserving them */
         DESCRIPTOR addrTempDesc;
         addrTempDesc = addr2Desc;
         addr2Desc = addr1Desc;
         addr1Desc = addrTempDesc;
      }
   }
   if (0L == bytesLeft)  /* only occurs if entering large address range */
      bytesLeft = 0xFFFFFFFFL;
   /* correct for size of remaining memory when close to the end of memory */
   if (GOOD != (err = AdrRemainingBytes(addr1Desc, &bytesToEnd)))
      goto CLEANUP_1;
   if (0L == bytesToEnd) { /* 0 means largest value; convert */
      bytesToEnd = 0xFFFFFFFFL;
   }
   bytesLeft = min(bytesLeft, bytesToEnd);

   err = MemTest(addr1Desc, bytesLeft, (ADDR FAR *)&retAddr);
   if (err == GOOD) {
      strcpy(outputBuff, "RAM Test OK.");
   } else {
      sprintf(outputBuff, "RAM Test failure at: 0x%lX  %s", retAddr.pos, spaceText);
//      err=GOOD;
   }
   SendCliMessage(cliServerHandle,outputBuff);


CLEANUP_1:
   firstErr = err;
   err = AdrDestroyAddress(addr2Desc);
   if (!firstErr) firstErr = err;
   err = AdrDestroyAddress(addr1Desc);
   if (!firstErr) firstErr = err;
   return firstErr;
}  /* end of MemCliRamtst */

/**************************************************************************
**
** Name : Diagnostic
**
** Function
**
**    Input  :
**
**    Output :
**
** Notes:
**
**************************************************************************/
#define HighWord(x)      ((U16)((U32)(x) >> 16))
#define LowWord(x)       ((U16)(x))

static char *diagInitDisplay[] = {
    "MCE 8255         ",
    "Download 4003    ",
    "Data Memory      "
};

static char *BinFile[] = {
    "main302.bin",
    "main306.bin",
    "main307.bin",
    "main328.bin"
};

RETCODE EXPORT MemCliDiagnost(VOID) {
RETCODE err;
RETCODE status,diagStatus;
U16 lp2;
U8  retId, idxBinName;
U32 memFailAddress;
char outputBuff[80];
PROBE_TYPE probeType;

   ProcReturnSpecificProcessor(&probeType);
   switch (probeType) {
   case M68302_MP:
      idxBinName = 0;
      break;
   case M68306_MP:
      idxBinName = 1;
      break;
   case M68307_MP:
      idxBinName = 2;
      break;
   case M68328_MP:
      idxBinName = 3;
      break;
   }
   status = CheckFwStatus();
   if (status == NORMAL_STATUS) {
      iceDiagnostic();
      CheckFwStatus();
   }
   sprintf(outputBuff,"Download diagnostic file....");
   SendCliMessage(cliServerHandle, outputBuff);
   DownLoadFirmware((U8 *)"diagnost.bin", 0x400, 0xff);

   diagStatus = DiagnosticFunction(INITIAL_TEST, &memFailAddress, &retId);

   // MCE_8255_FAIL        = 0x01,
   // DOWNLOAD_4003_FAIL   = 0x02,
   // DATA_MEMORY_FAIL     = 0x04,
//   for (lp2 = 0; lp2 < 3 ; lp2++) {
//      if (diagStatus & (1 << lp2)) {
//         if ((1 << lp2) == DATA_MEMORY_FAIL) {
//            sprintf(outputBuff,"%s fail address: %X:%X",diagInitDisplay[lp2],
//               HighWord(memFailAddress),LowWord(memFailAddress));
//            SendCliMessage(cliServerHandle, outputBuff);
//         }
//         else
//            sprintf(outputBuff,"%s Fail",diagInitDisplay[lp2]);
//            SendCliMessage(cliServerHandle, outputBuff);
//      }
//      else {
//         sprintf(outputBuff,"%s OK",diagInitDisplay[lp2]);
//         SendCliMessage(cliServerHandle, outputBuff);
//      }
//   }

//   DiagnosticMCE();
   if (!(diagStatus & MTAT_EXIST)) {
      SendCliMessage(cliServerHandle, "No MTAT2 Board");
   }
   else {
/*    DiagnosticMTAT(diagStatus);  *for MTAT test */
      DiagnosticMTAT2(diagStatus); /* for MTAT2 test */
/*    DiagnosticMCEConnect();      not support temporally */
   }

   status = DiagnosticFunction(END_DIAG, &memFailAddress, &retId);
   CheckFwStatus();
   sprintf(outputBuff,"Recovery system file....");
   SendCliMessage(cliServerHandle, outputBuff);
   DownLoadFirmware(BinFile[idxBinName], 0x400, 0xff);
//   ReassignProcessorType(probeType);
   Sds2AbiFwUnloadRegisters(TRUE);
   sprintf(outputBuff,"Diagnostic test finished.");
   SendCliMessage(cliServerHandle, outputBuff);
   return(GOOD);
}

static char *diagDisplayMTAT2[] = {
     "Bus Compare:  RDATA BUS test...",
     "              SDATA BUS test...",
     "              TDATA BUS test...",
     "              UDATA BUS test...",
     "              VDATA BUS test...",
     "              WDATA BUS test...",
     "              RADDR BUS test...",
     "              SADDR BUS test...",
     "              TADDR BUS test...",
     "              UADDR BUS test...",
     "              VADDR BUS test...",
     "              WADDR BUS test...",
     "Trace Buffer: RSDATA BUS test..",
     "              TUDATA BUS test..",
     "              TPDATA BUS test..",
     "              VWDATA BUS test..",
     "              TSDATA BUS test..",
     "              EVDATA BUS test..",
     "              RSADDR BUS test..",
     "              TUADDR BUS test..",
     "              TPADDR BUS test..",
     "              VWADDR BUS test..",
     "              TSADDR BUS test..",
     "              EVADDR BUS test.."
};

VOID DiagnosticMTAT2(U16 diagStatus) {
DIAG_ID lp;
U32 status;
char outputBuff[80];
U32 memFailAddress;
U8  retId;

   status = DiagnosticFunction(TEST_SEQ_RAM, &memFailAddress, &retId);
   if (status == GOOD)
      sprintf(outputBuff,"SEQ RAM TEST      OK");
   else
      sprintf(outputBuff,"SEQ RAM TEST      Fail");
   SendCliMessage(cliServerHandle, outputBuff);

   for (lp = TEST_BC_RDATA_BUS; lp <= TEST_TB_EVADDR_BUS; lp++) {
       sprintf(outputBuff,"%s Please wait 40-60 seconds !",
               diagDisplayMTAT2[lp-TEST_BC_RDATA_BUS]);
       SendCliMessageNo(cliServerHandle, outputBuff);
       status = DiagnosticFunction(lp, &memFailAddress, &retId);
       if (status == GOOD) {
          sprintf(outputBuff,"%s OK", diagDisplayMTAT2[lp-TEST_BC_RDATA_BUS]);
          SendCliMessage(cliServerHandle, outputBuff);
       } else {
          sprintf(outputBuff,"%s Fail--%8X", diagDisplayMTAT2[lp-TEST_BC_RDATA_BUS],
             (U32)memFailAddress);
          SendCliMessage(cliServerHandle, outputBuff);
          if (lp < TEST_BC_WADDR_BUS)
             lp=TEST_BC_WADDR_BUS;
          else
             break;
       }
   }
}

RETCODE SendCliMessageNo(HANDLE cliHandle, LPSTR msgPtr) {

   HANDLE               msgBufHandle;
   CSERVER_RESULTS FAR  *msgBufPtr;
   U16                  msgTextSize, loop ;

   msgTextSize = lstrlen(msgPtr);
   if ((msgBufHandle =
      GlobalAlloc(GMEM_MOVEABLE,
                  (sizeof(CSERVER_RESULTS) + msgTextSize + 2)))
      == (HANDLE)NULL) {
      return(ER_OUT_OF_MEMORY);
   }
   else if((msgBufPtr=(CSERVER_RESULTS *)GlobalLock(msgBufHandle)) == NULL) {
      GlobalFree(msgBufHandle);
      return(ER_WINDOWS_MEMLOCK);
   }
   msgBufPtr->target               = 0;    /*@@ CLI: not yet def'ed @@*/
   msgBufPtr->variantCode          = CLI_SERVER_RESULTS;
   msgBufPtr->resultTextLength     = msgTextSize-1; /* message string length */
   for (loop = 0; loop < msgTextSize; loop++ ) {
      msgBufPtr->messageText[loop]  =  *msgPtr++;
   }
/*   msgBufPtr->messageText[msgTextSize+1] = 0 ; */

   SendMessage(cliHandle, CLI_SERVER_RESULTS,
               msgBufHandle, CLI_SERVER_RESULTS);
   return GOOD;
}
/********************************* E O F ***********************************/
