/*********************************************************************
*            (c) 1995 - 2018 SEGGER Microcontroller GmbH             *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

File    : CY8C6xxA_CM0p_tm.JLinkScript
Purpose : J-Link script file for Cypress PSoC6A-2M/512K devices (CY8C6xxA and CY8C6xx5)
Literature:
  [1] J-Link User Guide
  [2] PSoC\xae 6 MCU Programming Specifications (Document Number: 002-15554 http://www.cypress.com/file/385671/download)

Additional information:
  For more information about public functions that can be implemented in order to customize J-Link actions, please refer to [1]
*/

/*********************************************************************
*       Constants (similar to defines) 
*********************************************************************/

/* --- Flags --- */
__constant U8 _DO_ACQUIRE_TEST_MODE         = 1; // Perform or skip Test Mode acquisition sequence
__constant U8 _DO_ACQUIRE_ALTERNATE         = 1; // Perform or skip Alternate acquisition sequence

/* --- Misc. --- */
__constant int _STATUS_OK                   = 0;  // Function return status: O.K.
__constant int _STATUS_ERR                  = -1; // Function return status: Error
__constant U32 _TIMEOUT_HANDSHAKE           = 3000;
__constant U32 _TIMEOUT_HALT_CPU            = 300;
__constant U32 _TIMEOUT_SLEEP_LISTEN_WINDOW = 200;
__constant U32 _TEST_MODE_SWD_SPEED         = 4000;

/* PSoC\xae 6 MCU definitions */
__constant U32 _AP_SYS                      = 0; // AP[0]  SYS-AP (used for chip acquisition sequence)
__constant U32 _AP_CM0                      = 1; // AP[1]  CM0-AP (used for J-Link communication with Cortex-M0 core)
__constant U32 _AP_CM4                      = 2; // AP[2]  CM4-AP (used for J-Link communication with Cortex-M4 core)
__constant U32 _AP_MYCORE                   = 1; // AP[1]  CM0+ Core is used as the default for this script
__constant U32 _DP_IDCODE_MSK               = 0xFFF00FFF; // AP[2]  CM4-AP (used for J-Link communication with Cortex-M4 core)
__constant U32 _DP_IDCODE_VAL               = 0x6BA00477; // AP[2]  0x6BA02477 for SWD or 0x6BA00477 for JTAG
__constant U32 _CPUSS_CM0_VTBASE_ADDR       = 0x40201120; // Vector table base address for CM0+ core (CPUSS_CM0_VECTOR_TABLE_BASE reg.)
__constant U32 _CPUSS_CMX_VTBASE_ERR_MSK    = 0xFFFF0000; // Set by boot code if flash is empty or secure application
__constant U32 _SRSS_TST_MODE_ADDR          = 0x40260100; // SRSS_TST_MODE: Test Mode Control Register
__constant U32 _SRSS_TST_MODE_TEST_MODE     = (1 << 31);  // SRSS_TST_MODE.TEST_MODE (bit[31], 0x80000000): 1 - Indicates the chip is in test mode. 0 - Normal operation mode
__constant U32 _MEM_BASE_ROM                = 0x00000000; // Base address of System ROM
__constant U32 _MEM_SIZE_ROM                = 0x00020000; // Size of System ROM
__constant U32 _MEM_BASE_SFLASH             = 0x16000000; // Base address of supervisory flash
__constant U32 _MEM_SIZE_SFLASH             = 0x00008000; // Size of supervisory flash
__constant U32 _SRAM_ERROR_ADDR             = 0x080002FC; // Address in SRAM for error code
__constant U32 _SRAM_LOOP_ADDR              = 0x08000300; // Address in SRAM for infinite loop
__constant U32 _SRAM_TOP_ADDR               = 0x0800FFF0; // Top of SRAM address for SP set by acquisition sequence. Use minimum SRAM size devices (65 KB)

/* --- AP/DP registers --- */
__constant U32 _ACC_DP                      = 0; // APnDP for DP access
__constant U32 _ACC_AP                      = 1; // APnDP for AP access
__constant U32 _AP_ABORT_ORUNERRCLR         = (1 << 4);   // AP->ABORT.ORUNERRCLR (bit[4], 0x00000010): Clears CTRL/STAT.STICKYORUN
__constant U32 _AP_ABORT_WDERRCLR           = (1 << 3);   // AP->ABORT.WDERRCLR   (bit[3], 0x00000008): Clears CTRL/STAT.WDATAERR
__constant U32 _AP_ABORT_STKERRCLR          = (1 << 2);   // AP->ABORT.STKERRCLR  (bit[2], 0x00000004): Clears CTRL/STAT.STICKYERR
__constant U32 _AP_ABORT_STKCMPCLR          = (1 << 1);   // AP->ABORT.STKCMPCLR  (bit[1], 0x00000002): Clears CTRL/STAT.STICKYERR
                                                          //                      (     |= 0x0000001E)
__constant U32 _AP_SELECT_APSEL_RSH         = 24;         // AP->SELECT.APSEL (bits[31:24], 0xFF000000): Selects an AP
__constant U32 _DP_CTRL_STAT_CSYSPWRUPREQ   = (1 << 30);  // DP->CTRL/STAT.CSYSPWRUPREQ (bit[30], 0x40000000): System powerup request
__constant U32 _DP_CTRL_STAT_CDBGPRWUPREQ   = (1 << 28);  // DP->CTRL/STAT.CDBGPRWUPREQ (bit[28], 0x10000000): Debug powerup request
__constant U32 _DP_CTRL_STAT_CDBGRSTREQ     = (1 << 26);  // DP->CTRL/STAT.CDBGRSTREQ   (bit[26], 0x04000000): Debug reset request
__constant U32 _DP_CTRL_STAT_STICKYERR      = (1 << 5);   // DP->CTRL/STAT.STICKYERR    ( bit[5], 0x00000020): Error in AP transaction
__constant U32 _DP_CTRL_STAT_STICKYCMP      = (1 << 4);   // DP->CTRL/STAT.STICKYCMP    ( bit[4], 0x00000010): Match on a pushed operations
__constant U32 _DP_CTRL_STAT_STICKYORUN     = (1 << 1);   // DP->CTRL/STAT.STICKYORUN   ( bit[1], 0x00000002): Overrun detection
                                                          //                                   |= 0x50000032
__constant U32 _DP_CSW_PROT_VAL             = (0x23 << 24); // DP->CSW.Prot (bits[30:24], 0x23000000): Bus access protection control
                                                            // Set to 0x23, otherwise no access to CPU registers via M4 AP
__constant U32 _DP_CSW_SIZE_WORD            = (2 << 0);     // DP->CSW.Size (  bits[2:0], 0x00000002): Size of access <- Word (32-bits)
                                                            //                         |= 0x23000002
/* --- ARMv6-M & ARMv7-M --- */
__constant U32 _LOOP_CODE                   = 0xE7FEE7FE; // Endless loop
__constant U32 _BP_CTRL_ADDR                = 0xE0002000; // BP_CTRL: Breakpoint Control register in ARMv6-M. In ARMv7-M, it is FP_CTRL: FlashPatch Control Register.
__constant U32 _BP_CTRL_KEY                 = (1 << 1);   // BP_CTRL.KEY    (bit[1], 0x00000002): Enables write to the register
__constant U32 _BP_CTRL_ENABLE              = (1 << 0);   // BP_CTRL.ENABLE (bit[0], 0x00000001): Enables the BPU
__constant U32 _BP_COMP0_ADDR               = 0xE0002008; // BP_COMP0: Breakpoint Comparator registers
__constant U32 _BP_COMP_BPMATCH             = (3 << 30);  // BP_COMP.BP_MATCH (bits[31:30], 0xC0000000): Defines the behavior when the COMP address is matched
__constant U32 _BP_COMP_COMP_MSK            = 0x1FFFFFFC; // BP_COMP.COMP     ( bits[28:2], 0x07FFFFFF): Stores bits [28:2] of the comparison address
__constant U32 _BP_COMP_ENABLE              = (1 << 0);   // BP_COMP.ENABLE   (     bit[0], 0x00000001): Enables the comparator
__constant U32 _AIRCR_ADDR                  = 0xE000ED0C;     // AIRCR: Application Interrupt and Reset Control Register
__constant U32 _AIRCR_VECTKEY_VAL           = (0x05FA << 16); // AIRCR.VECTKEY       (bits[31:16], 0x05FA0000): Vector Key. The value 0x05FA must be written to this register
__constant U32 _AIRCR_SYSRESETREQ           = (1 << 2);       // AIRCR.SYSRESETREQ   (     bit[2], 0x00000004): System Reset Request
__constant U32 _DHCSR_ADDR                  = 0xE000EDF0;     // DHCSR: Debug Halting Control and Status Register
__constant U32 _DHCSR_DBGKEY_VAL            = (0xA05F << 16); // DHCSR.DBGKEY    (bits[31:16], 0xA05F0000): Must write 0xA05F to DBGKEY to enable write accesses to bits[15:0]
__constant U32 _DHCSR_S_SLEEP               = (1 << 18);      // DHCSR.S_SLEEP   (    bit[18], 0x00040000): Indicates whether the processor is sleeping
__constant U32 _DHCSR_S_HALT                = (1 << 17);      // DHCSR.S_HALT    (    bit[17], 0x00020000): Indicates whether the processor is in Debug state
__constant U32 _DHCSR_C_HALT                = (1 << 1);       // DHCSR.C_HALT    (     bit[1], 0x00000002): Processor halt bit
__constant U32 _DHCSR_C_DEBUGEN             = (1 << 0);       // DHCSR.C_DEBUGEN (     bit[0], 0x00000001): Halting debug enable bit
                                                              //                 (DBGKEY|C_HALT|C_DEBUGEN = 0xA05F0003)
__constant U32 _DCRSR_ADDR                  = 0xE000EDF4; // DCRSR: Debug Core Register Selector Register
__constant U32 _DCRSR_REGWnR                = (1 << 16);  // DCRSR.REGWnR (  bit[16], 0x00010000): Specifies the access type for the transfer ('0' - Read, '1' - Write)
__constant U32 _DCRSR_REGSEL_MSK            = 0x0000007F; // DCRSR.REGSEL (bits[6:0], 0x0000007F): Specifies the ARM core register, special-purpose register, or Floating-point extension register
__constant U32 _xPSR_T                      = (1 << 24);  // xPSR.T (bit[24], 0x01000000): Thumb bit
__constant U32 _REGSEL_xPSR                 = 0x10;       // xPSR
__constant U32 _REGSEL_MSP                  = 0x11;       // Main stack pointer, MSP
__constant U32 _REGSEL_PC                   = 0x0F;       // PC / DebugReturnAddress
__constant U32 _DCRDR_ADDR                  = 0xE000EDF8; // DCRDR: Debug Core Register Data Register
__constant U32 _DEMCR_ADDR                  = 0xE000EDFC; // DEMCR: Debug Exception and Monitor Control Register
__constant U32 _DEMCR_TRCENA                = (1 << 24);  // DEMCR.TRCENA (bit[24], 0x01000000): Global enable for all DWT and ITM features


/*********************************************************************
*       Static data
*********************************************************************/

// Standard ARM command to switch SWJ-DP from JTAG to SWD operations:
const U8 _aData_JTAGtoSWD[] = {
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,      // Send at least 50 SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that the current interface is in its reset state.
                                                 // The JTAG interface detects only the 16-bit JTAG-to-SWD sequence starting from the test-logic-reset state.
  0x9E, 0xE7,                                    // Send the 16-bit JTAG-to-SWD select sequence on SWDIOTMS: 0b0111 1001 1110 0111, most significant bit (MSb) first.
                                                 // This can be represented as 0x79E7, transmitted MSB first or 0xE79E, transmitted least significant bit (LSb) first.
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,      // Send at least 50 SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that if SWJ-DP was already in SWD operation
                                                 // before sending the select sequence, the SWD interface enters line reset state.
  0x00, 0x00                                     // Make sure SWD is ready for a start bit (min. 2 clocks with SWDIO == LOW)
};

// Standard ARM command to switch SWJ-DP from SWD to JTAG operations
const U8 _aData_SWDtoJTAG[] = {
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,      // Send at least 50 SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that the current interface is in its reset state.
                                                 // The SWD interface detects the 16-bit SWD-to-JTAG sequence only when it is in reset state.
  0x3C, 0xE7,                                    // Send the 16-bit SWD-to-JTAG select sequence on SWDIOTMS: 0b0011 1100 1110 0111, MSb first.
                                                 // This can be represented as 0x3CE7, transmitted MSb first or 0xE73C, transmitted LSb first.
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,      // Send at least five SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that if SWJ-DP was already in JTAG
                                                 // operation before sending the select sequence, the JTAG TAP enters the test-logic-reset state.
  0x00, 0x00                                     // Make sure SWD is ready for a start bit (min. 2 clocks with SWDIO == LOW)
};

// Direction buffer
const U8 _aDir_SWJDPSwitch[] = {
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF
};

// Buffer for receiving data from target. Needs to be big enough to hold data for above sequences
U8 _aDataOut[18];

/*********************************************************************
*       Local functions
*********************************************************************/

/*********************************************************************
*  Checks function result
*
*  Return value
*    true   O.K.
*    false  Error
*/
int _CheckStatus(int status) {
  if (status >= _STATUS_OK) {
    return _STATUS_OK;
  } else {
    // Push error code to SWD that is it easier to debug the issues
    JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACC_AP, _SRAM_ERROR_ADDR);
    JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACC_AP, 0xDEADBEEF);   	  
    return _STATUS_ERR;
  }
}

/*********************************************************************
*  Writes U32 value to provided memory address.
*  Used instead of JLINK_MEM_ReadU32 to validate transaction status
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*/
int _ReadMem(U32 address, U32* value) { 
  int status;
  
  status = JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACC_AP, address); // AP.TAR <- address
  if (_CheckStatus(status) == _STATUS_OK) {
    status = JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACC_AP, value);  // AP.DRW -> value
  }
  
  return status; 
}

/*********************************************************************
*  Writes U32 value to provided memory address.
*  Used instead of JLINK_MEM_WriteU32 to validate transaction status
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*/
int _WriteMem(U32 address, U32 value) { 
  int status;
  
  status = JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACC_AP, address); // AP.TAR <- address
  if (_CheckStatus(status) == _STATUS_OK) {
    status = JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACC_AP, value); // AP.DRW <- value
  }
  
  return status; 
}

/*********************************************************************
*  Polls for the expected bit-field value in given register
*
*  Return value
*    >= 0  O.K.
*    <  0  Error/Timeout
*/
int _PollMem(U32 regAddr, U32 fieldMsk, U32 rsh, U32 expectedValue, U32 timeout, U32 sleepBetweenPolling) {
  int status;  
  int t;
  int tDelta;
  U32 v;
  tDelta = -1;
  
  status = JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACC_AP, regAddr); // AP.ADDR <- regAddr
  if (_CheckStatus(status) == _STATUS_OK) {
    status = _STATUS_ERR;
    t = JLINK_GetTime();
    do {
      // Sleep some time between polling: let CPU do its job and avoid too much garbage on SWD
      if ((sleepBetweenPolling > 0) && (tDelta >= 0 /* not first iteration*/)) {
        JLINK_SYS_Sleep(sleepBetweenPolling);
      }
      v = 0;
      status = JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACC_AP, &v);
      if (_CheckStatus(status) != _STATUS_OK) {
      break;
      }
      if (((v & fieldMsk) >> rsh) == expectedValue) {
        status = _STATUS_OK;
        break;
      }	  
      tDelta = JLINK_GetTime() - t;
    } while (tDelta < timeout);
  }
  
  return _CheckStatus(status); 
}

/*********************************************************************
*  Reads ARM core register, special-purpose register, or Floating-point extension register
*  CPU must be halted for this operation
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*/
int _ReadCoreReg(U32 regsel, U32* value) { 
  int status;

  status = _WriteMem(_DCRSR_ADDR, (regsel & _DCRSR_REGSEL_MSK)); // DCRSR (0xE000EDF4) <- REGWnR == read) | REGSEL
  if (_CheckStatus(status) == _STATUS_OK) {
    status = _ReadMem(_DCRDR_ADDR, value);                       // DCRDR (0xE000EDF8) -> value
  }
 
  return status; 
}

/*********************************************************************
*  Writes ARM core register, special-purpose register, or Floating-point extension register
*  CPU must be halted for this operation
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*/
int _WriteCoreReg(U32 regsel, U32 value) { 
  int status;

  status = _WriteMem(_DCRDR_ADDR, value); // DCRDR (0xE000EDF8) <- value
  if (_CheckStatus(status) == _STATUS_OK) {
    status = _WriteMem(_DCRSR_ADDR, (_DCRSR_REGWnR | (regsel & _DCRSR_REGSEL_MSK))); // DCRSR (0xE000EDF4) <- (REGWnR == write) | REGSEL	  
  }
   
  return status; 
}

/*********************************************************************
*  Handshake: wait for debug interface becomes enabled after device reset (tboot).
*  In worst case, when the boot code performs application HASH verification,
*  tboot is around 600ms and depends on CPU clock used by boot code.
*  For PowerCycle, timeout depends on the design schematic and must be longer.
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*
*  Notes
*    (1) Must not use any high-level functions as it is also called from InitTarget() and uses non-standard APs etc.
*/
int _Handshake(void) {
  U32 v;
  int t;
  int tDelta;
  int status;

  status = _STATUS_ERR;
  t = JLINK_GetTime();
  do {
    if (JLINK_ActiveTIF == JLINK_TIF_JTAG) {
      JLINK_SWD_ReadWriteBits(&_aData_SWDtoJTAG[0], &_aDir_SWJDPSwitch[0], &_aDataOut[0], 18 * 8);
    } else { // JLINK_ActiveTIF == JLINK_TIF_SWD
      JLINK_SWD_ReadWriteBits(&_aData_JTAGtoSWD[0], &_aDir_SWJDPSwitch[0], &_aDataOut[0], 18 * 8);
    }  
    v = 0;
    JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_DP_REG_IDCODE, _ACC_DP, &v);
    if ((v & _DP_IDCODE_MSK) == _DP_IDCODE_VAL) { // DAP is responsive if we can read IDCODE (0x6BA02477 for SWD or 0x6BA00477 for JTAG)
      status = _STATUS_OK;
      break;
    }
    tDelta = JLINK_GetTime() - t;
  } while (tDelta < _TIMEOUT_HANDSHAKE); // Timeout reached?
  
  return status;
}

/*********************************************************************
*  Clears any sticky errors which could be left from previous sessions.
*  Otherwise only power-down-up cycle helps to restore DAP.
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*
*  Notes
*    (1) Must not use any high-level functions as it is also called from InitTarget() and uses non-standard APs etc.
*/
int _ClearStickyErrors() {
  int status;
  U32 abort_reg;
  U32 abort_val;

  if (JLINK_ActiveTIF == JLINK_TIF_JTAG) {	  
    // Power up DAP and clear sticky errors using DP.CTRL/STAT: [30]:CSYSPWRUPREQ, [28]:CDBGPWRUPREQ, [5]:STICKYERR, [4]:STICKYCMP, [1]:STICKYORUN
    // Note: for JTAG, sticky error bits are read-write enabled and writing '1' to these bits clears associated sticky errors.
    // For SWD, these bits are read-only and to clean the sticky errors, you should write to appropriate bits of DP.ABORT register
    abort_reg = JLINK_CORESIGHT_DP_REG_CTRL_STAT;
    abort_val = _DP_CTRL_STAT_CSYSPWRUPREQ | _DP_CTRL_STAT_CDBGPRWUPREQ | _DP_CTRL_STAT_STICKYERR | _DP_CTRL_STAT_STICKYCMP | _DP_CTRL_STAT_STICKYORUN; // 0x50000032	
  } else { // JLINK_ActiveTIF == JLINK_TIF_SWD
    abort_reg = JLINK_CORESIGHT_DP_REG_ABORT;
    abort_val = _AP_ABORT_ORUNERRCLR | _AP_ABORT_WDERRCLR | _AP_ABORT_STKERRCLR | _AP_ABORT_STKCMPCLR; // 0x0000001E
  }

  status = JLINK_CORESIGHT_WriteDAP(abort_reg, _ACC_DP, abort_val);
  
  return status;
}

/*********************************************************************
*  Initialize the Debug Port for programing operations.
*  Accepts Access Port number as input: 0 - System AP; 1 - CM0+ AP; 2 - CM4 AP.
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*
*  Notes
*    (1) Must not use any high-level functions as it is also called from InitTarget() and uses non-standard APs etc.
*/
int _InitDAP(U8 apNum, U8 doPowerUp) {
  int status;

  status = _ClearStickyErrors();
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }

  if (doPowerUp != 0) {
    // Power up DAP using DP.CTRL/STAT: [30]:CSYSPWRUPREQ, [28]:CDBGPWRUPREQ
    status = JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_DP_REG_CTRL_STAT, _ACC_DP, _DP_CTRL_STAT_CSYSPWRUPREQ | _DP_CTRL_STAT_CDBGPRWUPREQ); // 0x50000000	  
    if (_CheckStatus(status) != _STATUS_OK) {
      return status;
    }
  }
  
  // Select desired Access Port and set bank 0 in APACC space
  status = JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_DP_REG_SELECT, _ACC_DP, (apNum << _AP_SELECT_APSEL_RSH) ); // DP->SELECT.APSEL <- apNum
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }

  // Set CSW (DbgSwEnable=0, Prot=0x23, SPIDEN=0, Mode=0x0, TrInProg=0, DeviceEn=0, AddrInc=Auto-increment off, Size=Word (32 bits))
  // Note: Set Prot bits in DAP CSW register, because of no access to CPU registers via M4 AP without these bits
  status = JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_CTRL, _ACC_AP, _DP_CSW_PROT_VAL | _DP_CSW_SIZE_WORD); // 0x23000002
  
  return _CheckStatus(status);
}

/*********************************************************************
*  Performs hardware reset by toggling XRES pin
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*
*  Notes
*    (1) Must not use any high-level functions as it is also called from InitTarget() and uses non-standard APs etc.
*/
int _HardReset(void) {
  JLINK_JTAG_ResetPin = 0;  // nRESET == LOW
  JLINK_SYS_Sleep(50);      // Make sure that device recognizes the reset
  JLINK_JTAG_ResetPin = 1;  // nRESET == HIGH
  return _STATUS_OK;
}

/*********************************************************************
*  Performs software reset using SYSRESETREQ bit in the AIRCR (Application Interrupt and Reset Control Register)
*  DAP communication must be established before this method call (e.g. use _Handshake + _InitDAP function)
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*/
int _SoftReset() {
  int status;
  
  status = JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACC_AP, _AIRCR_ADDR); // AP.TAR <- @AIRCR (0xE000ED0C)
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  // Note: do not check OK/WAIT/FAULT ACKs for the data write phase since the target immediately reboots
  JLINK_CORESIGHT_WriteDP(JLINK_CORESIGHT_AP_REG_DATA, (_AIRCR_VECTKEY_VAL | _AIRCR_SYSRESETREQ) ); // AP.DRW <- 0x05FA0004
  
  return _CheckStatus(status);
}

/*********************************************************************
*  Performs either of:
*    a. Hardware reset (XRES)
*    b. Software reset (AIRCR.SYSRESETREQ)
*    c. Software reset (DP->CTRL/STAT.CDBGRSTREQ)
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*/
int _PSoC6_Reset(U8 doXRES) {
  int status;
  
  if (doXRES != 0) {
    status = _HardReset();
  } else {
    // Handshake: wait for debug interface becomes enabled after device reset
    status = _Handshake();
    if (_CheckStatus(status) == _STATUS_OK) {
      // Initialize the Debug Port and select CM0+ Access Port (AP[1])
      status = _InitDAP(_AP_MYCORE, 1 /* "1" - do power up request */);
      if (_CheckStatus(status) == _STATUS_OK) {
       status = _SoftReset(); // AIRCR.SYSRESETREQ
      }

      // In worst case, if standard software reset via SYSRESETREQ failed, it may mean that the firmware did
      // very bad things disabling the debug pins or AHB_AP access (anything behind the DAP).
      // However, if we still can access DAP registers, the last thing we could try is to reset the target
      // via DP->CTRL/STAT.CDBGRSTREQ. In MXS40, setting the CDBGRSTREQ bit will result in a System wide Debug
      // DeepSleep reset, what resets both (CM0+ and CM4) cores.
      // Note that CDBGRSTREQ will reset the target only at first attempt after the hardware reset (XRES or Power Cycle).
      // You need to do the additional hardware reset manually before the acquisition sequence execution if the target
      // stucked in 'bad' state and you already used the CDBGRSTREQ bit since the previous hardware reset.
      // If such case happens and we managed to reset the target using CDBGRSTREQ,
      // the next thing would be to halt the CPU as quickly as possible to prevent firmware to do the bad things again.
      if (_CheckStatus(status) != _STATUS_OK) {
        status = _Handshake();
        if (_CheckStatus(status) == _STATUS_OK) {
          JLINK_CORESIGHT_WriteDP(JLINK_CORESIGHT_DP_REG_CTRL_STAT, _DP_CTRL_STAT_CSYSPWRUPREQ | _DP_CTRL_STAT_CDBGPRWUPREQ | _DP_CTRL_STAT_CDBGRSTREQ); // 0x54000000
        }
      }

    }
  }
  
  return _CheckStatus(status);
}

/*********************************************************************
*  Enables debug and halts or resumes the CPU using the DHCSR register
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*/
int _HaltResumeCPU(U8 haltNresume) {
  int status;
  U32 v;
  int t;
  int tDelta;
  U32 dhcsrVal;
  U32 shaltExpectedVal;
  
  if (haltNresume == 0) { // Resume	
    dhcsrVal = _DHCSR_DBGKEY_VAL | _DHCSR_C_DEBUGEN; // 0xA05F0001
    shaltExpectedVal = 0;
  } else { // Halt
    dhcsrVal = _DHCSR_DBGKEY_VAL | _DHCSR_C_HALT | _DHCSR_C_DEBUGEN; // 0xA05F0003
    shaltExpectedVal = _DHCSR_S_HALT;
  }

  // Enable debug, and halt the CPU using the DHCSR register
  status = _WriteMem(_DHCSR_ADDR, dhcsrVal); // _DHCSR_ADDR (0xE000EDF0) <- dhcsrVal

  if (_CheckStatus(status) == _STATUS_OK) {
    // Poll for S_HALT bit [17] in DHCSR register (@0xE000EDF0)
    status = _PollMem(_DHCSR_ADDR, _DHCSR_S_HALT, 0, shaltExpectedVal, _TIMEOUT_HALT_CPU, 0);
  }
  
  return _CheckStatus(status);
}

/*********************************************************************
*  Gets Reset Address and Initial SP values from application Vector Table
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*/
int _PSoC6_GetVectorTableData(U32* resetAddress, U32* sp) {
  int status;
  U32 v;
  U32 vtBase;

  *resetAddress = 0;
  *sp = 0;
  
  // Check CPUSS_CM0_VECTOR_TABLE_BASE. Zero or error code there means that the Flash is empty or TOC is corrupted.
  // In this case boot code jumps to infinite loop in ROM or executes 'dummy' application.
  // This case is sufficient condition for programming, but has no sense for debugging.
  // Otherwise, application exist, so need to set correct PC/SP for debugging
  
  status = _ReadMem(_CPUSS_CM0_VTBASE_ADDR, &vtBase);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  vtBase &= _CPUSS_CMX_VTBASE_ERR_MSK;
  
  if ((vtBase != 0) && (vtBase != _CPUSS_CMX_VTBASE_ERR_MSK)) {

    // Get Initial SP value from Vector Table
    status = _ReadMem(vtBase, &v);
    if (_CheckStatus(status) != _STATUS_OK) {
      return status;
    }
    *sp = v;
  
    // Get Reset Address from Vector Table
    status = _ReadMem(vtBase + 4, &v);
    if (_CheckStatus(status) != _STATUS_OK) {
      return status;
    }
    *resetAddress = v;
  }

  return _CheckStatus(status);
}

/*********************************************************************
*    Sets PC and SP getting the values from Vector Table
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*/
int _PSoC6_SetPCandSPFromVectorTable(void) {
  int status;
  U32 v;
  U32 pc;
  U32 sp;

  // Get PC and SP for the application in flash
  status = _PSoC6_GetVectorTableData(&pc, &sp);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
 
  if ((pc > 0) && (sp > 0)) {
  
    // Set PC
    status = _WriteCoreReg(_REGSEL_PC, pc);
    if (_CheckStatus(status) != _STATUS_OK) {
      return status;
    }
    
    // Set MSP
    status = _WriteCoreReg(_REGSEL_MSP, sp);
    if (_CheckStatus(status) != _STATUS_OK) {
      return status;
    }
    
    //Read xPSR register, set the thumb bit, and restore modified value to xPSR register
    status = _ReadCoreReg(_REGSEL_xPSR, &v);
    if (_CheckStatus(status) != _STATUS_OK) {
      return status;
    }
    status = _WriteCoreReg(_REGSEL_xPSR, (v | _xPSR_T) );
  }

  return _CheckStatus(status);
}

/*********************************************************************
*  Performs PSoC 6 chip acquisition in test mode:
*    1. Do hardware (XRES) or one of the software (AIRCR.SYSRESETREQ or DP->CTRL/STAT.CDBGRSTREQ) reset
*    2. Handshake + Init DAP
*    3. Set TEST_MODE bit in TST_MODE SRSS register
*    4. Check CPU is sleeping (executes WFI)
*    5. Check PC is in ROM or in SFLASH (CPU must be halted to read PC)
*   
*  Refer PSoC 6 MCU Programming Specifications: 002-15554 http://www.cypress.com/file/385671/download
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*
*  Notes
*    (1) Must not use any high-level functions as it is also called from InitTarget() and uses non-standard APs etc.
*/
int _PSoC6_AcquireTestMode(U8 doXRES) {
  int status;
  U32 v;
  U32 OrgTIFSpeed;

  // Make sure that J-Link is using a high target interface speed, so we can meet the timing requirements as per programming specifications
  // Might be necessary for some IDEs that select a very slow interface speed by default and do not allow to change this
  OrgTIFSpeed = JLINK_JTAG_Speed;
  JLINK_JTAG_Speed = _TEST_MODE_SWD_SPEED;
  
  // Preconfigure some CoreSight settings as time is not critical at this point
  // E.g. by default, when executing DAP API calls from within the firmware, J-Link will do a retry of the DAP transfer for some interfaces, if we got an invalid response from the DAP.
  // As this costs valuable time here, we temporarily disable this behavior and restore it at the end of the call.
  // Additionally, suppress output of the JTAG/SWD switching sequence init at the end of the CORESIGHT_Configure() call, as we do not need it and it only costs time
  JLINK_CORESIGHT_Configure("RetryOnInvalDAPResp=0;PerformTIFInit=0");

  // - 1 ----------------------------------------------------------------------
  // Do hardware (XRES) of software (AIRCR.SYSRESETREQ or DP->CTRL/STAT.CDBGRSTREQ) pre-reset
  // It is critical for Test Mode acquisition, so stop and in case of failure
  status = _PSoC6_Reset(doXRES);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  
  // - 2 ----------------------------------------------------------------------
  // Handshake: wait for debug interface becomes enabled after device reset
  status = _Handshake();
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  // Initialize the Debug Port and select CM0-AP (AP[1])
  status = _InitDAP(_AP_CM0, 1 /* "1" - do power up request */);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  
  // - 3 ----------------------------------------------------------------------
  // Enter CPU into Test Mode, so it does not start the user application
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACC_AP, _SRSS_TST_MODE_ADDR); // Set TEST_MODE bit in TST_MODE SRSS register
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACC_AP, _SRSS_TST_MODE_TEST_MODE);   
  // Read RDBUFF to make sure that the last AP write actually happens as SW-DP may buffer/delay it until next DAP access
  JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_DP_REG_RDBUF, _ACC_DP, &v);

  // The steps above are time critical and must be executed without delays immediately after reset.
  // No hurry for further steps - target already acquired in Test Mode

  // Restore CORESIGHT settings (See beginning of this function call for more info) and restore original TIF speed
  JLINK_CORESIGHT_Configure("RetryOnInvalDAPResp=1;PerformTIFInit=0");
  JLINK_JTAG_Speed = OrgTIFSpeed;
  
  // - 4 ----------------------------------------------------------------------
  // Wait for the boot code to finish with Listen window and jump to WFI instruction
  // Polls for S_SLEEP bit [18] in DHCSR register (@0xE000EDF0) what will indicate that the Listen window ended and CPU executes WFI instruction
  status = _PollMem(_DHCSR_ADDR, _DHCSR_S_SLEEP, 0, _DHCSR_S_SLEEP, _TIMEOUT_SLEEP_LISTEN_WINDOW, 1);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }

  // - 5 ----------------------------------------------------------------------
  // However, the WFI instruction may be executed by user application as well,
  // so additional verification is to check PC is in ROM or in SFLASH.  
  // CPU must be halted to read the PC
  status = _HaltResumeCPU(1 /* "1" - halt */);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  // Read PC and check it points to address in ROM or in SFLASH
  _ReadCoreReg(_REGSEL_PC, &v);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  if (((v >= _MEM_BASE_ROM) && (v < (_MEM_BASE_ROM + _MEM_SIZE_ROM))) || ((v >= _MEM_BASE_SFLASH) && (v < (_MEM_BASE_SFLASH + _MEM_SIZE_SFLASH)))) {
    status = _STATUS_OK;
  } else {
    status = _STATUS_ERR;
  }
  
  // If S_SLEEP is set and PC points to the address in SROM or in SFLASH, it means either of:
  //   a. Test Mode acquisition succeeded and we fit timings
  //   b. flash is empty or TOC2 is corrupted, so the boot code jumped to WFI or dummy application in ROM/SFLASH
  // Either of this case is sufficient for programming
  
  // Clear TEST_MODE bit in TST_MODE SRSS register
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACC_AP, _SRSS_TST_MODE_ADDR);
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACC_AP, 0);   

  return _CheckStatus(status);
}

/*********************************************************************
*  Performs PSoC 6 chip acquisition using alternate sequence:
*    1. Do hardware (XRES) or one of the software (AIRCR.SYSRESETREQ or DP->CTRL/STAT.CDBGRSTREQ) reset
*    2. Handshake + Init DAP
*    3. Halt CPU, enable debug
*    4. Get Reset Address and Initial SP value from the vector table
*    5. Enable Breakpoint unit and set the breakpoint at Reset Address
*    6. Issue software reset using the SYSRESETREQ bit in AIRCR register
*    7. Handshake + Init DAP
*    8. Verify CPU is halted at breakpoint being set at Reset Address
*    9. Load infinite loop into SRAM and set PC to this address
*   10. Load SP with top of SRAM address, set thumb bit in xPSR
*   11. Disable breakpoint unit and resume the CPU
*   
*  Refer PSoC 6 MCU Programming Specifications: 002-15554 http://www.cypress.com/file/385671/download
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*
*  Notes
*    (1) Must not use any high-level functions as it is also called from InitTarget() and uses non-standard APs etc.
*/
int _PSoC6_AcquireAlternate(U8 doXRES) {
  int status;
  U32 v;
  U32 resetAddress;
  U32 sp;
 
  // - 1 ----------------------------------------------------------------------
  // Do hardware (XRES) of software (AIRCR.SYSRESETREQ or DP->CTRL/STAT.CDBGRSTREQ) pre-reset.
  // It is good to do even for the alternate method
  status = _PSoC6_Reset(doXRES);
  if (_CheckStatus(status) != _STATUS_OK) {
	// Stop and return failure status if initial reset failed because it is critical for Test Mode acquisition
    return status;
  }

  // - 2 ----------------------------------------------------------------------
  // Handshake: wait for debug interface becomes enabled after device reset
  status = _Handshake();
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  // Initialize the Debug Port and select CM0+ Access Port (AP[1])
  status = _InitDAP(_AP_MYCORE, 1 /* "1" - do power up request */);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  
  // - 3 ----------------------------------------------------------------------
  // Enable debug and halt CPU as quickly as possible right after Reset+Handshake+InitDAP
  // It is not absolutely mandatory to do this quickly, but there is a good chance to stop in Listen window or at least prevent user application from doing too much "bad" stuff
  status = _HaltResumeCPU(1 /* "1" - halt */);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  
  // - 4 ----------------------------------------------------------------------
  // Get Reset Address and Initial SP values for the current application from the vector table
  status = _PSoC6_GetVectorTableData(&resetAddress, &sp);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  // Zero or error code means that the Flash is empty or TOC2 is corrupted
  // In this case boot code jumps to infinite loop in ROM or executes 'dummy' application, what is sufficient condition for programming.
  // Otherwise, user application exists, so need to do clean-up.
  if ((resetAddress == 0) || sp == 0) {
	  // Note that CPU is halted at this point and resume is required for system calls used during programming
	  return _STATUS_OK;
  }
   
  // - 5 ----------------------------------------------------------------------
  // Enable Breakpoint unit
  status = _WriteMem(_BP_CTRL_ADDR, _BP_CTRL_KEY | _BP_CTRL_ENABLE); // BP_CTRL (0xE0002000) <- 0x00000003
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  // Map the address bits to the breakpoint compare register bit-map, set the ENABLE and BPMATCH bits
  v = (resetAddress & _BP_COMP_COMP_MSK) | _BP_COMP_BPMATCH | _BP_COMP_ENABLE; //(resetAddress & 0x1FFFFFFC) | 0xC0000001
  // Update the breakpoint compare register
  status = _WriteMem(_BP_COMP0_ADDR, v);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  
  // - 6 ----------------------------------------------------------------------
  // Issue software reset using SYSRESETREQ bit in the AIRCR (Application Interrupt and Reset Control Register)
  _SoftReset();

  // - 7 ----------------------------------------------------------------------
  // Handshake: wait for debug interface becomes enabled after device reset
  status = _Handshake();
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  // Initialize the Debug Port and select CM0+ Access Port (AP[1])
  status = _InitDAP(_AP_MYCORE, 1 /* "1" - do power up request */);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }

  // - 8 ----------------------------------------------------------------------
  // Verify CPU is halted at breakpoint being set at Reset Address
  // S_HALT (bit[17]) and C_DEBUGE (bit[0]) in DHCSR register (@0xE000EDF0) must be set
  // Polling is required in order to wait till boot code finished execution (Listen window closed) and CPU halted at the user application entry
  v = _DHCSR_S_HALT | _DHCSR_C_DEBUGEN;
  status = _PollMem(_DHCSR_ADDR, v, 0, v, _TIMEOUT_SLEEP_LISTEN_WINDOW, 1);
  
  // - 9 ----------------------------------------------------------------------
  // Load infinite loop code into SRAM (0x08000300 <- 0xE7FEE7FE)
  status = _WriteMem(_SRAM_LOOP_ADDR, _LOOP_CODE);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  // Load PC with address of infinite for loop SRAM address with thumb bit (bit [0]) set
  status = _WriteCoreReg(_REGSEL_PC, (_SRAM_LOOP_ADDR | 1));
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }

  // - 10 ---------------------------------------------------------------------
  // Load SP with top of SRAM address - Set for minimum SRAM size devices (65 KB size)
  status = _WriteCoreReg(_REGSEL_MSP, _SRAM_TOP_ADDR); // SP <- 0x0800FFF0
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  // Read xPSR register, set the thumb bit, and restore modified value to xPSR register
  status = _ReadCoreReg(_REGSEL_xPSR, &v);
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  status = _WriteCoreReg(_REGSEL_xPSR, (v | _xPSR_T));

  // - 11 ---------------------------------------------------------------------
  // Disable Breakpoint unit so CPU will jump to endless loop execution in SRAM
  status = _WriteMem(_BP_CTRL_ADDR, _BP_CTRL_KEY); // BP_CTRL (0xE0002000) <- 0x00000002 (ENABLE == "0")
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  
  return _CheckStatus(status);
}

/*********************************************************************
*  Performs variety of PSoC 6 chip acquisition attempts:
*    1. Acquire in Test Mode so the boot code will not start the application
*    1.a. Using hardware pre-reset (XRES).
*         This is recommended and the only 100% reliable method.
*         But it will not work if XRES pin is not connected or debugger cannot meet timing requirements.
*    1.b. Using software pre-reset (AIRCR.SYSRESETREQ).
*         Do it in case XRES pin is not connected.
*    1.c. Acquire in Test Mode using software pre-reset (DP->CTRL/STAT.CDBGRSTREQ)
*         Do it in case firmware disabled anything behind the DAP so we can't use SYSRESETREQ.
* 
*    If all above steps failed, Test Mode acquisition is not possible because of
*    Listen window is turned off or the debugger cannot meet timing requirements.
*    In this case, use one following Alternate acquisition methods with same as above pre-reset strategies:
*
*    2. Acquire with "Alternate Method" based on setting the breakpoint at reset address
*    2.a. Using hardware pre-reset (XRES).
*    2.b. Using software pre-reset (AIRCR.SYSRESETREQ)
*    2.c. Using software pre-reset (DP->CTRL/STAT.CDBGRSTREQ)
*
* ! Note that XRES connection is strongly required for the hardware reset.
*   Otherwise, neither of above methods will work if the firmware does really "bad" things such as:
*   - Repurposes the debug pins (intentionally or unintentionally)
*   - Disables/Protects access ports and the Listen window is turned off or too short
*   - Intentionally or unintentionally corrupts values in MMIO registers and the Listen window is turned off or too short
*   In this case, there is no way for debugger to establish even basic communication with target
*   
*  Refer PSoC 6 MCU Programming Specifications: 002-15554 http://www.cypress.com/file/385671/download
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*
*  Notes
*    (1) Must not use any high-level functions as it is also called from InitTarget() and uses non-standard APs etc.
*/

int _PSoC6_Acquire(U32 resumeCPU) {
  int status;
  status = _STATUS_ERR;
  
  if (_DO_ACQUIRE_TEST_MODE != 0) {
    // 1. Acquire PSoC 6 in Test Mode:  
    //   1.1. Do hardware (XRES) or one of the software (AIRCR.SYSRESETREQ or DP->CTRL/STAT.CDBGRSTREQ) reset
    //   1.2. Handshake + Init DAP
    //   1.3. Set TEST_MODE bit in TST_MODE SRSS register
    //   1.4. Check CPU is sleeping (executes WFI)
    //   1.5. Check PC is in ROM or in SFLASH (CPU must be halted to read PC)
    // Items 1.1 to 1.3 are time critical, so entire function executed in J-Link firmware and requires __probe attribute for caller
    status = _PSoC6_AcquireTestMode(1 /* "1" - do hardware pre-reset (XRES) */);
    if (_CheckStatus(status) != _STATUS_OK) {
      // If acquisition failed for some reason (e.g. XRES is not connected), try to acquire in test mode using software reset
      // This should work if the Listen window is wide enough and the application did not disable the debug pins
      status = _PSoC6_AcquireTestMode(0 /* "0" - do software pre-reset (AIRCR.SYSRESETREQ or DP->CTRL/STAT.CDBGRSTREQ) */);
    }
  }

  if ((status != _STATUS_OK) && (_DO_ACQUIRE_ALTERNATE != 0) ) {
    // 2. Performs PSoC 6 acquisition using alternate sequence:
    //   2.1. Do hardware (XRES) or one of the software (AIRCR.SYSRESETREQ or DP->CTRL/STAT.CDBGRSTREQ) reset
    //   2.2. Handshake + Init DAP
    //   2.3. Halt CPU, enable debug
    //   2.4. Get Reset Address and Initial SP value from the vector table
    //   2.5. Enable Breakpoint unit and set the breakpoint at Reset Address
    //   2.6. Issue software reset using the SYSRESETREQ bit in AIRCR register
    //   2.7. Handshake + Init DAP
    //   2.8. Verify CPU is halted at breakpoint being set at Reset Address
    //   2.9. Load infinite loop into SRAM and set PC to this address
    //   2.10. Load SP with top of SRAM address, set thumb bit in xPSR
    //   2.11. Disable breakpoint unit and resume the CPU
    status = _PSoC6_AcquireAlternate(1 /* "1" - do hardware pre-reset (XRES) */);
    if (_CheckStatus(status) != _STATUS_OK) {
      // Last chance is to acquire using alternate method and software pre-reset
      status = _PSoC6_AcquireAlternate(0 /* "0" - do software pre-reset (AIRCR.SYSRESETREQ or DP->CTRL/STAT.CDBGRSTREQ) */);
    }
  }

  // Sets PC and SP for further debugging
  status = _PSoC6_SetPCandSPFromVectorTable();

  // Resume CPU that was halted above if it is required for caller
  if ((_CheckStatus(status) == _STATUS_OK) && (resumeCPU != 0)) {
    status = _HaltResumeCPU(0 /* "0" - resume */);
  }
 
  return _CheckStatus(status);
}
/*********************************************************************
*       Global functions
*********************************************************************/

/*********************************************************************
*  Called before InitTarget(). Mainly used to set some global DLL variables to customize the normal connect procedure.
*  For ARM CoreSight devices this may be specifying the base address of some CoreSight components (ETM, ...)
*  that cannot be automatically detected by J-Link due to erroneous ROM tables etc.
*  May also be used to specify the device name in case debugger does not pass it to the DLL.
*
*  Notes
*    (1) May not, under absolutely NO circumstances, call any API functions that perform target communication.
*    (2) Should only set some global DLL variables
*/
int ConfigTargetSettings(void) {
  Report("*****************************************************************");
  Report("JLinkScript: Start 'ConfigTargetSettings' for Cortex-M0+ of CY8C6xx5/CY8C6xxA");

  JLINK_CORESIGHT_AddAP(_AP_SYS, CORESIGHT_CUSTOM_AP); // AP[0]  SYS-AP (used for chip acquisition sequence)
  JLINK_CORESIGHT_AddAP(_AP_CM0, CORESIGHT_AHB_AP);    // AP[1]  CM0-AP (used for J-Link communication with Cortex-M0 core)
  JLINK_CORESIGHT_AddAP(_AP_CM4, CORESIGHT_AHB_AP);    // AP[2]  CM4-AP (used for J-Link communication with Cortex-M4 core)
  JLINK_CORESIGHT_IndexAHBAPToUse = _AP_MYCORE;        // AP-Index of AHB-AP to use for communication with core
  CPU=CORTEX_M0;

  Report("*****************************************************************");
  return _STATUS_OK;
}

/*********************************************************************
*  Replaces reset strategies of DLL.
*  No matter what reset type is selected in the DLL, if this function is present, it will be called instead of the DLL internal reset.
*
*  Return value
*    >= 0  O.K.
*    <  0  Error
*
*  Notes
*    (1) DLL expects target CPU to be halted / in debug mode, when leaving this function
*    (2) May use MEM_ API functions
*    (3) __probe attribute specifies that this function is executed in the J-Link firmware rather than on the PC side,
*        so changes to global variables may only be temporarily valid inside this function (not guaranteed to be valid later)
*/
__probe int ResetTarget(void) {
  int status;

  // Acquire PSoC 6 in Test Mode or using Alternate Method
  // Note: Test Mode acquisition is time critical, so entire function executed in J-Link firmware and requires __probe attribute for caller
  status = _PSoC6_Acquire(0); // "0" - Do not resume CPU that is halted during acquisition since DLL expects target CPU to be halted / in debug mode, when leaving ResetTarget function
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }
  
  // Enable DWT, ITM, TPIU, and ETM units by setting TRCENA bit in DEMCR register
  status = _WriteMem(_DEMCR_ADDR, _DEMCR_TRCENA); // DEMCR (0xE000EDFC) <- TRCENA
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }

  return _CheckStatus(status);
}

/*********************************************************************
*  Replaces the target-CPU-auto-find procedure of the J-Link DLL.
*  Useful for target CPUs that are not accessible by default and need some special steps
*  to be executed before the normal debug probe connect procedure can be executed successfully.
*
*  Return value
*    >= 0:  O.K.
*     < 0:  Error
*
*  Notes
*    (1) If target interface JTAG is used: JTAG chain has to be specified manually before leaving this function
*        (meaning all devices and their TAP IDs have to be specified by the user).
*        Also appropriate JTAG TAP number to communicate with during the debug session has to be manually specified in this function.
*    (2) MUST NOT use any MEM_ API functions
*    (3) Global DLL variable "CPU" MUST be set when implementing this function, so the DLL knows which CPU module to use internally.
*    (4) __probe attribute specifies that this function is executed in the J-Link firmware rather than on the PC side,
*        so changes to global variables may only be temporarily valid inside this function (not guaranteed to be valid later)
*/
__probe int InitTarget(void) {
  int status;

  // Acquire PSoC 6 in Test Mode (a. ToggleXRES; b. Handshake; c. Init DAP; d. Set TEST_MODE bit in TST_MODE SRSS register)
  // Sequence is time critical, so executed in J-Link firmware and requires __probe attribute for caller
  status = _PSoC6_Acquire(1); // "1" - Resume CPU that was halted during acquisition
  if (_CheckStatus(status) != _STATUS_OK) {
    return status;
  }

  JLINK_ExecCommand("SetETBIsPresent = 1"); // ETB is available

  return status;
}

/*********************************************************************
*  Called right after flash programming Usually used to restore initialized peripherals
*  which have been used during the flash download like for example clocks or port pins
*  (e.g. QSPI alternate function)
*
*  Notes / Limitations
*    (1) DLL expects target CPU to be halted / in debug mode, when leaving this function
*    (2) May use MEM_ API functions
*/
int HandleAfterFlashProg(void) {
  int status;

  // Do hardware (XRES) of software (AIRCR.SYSRESETREQ or DP->CTRL/STAT.CDBGRSTREQ) reset.
  // Otherwise, device remains acquired because the reset command sent by IDE after programming,
  // calls ResetTarget function, which will acquire target again.
  // This is required to start the application for normal execution and for "Attach" actions after programming.
  status = _PSoC6_Reset(1); // "1" do XRES
  return status;
}

/*************************** end of file ****************************/
