//!  2.2.8.2 Execute a Single Step
//!
//! @param dnNrInstructions
//!
USBDM_GDI_API
DiReturnT DiExecSingleStep ( DiUInt32T dnNrInstructions ) {
    USBDM_ErrorCode BDMrc;

    Logging::print("DiExecSingleStep(%d)\n", dnNrInstructions);

    CHECK_ERROR_STATE();

#if (TARGET == MC56F80xx)
    BDMrc = DSC_TargetStepN(dnNrInstructions);
#else
    if (dnNrInstructions>1) {
        Logging::print("DiExecSingleStep() - Only a single step is supported!\n");
        return setErrorState(DI_ERR_PARAM, ("Only a single step is allowed"));
    }
    BDMrc = USBDM_TargetStep();
#endif

    if (BDMrc != BDM_RC_OK) {
        return setErrorState(DI_ERR_NONFATAL, BDMrc);
    }
    return setErrorState(DI_OK);
}
//!  2.2.8.2 Execute a Single Step
//!
//! @param dnNrInstructions
//!
USBDM_GDI_DECLSPEC
DiReturnT DiExecSingleStep ( DiUInt32T dnNrInstructions ) {
   LOGGING_Q;
   log.print("(%d)\n", dnNrInstructions);

   USBDM_ErrorCode BDMrc;
   long unsigned ccrValue;
   long unsigned pcValue;
   unsigned char currentOpcode;
   const int interruptMask = (1<<3);
   const int tapOpcode  = 0x84;
   const int tpaOpcode  = 0x85;
   const int seiOpcode  = 0x9B;
   const int cliOpcode  = 0x9A;
   const int waitOpcode = 0x8F;
   const int rtiOpcode  = 0x80;
   const int swiOpcode  = 0x83;
   const int stopOpcode = 0x8E;

   CHECK_ERROR_STATE();
#if (TARGET == MC56F80xx)
   BDMrc = DSC_TargetStepN(dnNrInstructions);
#else
   if (dnNrInstructions>1) {
      log.print("DiExecSingleStep() - Only a single step is supported!\n");
      return setErrorState(DI_ERR_PARAM, ("Only a single step is allowed"));
   }
/*
 * Cases to consider when masking interrupts during step
 *
 * +--------+-----------+---------+-----------------------------------------------------+
 * | Opcode | Initial I | Final I | Problem - action                                    |
 * +--------+-----------+---------+-----------------------------------------------------+
 * | ---    |     1     |    X    | None - no action (interrupts already masked)        |
 * +--------+-----------+---------+-----------------------------------------------------+
 * | CLI    |     0     |    ?    | It may be possible for an interrupt to occur,       |
 * | WAIT   |           |         | setting I-flag which is then incorrectly cleared.   |
 * | STOP   |           |         | (I don't think it applies to CLI but be safe.)      |
 * | SWI    |           |         | - don't 'fix' CCR                                   |
 * +--------+-----------+---------+-----------------------------------------------------+
 * | RTI    |     0     |    1    | Contrived but possible situation. I flag            |
 * |        |           |         | incorrectly cleared - don't 'fix' CCR               |
 * +--------+-----------+---------+-----------------------------------------------------+
 * | SEI    |     0     |    1    | The instruction may set I-flag which is then        |
 * | TAP    |     0     |    1    | incorrectly cleared - don't 'fix' CCR               |
 * +--------+-----------+---------+-----------------------------------------------------+
 * | TPA    |     0     |    X    | The wrong value is transferred to A - fix A         |
 * +--------+-----------+---------+-----------------------------------------------------+
 * | ---    |     0     |    0    | CCR change - clear I-flag in new CCR                |
 * +--------+-----------+---------+-----------------------------------------------------+
 */
   if (bdmOptions.maskInterrupts) {
      log.print("DiExecSingleStep() - checking if interrupt masking needed\n");
      USBDM_ReadReg(HCS08_RegCCR, &ccrValue);
      if ((ccrValue&interruptMask) != 0) {
         // Interrupts already masked - just step
         BDMrc = USBDM_TargetStep();
      }
      else {
         // Mask interrupts
         log.print("DiExecSingleStep() - masking interrupts\n");
         USBDM_WriteReg(HCS08_RegCCR, ccrValue|interruptMask);
         // Get current instruction opcode
         USBDM_ReadReg(HCS08_RegPC, &pcValue);
         USBDM_ReadMemory(1,1,pcValue,&currentOpcode);
         // Do a step
         BDMrc = USBDM_TargetStep();
         switch(currentOpcode) {
            case cliOpcode  :
            case waitOpcode :
            case seiOpcode  :
            case tapOpcode  :
            case rtiOpcode  :
            case swiOpcode  : // Not ever stepped - treated as subroutine?
            case stopOpcode :
               log.print("DiExecSingleStep() - skipping CCR restore\n");
               // Don't 'fix' CCR as updated by instruction or int ack
               break;
            case tpaOpcode :
               // Fix A & CCR  (clear I flag)
               log.print("DiExecSingleStep() - fixing A & CCR reg\n");
               USBDM_WriteReg(HCS08_RegA, ccrValue&~interruptMask);
               USBDM_WriteReg(HCS08_RegCCR, ccrValue&~interruptMask);
               break;
            default :
               // Fix CCR (clear I flag)
               // Unmask interrupts
               log.print("DiExecSingleStep() - fixing CCR reg\n");
               USBDM_ReadReg(HCS08_RegCCR, &ccrValue);
               USBDM_WriteReg(HCS08_RegCCR, ccrValue&~interruptMask);
               break;
         }
      }
   }
   else
      BDMrc = USBDM_TargetStep();
#endif
   if (BDMrc != BDM_RC_OK) {
      return setErrorState(DI_ERR_NONFATAL, BDMrc);
   }
   return setErrorState(DI_OK);
}