/****************************************************************************
**
**  Name:  dummyfw.c
**
**  Description:
**     Dummy sharefw.c to be used with no hardware
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_186/sds/dummyfw.c_v  $
** 
**    Rev 1.0   16 Dec 1996 13:46:02   Judy
** Initial revision.
** 
**    Rev 1.0   27 Aug 1996 15:12:10   Judy
** Initial revision.
** 
**    Rev 1.0   27 Aug 1996 15:06:48   Judy
** Initial revision.
** 
**    Rev 1.0   14 Jun 1996 13:50:58   Judy
** Initial revision.
** 
**    Rev 1.12   06 Sep 1994 14:55:52   ernie
** Added memory search and memory copy.
** 
**    Rev 1.11   15 Jun 1994 09:29:38   steve
** merged 1.9.1.0 to the trunk
** 
**    Rev 1.10   11 May 1994 08:45:04   ernie
** Added registration for RDWR interface to avoid hanging.
**
**    Rev 1.9.1.0   17 May 1994 15:26:32   ernie
** Added serial number to load response packet.
**
**    Rev 1.9   06 May 1994 14:51:48   ernie
** Updated loader to handle packet serial numbers
** 
**    Rev 1.8   16 Jul 1993 11:58:42   ernie
** Removed obsolete includes error.h and sdserror.h
** 
**    Rev 1.7   13 Jul 1993 09:07:46   ernie
** Support new loader interface.
** 
**    Rev 1.6   17 May 1993 08:03:14   ernie
** Cleaned up warnings
** 
**    Rev 1.5   05 May 1993 09:23:38   doug
** support demo version (no hardware) run-time
** 
**    Rev 1.4   30 Jul 1992 15:20:18   doug
** a) error.h now called sdserror.h so as not to conflict with one from boot
** b) change error name to not conflict with flash
** 
**    Rev 1.3   22 Jul 1992 16:34:42   doug
** set map members to reasonable values
** 
**    Rev 1.2   21 Jul 1992 08:37:24   doug
** The dummy shared data server is now generic once again
** 
**    Rev 1.1   22 Jan 1992 22:39:26   doug
** remove template
** 
**    Rev 1.0   22 Jan 1992 21:45:50   doug
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/sds/dummyfw.c_v   1.0   16 Dec 1996 13:46:02   Judy  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#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 _SDPROBE_
#include "sdprobe.h"
#endif

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

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
VOID EXPORT ReadMemory(DESCRIPTOR desc);
RETCODE ReadMem(DESCRIPTOR desc);
VOID EXPORT FillInMemoryBuff(DESCRIPTOR desc);
RETCODE FillInMem(DESCRIPTOR desc);

VOID FAR PASCAL SdDummyMemSearch(DESCRIPTOR desc);
RETCODE PRIVATE SearchMemReverse(U32 *offset, U32 length,
      U16 pLength, BOOLEAN not,
      U8 *data, BOOLEAN *found);
RETCODE PRIVATE SearchMemForward(U32 *offset, U32 length,
      U16 pLength, BOOLEAN not,
      U8 *data, BOOLEAN *found);
RETCODE PRIVATE DummyMemSearchAction(BOOLEAN *found);

VOID FAR PASCAL SdDummyMemCopy(DESCRIPTOR desc);
RETCODE PRIVATE DummyMemCopyAction(DESCRIPTOR desc);

VOID FAR PASCAL SdDummyRdWrCommand(DESCRIPTOR desc);
VOID EXPORT LoadMemory(DESCRIPTOR desc);
VOID FAR PASCAL LoadMemoryCommand(DESCRIPTOR desc);
RETCODE LoadMemAction(U8 *data);
RETCODE SvcReadMem(U32 srcAddr, U32 numBytes, VOID *buff);
RETCODE ReadByte(U32 addr, U8 *byte);
RETCODE SvcFillMem(U32 dest, U32 numBytes, U32 numPattern, VOID *buff);
RETCODE WriteByte(U32 addr, U8 byte);
VOID EXPORT EmulGo(DESCRIPTOR desc);
RETCODE DummyGo(DESCRIPTOR desc);
VOID EXPORT EmulStep(DESCRIPTOR desc);
RETCODE DummyStep(DESCRIPTOR desc);
VOID EXPORT EmulHalt(DESCRIPTOR desc);
RETCODE DummyHalt(DESCRIPTOR desc);
VOID EXPORT EmulBkpt(DESCRIPTOR desc);
RETCODE DummyBkpt(DESCRIPTOR desc);

#define NUM_MEM_BUFFERS 256
#define NUM_BYTES_PER_BUFFER (4*1024)  /* use 4k buffers */
#define SHIFT_COUNT 12 /* 12 bits in 4k buffers */

/* static data */
static U8 FAR *MemBuff[NUM_MEM_BUFFERS];
FARPROC lpReadMemCallback;
FARPROC lpFillMemCallback;
FARPROC lpLoadMemCallback;
FARPROC lpGoCallback;
FARPROC lpStepCallback;
FARPROC lpHaltCallback;
FARPROC lpBkptCallback;
PRIVATE DESCRIPTOR emulStateDesc;

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

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

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


RETCODE InitDummy(VOID) {
   RETCODE err;
   LOOP_VAR i;
   MEMBER_NAME fullName[SD_MAX_NAME];
   DESCRIPTOR desc;
   U32 numMapBlocks = 2, sizeMapBlock = 0x20000L, granMapBlock = 0x10000L;
   FARPROC func;
   
   /*
   ** register on memory writes and reads to simulate memory
   */
   for(i=0; i< NUM_DUMP; i++) {
      sprintf(fullName, "%s %d", SD_DUMP_LENGTH, i) ;
      lpReadMemCallback = MakeProcInstance((FARPROC)ReadMemory, hLib);
      if ((err = SdRegister(fullName, (FARPROC)lpReadMemCallback, &desc)) != GOOD)
         return(err);
   }
   for(i=0; i < NUM_FILL; i++) {
      sprintf(fullName, "%s %d", SD_FILL_COMMAND, i) ;
      lpFillMemCallback = MakeProcInstance((FARPROC)FillInMemoryBuff, hLib);
      if ((err = SdRegister(fullName, (FARPROC)lpFillMemCallback, &desc))
                           != GOOD) return(err);
   }

   func = MakeProcInstance((FARPROC) SdDummyMemSearch, hLib);
   if ((err=SdnRegister(SDN_SEARCH_COMMAND, func, &desc)) != GOOD)
      return(err);
   func = MakeProcInstance((FARPROC) SdDummyMemCopy, hLib);
   if ((err=SdnRegister(SDN_COPY_COMMAND, func, &desc)) != GOOD)
      return(err);
   func = MakeProcInstance((FARPROC) SdDummyRdWrCommand, hLib);
   if ((err=SdnRegister(SDN_RDWR_COMMAND, func, &desc)) != GOOD) return(err);

   for(i=0; i<NUM_LOAD; i++) {
      lpLoadMemCallback = MakeProcInstance((FARPROC)LoadMemory, hLib);
      if ((err = SdnRegister(SDN_LOAD_DATA+i, (FARPROC)lpLoadMemCallback,
         &desc)) != GOOD) return(err);
   }
   lpLoadMemCallback = MakeProcInstance((FARPROC)LoadMemoryCommand, hLib);
   if ((err = SdnRegister(SDN_LOAD_COMMAND, (FARPROC)lpLoadMemCallback,
      &desc)) != GOOD) return(err);

   for(i=0; i<NUM_MEM_BUFFERS; i++) MemBuff[i] = NULLPTR;
   
   lpGoCallback = MakeProcInstance((FARPROC)EmulGo, hLib);
   if((err = SdRegister(SD_GO, (FARPROC)lpGoCallback, &desc))!= GOOD)
      return(err);
   lpStepCallback = MakeProcInstance((FARPROC)EmulStep, hLib);
   if((err = SdRegister(SD_STEP,
                        (FARPROC)lpStepCallback, &desc))!= GOOD)
      return(err);
   lpHaltCallback = MakeProcInstance((FARPROC)EmulHalt, hLib);
   if((err = SdRegister(SD_HALT, (FARPROC)lpHaltCallback, &desc))!= GOOD)
      return(err);
   lpBkptCallback = MakeProcInstance((FARPROC)EmulBkpt, hLib);
   if((err = SdRegister(SD_BKPT_CMD, (FARPROC)lpBkptCallback, &desc))
      != GOOD) return(err);
   if((err = SdRegister(SD_EMULATION_STATE, NULLPTR, &emulStateDesc)) != GOOD)
      return(err);

   if((err = SdnWriteMember(SDN_NUM_MAP_BLOCKS, (U8 FAR *)&numMapBlocks,GOOD))
      !=GOOD) return(err);
   if((err = SdnWriteMember(SDN_SIZE_MAP_BLOCK, (U8 FAR *)&sizeMapBlock,GOOD))
      !=GOOD) return(err);
   if((err = SdnWriteMember(SDN_GRAN_MAP_BLOCK, (U8 FAR *)&granMapBlock,GOOD))
      !=GOOD) return(err);
         
   return(GOOD);
}

VOID EXPORT ReadMemory(DESCRIPTOR desc) {
   RETCODE err = ReadMem(desc);
   if(err) SdWriteMember(desc, NULLPTR, err);
}

RETCODE ReadMem(DESCRIPTOR desc) {
   RETCODE err, err1;
   DESCRIPTOR sdDesc;
   MEMBER_INDEX index=0;
   U32 length=0 ;
   U32 startAddr;
   U8 *dummyData;
   MEMBER_NAME fullName[SD_MAX_NAME];

   /*
   ** Get the length to read
   */
   if ((err = SdReadMember(desc,(U8 FAR *)&length))!=GOOD) goto WRITE_RESULTS;
   if (length>SIZE_DUMP) {
      err=ER_MEM_BUFF_LEN;
      goto WRITE_RESULTS;
   }
   if ((err = SdGetMemberIndex(desc, &index))!=GOOD) goto WRITE_RESULTS;
   /*
   ** get the start address
   */
   sprintf(fullName, "%s %d", SD_DUMP_OFFSET, index);
   if((err = SdRegister(fullName, NULLPTR, &sdDesc))!=GOOD)
      goto WRITE_RESULTS;
   if ((err = SdReadMember(sdDesc, (U8 FAR *)&startAddr))!=GOOD) {
      SdUnRegister(sdDesc);
      goto WRITE_RESULTS;
   }
   if ((err = SdUnRegister(sdDesc))!=GOOD) goto WRITE_RESULTS;
   /*
   ** get memory and fill in dummy data
   */
   if((dummyData = (U8 *)TMalloc(length))==NULL) {
      err=ER_OUT_OF_MEMORY;
      goto WRITE_RESULTS;
   }

   if ((err = SvcReadMem(startAddr, length, dummyData)) != GOOD)
      goto WRITE_RESULTS ;
   /*
   ** register with appropriate memory store (use index)
   */
   sprintf(fullName, "%s %d", SD_DUMP_BUFFER, index);
   if((err = SdRegister(fullName, NULLPTR, &sdDesc))!=GOOD) {
      goto WRITE_RESULTS;
   }
   /*
   ** write the shared data member
   */
   err = SdWritePartialMember(sdDesc,0,length,dummyData, err);
   err1 = SdUnRegister(sdDesc);
   TFree((LPSTR)dummyData); /* ignore error */
   if (!err) err = err1;
   /*
   ** register with memory result (use index)
   */
WRITE_RESULTS:
   sprintf(fullName, "%s %d", SD_DUMP_RESULT, index);
   if(SdRegister(fullName, NULLPTR, &sdDesc)==GOOD) {
      /*
      ** write the shared data member, ack to server
      */
      if((err=SdWriteMember(sdDesc, (U8 FAR *)&err, GOOD))!=GOOD) {
         SdUnRegister(sdDesc);
         return(err);
      }
      if ((err = SdUnRegister(sdDesc))!=GOOD) return(err);
   }

   return(GOOD);
}

VOID EXPORT FillInMemoryBuff(DESCRIPTOR desc) {
   RETCODE err = FillInMem(desc);
   if(err) SdWriteMember(desc, NULLPTR, err);
}

RETCODE FillInMem(DESCRIPTOR desc) {
   RETCODE err=GOOD;
   DESCRIPTOR sdDesc;
   MEMBER_INDEX index;
   U32 length, pLength ;
   U32 startAddr;
   U8 *dummyData;
   MEMBER_NAME fullName[SD_MAX_NAME];

   /* get the index of this fill command */
   if ((err = SdGetMemberIndex(desc, &index))!=GOOD) goto WRITE_RESULTS;
   /*
   ** Get the length to write
   */
   sprintf(fullName, "%s %d", SD_FILL_LENGTH, index) ;
   if ((err = SdRegister(fullName, NULLPTR, &sdDesc)) != GOOD)
      goto WRITE_RESULTS;
   if((err = SdReadMember(sdDesc, (U8 FAR *)&length)) != GOOD) {
      SdUnRegister(sdDesc) ;
      goto WRITE_RESULTS;
   }
   if ((err = SdUnRegister(sdDesc)) != GOOD) goto WRITE_RESULTS ;
   
   if (length == 0) {
      err = GOOD; /* if length == 0 don't work */
      goto WRITE_RESULTS;
   }

   sprintf(fullName, "%s %d", SD_FILL_PATLENGTH, index) ;
   if ((err = SdRegister(fullName, NULLPTR, &sdDesc)) != GOOD)
      goto WRITE_RESULTS ;
   if((err = SdReadMember(sdDesc, (U8 FAR *)&pLength)) != GOOD) {
      SdUnRegister(sdDesc) ;
      goto WRITE_RESULTS;
   }
   if ((err = SdUnRegister(sdDesc)) != GOOD) goto WRITE_RESULTS ;
   if (pLength == 0) {
      err = GOOD;
      goto WRITE_RESULTS; /* if pattern length == 0 no work */
   }
   if (pLength>SIZE_FILL) {
      err=ER_MEM_BUFF_LEN;
      goto WRITE_RESULTS;
   }
   /*
   ** get the start address
   */
   sprintf(fullName, "%s %d", SD_FILL_OFFSET, index);
   if((err = SdRegister(fullName, NULLPTR, &sdDesc))!=GOOD)
      goto WRITE_RESULTS;
   if((err = SdReadMember(sdDesc, (U8 FAR *)&startAddr))!=GOOD) {
      SdUnRegister(sdDesc);
      goto WRITE_RESULTS;
   }
   if((err = SdUnRegister(sdDesc))!=GOOD) goto WRITE_RESULTS;
   /*
   ** register with appropriate memory store (use index)
   */
   sprintf(fullName, "%s %d", SD_FILL_BUFFER, index);
   if((err = SdRegister(fullName, NULLPTR, &sdDesc))!=GOOD)
      goto WRITE_RESULTS;
   /*
   ** get memory and fill in dummy data
   */
   if((dummyData = (U8 *)TMalloc(pLength))==NULL) {
      SdUnRegister(sdDesc);
      err = ER_OUT_OF_MEMORY;
      goto WRITE_RESULTS;
   }
   /*
   ** read the shared data member
   */
   if((err=SdReadPartialMember(sdDesc,0,pLength,dummyData))!=GOOD) {
      SdUnRegister(sdDesc);
      goto WRITE_RESULTS_FREE;
   }
   if((err = SdUnRegister(sdDesc))!=GOOD) goto WRITE_RESULTS_FREE;
   /* do fill comand in debug program */
   err = SvcFillMem(startAddr, length, pLength, dummyData);
   /*
   ** free memory
   */
WRITE_RESULTS_FREE:
   TFree((LPSTR)dummyData);  /* ignore error */
   /* write the result back to template */
WRITE_RESULTS:
   /* Always return the results for the host side */
   sprintf(fullName, "%s %d", SD_FILL_RESULTS, index);
   if(SdRegister(fullName, NULLPTR, &sdDesc)==GOOD)
      if((err = SdWriteMember(sdDesc, (U8 FAR *)&err, GOOD))!=GOOD) {
         SdUnRegister(sdDesc);
         return(err);
      }
   if((err = SdUnRegister(sdDesc))!=GOOD) return(err);

   return(GOOD);
}

RETCODE SvcReadMem(U32 srcAddr, U32 numBytes, VOID *buff) {
   RETCODE err;
   U32 i;
   U8 *byteBuff = buff;
   if((srcAddr+(U32)numBytes-1) >= (U32)(1L*1024L*1024L))
      return(ER_OUT_OF_RANGE);
   for(i=0; i<numBytes; i++) {
      if((err = ReadByte(srcAddr, &byteBuff[(U16)i]))!=GOOD) return(err);
      srcAddr++;
   }
   return(GOOD);
}

RETCODE ReadByte(U32 addr, U8 *byte) {
   U16 tableIndex = addr>>SHIFT_COUNT;
   U8 *pByte;
   if(MemBuff[tableIndex]==NULLPTR) {
      if((MemBuff[tableIndex]=(U8 *)TMalloc((U32)NUM_BYTES_PER_BUFFER))==NULL)
         return(ER_OUT_OF_MEMORY);
   }
   pByte = (U8 *)(MemBuff[tableIndex]+(U16)(addr%NUM_BYTES_PER_BUFFER));
   *byte = *pByte;
   return(GOOD);
}

RETCODE SvcFillMem(U32 dest, U32 numBytes, U32 numPattern, VOID *buff) {
   U32 i;
   U32 pat = 0;
   RETCODE err;
   U8 *byteBuff = buff;
   if((dest+(U32)numBytes-1) >= (U32)(1L*1024L*1024L))
      return(ER_OUT_OF_RANGE);
   for(i=0; i<numBytes; i++) {
      if(pat==0) byteBuff = buff;
      if((err = WriteByte(dest, *byteBuff))!=GOOD) return(err);
      dest++;
      byteBuff++;
      if((++pat)==numPattern) pat = 0; /* reset after pattern length */
   }
   return(GOOD);
}

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

#pragma argsused
VOID FAR PASCAL SdDummyMemSearch(DESCRIPTOR desc) {
   RETCODE result;
   BOOLEAN found;
   result=DummyMemSearchAction(&found);
   SdnWriteMember(SDN_SEARCH_FOUND,(U8*)&found,result);
}

#define SEARCH_BUFFER_SIZE 256

RETCODE PRIVATE DummyMemSearchAction(BOOLEAN *found) {
   RETCODE err;
   U32 length, pLength;
   U32 offset;
   BOOLEAN not,forward;

   *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_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 (forward)
      err = SearchMemForward(&offset,length,(U16)pLength,not,
         SdnData(SDN_SEARCH_PATTERN), found);
   else
      err = SearchMemReverse(&offset,length,(U16)pLength,not,
         SdnData(SDN_SEARCH_PATTERN), found);
   if (!err) err = SdnWriteMember(SDN_SEARCH_OFFSET,(U8*)&offset,GOOD);
   return(err);
}

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

   *found = FALSE;
   bufferOffset = *offset;
   pIndex = 0;
   bytesInBuffer=0;
   while (1) {
      U16 readLength = min(SEARCH_BUFFER_SIZE-bytesInBuffer, (U16)length);
      if ((err = SvcReadMem(bufferOffset+bytesInBuffer, 
         readLength, 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;

      if (CHECK_ABORT()) return(ER_SEARCH_ABORT);
   }
   return(GOOD);
}

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

   *found = FALSE;
   bufferOffset = *offset+length;
   pIndex = 0;
   bytesInBuffer=0;
   while (1) {
      U16 readLength = min(SEARCH_BUFFER_SIZE-bytesInBuffer, (U16)length);
      if ((err = SvcReadMem(bufferOffset-bytesInBuffer-readLength,
         readLength, 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;

      if (CHECK_ABORT()) return(ER_SEARCH_ABORT);
   }
   return(GOOD);
}

VOID FAR PASCAL SdDummyMemCopy(DESCRIPTOR desc) {
   RETCODE result;
   result=DummyMemCopyAction(desc);
   SdnWriteMember(SDN_COPY_RESULTS,(U8*)&result,result);
}

#define MCPY_BLOCK_SIZE  128

#pragma argsused
RETCODE PRIVATE DummyMemCopyAction(DESCRIPTOR desc) {
   RETCODE     err;
   U32         srcLength;
   U32         srcAddrOffset;
   U32         destAddrOffset;
   U32         blkLength;      // length of this block: either MCPY_BLOCK_SIZE
                               // or what is left over
   BOOLEAN     increasingCopy;
   U32         currentSrcOffset;
   U32         currentDestOffset;
   U32         lengthLeft;
   // buffer for copy, plus pad area
   U8          memoryBlock[ MCPY_BLOCK_SIZE + 10];
   RETCODE     retcode;

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

   if (srcLength==0) return GOOD;

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

   if( srcAddrOffset >= destAddrOffset)   {
      increasingCopy     = TRUE;
      currentSrcOffset   = srcAddrOffset;
      currentDestOffset  = destAddrOffset;
   }
   else {
      increasingCopy = FALSE;
      currentSrcOffset  = srcAddrOffset  + srcLength
                             - ( min(srcLength, (U32) MCPY_BLOCK_SIZE ));
      currentDestOffset = destAddrOffset + srcLength
                             - ( min(srcLength, (U32) MCPY_BLOCK_SIZE ));
   }

   while(lengthLeft > 0)  {
      blkLength = min(lengthLeft, (U32) MCPY_BLOCK_SIZE );
      if ((retcode = SvcReadMem(currentSrcOffset, blkLength, memoryBlock))
         != GOOD) return(retcode);
      if ((retcode = SvcFillMem(currentDestOffset, 
                   blkLength,         //  fill length
                   blkLength,         //  pLength is same size
                   memoryBlock)) != GOOD) return(retcode);
      lengthLeft = lengthLeft - blkLength ;

      if(increasingCopy)  {
          currentSrcOffset  = currentSrcOffset   +  blkLength;
          currentDestOffset = currentDestOffset  +  blkLength;
      } else {
          currentSrcOffset  = currentSrcOffset
                                - min( lengthLeft, blkLength);
          currentDestOffset = currentDestOffset
                                - min( lengthLeft, blkLength);
      }
      if (CHECK_ABORT()) return(ER_COPY_ABORT);
   }
   return(GOOD);
}

VOID EXPORT LoadMemory(DESCRIPTOR desc) {
   LOAD_RESULT loadResult;
   MEMBER_INDEX index;

   if (SdGetMemberIndex(desc, &index) != GOOD) return;
   loadResult.serialNumber = *((U32*)SdnData(SDN_LOAD_DATA+index));
   loadResult.retcode = LoadMemAction(SdnData(SDN_LOAD_DATA+index)
      + sizeof(U32));
   SdnWriteMember(SDN_LOAD_RESULT+index, (U8*)&loadResult, GOOD);
}

VOID FAR PASCAL LoadMemoryCommand(DESCRIPTOR desc) {
   RETCODE err;
   LOAD_COMMAND command;
   err = SdReadMember(desc, (U8*)&command);
   SdnWriteMemberNoCallback(SDN_LOAD_COMMAND, (U8*)&command, err);
}

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

RETCODE LoadMemAction(U8 *data) {
   RETCODE err=GOOD;
   U32 currentLoadAddr=0;
   U32 loadRepeatCount=1;
   U32 pLength, length;
   while (!err && (*data != LOAD_EOF)) {
      if (CHECK_ABORT()) { 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 = SvcFillMem(currentLoadAddr, length, pLength, data);
      currentLoadAddr += length;
      data += (U16)pLength;
      loadRepeatCount = 1;
   }
   return((err == ER_FILL_ABORT) ? ER_LOAD_ABORT : err);
}


RETCODE WriteByte(U32 addr, U8 byte) {
   U16 tableIndex = addr>>SHIFT_COUNT;
   U8 *pByte;
   if(MemBuff[tableIndex]==NULLPTR) {
      if((MemBuff[tableIndex]=(U8 *)TMalloc((U32)NUM_BYTES_PER_BUFFER))==NULL)
         return(ER_OUT_OF_MEMORY);
   }
   pByte=(U8 *)(MemBuff[tableIndex]+(U16)(addr%NUM_BYTES_PER_BUFFER));
   *pByte = byte;
   return(GOOD);
}

#pragma argsused
VOID EXPORT EmulGo(DESCRIPTOR desc) {
   RETCODE err = DummyGo(desc);
   if(err) SdWriteMember(desc, NULLPTR, err);
}

#pragma argsused
RETCODE DummyGo(DESCRIPTOR desc) {
   EMULATION_STATE emulState = EM_RUNNING;
   return(SdWriteMember(emulStateDesc, (U8 FAR *)&emulState, GOOD));
}

VOID EXPORT EmulStep(DESCRIPTOR desc) {
   RETCODE err = DummyStep(desc);
   if(err) SdWriteMember(desc, NULLPTR, err);
}

#pragma argsused
RETCODE DummyStep(DESCRIPTOR desc) {
   EMULATION_STATE emulState = EM_HALTED;
   return(SdWriteMember(emulStateDesc, (U8 FAR *)&emulState, GOOD));
}

#pragma argsused
VOID EXPORT EmulHalt(DESCRIPTOR desc) {
   RETCODE err = DummyHalt(desc);
   if(err) SdWriteMember(desc, NULLPTR, err);
}

#pragma argsused
RETCODE DummyHalt(DESCRIPTOR desc) {
   EMULATION_STATE emulState = EM_HALTED;
   return(SdWriteMember(emulStateDesc, (U8 FAR *)&emulState, GOOD));
}

VOID EXPORT EmulBkpt(DESCRIPTOR desc) {
   RETCODE err = DummyBkpt(desc);
   if(err) SdWriteMember(desc, NULLPTR, err);
}

#pragma argsused
RETCODE DummyBkpt(DESCRIPTOR desc) {
   RETCODE err=GOOD;
   return(SdnWriteMember(SDN_BKPT_RESULT, (U8 FAR *)&err, GOOD));
}

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