/****************************************************************************
**
**  Name:  dq86.c
**
**  Description:
**     This is a dequeuer interface calls
**
**  Status:  REVIEWED
**
**  $Log:   S:/tbird/mt2_186/dad186/dq86.c_v  $
** 
**    Rev 1.0   16 Dec 1996 15:14:00   Judy
** Initial revision.
** 
**    Rev 1.4   12 Sep 1994 12:48:36   mindy
** getting bad size from adr server
** 
**    Rev 1.3   05 Sep 1994 18:12:48   mindy
** changed interface to support linked cursors better
** 
**    Rev 1.2   12 Aug 1994 14:58:42   mindy
** grab more memory need room for data
** 
**    Rev 1.1   30 Jun 1994 08:12:02   mindy
** added 386 and debugged it
** 
**    Rev 1.0   25 May 1994 14:19:18   nghia
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/dad186/dq86.c_v   1.0   16 Dec 1996 15:14:00   Judy  $
**
**  Copyright (C) 1994 Microtek International.  All rights reserved.
**
****************************************************************************/

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

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

#ifndef _DADDEF86_
#include "daddef86.h"
#endif

#ifndef _PDASM86_
#include "pdasm86.h"
#endif

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

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

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

#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif

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

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

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

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

#ifndef __STDLIB_H_
#include <stdlib.h>
#endif


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

extern U8 *SymSet[];

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
extern HANDLE  cliServerHandle;
STATIC DESCRIPTOR cliDqId=0;

                        /***************************
                        *                          *
                        *        PROTOTYPES        *
                        *                          *
                        ***************************/
RETCODE DqInsts(DESCRIPTOR id, S32 numInst, LPSTR buffer, DESCRIPTOR *descs);
RETCODE PrintDataLine(FW_LINES *lines, U16 *idx, BOOLEAN *instUsed,
                      U16 *cycleCount, LPSTR buffer, DESCRIPTOR *descs,
                      U16 *lineNum, BOOLEAN timestampOn);

                        /***************************
                        *                          *
                        *     EXECUTABLE CODE      *
                        *                          *
                        ***************************/
static S32 startingFrame, endingFrame;
VOID GetStartEndFrame(S32 *starting, S32 *ending) {
   *starting = startingFrame;
   *ending = endingFrame;
}

/****************************************************************************
**
**  Name:  DadDqOpen
**
****************************************************************************/
RETCODE EXPORT DadDqOpen(DESCRIPTOR FAR *id, DESCRIPTOR traceId) {
   *id = 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 ) {
   RETCODE err;
   LOOP_VAR i;
   *textLen = 0;
   if ((*buffer = TMalloc(MAX_LINE_LENGTH*MAX_NUM_DQ_LINES)) == 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(id,TRIGGER_ALIGN)) != GOOD) {
      TFree(*buffer);
      TFree((LPSTR)*addrDesc);
      return err;
   }

   if ((err = DqInsts(id,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;
   }

   GetStartEndFrame(startFrame,endFrame);

   *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 ) {
   LOOP_VAR i;
   RETCODE err;
   *textLen = 0;
   if ((*buffer = TMalloc(MAX_LINE_LENGTH*MAX_NUM_DQ_LINES)) == 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(id,TRIGGER_ALIGN)) != GOOD) {
      TFree(*buffer);
      TFree((LPSTR)*addrDesc);
      return err;
   }

   if ((err = DqInsts(id,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;
   }

   GetStartEndFrame(startFrame,endFrame);
   *textLen = lstrlen(*buffer);
   return(GOOD);
}

/****************************************************************************
**
** Name:  DadSetDqOffset
**
****************************************************************************/
RETCODE EXPORT DadSetDqOffset(DESCRIPTOR id, U16 offset) {
   return(GOOD);
}

/****************************************************************************
**
**  Name:  DadGetDqOffset
**
****************************************************************************/
RETCODE EXPORT DadGetDqOffset(DESCRIPTOR id, U16 FAR *offset) {
   return(GOOD);
}

/****************************************************************************
**
** Name:  DadDqClose
**
****************************************************************************/
RETCODE EXPORT DadDqClose(DESCRIPTOR id) {
   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;
   CHAR 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[(U16)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;
   LPSTR buffer;
   S32 end,start;
   S8 *endptr;
   U16 len;
   U32 numInst = 1;
   DESCRIPTOR *addrDesc=NULL;
   if (!cliDqId) {
      if((err=DqCliOpen())!=GOOD)
         return(err);
   }
   if (argc == 2)
      numInst = strtoul(&cmdString[(U16)argv[1]],&endptr,16);
   if ((err=DadForwardDqInst(cliDqId,numInst,&start,&end,&buffer,&len,
                             &addrDesc))!=GOOD)
      return(err);

   if((err=TrcReadFrameSet(cliDqId,end+1))!=GOOD) return(err);
   err = SendCliMessage(cliServerHandle,buffer);
   for(len =0; len < MAX_NUM_DQ_LINES; len++) {
      if((err=AdrDestroyAddress(addrDesc[len]))!=GOOD) return(err);
   }
   TFree((LPSTR)addrDesc);
   TFree(buffer);
   return(err);
}

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

/**************************************************************************
**
**  DqInsts
**
** Description:
**   This is the main entry point for the dequeuer.  The frame to start
**   dequeuing is part of id (traceId), and numInst instructions with data
**   are to be dequeued and their text placed in buffer.
**
**************************************************************************/
STATIC U32 lastInstAddr;
STATIC ADDR_SPACE lastInstSpace;
RETCODE DqInsts(DESCRIPTOR id, S32 numInst, LPSTR buffer, DESCRIPTOR *descs) {
   RETCODE err;
   BOOLEAN true=TRUE, timedOut, found, instUsed[100], timestampOn;
   BOOLEAN firstInstFound = FALSE;
   U16 instCount, actualCount, trcBuffer, lineNum;
   DASM_INFO dasmInfo;
   FW_LINES dqLines[100];
   S16 truncCount = numInst;
   S32 oldest, newest, trig, firstFrame, prevFrame;
   U32 numFrames;
   ADDR_OP_SIZE opSize;
   startingFrame = endingFrame = 0;
   if((err=TrcNumFramesGet(id, &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(id,&oldest,&newest,&trig)) != GOOD)
      return(err);
   if ((err = TrcReadFrameGet(id, &firstFrame)) != GOOD) return(err);
   
   if ((err = TrcReadBufferGet(id, &trcBuffer)) != GOOD) return(err);
   if ((err = SdnWriteMember(SDN_FIND_FLUSH_BUFFER, (U8 FAR*)&trcBuffer,GOOD))
      != 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, 180, &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);

      // 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);
   
   if ((err = TrcTimestampGet(id,&timestampOn)) != GOOD ) return(err);
   instUsed[0] = TRUE;
   for (instCount=1 ; instCount < actualCount ; instCount++)
      instUsed[instCount] = FALSE;
      
   if ((err = AdrCreateAddressWithType(ADDR_LINEAR,&dasmInfo.target))
        != GOOD) return(err); // Next call returns bad Size if we use default
                              // address type (i.e.: virtual)
   if ((err = AdrGetDefaultSize(dasmInfo.target,&opSize)) != GOOD) return(err);

   for (lineNum=0, instCount=1 ; instCount < actualCount ; instCount++) {
      LOOP_VAR idx;
      if( !instUsed[instCount] ) {
         if( dqLines[instCount].inst ) {
            // inst addresses are linear
            if ((err = AdrCreateAddressWithType(ADDR_LINEAR,
                                                &descs[lineNum]))!=GOOD)
               return(err);
            buffer+=wsprintf(buffer,"%8ld ",dqLines[instCount].frameNo);
            lastInstAddr = dqLines[instCount].addr;
            lastInstSpace = dqLines[instCount].space;
            if((err=AdrSetAddrOffset(descs[lineNum],lastInstAddr))!=GOOD){
               AdrDestroyAddress(dasmInfo.target);
               return(err);
            }
            if((err=AdrSetAddrSpace(descs[lineNum],lastInstSpace))!=GOOD){
               AdrDestroyAddress(dasmInfo.target);
               return(err);
            }
            // Keep setting endingFrame to current frame number then
            // when we are finished it will be pointing to the last
            // instruction's frame number.
            endingFrame = dqLines[instCount].frameNo;
            if( timestampOn && (err=TrcGetTimestampText(id,
                                       dqLines[instCount].frameNo,
                                       prevFrame, buffer)) != GOOD) break;
         
            strcat(buffer," ");    // space between timestamp and address
            buffer += strlen(buffer);
            prevFrame = dqLines[instCount].frameNo;
            if((err=AdrConvAddressToTextWithParams(descs[lineNum],FALSE,TRUE,
                                                   buffer)) !=GOOD) break;
            buffer += strlen(buffer);
            strcat(buffer,"     ");    // space between address and dasm
            buffer += strlen(buffer);
            if((err=DadGetDasmInstruction(descs[lineNum],opSize,
                                          dqLines[instCount].data.bytes,
                                          buffer, &dasmInfo))!= GOOD) break;
            buffer += strlen(buffer);
            strcat(buffer,"\r\n");    // new line
            buffer += strlen(buffer);
            instUsed[instCount] = TRUE;
            lineNum++;     // go to next line 
            if( !dasmInfo.MRCycles && !dasmInfo.MWCycles && !dasmInfo.IRCycles
                && !dasmInfo.IWCycles ) {
               if( firstInstFound ) continue; // if no data skip rest of loop
               else { // we want to "eat" up data cycles that are probably
                  // for some previous instruction.
                  idx = instCount+1;
                  for( ; idx < actualCount; idx++) {
                     if( dqLines[idx].inst ) break;
                     else if( !instUsed[idx] && !dqLines[idx].inst ) {
                        instUsed[idx] = TRUE;
                     }
                  }
               }
            }
   
            if( !firstInstFound ) {
               // First instruction is starting frame number
               startingFrame = dqLines[instCount].frameNo;
               firstInstFound = TRUE;
            }            
            idx = instCount+1;
            while(dasmInfo.MRCycles && (idx < actualCount)) {
               if( !instUsed[idx] && !dqLines[idx].inst
                   && !dqLines[idx].write && !dqLines[idx].io) {
                  if((err=PrintDataLine(dqLines, &idx, instUsed,
                             &dasmInfo.MRCycles, buffer, descs,
                             &lineNum, timestampOn))!=GOOD) {
                     AdrDestroyAddress(dasmInfo.target);
                     return(err);
                  }
                  buffer += strlen(buffer);
               }
               else idx++;
               if(idx == actualCount) break; 
            }
            idx = instCount+1;
            while(dasmInfo.MWCycles && (idx < actualCount)) {
               if( !instUsed[idx] && !dqLines[idx].inst
                   && dqLines[idx].write && !dqLines[idx].io) {
                  if((err=PrintDataLine(dqLines, &idx, instUsed,
                             &dasmInfo.MWCycles, buffer, descs,
                             &lineNum, timestampOn))!=GOOD) {
                     AdrDestroyAddress(dasmInfo.target);
                     return(err);
                  }
                  buffer += strlen(buffer);
               }
               else idx++;
               if(idx == actualCount) break; 
            }
            idx = instCount+1;
            while(dasmInfo.IRCycles && (idx < actualCount)) {
               if( !instUsed[idx] && !dqLines[idx].inst
                   && !dqLines[idx].write && dqLines[idx].io) {
                  if((err=PrintDataLine(dqLines, &idx, instUsed,
                             &dasmInfo.IRCycles, buffer, descs,
                             &lineNum, timestampOn))!=GOOD) {
                     AdrDestroyAddress(dasmInfo.target);
                     return(err);
                  }
                  buffer += strlen(buffer);
               }
               else idx++;
               if(idx == actualCount) break; 
            }
            idx = instCount+1;
            while(dasmInfo.IWCycles && (idx < actualCount)) {
               if( !instUsed[idx] && !dqLines[idx].inst
                   && dqLines[idx].write && dqLines[idx].io) {
                  if((err=PrintDataLine(dqLines, &idx, instUsed,
                             &dasmInfo.IWCycles, buffer, descs,
                             &lineNum, timestampOn))!=GOOD) {
                     AdrDestroyAddress(dasmInfo.target);
                     return(err);
                  }
                  buffer += strlen(buffer);
               }
               else idx++;
               if(idx == actualCount) break; 
            }
         }
         else {
            U16 byteCount = 4, idx=instCount; // dummy place holders
            if((err=PrintDataLine(dqLines, &idx, instUsed, &byteCount,
                                  buffer, descs, &lineNum,
                                  timestampOn))
               != GOOD){
               AdrDestroyAddress(dasmInfo.target);
               return(err);
            }
            buffer += strlen(buffer);
         }
      }
   }
   AdrDestroyAddress(dasmInfo.target);
   return(err);
}
   
RETCODE PrintDataLine(FW_LINES *lines, U16 *idx, BOOLEAN *instUsed,
                      U16 *cycleCount, LPSTR buffer, DESCRIPTOR *descs,
                      U16 *lineNum, BOOLEAN timestampOn) {
   RETCODE err;
   LOOP_VAR colCnt;
   FW_LINES *info;
   // data addresses are physical
   if ((err = AdrCreateAddressWithType(ADDR_PHYSICAL, &descs[*lineNum]))!=GOOD)
      return(err);
   info = &lines[*idx];
   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);
   colCnt = strlen(buffer);
   for( ; colCnt < 28; colCnt++ ) strcat(buffer," ");
   buffer += strlen(buffer);

   buffer += wsprintf(buffer,"%s %s ", (info->io)   ? "io "    :"mem",
                                       (info->write)? "write:" : "read: ");
   // If next line has the same frame number then we will combine data
   if( info->frameNo == lines[*idx+1].frameNo ) {
      U16 data;
      data = lines[*idx+1].data.bytes[0] << 8;
      data |= info->data.bytes[0];
      buffer+= wsprintf(buffer,"%04X\r\n",data);
      instUsed[*idx] = TRUE;
      (*idx)++;
      if( *cycleCount > 1 ) (*cycleCount)--; // incase dasm count is wrong
                                             // don't want to mess myself up
   }
   else {
      buffer+= wsprintf(buffer,"  %02X\r\n",info->data.bytes[0]);
   }
   // For linked cursor support make address equal to last instruction
   if((err=AdrSetAddrType(descs[*lineNum],ADDR_LINEAR))!=GOOD) return(err);
   if((err=AdrSetAddrOffset(descs[*lineNum],lastInstAddr))!=GOOD) return(err);
   if((err=AdrSetAddrSpace(descs[*lineNum],lastInstSpace))!=GOOD) return(err);
   instUsed[*idx] = TRUE;
   (*idx)++;
   (*lineNum)++;
   (*cycleCount)--;
   return(GOOD);
}
/**************************** E O F ***************************************/
