/****************************************************************************
**
**  Name:  trig.c
**
**  Description:
**     Provides shared data server handling routines for trigger.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_68k/trace/mp_trig.c_v  $
** 
**    Rev 1.5   30 Apr 1997 10:32:12   gene
** fixed a bug of trigger transfer to level 0 
** 
**    Rev 1.4   22 Apr 1997 14:30:56   gene
** 
**    Rev 1.3   31 Mar 1997 09:48:28   gene
** 
**    Rev 1.2   24 Mar 1997 08:36:44   gene
** 
**    Rev 1.1   04 Mar 1997 13:05:26   gene
** 
**    Rev 1.0   13 Feb 1997 09:07:20   gene
** Initial revision.
** 
**    Rev 1.6   17 Jan 1996 08:56:06   kevin
** in EvtrecTask, using Sds2AbiClearEvent(0xFFFF) to clear all bus events.
** 
**    Rev 1.5   21 Dec 1995 09:47:24   kevin
** AND condition of external-in
** 
**    Rev 1.4   20 Dec 1995 13:21:22   kevin
** fixed a bug of trigger level
** 
**    Rev 1.3   18 Dec 1995 14:40:54   kevin
** An enabled event without any setting should not take effect.
** 
**    Rev 1.2   17 Nov 1995 10:40:22   kevin
** modified convertaction()
** 
**    Rev 1.1   15 Nov 1995 14:39:32   kevin
** modify extEvent initial value
** 
**    Rev 1.0   07 Sep 1995 11:22:22   gene
** Initial revision.
** 
**    Rev 1.7   05 Aug 1993 12:27:26   ernie
** Changed types of tc1,tc1 variables to match shared data sizes.  The
** size mismatch interfered with timer mode.
** 
**    Rev 1.6   28 Jul 1993 13:19:38   ernie
** Added GetYoungestFrame() prototype
** 
**    Rev 1.5   09 Jul 1993 16:44:24   ernie
** Fixed problem with event 6 triggering.  Xilinx def was wrong.
** 
**    Rev 1.4   01 Jun 1993 12:24:56   ernie
** Rearranged EvtrecTask() for efficiency
** 
**    Rev 1.3   26 May 1993 15:52:08   john
** moved function call to be called only when necessary
** 
**    Rev 1.2   19 May 1993 15:28:18   john
** Corrected bug in finding TRACE STORE FULL info
** 
**    Rev 1.1   10 Mar 1993 12:16:04   ernie
** Added support for show cycle triggering and tracing
** 
**    Rev 1.0   16 Dec 1992 15:26:34   mindy
** moved trace to fw
** 
**  $Header:   S:/tbird/mt2_68k/trace/mp_trig.c_v   1.5   30 Apr 1997 10:32:12   gene  $
**
**  Copyright (C) 1992 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

#ifndef _STDIO_
#include "stdio.h"
#endif
/*#ifndef _ERROR_
#include "error.h"
#endif*/
#ifndef _MEMORY_H
#include "memory.h"
#endif
#ifndef _SDPROBE_
#include "sdprobe.h"
#endif
#ifndef _SSHARED_
#include "sshared.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 _TRIG_
#include "trig.h"
#endif
/*!!!*/
#undef PRIVATE
#define PRIVATE  

                        /****************************
                         *                          *
                         *     LOCAL DEFINITIONS    *
                         *                          *
                         ****************************/
#define INIT_NUM_TRCBUFS    1
#define TOTAL_NUM_SUB_BUFFERS 1024

typedef struct {
   EVTREC_TYPE type;
   U16 func1;
   U16 func2;
   U8 frameQual;
   BOOLEAN useDelayed;
} EVTREC_CONFIG;
/*
**    word 0:  bit 15:  1=trace store full (has wrapped)
**             bit 14:  1=trace buffer full (has wrapped)
**             bit 13:  1=trace buffer was entered by trigger-continue
**             bit 12-10:  unused
**             bit 9-0:  physical sub buffer number where trigger occurred
**    word 1:  bit 15-8:  unused
**             bit 7-0:  frame number within sub buffer where trigger is
**                      (valid regardless of size of sub buffer 128 or 256)
*/
typedef struct {
   U16 subBuffer:10;
   U16 Unused1:3;
   U16 trigCont:1;
   U16 bufferFull:1;
   U16 storeFull:1;
   U8 frame;
   U8 Unused2;
} TRIG_POS;

static DESCRIPTOR descQualMode;
static BOOLEAN triggerAbort = FALSE;
static U16 subBufferSize;

                        /****************************
                         *                          *
                         *    EXTERNAL VARIABLES    *
                         *                          *
                         ****************************/
/*
** This array is the destination of DMA cycles initiated by the TMAN when
** a trigger occurs.  It must be word-aligned and totally contained within
** a single 64k physical memory block.
*/
TRIG_POS triggerPos[MAX_TRCBUFFERS];
extern DESCRIPTOR trigId;

                        /****************************
                         *                          *
                         *     LOCAL PROTOTYPES     *
                         *                          *
                         ****************************/
/*
** Shared Data Server Handler routines
*/
RETCODE EXPORT TriggerProgramTask(DESCRIPTOR desc) ;
RETCODE PRIVATE TriggerProgram(DESCRIPTOR desc);
RETCODE EXPORT EvtrecTask(DESCRIPTOR desc);
/*
** Other local routines
*/
RETCODE EXPORT TriggerProgramAbort(DESCRIPTOR desc);
                
                        /****************************
                         *                          *
                         *      EXECUTABLE CODE     *
                         *                          *
                         ****************************/

RETCODE EXPORT TrigInit(HANDLE hLib) {
   RETCODE err;
   DESCRIPTOR desc;
   LOOP_VAR i;
   FARPROC  lpProc;
/*
** Register routines to be called when shared data is written.
** Write initial values to members as they are registered so we don't have
** to keep the descriptor.  Some of these need to actually fill data into
** hardware. This is done by re-registering with a null callback so that
** SdWriteMember() will call the callback.
*/
   lpProc = MakeProcInstance((FARPROC)TriggerProgramTask, hLib);
   if((err = SdnRegister(SDN_TRIGGER_INFO,lpProc,&desc))!=GOOD)
      return(err);
   lpProc = MakeProcInstance((FARPROC)TriggerProgramAbort, hLib);
   if((err=SdnRegister(SDN_TRIGGER_PROG_ABORT,lpProc,&desc))
      != GOOD) return(err);
/*
x  {1, SD_TRIGGER_INFO,         SDN_TRIGGER_INFO,        SIZE_TRIGGER,   WR, RD }
x  {1, SD_TRIGGER_PROG_ABORT,   SDN_TRIGGER_PROG_ABORT,  SIZE_BOOL,      WR, RD }
x  {1, SD_TRIGGER_PROGRAM_ACK,  SDN_TRIGGER_PROGRAM_ACK, SIZE_RETCODE,   RD, WR }
  {1, SD_NUM_TRCBUFS,          SDN_NUM_TRCBUFS,         SIZE_WORD,      RW, RD }
  {1, SD_BRK_ON_TRACE_FULL,    SDN_BRK_ON_TRACE_FULL,   SIZE_BOOL,      RW, RD }
  {1, SD_TRACE_MODE,           SDN_TRACE_MODE,          SIZE_TRACE_MODE,RW, RD }
  {1, SD_TRIC_DIAGNOSTIC_MODE, SDN_TRIC_DIAGNOSTIC_MODE,SIZE_BOOL,      RW, RD }
o  {NUM_GROUPS, SD_EVTREC,      SDN_EVTREC,         SIZE_EVTREC_CONFIG,  RW, RD }
o  {1, SD_QUAL_MODE,            SDN_QUAL_MODE,           SIZE_QUAL_MODE, RW, RD }
o  {1, SD_TERMINAL_COUNT_A,     SDN_TERMINAL_COUNT_A,    SIZE_WORD,      RW, RD }
o  {1, SD_TERMINAL_COUNT_B,     SDN_TERMINAL_COUNT_B,    SIZE_WORD,      RW, RD }
  {1, SD_TRIGOUT_ENABLE,       SDN_TRIGOUT_ENABLE,      SIZE_BOOL,      RW, RD }
*/
   {
   U32   tc = 1L;
      if((err = SdnWriteMember(SDN_TERMINAL_COUNT_A,&tc,GOOD))!=GOOD) return(err);
      if((err = SdnWriteMember(SDN_TERMINAL_COUNT_B,&tc,GOOD))!=GOOD) return(err);
   }
   {
      FW_TRIGGER fw;
      U16 level,cond;
      if((err = SdnRegister(SDN_TRIGGER_INFO,NULLPTR,&desc))!=GOOD) 
         return(err);
      for (level=0; level<NUM_LEVELS; level++) {
         for (cond=0; cond<NUM_EVENT_COND; cond++) {
            fw.useEvt[cond][level] = fw.useExt[cond][level] = FALSE;
            fw.action[cond][level] = NULL_MASK;
         }
      }
      if((err = SdWriteMember(desc,&fw,GOOD)) != GOOD) return(err);
      if ((err=SdUnRegister(desc)) != GOOD) return(err);
   }
  
   {
      QUAL_MODE data = QUAL_BUS;
      if ((err = SdnWriteMember(SDN_QUAL_MODE,&data,GOOD))!=GOOD) return(err);
   }

   for(i=0; i<NUM_GROUPS; i++) {
      lpProc = MakeProcInstance((FARPROC)EvtrecTask, hLib);
      if((err = SdnRegister(SDN_EVTREC+i,lpProc,&desc))!=GOOD)
         return(err);
   }

   if((err = SdnRegister(SDN_QUAL_MODE,NULLPTR,&descQualMode))!=GOOD)
      return(err);

   subBufferSize = 128;

   // init external trigger input as bit 1, high active
   // note that this should be matched with Actor code
   // Currently, Actor use above initial state
   return(Sds2AbiSetExtEvent(0x0001));
}

RETCODE EXPORT TriggerProgramAbort(DESCRIPTOR desc) {
   return(SdReadMember(desc,&triggerAbort));
}

/****************************************************************************
**
**  TriggerProgramTask
**
**  Description:
**     First gets the trigger programming information then creates the
**     entire sequencer ram setup. Next writes the entire sequencer ram.
**     Called when the host write the trigger information in the shared
**     data server.
**
**  Parameters:
**     input:
**        desc:  opaque descriptor
**     output:
**        none
**
*****************************************************************************/
RETCODE EXPORT TriggerProgramTask(DESCRIPTOR desc) {
   RETCODE err;
   err = TriggerProgram(desc);
   return(SdnWriteMember(SDN_TRIGGER_PROGRAM_ACK,&err,err));
}
   
RETCODE ConvertAction(ACTION_MASK ppAction, U16 *mpAction)
{
//typedef enum { NULL_MASK=0, SEQ_MASK=1, RESET_MASK=2, TRIG_CONT_MASK=4,
//   TRIG_HALT_MASK=8, EM_BRK_MASK=0x10, INC0_MASK=0x20, INC1_MASK=0x40,
//   RST0_MASK=0x80, RST1_MASK=0x100, START_TMR_MASK=0x200, STOP_TMR_MASK=0x400,
//   RST_TMR_MASK=0x800, EXT_TRIG_ON=0x1000, EXT_TRIG_OFF=0x2000,
//   AM_DUMMY = 0x7fff
//} ACTION_MASK;
// *mpAction = 0;
// if (ppAction & EM_BRK_MASK) *mpAction |= 0x0001;
// if (ppAction & RESET_MASK) *mpAction |= 0x0002;
// if (ppAction & SEQ_MASK) *mpAction |= 0x0004;
//
// //vincent: missing TROFF & NEXT
// if (ppAction & TRIG_HALT_MASK) *mpAction |=0x0008;
// if (ppAction & TRIG_CONT_MASK) *mpAction |= 0x0010;
//
// if (ppAction & INC0_MASK) *mpAction |= 0x0020;
// if (ppAction & RST0_MASK) *mpAction |= 0x0040;
//
// if (ppAction & INC1_MASK) *mpAction |= 0x0080;
// if (ppAction & RST1_MASK) *mpAction |= 0x0100;
//
// //vincent: missing EXTIN & EXTOUT
// if (ppAction & EXT_TRIG_ON) *mpAction |= 0x0400;
// if (ppAction & START_TMR_MASK) *mpAction |= 0x0800;
// if (ppAction & STOP_TMR_MASK) *mpAction |= 0x1000;
//
//
   *mpAction = ppAction;
   return(GOOD);
}

RETCODE PRIVATE TriggerProgram(DESCRIPTOR desc) {
   FW_TRIGGER fw;
   U16 level,cond;
   U32 tc0, tc1;
   RETCODE err;
   MP_TRIGGER  mp_trig;
   TRACE_MODE  traceMode;
   int   used;
   TRIGGER FAR *trigger;

   /* if trigger not open'd assume there's nothing to program */
   if( !trigId ) {
      if((err=TrigTriggerOpen(&trigId,"","default"))!=GOOD) return(err);
   }
   trigger = (TRIGGER FAR *)trigId;

   triggerAbort = FALSE;
   ClearTriggerPositions();   /* need to have this completely done before
                                 we program the sequencer - host sw is
                                 reading trigger info too soon. !!!!
                               */
//   if((err=SdReadMember(desc, &fw)) != GOOD ) return(err);
   if((err=SdnReadMember(SDN_TRIGGER_INFO, &fw)) != GOOD ) return(err);
//   if (triggerAbort) return(ER_TRIGGER_ABORTED);

//   if((err=SdnReadMember(SDN_TERMINAL_COUNT_A,&tc0))!=GOOD) return(err);
//   if((err=SdnReadMember(SDN_TERMINAL_COUNT_B,&tc1))!=GOOD) return(err);
   tc0 = trigger->terminalCount[0];
   tc1 = trigger->terminalCount[1];
   if ((err = Sds2AbiSetTimerCounter(fw.counterMode, tc0, tc1)) != GOOD) return(err);

//   if ((err = Sds2AbiClearTrig(0)) != GOOD) return(err);

   for (level = 0; level < NUM_LEVELS; level++)
      {
//      mp_trig.defined = 0;
      memset(&mp_trig,0,sizeof(MP_TRIGGER));
      used = 0;
      for (cond = 0; cond < NUM_EVENT_COND; cond++)
         {
         if (fw.useEvt[cond][level])
            {
            // set up event list used in this trigger level, meanwhile
            // performing event convertion from PowerPack to MICEPack
            if ((0 <= cond) && (cond <= 7)) mp_trig.evNo[used] = fw.useEvt[cond][level];
            else if ((cond == 8) || (cond == 9)) mp_trig.evNo[used] = cond + 2;
            else if (cond == 10) mp_trig.evNo[used] = 9;
            mp_trig.defined = 1;
//            if (fw.action[cond][level])
//               {
               err = ConvertAction(fw.action[cond][level], &(mp_trig.act[used]));
//               if (fw.useExt[cond][level])     // Gene
//                  mp_trig.act[used] |= 0x0200; // special for ext in condition
               if (err != GOOD) return(err);
               used++;
               mp_trig.delay = 1;
//               }
            }
         }
//      if (mp_trig.defined)
//         {
         mp_trig.evNo[used] = 0; // no more events used
         mp_trig.act[used] = 0;  // so does action

         // set up trace mode if TR1
         if (level == 0)   
            {
            if((err=SdnReadMember(SDN_TRACE_MODE,&traceMode))!=GOOD) return(err);
            if ((err=Sds2AbiConvertTraceMode(traceMode, &(mp_trig.mode))) != GOOD) return(err);
            }
         if ((err = Sds2AbiSetTrig(level + 1, &mp_trig)) != GOOD) return(err);
//         }
      }
   return(GOOD);
}

/****************************************************************************
**
**  EvtrecTask
**
**  Description:
**     Programs one event recognizer.  This routine takes the generic event
**     recognizer xilinx config and modifies the range and mask portions
**     according to input data.  The resulting bitstream is programmed into
**     one xilinx (determined by calling SdGetMemberIndex).
**
**     The QualMode parameter is read when the evtrec sd item is written.
**     The host must follow each write of QualMode by a reconfig of each
**     event recognizer.
**
**  Parameters:
**     input:
**        desc:  opaque descriptor
**     output:
**        none
**
*****************************************************************************/
U32 PRIVATE convert2Status(U32 pvBusStatus)
{
U32   mpBusStatus;

   mpBusStatus = pvBusStatus;
   mpBusStatus = 0xff; //vincent: let it be ALL for test purpose
   return(mpBusStatus);
}

RETCODE EXPORT EvtrecTask(DESCRIPTOR desc){
RETCODE err;
U8 row,LastEvtNo = 0;
MEMBER_INDEX index;
EVTREC_RANGE rangeR, rangeS, rangeT;
BUS_EVENT   bus;

   if ((err = SdGetMemberIndex(desc,&index)) != GOOD) return(err);
   index -= 2;    // only T-GROUP (index 2) will invoke

   // clear all events first
   if ((err = Sds2AbiClearEvent(0xFFFF)) != GOOD) return(err);

   for (row=0; row<8; row++)
      {
      // get event description first
      if ((err = SdnReadPartialMember(SDN_EVTREC+index,row*sizeof(rangeR),
         sizeof(rangeR),&rangeR)) != GOOD) return(err);
      if ((err = SdnReadPartialMember(SDN_EVTREC+index+1,row*sizeof(rangeS),
         sizeof(rangeS),&rangeS)) != GOOD) return(err);
      if ((err = SdnReadPartialMember(SDN_EVTREC+index+2,row*sizeof(rangeT),
         sizeof(rangeT),&rangeT)) != GOOD) return(err);
      /*
      ** First check if event is used.  If programmed always OFF, leave
      ** programming as default.  OFF is denoted by mask=0 && not=1.
      */
      if ((rangeR.not != 1) || (rangeS.not != 1) || (rangeT.not != 1))
         {
         bus.enable = 1;
         bus.addrLow = rangeR.low;
         if (rangeR.low != rangeR.high)
            {
            // a (address) range breakpoint
            bus.addrSpec = RANGE_ADDR;
            bus.addrHigh = rangeR.high;
            }
         else if (rangeR.mask == 0xffffffffL)
            {
            // single address match, addrHi must be enable
            bus.addrSpec = SINGLE_ADDR;
            bus.addrHigh = 0xffffffff;
            }
            else {
               // address with mask
               bus.addrSpec = MASK_ADDR;
               bus.addrHigh = rangeR.mask;
               }

         // setting data attribute : 16-bits data
         bus.dataLow = (rangeS.low & 0xffffL);
// mask for mtat2, gene
         bus.dataLow = rangeS.low & 0xffffL;
         if ((rangeS.mask & 0xffffL) != 0xffffL) {
            bus.dataSpec = MASK_DATA;
            bus.dataHigh = rangeS.mask & 0xffffL;
         } else {
            bus.dataSpec = MASK_DATA;  // treat SINGLE as special case of MASK
            bus.dataHigh = 0xffffL;
         }
// vincent: need modification
         bus.spareLow = 1;
         bus.spareHigh = 0;

         bus.statusFlag = 1;  // use PowerViews' style
         bus.status2.status2Low = (rangeT.low & 0xfffffffbL);   // mask off bit 2
         bus.status2.status2High = (rangeT.mask & 0xfffffffbL); // mask off bit 2
// trace bit setting for mtat2, gene
         bus.status2.TraceBitLow = (U8)((rangeS.low >> 16) & 0xff); 
         bus.status2.TraceBitHigh = (U8)((rangeS.mask >> 16) & 0xff); 

         // setting status attribute
// vincent: need modification         bus.stat = convert2Status(rangeT.low);

         if ((err = Sds2AbiSetEvent(row+1, &bus)) != GOOD) return(err);
         LastEvtNo = row + 1;
         }
   }
   bus.enable = 0x8001;
   if ((err = Sds2AbiSetEvent(LastEvtNo, &bus)) != GOOD) return(err);
   return(GOOD);
}

VOID EXPORT ClearTriggerPositions(VOID) {
   LOOP_VAR i;
   U8 *ptr = (U8 *)triggerPos;
   for(i=0;i<sizeof(triggerPos);i++)
      *ptr++ = 0;
}

U16 EXPORT GetTriggerSubBuffer(U16 buffer) {
   if( triggerPos[buffer].subBuffer & 0x1 )  /* QSF == 1 */
      return(IncSubBuffer(triggerPos[buffer].subBuffer,-1));
   return(IncSubBuffer(triggerPos[buffer].subBuffer,1));
}

U32 EXPORT GetTriggerFrame(U16 buffer) {
    return(Sds2AbiGetTriggerFrame(buffer));
}

BOOLEAN EXPORT TraceStoreFull(U16 buffer) {
   if (buffer==0) return(triggerPos[(NumTraceBuffers()-1)].storeFull);
   return( triggerPos[buffer-1].storeFull );
}

BOOLEAN EXPORT  TraceIsEmpty(U16 buffer) {
   return(Sds2AbiIsTraceBufferEmpty(buffer));
}

BOOLEAN EXPORT TraceBufferFull(U16 buffer) {
BOOLEAN full;

   Sds2AbiIsTraceBufferFull(buffer, &full);
   return(full);
}

RETCODE EXPORT GetPhysicalTriggerFrame(U16 buffer, U32 *trigger) {
   *trigger = (GetTriggerSubBuffer(buffer)*(U32)subBufferSize) 
               + GetTriggerFrame(buffer) - 8;
   return(GOOD);
}

U16 DecrementTraceBuffer(U16 buffer) {
   U16 numTraceBuffers=NumTraceBuffers();
   return( ((buffer - 1) & (numTraceBuffers-1))
         | (buffer & ~(numTraceBuffers-1)) );
}

U32 EXPORT MaxNumFramesPerTraceBuffer(VOID) {
   return((U32)NumSubBufsPerTraceBuffer() * (U32)subBufferSize);
}

/*
** SubBufferStartOffset
**    Determine if the given trace buffer starts in the first sub buffer
**    (returns offset 0).
*/
U32 EXPORT SubBufferStartOffset(U16 buffer) {
   if( (NumTraceBuffers() > 1) 
      && ((buffer!=0)||((buffer==0) && TraceStoreFull(buffer)))) {
      /* need to read the trigger information of previous trace buffer
         in order to determine which sub buffer we started filling
         this trace buffer with.  hw alternates between filling even
         and odd sub buffers.
       */
      if((GetTriggerSubBuffer(DecrementTraceBuffer(buffer)) & 0x1) != 0)
         /* previous buffer triggered in an odd sub buffer, therefore
            ended filling on an even sub buffer thus this trace buffer
            started filling in sub buffer 1.
          */     
         return((U32)subBufferSize);
   }
   return(0);
}

U32 EXPORT GetNumFramesBeforeTrigger(U16 buffer) {
U32   beforeFrames, afterFrames, trigFrame;

   if( TraceIsEmpty(buffer) ) return(0);
   Sds2AbiGetTraceBufferInfo(buffer, &beforeFrames, &afterFrames, &trigFrame);
   return(beforeFrames);
}

U32 EXPORT GetNumFramesAfterTrigger(U16 buffer) {
U32   beforeFrames, afterFrames, trigFrame;

   if( TraceIsEmpty(buffer) ) return(0);
   Sds2AbiGetTraceBufferInfo(buffer, &beforeFrames, &afterFrames, &trigFrame);
   return(afterFrames);
}

U32 EXPORT GetNumFramesInTraceBuffer(U16 buffer) {
U32   beforeFrames, afterFrames, trigFrame;

   if( TraceIsEmpty(buffer) ) return(0);
   Sds2AbiGetTraceBufferInfo(buffer, &beforeFrames, &afterFrames, &trigFrame);
   return( beforeFrames + 1 + afterFrames);
}

U32 EXPORT GetPhysicalFrame(U16 buffer, S32 frame) {
   U32 trigger;
   if( GetPhysicalTriggerFrame(buffer, &trigger) ) return(0);
   return(IncPhysicalFrame(trigger,frame));
}

/**************************************************************************
**  added for mtat2 68k                                                  **
***************************************************************************/

/*****************************************************************************
** 
**    TrigTriggerAccept
** 
*****************************************************************************/
RETCODE EXPORT TrigTriggerAccept(DESCRIPTOR id) {
   RETCODE err;

   err = TrigTriggerProgram();
   return(err);
}

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