/*********************************************************************
*            (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

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)
*
**********************************************************************
*/

__constant U32 _ACCESS_DP                        = 0;
__constant U32 _ACCESS_AP                        = 1;
__constant U32 _DHCSR_ADDR                       = 0xE000EDF0; // Debug Halting Control and Status Register
__constant U32 _DEMCR_ADDR                       = 0xE000EDFC; // Debug Exception and Monitor Control Register
__constant U32 _DCRDR_ADDR                       = 0xE000EDF8; // Debug Core Register Data Register
__constant U32 _DCRSR_ADDR                       = 0xE000EDF4; // Debug Core Register Selector Register
__constant U32 _DAP_ACC_32BIT_NO_AUTO_INC        = (1 << 29) | (1 << 25) | (1 << 24) | (0 << 4) | (2 << 0);
__constant U32 _CPUSS_CM0_VTBASE                 = 0x40201120; // Vector table base address for CM0+ core (CPUSS_CM0_VECTOR_TABLE_BASE reg.)
__constant U32 _CPUSS_CMX_VTBASE_ERR_MSK         = 0xFFFFFF00; // Set by boot code if flash is empty or secure application

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

const U8 _aData_SeqSwitchToSWD[] = {
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,              // Line reset (min. 50 clocks SWDIO == HIGH)
  0x9E, 0xE7,                                            // Switching sequence STM32
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,              // Line reset (min. 50 clocks SWDIO == HIGH)
  0x00, 0x00                                             // Make sure SWD is ready for a start bit (min. 2 clocks with SWDIO == LOW)
};

const U8 _aDir_SeqSwitchToSWD[] = {
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF
};

U8 _aDataOut[18];                                  // Needs to be big enough to hold data for longest sequence

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

/*********************************************************************
*
*       _PerformChipAcquisitionSeq()
*
*  Function description
*    Performs the Cypress PSoC6-specific chip acquisition sequence.
*
*  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 _PerformChipAcquisitionSeq(void) {
  U32 v;
  U32 OrgTIFSpeed;
  int t;
  int tDelta;
  //
  // Perform Cypress PSoC 6 chip acquisition sequence
  // This is the recommended connection sequence, to make sure that we can gain control over the device again, even if there is bad code running on it
  //   nRESET == LOW
  //   nRESET == HIGH
  //   xx us (Wait for reset release)
  //   xx us (wait for secure boot code to finish)
  //   JTAGToSWDSwitching()
  //   Set TST_CTRL
  //   Device waits for app. 1500 us to receive the switching sequence + set TST_CTRL before it starts the user application
  //
  // We do not wait any fixed delay after reset release.
  // We just output the switching sequence and try to read the SW-DP Id. This is repeated, until successful.
  // This is done because the whole chip acquisition sequence is very time critical
  //
  //
  // Make sure that J-Link is using a high target interface speed,
  // so we can meet the timing requirements for "chip acquisition sequence"
  // 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 = 4000;
  //
  // 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
  //
  JLINK_CORESIGHT_Configure("RetryOnInvalDAPResp=0;PerformTIFInit=0"); // 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
  //
  // Reset device, so it will wait for "device acquisition sequence"
  //
  JLINK_JTAG_ResetPin = 0;  // nRESET == LOW
  JLINK_SYS_Sleep(10);      // Make sure that device recognizes the reset
  JLINK_JTAG_ResetPin = 1;  // nRESET == HIGH
  //
  // Wait until device becomes responsive
  //
  t = JLINK_GetTime();
  do {
    JLINK_SWD_ReadWriteBits(&_aData_SeqSwitchToSWD[0], &_aDir_SeqSwitchToSWD[0], &_aDataOut[0], 18 * 8);
    v = 0;
    JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_DP_REG_IDCODE, 0, &v);
    v &= 0x0F000FFF;
    if (v == 0x0B000477) {                      // DAP is responsive?
      break;
    }
    tDelta = JLINK_GetTime() - t;
  } while (tDelta < 1000);                        // Timeout reached?
  //
  // Put device into test mode, so it does not start the user application
  //
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_DP_REG_CTRL_STAT, 0, 0x50000000);
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_DP_REG_SELECT, 0, 0x00000000);
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_CTRL, 1, 0x00000002);
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, 1, 0x40260100);
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, 1, 0x80000000);  
  JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_DP_REG_RDBUF, 0, &v);   // Make sure that the last AP write actually happens as SW-DP may buffer/delay it until next DAP access
  //
  // Restore CORESIGHT settings (See beginning of this function call for more info)
  //
  JLINK_CORESIGHT_Configure("RetryOnInvalDAPResp=1;PerformTIFInit=0"); // 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
  //
  // Restore original TIF speed
  //
  JLINK_JTAG_Speed = OrgTIFSpeed;
  return 0;
}

/*********************************************************************
*
*       Global functions
*
**********************************************************************
*/

/*********************************************************************
*
*       ConfigTargetSettings()
*
*  Function description
*    Called before InitTarget(). Maninly 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 PSoC6xxA Cortex-M0+");

  //
  // The PSoC 6 has the following APs:
  // AP[0]  SYS-AP (used for chip acquisition sequence)
  // AP[1]  CM0-AP (used for J-Link communication with Cortex-M0 core)
  // AP[2]  CM4-AP (used for J-Link communication with Cortex-M4 core)
  //
  JLINK_CORESIGHT_AddAP(0, CORESIGHT_CUSTOM_AP);
  JLINK_CORESIGHT_AddAP(1, CORESIGHT_AHB_AP);
  JLINK_CORESIGHT_AddAP(2, CORESIGHT_AHB_AP);
  JLINK_CORESIGHT_IndexAHBAPToUse = 1; // AP-Index of AHB-AP to use for communication with core
  CPU=CORTEX_M0;

//  //
//  // Mark a specific memory region as memory type illegal
//  // in order to make sure that the software is not allowed to access these regions
//  // Note: This does not work for J-Flash tool
//  //
//  // Exclude SFLASH regions
//  JLINK_ExecCommand("map region 0x16000000-0x160007FF XI"); // [SFLASH Start - User Data Start]
//  JLINK_ExecCommand("map region 0x16001000-0x160019FF XI"); // [User Data End - NAR Start]
//  JLINK_ExecCommand("map region 0x16001C00-0x160059FF XI"); // [NAR End - Public Key Start]
//  JLINK_ExecCommand("map region 0x16006600-0x16007BFF XI"); // [Public Key End - TOC2 Start]
//  // Exclude Cy Metadata
//  JLINK_ExecCommand("map region 0x90300000-0x903FFFFF XI"); // Cy Checksum
//  JLINK_ExecCommand("map region 0x90500000-0x905FFFFF XI"); // Cy Metadata

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

/*********************************************************************
*
*       ResetTarget()
*
*  Function description
*    Replaces selected reset strategy of J-Link software.
*    No matter what reset type is selected, if this function is present, it will be called instead of the selected reset strategy
*
*  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
*/
__probe int ResetTarget(void) {   // __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)
  U32 iAPBank;
  U32 iAP;
  U32 v;
  U32 vtBase;
  U32 resetAddr;
  //
  // Perform standard chip acquisition sequence which also includes a reset
  //
  _PerformChipAcquisitionSeq();   // Requires __probe attribute for caller
  //
  // Make sure that the CPU is halted. See (1)
  // No rush here, as chip acquisition sequence makes sure that user application is not started
  //
  // DAP has already been powered-up etc. by _PerformChipAcquisitionSeq(), so no need to configure CoreSight here again
  //
  JLINK_SYS_Sleep(5);   // Give BTL some time to enter WFI
  iAPBank = 0;
  iAP = 1;    // AHB-AP for M0
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_DP_REG_SELECT, _ACCESS_DP, (iAP << 24) | (iAPBank << 4));
  //
  // Reset of PSoC6 also resets debug logic, so we need to restore some registers
  // Luckily, we need to touch most of these registers anyhow, to halt the core
  //
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_CTRL, _ACCESS_AP, _DAP_ACC_32BIT_NO_AUTO_INC);
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DHCSR_ADDR);
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACCESS_AP, 0xA05F0003);  // Key + C_DEBUGEN + C_HALT
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DEMCR_ADDR);
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACCESS_AP, (1 << 24));   // TRCENA
  JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_DP_REG_RDBUF, _ACCESS_DP, &v);          // Make sure that the last AP write actually happens as SW-DP may buffer/delay it until next DAP access
  JLINK_SYS_Sleep(2);  // Give CPU some time to handle halt request (should not be necessary, but as user-initiated reset is not really a time critical operation that happens rarely, it does not hurt)

  //
  // 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.
  // 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
  //
  JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _CPUSS_CM0_VTBASE);
  JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_AP_REG_DATA,  _ACCESS_AP, &vtBase);
  vtBase &= _CPUSS_CMX_VTBASE_ERR_MSK;
  
  if (vtBase != 0 && vtBase != _CPUSS_CMX_VTBASE_ERR_MSK) {

    // Get address at reset vector
    JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, vtBase + 4);
    JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_AP_REG_DATA,  _ACCESS_AP, &resetAddr);
    if (resetAddr != 0) {
  
      // Set PC with address at reset
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DCRDR_ADDR);
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACCESS_AP, resetAddr);  
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DCRSR_ADDR);
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACCESS_AP, 0x0001000F);  
    
      // Get address at vector table & set SP
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, vtBase);
      JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_AP_REG_DATA,  _ACCESS_AP, &v);
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DCRDR_ADDR);
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACCESS_AP, v);  
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DCRSR_ADDR);
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACCESS_AP, 0x00010011);  
    
      //Read xPSR register, set the thumb bit, and restore modified value to xPSR register
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DCRSR_ADDR);
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACCESS_AP, 0x00000010);  
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DCRDR_ADDR);
      JLINK_CORESIGHT_ReadDAP(JLINK_CORESIGHT_AP_REG_DATA,  _ACCESS_AP, &v);  
      v |= 0x01000000;
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DCRDR_ADDR);
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACCESS_AP, v);  
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_ADDR, _ACCESS_AP, _DCRSR_ADDR);
      JLINK_CORESIGHT_WriteDAP(JLINK_CORESIGHT_AP_REG_DATA, _ACCESS_AP, 0x00010010);  
	}
  }
  return 0;
}

/*********************************************************************
*
*       InitTarget()
*
*  Function description
*    If present, called right before performing generic connect sequence.
*    Usually used for targets which need a special connect sequence.
*    E.g.: TI devices with ICEPick TAP on them where core TAP needs to be enabled via specific ICEPick sequences first
*
*  Return value
*    >= 0:  O.K.
*     < 0:  Error
*
*  Notes
*    (1) Must not use high-level API functions like JLINK_MEM_ etc.
*    (2) For target interface JTAG, this device has to setup the JTAG chain + JTAG TAP Ids.
*    (3) This function is called before J-Link performed any communication with the device
*    (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) {   // __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)
  _PerformChipAcquisitionSeq();  // Requires __probe attribute for caller
  JLINK_ExecCommand("SetETBIsPresent = 1");
  return 0;
}

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