/****************************************************************************
**
**  Name:  trace.c
**
**  Description:
**     Provides shared data server handling routines for trace and trigger.
**     This is proprietary to MICEPack
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_68k/trace/mp_trace.c_v  $
** 
**    Rev 1.3   02 Feb 1998 19:59:38   Eric
** Added ABORT function when searching event
** 
**    Rev 1.2   18 Mar 1997 09:04:54   gene
** 
**    Rev 1.1   04 Mar 1997 13:05:40   gene
** 
**    Rev 1.0   13 Feb 1997 09:07:20   gene
** Initial revision.
** 
**    Rev 1.13   10 Sep 1996 13:48:50   kevin
** revised the behavior of qualified trace
** 
**    Rev 1.12   25 Jul 1996 16:09:26   kevin
** fixed a bug while searching trace frames
** 
**    Rev 1.11   28 Jun 1996 13:15:42   kevin
** fixed bugs in qualified trace
** 
**    Rev 1.10   27 Jun 1996 11:30:12   kevin
** typo error
** 
**    Rev 1.9   30 May 1996 14:07:28   kevin
** added NDMA control to dialog box of qualified trace
** 
**    Rev 1.8   29 May 1996 18:02:50   kevin
** modified ForwardReadTrace to get uGroup
** 
**    Rev 1.7   10 Apr 1996 13:36:42   kevin
** Added qualify trace
** 
**    Rev 1.6   22 Dec 1995 09:36:00   kevin
** added TrcGetCounters()
** 
**    Rev 1.5   19 Dec 1995 09:46:12   kevin
** modified validtracebuffer()
** 
**    Rev 1.4   18 Dec 1995 14:43:12   kevin
** TrcLinkedCursor will not check invalid frames
** 
**    Rev 1.3   28 Nov 1995 14:51:46   kevin
** added TFree(TraceData) in TrcReadTrace() to prevent from leaking memory
** 
**    Rev 1.2   11 Oct 1995 13:49:38   gene
** modify Trace Search problem
** 
**    Rev 1.1   08 Sep 1995 15:30:46   kevin
** fixed linked cursor problem
** 
**    Rev 1.0   07 Sep 1995 11:22:20   gene
** Initial revision.
** 
** 
**  $Header:   S:/tbird/mt2_68k/trace/mp_trace.c_v   1.3   02 Feb 1998 19:59:38   Eric  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

#ifndef _MEMORY_H
#include "memory.h"
#endif
#ifndef _STDIO_
#include "stdio.h"
#endif
#ifndef _STDLIB_H
#include <stdlib.h>
#endif
#ifndef _HEAP_
#include "heap.h"
#endif
#ifndef _SDPROBE_
#include "sdprobe.h"
#endif
#ifndef _SSHARED_
#include "sshared.h"
#endif
#ifndef  _HOSTERRS_
#include "hosterrs.h"
#endif
#ifndef _MP_TRACE_
#include "mp_trc.h"
#endif
#ifndef _MP_TRIG_
#include "mp_trig.h"
#endif
#ifndef  _SDS2ABI_
#include "sds2abi.h"
#endif
#ifndef _PVTASK_
#include "pvtask.h"
#endif

/*!!!*/
#undef PRIVATE
#define PRIVATE  
                        /****************************
                         *                          *
                         *     LOCAL DEFINITIONS    *
                         *                          *
                         ****************************/
//???static U32 updateInterval;
//???static MBOX updateIntervalMbox;

extern HANDLE hLib;

static BOOLEAN showCycleEnable = FALSE;
static BOOLEAN reconfigMtatPendingFlag;

static DESCRIPTOR descSeqLevel;
static DESCRIPTOR descCurSubbuffer;
static DESCRIPTOR descTracing;
static DESCRIPTOR descCounter0;
static DESCRIPTOR descCounter1;
static DESCRIPTOR descNumTrcbufs;
static DESCRIPTOR descTraceMode;
static DESCRIPTOR descTraceEmpty;
static DESCRIPTOR descBrkOnTraceFull;
static DESCRIPTOR descTerminalCountA;
static DESCRIPTOR descTerminalCountB;
static DESCRIPTOR descMaxBuffer;
static U8 bActive=0;

typedef enum {
   TRACE_SEARCH_FORWARD, TRACE_SEARCH_BACKWARD, TRACE_SEARCH_END=0x7fff
} TRACE_SEARCH_DIRECTION;

                        /****************************
                         *                          *
                         *     LOCAL PROTOTYPES     *
                         *                          *
                         ****************************/
/*
** Shared Data Server Handler routines
*/
RETCODE EXPORT TrcReconfigMtat(DESCRIPTOR desc);
RETCODE EXPORT ProgramMtat(DESCRIPTOR desc);
RETCODE EXPORT TriggerProgramTask(DESCRIPTOR desc) ;
RETCODE EXPORT TrcTracingSet(BOOLEAN value);

RETCODE EXPORT TrcDiagnosticModeTask(DESCRIPTOR desc);
RETCODE EXPORT TrcTrigOutEnableTask(DESCRIPTOR desc);
RETCODE EXPORT TrcUpdatesPerMinuteTask(DESCRIPTOR desc);
RETCODE EXPORT TrcGetStatusTask(DESCRIPTOR desc);
RETCODE EXPORT TrcTracingTask(DESCRIPTOR desc);
RETCODE EXPORT TrcTracingAction(DESCRIPTOR desc,BOOLEAN *tracing);
RETCODE EXPORT TrcEnableSequencerTask(DESCRIPTOR desc);
RETCODE EXPORT EnableSequencerAction(BOOLEAN enable);
RETCODE EXPORT TrcClearTraceTask(DESCRIPTOR desc);
RETCODE EXPORT TrcIncTraceBufferTask(DESCRIPTOR desc);
RETCODE EXPORT TrcSearchTask(DESCRIPTOR desc);
RETCODE EXPORT TrcSearchBuffer(DESCRIPTOR desc, BOOLEAN *found);
RETCODE EXPORT TrcBufferCheckTask(DESCRIPTOR desc);
RETCODE EXPORT TrcLinkedCursorTask(DESCRIPTOR desc);
RETCODE EXPORT TrcLinkedCursor(DESCRIPTOR desc, BOOLEAN *instFrame);
RETCODE EXPORT TrcResetSequenceLevelTask(DESCRIPTOR desc);
RETCODE EXPORT TrcReadTrace(DESCRIPTOR desc);
RETCODE EXPORT TrcReadTraceTask(DESCRIPTOR desc);
RETCODE EXPORT TrcWriteLengthTask(DESCRIPTOR desc) ;
RETCODE EXPORT TrcBreakOnFullTask(DESCRIPTOR desc);
RETCODE EXPORT TrcNumBuffersTask(DESCRIPTOR desc);
RETCODE EXPORT TrcMaxBuffer(DESCRIPTOR desc);
RETCODE EXPORT TrcGetCounters(U16 *cnt0, U16 *cnt1);
/*
** Other local routines
*/
RETCODE EXPORT TrcWriteStatus(VOID);
VOID EXPORT WriteTraceFrame(U32 frame, TRACE_FRAME result);

RETCODE  GetOldestFrame(U16 buffer, U32 *oldest);
BOOLEAN ValidTraceBuffer(U16 buffer);
RETCODE GetStartingBusCycle(U16 buffer, S32 *frameNo, TRACE_FRAME *frame,
         BOOLEAN *foundOne);
RETCODE PRIVATE EnableItems(HWND hDlg, U8 num, BOOL enable); 
RETCODE PRIVATE SetRadioButtons(HWND hDlg, U8 numSig, U16 qStatus, U16 qMask);
RETCODE PRIVATE GetItemVal(HWND hDlg, U16 CtlID, DWORD *dwVal);
RETCODE PRIVATE SetItemVal(HWND hDlg, U16 ItemID, LPSTR format, DWORD dwVal);

U16 GetMaxValidTraceBuffer(VOID);

RETCODE EXPORT TrcInit(HANDLE hLib) {
   RETCODE err;
   DESCRIPTOR desc;
   MEMBER_NAME fullName[SD_MAX_NAME];
   LOOP_VAR i;
   FARPROC  lp;

   reconfigMtatPendingFlag = FALSE;

   lp = MakeProcInstance((FARPROC)TrcReconfigMtat, hLib);
   if((err = SdnRegister(SDN_TRACE_MODE,lp,&desc))!=GOOD)
      return(err);

   {
      U16 data=1;
      lp = MakeProcInstance((FARPROC)TrcNumBuffersTask, hLib);
      if((err = SdnRegister(SDN_NUM_TRCBUFS,lp,&desc))
         !=GOOD) return(err);
      if((err = SdnRegister(SDN_NUM_TRCBUFS,NULLPTR,&desc))
         !=GOOD) return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
   }

   lp = MakeProcInstance((FARPROC)TrcMaxBuffer, hLib);
   if((err = SdnRegister(SDN_MAX_TRACE_BUFFER,lp,&desc))
      !=GOOD) return(err);
   
   {
      BOOLEAN data=FALSE;
      lp = MakeProcInstance((FARPROC)TrcBreakOnFullTask, hLib);
      if((err=SdnRegister(SDN_BRK_ON_TRACE_FULL,lp,&desc))
         !=GOOD) return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
       
      lp = MakeProcInstance((FARPROC)ProgramMtat, hLib);
      if((err=SdnRegister(SDN_TRIC_DIAGNOSTIC_MODE,lp,&desc)) != GOOD) return(err);
// vincent      if((err = SdnRegister(SDN_TRIC_DIAGNOSTIC_MODE,NULLPTR,&desc))!=GOOD)
// vincent         return(err);
// vincent      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
// vincent      if ((err=SdUnRegister(desc)) != GOOD) return(err);

      lp = MakeProcInstance((FARPROC)TrcTrigOutEnableTask, hLib);
      if((err=SdnRegister(SDN_TRIGOUT_ENABLE,lp,&desc))
         !=GOOD) return(err);
      if((err = SdnRegister(SDN_TRIGOUT_ENABLE,NULLPTR,&desc))!=GOOD)
         return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
      if ((err=SdUnRegister(desc)) != GOOD) return(err);

      lp = MakeProcInstance((FARPROC)TrcIncTraceBufferTask, hLib);
      if((err = SdnRegister(SDN_INC_TRACE_BUFFER,lp,&desc))
         !=GOOD) return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
      lp = MakeProcInstance((FARPROC)TrcResetSequenceLevelTask, hLib);
      if((err= SdnRegister(SDN_RESET_SEQUENCE_LEVEL,lp,
         &desc))!=GOOD) return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
      lp = MakeProcInstance((FARPROC)TrcEnableSequencerTask, hLib);
      if((err =SdnRegister(SDN_ENABLE_SEQUENCER,lp,&desc))
         !=GOOD) return(err);
   }
   {
      U16 data=0;
      lp = MakeProcInstance((FARPROC)TrcReconfigMtat, hLib);
      if((err= SdnRegister(SDN_TERMINAL_COUNT_A,lp,&desc))
         !=GOOD) return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
      lp = MakeProcInstance((FARPROC)TrcReconfigMtat, hLib);
      if((err= SdnRegister(SDN_TERMINAL_COUNT_B,lp,&desc))
         !=GOOD) return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
   }

   {
      U32 data=0;
      lp = MakeProcInstance((FARPROC)TrcUpdatesPerMinuteTask, hLib);
      if((err=SdnRegister(SDN_UPDATES_PER_MINUTE,lp,&desc)) !=GOOD) return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
   }

   for(i=0; i<NUM_TRACE; i++) {
      sprintf(fullName, "%s %d", SD_TRACE_BUFF_LEN, i);
      lp = MakeProcInstance((FARPROC)TrcReadTraceTask, hLib);
      if((err=SdRegister(fullName,lp,&desc))!=GOOD) return(err);
   }
      lp = MakeProcInstance((FARPROC)TrcWriteLengthTask, hLib);
   if((err = SdnRegister(SDN_TRACE_WRITE_LENGTH,lp,&desc))
      !=GOOD) return(err);
      lp = MakeProcInstance((FARPROC)TrcSearchTask, hLib);
   if((err = SdnRegister(SDN_SEARCH_START_FRAME,lp,&desc)) != GOOD)
      return(err);
      lp = MakeProcInstance((FARPROC)TrcBufferCheckTask, hLib);
   if((err = SdnRegister(SDN_BUFFER_CHECK,lp,&desc)) != GOOD)
      return(err);
      lp = MakeProcInstance((FARPROC)TrcLinkedCursorTask, hLib);
   if((err=SdnRegister(SDN_LINKCURS_FRAME,lp,&desc))!=GOOD)
      return(err);
/*
** set up static descriptors for often-accessed sd members
*/ 
   if((err = SdnRegister(SDN_SEQUENCE_LEVEL,NULLPTR,&descSeqLevel))!=GOOD)
      return(err);
   if((err = SdnRegister(SDN_CURRENT_SUBBUFFER,NULLPTR,&descCurSubbuffer))
      !=GOOD) return(err);
   if((err= SdnRegister(SDN_TRACING,NULLPTR,&descTracing))!=GOOD) return(err);
   sprintf(fullName, "%s %d", SD_COUNTER_VALUE, 0);
   if((err = SdRegister(fullName,NULLPTR,&descCounter0))!=GOOD) return(err);
   sprintf(fullName, "%s %d", SD_COUNTER_VALUE, 1);
   if((err = SdRegister(fullName,NULLPTR,&descCounter1))!=GOOD) return(err);
   if((err = SdnRegister(SDN_NUM_TRCBUFS,NULLPTR,&descNumTrcbufs))!=GOOD)
      return(err);
   if((err = SdnRegister(SDN_TRACE_MODE,NULLPTR,&descTraceMode))!=GOOD)
      return(err);
   if((err = SdnRegister(SDN_TRACE_EMPTY,NULLPTR,&descTraceEmpty))!=GOOD)
      return(err);
   if((err = SdnRegister(SDN_BRK_ON_TRACE_FULL,NULLPTR,&descBrkOnTraceFull))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_TERMINAL_COUNT_A,NULLPTR,&descTerminalCountA))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_TERMINAL_COUNT_B,NULLPTR,&descTerminalCountB))
      !=GOOD) return(err);
   if((err = SdnRegister(SDN_MAX_TRACE_BUFFER,NULLPTR,&descMaxBuffer))
      !=GOOD) return(err);
   {
   BOOLEAN data;
      lp = MakeProcInstance((FARPROC)TrcGetStatusTask, hLib);
      if((err=SdnRegister(SDN_TRACE_GET_STATUS,lp,&desc))!=GOOD)
         return(err);
      if ((err=SdnRegister(SDN_TRACE_GET_STATUS,NULLPTR,&desc))!=GOOD)return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
      if ((err = SdUnRegister(desc)) != GOOD) return(err);

      lp = MakeProcInstance((FARPROC)TrcTracingTask, hLib);
      if((err = SdnRegister(SDN_SET_TRACING,lp,&desc))!=GOOD)
         return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);

      lp = MakeProcInstance((FARPROC)TrcClearTraceTask, hLib);
      if((err = SdnRegister(SDN_CLEAR_TRACE,lp,&desc))!=GOOD)
         return(err);
      if((err = SdWriteMember(desc,&data,GOOD)) != GOOD) return(err);
   }

   {
      BOOLEAN true=TRUE;
      if((err = SdWriteMember(descTraceEmpty,&true,GOOD))!=GOOD) return(err);
      ClearTriggerPositions();
   }
   {
      TRACE_MODE traceMode=TRACE_PRE;
      if((err = SdWriteMember(descTraceMode,&traceMode,GOOD))!=GOOD)
         return(err);
   }
   /* program trigger hardware, wait for result before returning */
   {
      BOOLEAN true = TRUE;
      if ((err = SdnWriteMember(SDN_ENABLE_SEQUENCER,&true,GOOD)) != GOOD)
         return(err);
      if ((err = SdnReadMember(SDN_ENABLE_SEQUENCER,&true)) != GOOD)
         return(err);                     /* Sequencer enable failed */
   }
   Sds2AbiDisableQual();

   return(GOOD);
}

RETCODE EXPORT ProgramMtat(DESCRIPTOR desc)
{
RETCODE     err;


//   if (reconfigMtatPendingFlag == TRUE)
//      {
//      if ((err = SdnRegister(SDN_TRIGGER_INFO, NULLPTR, &desc)) != GOOD) return(err);
//      TriggerProgramTask(desc);
//      reconfigMtatPendingFlag = FALSE;
//      err = SdUnRegister(desc);
//      return(err);
//      }
//   return(GOOD);
//
   
   return(TrcTracingSet(TRUE));
}


/*
**  TrcReconfigMtat
**     A request has arrived which requires reloading the TMAN.  The request
**     is noted and when the sequencer is reenabled, the TMAN will be loaded
**     with the new parameters.
*/
RETCODE EXPORT TrcReconfigMtat(DESCRIPTOR desc){
   reconfigMtatPendingFlag = TRUE;
   return(GOOD);
}

/*
**  TrcNumBuffersTask
**     The number of trace buffer configuration has changed.  Using this
**     as a flag that we need to change the frame increment variables.
*/
RETCODE EXPORT TrcNumBuffersTask(DESCRIPTOR desc) {
   U16 curNumBufs, numBufsIndex;
   RETCODE err;
   if((err=SdReadMember(desc,&curNumBufs))!=GOOD) return(err);
   if ((err = Sds2AbiSetNumTraceBuffers(curNumBufs)) != GOOD) return(err);
//vvv   return(TrcReconfigMtat(desc));
   return(GOOD);
}

RETCODE EXPORT TrcBreakOnFullTask(DESCRIPTOR desc) {
   U16 full;
   RETCODE err;
   if((err=SdReadMember(desc,&full))!=GOOD) return(err);
   if ((err = Sds2AbiSetBreakOnFull(full)) != GOOD) return(err);
   return(GOOD);
}
   
/*
**  TrcDiagnosticModeTask
**     Turns on or off the TRIC TEST bit.  When on, the TRIC generates a test
**     pattern of walking ones.
*/
RETCODE EXPORT TrcDiagnosticModeTask(DESCRIPTOR desc){
   BOOLEAN testBit;
   RETCODE err;
   if ((err = SdReadMember(desc, &testBit)) != GOOD) return(err);
   return(GOOD);
}

/*
**  TrcTrigOutEnableTask
**     Turns on or off the external trigger out enable.
*/
RETCODE EXPORT TrcTrigOutEnableTask(DESCRIPTOR desc){
   BOOLEAN bit;
   RETCODE err;
   if ((err = SdReadMember(desc, &bit)) != GOOD) return(err);

   return(GOOD);
}

/*
**  TrcUpdatesPerMinuteTask
**     Sets up a VRTX task to periodically poll and write various trace system
**     conditions to the shared data server.  This is used by a host to get
**     periodic updates for real-time displays.  The items polled are:
**        1. SD_SEQUENCE_LEVEL
**        2. SD_CURRENT_SUBBUFFER
**        3. SD_COUNTER_VALUE (0 and 1)
**        4. SD_MAX_TRACE_BUFFER
*/
RETCODE EXPORT TrcUpdatesPerMinuteTask(DESCRIPTOR desc) {
   RETCODE err;
   U32 updatesPerMinute;
   if ((err = SdReadMember(desc,&updatesPerMinute)) != GOOD) return(err);
//???   if (updatesPerMinute == 0) updateInterval = 0;
//???   else {
//???      updateInterval = ((60*SECOND) / updatesPerMinute);
//???      if (updateInterval == 0) updateInterval = 1;
//???   }
   return(err);
}

/*
**  TrcGetStatusTask
**     Reads then updates the trace system status.  When all status items have
**     been updated, firmware sets SD_TRACE_GET_STATUS back to FALSE.  The
**     items updated are:
**        1. SD_SEQUENCE_LEVEL
**        2. SD_CURRENT_SUBBUFFER
**        3. SD_COUNTER_VALUE (0 and 1)
*/
RETCODE EXPORT TrcGetStatusTask(DESCRIPTOR desc){
   RETCODE err;
   BOOLEAN status=FALSE;
   if((err=TrcWriteStatus())!=GOOD) return(err);
   return(SdWriteMemberNoCallback(desc,&status,GOOD));
}

RETCODE EXPORT TrcWriteStatus(VOID) {
   RETCODE err;
   U16 curSubBuf, cnt0, cnt1, maxBuf, level;

   err = Sds2AbiGetTraceInfo(&level, &curSubBuf, &cnt0, &cnt1, &maxBuf);
   if (err != GOOD) return(err);
   err = SdWriteMember(descSeqLevel, &level,GOOD);
   if(!err) err = SdWriteMember(descCurSubbuffer,&curSubBuf,GOOD);
   if(!err) err = SdWriteMember(descCounter0,&cnt0,GOOD);
   if(!err) err = SdWriteMember(descCounter1,&cnt1,GOOD);
   if(!err) {
      err = SdWriteMember(descMaxBuffer,&maxBuf,GOOD);
   }   
   return(err);
}

/*
**  TrcTracingTask
**     Used by host software to manually start and stop tracing.  Also used by
**     start emulation commands to start the trace hardware before emulation
**     begins.  Writing TRUE causes tracing to begin immediately within the
**     current trace buffer.  Writing FALSE stops tracing after the current
**     trace buffer is filled.
*/
RETCODE EXPORT TrcTracingTask(DESCRIPTOR desc){
   RETCODE err;
   BOOLEAN tracing;

//   err = TrcTracingAction(desc,&tracing);

   if ((err = SdReadMemberNoInputCheck(desc, &tracing)) != GOOD) return(err);
   if ((err = Sds2AbiSetTracing(tracing)) != GOOD) return(err);
   SdnWriteMember(SDN_FW_TRACING_STATUS,&tracing,err);
   return(SdnWriteMember(SDN_TRACING,&tracing,err));
}

RETCODE EXPORT TrcTracingAction(DESCRIPTOR desc,BOOLEAN *tracing){
   U16 numTrcbufs, i;
   RETCODE err;
   BOOLEAN empty,false=FALSE,true=TRUE;
   if ((err = SdReadMember(desc, tracing)) != GOOD) return(err);
   if (*tracing) {
      if((err = SdReadMember(descTraceEmpty,&empty))!=GOOD) return(err);
      if (!empty) //VramClearSam();   /* Clear out any overrun frames */
      if ((err=SdReadMember(descNumTrcbufs,&numTrcbufs)) != GOOD) return(err);
      if (numTrcbufs == 1) {
//???
      }
      if((err = SdWriteMember(descTracing, &true, GOOD)) != GOOD) return(err);
      if((err = SdWriteMember(descTraceEmpty,&false,GOOD))!=GOOD) return(err);
   }
   else {
//???
   }
   return(GOOD);
}

/*
**  TrcEnableSequencerTask
**     Turns sequencer on and off.  Used for stopping while trace system
**     parameters are reprogrammed. Enabling the sequencer actually causes
**     trace system reprogramming to occur.  All queued requests are
**     combined to generate the final xilinx config and setup parameters.
*/
RETCODE EXPORT TrcEnableSequencerTask(DESCRIPTOR desc){
   BOOLEAN enable;
   RETCODE err,err2;
   if ((err = SdReadMember(desc, &enable)) != GOOD) return(err);
   /*
   **  Lower priority so that all other sd items in queue will complete
   **  before the sequencer is enabled.
   */
   err = EnableSequencerAction(enable);
   err2 = SdnWriteMember(SDN_ENABLE_SEQUENCER_ACK, &err, err);
   return(err?err:err2);
}

RETCODE EXPORT EnableSequencerAction(BOOLEAN enable) {
   return(GOOD);
}

/*
**  TrcClearTraceTask
**     Resets trace buffer pointers to zero and initializes VRAM serial buffer
**     pointer.  Does not actually clear VRAM or side data file contents.
*/
RETCODE EXPORT TrcClearTraceTask(DESCRIPTOR desc){
   BOOLEAN value;
   LOOP_VAR i;
   RETCODE err;

   if ((err = SdReadMember(desc, &value)) != GOOD) return(err);
   if (value) {
      if((err = SdWriteMember(descTraceEmpty,&value,GOOD))!=GOOD) return(err);
      ClearTriggerPositions();
      value = FALSE;
      if((err = SdWriteMember(desc,&value,GOOD)) != GOOD) return(err);
   }
   return(GOOD);
}

/*
**  TrcIncTraceBufferTask
**     Performs the equivalent of trigger-and-continue action.  TMAN DOES NOT
**     CURRENTLY SUPPORT THIS FUNCTION.
*/
RETCODE EXPORT TrcIncTraceBufferTask(DESCRIPTOR desc){
   return(ER_NOT_SUPPORTED);
}

/*
**  TrcResetSequenceLevelTask
**     Writes to TMAN causing the sequencer level to be set to 0.  May be
**     called while sequencer is running.  Writes 0 to member when done.
*/
RETCODE EXPORT TrcResetSequenceLevelTask(DESCRIPTOR desc){
   BOOLEAN value;
   RETCODE err;
   if ((err = SdReadMember(desc, &value)) != GOOD) return(err);
   if (value) {
      value = FALSE;
      if ((err = SdWriteMember(desc,&value,GOOD)) != GOOD) return(err);
   }
   return(GOOD);
}

VOID EXPORT ReadTraceFrame(U32 frame, TRACE_FRAME *result) {
//???
}

VOID EXPORT WriteTraceFrame(U32 frame, TRACE_FRAME result) {
//???
}

/*
**  TrcWriteLengthTask
**     Writes specified length of data found in SD_TRACE_WRITE_DATA to address
**     found in SD_TRACE_WRITE_ADDRESS in the trace buffer memory.
*/
RETCODE EXPORT TrcWriteLengthTask(DESCRIPTOR desc) {
   RETCODE err;
   TRACE_FRAME tempFrame;
   U32 length;
   U32 frame;
   DESCRIPTOR tempDesc;
   LOOP_VAR frameCount;
   if ((err = SdReadMember(desc, &length)) != GOOD) return(err);
   if ((err = SdnRegister(SDN_TRACE_WRITE_ADDRESS,NULLPTR,&tempDesc)) != GOOD)
      return(err);
   if ((err = SdReadMember(tempDesc, &frame)) != GOOD) {
      SdUnRegister(tempDesc);
      return(err);
   }
   if ((err = SdUnRegister(tempDesc)) != GOOD) return(err);
   if ((err = SdRegister(SD_TRACE_WRITE_DATA,NULLPTR,&tempDesc)) != GOOD)
      return(err);
   for (frameCount=0; frameCount<length; frameCount++) {
      if ((err = SdReadPartialMember(tempDesc, frameCount*sizeof(TRACE_FRAME),
            sizeof(TRACE_FRAME), &tempFrame)) != GOOD) {
         SdUnRegister(tempDesc);
         return(err);
      }
      WriteTraceFrame(frame++,tempFrame);
   }

   if ((err = SdUnRegister(tempDesc)) != GOOD) return(err);
   return(GOOD);
}

/*
**  TrcSearchTask
**     Registered on SD_SEARCH_START_FRAME item.  Searches trace buffer
**     for a frame matching specified event.  Writes match frame to
**     SD_SEARCH_START_FRAME (if found), then writes TRUE or FALSE to
**     SD_FOUND_SEARCH_EVENT.
*/
RETCODE EXPORT TrcSearchTask(DESCRIPTOR desc) {
   RETCODE err;
   BOOLEAN found;
   err = TrcSearchBuffer(desc, &found);
   return(SdnWriteMember(SDN_FOUND_SEARCH_EVENT,&found,err));
}
   
/* 
**    GetTraceFrames
**       Reads numFrames frames of trace.  If weedOutEmon is TRUE then we
**    only return the frames with the EMON bit on.
*/
RETCODE GetTraceFrames(U16 buffer, U32 frameNo, U32 numFrames, 
                       U32 *framesRead, TRACE_FRAME *frames){

RETCODE  err;
U32      num;

   num = numFrames;
   err = Sds2AbiGetTraceFrames(buffer, frameNo, &num, frames);
   if (err != GOOD) return(err);
   *framesRead = num;
   return(GOOD);
}

RETCODE EXPORT TraceSearch(U16 buffer, U32 *startFrame, EVTREC_RANGE *event,
         TRACE_SEARCH_DIRECTION dir, BOOLEAN *found) {
TRACE_FRAME frame;
RETCODE  err;
U32   r, s, t, u, framesRead;
S32   start, end, curFrame;
BOOLEAN  abortFromEsc;


   err = Sds2AbiGetTraceBufferLogicInfo(buffer, &start, &end);
   if (err != GOOD) return(err);

   *found = FALSE;
   if (dir == TRACE_SEARCH_FORWARD) {
      for (; ; (*startFrame)++)  // search until end of buffer if not found
         {
         //add by Eric 1/14/98
         err = TskCheckAbort(&abortFromEsc);
         if(err!=GOOD) return err;
         if (abortFromEsc!=0) {
            err = ER_ABORT_FROM_ESC;
            return err;
         }
         //eof Eric 1/14/98
         curFrame = *(S32 *)startFrame;
         if (curFrame > end) break;
         if((err=GetTraceFrames(buffer,*startFrame,(U32)1ul,&framesRead,&frame)) != GOOD) return(err);
         if (framesRead != 1ul) break;
         r = (((U32)frame.groupRmsw) << 16) | ((U32)frame.groupRlsw);
         s = (((U32)frame.groupSmsw) << 16) | ((U32)frame.groupSlsw);
         t = (((U32)frame.groupTmsw) << 16) | ((U32)frame.groupTlsw);
         u = (((U32)frame.groupUmsw) << 16) | ((U32)frame.groupUlsw);

         // range R: address match?
         if (event->low != event->high)
            {
            // range address
            if ((r < event->low) || (r > event->high)) continue;  // not in range
            }
         else {
            // range S: mask address
            if ((event->low & event->mask) != (r & event->mask)) continue;
            }

         // data match?
         event++;
         if ((event->low & event->mask) != (s & event->mask)) {
            event--;
            continue;
         }
         // range T: status & misc match?
         event++;
//kevin         event->low &= 0xfffffffbul;
//kevin         event->mask &= 0xfffffffbul;
         if ((event->low & event->mask) != (t & event->mask)) {
            event -= 2 ;
            continue;
         }
         *found=TRUE;
         break;
         }
   } else {
      *found=TRUE;   // seems never reach here!
   }
   return(GOOD);
}

RETCODE EXPORT TrcSearchBuffer(DESCRIPTOR desc, BOOLEAN *found) {
   RETCODE err;
   U16 buffer;
   S32 startFrame; 
   LOOP_VAR group;
   EVTREC_RANGE event[NUM_GROUPS];
   *found=FALSE;
   if((err=SdReadMember(desc,&startFrame))!=GOOD) return(err);
   if((err=SdnReadMember(SDN_SEARCH_BUFFER,&buffer))!=GOOD) return(err);
   if( !ValidTraceBuffer(buffer) ) return(ER_INVALID_BUFFER);
   for (group=0; group<NUM_GROUPS; group++) {
      if((err=SdnReadMember(SDN_SEARCH_EVENT+group,&event[group]))!=GOOD)
         return(err);
      event[group].low  &= event[group].mask;
      event[group].high &= event[group].mask;
   }
   if ((err = TraceSearch(buffer, &startFrame, event,
                        TRACE_SEARCH_FORWARD, found)) != GOOD)
      return(err);
   if( *found ) {
      if((err=SdWriteMember(desc,&startFrame,GOOD)) != GOOD ) return(err);
   }
   return(GOOD);
}
    
U32 EXPORT IncPhysicalFrame(U32 frame, S32 count) {
   return(frame+count);
}

U16 EXPORT NumTraceBuffers(VOID) {
   static U16 oldNumTraceBuffers;
   U16 numTraceBuffers;
   if( SdnReadMember(SDN_NUM_TRCBUFS,&numTraceBuffers) ) return(1);
   if( numTraceBuffers ) oldNumTraceBuffers = numTraceBuffers;
   else numTraceBuffers = oldNumTraceBuffers;  // use old value if comes back 0
   return(numTraceBuffers);
}

U16 EXPORT NumSubBufsPerTraceBuffer(VOID) {
   return(NUM_SUBBUFFERS/NumTraceBuffers());
}

/*
** IncSubBuffer
**    Adds or subtracts count from the given sub buffer number.  This
**    handles wrapping results within a trace buffer (i.e.: keeps
**    results within the number of sub buffers per trace buffer range).
*/
U16 EXPORT IncSubBuffer(U16 subBuff, S16 count) {
   U16 numSubBuffers;
   numSubBuffers = NumSubBufsPerTraceBuffer();
   return( ((subBuff + count) & (numSubBuffers-1))
          | (subBuff & ~(numSubBuffers-1)) );
}

RETCODE EXPORT TraceBufferInfo(U16 buffer, BOOLEAN emon, S32 *oldest, S32 *youngest){
   *oldest = 0;
   *youngest = 0;
   if( !TraceIsEmpty(buffer) ) {
      U32 numFrames;
      if( (numFrames=GetNumFramesInTraceBuffer(buffer)) == 0)
         return(GOOD);    /* NO frames in trace buffer at ALL */
      *oldest = -GetNumFramesBeforeTrigger(buffer);
      *youngest = GetNumFramesAfterTrigger(buffer);
   }
   return(GOOD);
}

U16 GetMaxValidTraceBuffer(VOID) {
   U16 level, curSubBuf, cnt0, cnt1, maxBuf;

   Sds2AbiGetTraceInfo(&level, &curSubBuf, &cnt0, &cnt1, &maxBuf);
   return(maxBuf);
}

RETCODE EXPORT TrcMaxBuffer(DESCRIPTOR desc) {
   U16 maxBuffer;
   maxBuffer = GetMaxValidTraceBuffer();
   SdWriteMember(desc, &maxBuffer, GOOD);
   return(GOOD);
}   

/*
** ValidTraceBuffer
**    Determines if the incoming trace buffer is a valid trace buffer.
**    There's two conditions to check.  First is the trace store split
**    up into at least that many buffers and second has that trace buffer 
**    been filled yet.
*/
BOOLEAN ValidTraceBuffer(U16 buffer) {
   if( !buffer ) return(TRUE);
   if( buffer > GetMaxValidTraceBuffer() ) return(FALSE);
   return(TRUE);
}
   
RETCODE EXPORT TrcBufferCheckTask(DESCRIPTOR desc) {
   BOOLEAN emon;
   S32 oldest=0, youngest=0;
   U16 buffer;
   RETCODE err;
   err=SdReadMember(desc,&buffer);
   if( !ValidTraceBuffer(buffer) ) err=ER_INVALID_BUFFER;
   if( !err ) {
      emon = FALSE;
      if( !err ) err = TraceBufferInfo(buffer, emon, &oldest, &youngest);
   }
   if( !err ) SdnWriteMember(SDN_BUFFER_OLDEST,&oldest,err);
   /* might write to YOUNGEST since Host is pending on this write. */
   SdnWriteMember(SDN_BUFFER_YOUNGEST,&youngest,err);
   return(GOOD);
}

RETCODE EXPORT TrcLinkedCursorTask(DESCRIPTOR desc) {
   BOOLEAN instFrame;
   RETCODE err;
   err = TrcLinkedCursor(desc,&instFrame);
   return(SdnWriteMember(SDN_LINKCURS_INST,&instFrame,err));
}
   
RETCODE EXPORT TrcLinkedCursor(DESCRIPTOR desc, BOOLEAN *instFrame) {
   BOOLEAN emon, foundOne;
   TRACE_FRAME frameData;
   S32 logFrame, frame, frameNo, tmpFrame;
   U32 address;
   U16 buffer, count, loop;
   S32 oldest, newest;
   RETCODE err;
   *instFrame = FALSE;
   if((err=SdReadMember(desc,&logFrame))!=GOOD) return(err);
   if((err=SdnReadMember(SDN_LINKCURS_BUFFER,&buffer))!=GOOD) return(err);
   if( !ValidTraceBuffer(buffer) ) return(ER_INVALID_BUFFER);
   
   if((err=Sds2AbiGetTraceBufferLogicInfo(buffer,&oldest,&newest))!=GOOD) return(err);
   if (oldest<-2 && logFrame > -16) 
     { tmpFrame=-2;
       GetStartingBusCycle(buffer,&tmpFrame,&frameData,&foundOne);     
       if((frameData.groupTlsw & 0xe0)==0xE0)
         for(loop=0;loop<14;loop++) {
           {  tmpFrame--;
              GetStartingBusCycle(buffer,&tmpFrame,&frameData,&foundOne);
              if((frameData.groupTlsw & 0xe0)==0x40||(frameData.groupTlsw & 0xe0)==0xc0)  
                   if(frameData.groupSlsw==0xa000) 
                     break;
           }
         if(logFrame>tmpFrame)  logFrame=tmpFrame;
       }
     }  

   frameNo = logFrame;
   if((err=GetStartingBusCycle(buffer, &frameNo, &frameData, &foundOne)) 
      !=GOOD) return(err);
   if( foundOne )
      {
      // check if it is a supervisor or user program cycle
      *instFrame=(((frameData.groupTlsw & 0xe0) == 0x40) ||
                  ((frameData.groupTlsw & 0xe0) == 0xc0));
      address = (U32)frameData.groupRmsw;
      address = (address << 16) + frameData.groupRlsw;
      }
   if( foundOne ) {
      if((err=SdnWriteMember(SDN_LINKCURS_ADDRESS,&address,GOOD))!=GOOD)
         return(err);
   }
   return(GOOD);
}

/* !!! processor specific routine */
/*
** GetStartingBusCycle
*/         /* processor specific routine now!!! */
RETCODE GetStartingBusCycle(U16 buffer, S32 *frameNo, TRACE_FRAME *frame,
         BOOLEAN *foundOne) {
   RETCODE err;
   PROBE_TYPE probeType;
   U32 framesRead;

   *foundOne = FALSE;
   if ((err = SdnReadMember(SDN_PROBE_TYPE, &probeType)) != GOOD) return(err);
   if((err=GetTraceFrames(buffer, *frameNo, (U32)1L, &framesRead, frame)) 
         != GOOD) return(err);
   if( framesRead == 1ul ) *foundOne = TRUE;
   return(GOOD);
}

RETCODE ForwardReadTrace(U16 buffer, U32 frameNo, TRACE_CYCLES mode,
                         U32 *numFrames, TRACE_INFO *traceData){
   RETCODE err;
   BOOLEAN firstTime = TRUE, foundOne;
   LOOP_VAR i, j;
   TRACE_FRAME frame[0x20];
   U32 before, maxNumFrames, requestedFrames=*numFrames, prevInstFrame;

   traceData[0].rGroup = 0xffffffffL; // timestamp signature
   traceData[0].frameNumber = frameNo;

   if( !maxNumFrames ) return(ER_END_OF_BUFFER);  /* no frames to read */
   if( requestedFrames > 256 ) return(ER_TOO_MANY_FRAMES);
   if( requestedFrames > maxNumFrames ) requestedFrames = maxNumFrames;
   *numFrames = 0;
   for(i=1; i <= requestedFrames; ) {
      U32 framesRead;

      // MICEpack send up to 64 frames
      framesRead = min(requestedFrames, (U32)0x20L);
      if((err=GetTraceFrames(buffer,frameNo,framesRead,&framesRead,&frame))
            != GOOD ) return(err); 
      if( firstTime ) {
         foundOne = (framesRead != 0);
      }
      if( firstTime ) {
         if( !foundOne ) return(ER_END_OF_BUFFER);
         firstTime = FALSE;
      }
      else {/* we found at least one frame it's ok to fail now-just return */
         if( !foundOne ) return(GOOD);
      }

      (*numFrames) += framesRead;
      for (j=0; j < framesRead; j++)
         {
         traceData[i].frameNumber = frameNo++;
         traceData[i].rGroup = (((U32)frame[j].groupRmsw) << 16) | ((U32)frame[j].groupRlsw);
         traceData[i].sGroup = (((U32)frame[j].groupSmsw) << 16) | ((U32)frame[j].groupSlsw);
         traceData[i].tGroup = (((U32)frame[j].groupTmsw) << 16) | ((U32)frame[j].groupTlsw);
         traceData[i].uGroup = (((U32)frame[j].groupUmsw) << 16) | ((U32)frame[j].groupUlsw);

         /* added for mtat2 trace data <gene> */
         traceData[i].tshGroup = frame[j].groupTSH;
         traceData[i].tsGroup = frame[j].groupTS;
         traceData[i++].leGroup = frame[j].groupLE;
         }
      if (framesRead < (U32)0x20) break;
   }
   (*numFrames)++;   // incr for timestamp Marker
   
   return(GOOD);
}

/*
**
**  TrcReadTraceTask
**
**  Description:
**     Registered on SD_TRACE_BUFF_LEN field of all trace buffer windows.
**     Reads the specified frames from TMOD VRAM.  Now being changed to
**     handle checking for physical limits within a buffer.  Also if
**     SD_TRACE_BUFF_LEN field is negative a backward read is done.
**     Also SDN_FRAME_TYPE is read to determine if bus cycles or clock
**     cycles are being processed.
*/
RETCODE EXPORT TrcReadTraceTask(DESCRIPTOR desc){
   RETCODE err, err2;
   if((err=TrcReadTrace(desc))!=GOOD) {
      MEMBER_INDEX index;
      TRACE_INFO traceData;
      DESCRIPTOR tempDesc;
      err2=SdGetMemberIndex(desc,&index);
      if(!err2) err=SdnRegister(SDN_TRACE_STORE+index,NULLPTR,&tempDesc);
      if( !err2 )
         err2=
           SdWritePartialMember(tempDesc,0,sizeof(TRACE_INFO),&traceData,err);
      SdUnRegister(tempDesc);
      return(err2);
   }
   return(GOOD);
}
      
RETCODE EXPORT TrcReadTrace(DESCRIPTOR desc){
   RETCODE err,err1;
   MEMBER_INDEX index;
   TRACE_INFO *traceData;
   DESCRIPTOR tempDesc;
   S32 length, logFrame;
   U16 buffer;
   U32 frameNo, frameCount=0, memSize;
   TRACE_CYCLES frameMode;
   if ((err = SdReadMember(desc, &length)) != GOOD) return(err);
   /* clear out host count incase we error out */
   if((err=SdWriteMemberNoCallback(desc,&frameCount,GOOD))!=GOOD) return(err);
   if ((err = SdGetMemberIndex(desc,&index)) != GOOD) return(err);
   if ((err = SdnReadMember(SDN_TRACE_START_FRAME+index, &logFrame)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_ACTIVE_BUFFER+index, &buffer)) != GOOD)
      return(err);
//kevin 12/14/95   if( !ValidTraceBuffer(buffer) ) return(ER_INVALID_BUFFER);
   if( GetNumFramesInTraceBuffer(buffer) == 0 ) return(ER_END_OF_BUFFER);   
   if ((err = SdnRegister(SDN_TRACE_STORE+index,NULLPTR,&tempDesc)) != GOOD)
      return(err);
   if( length < 0 ) frameCount = 0 - length;
   else frameCount = length;
   memSize = sizeof(TRACE_INFO)*(frameCount+1);
   if ((traceData = (TRACE_INFO FAR *)TMalloc(memSize)) == NULL) {
      SdUnRegister(tempDesc);
      return(ER_OUT_OF_MEMORY);
   }
   if( length < 0 ) {   /* backwards trace type */
      S32 oldest;

      if((err=SdnReadMember(SDN_BUFFER_OLDEST,(U8 FAR *)&oldest))!=GOOD) return(err);
      if ((logFrame - (S32)frameCount) < oldest)
         {
         frameCount = (U32)(logFrame - oldest);
         logFrame = oldest;
         }
      else {
         logFrame -= frameCount;
         }
      frameNo = (U32)logFrame;
      err1=ForwardReadTrace(buffer,frameNo,frameMode,&frameCount,traceData);
   }
   else {
      frameNo = (U32)logFrame;
      err1=ForwardReadTrace(buffer,frameNo,frameMode,&frameCount,traceData);
   }
   if((err=SdWriteMemberNoCallback(desc,&frameCount,GOOD))!=GOOD) {
      TFree(traceData);
      SdUnRegister(tempDesc);
      return(err);
   }
   if( err1 || !frameCount ) frameCount = 1;   /* write at least one since
      host is waiting */
   if ((err = SdWritePartialMember(tempDesc,0,sizeof(TRACE_INFO)*frameCount,
         traceData,err1)) != GOOD) {
      TFree(traceData);
      SdUnRegister(tempDesc);
      return(err);
   }
   if ((err = SdUnRegister(tempDesc)) != GOOD) return(err);
   TFree(traceData);
   return(GOOD);
}

/**************************************************************************
**
** TrcSetShowCycleEnable
** TrcGetShowCycleEnable
**
**************************************************************************/
RETCODE EXPORT TrcSetShowCycleEnable(BOOLEAN enable) {
   showCycleEnable = enable;
   return(GOOD);
}

RETCODE EXPORT TrcGetShowCycleEnable(BOOLEAN *enable) {
   *enable = showCycleEnable;
   return(GOOD);
}

RETCODE EXPORT TrcGetCounters(U16 *cnt0, U16 *cnt1) {
RETCODE err;
   U16 curSubBuf, maxBuf, level;
   err = Sds2AbiGetTraceInfo(&level, &curSubBuf, cnt0, cnt1, &maxBuf);
   return(err);
/*   if ((err = SdnReadMember(SDN_COUNTER_VALUE, cnt0)) != GOOD)
      return(err);
   if ((err = SdnReadMember(SDN_COUNTER_VALUE+1, cnt1)) != GOOD)
      return(err);
   return(err);
*/
}

/******************************************************
**
**   TrcDlgQTraceProc
**
** The dialog window procedure
**
**  returns result to DialogBox callerwith EndDialog() function::
**    0:   Disable qualify trace
**    1:   Enable qualify trace
**
**  After pressing OK, if parse is not successful (or
**  some other error occurs), we display the error, and
**  permit a retry.  User can exit with Cancel, though.
**
**  Note that errors are NOT propagated up to Actor level.
**
**
**  The params follow Windows 3.0 conventions, NOT those of Win3.1
**
**  Return value is standard also: a Windows BOOL, NOT the
**  Powerviews BOOLEAN!
**  returns TRUE of message was handled, FALSE if not handled.
**
** 101/102: Enable/Disable Buttons
** 104,106: Edit Boxes
** 110-129: Radio Buttons
**
*******************************************************/
#pragma argsused
BOOL EXPORT TrcDlgQTraceProc(HWND hDlg, WORD message, WORD wParam, LONG lParam) {
static U8  prevActive, numSig, bMask=0;
static U32 address=0, addrMask=0;
static U16 qStatus=0, qMask=0, tmpStatus, tmpMask;
U8  index, state;
PROBE_TYPE Processor;

   switch (message) {
      case WM_INITDIALOG:
         // some items are not saved between invocations
         // RegisterHelpEntry(HI_MESSAGEBOXEX, hDlg, HE_MEMCOPY);
         ProcReturnSpecificProcessor(&Processor);
         numSig = (Processor == M68302_MP) ? 7 : 6;
         prevActive = bActive;
         tmpStatus = qStatus;
         tmpMask   = qMask;
         bMask = 2;
         CheckRadioButton(hDlg, 101, 102, 102-bActive); // enable/disable
         SetRadioButtons(hDlg, numSig, tmpStatus, tmpMask);
         SetItemVal(hDlg, 104, "%#lX", address);
         SetItemVal(hDlg, 106, "%#lX", addrMask);
         EnableItems(hDlg, 7, FALSE);
         PostMessage(hDlg, WM_COMMAND, (WORD)102-bActive, NULL); 
         return TRUE;

      case WM_COMMAND:
         if (wParam >= 110 && wParam < 110+3*numSig) {
            index = (wParam - 110) / 3;
            state = (wParam - 110) % 3;
            CheckRadioButton(hDlg, index*3+110, index*3+112, wParam);
            if (state == 2) {
               tmpMask &= ~((U16)0x1 << index);
            }
            else {
               tmpMask |= 1 << index;
               if (state)
                  tmpStatus |= 1 << index;
               else
                  tmpStatus &= ~((U16)0x1 << index);
            }
            return TRUE;
         }
         switch(wParam) {
            case 104: // Edit box of address
               if (bMask && HIWORD(lParam) == EN_CHANGE) {
                  bMask--;
                  if (!bMask) {
//kevin              addrMask = 0xFFFFFFFF;
                     SetItemVal(hDlg, 106, "%#lX", 0xFFFFFFFF);
                  }
               }
               break;
            case 101: // Enable Button
            case 102: // Disable Button
               bActive = 102 - wParam;
               SetRadioButtons(hDlg, numSig, tmpStatus, tmpMask);
               EnableItems(hDlg, numSig, bActive);
               break;
            case IDOK:
               if (GetItemVal(hDlg, 104, &address)!=GOOD ||
                   GetItemVal(hDlg, 106, &addrMask)!=GOOD) { 
                  ErrDisplayError(ER_ADR_INVALID_ADDRESS_STR, CHECK_MODE);
                  break;
               }
               EndDialog(hDlg, bActive);
               if (bActive) {
                  qMask = tmpMask;
                  qStatus = tmpStatus;
                  Sds2AbiSetQualTrace(address, addrMask, qStatus, qMask);
               }
               else
                  Sds2AbiDisableQual();
               return bActive;

/*****
            case IDHELP:
               WinHelp(hDlg, "PWRVIEWS.HLP",
                  HELP_CONTEXT, HE_MEMCOPY);
               return FALSE;
*****/
            case IDCANCEL:
               EndDialog(hDlg, prevActive);
               bActive = prevActive;
               return prevActive;
      }
   }
   return (FALSE);   // Didn't process a message
}

/******************************************************
**
** TrcDlgQTrace   
**
**   Execute the dialog
**
**  called from ACTOR memory presenter menu item...
**
*********************************************************/

RETCODE EXPORT TrcDlgQTrace(HWND hwnd)   {
   int      dlgRet;    // "int" is return type of DialogBox()

   dlgRet = DialogBox(hLib,           // instance (for dlg template)
           "TRCDLGQTRACE",
            hwnd,                     // parent handle
           (FARPROC) TrcDlgQTraceProc);  // within DLL, no proc instance address reqd

   return dlgRet;
}

RETCODE EXPORT TrcGetQTraceActive(void) {
   return bActive;
}

RETCODE PRIVATE EnableItems(HWND hDlg, U8 num, BOOL enable) {
int id;

   for (id=103; id<110+3*num; id++)
      EnableWindow(GetDlgItem(hDlg, id), enable);
   return(GOOD);
}

RETCODE PRIVATE SetRadioButtons(HWND hDlg, U8 numSig, U16 qStatus, U16 qMask) {
U8 index, pos, state;

   for (index=0; index < numSig; index++) {
      pos = 1 << index;
      if (qMask & pos)
         state = (qStatus & pos) ? 1 : 0;
      else
         state = 2;
      pos = 110 + index * 3;
      CheckRadioButton(hDlg, pos, pos+2, pos+state);
   }
   return(GOOD);
}

/**************************************************************************
**
**  GetItemVal
**
**  Purpose: get value from a item
**
**  hDlg (in): handle of the dialog box
**  CtlID (in): ID of the item to be set focus
**  dwVal (out)
**
***************************************************************************/
RETCODE PRIVATE GetItemVal(HWND hDlg, U16 CtlID, DWORD *dwVal) {
   CHAR szVal[20], str[20];
   CHAR *endptr;

   if (GetDlgItemText(hDlg, CtlID, szVal, 20) == NULL) {
      *dwVal = 0;
      return(!GOOD);
   }
   if (!strstr(szVal, "0x") && !strstr(szVal, "0X"))
      strcpy(str, "0x");
   else
      str[0] = '\0';
   strcat(str, szVal);
   *dwVal = strtoul(str, &endptr, 0);
   if (*endptr != '\0')
      return(!GOOD);

   return(GOOD);
}

/**************************************************************************
**
**  SetItemVal
**
**  Purpose: set value in the item
**
**  hDlg (in): handle of the dialog box
**  CtlID (in): ID of the item to be set focus
**  format (in): format for the output value
**  dwVal (in)
**
***************************************************************************/
RETCODE PRIVATE SetItemVal(HWND hDlg, U16 ItemID, LPSTR format, DWORD dwVal) {
   CHAR szStrBuff[100];

   wsprintf(szStrBuff, format, dwVal);
   if (strcmp(format, "%#lX") == 0)
      szStrBuff[1] = 'x';
   SetDlgItemText(hDlg, ItemID, szStrBuff);
   return GOOD;
}

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