#pragma message ( "including mshftcpu.cc" );
/*****************************************************************************/
/*                                                                           */
/*   Function    : f6809Tick()                                               */
/*                                                                           */
/*   Author      : K.W / C.S.                                                */
/*                                                                           */
/*   Description : This function runs one cycle of CPU time emulation.       */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

/*************************************************/
/* CPU MULTI TICK WITH PIA SHIFT REGISTER ACCESS */
/*************************************************/
#define PIA_SHIFT
/***************************************/
/*         MULTI TICK START            */
/***************************************/
{
 static int i;
#if defined SEQUENCER_LIGHTPEN || defined CLAY_ONLY
 if (!iCount)
 {
#endif
  /*****************************************/
  /* Switch on the status of the processor */
  /*****************************************/
  switch (i6809status)
  {
   case CPU_FETCH:
   {
    register T_SWORD ticks_at_once;
    /**********************************************/
    /* Print Instruction disassembly within debug */
    /**********************************************/
#ifdef DEBUG_MSG
    if(tGblDebugLevel==LOW)
    {
     T_UWORD    wUBYTECount,wAddress,wLoop;
     T_CHAR    acTmp[STRING_LENGTH];
     T_CHAR    acDisString[STRING_LENGTH];
     T_CHAR    acLine[STRING_LENGTH];
     fDebug(LOW,(""));
     fDebug(LOW,("f6809shiftmulti() - x   0x%04x    y   0x%04x    d   0x%04x (a=0x%02x  b=0x%02x)",tsCPURegisters.tX,tsCPURegisters.tY,tsCPURegisters.uABD.tD,tsCPURegisters.uABD.sAB.tA,tsCPURegisters.uABD.sAB.tB));
     fDebug(LOW,("f6809shiftmulti() - usp 0x%04x    hsp 0x%04x    dp  0x%02x",tsCPURegisters.tUSP,tsCPURegisters.tHSP,tsCPURegisters.tDP));
     fDebug(LOW,("f6809shiftmulti() - pc  0x%04x    cc  0x%02x (c=%d v=%d z=%d n=%d)",tsCPURegisters.tPC,tsCPURegisters.uCC.tCC,tsCPURegisters.uCC.sCC.bC,tsCPURegisters.uCC.sCC.bV,tsCPURegisters.uCC.sCC.bZ,tsCPURegisters.uCC.sCC.bN));
     fDebug(LOW,("f6809shiftmulti()"));

     wAddress=f6809Disassemble(tsCPURegisters.tPC,acDisString);
     wUBYTECount=wAddress-tsCPURegisters.tPC;
     sprintf(acLine,"%04x  ",tsCPURegisters.tPC);

     for (wLoop=0;wLoop<wUBYTECount;wLoop++)
     {
      sprintf(acTmp,"%02x ",f6809AddressRead(tsCPURegisters.tPC+wLoop));
      strcat(acLine,acTmp);
     }
     for(wLoop=wUBYTECount;wLoop<4;wLoop++)
     {
      strcat(acLine,"   ");
     }
     strcat(acLine,"  ");
     strcat(acLine,acDisString);
     fDebug(LOW,("f6809shiftmulti() - %s",acLine));
     fDebug(LOW,("f6809shiftmulti()"));
    }
#endif
    /***********************************************************/
    /* iBPTriggered is used as a state toggle, breakpoints     */
    /* are only enabled if they haven't been triggered         */
    /* on the next trip thru after trigger, the BPTrigger will */
    /* be cleared and we'll go into CPU_DECODE                 */
    /***********************************************************/
#ifdef DEBUG_MON
    if (iBreakpointEnable && iBreakpoint==tsCPURegisters.tPC && !iBPTriggered)
    {
     if (iSkipCount>0)
     {
      iSkipCount--;
     }
     else
     {
//     bGblDebugMonitorEnable=T_TRUE;
      bGblPauseMode=T_TRUE;
      vector_undraw();
      vector_refresh();
      vectrex_update->frequency=1;
      if (bGblDebugMonitorEnable!=T_TRUE)
      if (open_monitor_window()==T_TRUE)
      {
       bGblDebugMonitorEnable=T_TRUE;
       if (bGblGUIEnable==T_FALSE)
       {
        WINDOW_LISTEN_ELEMENT *MonitorWin=get_window(MonitorWinId);
        hide_raw_window(MonitorWin);
        back_save(FORCED_SAVE);
        show_all_windows();
       }
       bGblGUIEnable=T_TRUE;
       set_functions();
       reset_state=T_FALSE;
       wGblQuitFlag=EMU_RESTART;
      }
      iBPTriggered=T_TRUE;
      break;
     }
    }
    else
    {
     iBPTriggered=T_FALSE;
    }
    iLastAddress=tsCPURegisters.tPC;
#endif
    /**********************************************************/
    /* ...   interrupt status ignore NMI as it is unconnected */
    /* Interrupt can't happen in multi tick (supposedly)      */
    /**********************************************************/
    /* Chris: Interrupts should not occur while in Multitick  */
    /**********************************************************/
/*
    if (tsCPURegisters.tIRQFlag && !tsCPURegisters.uCC.sCC.bI)
    {
     fDebug(HIGH,("f6809shiftmulti() - IRQ Detected <PC=%04x>",tsCPURegisters.tPC));
     tsCPURegisters.tIRQFlag=0;
     #include "pia.cc"
     ticks_at_once=f6809IRQ();
     tsCPURegisters.tPC=(f6809FastAddressRead(0xfff8)<<8)+f6809FastAddressRead(0xfff9);

     lwGblSystemTickTotal++;
     for (i=0;i<ticks_at_once;i++)
     {
      #include "pia.cc"
      lwGblSystemTickTotal++;
     }

     u6522Timer1.uCount.tW-=(++ticks_at_once);
     u6522Timer2.uCount.tW-=ticks_at_once;
     break;
    }
    else if (tsCPURegisters.tFIRQFlag && !tsCPURegisters.uCC.sCC.bF)
    {
     fDebug(HIGH,("f6809shiftmulti() - FIRQ Detected <PC=%04x>",tsCPURegisters.tPC));
     tsCPURegisters.tFIRQFlag=0;
     #include "pia.cc"
     ticks_at_once=f6809FIRQ();
     tsCPURegisters.tPC=(f6809FastAddressRead(0xfff6)<<8)+f6809FastAddressRead(0xfff7);
     lwGblSystemTickTotal++;
     for (i=0;i<ticks_at_once;i++)
     {
      #include "pia.cc"
      lwGblSystemTickTotal++;
     }
     u6522Timer1.uCount.tW-=(++ticks_at_once);
     u6522Timer2.uCount.tW-=ticks_at_once;
     break;
    }
    else
*/
    {
     T_UWORD *hpoint;
#ifndef DEBUG_MSG
     ticks_at_once=cycle_count[*(hpoint=(T_UWORD*)(atSystemImage+(tsCPURegisters.tPC++)))];
#endif
#ifdef DEBUG_MSG
     if ((ticks_at_once=cycle_count[*(hpoint=(T_UWORD*)(atSystemImage+(tsCPURegisters.tPC++)))])==-1)
     {
      fDebug(VERROR,("f6809shiftmulti() - Bad instruction decoded #$%02x",iInstruction));
      i6809status=CPU_EXCEPTION;
      #include "pia.cc"
      u6522Timer1.uCount.tW--;
      u6522Timer2.uCount.tW--;
      lwGblSystemTickTotal++;
      break;
     }
     else
     {
      fDebug(LOW,("f6809shiftmulti() - FETCH CYCLE - Addr $%04x,  OpCode #$%02x, %d cycles before decode",iLastAddress,iInstruction,iCount));
     }
#endif
     for (i=0;i<ticks_at_once+1;i++)
     {
      #include "pia.cc"
      lwGblSystemTickTotal++;
     }
     ticks_at_once++;

     u6522Timer1.uCount.tW-=(++ticks_at_once); /* plus 1 because instruction fetch takes one tick */
     u6522Timer2.uCount.tW-=ticks_at_once;
     #include "pia.cc"

/*   i6809status=CPU_DECODE; */
     i6809status=(apfExecuteInstruction[*((T_PUCHAR)hpoint)])();
     fDebug(LOW,("f6809shiftmulti() - FETCH & DECODE CYCLE- Ret  #$%02x",i6809status));
     lwGblSystemTickTotal++;
     break;
    }
    break;
   }
   case CPU_DECODE:
   {
    /****************************************/
    /* multi CPU_FETCH should not come here */
    /****************************************/
    /*********************************************************************/
    /* here it is important to reduce timers BEFORE CALLING PIA_SHIFT!!! */
    /*********************************************************************/
    u6522Timer1.uCount.tW--;
    u6522Timer2.uCount.tW--;
    #include "pia.cc"
    i6809status=(apfExecuteInstruction[iInstruction])();
    fDebug(LOW,("f6809shiftmulti() - DECODE CYCLE- Ret  #$%02x",i6809status));
    lwGblSystemTickTotal++;
    break;
   }
   case CPU_HALT:
   {
    f6522Tick();
    f6809Reset();
    i6809status=CPU_WAIT;
    u6522Timer1.uCount.tW--;
    u6522Timer2.uCount.tW--;
    lwGblSystemTickTotal++;
    break;
   }
   case CPU_EXCEPTION:
   {
    f6522Tick();
    fDebug(VERROR,("f6809shiftmulti() - Exception generated by instruction #$%02x at address $%04x",iInstruction,iLastAddress));
    i6809status=CPU_WAIT;
#ifdef DEBUG_MON
//    bGblDebugMonitorEnable=T_TRUE;
      bGblPauseMode=T_TRUE;
      vector_undraw();
      vector_refresh();
      vectrex_update->frequency=1;
      if (bGblDebugMonitorEnable!=T_TRUE)
      if (open_monitor_window()==T_TRUE)
      {
       bGblDebugMonitorEnable=T_TRUE;
       if (bGblGUIEnable==T_FALSE)
       {
        WINDOW_LISTEN_ELEMENT *MonitorWin=get_window(MonitorWinId);
        hide_raw_window(MonitorWin);
        back_save(FORCED_SAVE);
        show_all_windows();
       }
       bGblGUIEnable=T_TRUE;
       set_functions();
       reset_state=T_FALSE;
       wGblQuitFlag=EMU_RESTART;
      }
#endif
    u6522Timer1.uCount.tW--;
    u6522Timer2.uCount.tW--;
    lwGblSystemTickTotal++;
    break;
   }
   case CPU_CWAI:
   {
    /********************************************************/
    /* CWAI is handled differently as the stack has already */
    /* been pushed                                          */
    /********************************************************/
    /**********************************************************/
    /* Chris: Interrupts should not occur while in Multitick  */
    /**********************************************************/
    f6522Tick();
    if (tsCPURegisters.tIRQFlag && !tsCPURegisters.uCC.sCC.bI)
    {
     tsCPURegisters.tIRQFlag=T_FALSE;
     tsCPURegisters.uCC.sCC.bI=1;
     tsCPURegisters.uCC.sCC.bF=1;
     tsCPURegisters.tPC=(f6809FastAddressRead(0xfff8)<<8)+f6809FastAddressRead(0xfff9);
     i6809status=CPU_FETCH;
     fDebug(HIGH,("f6809shiftmulti() - IRQ Detected, cwai released to addr %04x",tsCPURegisters.tPC));
    }
    else if(tsCPURegisters.tFIRQFlag && !tsCPURegisters.uCC.sCC.bF)
    {
     tsCPURegisters.tFIRQFlag=T_FALSE;
     tsCPURegisters.uCC.sCC.bI=1;
     tsCPURegisters.uCC.sCC.bF=1;
     tsCPURegisters.tPC=(f6809FastAddressRead(0xfff6)<<8)+f6809FastAddressRead(0xfff7);
     i6809status=CPU_FETCH;
     fDebug(HIGH,("f6809shiftmulti() - FIRQ Detected, cwai released to addr %04x",tsCPURegisters.tPC));
    }
    else if(tsCPURegisters.uCC.sCC.bI & tsCPURegisters.uCC.sCC.bI)
    {
     fopen_monitor_debug_pause();
#define _fDebug(level,body) ((bGblDebugEnable==T_TRUE && level>=tGblDebugLevel)?(tGblDebugMsgLevel=level),(fDebugXX body):0)
     _fDebug(HIGH,("f6809shiftmulti() CWAI - CPU permanently halted wait for NMI at addr $%04x",tsCPURegisters.tPC));
#undef _fDebug
    }
    u6522Timer1.uCount.tW--;
    u6522Timer2.uCount.tW--;
    lwGblSystemTickTotal++;
    break;
   }
   case CPU_SYNC:
   {
    f6522Tick();
    /******************************************************************/
    /* Leave the interrupt handler in CPU_FETCH to handle the IRQ now */
    /******************************************************************/
    /**********************************************************/
    /* Chris: Interrupts should not occur while in Multitick  */
    /**********************************************************/
    if (tsCPURegisters.tIRQFlag)
    {
     fDebug(HIGH,("f6809shiftmulti() - IRQ Detected, sync released to addr %04x",tsCPURegisters.tPC));
     i6809status=CPU_FETCH;
    }
    if (tsCPURegisters.tFIRQFlag)
    {
     fDebug(HIGH,("f6809shiftmulti() - FIRQ Detected, sync released to addr %04x",tsCPURegisters.tPC));
     i6809status=CPU_FETCH;
    }
    u6522Timer1.uCount.tW--;
    u6522Timer2.uCount.tW--;
    lwGblSystemTickTotal++;
    break;
   }
   case CPU_WAIT:
   {
    f6522Tick();
#ifndef DEBUG_MSG
    fFatal("f6809shiftmulti() WAIT - CPU ERROR - Exception generated, emulator will die now \n");
#else
//    fAlertBox(RED_BASE+BRIGHT14,"\n f6809shiftmulti() WAIT CPU ERROR - Exception generated, emulator will now reset \n");
    show_message("\n f6809shiftmulti() WAIT CPU ERROR - Exception generated, emulator will now reset \n");
#endif
    bGblStatsValid=T_FALSE;
    fSequencerReboot(0);
    u6522Timer1.uCount.tW--;
    u6522Timer2.uCount.tW--;
    lwGblSystemTickTotal++;
    break;
   }
   default:
   {
    /****************************************************/
    /* Default case is used to add further delay cycles */
    /* 00 = Fetch, all other codes are 0xf8 onwards     */
    /****************************************************/
    if (i6809status>=limit)
    {
     i6809status-=limit;
     u6522Timer1.uCount.tW-=limit;
     u6522Timer2.uCount.tW-=limit;
     {
      for (i=0;i<limit;i++)
      {
       #include "pia.cc"
       lwGblSystemTickTotal++;
      }
     }
     break;
    }
    else
    {
     u6522Timer1.uCount.tW-=i6809status;
     u6522Timer2.uCount.tW-=i6809status;
     {
      for (i=0;i<i6809status;i++)
      {
       #include "pia.cc"
       lwGblSystemTickTotal++;
      }
     }
     i6809status=0;
     break;
    }
   }
  }
#if defined SEQUENCER_LIGHTPEN || defined CLAY_ONLY
 }
 else
 {
  {
   for (i=0;i<iCount;i++)
   {
    #include "pia.cc"
    lwGblSystemTickTotal++;
   }
  }
  u6522Timer1.uCount.tW-=iCount;
  u6522Timer2.uCount.tW-=iCount;
  iCount=0;
 }
#endif
}
/***************************************/
/*          MULTI TICK END             */
/***************************************/

#undef PIA_SHIFT
