/****************************************************************************
**
**  Name:  dq332.c
**
**  Description:
**     This is a dequeuer for Motorola 68332
**
**
**  Status:  REVIEWED
**
**  $Log:   S:/tbird/mt2_186/dad186/dq332.c_v  $
** 
**    Rev 1.0   16 Dec 1996 15:13:46   Judy
** Initial revision.
** 
**    Rev 1.22   12 Sep 1994 12:57:58   mindy
**  combine data if in the same frame
** 
**    Rev 1.21   05 Sep 1994 18:17:58   mindy
** changed interface to support linked cursors better
** 
**    Rev 1.20   30 Jun 1994 08:17:14   mindy
** FW_LINES structure changed
** 
**    Rev 1.19   30 Mar 1994 19:31:52   STEVE
** No longer need strlib.h.
** 
**    Rev 1.18   01 Sep 1993 21:46:10   mindy
** removed last frame crud - not used anymore
** 
**    Rev 1.17   27 Jul 1993 16:30:30   john
** Increased timeout to correct 340 dq'r problem
** 
**    Rev 1.16   27 Jul 1993 15:34:24   john
** Added extra space to accomodate extra space added to ts display
** 
**    Rev 1.15   22 Jul 1993 10:20:54   ernie
** (for Mindy):  Added support for dequeuer backup and timestamp.
** 
**    Rev 1.14   16 Jul 1993 11:50:48   ernie
** Removed error.h include.  All errors now in errcodec.h
** 
**    Rev 1.13   25 May 1993 12:03:42   ernie
** Changed dasmSym to be system-wide global
** 
**    Rev 1.12   14 Apr 1993 13:28:22   doug
** template stuff not used anymore
** 
**    Rev 1.11   16 Dec 1992 15:35:32   mindy
** moved dq to fw
** 
**    Rev 1.10   09 Dec 1992 10:30:50   mindy
** Now firmware returns a sturcture of dq lines and the host just
** prints out the data access frames and runs the dq'd bytes through
** the assembler.
** 
**    Rev 1.9   02 Nov 1992 13:08:02   ernie
** 1. Added support for abort of SyncDq firmware function.
** 2. Streamlined Output() by calling disassembler only when actually
**    putting out text.
** 
**    Rev 1.8   15 Oct 1992 15:46:10   ernie
** Added support for loop mode (execution without fetching)
** 
**    Rev 1.7   14 Oct 1992 13:41:30   ernie
** 1. Largely rewrote dequeuer to increase speed and fix sync-up problems.
**    The sync-up processing is now done by the firmware since it has
**    direct access to the trace buffer.
** 2. Removed local caching of trace frames; there was no speed increase
**    gained because the trace server keeps a cache of frames also.
** 3. Removed the check for BERR and HALT assertion in DadGetFrameAddress().
**    This routine is called for code frames to get the code address to
**    propagate to the linked cursor.  Even if the data is ignored by the
**    processor for this cycle, the address still indicates the current PC.
** 
**    Rev 1.6   18 Sep 1992 10:01:42   marilyn
** Fixed memory leaks.
** 
**    Rev 1.5   31 Aug 1992 09:25:08   marilyn
** Fixed UAEs and other bugs in the dqueuer.
** 
**    Rev 1.4   28 Aug 1992 10:41:12   mindy
** ifetch is active LOW
** 
**    Rev 1.3   28 Aug 1992 09:51:14   mindy
** make address create give the correct address type
** 
**    Rev 1.2   27 Aug 1992 15:22:18   marilyn
** Fixed UAE bugs.
** 
**    Rev 1.1   05 Aug 1992 10:36:44   marilyn
** Made changes suggested in the code review.
** 
**    Rev 1.0   31 Jul 1992 12:48:58   marilyn
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/dad186/dq332.c_v   1.0   16 Dec 1996 15:13:46   Judy  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/
#ifndef _BASEWIND_
#include "basewind.h"
#endif

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

#ifndef _DAD_DEFINE_
#include "daddef.h"
#endif

#ifndef _DADDQ332_
#include "daddq332.h"
#endif

#ifndef _HEAP_
#include "heap.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

#ifndef __STDIO_H
#include <stdio.h>
#endif

                        /****************************
                         *                          *
                         *     DEFINITIONS          *
                         *                          *
                         ****************************/

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

extern HANDLE cliServerHandle;

                        /****************************
                         *                          *
                         *     LOCAL VARIABLES      *
                         *                          *
                         ****************************/

                        /****************************
                         *                          *
                         *     LOCAL PROTOTYPES     *
                         *                          *
                         ****************************/

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

/**************************************************************************
**
**  DqInsts
**
** Description:
**   This is the main entry point for the dequeuer.  The frame to start
**   dequeuing is part of dqState, and numInst instructions with data
**   are to be dequeued and their text placed in buffer.
**
** Theory:
**   The 68332 provides two signals which may be used in conjunction with
**   address and data buses for 100% accurate dequeueing.  IFETCH during
**   a bus cycle indicates the word fetched is being added to the instruction
**   pipeline.  IFETCH on for two successive clocks indicates the pipe is
**   being flushed, and 1 word is being fetched.  IPIPE indicates when
**   words are removed from the queue and executed.  IPIPE on for 2 clocks
**   indicates the word removed is the opcode word of an instruction.  IPIPE
**   on for 1 clock indicates the word is an instruction extension word.
**
**   The algorithm searches backward for the most recent queue flush, then
**   simulates the prefetch queue of the processor.  When a complete
**   instruction is executed (indicated by execution of the next opcode
**   word), the gathered data is passed to the disassembler and converted
**   to text.  Any data cycles seen during the execution of the instruction
**   are output just following the instruction.
**
**************************************************************************/
RETCODE DqInsts(DQ_STATE *dqState, S32 numInst, LPSTR buffer,
                DESCRIPTOR *descs) {
   RETCODE err;
   BOOLEAN true=TRUE, timedOut, found, timestampOn, dasmSym;
   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, lastInstAddr;
   if ((err = DadGetDasmSymbol(&dasmSym)) != GOOD) return(err);
   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 = 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(dqState->traceId,&timestampOn)) != GOOD )
      return(err);

   for (lineNum = 0, instCount=1 ; instCount < actualCount ;
            instCount++, lineNum++) {
      buffer+=wsprintf(buffer,"  %8ld  ",dqLines[instCount].frameNo);
      if ((err = AdrCreateAddress(&descs[lineNum])) != GOOD) return(err);
      if( 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.
         endingFrame = dqLines[instCount].frameNo;
         lastInstAddr = dqLines[instCount].addr;
         if( !firstInstFound ) {
            // First instruction is starting frame number
            startingFrame = dqLines[instCount].frameNo;
            firstInstFound = TRUE;
         }            
         if((err=TrcGetTimestampText(dqState->traceId,
                                dqLines[instCount].frameNo,
                                prevFrame, buffer)) != GOOD) break;
         
         strcat(buffer," ");    // more space between timestamp and address
         buffer += strlen(buffer);
         prevFrame = dqLines[instCount].frameNo;
      }
      else {
         if( timestampOn ) buffer+=wsprintf(buffer,"             ");
         buffer+=wsprintf(buffer," "); 
      }      
      if((err=AdrSetAddrOffset(descs[lineNum],dqLines[instCount].addr))!=GOOD)
         return(err);
      if((err=AdrConvAddressToTextWithParams(descs[lineNum],FALSE,TRUE,buffer))
         !=GOOD) return(err);
      if((err=AdrSetAddrOffset(descs[lineNum],lastInstAddr))!=GOOD)
         return(err);
      buffer += strlen(buffer);
      
      if( dqLines[instCount].inst ) {
         if (TraceBufInst(dqLines[instCount].data.words,
                           dqLines[instCount].addr,
                           dasmSym,
                           (U8*)buffer,
                           &dasmInfo) != GOOD ) {
            break;
         } else {
            buffer += strlen(buffer);
            buffer += wsprintf(buffer,"\r\n");
         }
      }
      else {
         U32 longData;
         buffer += wsprintf(buffer,"    Data %s ",
            (dqLines[instCount].write)? "write:" : "read: ");
         if( dqLines[instCount].frameNo == dqLines[instCount+1].frameNo ) {
            longData = dqLines[instCount].data.words[0] << 16;
            instCount++;
            longData |= dqLines[instCount].data.words[0];
            buffer+= wsprintf(buffer,"%08X\r\n",longData);
         }
         else {
            buffer+= wsprintf(buffer,
                       "    %04X\r\n",dqLines[instCount].data.words[0]);
         }
      }
   }
   return(err);
}

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



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