/****************************************************************************
**
**  Name:  dummyfw.c
**
**  Description:
**     Dummy sharefw.c to be used with no hardware
**
**  Status:  CODED
**
**  $Log:   S:/tbird/arcppc/sds/dummyfw.c_v  $
** 
**    Rev 1.0   17 Jan 1997 09:23:40   kevin
** Initial revision.
** 
**    Rev 1.0   03 Jun 1996 11:37:20   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 11:12:00   gene
** Initial revision.
** 
**    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/arcppc/sds/dummyfw.c_v   1.0   17 Jan 1997 09:23:40   kevin  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <stdio.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 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;

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

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

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