//! (HCS12) Reads contents of core registers
//!
//! @param  registers   pointer to structure to receive the register values
//!
//! @return 0 => Success,\n !=0 => Fail
//!
TBDML_API unsigned char _tbdml_read_regs(registers_t *registers) {
   uint8_t rc;
   unsigned long value;

   rc = USBDM_ReadReg(HCS12_RegPC, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hc12.pc  = (uint16_t)value;
   rc = USBDM_ReadReg(HCS12_RegSP, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hc12.sp  = (uint16_t)value;
   rc = USBDM_ReadReg(HCS12_RegX, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hc12.ix  = (uint16_t)value;
   rc = USBDM_ReadReg(HCS12_RegY, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hc12.iy  = (uint16_t)value;
   rc = USBDM_ReadReg(HCS12_RegD, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hc12.d   = (uint16_t)value;
   rc = USBDM_ReadDReg(0xFF06,&value);
   if (rc != BDM_RC_OK)
      return rc;
	registers->hc12.ccr = (uint8_t)value;

   return BDM_RC_OK;
}
//! (HCS08 & RS08) Reads contents of core registers
//!
//! @param  registers   pointer to structure to receive the register values
//!
//! @return 0 => Success,\n !=0 => Fail
//!
OSBDM_API unsigned char _opensourcebdm_read_regs(registers_t *registers) {
   U8 rc;
   unsigned long value;

   rc = USBDM_ReadReg(HCS08_RegPC, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hcs08.pc  = (U16)value;
   rc = USBDM_ReadReg(HCS08_RegSP, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hcs08.sp  = (U16)value;
   rc = USBDM_ReadReg(HCS08_RegHX, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hcs08.hx  = (U16)value;
   rc = USBDM_ReadReg(HCS08_RegA, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hcs08.a   = (U8)value;
   rc = USBDM_ReadReg(HCS08_RegCCR, &value);
   if (rc != BDM_RC_OK)
      return rc;
   registers->hcs08.ccr = (U8)value;

   return BDM_RC_OK;
}
//! 2.2.6.2 Read Value from Register
//!
//! @param dnRegNumber
//! @param drvValue
//!
USBDM_GDI_API
DiReturnT DiRegisterRead ( DiUInt32T         dnRegNumber,
                           pDiRegisterValueT drvValue ) {
unsigned long dataValue = 0xDEADBEEF;
USBDM_ErrorCode rc = BDM_RC_OK;

   Logging::print("DiRegisterRead(0x%X(%d))\n", dnRegNumber, dnRegNumber);

   CHECK_ERROR_STATE();

   if (dnRegNumber>=cfv234regID_FIRST_DEBUG_REG) {
      dnRegNumber -= cfv234regID_FIRST_DEBUG_REG;
      rc = USBDM_ReadDReg(dnRegNumber,&dataValue);
      Logging::print("DiRegisterRead(0x%X(%s) => 0x%08X)\n", dnRegNumber, getCFVxDebugRegName(dnRegNumber), (uint32_t)dataValue);
   }
   else if (dnRegNumber >= cfv234regID_FIRST_CONTROL_REG) {
      dnRegNumber -= cfv234regID_FIRST_CONTROL_REG;
      rc = USBDM_ReadCReg(dnRegNumber,&dataValue);
      Logging::print("DiRegisterRead(0x%X(%s) => 0x%08X)\n", dnRegNumber, getCFVxControlRegName(dnRegNumber), (uint32_t)dataValue);
   }
   else {
      switch (dnRegNumber) {
         case cfv234regID_pc :
            rc = USBDM_ReadCReg(CFVx_CRegPC,&dataValue);
            Logging::print("DiRegisterRead(0x%X(%s) => 0x%08X)\n", CFVx_CRegPC, getCFVxControlRegName(CFVx_CRegPC), (uint32_t)dataValue);
            break;
         case cfv234regID_sr :
            rc = USBDM_ReadCReg(CFVx_CRegSR,&dataValue);
            Logging::print("DiRegisterRead(0x%X(%s) => 0x%08X)\n", CFVx_CRegSR, getCFVxControlRegName(CFVx_CRegSR), (uint32_t)dataValue);
            break;
         default : // D0-7, A0-7
            if (dnRegNumber<=cfv234regID_a7) {
               rc = USBDM_ReadReg(dnRegNumber,&dataValue);
               Logging::print("DiRegisterRead(0x%X(%s) => 0x%08X)\n", dnRegNumber, getCFVxRegName(dnRegNumber), (uint32_t)dataValue);
            }
            else {
               Logging::print("DiRegisterRead(Illegal reg# = 0x%X (%d)\n", dnRegNumber, dnRegNumber);
               rc = BDM_RC_ILLEGAL_PARAMS;
            }
            break;
      }
   }
   if (rc != BDM_RC_OK) {
      Logging::print("DiRegisterRead(0x%X) => error\n", dnRegNumber);
      return setErrorState(DI_ERR_NONFATAL, rc);
   }
   *drvValue = (U32c)dataValue;
   Logging::print("0x%X(%d) => 0x%08X\n", dnRegNumber, dnRegNumber, dataValue);
   return setErrorState(DI_OK);
}
//! 2.2.6.2 Read Value from Register
//!
//! @param dnRegNumber
//! @param drvValue
//!
USBDM_GDI_DECLSPEC
DiReturnT DiRegisterRead ( DiUInt32T         dnRegNumber,
                           pDiRegisterValueT drvValue ) {
   unsigned long dataValue = 0xDEADBEEF;
   USBDM_ErrorCode rc = BDM_RC_OK;
   LOGGING;
   log.print("0x%X(%d)\n", dnRegNumber, dnRegNumber);

   CHECK_ERROR_STATE();

   if (dnRegNumber > S12Z_RegCCR) {
      return setErrorState(DI_ERR_PARAM, ("Illegal register identifier"));
   }
   rc = USBDM_ReadReg(dnRegNumber,  &dataValue);
   if (rc != BDM_RC_OK) {
      log.print("DiRegisterRead(0x%X) => error\n", dnRegNumber);
      return setErrorState(DI_ERR_NONFATAL, rc);
   }
   *drvValue = (U32c)dataValue;
   log.print("0x%lX(%ld) => 0x%08lX\n", (unsigned long)dnRegNumber, (unsigned long)dnRegNumber, (unsigned long)dataValue);
   return setErrorState(DI_OK);
}
//! 2.2.6.2 Read Value from Register
//!
//! @param dnRegNumber
//! @param drvValue
//!
USBDM_GDI_DECLSPEC
DiReturnT DiRegisterRead ( DiUInt32T         dnRegNumber,
                           pDiRegisterValueT drvValue ) {
   LOGGING;
   log.print("0x%X(%d)\n", dnRegNumber, dnRegNumber);

   unsigned long     dataValue = 0xDEADBEEF;
   USBDM_ErrorCode   rc        = BDM_RC_OK;
   log.print("0x%X(%d)\n", dnRegNumber, dnRegNumber);

   if (forceMassErase) {
      // Dummy register reads until device in unsecured
      *drvValue = (U32c)dataValue;
      return setErrorState(DI_OK);
   }
   CHECK_ERROR_STATE();

   if (dnRegNumber>cfv1regID_FIRST_DEBUG_regID_BYTE)
      switch (dnRegNumber) {
         case cfv1regID_xcsr_byte :
            rc = USBDM_ReadStatusReg(&dataValue);
            break;
         case cfv1regID_csr2_byte :
            rc = USBDM_ReadDReg(CFV1_DRegCSR2byte,&dataValue);
            break;
         case cfv1regID_csr3_byte :
            rc = USBDM_ReadDReg(CFV1_DRegCSR3byte,&dataValue);
            break;
         default                  :
            log.print("DiRegisterRead(Illegal Reg# 0x%X(%d)\n", dnRegNumber, dnRegNumber);
            rc = BDM_RC_ILLEGAL_PARAMS;
            break;
      }
   else if (dnRegNumber>cfv1regID_FIRST_DEBUG_REG)
      rc = USBDM_ReadDReg(dnRegNumber-cfv1regID_FIRST_DEBUG_REG,&dataValue);
   else if (dnRegNumber > cfv1regID_FIRST_CONTROL_REG)
      rc = USBDM_ReadCReg(dnRegNumber-cfv1regID_FIRST_CONTROL_REG,&dataValue);
   else {
      switch (dnRegNumber) {
         case cfv1regID_pc :
            rc = USBDM_ReadCReg(CFV1_CRegPC,&dataValue);
            break;
         case cfv1regID_sr :
            rc = USBDM_ReadCReg(CFV1_CRegSR,&dataValue);
            break;
         default : // D0-7, A0-7
            if (dnRegNumber>15) {
               log.print("DiRegisterRead(Illegal Reg# 0x%X(%d)\n", dnRegNumber, dnRegNumber);
               rc = BDM_RC_ILLEGAL_PARAMS;
            }
            else
               rc = USBDM_ReadReg(dnRegNumber,&dataValue);
            break;
      }
   }
   if (rc != BDM_RC_OK) {
      log.print("DiRegisterRead(0x%X) => error\n", dnRegNumber);
      return setErrorState(DI_ERR_NONFATAL, rc);
   }
   *drvValue = (U32c)dataValue;
   log.print("0x%lX(%ld) => 0x%08lX\n", (unsigned long)dnRegNumber, (unsigned long)dnRegNumber, (unsigned long)dataValue);
   return setErrorState(DI_OK);
}
USBDM_ErrorCode BdmInterface_RS08::readPC(unsigned long *regValue) {
   return USBDM_ReadReg(RS08_RegCCR_PC, regValue);
};
//!  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);
}
USBDM_ErrorCode BdmInterface_ARM::readPC(unsigned long *regValue) {
   return USBDM_ReadReg(ARM_RegPC, regValue);
}
//!  2.2.8.6 Get DI Execution/Exit Status
//!
//! @param pdesExitStatus
//!
//! @return \n
//!     DI_OK              => OK \n
//!     DI_ERR_FATAL       => Error see \ref currentErrorString
//!
USBDM_GDI_API
DiReturnT DiExecGetStatus ( pDiExitStatusT pdesExitStatus ) {
   LOGGING;
   USBDM_ErrorCode BDMrc;
   static DiExitCauseT lastStatus = DI_WAIT_USER;

//   Logging::print("DiExecGetStatus()\n");

   // Defaults
   pdesExitStatus->dscCause = DI_WAIT_UNKNOWN;
   pdesExitStatus->dwBpId   = 0x1000400; // bkpt ID?
   pdesExitStatus->szReason = (DiStringT)"unknown state";

// Removed as prevents CW retry strategy
//   CHECK_ERROR_STATE();

   if (bdmOptions.autoReconnect) {
      USBDM_ErrorCode bdmRc = targetConnect(softConnectOptions);

      if (bdmRc != BDM_RC_OK) {
         Logging::print("DiExecGetStatus()=> connect failed\n");
         return setErrorState(DI_ERR_COMMUNICATION, bdmRc);
      }
   }
   else {
      USBDM_GetBDMStatus(&USBDMStatus);
   }
//   pdesExitStatus->szReason = (DiStringT)getBDMStatusName(&USBDMStatus);

   if (USBDMStatus.reset_recent == RESET_DETECTED) {
      Logging::print("DiExecGetStatus()=>Target has been reset\n");
      mtwksDisplayLine("Target RESET detected\n");
   }
   if (bdmOptions.usePSTSignals) {
      // Check processor state using PST signals
      if (USBDMStatus.halt_state) {
         // Processor halted
         pdesExitStatus->dscCause = DI_WAIT_UNKNOWN;
         pdesExitStatus->szReason = (DiStringT)"Debug Halted";
         if (lastStatus != pdesExitStatus->dscCause) {
            Logging::print("DiExecGetStatus(PST) status change => DI_WAIT_UNKNOWN, (%s)\n",
                  pdesExitStatus->szReason);
            }
      }
      else {
         // Processor executing
         pdesExitStatus->dscCause = DI_WAIT_RUNNING;
         pdesExitStatus->szReason = (DiStringT)"Running";
         if (lastStatus != pdesExitStatus->dscCause) {
            Logging::print("DiExecGetStatus(PST) status change => DI_WAIT_RUNNING, (%s)\n",
                  pdesExitStatus->szReason);
            }
      }
   }
   else {
      // Probe D0 register - if fail assume processor running!
      // BUG - If stopped D0 can still be read so CW thinks the target is halted
      //       but is still running.
      unsigned long int dummy;
      BDMrc = USBDM_ReadReg(CFVx_RegD0, &dummy);
      if (BDMrc == BDM_RC_OK) {
         // Processor halted
         pdesExitStatus->dscCause = DI_WAIT_UNKNOWN;
         pdesExitStatus->szReason = (DiStringT)"Debug Halted";
         if (lastStatus != pdesExitStatus->dscCause) {
            Logging::print("DiExecGetStatus() status change => DI_WAIT_UNKNOWN, (%s)\n",
                  pdesExitStatus->szReason);
         }
      }
      else {
         // Processor executing
         pdesExitStatus->dscCause = DI_WAIT_RUNNING;
         pdesExitStatus->szReason = (DiStringT)"Running";
         if (lastStatus != pdesExitStatus->dscCause) {
            Logging::print("DiExecGetStatus() status change => DI_WAIT_RUNNING, (%s)\n",
                  pdesExitStatus->szReason);
         }
      }
   }
   lastStatus = pdesExitStatus->dscCause;
   return setErrorState(DI_OK);
}
//! (CFv1) Read Core registers
//!
//! @param regNo  Register #
//!
//! @return 32-bit number
//!
OSBDM_API unsigned int  _opensourcebdm_read_reg(unsigned char regNo) {
unsigned long value;

   USBDM_ReadReg(regNo, &value);
   return value;
}