/****************************************************************************
**
**  Name:  dq16.cpp
**
**  Description:
**     This is a dequeuer for Motorola hc16.
**
**  Status:
**
**  $Log:   S:/tbird/mt2_186/dad186/dq16.cpv  $
** 
**    Rev 1.0   16 Dec 1996 15:13:48   Judy
** Initial revision.
** 
**    Rev 1.11   05 Sep 1994 18:14:30   mindy
** changed interface to support linked cursors better
** 
**    Rev 1.10   30 Jun 1994 08:15:14   mindy
** FW_LINES structure changed
** 
**    Rev 1.9   01 Sep 1993 21:44:32   mindy
** removed last frame crud - not used anymore
** 
**    Rev 1.8   28 Jul 1993 13:25:14   ernie
** (For Mindy) Free dq buffer in error cases.
** 
**    Rev 1.7   27 Jul 1993 15:35:28   john
** Added extra space to accomodate extra space added to ts display
** 
**    Rev 1.6   24 Jul 1993 13:47:08   mindy
** update starting frame number for _dt command
** 
**    Rev 1.5   22 Jul 1993 10:28:42   ernie
** (For Mindy): Added support for dqeueuer backup and timestamp.
** 
**    Rev 1.4   19 Jul 1993 07:32:10   ernie
** Removed firmware error def file error.h.  All errors now in errcodec.h
** 
**    Rev 1.3   13 Jul 1993 19:23:32   doug
** Errors consolidated in errtext/mkerrors.h and use generic syntax error
** 
**    Rev 1.2   15 Jun 1993 11:30:14   mindy
** Added check for end of buffer in DqInsts.
** 
**    Rev 1.1   25 May 1993 12:07:42   ernie
** Changed dasmSym to be system-wide global
** 
**    Rev 1.0.1.0   16 Jun 1993 09:30:16   mindy
** Added check for end of buffer in DqInsts.
** 
**    Rev 1.0   08 Apr 1993 09:42:52   doug
** Initial revision.
** 
**    Rev 1.1   30 Mar 1993 16:12:54   ernie
** (for mindy): added symbol support
** 
**    Rev 1.0   12 Mar 1993 09:51:34   mindy
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/dad186/dq16.cpv   1.0   16 Dec 1996 15:13:48   Judy  $
**
**  Copyright (C) 1993 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

#ifndef _DADDEF16_
#include "daddef16.h"
#endif

#ifndef _DAD_SERVER_
#include "dasm.h"
#endif

#ifndef _DTINFO16_
#include "dtinfo16.h"
#endif

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

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

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

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

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

#ifndef _SDNUM_
#include "sdnum.h"
#endif

#ifndef _TRACE_
#include "trace.h"
#endif

#include <string.h>
#include <stdlib.h>


                       /****************************
                        *                          *
                        *     EXTERNALS            *
                        *                          *
                        ****************************/

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

extern HANDLE  cliServerHandle;
STATIC DESCRIPTOR cliDqId=0;
static S32 startingFrame, endingFrame;

typedef struct {
    DESCRIPTOR      traceId;
    DtInfo          *dt;
} DQ_STATE;

                        /***************************
                        *                          *
                        *        PROTOTYPES        *
                        *                          *
                        ***************************/
RETCODE DqInsts(DQ_STATE *dqState, S32 numInst, LPSTR buffer,
                DESCRIPTOR *descs);
RETCODE PrintDataLine(FW_LINES info, LPSTR buffer, DESCRIPTOR *descs,
                      U16 *lineNum, U32 lastInstAddr, BOOLEAN timestampOn);

extern "C" {
RETCODE EXPORT DadCliGetDqInst(LPSTR cmdString, U32 argc, U32 argv[]);
};
                        /***************************
                        *                          *
                        *     EXECUTABLE CODE      *
                        *                          *
                        ***************************/

/****************************************************************************
**
**  Name:  DadDqOpen
**
****************************************************************************/
RETCODE EXPORT DadDqOpen(DESCRIPTOR FAR *id, DESCRIPTOR traceId) {
   DQ_STATE FAR  *dqState;
   RETCODE err;
   if ((dqState = (DQ_STATE FAR *)TMalloc(sizeof(DQ_STATE))) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   *id = (DESCRIPTOR)dqState;
   dqState->dt = new DtInfo;
   dqState->traceId    = traceId;
   return(GOOD);
}

/****************************************************************************
**
** Name:  DadForwardDqInst
**
****************************************************************************/
RETCODE EXPORT DadForwardDqInst(DESCRIPTOR id,U32 numInst,S32 FAR *startFrame,
                        S32 FAR *endFrame, LPSTR *buffer, U16 FAR *textLen,
                        DESCRIPTOR **addrDesc ) {
   DQ_STATE FAR *dqState;
   LOOP_VAR i;
   RETCODE err;
   *textLen = 0;
   if ((dqState = (DQ_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;

   if ((*buffer = TMalloc(MAX_LINE_LENGTH*numInst)) == NULL) 
      return(ER_OUT_OF_MEMORY);

   if((*addrDesc=(DESCRIPTOR *)TMalloc(sizeof(DESCRIPTOR)*MAX_NUM_DQ_LINES))
       == NULL) {
      TFree(*buffer);
      return(ER_OUT_OF_MEMORY);
   }

   for(i=0; i<MAX_NUM_DQ_LINES; i++) addrDesc[0][i] = NULL;
   memset(*buffer,'\0',(U16)numInst*MAX_LINE_LENGTH); /* initialize string */

   if ((err = TrcFrameDisplayModeSet(dqState->traceId,TRIGGER_ALIGN))
         != GOOD) {
      TFree(*buffer);
      TFree((LPSTR)*addrDesc);
      return err;
   }

   if ((err = DqInsts(dqState,numInst,*buffer, *addrDesc)) != GOOD) {
      TFree(*buffer);
      // free any address desc that might of been created
      for(i=0;i<MAX_NUM_DQ_LINES; i++) { 
         if( addrDesc[0][i] ) AdrDestroyAddress(addrDesc[0][i]);
      }
      TFree((LPSTR)*addrDesc);
      return err;
   }

   *startFrame = startingFrame;
   *endFrame = endingFrame;
   *textLen = lstrlen(*buffer);
   return(GOOD);
}

/****************************************************************************
**
** Name:  DadBackwardDqInst
**
****************************************************************************/
RETCODE EXPORT DadBackwardDqInst(DESCRIPTOR id,U32 numInst,S32 FAR *startFrame,
                        S32 FAR *endFrame, LPSTR *buffer, U16 FAR *textLen,
                        DESCRIPTOR **addrDesc ) {
   DQ_STATE FAR *dqState;
   LOOP_VAR i;
   RETCODE err;
   *textLen = 0;
   if ((dqState = (DQ_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;

   if ((*buffer = TMalloc(MAX_LINE_LENGTH*numInst)) == NULL) 
      return(ER_OUT_OF_MEMORY);

   if((*addrDesc=(DESCRIPTOR *)TMalloc(sizeof(DESCRIPTOR)*MAX_NUM_DQ_LINES))
      == NULL) {
      TFree(*buffer);
      return(ER_OUT_OF_MEMORY);
   }

   for(i=0; i<MAX_NUM_DQ_LINES; i++) addrDesc[0][i] = NULL;
   memset(*buffer,'\0',(U16)numInst*MAX_LINE_LENGTH); /* initialize string */

   if ((err = TrcFrameDisplayModeSet(dqState->traceId,TRIGGER_ALIGN))
         != GOOD) {
      TFree(*buffer);
      TFree((LPSTR)*addrDesc);
      return err;
   }

   if ((err = DqInsts(dqState,0-numInst,*buffer,*addrDesc)) != GOOD) {
      TFree(*buffer);
      // free any address desc that might of been created
      for(i=0;i<MAX_NUM_DQ_LINES; i++) { 
         if( addrDesc[0][i] ) AdrDestroyAddress(addrDesc[0][i]);
      }
      TFree((LPSTR)*addrDesc);
      return err;
   }

   *startFrame = startingFrame;
   *endFrame = endingFrame;
   *textLen = lstrlen(*buffer);
   return(GOOD);
}

/****************************************************************************
**
** Name:  DadSetDqOffset
**
****************************************************************************/
RETCODE EXPORT DadSetDqOffset(DESCRIPTOR id, U16 offset) {
   if (id == NULL) return ER_DAD_INVALID_ID_DESCRIPTOR;
   return(1);
}

/****************************************************************************
**
**  Name:  DadGetDqOffset
**
****************************************************************************/
RETCODE EXPORT DadGetDqOffset(DESCRIPTOR id, U16 FAR *offset) {
   if (id == NULL) return ER_DAD_INVALID_ID_DESCRIPTOR;
   return(1);
}

/****************************************************************************
**
** Name:  DadDqClose
**
****************************************************************************/
RETCODE EXPORT DadDqClose(DESCRIPTOR id) {
   DQ_STATE FAR  *dqState;
   RETCODE err;
   if ((dqState = (DQ_STATE FAR *)id) == NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   delete(dqState->dt);
   if ((err = TFree((LPSTR)dqState)) != GOOD)
      return err;
   return(GOOD);
}

/***************************************************************************
**
**  DqCliOpen
**
**************************************************************************/
RETCODE DqCliOpen(void) {
   RETCODE err;
   DESCRIPTOR traceId;

   if((err=TrcGetCliId(&traceId))!=GOOD) return(err);
   if((err=DadDqOpen(&cliDqId,traceId)) != GOOD) return(err);
   return(err);
}

/***************************************************************************
**
**  DadCliDqOffset
**
**************************************************************************/
RETCODE EXPORT DadCliDqOffset(LPSTR cmdString, U32 argc, U32 argv[]) {

   U16 offset;
   U8 resultBuff[128];
   RETCODE err;
   S8 *endptr;

   if (argc > 2) return (ER_CLI_SYNTAX);
   if( !cliDqId ) {
      if((err=DqCliOpen())!=GOOD) return(err);
   }
   if( argc == 2 ) {
      offset = (U16)strtoul(&cmdString[argv[1]],&endptr,16);
      if((err=DadSetDqOffset(cliDqId,offset))!=GOOD) return(err);
   }
   if( (err=DadGetDqOffset(cliDqId,&offset)) != GOOD ) return(err);
   wsprintf(resultBuff,"dq offset: %x", offset);
   return(SendCliMessage(cliServerHandle,resultBuff));
}

/*************************************************************************
**
** DadCliGetDqInst
**
***************************************************************************/
RETCODE EXPORT DadCliGetDqInst(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE err;
   DESCRIPTOR *descs;
   LPSTR buffer;
   S32 end,start;
   S8 *endptr;
   U16 len;
   U32 numInst = 1;
   DQ_STATE FAR *dqState;
   if (!cliDqId) {
      if((err=DqCliOpen())!=GOOD)
         return(err);
   }
   if (argc == 2)
      numInst = strtoul(&cmdString[argv[1]],&endptr,16);
   if ((err=DadForwardDqInst(cliDqId,numInst,&start,&end,&buffer,&len,&descs))
       !=GOOD) return(err);
   if((dqState=(DQ_STATE FAR *)cliDqId)==NULL)
      return ER_DAD_INVALID_ID_DESCRIPTOR;
   if((err=TrcReadFrameSet(dqState->traceId,end+1))!=GOOD) return(err);
   err = SendCliMessage(cliServerHandle,buffer);
   TFree(buffer);
   for(len=0;len<MAX_NUM_DQ_LINES;len++) {
      if( descs[len] ) AdrDestroyAddress(descs[len]);
   }
   TFree((LPSTR)descs);
   return(err);
}

RETCODE DqInsts(DQ_STATE *dqState, S32 numInst, LPSTR buffer,
                DESCRIPTOR *descs) {
   RETCODE err, err2;
   BOOLEAN true=TRUE, timedOut, found, instUsed[100], timestampOn;
   BOOLEAN firstInstFound = FALSE;
   U16 instCount, actualCount, trcBuffer, lineNum;
   FW_LINES dqLines[100];
   S16 truncCount = numInst;
   S32 oldest, newest, trig, firstFrame, prevFrame;
   U32 numFrames, lastInstAddr;
   startingFrame = endingFrame = 0;
   if((err=TrcNumFramesGet(dqState->traceId, &numFrames))!=GOOD)
      return(err);
   if( !numFrames ) return(GOOD); /* no frames just get out! */
   
/*
** Retrieve information about trace buffer limits and requested range
*/
   if ((err = TrcTraceBufferInfoGet(dqState->traceId,&oldest,&newest,&trig))
      != GOOD) return(err);
   if ((err = TrcReadFrameGet(dqState->traceId, &firstFrame)) != GOOD)
      return(err);
   
   if ((err = TrcReadBufferGet(dqState->traceId, &trcBuffer)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_FIND_FLUSH_BUFFER, (U8 FAR*)&trcBuffer,GOOD))
      != GOOD) return(err);
   if ((err = TrcTimestampGet(dqState->traceId,&timestampOn)) != GOOD )
      return(err);
   if ((err = SdnWriteMember(SDN_FIND_FLUSH_COUNT, (U8 FAR*)&truncCount,GOOD))
      != GOOD) return(err);

   err = SdnWriteCmdChkAbortReadResponse(SDN_FIND_FLUSH_START,
      &firstFrame,GOOD,SDN_FIND_FLUSH_ABORT, &true, GOOD,
      SDN_FIND_FLUSH_FOUND, 60, &timedOut);
   if (err == ER_DQ_ABORTED) err = ER_ABORT_FROM_ESC;
   if (err) return(err);
   if ((err = SdnReadMember(SDN_FIND_FLUSH_FOUND, &found)) != GOOD)
      return(err);
   if (!found) return (ER_DAD_NO_FLUSH_FRAMES_FOUND);
   if ((err = SdnReadMember(SDN_FIND_FLUSH_COUNT, (U8 FAR*)&actualCount))
      != GOOD) return(err);
   if( !actualCount ) return(GOOD);  /* must be at end of buffer */
   if( actualCount > 100 ) actualCount = 100;  // throw away frames !!!??

   if( (err = SdnReadPartialMember(SDN_FIND_FLUSH_INSTS, 0, 
       actualCount*sizeof(FW_LINES),(U8 FAR *)&dqLines))!= GOOD ) return(err);

   if((err=dqState->dt->SetTraceId(dqState->traceId))!=GOOD) return(err);

   // dqLines[0] is assumed to be a timestamp marker for first frame
   prevFrame = dqLines[0].frameNo;
   if( !dqLines[0].inst || (dqLines[0].addr!=0xffffffffL))
      return(ER_DAD_BAD_FW_LINES);
   instUsed[0] = TRUE;
   for (instCount=1 ; instCount < actualCount ; instCount++)
      instUsed[instCount] = FALSE;
      
   for (lineNum = 0, instCount=1 ; instCount < actualCount ; instCount++) {
      if((err = AdrCreateAddress(&descs[lineNum])) != GOOD) return(err);
      if((err = AdrSetAddrOffset(descs[lineNum],dqLines[instCount].addr))
         !=GOOD) return(err);
      if( !instUsed[instCount] && dqLines[instCount].inst ) {
         // Keep setting endingFrame to current frame number then
         // when we are finished it will be pointing to the last
         // instruction's frame number.
         lastInstAddr = dqLines[instCount].addr;
         endingFrame = dqLines[instCount].frameNo;
         if( !firstInstFound ) {
            // First instruction is starting frame number
            startingFrame = dqLines[instCount].frameNo;
            firstInstFound = TRUE;
         }            
         if((err=dqState->dt->SetStartAddress(descs[lineNum]))!=GOOD) 
            return(err);
         if((err=dqState->dt->SetFrameNumber(dqLines[instCount].frameNo))
            !=GOOD) return(err);
         if((err=dqState->dt->SetPrevFrameNumber(prevFrame))!=GOOD) 
            return(err);
         prevFrame = dqLines[instCount].frameNo;
         if((err=dqState->dt->Disassemble(buffer,
               dqLines[instCount].data.bytes)) != GOOD) return(err);
         buffer += strlen(buffer);
         lineNum++;
         instUsed[instCount] = TRUE;
         LOOP_VAR dataCnt = dqState->dt->DataCycles();
         LOOP_VAR idx = instCount+1;
         while( dataCnt-- ) {
            for( ; idx < actualCount; idx++) {
               if( !instUsed[idx] && !dqLines[idx].inst ) {
                  if((err=PrintDataLine(dqLines[idx], buffer, descs,&lineNum,
                             lastInstAddr,timestampOn)) != GOOD ) 
                     return(err);
                  buffer += strlen(buffer);
                  instUsed[idx] = TRUE;
                  break;
               }        
            }
            if( idx == actualCount ) break;
         }
      }
      else if( !instUsed[instCount] ) {
         if((err=PrintDataLine(dqLines[instCount], buffer, descs, &lineNum,
                    lastInstAddr, timestampOn)) != GOOD)
            return(err);
         buffer += strlen(buffer);
         instUsed[instCount] = TRUE;
      }
   }
   return(GOOD);
}

/****************************************************************************
**
**  DadDqFlush
**
****************************************************************************/
#pragma argsused
RETCODE EXPORT DadDqFlush(DESCRIPTOR id) {
   return(GOOD);
}


RETCODE PrintDataLine(FW_LINES info, LPSTR buffer, DESCRIPTOR *descs,
                      U16 *lineNum, U32 lastInstAddr, BOOLEAN timestampOn) {
   RETCODE err;
   if( !descs[*lineNum] ) {
      if((err = AdrCreateAddress(&descs[*lineNum])) != GOOD) return(err);
   }
   if((err = AdrSetAddrOffset(descs[*lineNum],info.addr))!=GOOD) return(err);
   buffer+=wsprintf(buffer,"%8ld ", info.frameNo);
   if( timestampOn ) buffer+=wsprintf(buffer,"             ");
   buffer+=wsprintf(buffer," ");  // need buffer to be pointing to end of str
   if((err=AdrConvAddressToTextWithParams(descs[*lineNum],FALSE,TRUE,buffer))
      != GOOD ) return(err);
   LOOP_VAR colCnt = strlen(buffer);
   for( ; colCnt < 28; colCnt++ ) strcat(buffer," ");
   buffer += strlen(buffer);
   buffer += wsprintf(buffer,"Data %s ", (info.write)? "write:" : "read: ");
   // Data in wrong endian format.
   U16 temp = (info.data.words[0] >> 8) + ((info.data.words[0] & 0xff) << 8);
   buffer += wsprintf(buffer,"%04X\r\n", temp);
   if((err = AdrSetAddrOffset(descs[*lineNum],lastInstAddr))!=GOOD)
      return(err);
   (*lineNum)++;   
   return(GOOD);
}

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