/****************************************************************************
**
**  Name:  emumain.c
**
**  Description:
**     Michelle main(base) function routine. Include the control procedure.
**
**  Status:  preliminary
**
**  $Log:   S:/tbird/arcppc/fw/860/emumain.c_v  $
** 
**    Rev 1.8   12 Dec 1997 11:28:28   kevin
** Put the version number to IdData so that the SLD is able to check the 
** FW is whether compatiable with SLD or not
** 
**    Rev 1.7   29 Oct 1997 14:03:56   kevin
** warning-free version
** 
**    Rev 1.6   23 Sep 1997 16:46:06   kevin
** added additional parameter to EmuAbort()
** 
**    Rev 1.5   18 Sep 1997 10:36:40   kevin
** added command handlers for SET_ISCT_SER and SET_BKPT_NONMASK
** 
**    Rev 1.4   28 Aug 1997 10:23:04   cjchen
** 
**    Rev 1.3   19 Aug 1997 16:02:16   cjchen
** 
**    Rev 1.2   04 Aug 1997 13:20:18   cjchen
** 
**    Rev 1.1   28 Jul 1997 10:08:10   cjchen
** 
**    Rev 1.0   18 Jul 1997 15:12:56   cjchen
** Initial revision.
** 
** Initial revision.
** 
** Copyright (C) 1997 Microtek International, Inc.
**
*****************************************************************************/

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

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

#ifndef _EMU_BASE_TYPES_
#include "emutypes.h"
#endif

#ifndef _EMU_GLOBAL_
#include "emuglb.h"
#endif

#ifndef _EMU_COMM_
#include "emucomm.h"
#endif

#ifndef _COMM_DATA_
#include "commdata.h"
#endif

#ifndef _EMU_LLFW_
#include "emullfw.h"
#endif

#ifndef _EMU_LIB_
#include "emulib.h"
#endif

#ifndef _EMU_MEM_
#include "emumem.h"
#endif

#ifndef _EMU_EMUL_
#include "emuemul.h"
#endif

#ifndef _EMU_SETUP_
#include "emusetup.h"
#endif

#ifndef _EMU_TRACE_
#include "emutrace.h"
#endif

#include "strings.def"
#include <string.h>
#include <stdlib.h>

extern U8 timeOut;
extern U16 errorFlag;
extern U8 cpuFlag;
extern U32 bankSize;
extern BOOLEAN mtatExist;
           /****************************
            *                          *
            *     LOCAL DEFINITIONS    *
            *                          *
            ****************************/
// Firmware version = Major*10 + Minor
VOID Output(STATUS status,U8 endData);
VOID InitFwControl(VOID);
VOID InitDataBase(VOID);
RETCODE ReceiveInputCommand(VOID);
RETCODE DispatchCommand(U16 *ac, U8 *av[], U8 *cmdStream);
RETCODE ProcessCommand(U16 ac, U8 *av[]);

            /****************************
             *                          *
             *    EXTERNAL VARIABLES    *
             *                          *
             ****************************/

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

/***************************************************************************
**
**  main()
**
**  Description: Michelle main routine, with its linear control process
**               sequence. We always think this fw process with one single
**               task.
**
**  Parameters:
**     input:
**        none
**     output:
**        none
**
****************************************************************************/
U8 sNo,preNo;
main() {
   U16 argc;
   U8 *argv[10];
   char Normal[]={'M','I','C','E'};
   char Debug0[] ={'D','B','U','G'};
   char Debug1[] ={'T','E','S','T'};
   char WrROM[] ={'W','R','O','M'};
   char *SyncPtn[]={ Normal, Debug0, WrROM, Debug1, 0};
   RETCODE errNo;

   if(debug_mode)
     write_str(S_LEAVE);
   switch(CommSync(4,SyncPtn))
   {
     case 0: /* Normal Operation */
       break;
     case 1: /* Debug */
       SetBaud();
     case 3:
       SetWatchDog(100);
       for(timeOut=0;!timeOut;);
//!!       EngTest();
       FwReset();
     case 2: /* Write ROM */
       clear_xlx();
       SetBaud();
       SetWatchDog(100);
       for(timeOut=0;!timeOut;);
       FW_UPGRADE();
     default:
       FwReset();
   }

   fwId = EB;
   InitDataBase(); // all data sets setting or default value.
   InitFwControl(); // Initial hardware and firmware

   while (TRUE) {
      ReceiveStream(); /* read the input commands stream. */
      if(preNo!=sNo)
      {
        preNo=sNo;
        DispatchCommand(&argc, argv, commandStream); // parser the input commands stream.
        errNo = ProcessCommand(argc,argv); // case switching the command tasks
      }
      if (errNo == OK) TransmitStream();
      else EmuReportError(errNo);
      //Output(GOOD,ON);
      //TransmitStream();
   }
   return(GOOD);
}

VOID InitDataBase(VOID) {
   U16 phyCpu,size,timerFlag = 0xff,brokeReason = BROKE;

   noUse = C_OFF = 0;
   C_ON = 1;
   noUseByte = 0;
   AccessIceFlag(READ_ONE,PHY_CPU_TYPE,&phyCpu);
   AccessIceFlag(CLEAR_ALL,noUse,&noUse);// special for timer flag
   AccessIceFlag(WRITE_ONE,PHY_CPU_TYPE,&phyCpu);
   AccessIceFlag(WRITE_ONE,FLY_RUN,&C_OFF);
   //AccessIceFlag(WRITE_ONE,BROKE_REASON,&brokeReason);
   AccessIceFlag(WRITE_ONE,TIMER_FLAG,&noUse);
   //AccessIceFlag(WRITE_ONE,TRACE_BUFF,&bufNum);
   AccessIceFlag(WRITE_ONE,TRACE_BREAK,&C_OFF);
   AccessIceFlag(WRITE_ONE,VERIFY_FLAG,&C_ON);
   AccessIceFlag(WRITE_ONE,BUFFER_FILL,&C_ON);
   AccessStatusFlag(CLEAR_ALL,noUse,&noUse);
   size = S_BYTE;
   AccessIceFlag(WRITE_ONE,SIZE_FLAG,&size);
   AccessIceFlag(WRITE_ONE,TRACE_MODE,&C_OFF);
   //CommRecover();
}

VOID InitFwControl(VOID) {
   U8 status;
//   U16 lp;
//   U32 baseReg[MAX_BASE_REG_NO];
//   U8 vccFlag;
//   U16 action[11],ev[11];
//   U32 mapAddr1,mapAddr2;
//   BUS_EVENT testEvent;
//   QUALIFY_LIST condition;
   U16 len = 8;
//   ADDR addr;
   
   status = GOOD;
   AccessIceFlag(WRITE_ONE,RESET_FLAG,&C_ON);
   idData[FIRMWARE_TYPE] = 'M'; // This is a MICEpack firmware.
   idData[FIRMWARE_VER] = CUR_FW_VER;// version 0.1
   idData[CPU_TYPE] = 0x81; // 0x80=CPU603E, 0x81=CPU860
//   SetClockPhase();

//!!   if (InitialReset(baseReg))
//!!      OutputExceptReason(ON);
   idData[INIT_HW_STATUS] = (U8)(*(U16 *)outputStream);

//   if (iceStartFlag == 0xaaaa) { // Cold start
//      DisableControl();
//      FunctionTest();
//      EnableControl();
//   }
//   vccFlag = Reset(baseReg);
//   TraceReset(); // gene
//   if (iceStartFlag == 0xaaaa) { // Cold start & trace board exist.
//   }
   iceStartFlag = 0x0;
}

/***************************************************************************
**
**  DispatchCommand
**
**  Description: Dispath the input command stream.
**         Note: Please refer input command protocol format.
**
**  Parameters:
**     input:
**        commandStream : input command stream.
**     output:
**        ac      : argument counter.
**        av      : argument position.
**
****************************************************************************/
RETCODE DispatchCommand(U16 *ac, U8 *av[], U8 *cmdStream) {

   *ac = 1;   /* Initial argument. */
   av[0] = cmdStream;
   cmdStream++;
   while ((*cmdStream) && (*cmdStream != 0xff)){
      av[(*ac)++] = cmdStream;
      cmdStream += *cmdStream + 1;
   }
   return(GOOD);
}

/***************************************************************************
**
**  ProcessCommand
**
**  Description: Idnetidy then command ID and call FW function.
**
**  Parameters:
**     input:
**        commandStream : input command stream.
**        ac            : argument counter.
**        av            : argument position.
**     output:
**        outputStream  : the message of executive result.
**
****************************************************************************/
RETCODE ProcessCommand(U16 ac, U8 *av[]) {
   U16 dataLen,flyFlag;
   U32 data[10];
   LOOP_VAR lp;
   STATUS status;

   for (lp = 1; lp < (LOOP_VAR)ac; lp++) {
      dataLen = *(av[lp]);
      switch (dataLen) {
         case 1 : /* byte */
            data[lp] = *(U8 *)(av[lp]+1);
           break;
         case 2 : /* word */
            data[lp] = *(U16 *)(av[lp]+1);
            break;
         case 3 : /* 3 byte */
            data[lp] = *(U32 *)(av[lp]+1) & 0x00ffffff;
            break;
         case 4 : /* long */
            data[lp] = *(U32 *)(av[lp]+1);
            break;
         case 0xff : /* more than 255 */
            data[lp] = *(U16 *)(av[lp]+1);
            break;
         default : /* do nothing */
            data[lp] = 0;
            break;
      }
   }

   if (!ac) return(FALSE);
   status = GOOD;
   AccessIceFlag(READ_ONE,FLYING,&flyFlag);
//   if (flyFlag) EmuGetCpuStatus();
   switch ((COMMAND_ID)(*av[0])) {
      case CHECKSUM :
         EmuChecksum((ADDR *)(av[1]+1),(U32)data[2]);
         break;
      case COMPARE :
         EmuCompare((ADDR *)(av[1]+1), (U32)data[2], (ADDR *)(av[3]+1));
         break;
      case COPY :
         EmuCopy((ADDR *)(av[1]+1), (U32)data[2], (ADDR *)(av[3]+1));
         break;
      //case FUNCTION_TEST :
      //   EmuFunctionTest((U16)data[1]);
      //   break;
      //  only use at run command
      //case ESC_COMMAND :
      //   break;
      //
      case FILL :
         EmuFill((ADDR *)(av[1]+1), (U32)data[2], (U8 *)(av[3]+1), *av[3]);
         break;
      case GET_ID :
         EmuGetID();
         break;
      //case GET_DEPTH :
      //   if (flyFlag) status = INVALID_FLY_COMMAND;
      //   else {
      //      if (mtatExist) EmuGetTraceDepth((U16)data[1]);
      //      else OutputStatus(NO_TRACE_MODULE,ON);
      //   }
      //   break;
      //case GET_MODE :
      //   EmuGetMode();
      //   break;
      case GET_REG :
         EmuGetReg((REG_MODE)data[1], (U16)data[2]);
         break;
      case GET_SIZE :
         EmuGetAccessSize();
         break;
      //case GET_STAT :
      //   EmuGetStatus();
      //   break;
      case GET_VERIFY :
         EmuGetVerify();
         break;
      //case GET_WAIT :
      //   EmuGetWait();
      //   break;
      case GO_COMMAND :
         //if (flyFlag) status = INVALID_FLY_COMMAND;
         //else {
            EmuGo((S16)data[1]);
            return(GOOD);
         //}
         break;
      case HALT :
         EmuHalt();
         break;
      //case INPUT :
      //   EmuInput((U16)data[1], (U16)data[2], (U16)data[3]);
      //   break;
      //case OUTPUT :
      //   EmuOutput((U16)data[1], (U8 *)(av[2]+1), (U16)data[3], (U16)data[4]);
      //   break;
      case READ_MEM_N :
         EmuReadMemN((ADDR *)(av[1]+1), (U16)data[2]);
         break;
      case RESET :
         EmuReset();
         AccessIceFlag(READ_ONE,FLYING,&flyFlag);
         break;
      case SEARCH :
         EmuSearch((ADDR *)(av[1]+1), (U32)data[2], (U8 *)(av[3]+1), *av[3]);
         break;
      case SET_EX_BKPT :
         EmuSetExBkpt((I_WATCHPOINT *)(av[1]+1),(L_ADDR *)(av[2]+1),(L_DATA *)(av[3]+1),
            (L_WATCHPOINT *)(av[4]+1),(WATCHPOINT_COUNTER *)(av[5]+1));
         break;
      //case SET_ID :
      //   EmuSetID((U16)data[1]);
      //   break;
      case SET_MEM_N :
         EmuSetMemN((ADDR *)(av[1]+1), (U8 *)(av[2]+1),(U16)*av[2]);
         break;
      case SET_REG :
         EmuSetReg((REG_MODE)data[1], (U16)data[2],(U32)data[3]);
         break;
      case SET_SIZE :
         EmuSetAccessSize((U16)data[1]);
         break;
      //case SET_TIME_COUNT :
      //   EmuSetTimerCounter((U16)data[1],(U32)data[2]);
      //   break;
      //case SET_TIMER_REG :
      //   EmuEpTimer((U16)data[1]);
      //   break;
      case SET_VERIFY :
         EmuSetVerify((U16)data[1]);
         break;
      //case SET_WAIT :
      //   EmuSetWait((U16)data[1]);
      //   break;
      case STEP :
         if (flyFlag) status = INVALID_FLY_COMMAND;
         else EmuStepRange((ADDR *)(av[1]+1),(ADDR *)(av[2]+1));
         break;
      case STEP_ONE :
         if (flyFlag) status = INVALID_FLY_COMMAND;
         else EmuStepRange(0,0);
         break;
      case TEST :
         EmuTest((ADDR *)(av[1]+1), (U32)data[2]);
         break;
      case GET_CPU_STATUS :
         EmuGetCpuStatus();
         break;
      case ABORT :
         EmuAbort((U16)data[1]);
         AccessIceFlag(READ_ONE,FLYING,&flyFlag);
         break;
      //case DIAGNOSTIC :
      //   EmuDiagnostic();
      //   break;
      case ENABLE_SW_BKPT :
         EmuEnSwBkpt();
         break;
      case DISABLE_SW_BKPT :
         EmuDisSwBkpt();
         break;
      case SET_BKPT_CODE :
         EmuSetBkptCode((BKPT_OP_CODE)data[1]);
         break;
      //case TRACE_RESET :
      //   EmuTraceReset();
      //   break;
      //case GOEP_DELAY :
      //   EmuGoEpDelay((BOOLEAN)data[1]);
      //   break;
      case SET_INT_REG :
         EmuSetIntReg((U16)data[1],(U16)data[2],(U32)(data[3]),(BOOLEAN)data[4]);
         break;
      case GET_INT_REG :
         EmuGetIntReg((U16)data[1],(U16)data[2],(BOOLEAN)data[3]);
         break;
      case GET_UPM:
         EmuGetUpm((U16)data[1],(U16)data[2],(U16)data[3],(U32 *)(av[4]+1));
         break;
      case SET_UPM:
         EmuSetUpm((U16)data[1],(U16)data[2],(U32)data[3]);
         break;
      case SET_BKPT_NONMASK:
         EmuSetBkptNonmask((U16)data[1]);
         break;
      case SET_ISCT_SER:
         EmuSetISCT_SER((U16)data[1]);
         break;
      default :
         Output(GOOD,ON);
         //EmuReportError(COMMAND_ERROR);
   } /* end switch *data[0]. */
//   AccessIceFlag(READ_ONE,FLYING,&flyFlag);
//   if (flyFlag) EmuGetCpuStatus();
//   AccessIceFlag(READ_ONE,FLYING,&flyFlag);
//   if (status == INVALID_FLY_COMMAND) OutputStatus(status,ON);
//   else if (flyFlag && CheckEpStop()) {
//        for (lp = 0; lp < 1000; lp++);
//        StartGo(FLY_RUN);
//   }
   
   return(GOOD);
}

/****************************************************************************
**
**  OutputStatus
**
**  Description: output the status of executive FW to outputStream
**
**  Parameters:
**     input:
**
**     output:
**
**        return data --
**
****************************************************************************/
VOID Output(STATUS status,U8 endData) {

   outputStreamLen = sizeof(status);
   memcpy (&outputStream[0],&status,outputStreamLen);
   if (endData == ON)
      outputStream[outputStreamLen++] = 0x00;/* Output stream length */
}
