/***************************************************************************
**
**  Name:  emutrace.c
**
**  Description:
**     Michelle trace-group routines.
**
**  Status:  preliminary
**
**  $Log:   S:/tbird/arcppc/fw/603e/emutrace.c_v  $
** 
**    Rev 1.0   11 Feb 1997 16:16:58   kevin
** Initial revision.
** 
**    Rev 1.24   17 Dec 1996 10:03:36   gene
** 
**    Rev 1.23   24 Oct 1996 11:22:28   gene
** added TRACE_MODE flag recognize
** 
**    Rev 1.22   15 Oct 1996 19:25:30   gene
** 
**    Rev 1.21   15 Oct 1996 19:22:32   gene
** added TraceEnable parameter type
** 
**    Rev 1.20   08 Oct 1996 13:05:38   gene
** changed GetCpuStatus report result
** 
**    Rev 1.19   02 Oct 1996 17:19:28   gene
** check SRCSTEP_RUN flag ,if set disable trigger setting
** 
**    Rev 1.18   20 Sep 1996 15:18:50   gene
** added real-time trace GetStartPC in not overflew condition
** 
**    Rev 1.17   10 Sep 1996 10:53:32   gene
** added Realtime trace
** 
**    Rev 1.16   14 Aug 1996 10:47:58   gene
** fixed trigger bus event data setting error
** 
**    Rev 1.15   09 Aug 1996 11:01:06   gene
** modify for no delay condition while push reset
** 
**    Rev 1.14   06 Aug 1996 15:48:40   gene
** modify EmuListTrace()
** 
**    Rev 1.13   06 Aug 1996 13:58:28   gene
** added for H/W work around (trace buffer full not delay)
** 
**    Rev 1.12   11 Jul 1996 13:03:46   gene
** added (1) TrcProcResetVector for 4 4 B pattern
**       (2) Check448Pattern for software breakpoint
** 
**    Rev 1.12   11 Jul 1996 10:08:58   gene
** added recognizable pattern 4 4 B for reset exception
** 
**    Rev 1.11   10 Jul 1996 15:36:50   gene
** modify for trace buffer content when reset exception 
** 
**    Rev 1.10   02 Jul 1996 19:16:14   gene
** changed list trace buffer transfer protocol
** 
**    Rev 1.9   02 Jul 1996 11:36:34   gene
** modify GetNextHiNible() prototype and 
** GetStartPC when BUFFER_EMPTY condition
** 
**    Rev 1.8   01 Jul 1996 18:46:26   gene
** modify GetStartPC() for BUFFER_EMPTY condition
** 
**    Rev 1.7   27 Jun 1996 11:48:44   gene
** 
**    Rev 1.6   27 Jun 1996 10:58:52   gene
** added EmuTraceReset()
** 
**    Rev 1.5   27 Jun 1996 09:30:22   gene
** fixed trace buffer empty condition
** 
**    Rev 1.4   17 Jun 1996 08:38:00   gene
** 
**    Rev 1.3   14 Jun 1996 13:52:14   gene
** modify tempTraceBuff length
** 
**    Rev 1.2   11 Jun 1996 17:38:46   gene
** 
**    Rev 1.1   10 Jun 1996 10:57:28   gene
** 
**    Rev 1.0   03 Jun 1996 14:19:10   gene
** Initial revision.
** 
** Copyright (C) 1992 Microtek International, Inc.
**
****************************************************************************/

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

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

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

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

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

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

#ifndef _EMU_EXTERNAL_
#include "emuext.h"
#endif

#include <string.h>
#include <conio.h>
                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
#define MK_FP(seg, ofs) ((VOID _far *) ((((U32) seg) << 16) | ((U16) ofs)))
#define MAX_EXEC_EVENT_NO      1
#define MAX_BUS_EVENT_NO       2
#define BUF_SIZE           0x800 /* 2k */
#define LIST_BUF_SIZE       1024
#define LIST_BUF_LEN        1000
enum { TRC_START = 0, TRC_END, TRC_MID1,
       MAX_TRC_IDX };

enum TC_MODE {TC_COUNT0,TC_COUNT1,TC_TIMER};
EXEC_EVENT execEvent[MAX_EXEC_EVENT_NO];
BUS_EVENT busEvent[MAX_BUS_EVENT_NO];
U16 tcFlag, pstIdx, trcIdx[MAX_TRC_IDX+1];
U16 counter0, counter1;
U8 tempTraceBuff[LIST_BUF_SIZE];

#define addPstIndex() pstIdx++; \
                      pstIdx &= 0x7FFF
#define subPstIndex() pstIdx--; \
                      pstIdx &= 0x7FFF
#define GetPstIndex() pstIdx;
#define SetPstIndex(idx) pstIdx = idx;

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

                        /****************************
                         *                          *
                         *     LOCAL PROTOTYPES     *
                         *                          *
                         ****************************/
VOID SetPhyTrig(VOID);
U16 GetEventTrigMode(BUS_EVENT *aEvent,U16 action);
U8 GetNextHiNible(U8 *pst);
VOID outputTrcData(U8 id,U8 *data,U8 len,U16 *counter);
VOID TrcGetData(U32 dataPtr,U32 *DData,U8 len);
STATUS TrcGetStartPC(U16 *counter,U16 pcIdx);
STATUS TrcGetStartPCNoBreak(U16 *counter,U16 pcIdx,BOOLEAN overFlew);
VOID procExceptHead(U16 *counter);
VOID TrcProcResetVector(U16 *counter);
BOOLEAN Check448Pattern(VOID);
U16 GetStartIndex(U16 *trcIdx,BOOLEAN *overFlew);
VOID TrcTraceReset(VOID);

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

/****************************************************************************
**
**  EmuSetEvent
**
**  Description: Michelle trace-group routine, to define a bus event.
**               Set a bus event, the "addrspec" and "dataspec" are
**               defined as followings:
**               = "0" --> address/data field is not defined
**               = "1" --> address/data field is a single value
**               = "2" --> address/data field is a range value
**               = "3" --> address/data with a mask value.
**
**               "addrhi/datahi" is a wildcard value. "0" means "don't care".
**               EX. wildcard value 0xfffffffc means bit-0 and bit-1 are
**               "don't care".
**
**  Parameters:
**     input:
**     ev_id    -- int,
**     addrspec -- unsigned int,
**     addrlo   -- unsigned long,
**     addrhi   -- unsigned long,
**     dataspec -- unsigned int,
**     datalo   -- unsigned int,
**     datahi   -- unsigned int,
**     stat     -- unsigned int,
**     count    -- int
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**
****************************************************************************/
VOID EmuSetEvent(U16 evId, U8 *busEventData) {
   STATUS status;
   BUS_EVENT locEvent;

   status = GOOD;
   StopRun();
   memcpy(&locEvent,busEventData,sizeof(locEvent));
   status = AccessBusEvent(WRITE_ONE,evId,&locEvent);

   OutputStatus(status,ON);/* Before add other data to outputStream, len - 1 */

}

/****************************************************************************
**
**  AccessBusEvent
**
**  Description:
**
**  Parameters:
**     input:
**
**     output:
**
**        return data --
**
****************************************************************************/
STATUS AccessBusEvent(ACCESS_MODE accessMode, U16 evId, BUS_EVENT *value) {
U16 lp;
BUS_EVENT clrBusEvent;

   evId--;
   memset(&clrBusEvent,0,sizeof(BUS_EVENT));
   clrBusEvent.statusFlag = 1 ;// use status. 1: PowerView, 0: MICEview

   switch (accessMode) {
      case READ_ONE :
         memcpy(value,&busEvent[evId],sizeof(BUS_EVENT));
         break;
      case WRITE_ONE :
         memcpy(&busEvent[evId],value,sizeof(BUS_EVENT));
         busEvent[evId].enable = 1;
         break;
      case READ_ALL :
         memcpy(value,busEvent,sizeof(BUS_EVENT) * MAX_BUS_EVENT_NO);
         break;
      case WRITE_ALL :
         memcpy(busEvent,value,sizeof(BUS_EVENT) * MAX_BUS_EVENT_NO);
         for (lp = 0; lp < MAX_BUS_EVENT_NO; lp++) {
            if (busEvent[lp].enable == OFF)
               memcpy(&busEvent[lp],&clrBusEvent,sizeof(BUS_EVENT));
         }
         break;
      case CLEAR_ONE :
         memcpy(&busEvent[evId],&clrBusEvent,sizeof(BUS_EVENT));
         busEvent[evId].enable= OFF;
         break;
      case CLEAR_ALL :
         for (lp = 0; lp < MAX_BUS_EVENT_NO; lp++) {
            memcpy(&busEvent[lp],&clrBusEvent,sizeof(BUS_EVENT));
            busEvent[lp].enable= OFF;
         }
         break;
   }
   return(GOOD);
};

/****************************************************************************
**
**  AccessExecEvent
**
**  Description:
**
**  Parameters:
**     input:
**
**     output:
**
**        return data --
**
****************************************************************************/
VOID AccessExecEvent(ACCESS_MODE accessMode, U16 evId, EXEC_EVENT *execData) {
   U16 lp;
   EXEC_EVENT clrExecEvent;
   U32 argBuff[3];

   clrExecEvent.enable = OFF;
   clrExecEvent.addr.pos = 0;
   clrExecEvent.addr.space = 0;

   switch (accessMode) {
      case READ_ONE :
         memcpy(execData,&execEvent[evId],sizeof(EXEC_EVENT));
         break;
      case WRITE_ONE :
         execData->enable = ON;
         memcpy(&execEvent[evId],execData,sizeof(EXEC_EVENT));
         //execData->addr.space = TransferSpace(execData->addr.space);
         argBuff[0] = execData->addr.pos;
         argBuff[1] = 0;
         SetBreakPoint(BP_PC,argBuff); // gene
         SetTriggerLevel(BP_PC,BP_NONE);
         AccessStatusFlag(WRITE_ONE,BKPT,&evId);
         break;
      case READ_ALL :
         memcpy(execData,execEvent,sizeof(EXEC_EVENT) * MAX_EXEC_EVENT_NO);
         break;
      case WRITE_ALL :
         memcpy(execEvent,execData,sizeof(EXEC_EVENT) * MAX_EXEC_EVENT_NO);
         for (lp = 0; lp <= 1 ; lp++) {
            //execData[lp].addr.space = TransferSpace(execData[lp].addr.space);
            //SetBreakPoint(); // gene
            if (execData[lp].enable == 0) AccessStatusFlag(CLEAR_ONE,BKPT,&lp);
            else AccessStatusFlag(WRITE_ONE,BKPT,&evId);
         }
         break;
      case CLEAR_ONE :
         memcpy(&execEvent[evId],&clrExecEvent,sizeof(EXEC_EVENT));
         AccessStatusFlag(CLEAR_ONE,BKPT,&evId);
         break;
      case CLEAR_ALL :
         for (lp = 0; lp < MAX_EXEC_EVENT_NO; lp++) {
            memcpy(&execEvent[lp],&clrExecEvent,sizeof(EXEC_EVENT));
            AccessStatusFlag(CLEAR_ONE,BKPT,&lp);
         }
         break;
   }
   //   if (errFlag) return init error or done error.
};

/****************************************************************************
**
**  ReadTraceFrame
**
**  Description:
**
**  Parameters:
**     input:
**
**     output:
**
**        return data --
**
****************************************************************************/
STATUS ReadTraceFrame(U16 frame, TRACE_DATA *frameData,U8 traceMode) {
   return(OK);
}


/****************************************************************************
**
**  ReadTraceCount
**
**  Description:
**
**  Parameters:
**     input:
**
**     output:
**
**        return data --
**
****************************************************************************/
STATUS ReadTraceCount(TRACE_INFO *traceData) {
   return(GOOD);
};

/****************************************************************************
**
**  EmuHalt
**
**  Description: Michelle trace-group routine, to stop the target CPU.
**               Stop execution of target CPU.
**
**  Parameters:
**     input:
**        none
**
**     output:
**        return status code(error-code) in to the output processor.
**        -- O.K. for Normal return
**        -- Fatal Error code return for HW emulator error :
**             BusRq, Reset, NoClock, CPU not Ready ...
**        return data -- "length" + "PC"
**
**
****************************************************************************/
VOID EmuHalt(VOID) {
   STATUS status;
   U32 baseReg[MAX_BASE_REG_NO];
   //U32 pc;

   status = StopEP(baseReg);
   AccessBaseReg(FW_WRITE_ALL,noUse,baseReg);
   TraceDisable(); // gene
   OutputStatus(status,OFF);
   if (status == OK) {
      OutData(sizeof(U32),&(baseReg[BREG_PC]),ON);
   }
   OutEnd();
}

/****************************************************************************
**
**  EmuAbort
**
**  Description: Michelle trace-group routine, to abort the michelle.
**
**  Parameters:
**     input:
**
**     output:
**
**        return data -- "length" + "PC" + "brealFlag"
**
**
****************************************************************************/
VOID EmuAbort(VOID) {
   STATUS status, flgViolation=0;
   U8 goEndFlag = 0;
   //U16 traceBufNo,cnt0,cnt1;
   U16 traceing;
   U32 baseReg[MAX_BASE_REG_NO];
   //U32 tmpCnt;

   goEndFlag = 1;

   StopEP(baseReg); // gene
   AccessBaseReg(FW_WRITE_ALL,noUse,baseReg);
   switch (status = EPstatus(baseReg)) {
      case 0:
         break;
      case 1:
         status = HALT_USER;
         break;
      case 2:
         status = SW_BKPT_HALT;
         break;
      case 4:
         status = BKPT1_HALT;
         break;
      case 8: // check exceptBreak
         break;
   }
   AccessIceFlag(WRITE_ONE,FLYING,&C_OFF);
   AccessIceFlag(WRITE_ONE,RUNNING,&C_OFF);
   AccessIceFlag(WRITE_ONE,BROKE_REASON,&status);
   AccessIceFlag(READ_ONE,TRACEING,&traceing);
   if (traceing) {
      TraceDisable(); // gene
      AccessIceFlag(WRITE_ONE,TRACEING,&C_OFF);
   }
   if (exceptBreak) 
      OutputExceptReason(OFF);
   else if (flgViolation != GOOD) 
      OutputStatus(flgViolation,OFF);
   else
      OutputStatus(status,OFF);
   OutData(1,&goEndFlag,OFF);
   OutEnd();

}

/****************************************************************************
**
** EmuGo
**
**  Description: Michelle trace-group routine, to set the target CPU free
**               running. Default free running target CPU from current PC.
**
**  Parameters:
**     input:
**        mode -- int
**        addr -- unsigned long
**
**     output:
**        return status code(error-code) in to the output processor.
**        status-code = "BROKE"     --> Program broke at breakpoint.
**        status-code = "USER_HALT" --> Aborted by user.
**        status-code = "HALT"      --> Target CPU Halted.
**
**        return data -- "length" + "PC" + "brealFlag"
**
**  NOTE: The firmware should reserve an execution breakpoint to be used
**        as the temporary breakpoint implementation.
**
****************************************************************************/
U8 timeFlag,timeOver;
STATUS StartGo(S16 mode) {
//   U32 baseReg[MAX_BASE_REG_NO];
   U16 evId, trcBreak;
   EXEC_EVENT execEvt;
   U32 buf[3];
//   STATUS status = GOOD;

   AccessIceFlag(WRITE_ONE,EP_RUN,&C_OFF);
   if (mode == FLY_RUN) AccessIceFlag(WRITE_ONE,FLYING,&C_ON);
   evId = 0;
   AccessStatusFlag(READ_ONE,BKPT,&evId);
   if (evId) {
      AccessExecEvent(READ_ONE,0,&execEvt);
      buf[0] = execEvt.addr.pos;
      buf[1] = 0;
      SetBreakPoint(BP_PC,buf);
      SetTriggerLevel(BP_PC,BP_NONE);
   } else {
      if (mode != SRCSTEP_RUN)
         SetPhyTrig();
   }
   TrcTraceReset();
   AccessIceFlag(READ_ONE,TRACE_BREAK,&trcBreak);
   AccessIceFlag(WRITE_ONE,TRACE_MODE,&trcBreak);
   if (trcBreak == 2)
      AccessIceFlag(WRITE_ONE,BUFFER_FILL,&C_OFF);
   else
      AccessIceFlag(WRITE_ONE,BUFFER_FILL,&C_ON);
   TraceEnable((U8)(trcBreak&0xFF)); // gene
   GoEP();
   AccessIceFlag(WRITE_ONE,RUNNING,&C_ON);
   AccessIceFlag(WRITE_ONE,BROKE_REASON,&C_ON);
   AccessIceFlag(WRITE_ONE,TRACEING,&C_ON);
   timeOver = timeFlag = 0;
   return(GOOD);
}

VOID EmuGo(S16 mode) {
STATUS status;

   status = StartGo(mode);
   if (exceptBreak != GOOD) OutputExceptReason(ON);
   else OutputStatus(status,ON);
}

/****************************************************************************
**
** EmuGetCpuStatus
**
**  Description: Michelle trace-group routine, to set the target CPU free
**              running. Default free running target CPU from current PC.
**               "mode" is to indicate the mode of free-running.
**               "mode" = 1 --> no temporary breakpoint is specified.
**               "mode" = 2 --> set temporary breakpoint at "addr" location
**
**  Parameters:
**     input:
**        mode -- int
**        addr -- unsigned long
**
**     output:
**        return status code(error-code) in to the output processor.
**        status-code = "BROKE"     --> Program broke at breakpoint.
**        status-code = "USER_HALT" --> Aborted by user.
**        status-code = "HALT"      --> Target CPU Halted.
**
**        return data -- "length" + "PC" + "brealFlag"
**
**  NOTE: The firmware should reserve an execution breakpoint to be used
**        as the temporary breakpoint implementation.
**
****************************************************************************/
VOID EmuGetCpuStatus(VOID) {
   STATUS status,brokeReason;
   U8 goEndFlag = 0;
   U32 baseReg[MAX_BASE_REG_NO];
   //U16 traceBufNo,cnt0,cnt1,flyFlag,syncIn,epRun,runFlag;
   U16 runFlag;
   //U32 tmpCnt;

   status = GOOD;
   AccessIceFlag(READ_ONE,RUNNING,&runFlag);
   if (runFlag == OFF) {
      AccessIceFlag(READ_ONE,BROKE_REASON,&brokeReason);
      status = brokeReason;
      goEndFlag = 1;
   } else {
      switch (status = EPstatus(baseReg)) {
         case 0:
            break;
         case 1:
            status = HALT_USER;
            break;
         case 2:
            status = SW_BKPT_HALT;
            break;
         case 4:
            status = TRIG_HALT;
            break;
         case 8: // check exceptBreak
         default:
            break;
      }
      if (status != GOOD) {
         AccessIceFlag(WRITE_ONE,FLYING,&C_OFF);
         AccessIceFlag(WRITE_ONE,RUNNING,&C_OFF);
         AccessIceFlag(WRITE_ONE,BROKE_REASON,&status);
         AccessIceFlag(WRITE_ONE,TRACEING,&C_OFF);
         AccessBaseReg(FW_WRITE_ALL,noUse,baseReg);
         goEndFlag = 1;
         TraceDisable();
      }
   }
   if (exceptBreak) OutputExceptReason(OFF);
   else if (status == GOOD) {
//      if (flyFlag) OutputStatus(CPU_FLY,OFF);
//      else OutputStatus(GOOD,OFF);
      OutputStatus(GOOD,OFF);
   }
   else OutputStatus(status,OFF);
   OutData(1,&goEndFlag,OFF);
   OutEnd();
}

/***************************************************************************
**
**  EmuSetExBkpt
**
**  Description: Michelle trace-group routine, to define an execution
**               brekpoint. (Set an execution breakpoint.)
**
**  Parameters:
**     input:
**        evId --
**        addr  --
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**
****************************************************************************/
VOID EmuSetExBkpt(U16 evId, ADDR *addr) {
EXEC_EVENT execEvent;

   StopRun();
   execEvent.addr.pos = addr->pos; // gene
   execEvent.addr.space = addr->space;
   evId -= 10;
   AccessExecEvent(WRITE_ONE,evId,&execEvent);
   AccessStatusFlag(WRITE_ONE,BKPT,&evId);

   OutputStatus(GOOD,ON);/* Before add other data to outputStream, len - 1 */

}

/***************************************************************************
**
**  EmuClrEvent
**
**  Description: Michelle trace-group routine, to clear the setting of
**               event(s) -- bus or execution breakpoint.
**
**  Parameters:
**     input:
**        ev_id -- int
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**
****************************************************************************/
VOID EmuClrEvent(U16 evId) {
STATUS status;

   status = GOOD;
   if (evId == 0x0) {              // clear all events
      AccessExecEvent(CLEAR_ALL,noUse,(EXEC_EVENT *)&noUse);
      AccessBusEvent(CLEAR_ALL,noUse,(BUS_EVENT *)&noUse);
   } else if (evId == 0xFFFF) {   // clear all bus events
      AccessBusEvent(CLEAR_ALL,noUse,(BUS_EVENT *)&noUse);
   } else if (evId >=1 && evId <= 8)
      AccessBusEvent(CLEAR_ONE,noUse,(BUS_EVENT *)&noUse);
   else if (evId == 10 || evId == 11) 
      AccessExecEvent(CLEAR_ONE,evId-10,(EXEC_EVENT *)&noUse);

   OutputStatus(status,ON);
}

/***************************************************************************
**
**  EmuGetEvent
**
**  Description: Michelle trace-group routine, to clear the setting of
**               event(s) -- bus or execution breakpoint.
**
**  Parameters:
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**
****************************************************************************/
VOID EmuGetAllEvent(VOID) {
   U8 totalLen,lp;
   //U8 tempEvBuff[256];
   BUS_EVENT tempEvBuff[MAX_BUS_EVENT_NO];

   totalLen = sizeof(BUS_EVENT) * MAX_BUS_EVENT_NO +
              sizeof(EXEC_EVENT) * MAX_EXEC_EVENT_NO;
   OutLength(totalLen);

   AccessBusEvent(READ_ALL,noUse,tempEvBuff);
   for (lp = 0; lp < MAX_BUS_EVENT_NO; lp++)
      OutData(sizeof(BUS_EVENT),(U8 *)(&tempEvBuff[lp]),OFF);
   //OutData(sizeof(BUS_EVENT) * MAX_BUS_EVENT_NO,(U8)tempEvBuff,OFF);

   AccessExecEvent(READ_ALL,noUse,(EXEC_EVENT *)tempEvBuff);
   OutData(sizeof(EXEC_EVENT) * MAX_EXEC_EVENT_NO,tempEvBuff,OFF);

   OutData(sizeof(tcFlag),&tcFlag,OFF);
   OutData(sizeof(counter0),&counter0,OFF);
   OutData(sizeof(counter1),&counter1,OFF);
   OutEnd();

}

/***************************************************************************
**
**  EmuListTrace
**
**  Description: Michelle trace-group routine, to list raw data from the
**               trace buffer.
**               List trace buffer content in RAW data format which is
**               similar to the output of LOSTAN command in MICE-III.
**               The "frame" is the starting listing frame. If "frame" is
**               "-1", <ew MICE will return the number of frames in the
**               trace buffer.
**
**  Parameters:
**     input:
**        frame -- U16
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**        list trace -- ("length" + "frame_data") *
**                      (min(256, "rest_frames_ in_trace_buffer"))
**        return count -- "length" + "number"
**
****************************************************************************/
VOID EmuListTrace(U8 firstTime) {
STATUS status;
U16 BuffCount = 0, trcMode, bufferFill;
U8 flagRead;
BOOLEAN overFlew;

   StopRun();
   AccessIceFlag(READ_ONE,TRACE_MODE,&trcMode);
   AccessIceFlag(READ_ONE,BUFFER_FILL,&bufferFill);
   if (bufferFill == 0) {
      OutputStatus(BUFFER_EMPTY,ON);
      return;
   }

   if (firstTime) {
      TraceStatus(trcIdx);
      if (trcIdx[TRC_START] == 0 && trcIdx[TRC_END] == 0) {
         OutputStatus(BUFFER_EMPTY,ON);
         return;
      }
      switch (trcMode) {
      case 1:
         pstIdx = trcIdx[TRC_START]; // gene
         if (TrcGetStartPC(&BuffCount,0) != GOOD) {
            OutputStatus(BUFFER_EMPTY,ON);
            return;
         }
         break;
      case 0:
         pstIdx = GetStartIndex(trcIdx,&overFlew); // gene*
         if (TrcGetStartPCNoBreak(&BuffCount,0,overFlew) != GOOD) {
            OutputStatus(BUFFER_EMPTY,ON);
            return;
         }
         break;
      default:
         OutputStatus(BUFFER_EMPTY,ON);
         return;
      }
   }
   status = ListTraceBuffer(&BuffCount,&flagRead,trcMode);
   OutputStatus(status,OFF);
   OutData(1,&flagRead,OFF);
   memcpy(&outputStream[outputStreamLen],&BuffCount,sizeof(BuffCount));
   outputStreamLen += sizeof(BuffCount);
   memcpy(&outputStream[outputStreamLen],tempTraceBuff,BuffCount);
   outputStreamLen += BuffCount;
   OutEnd();
}

STATUS ListTraceBuffer(U16 *counter,U8 *flagRead,U16 trcBreak) {
   U16 instCount = 0;
   U8 state = 0, PST, len;
   U32 DData;
   BOOLEAN pstProcess = TRUE;

   while ((pstIdx != trcIdx[TRC_END] && *counter < LIST_BUF_LEN) || !pstProcess) {
      if (pstProcess)
         GetNextHiNible(&PST);
      if ((pstIdx == (trcIdx[TRC_MID1]+1)) && (pstIdx != (trcIdx[TRC_START]+1))) {
         if (state == 1 || state == 5) {
            outputTrcData(state,(U8*)&instCount,2,counter);
            instCount = 0;
         }
         if (trcBreak == 1)
            TrcGetStartPC(counter,1);
//         else                                 // gene*
//            TrcGetStartPCNoBreak(counter,1);  // gene*
         state = 0;
         pstProcess = TRUE;
         if (GoEP_dly)
            GetNextHiNible(&PST);
      }
      if (PST == 4) {                       // if PST == 4 check for special pattern 4,4,8
         if (Check448Pattern() && GoEP_dly) // take PST id 4 as normal instruction.
            TrcGetStartPC(counter,0);       // transfer PST id 4 as 1. gene
         else
            PST = 1;
      }
      switch(state) {
      case 0 :
         switch(PST) {
         case 1 :
         case 5 :
            state = PST;
            instCount++;
            break;
         case 3 :
            outputTrcData(PST,(U8*)&PST,0,counter);
            break;
         case 8 :
         case 9 :
         case 0xA :
         case 0xB :
            len = (U8)(PST - 7);
            TrcGetData(pstIdx,&DData,len);
            outputTrcData(PST,(U8*)&DData,len,counter);
            break;
         case 0xC :
            procExceptHead(counter);
            break;
         default:;
         }
         pstProcess = TRUE;
         break;
      case 1 :
      case 5 :
         if (PST == state) {
            instCount++;
            pstProcess = TRUE;
         } else {
            outputTrcData(state,(U8*)&instCount,2,counter);
            state = 0;
            pstProcess = FALSE;
            instCount = 0;
         }
         break;
      default :;
      }
   }
   if (state == 1 || state == 5)
      outputTrcData(state,(U8*)&instCount,2,counter);

   if (pstIdx == trcIdx[TRC_END]) {
      tempTraceBuff[(*counter)++] = 7;
      *flagRead = 0;
   } else
      *flagRead = 1;
   return(GOOD);
}

VOID procExceptHead(U16 *counter) {
   U8 pst, DData[5];

   DData[4] = 0; // always is supervisor mode
   while ((GetNextHiNible(&pst) == GOOD) && (pst == 0xC));
   if (pst == 5) {
      TrcProcResetVector(counter);
   } else {
      while ((GetNextHiNible(&pst) == GOOD) && (pst != 5)) {
         if (pst == 0xB) {
            TrcGetData(pstIdx,(U32 *)DData,4);
            outputTrcData(pst,DData,4,counter);
         }
      }
      while ((GetNextHiNible(&pst) == GOOD) && (pst != 0xB));
      TrcGetData(pstIdx,(U32 *)DData,4);
      outputTrcData(0,DData,5,counter);
   }
}

U8 GetNextHiNible(U8 *pst) {
   U8 retVal;

   while (((*pst=(U8)HiNible(TraceBuffer[(U16)pstIdx])) == 0) &&
            (pstIdx != trcIdx[TRC_END])) {
      addPstIndex();
   }
   if (pstIdx != trcIdx[TRC_END]) {
      addPstIndex();
      retVal = GOOD;
   } else
      retVal = (U8)TRC_END;
   return(retVal);
}

VOID outputTrcData(U8 id,U8 *data,U8 len,U16 *counter) {
   U8 T255 = 0xFF;
   U16 instNo;

   switch(id) {
      case 3:
         id = 8;
         break;
      case 8:
      case 9:
      case 0xA:
      case 0xB:
         id -= 5;
         break;
      case 5:
         id = 2;
      case 1:
         instNo = *(U16 *)data;
         if (instNo <= 0xF) {
           id += (*data << 4);
           len = 0;
           tempTraceBuff[(*counter)++] = id;
         } else {
           for (; 255 < instNo; instNo -= 255) {
              tempTraceBuff[(*counter)++] = id;
              memcpy(tempTraceBuff+(*counter),&T255,1);
              (*counter)++;
           }
           tempTraceBuff[(*counter)++] = id;
           memcpy(tempTraceBuff+(*counter),&instNo,1);
           (*counter)++;
         }
         return;
   }

   tempTraceBuff[(*counter)++] = id;
   if (len != 0) {
      memcpy(tempTraceBuff+(*counter),data,len);
      *counter += len;
   }
}

VOID TrcGetData(U32 dataIdx,U32 *DData,U8 len) {
   U32 tmpValue;
   U8 i;

   *DData = 0;
   for (i = 0; i < (U8)(len*2); i++, dataIdx++) {
      tmpValue = (U32)LowNible(TraceBuffer[(U16)dataIdx]);
      *DData = *DData + (tmpValue << (4*i));
   }
}

STATUS TrcGetStartPC(U16 *counter,U16 pcIdx) {
   U8 DData[5]; // [0-3] PC value, [4] space : 0 supervisor, 1 user
   U8 pst;

   DData[4] = 0;
   if (GoEP_dly == 0) {
      memcpy(DData,&(Trace_PC[pcIdx]),4);
      outputTrcData(0,DData,5,counter);
   } else {
      while ((GetNextHiNible(&pst) == GOOD) && (pst == 0x4));
      if (pst == 0xB) {
         TrcProcResetVector(counter);
      } else {
         while ((GetNextHiNible(&pst) == GOOD) && (pst != 7)); // find RTE
         if (pstIdx == trcIdx[TRC_END])
            return(BUFFER_EMPTY);
         while ((GetNextHiNible(&pst) == GOOD) && (pst != 5)) {
            switch(pst) {
            case 3 :
               DData[4] = 1;
               break;
            case 0xB :
               TrcGetData(pstIdx,(U32 *)DData,4);
               break;
            }
         }
         outputTrcData(0,DData,5,counter);
         while ((GetNextHiNible(&pst) == GOOD) && (pst != 0xB));
      }
  }
   return(GOOD);
}

STATUS TrcGetStartPCNoBreak(U16 *counter,U16 pcIdx,BOOLEAN overFlew) {
   U8 DData[5]; // [0-3] PC value, [4] space : 0 supervisor, 1 user
   U8 pst;
//   U16 tmpPstIdx;
   U32 adrData1,adrData2;

   DData[4] = 0;

   if (!overFlew) {
      memcpy(DData,&(Trace_PC[pcIdx]),4);
      outputTrcData(0,DData,5,counter);
   } else {
      while (1) {
         while ((GetNextHiNible(&pst) == GOOD) && (pst != 0xB)); //+
         if (pstIdx == trcIdx[TRC_END])                          //+
            return(BUFFER_EMPTY);                                //+
         TrcGetData(pstIdx,&adrData1,4);                         //+
         if (GetNextHiNible(&pst) != GOOD)                       //+
            return(BUFFER_EMPTY);                                //+
         if (pst != 5)  {                                        //+
            subPstIndex();                                       //+
            continue;                                            //+
         }                                                       //+
         if (GetNextHiNible(&pst) != GOOD)                       //+
            return(BUFFER_EMPTY);                                //+
         if (pst != 0xB) {                                       //+
            subPstIndex();                                       //+
            continue;                                            //+
         }
         TrcGetData(pstIdx,&adrData2,4);                         //+
         if (adrData1 == adrData2) break;                        //+
         subPstIndex();

      }
      memcpy(DData,&adrData2,4);
      outputTrcData(0,DData,5,counter);
   }
   return(GOOD);
}

U16 GetStartIndex(U16 *trcIdx,BOOLEAN *overFlew) {
   U16 i;

   *overFlew=FALSE;
   if (trcIdx[TRC_END] >= 0x7FF7)
      return(0);
   for (i = 0x7FF7; i <= 0x7FFF; i++)
      if ((U8)TraceBuffer[i] != 0xFF) {
         *overFlew = TRUE;
         break;
      }
   if (*overFlew)
      return(trcIdx[TRC_END]+1);
   else
      return(0);
}

VOID TrcProcResetVector(U16 *counter) {
   U8 pst, loPst, i, DData[5];

   DData[4] = 0;
   if (GoEP_dly) {
      while ((GetNextHiNible(&pst) == GOOD) && (pst != 7));
      while ((GetNextHiNible(&pst) == GOOD) && (pst != 5));
      while ((GetNextHiNible(&pst) == GOOD) && (pst != 0xB));
      TrcGetData(pstIdx,(U32 *)DData,4);
      outputTrcData(0,DData,5,counter);
      pst = 0xB;
      for (i=0; i<2 ;i++)
         outputTrcData(pst,(U8*)&(Reset_Vector[i]),4,counter);
   } else {
      loPst = (U8)LowNible(TraceBuffer[(U16)(pstIdx-2)]);
      if (loPst == 0) {
         while ((GetNextHiNible(&pst) == GOOD) && (pst != 0xC));
      }
      while ((GetNextHiNible(&pst) == GOOD) && (pst != 0xB));
      TrcGetData(pstIdx,(U32 *)DData,4);
      outputTrcData(0,DData,5,counter);
   }
}

BOOLEAN Check448Pattern(VOID) {

   if ((HiNible(pstIdx) == 0x4) && (HiNible(pstIdx) == 0x8))
      return(TRUE);
   return(FALSE);
}

/***************************************************************************
**
**  EmuGetTraceInfo
**
**  Description: Michelle trace-group routine, to set the trace mode.
**
**  Parameters:
**     input:
**        mode -- U8
**
**     output:
**        "O.K." -- Normal return
**
****************************************************************************/
VOID EmuGetTraceInfo(VOID) {
   U16 lastBufNo=0,cnt0=0,cnt1=0,traceBufNo=0;

//   AccessIceFlag(READ_ONE,TRACED_BUFF_NO,&lastBufNo);
//   AccessIceFlag(READ_ONE,COUNTER1,&cnt1);
//   AccessIceFlag(READ_ONE,COUNTER0,&cnt0);
//   AccessIceFlag(READ_ONE,TRACE_BUFF,&traceBufNo);

   OutputStatus(GOOD,OFF);

   OutData(sizeof(lastBufNo),&lastBufNo,OFF);

   OutData(sizeof(cnt1),&cnt1,OFF);

   OutData(sizeof(cnt0),&cnt0,OFF);

   OutData(sizeof(traceBufNo),&traceBufNo,OFF);

   OutEnd();
}

/***************************************************************************
**
**  EmuSetTraceBreak
**
**  Description: Michelle trace-group routine, to set the trace mode.
**
**  Parameters:
**     input:
**        mode -- U8
**
**     output:
**        "O.K." -- Normal return
**
****************************************************************************/
VOID EmuSetTraceBreak(U16 breakFull) {
//STATUS status;
//TRIG_LOC traceDelay;
//U16 traceBufNum;

//   status = GOOD;
//   AccessIceFlag(READ_ONE,TRACE_MODE,&traceDelay);
//   AccessIceFlag(READ_ONE,TRACE_BUFF,&traceBufNum);
   AccessIceFlag(WRITE_ONE,TRACE_BREAK,&breakFull);
//   status = ConfigTrace(traceBufNum,traceDelay,(BOOLEAN)breakFull);

   OutputStatus(GOOD,ON);/* Before add other data to outputStream, len - 1 */
}

/***************************************************************************
**
**  EmuGetTraceDepth
**
**  Description: Michelle trace-group routine, to set the trace mode.
**
**  Parameters:
**     input:
**        mode -- U8
**
**     output:
**        "O.K." -- Normal return
**
****************************************************************************/
VOID EmuGetTraceDepth(U16 traceBufId) {
   STATUS status;
   U16 buffFill;
   //U8 tempDepthBuff[8];

   status = GOOD;
   AccessIceFlag(READ_ONE,BUFFER_FILL,&buffFill);
   if (buffFill == ON) {
   }
   else OutputStatus(BUFFER_EMPTY,ON);
}

VOID EmuTraceReset(VOID) {
   TraceReset();
   OutputStatus(GOOD,ON);
}

/***************************************************************************
**
**  EmuClrTrig()
**
**  Description: Michelle trace-group routine, to clear the trigger setting.
**
**  Parameters:
**     input:
**        none
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**
****************************************************************************/
VOID EmuClrTrig(U16 levelNo) {
U16 lp,action[11],ev[11];;

   for (lp = 0; lp < 11; lp++)
      ev[lp] = action[lp] = 0;
   if (levelNo == 0x0) { // Clear all trigger.
      for (lp = 1; lp <= TRIG_NO; lp++)
         EmuSetTrig(lp,ev,action,1);
   }
   else EmuSetTrig(levelNo,ev,action,1);
   OutputStatus(GOOD,ON);/* Before add other data to outputStream, len - 1 */
}

/***************************************************************************
**
**  EmuGetTrig
**
**  Description: Michelle trace-group routine, to define the trigger setting.
**
**  Parameters:
**     input:
**        ******* this function will be defined later............
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**
****************************************************************************/
VOID EmuGetAllTrig(VOID) {
U8 dataLen,lp;

   OutputStatus(GOOD,OFF);
   dataLen = sizeof(TRIGGER);
   for (lp = 0; lp < TRIG_NO; lp++) {
      OutData(dataLen,&trigLevel[lp],ON);
   }
   OutEnd();
}

/***************************************************************************
**
**  EmuSetTrig
**
**  Description: Michelle trace-group routine, to define the trigger setting.
**
**  Parameters:
**     input:
**        ******* this function will be defined later............
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**
****************************************************************************/
VOID EmuSetTrig(U16 levelNo, U16 *events, U16 *actions,U16 mode) {

   AccessIceFlag(WRITE_ONE,PHY_TRIG_SET,&C_OFF);
   if (levelNo <= TRIG_NO) {
      levelNo--;
      if (events[0] != 0)
         trig.defined = ON;  // event setted
      else
         trig.defined = OFF; // no event setted
      memcpy(trig.ev,events,11*2);
      memcpy(trig.act,actions,11*2);
      memcpy(&trigLevel[levelNo],&trig,sizeof(TRIGGER));
   }
   OutputStatus(GOOD,ON);
}

/***************************************************************************
**
**  SetPhyTrig
**
**  Description: Michelle trace-group routine, to define the trigger setting.
**
**  Parameters:
**     input:
**        ******* this function will be defined later............
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**
****************************************************************************/
VOID SetPhyTrig() {
   BUS_EVENT tmpEvent;
   TRIGGER *trig;
   U16 trigL1Mode = 0, trigL2Mode = 0;

   SetTriggerLevel(BP_NONE,BP_NONE);

   trig = &trigLevel[0];
   AccessBusEvent(READ_ONE,trig->ev[0],&tmpEvent);
   if (tmpEvent.enable && trig->defined) {
      trigL1Mode = GetEventTrigMode(&tmpEvent,trig->act[0]);

      trig = &trigLevel[1];
      AccessBusEvent(READ_ONE,trig->ev[0],&tmpEvent);
      if (tmpEvent.enable && trig->defined)
         trigL2Mode = GetEventTrigMode(&tmpEvent,trig->act[0]);
   }
   SetTriggerLevel(trigL1Mode,trigL2Mode);
}

/****************************************************************************
**
**  EmuSetTimerCounter
**
**  Description: Michelle trace-group routine, to define the trigger setting.
**
**  Parameters:
**     input:
**        ******* this function will be defined later............
**
**     output:
**        return status code(error-code) in to the output processor.
**        "O.K." -- Normal return
**        "Fatal error on emulator" -- Fatal HW error; check status-code
**
*****************************************************************************/
VOID EmuSetTimerCounter(U16 setFlag, U32 setData) {

   switch (setFlag) {
      case TC_COUNT0 :
         if (tcFlag ==  2) counter1 = 0;
         counter0 = (U16)(setData-1);
         break;
      case TC_COUNT1 :
         if (tcFlag ==  2) counter0 = 0;
         counter1 = (U16)(setData-1);
         break;
      case TC_TIMER :
         setData--;
         counter0 = (U16)(setData & 0x3ff);
         counter1 = (U16)(setData >> 10) & 0x3ff;
         //if (counter0 == 0) counter0 = 1;
         break;
   }
   AccessIceFlag(WRITE_ONE,PHY_TRIG_SET,&C_OFF);
   tcFlag = setFlag;
   OutputStatus(GOOD,ON);
}

/****************************************************************************
**
**  GetEventTrigMode
**
**  Description: Michelle trace-group routine, to define the trigger setting.
**
**  Parameters:
**     input:
**        BUS_EVENT aEvent
**
**     output:
**        return Trigger_Mode
**
*****************************************************************************/
U16 GetEventTrigMode(BUS_EVENT *aEvent,U16 action) {
   U16 mode = 0;
   U32 buf[3];
   U16 attr, attrMask, tmpAttr, tmpAttrMask;

   switch(action) {
   case 2:   /* PC breakpoint action */
      buf[0] = aEvent->addrLow;
      buf[1] = ~(aEvent->addrHigh);
      SetBreakPoint(BP_PC,buf);
      if (aEvent->notCondition & 0x01)
         mode = BP_PCInv;
      else
         mode = BP_PC;
      break;
   case 4:   /* bus breakpoint action */
      if (aEvent->addrLow != 0 || aEvent->addrHigh != 0) {
         switch(aEvent->addrSpec) {
         case 1:
            buf[0] = aEvent->addrLow;
            buf[1] = 0;
            SetBreakPoint(BP_SAddr,buf);
            mode |= BP_SAddr;
            break;
         case 2:
            buf[0] = aEvent->addrLow;
            buf[1] = aEvent->addrHigh;
            SetBreakPoint(BP_RAddr,buf);
            mode |= BP_RAddr;
            break;
         case 3:
            buf[0] = aEvent->addrLow;
            buf[1] = ~(aEvent->addrHigh);
            SetBreakPoint(BP_SAddr,buf);
            mode |= BP_SAddr;
            break;
         }
         if (aEvent->notCondition & 0x01)
            mode |= BP_AddrInv;
      }

      if (aEvent->dataLow != 0 || aEvent->dataHigh != 0) {
         switch(aEvent->dataSpec) {
         case 1:
            buf[0] = aEvent->dataLow;
            buf[1] = 0;
            mode |= BP_DLong;
            SetBreakPoint(BP_DLong,buf);
            break;
         case 3:
            buf[0] = aEvent->dataLow;
            buf[1] = ~(aEvent->dataHigh);
            mode |= BP_DLong;
            SetBreakPoint(BP_DLong,buf);
            break;
         }
         if (aEvent->notCondition & 0x02)
            mode |= BP_DInv;
      }

      if (aEvent->status2.status2High != 0) {
         tmpAttr = (U16)aEvent->status2.status2Low;
         tmpAttrMask = (U16)aEvent->status2.status2High;
         buf[0] = attr = attrMask = 0;
         attr |= (tmpAttr & 0x00E0) >> 5;
         attr |= (tmpAttr & 0x0010) << 3;
         attr |= (tmpAttr & 0x0003) << 5;
         attr |= (tmpAttr & 0x0300) >> 5;
         attrMask |= (tmpAttrMask & 0x00E0) >> 5;
         attrMask |= (tmpAttrMask & 0x0010) << 3;
         attrMask |= (tmpAttrMask & 0x0003) << 5;
         attrMask |= (tmpAttrMask & 0x0300) >> 5;
         buf[0] = ((~attrMask) << 8) + attr;
         SetBreakPoint(BP_Attrib,buf);
      } else {
         buf[0] = 0xFF00;
         SetBreakPoint(BP_Attrib,buf);
      }
      break;
   default: break;
   }
   return(mode);
}

VOID EmuGoEpDelay(BOOLEAN delay) {
   GoEP_dly = delay;
   OutputStatus(GOOD,ON);
}

VOID TrcTraceReset() {
   U16 i;

   TraceReset();
   for (i = 0x7FF7; i <= 0x7FFF; i++)
      TraceBuffer[i] = 0xFF;
}
/******************************** E O F ***********************************/
