diff --git a/src/command.c b/src/command.c index c86dedb34f7..a2d997ca62e 100644 --- a/src/command.c +++ b/src/command.c @@ -117,6 +117,7 @@ const command_s cmd_list[] = { {"halt_timeout", cmd_halt_timeout, "Timeout to wait until Cortex-M is halted: [TIMEOUT, default 2000ms]"}, {"connect_rst", cmd_connect_reset, "Configure connect under reset: [enable|disable]"}, {"reset", cmd_reset, "Pulse the nRST line - disconnects target: [PULSE_LEN, default 0ms]"}, + {"reset_halt", cmd_reset, "Reset the target and halt at the first instruction"}, {"tdi_low_reset", cmd_tdi_low_reset, "Pulse nRST with TDI set low to attempt to wake certain targets up (eg LPC82x)"}, #ifdef PLATFORM_HAS_POWER_SWITCH diff --git a/src/include/buffer_utils.h b/src/include/buffer_utils.h index ed79f88dba4..275e592395c 100644 --- a/src/include/buffer_utils.h +++ b/src/include/buffer_utils.h @@ -59,6 +59,30 @@ static inline void write_be4(uint8_t *const buffer, const size_t offset, const u buffer[offset + 3U] = value & 0xffU; } +static inline void write_le8(uint8_t *const buffer, const size_t offset, const uint64_t value) +{ + buffer[offset + 0U] = value & 0xffU; + buffer[offset + 1U] = (value >> 8U) & 0xffU; + buffer[offset + 2U] = (value >> 16U) & 0xffU; + buffer[offset + 3U] = (value >> 24U) & 0xffU; + buffer[offset + 4U] = (value >> 32U) & 0xffU; + buffer[offset + 5U] = (value >> 40U) & 0xffU; + buffer[offset + 6U] = (value >> 48U) & 0xffU; + buffer[offset + 7U] = (value >> 56U) & 0xffU; +} + +static inline void write_be8(uint8_t *const buffer, const size_t offset, const uint64_t value) +{ + buffer[offset + 0U] = (value >> 56U) & 0xffU; + buffer[offset + 1U] = (value >> 48U) & 0xffU; + buffer[offset + 2U] = (value >> 40U) & 0xffU; + buffer[offset + 3U] = (value >> 32U) & 0xffU; + buffer[offset + 4U] = (value >> 24U) & 0xffU; + buffer[offset + 5U] = (value >> 16U) & 0xffU; + buffer[offset + 6U] = (value >> 8U) & 0xffU; + buffer[offset + 7U] = value & 0xffU; +} + static inline uint16_t read_le2(const uint8_t *const buffer, const size_t offset) { uint8_t data[2U]; @@ -89,6 +113,14 @@ static inline uint64_t read_be8(const uint8_t *const buffer, const size_t offset ((uint64_t)data[6] << 8U) | data[7]; } +static inline uint64_t read_le8(const uint8_t *const buffer, const size_t offset) +{ + return ((uint64_t)buffer[offset + 7] << 56U) | ((uint64_t)buffer[offset + 6] << 48U) | + ((uint64_t)buffer[offset + 5] << 40U) | ((uint64_t)buffer[offset + 4] << 32U) | + ((uint64_t)buffer[offset + 3] << 24U) | ((uint64_t)buffer[offset + 2] << 16U) | + ((uint64_t)buffer[offset + 1] << 8U) | buffer[offset + 0]; +} + static inline size_t write_char(char *const buffer, const size_t buffer_size, const size_t offset, const char c) { if (buffer && offset < buffer_size) diff --git a/src/include/target.h b/src/include/target.h index 6f9151d3503..192727671f4 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -55,6 +55,7 @@ bool bmda_rvswd_scan(void); bool adiv5_swd_scan(void); bool adiv5_swd_scan_targetid(uint32_t targetid); bool jtag_scan(void); +bool jtag_discover(void); bool onboard_flash_scan(void); size_t target_foreach(void (*callback)(size_t index, target_s *target, void *context), void *context); @@ -71,8 +72,10 @@ void target_detach(target_s *target); /* Memory access functions */ bool target_mem_map(target_s *target, char *buf, size_t len); bool target_mem32_read(target_s *target, void *dest, target_addr_t src, size_t len); +bool target_mem32_read_unswapped(target_s *const target, void *const dest, const target_addr_t src, const size_t len); bool target_mem64_read(target_s *target, void *dest, target_addr64_t src, size_t len); bool target_mem32_write(target_s *target, target_addr_t dest, const void *src, size_t len); +bool target_mem32_write_unswapped(target_s *target, target_addr_t dest, const void *src, size_t len); bool target_mem64_write(target_s *target, target_addr64_t dest, const void *src, size_t len); bool target_mem_access_needs_halt(target_s *target); /* Flash memory access functions */ diff --git a/src/platforms/hosted/dap.c b/src/platforms/hosted/dap.c index bcb92692ebd..a092abdeae8 100644 --- a/src/platforms/hosted/dap.c +++ b/src/platforms/hosted/dap.c @@ -84,6 +84,7 @@ static bool dap_transfer_configure(uint8_t idle_cycles, uint16_t wait_retries, u static uint32_t dap_current_clock_freq; static bool dap_nrst_state = false; +static bool dap_ntrst_state = false; bool dap_connect(void) { @@ -236,6 +237,33 @@ bool dap_nrst_set_val(const bool nrst_state) return response == request.pin_values; } +bool dap_ntrst_get_val(void) +{ + return dap_ntrst_state; +} + +bool dap_ntrst_set_val(const bool ntrst_state) +{ + /* Setup the request for the pin state change request */ + dap_swj_pins_request_s request = { + .request = DAP_SWJ_PINS, + /* nRST is active low, so take that into account */ + .pin_values = ntrst_state ? 0U : DAP_SWJ_nTRST, + .selected_pins = DAP_SWJ_nTRST, + }; + /* Tell the hardware to wait for 10µs for the pin to settle */ + write_le4(request.wait_time, 0, 10); + uint8_t response = 0U; + /* Execute it and check if it failed */ + if (!dap_run_cmd(&request, 7U, &response, 1U)) { + DEBUG_PROBE("%s failed\n", __func__); + return false; + } + /* Extract the current pin state for the device, de-inverting it */ + dap_ntrst_state = !(response & DAP_SWJ_nTRST); + return response == request.pin_values; +} + uint32_t dap_read_reg(adiv5_debug_port_s *target_dp, const uint8_t reg) { const dap_transfer_request_s request = {.request = reg | DAP_TRANSFER_RnW}; diff --git a/src/platforms/hosted/dap.h b/src/platforms/hosted/dap.h index df6a7d6af05..05d6eaf4706 100644 --- a/src/platforms/hosted/dap.h +++ b/src/platforms/hosted/dap.h @@ -81,6 +81,8 @@ extern uint8_t dap_quirks; bool dap_connect(void); bool dap_disconnect(void); +bool dap_ntrst_get_val(void); +bool dap_ntrst_set_val(const bool ntrst_state); bool dap_led(dap_led_type_e type, bool state); size_t dap_info(dap_info_e requested_info, void *buffer, size_t buffer_length); bool dap_set_reset_state(bool nrst_state); diff --git a/src/platforms/hosted/dap_jtag.c b/src/platforms/hosted/dap_jtag.c index bc677128618..eabd68ab2c6 100644 --- a/src/platforms/hosted/dap_jtag.c +++ b/src/platforms/hosted/dap_jtag.c @@ -41,6 +41,7 @@ static void dap_jtag_tms_seq(uint32_t tms_states, size_t clock_cycles); static void dap_jtag_tdi_tdo_seq(uint8_t *data_out, bool final_tms, const uint8_t *data_in, size_t clock_cycles); static void dap_jtag_tdi_seq(bool final_tms, const uint8_t *data_in, size_t clock_cycles); static bool dap_jtag_next(bool tms, bool tdi); +static void dap_jtag_cycle(const bool tms, const bool tdi, const size_t clock_cycles); bool dap_jtag_init(void) { @@ -52,12 +53,15 @@ bool dap_jtag_init(void) dap_disconnect(); dap_mode = DAP_CAP_JTAG; dap_connect(); + dap_ntrst_set_val(true); + dap_ntrst_set_val(false); jtag_proc.jtagtap_reset = dap_jtag_reset; jtag_proc.jtagtap_next = dap_jtag_next; jtag_proc.jtagtap_tms_seq = dap_jtag_tms_seq; jtag_proc.jtagtap_tdi_tdo_seq = dap_jtag_tdi_tdo_seq; jtag_proc.jtagtap_tdi_seq = dap_jtag_tdi_seq; + jtag_proc.jtagtap_cycle = dap_jtag_cycle; /* Ensure we're in JTAG mode */ for (size_t i = 0; i <= 50U; ++i) @@ -145,3 +149,9 @@ bool dap_jtag_configure(void) DEBUG_ERROR("dap_jtag_configure failed with %02x\n", response); return response == DAP_RESPONSE_OK; } + +static void dap_jtag_cycle(const bool tms, const bool tdi, const size_t clock_cycles) +{ + for (size_t cycle = 0U; cycle < clock_cycles; ++cycle) + dap_jtag_next(tms, tdi); +} diff --git a/src/rtt.c b/src/rtt.c index d52f776753b..8c2bbe5838c 100644 --- a/src/rtt.c +++ b/src/rtt.c @@ -121,6 +121,7 @@ static char xmit_buf[RTT_UP_BUF_SIZE]; * [Algo] Rolling hash; Rabin-Karp string search * - 0: https://yurichev.com/news/20210205_rolling_hash/ */ + static uint32_t fast_search(target_s *const cur_target, const uint32_t ram_start, const uint32_t ram_end) { static const uint32_t hash_len = 16; @@ -140,12 +141,17 @@ static uint32_t fast_search(target_s *const cur_target, const uint32_t ram_start gdb_outf("rtt: read fail at 0x%" PRIx32 "\r\n", addr); return 0; } + fprintf(stderr, "RTT @ 0x%08x: ", addr); for (uint32_t i = 0; i < buf_siz; i++) { + fprintf(stderr, " %02x", srch_buf[i + hash_len]); hash = (hash + q - remainder * srch_buf[i] % q) % q; hash = ((hash << 8U) + srch_buf[i + hash_len]) % q; - if (pattern == hash) + if (pattern == hash) { + fprintf(stderr, "\n"); return addr + i - hash_len + 1U; + } } + fprintf(stderr, "\n"); } /* no match */ return 0; @@ -209,7 +215,7 @@ static void find_rtt(target_s *const cur_target) DEBUG_INFO("rtt: match at 0x%" PRIx32 "\n", rtt_cbaddr); /* read number of rtt up and down channels from target */ uint32_t num_buf[2]; - if (target_mem32_read(cur_target, num_buf, rtt_cbaddr + 16U, sizeof(num_buf))) + if (target_mem32_read_unswapped(cur_target, num_buf, rtt_cbaddr + 16U, sizeof(num_buf))) return; rtt_num_up_chan = num_buf[0]; if (rtt_num_up_chan > MAX_RTT_CHAN) @@ -233,6 +239,10 @@ static void find_rtt(target_s *const cur_target) /* clear channel data */ memset(rtt_channel, 0, sizeof rtt_channel); + /* save first 24 bytes of control block */ + if (target_mem32_read_unswapped(cur_target, saved_cblock_header, rtt_cbaddr, sizeof(saved_cblock_header))) + return; + /* auto channel: enable output channel 0, channel 1 and first input channel */ if (rtt_auto_channel) { for (uint32_t i = 0; i < MAX_RTT_CHAN; i++) @@ -243,12 +253,9 @@ static void find_rtt(target_s *const cur_target) rtt_channel_enabled[rtt_num_up_chan] = true; } - /* save first 24 bytes of control block */ - if (target_mem32_read(cur_target, saved_cblock_header, rtt_cbaddr, sizeof(saved_cblock_header))) - return; rtt_found = true; - DEBUG_INFO("rtt found\n"); + DEBUG_INFO("rtt found -- %d up channels and %d down channels\n", num_buf[0], num_buf[1]); } } @@ -276,8 +283,10 @@ static rtt_retval_e read_rtt(target_s *const cur_target, const uint32_t i) if (cur_target == NULL || rtt_channel[i].buf_addr == 0 || rtt_channel[i].buf_size == 0) return RTT_IDLE; - if (rtt_channel[i].head >= rtt_channel[i].buf_size || rtt_channel[i].tail >= rtt_channel[i].buf_size) + if (rtt_channel[i].head >= rtt_channel[i].buf_size || rtt_channel[i].tail >= rtt_channel[i].buf_size) { + DEBUG_TARGET("write head: %d buf_size: %d tail: %d\n", rtt_channel[i].head, rtt_channel[i].buf_size, rtt_channel[i].tail); return RTT_ERR; + } /* write recv_buf to target rtt 'down' buf */ while (true) { @@ -287,7 +296,7 @@ static rtt_retval_e read_rtt(target_s *const cur_target, const uint32_t i) const int ch = rtt_getchar(channel); if (ch == -1) break; - if (target_mem32_write(cur_target, rtt_channel[i].buf_addr + rtt_channel[i].head, &ch, 1)) + if (target_mem32_write_unswapped(cur_target, rtt_channel[i].buf_addr + rtt_channel[i].head, &ch, 1)) return RTT_ERR; /* advance head pointer */ rtt_channel[i].head = next_head; @@ -295,8 +304,10 @@ static rtt_retval_e read_rtt(target_s *const cur_target, const uint32_t i) /* update head of target 'down' buffer */ const uint32_t head_addr = rtt_cbaddr + 24U + i * 24U + 12U; - if (target_mem32_write(cur_target, head_addr, &rtt_channel[i].head, sizeof(rtt_channel[i].head))) + if (target_mem32_write_unswapped(cur_target, head_addr, &rtt_channel[i].head, sizeof(rtt_channel[i].head))) { + DEBUG_TARGET("Again with the write failure\n"); return RTT_ERR; + } return RTT_OK; } @@ -363,7 +374,7 @@ static rtt_retval_e print_rtt(target_s *const cur_target, const uint32_t i) /* update tail of target 'up' buffer */ const uint32_t tail_addr = rtt_cbaddr + 24U + i * 24U + 16U; - if (target_mem32_write(cur_target, tail_addr, &rtt_channel[i].tail, sizeof(rtt_channel[i].tail))) + if (target_mem32_write_unswapped(cur_target, tail_addr, &rtt_channel[i].tail, sizeof(rtt_channel[i].tail))) return RTT_ERR; /* write buffer to usb */ @@ -413,9 +424,22 @@ void poll_rtt(target_s *const cur_target) if (rtt_found) { uint32_t cblock_header[6]; // first 24 bytes of control block /* check control block not changed or corrupted */ - if (target_mem32_read(cur_target, cblock_header, rtt_cbaddr, sizeof(cblock_header)) || - memcmp(saved_cblock_header, cblock_header, sizeof(cblock_header)) != 0) + if (target_mem32_read_unswapped(cur_target, cblock_header, rtt_cbaddr, sizeof(cblock_header)) || + memcmp(saved_cblock_header, cblock_header, sizeof(cblock_header)) != 0) { + fprintf(stderr, "Read %lu blocks from 0x%08x and it's different\n", sizeof(cblock_header), rtt_cbaddr); + unsigned int i; + fprintf(stderr, "saved: "); + for (i = 0; i < sizeof(cblock_header)/4; i++) { + fprintf(stderr, " %08x", saved_cblock_header[i]); + } + fprintf(stderr, "\n"); + fprintf(stderr, "found: "); + for (i = 0; i < sizeof(cblock_header)/4; i++) { + fprintf(stderr, " %08x", cblock_header[i]); + } + fprintf(stderr, "\n"); rtt_found = false; // force searching control block next poll_rtt() + } } bool rtt_err = false; @@ -424,7 +448,7 @@ void poll_rtt(target_s *const cur_target) if (rtt_found && rtt_cbaddr) { /* copy control block from target */ uint32_t rtt_cblock_size = sizeof(rtt_channel[0]) * (rtt_num_up_chan + rtt_num_down_chan); - if (target_mem32_read(cur_target, rtt_channel, rtt_cbaddr + 24U, rtt_cblock_size)) { + if (target_mem32_read_unswapped(cur_target, rtt_channel, rtt_cbaddr + 24U, rtt_cblock_size)) { gdb_outf("rtt: read fail at 0x%" PRIx32 "\r\n", rtt_cbaddr + 24U); rtt_err = true; } else { diff --git a/src/target/adi.c b/src/target/adi.c index 054ac516c18..da81b9d4f90 100644 --- a/src/target/adi.c +++ b/src/target/adi.c @@ -120,6 +120,7 @@ static const arm_coresight_component_s arm_component_lut[] = { {0x924, 0x13, 0, aa_nosupport, cidc_unknown, ARM_COMPONENT_STR("Cortex-M3 ETM", "(Embedded Trace)")}, {0x925, 0x13, 0, aa_nosupport, cidc_unknown, ARM_COMPONENT_STR("Cortex-M4 ETM", "(Embedded Trace)")}, {0x930, 0x13, 0, aa_nosupport, cidc_unknown, ARM_COMPONENT_STR("Cortex-R4 ETM", "(Embedded Trace)")}, + {0x931, 0x13, 0, aa_nosupport, cidc_unknown, ARM_COMPONENT_STR("Cortex-R5 ETM", "(Embedded Trace)")}, {0x932, 0x31, 0x0a31, aa_nosupport, cidc_unknown, ARM_COMPONENT_STR("CoreSight MTB-M0+", "(Simple Execution Trace)")}, {0x941, 0x00, 0, aa_nosupport, cidc_unknown, @@ -147,6 +148,7 @@ static const arm_coresight_component_s arm_component_lut[] = { {0xc09, 0x15, 0, aa_cortexa, cidc_dc, ARM_COMPONENT_STR("Cortex-A9", "(Debug Unit)")}, {0xc0f, 0x15, 0, aa_cortexa, cidc_unknown, ARM_COMPONENT_STR("Cortex-A15", "(Debug Unit)")}, {0xc14, 0x15, 0, aa_cortexr, cidc_unknown, ARM_COMPONENT_STR("Cortex-R4", "(Debug Unit)")}, + {0xc15, 0x15, 0, aa_cortexr, cidc_unknown, ARM_COMPONENT_STR("Cortex-R5", "(Debug Unit)")}, {0xcd0, 0x00, 0, aa_nosupport, cidc_unknown, ARM_COMPONENT_STR("Atmel DSU", "(Device Service Unit)")}, {0xd20, 0x00, 0x2a04, aa_cortexm, cidc_gipc, ARM_COMPONENT_STR("Cortex-M23", "(System Control Space)")}, {0xd20, 0x11, 0, aa_nosupport, cidc_dc, ARM_COMPONENT_STR("Cortex-M23", "(Trace Port Interface Unit)")}, diff --git a/src/target/am335x.c b/src/target/am335x.c new file mode 100644 index 00000000000..49fc39e7a0d --- /dev/null +++ b/src/target/am335x.c @@ -0,0 +1,63 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2024 1BitSquared + * Written by Rachel Mant + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file implements support for AM355x series devices, providing memory + * maps and Flash programming routines. + * + * References: + * SPRUH73Q - AM335x and AMIC110 Sitara™ Processors + * https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf + */ + +#include "general.h" +#include "target.h" +#include "target_internal.h" +#include "cortex.h" + +#define AM335x_CTRL_BASE 0x44e10000U +#define AM335x_CTRL_DEVICE_ID (AM335x_CTRL_BASE + 0x600U) + +#define AM335x_CTRL_DEVICE_ID_MASK 0x0fffffffU +#define AM335x_CTRL_DEVICE_ID_AM335x 0x0b94402eU + +bool am335x_cm3_probe(target_s *const target) +{ + /* Try to read out the device identification register and check this is actually an AM335x device */ + const uint32_t device_id = target_mem32_read32(target, AM335x_CTRL_DEVICE_ID) & AM335x_CTRL_DEVICE_ID_MASK; + if (device_id != AM335x_CTRL_DEVICE_ID_AM335x) + return false; + + cortex_ap(target)->dp->quirks |= ADIV5_DP_QUIRK_DUPED_AP; + return true; +} diff --git a/src/target/cortexar.c b/src/target/cortexar.c index 4ec6ad10806..e2fb42e11d9 100644 --- a/src/target/cortexar.c +++ b/src/target/cortexar.c @@ -70,6 +70,8 @@ typedef struct cortexar_priv { uint32_t spsr[5U]; uint64_t d[16U]; uint32_t fpcsr; + uint32_t dfsr; + uint32_t dfar; } core_regs; /* Fault status/address cache */ @@ -194,6 +196,7 @@ typedef struct cortexar_priv { #define CORTEXAR_CPSR_MODE_HYP 0x0000001aU #define CORTEXAR_CPSR_MODE_SYS 0x0000001fU #define CORTEXAR_CPSR_THUMB (1U << 5U) +#define CORTEXAR_CPSR_BE (1U << 9U) /* CPSR remap position for GDB XML mapping */ #define CORTEXAR_CPSR_GDB_REMAP_POS 25U @@ -249,7 +252,7 @@ static const uint16_t cortexar_spsr_encodings[5] = { (((opc1) << 21U) | ((crn) << 16U) | ((rt) << 12U) | ((coproc) << 8U) | ((opc2) << 5U) | (crm)) /* Packs a CRn and CRm value for the coprocessor IO routines below to unpack */ #define ENCODE_CP_REG(n, m, opc1, opc2) \ - ((((n) & 0xfU) << 4U) | ((m) & 0xfU) | (((opc1) & 0x7U) << 8U) | (((opc2) & 0x7U) << 12U)) + ((((n)&0xfU) << 4U) | ((m)&0xfU) | (((opc1)&0x7U) << 8U) | (((opc2)&0x7U) << 12U)) /* * Instruction encodings for coprocessor load/store @@ -286,10 +289,10 @@ static const uint16_t cortexar_spsr_encodings[5] = { * The fourth is `STRH r1, [r0], #+2` to store a uint16_t to [r0] from r1 and increment * the address in r0 by 2, writing the new address back to r0. */ -#define ARM_LDRB_R0_R1_INSN 0xe4f01001U -#define ARM_LDRH_R0_R1_INSN 0xe0f010b2U -#define ARM_STRB_R1_R0_INSN 0xe4e01001U -#define ARM_STRH_R1_R0_INSN 0xe0e010b2U +#define ARM_LDRB_R0_R1_INSN 0xe4d01001U +#define ARM_LDRH_R0_R1_INSN 0xe0d010b2U +#define ARM_STRB_R1_R0_INSN 0xe4c01001U +#define ARM_STRH_R1_R0_INSN 0xe0c010b2U /* Instruction encodings for synchronisation barriers */ #define ARM_ISB_INSN 0xe57ff06fU @@ -348,6 +351,7 @@ static const uint16_t cortexar_spsr_encodings[5] = { #define TOPT_FLAVOUR_SEC_EXT (1U << 2U) /* If set, core has security extensions */ #define TOPT_FLAVOUR_VIRT_EXT (1U << 3U) /* If set, core has virtualisation extensions */ #define TOPT_FLAVOUR_VIRT_MEM (1U << 4U) /* If set, core uses the virtual memory model, not protected */ +#define TOPT_FLAVOUR_BE (1U << 5U) /* If set, core is big endian, not little endian */ #define CORTEXAR_STATUS_DATA_FAULT (1U << 0U) #define CORTEXAR_STATUS_MMU_FAULT (1U << 1U) @@ -699,7 +703,6 @@ static target_addr_t cortexar_virt_to_phys(target_s *const target, const target_ static bool cortexar_oslock_unlock(target_s *const target) { const uint32_t lock_status = cortex_dbg_read32(target, CORTEXAR_DBG_OSLSR); - DEBUG_TARGET("%s: OS lock status: %08" PRIx32 "\n", __func__, lock_status); /* Check if the lock is implemented, then if it is, if it's set */ if (((lock_status & CORTEXAR_DBG_OSLSR_OS_LOCK_MODEL) == CORTEXAR_DBG_OSLSR_OS_LOCK_MODEL_FULL || (lock_status & CORTEXAR_DBG_OSLSR_OS_LOCK_MODEL) == CORTEXAR_DBG_OSLSR_OS_LOCK_MODEL_PARTIAL) && @@ -886,6 +889,16 @@ static target_s *cortexar_probe( } else target_check_error(target); + /* Read the CPSR to figure out if this target is big endian. This clobbers r0, so save + * r0 beforehand and restore it after the read is complete. + */ + uint32_t r0 = cortexar_core_reg_read(target, 0U); + cortexar_run_insn(target, ARM_MRS_R0_CPSR_INSN); + priv->core_regs.cpsr = cortexar_core_reg_read(target, 0U); + cortexar_core_reg_write(target, 0U, r0); + if (priv->core_regs.cpsr & CORTEXAR_CPSR_BE) + target->target_options |= TOPT_FLAVOUR_BE; + return target; } @@ -922,6 +935,13 @@ bool cortexr_probe(adiv5_access_port_s *const ap, const target_addr_t base_addre if (!target) return false; + switch (target->designer_code) { + /* TI omitted the designer code on TMS570 */ + case 0: + PROBE(ti_tms570_probe); + break; + } + #if CONFIG_BMDA == 0 gdb_outf("Please report unknown device with Designer 0x%x Part ID 0x%x\n", target->designer_code, target->part_id); #else @@ -949,7 +969,7 @@ bool cortexar_attach(target_s *const target) target_halt_reason_e reason = TARGET_HALT_RUNNING; while (!platform_timeout_is_expired(&timeout) && reason == TARGET_HALT_RUNNING) reason = target_halt_poll(target, NULL); - if (reason != TARGET_HALT_REQUEST) { + if ((reason != TARGET_HALT_REQUEST) && (reason != TARGET_HALT_BREAKPOINT)) { DEBUG_ERROR("Failed to halt the core\n"); return false; } @@ -999,6 +1019,36 @@ static bool cortexar_check_error(target_s *const target) return fault || cortex_check_error(target); } +static inline uint32_t cortexar_endian_dp_read(target_s *const target, const uint16_t addr) +{ + cortexar_priv_s *const priv = (cortexar_priv_s *)target->priv; + uint32_t value = adiv5_dp_read(priv->base.ap->dp, addr); + extern bool skip_swap; + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) { + uint8_t tmp_value[4]; + // The instruction run gave us back a value that we interpreted as little endian, however + write_le4(tmp_value, 0, value); + // This target is big endian, so convert to the opposite representation + value = read_be4(tmp_value, 0); + } + return value; +} + +static inline void cortexar_endian_dp_write(target_s *const target, const uint16_t addr, uint32_t value) +{ + cortexar_priv_s *const priv = (cortexar_priv_s *)target->priv; + extern bool skip_swap; + + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) { + uint8_t tmp_value[4]; + // The instruction run gave us back a value that we interpreted as little endian, however + write_le4(tmp_value, 0, value); + // This target is big endian, so convert to the opposite representation + value = read_be4(tmp_value, 0); + } + adiv5_dp_write(priv->base.ap->dp, addr, value); +} + /* Fast path for cortexar_mem_read(). Assumes the address to read data from is already loaded in r0. */ static inline bool cortexar_mem_read_fast(target_s *const target, uint32_t *const dest, const size_t count) { @@ -1016,7 +1066,7 @@ static inline bool cortexar_mem_read_fast(target_s *const target, uint32_t *cons /* Run the transfer, hammering the DTR */ for (size_t offset = 0; offset < count; ++offset) { /* Read the next value, which is the value for the last instruction run */ - const uint32_t value = adiv5_dp_read(priv->base.ap->dp, ADIV5_AP_DB(CORTEXAR_BANKED_DTRRX)); + const uint32_t value = cortexar_endian_dp_read(target, ADIV5_AP_DB(CORTEXAR_BANKED_DTRRX)); /* If we've run the instruction at least once, store it */ if (offset) dest[offset - 1U] = value; @@ -1026,7 +1076,7 @@ static inline bool cortexar_mem_read_fast(target_s *const target, uint32_t *cons /* Go back into DCC Normal (Non-blocking) mode */ adiv5_dp_write(priv->base.ap->dp, ADIV5_AP_DB(CORTEXAR_BANKED_DCSR), dbg_dcsr | CORTEXAR_DBG_DCSR_DCC_NORMAL); /* Grab the value of the last instruction run now it won't run again */ - dest[count - 1U] = adiv5_dp_read(priv->base.ap->dp, ADIV5_AP_DB(CORTEXAR_BANKED_DTRRX)); + dest[count - 1U] = cortexar_endian_dp_read(target, ADIV5_AP_DB(CORTEXAR_BANKED_DTRRX)); /* Check if the instruction triggered a synchronous data abort */ return cortexar_check_data_abort(target, status); } @@ -1035,6 +1085,14 @@ static inline bool cortexar_mem_read_fast(target_s *const target, uint32_t *cons for (size_t offset = 0; offset < count; ++offset) { if (!cortexar_run_read_insn(target, ARM_LDC_R0_POSTINC4_DTRTX_INSN, dest + offset)) return false; /* Propagate failure if it happens */ + extern bool skip_swap; + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) { + uint8_t value[4]; + // The instruction run gave us back a value that we interpreted as little endian, however + write_le4(value, 0, dest[offset]); + // This target is big endian, so convert to the opposite representation + dest[offset] = read_be4(value, 0); + } } return true; /* Signal success */ } @@ -1160,7 +1218,7 @@ static inline bool cortexar_mem_write_fast(target_s *const target, const uint32_ adiv5_dp_write(priv->base.ap->dp, ADIV5_AP_DB(CORTEXAR_BANKED_ITR), ARM_STC_DTRRX_R0_POSTINC4_INSN); /* Run the transfer, hammering the DTR */ for (size_t offset = 0; offset < count; ++offset) - adiv5_dp_write(priv->base.ap->dp, ADIV5_AP_DB(CORTEXAR_BANKED_DTRTX), src[offset]); + cortexar_endian_dp_write(target, ADIV5_AP_DB(CORTEXAR_BANKED_DTRTX), src[offset]); /* Now read out the status from the DCSR in case anything went wrong */ const uint32_t status = adiv5_dp_read(priv->base.ap->dp, ADIV5_AP_DB(CORTEXAR_BANKED_DCSR)); /* Go back into DCC Normal (Non-blocking) mode */ @@ -1171,7 +1229,13 @@ static inline bool cortexar_mem_write_fast(target_s *const target, const uint32_ /* Write each of the uint32_t's checking for failure */ for (size_t offset = 0; offset < count; ++offset) { - if (!cortexar_run_write_insn(target, ARM_STC_DTRRX_R0_POSTINC4_INSN, src[offset])) + uint32_t value; + extern bool skip_swap; + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) + value = read_be4((const void *)src, offset * 4U); + else + value = read_le4((const void *)src, offset * 4U); + if (!cortexar_run_write_insn(target, ARM_STC_DTRRX_R0_POSTINC4_INSN, value)) return false; /* Propagate failure if it happens */ } return true; /* Signal success */ @@ -1271,12 +1335,31 @@ static void cortexar_regs_read(target_s *const target, void *const data) { const cortexar_priv_s *const priv = (cortexar_priv_s *)target->priv; uint32_t *const regs = (uint32_t *)data; + extern bool skip_swap; /* Copy the register values out from our cache */ - memcpy(regs, priv->core_regs.r, sizeof(priv->core_regs.r)); - regs[CORTEX_REG_CPSR] = priv->core_regs.cpsr; + for (size_t reg_index = 0; reg_index < sizeof(priv->core_regs.r) / sizeof(*priv->core_regs.r); reg_index++) + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) + write_be4(data, reg_index * 4, priv->core_regs.r[reg_index]); + else + write_le4(data, reg_index * 4, priv->core_regs.r[reg_index]); + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) { + uint8_t value[4]; + write_le4(value, 0, priv->core_regs.cpsr); + regs[CORTEX_REG_CPSR] = read_be4(value, 0); + } else + regs[CORTEX_REG_CPSR] = priv->core_regs.cpsr; if (target->target_options & TOPT_FLAVOUR_FLOAT) { - memcpy(regs + CORTEXAR_GENERAL_REG_COUNT, priv->core_regs.d, sizeof(priv->core_regs.d)); - regs[CORTEX_REG_FPCSR] = priv->core_regs.fpcsr; + for (size_t reg_index = 0; reg_index < sizeof(priv->core_regs.d) / sizeof(*priv->core_regs.d); reg_index++) + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) + write_be4(data, (CORTEXAR_GENERAL_REG_COUNT + reg_index) * 4, priv->core_regs.d[reg_index]); + else + write_le4(data, (CORTEXAR_GENERAL_REG_COUNT + reg_index) * 4, priv->core_regs.d[reg_index]); + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) { + uint8_t value[4]; + write_le4(value, 0, priv->core_regs.fpcsr); + regs[CORTEX_REG_FPCSR] = read_be4(value, 0); + } else + regs[CORTEX_REG_FPCSR] = priv->core_regs.fpcsr; } } @@ -1284,12 +1367,31 @@ static void cortexar_regs_write(target_s *const target, const void *const data) { cortexar_priv_s *const priv = (cortexar_priv_s *)target->priv; const uint32_t *const regs = (const uint32_t *)data; + extern bool skip_swap; /* Copy the new register values into our cache */ - memcpy(priv->core_regs.r, regs, sizeof(priv->core_regs.r)); - priv->core_regs.cpsr = regs[CORTEX_REG_CPSR]; + for (size_t reg_index = 0; reg_index < sizeof(priv->core_regs.r) / sizeof(*priv->core_regs.r); reg_index++) + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) + priv->core_regs.r[reg_index] = read_be4(data, reg_index * 4); + else + priv->core_regs.r[reg_index] = read_le4(data, reg_index * 4); + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) { + uint8_t value[4]; + write_le4(value, 0, regs[CORTEX_REG_CPSR]); + priv->core_regs.cpsr = read_be4(value, 0); + } else + priv->core_regs.cpsr = regs[CORTEX_REG_CPSR]; if (target->target_options & TOPT_FLAVOUR_FLOAT) { - memcpy(priv->core_regs.d, regs + CORTEXAR_GENERAL_REG_COUNT, sizeof(priv->core_regs.d)); - priv->core_regs.fpcsr = regs[CORTEX_REG_FPCSR]; + for (size_t reg_index = 0; reg_index < sizeof(priv->core_regs.r) / sizeof(*priv->core_regs.r); reg_index++) + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) + priv->core_regs.d[reg_index] = read_be4(data, (reg_index + CORTEXAR_GENERAL_REG_COUNT) * 4); + else + priv->core_regs.d[reg_index] = read_le4(data, (reg_index + CORTEXAR_GENERAL_REG_COUNT) * 4); + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) { + uint8_t value[4]; + write_le4(value, 0, regs[CORTEX_REG_FPCSR]); + priv->core_regs.fpcsr = read_be4(value, 0); + } else + priv->core_regs.fpcsr = regs[CORTEX_REG_FPCSR]; } } @@ -1325,6 +1427,7 @@ static size_t cortexar_reg_width(const size_t reg) static size_t cortexar_reg_read(target_s *const target, const uint32_t reg, void *const data, const size_t max) { + extern bool skip_swap; /* Try to get a pointer to the storage for the requested register, and return -1 if that fails */ const void *const reg_ptr = cortexar_reg_ptr(target, reg); if (!reg_ptr) @@ -1334,12 +1437,32 @@ static size_t cortexar_reg_read(target_s *const target, const uint32_t reg, void if (max < reg_width) return 0; /* Finally, copy the register data out and return the width */ - memcpy(data, reg_ptr, reg_width); + switch (reg_width) { + case 4: { + uint32_t value; + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) + value = read_be4(reg_ptr, 0); + else + value = read_le4(reg_ptr, 0); + write_le4(data, 0, value); + break; + } + case 8: { + uint64_t value; + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) + value = read_be8(reg_ptr, 0); + else + value = read_le8(reg_ptr, 0); + write_le8(data, 0, value); + break; + } + } return reg_width; } static size_t cortexar_reg_write(target_s *const target, const uint32_t reg, const void *const data, const size_t max) { + extern bool skip_swap; /* Try to get a pointer to the storage for the requested register, and return -1 if that fails */ void *const reg_ptr = cortexar_reg_ptr(target, reg); if (!reg_ptr) @@ -1349,7 +1472,24 @@ static size_t cortexar_reg_write(target_s *const target, const uint32_t reg, con if (max < reg_width) return 0; /* Finally, copy the new register data in and return the width */ - memcpy(reg_ptr, data, reg_width); + switch (reg_width) { + case 4: { + uint32_t value = read_le4(data, 0); + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) + write_be4(reg_ptr, 0, value); + else + write_le4(reg_ptr, 0, value); + break; + } + case 8: { + uint64_t value = read_le8(data, 0); + if ((target->target_options & TOPT_FLAVOUR_BE) && !skip_swap) + write_be8(reg_ptr, 0, value); + else + write_le8(reg_ptr, 0, value); + break; + } + } return reg_width; } @@ -1389,7 +1529,7 @@ static void cortexar_reset(target_s *const target) #endif /* 10ms delay to ensure bootroms have had time to run */ - platform_delay(10); + // platform_delay(10); /* Ignore any initial errors out of reset */ target_check_error(target); } @@ -1497,6 +1637,10 @@ static void cortexar_halt_resume(target_s *const target, const bool step) /* Invalidate all the instruction caches if we're on a VMSA model device */ if (target->target_options & TOPT_FLAVOUR_VIRT_MEM) cortexar_coproc_write(target, CORTEXAR_ICIALLU, 0U); + else { + cortexar_coproc_write(target, CORTEXAR_ICIALLU, 0U); + // cortexar_run_insn(target, ARM_ISB_INSN); + } /* Mark the fault status and address cache invalid */ priv->core_status &= ~CORTEXAR_STATUS_FAULT_CACHE_VALID; diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 71b571b4fde..0acef62e707 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -501,6 +501,7 @@ bool cortexm_probe(adiv5_access_port_s *ap) PROBE(ke04_probe); PROBE(lpc17xx_probe); PROBE(lpc11xx_probe); /* LPC1343 */ + PROBE(am335x_cm3_probe); break; } #if CONFIG_BMDA == 0 diff --git a/src/target/icepick.c b/src/target/icepick.c new file mode 100644 index 00000000000..f8fc67d5252 --- /dev/null +++ b/src/target/icepick.c @@ -0,0 +1,272 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2024 1BitSquared + * Written by Rachel Mant + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file implements support for the TI ICEPick controller that sits in front + * of TAPs in the scan chain on some TI devices. + * + * References: + * SPRUH35 - Using the ICEPick TAP (type-C) + * https://www.ti.com/lit/ug/spruh35/spruh35.pdf + */ + +#include "general.h" +#include "buffer_utils.h" +#include "jtag_scan.h" +#include "jtagtap.h" +#include "icepick.h" + +#define IR_ROUTER 0x02U +#define IR_IDCODE 0x04U +#define IR_ICEPICKCODE 0x05U +#define IR_CONNECT 0x07U + +/* + * The type-C value is taken from SPRUH35, the type-D value is + * from a BeagleBone Black Industrial (AM3358BZCZA100) + */ +#define ICEPICK_TYPE_MASK 0xfff0U +#define ICEPICK_TYPE_C 0x1cc0U +#define ICEPICK_TYPE_D 0xb3d0U + +#define ICEPICK_MAJOR_SHIFT 28U +#define ICEPICK_MAJOR_MASK 0xfU +#define ICEPICK_MINOR_SHIFT 24U +#define ICEPICK_MINOR_MASK 0xfU + +#define ICEPICK_TESTAPS_SHIFT 20 +#define ICEPICK_TESTAPS_MASK 7 + +#define ICEPICK_ROUTING_REG_MASK 0x7fU +#define ICEPICK_ROUTING_REG_SHIFT 24U +#define ICEPICK_ROUTING_DATA_MASK 0x00ffffffU +#define ICEPICK_ROUTING_RNW_MASK 0x80000000U +#define ICEPICK_ROUTING_RNW_WRITE 0x80000000U +#define ICEPICK_ROUTING_FAIL 0x80000000U + +#define ICEPICK_ROUTING_SYSCTRL 0x01U +#define ICEPICK_ROUTING_DEBUG_TAP_BASE 0x20U +#define ICEPICK_ROUTING_DEBUG_TAP_COUNT 16U +#define ICEPICK_ROUTING_CORE_BASE 0x60U +#define ICEPICK_ROUTING_CORE_COUNT 16U + +#define ICEPICK_ROUTING_SYSCTRL_FREE_RUNNING_TCK 0x00001000U +#define ICEPICK_ROUTING_SYSCTRL_KEEP_POWERED 0x00000080U +#define ICEPICK_ROUTING_SYSCTRL_TDO_ALWAYS_OUT 0x00000020U +#define ICEPICK_ROUTING_SYSCTRL_DEVICE_TYPE_MASK 0x0000000eU +#define ICEPICK_ROUTING_SYSCTRL_SYSTEM_RESET 0x00000001U + +#define ICEPICK_ROUTING_DEBUG_TAP_POWER_LOST 0x00200000U +#define ICEPICK_ROUTING_DEBUG_TAP_INHIBIT_SLEEP 0x00100000U +#define ICEPICK_ROUTING_DEBUG_TAP_RELEASE_WIR 0x00020000U +#define ICEPICK_ROUTING_DEBUG_TAP_DEBUG_ENABLE 0x00002000U +#define ICEPICK_ROUTING_DEBUG_TAP_SELECT 0x00000100U +#define ICEPICK_ROUTING_DEBUG_TAP_FORCE_ACTIVE 0x00000008U + +/* + * The connect register is 8 bits long and has the following format: + * [0:3] - Connect key (9 to connect, anything else to disconnect) + * [4:6] - Reserved, RAZ/WI + * [7] - Write Enable, 1 to enable writing this register + */ +#define ICEPICK_CONNECT 0x89U +#define ICEPICK_DISCONNECT 0x80U + +static void icepick_write_ir(jtag_dev_s *device, uint8_t ir); +static uint32_t icepick_shift_dr(const jtag_dev_s *device, uint32_t data_in, size_t clock_cycles); +static void icepick_configure(jtag_dev_s *device, char icepick_type, uint32_t tap_count); + +void icepick_router_handler(const uint8_t dev_index) +{ + if (dev_index >= 2U) + return; + jtag_dev_s *const device = &jtag_devs[dev_index]; + + /* Switch the ICEPick TAP into its controller identification mode */ + icepick_write_ir(device, IR_ICEPICKCODE); + /* Then read out the 32-bit controller ID code */ + const uint32_t icepick_idcode = icepick_shift_dr(device, 0U, 32U); + char icepick_type; + uint32_t testaps_count; + + /* Check it's a suitable ICEPick controller, and abort if not */ + switch (icepick_idcode & ICEPICK_TYPE_MASK) { + case ICEPICK_TYPE_C: + icepick_type = 'C'; + testaps_count = (icepick_idcode >> ICEPICK_TESTAPS_SHIFT) & ICEPICK_TESTAPS_MASK; + break; + case ICEPICK_TYPE_D: + icepick_type = 'D'; + testaps_count = ICEPICK_ROUTING_DEBUG_TAP_COUNT; + break; + default: + DEBUG_ERROR("ICEPick is not a type-C or type-D controller (%08" PRIx32 ")\n", icepick_idcode); + return; + } + + DEBUG_INFO("ICEPick type-%c controller v%u.%u (%08" PRIx32 ")\n", icepick_type, + (icepick_idcode >> ICEPICK_MAJOR_SHIFT) & ICEPICK_MAJOR_MASK, + (icepick_idcode >> ICEPICK_MINOR_SHIFT) & ICEPICK_MINOR_MASK, icepick_idcode); + + /* Connect to the controller so we can modify the scan chain */ + icepick_write_ir(device, IR_CONNECT); + icepick_shift_dr(device, ICEPICK_CONNECT, 8U); + + /* Now we're connected, go into the routing inspection/modification mode */ + icepick_write_ir(device, IR_ROUTER); + /* Configure the router to put the Cortex TAP(s) on chain */ + icepick_configure(device, icepick_type, testaps_count); + /* Go to an idle state instruction and then run 10 idle cycles to complete reconfiguration */ + icepick_write_ir(device, IR_IDCODE); + jtag_proc.jtagtap_cycle(false, false, 10U); + /* Now re-scan the bus to pick up all the new TAPs */ + jtag_discover(); +} + +/* Read an ICEPick routing register */ +static bool icepick_read_reg(const jtag_dev_s *const device, const uint8_t reg, uint32_t *const result) +{ + /* Start by building a read request and sending it to the controller */ + icepick_shift_dr(device, (uint32_t)(reg & ICEPICK_ROUTING_REG_MASK) << ICEPICK_ROUTING_REG_SHIFT, 32U); + /* Having completed this, now do a dummy request to reg 0 to find out what the response is */ + const uint32_t value = icepick_shift_dr(device, 0U, 32U); + /* Now check if the request failed */ + if (value & ICEPICK_ROUTING_FAIL) + return false; + /* It did not, so now extract the data portion of the result */ + *result = value & ICEPICK_ROUTING_DATA_MASK; + return true; +} + +/* Write an ICEPick routing register */ +static bool icepick_write_reg(const jtag_dev_s *const device, const uint8_t reg, const uint32_t value) +{ + /* Build a write a request and send it to the controller */ + icepick_shift_dr(device, + ICEPICK_ROUTING_RNW_WRITE | ((uint32_t)(reg & ICEPICK_ROUTING_REG_MASK) << ICEPICK_ROUTING_REG_SHIFT) | + (value & ICEPICK_ROUTING_DATA_MASK), + 32U); + /* Having completed this, now do a dummy request to reg 0 to find out what the response is */ + const uint32_t result = icepick_shift_dr(device, 0U, 32U); + /* Now check if the request failed */ + return !(result & ICEPICK_ROUTING_FAIL); +} + +static void icepick_configure(jtag_dev_s *const device, char icepick_type, const uint32_t testaps_count) +{ + /* Try to read out the system control register */ + uint32_t sysctrl = 0U; + if (!icepick_read_reg(device, ICEPICK_ROUTING_SYSCTRL, &sysctrl)) { + DEBUG_ERROR("Failed to read ICEPick System Control register\n"); + return; + } + + /* Decode the register to determine what we've got */ + DEBUG_INFO("ICEPick sysctrl = %08" PRIx32 "\n", sysctrl); + /* + * Make sure the controller is set up for non-free-running TCK, that will be reset + * when doing a test logic reset, and that TDO is always an output + */ + sysctrl &= ~(ICEPICK_ROUTING_SYSCTRL_FREE_RUNNING_TCK | ICEPICK_ROUTING_SYSCTRL_KEEP_POWERED | + ICEPICK_ROUTING_SYSCTRL_TDO_ALWAYS_OUT); + if (!icepick_write_reg(device, ICEPICK_ROUTING_SYSCTRL, sysctrl)) { + DEBUG_ERROR("Failed to configure ICEPick\n"); + return; + } + + for (uint8_t tap = 0U; tap < testaps_count; ++tap) { + uint32_t tap_config = 0U; + if (icepick_read_reg(device, ICEPICK_ROUTING_DEBUG_TAP_BASE + tap, &tap_config)) { + DEBUG_INFO("ICEPick TAP %u: %06" PRIx32 "\n", tap, tap_config); + if (!icepick_write_reg(device, ICEPICK_ROUTING_DEBUG_TAP_BASE + tap, + tap_config | ICEPICK_ROUTING_DEBUG_TAP_POWER_LOST | ICEPICK_ROUTING_DEBUG_TAP_INHIBIT_SLEEP | + ICEPICK_ROUTING_DEBUG_TAP_RELEASE_WIR | ICEPICK_ROUTING_DEBUG_TAP_DEBUG_ENABLE | + ICEPICK_ROUTING_DEBUG_TAP_SELECT | ICEPICK_ROUTING_DEBUG_TAP_FORCE_ACTIVE)) + DEBUG_ERROR("ICEPick TAP %u write failed\n", tap); + } else + DEBUG_PROBE("ICEPick TAP %u read failed\n", tap); + } + + icepick_write_ir(device, IR_IDCODE); + + if (icepick_type == 'D') { + for (uint8_t core = 0; core < ICEPICK_ROUTING_CORE_COUNT; ++core) { + uint32_t core_config = 0U; + if (icepick_read_reg(device, ICEPICK_ROUTING_CORE_BASE + core, &core_config)) { + DEBUG_INFO("ICEPick core %u: %06" PRIx32 "\n", core, core_config); + if (!icepick_write_reg(device, ICEPICK_ROUTING_CORE_BASE + core, 0x00002008U)) + DEBUG_ERROR("ICEPick core %u write failed\n", core); + } else + DEBUG_PROBE("ICEPick core %u read failed\n", core); + } + } +} + +static void icepick_write_ir(jtag_dev_s *const device, const uint8_t ir) +{ + /* Set all the other devices IR's to being in bypass */ + for (size_t device_index = 0; device_index < jtag_dev_count; device_index++) + jtag_devs[device_index].current_ir = UINT32_MAX; + /* Put the current device IR into the requested state */ + device->current_ir = ir; + + /* Do the work to make the scanchain match the jtag_devs state */ + jtagtap_shift_ir(); + /* Once in Shift-IR, clock out 1's till we hit the right device in the chain */ + jtag_proc.jtagtap_tdi_seq(false, ones, device->ir_prescan); + /* Then clock out the new IR value and drop into Exit1-IR on the last cycle if we're the last device */ + jtag_proc.jtagtap_tdi_seq(!device->ir_postscan, &ir, device->ir_len); + /* Make sure we're in Exit1-IR having clocked out 1's for any more devices on the chain */ + jtag_proc.jtagtap_tdi_seq(true, ones, device->ir_postscan); + /* Now go to Update-IR but do not go back to Idle */ + jtagtap_return_idle(0); +} + +static uint32_t icepick_shift_dr(const jtag_dev_s *const device, const uint32_t data_in, const size_t clock_cycles) +{ + /* Prepare the data to send */ + uint8_t data[4]; + write_le4(data, 0, data_in); + /* Switch into Shift-DR */ + jtagtap_shift_dr(); + /* Now we're in Shift-DR, clock out 1's till we hit the right device in the chain */ + jtag_proc.jtagtap_tdi_seq(false, ones, device->dr_prescan); + /* Now clock out the new DR value and get the response */ + jtag_proc.jtagtap_tdi_tdo_seq(data, !device->dr_postscan, data, clock_cycles); + /* Make sure we're in Exit1-DR having clocked out 1's for any more devices on the chain */ + jtag_proc.jtagtap_tdi_seq(true, ones, device->dr_postscan); + /* Now go to Update-DR but do not go back to Idle */ + jtagtap_return_idle(0); + /* Extract the resulting data */ + return read_le4(data, 0); +} diff --git a/src/target/icepick.h b/src/target/icepick.h new file mode 100644 index 00000000000..8e50f67aa0c --- /dev/null +++ b/src/target/icepick.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2023 1BitSquared + * Written by Rachel Mant + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TARGET_ICEPICK_H +#define TARGET_ICEPICK_H + +#include + +void icepick_router_handler(uint8_t dev_index); + +#endif /* TARGET_ICEPICK_H */ diff --git a/src/target/jtag_devs.c b/src/target/jtag_devs.c index ecd6eca761a..b7067b90823 100644 --- a/src/target/jtag_devs.c +++ b/src/target/jtag_devs.c @@ -24,6 +24,7 @@ #include "jtag_scan.h" #include "adiv5.h" #include "riscv_debug.h" +#include "icepick.h" #include "jtag_devs.h" const jtag_dev_descr_s dev_descr[] = { @@ -414,13 +415,14 @@ const jtag_dev_descr_s dev_descr[] = { .handler = riscv_jtag_dtm_handler, }, #endif -#if defined(CONFIG_CORTEXAR) // && defined(ENABLE_SITARA) +#if defined(CONFIG_CORTEXAR) && defined(ENABLE_TI_SITARA) { .idcode = 0x0b90002fU, .idmask = 0x0ff00fffU, #if ENABLE_DEBUG == 1 .descr = "TI ICEPick.", #endif + .handler = icepick_router_handler, }, #endif #if ENABLE_DEBUG == 1 diff --git a/src/target/jtag_scan.c b/src/target/jtag_scan.c index 09cadba4807..8af28ec4651 100644 --- a/src/target/jtag_scan.c +++ b/src/target/jtag_scan.c @@ -76,12 +76,6 @@ void jtag_add_device(const uint32_t dev_index, const jtag_dev_s *jtag_dev) */ bool jtag_scan(void) { - /* Free the device list if any, and clean state ready */ - target_list_free(); - - jtag_dev_count = 0; - memset(&jtag_devs, 0, sizeof(jtag_devs)); - /* * Initialise the JTAG backend if it's not already * This will automatically do the SWD-to-JTAG sequence just in case we've got @@ -99,6 +93,17 @@ bool jtag_scan(void) /* Reset the chain ready */ jtag_proc.jtagtap_reset(); + return jtag_discover(); +} + +bool jtag_discover(void) +{ + /* Free the device list if any, and clean state ready */ + target_list_free(); + + jtag_dev_count = 0; + memset(&jtag_devs, 0, sizeof(jtag_devs)); + /* Start by reading out the ID Codes for all the devices on the chain */ if (!jtag_read_idcodes() || /* Otherwise, try and learn the chain IR lengths */ @@ -143,7 +148,8 @@ bool jtag_scan(void) #endif /* Check for known devices and handle accordingly */ - for (size_t device = 0; device < jtag_dev_count; device++) { + const size_t devices = jtag_dev_count; + for (size_t device = 0; device < devices; device++) { for (size_t descr = 0; dev_descr[descr].idcode; descr++) { if ((jtag_devs[device].jd_idcode & dev_descr[descr].idmask) == dev_descr[descr].idcode) { /* Call handler to initialise/probe device further */ @@ -154,7 +160,7 @@ bool jtag_scan(void) } } - return jtag_dev_count > 0; + return devices > 0; } static bool jtag_read_idcodes(void) @@ -210,7 +216,14 @@ static void jtag_display_idcodes(void) break; } } - DEBUG_INFO("ID code 0x%08" PRIx32 ": %s\n", jtag_devs[device].jd_idcode, description); + DEBUG_INFO("ID code 0x%08" PRIx32 ": %-20s | drpre: %d drpost: %d irpre: %d irpost: %d irlen: %d\n", + jtag_devs[device].jd_idcode, description, + jtag_devs[device].dr_prescan, + jtag_devs[device].dr_postscan, + jtag_devs[device].ir_prescan, + jtag_devs[device].ir_postscan, + jtag_devs[device].ir_len + ); } #endif } diff --git a/src/target/meson.build b/src/target/meson.build index 4d37805121b..eb1cd900045 100644 --- a/src/target/meson.build +++ b/src/target/meson.build @@ -357,7 +357,7 @@ target_at32f4 = declare_dependency( dependencies: [target_cortexm, target_stm_common] ) -target_ti = declare_dependency( +target_ti_cortexm = declare_dependency( sources: files( 'lmi.c', 'msp432e4.c', @@ -368,6 +368,35 @@ target_ti = declare_dependency( dependencies: target_cortexm, ) +target_ti_cortexa = declare_dependency( + sources: files( + 'am335x.c', + 'icepick.c' + ), + dependencies: target_cortexar, + compile_args: ['-DENABLE_TI_SITARA=1'], +) + +target_ti_cortexr = declare_dependency( + sources: files( + 'ti_tms570.c', + 'icepick.c' + ), + dependencies: target_cortexar, + compile_args: ['-DENABLE_TI_TMS570=1'], +) + +# If the Cortex-A/R target is not enabled, don't enable TI AM335x part support +if not is_firmware_build or enabled_targets.contains('cortexar') + target_ti = [ + target_ti_cortexm, + target_ti_cortexa, + target_ti_cortexr, + ] +else + target_ti = target_ti_cortexm +endif + target_xilinx = declare_dependency( sources: files( 'zynq7000.c', @@ -433,7 +462,9 @@ libbmd_target_deps = [ target_rp, target_sam, target_stm, - target_ti, + target_ti_cortexa, + target_ti_cortexm, + target_ti_cortexr, target_xilinx, ] diff --git a/src/target/samx5x.c b/src/target/samx5x.c index e36c08cf86a..26c5233921e 100644 --- a/src/target/samx5x.c +++ b/src/target/samx5x.c @@ -890,7 +890,7 @@ static bool samx5x_cmd_update_user_word(target_s *t, int argc, const char **argv static uint32_t samx5x_ram_size(target_s *t) { /* Read the Device ID */ - const uint32_t did = target_mem_read32(t, SAMX5X_DSU_DID); + const uint32_t did = target_mem32_read32(t, SAMX5X_DSU_DID); /* Mask off the device select bits */ const samx5x_descr_s samx5x = samx5x_parse_device_id(did); /* Adjust the maximum ram size (256KB) down as appropriate */ @@ -926,7 +926,7 @@ static bool samx5x_cmd_mbist(target_s *t, int argc, const char **argv) /* Poll for DSU Ready */ uint32_t status = 0; while ((status & (SAMX5X_STATUSA_DONE | SAMX5X_STATUSA_PERR | SAMX5X_STATUSA_FAIL)) == 0U) { - status = target_mem_read32(t, SAMX5X_DSU_CTRLSTAT); + status = target_mem32_read32(t, SAMX5X_DSU_CTRLSTAT); if (target_check_error(t)) return false; } @@ -939,8 +939,8 @@ static bool samx5x_cmd_mbist(target_s *t, int argc, const char **argv) /* Test the fail bit in Status A */ if (status & SAMX5X_STATUSA_FAIL) { - const uint32_t data = target_mem_read32(t, SAMX5X_DSU_DATA); - tc_printf(t, "MBIST Fail @ 0x%08" PRIx32 " (bit %u in phase %u)\n", target_mem_read32(t, SAMX5X_DSU_ADDRESS), + const uint32_t data = target_mem32_read32(t, SAMX5X_DSU_DATA); + tc_printf(t, "MBIST Fail @ 0x%08" PRIx32 " (bit %u in phase %u)\n", target_mem32_read32(t, SAMX5X_DSU_ADDRESS), data & 0x1fU, data >> 8U); } else tc_printf(t, "MBIST Passed!\n"); diff --git a/src/target/target.c b/src/target/target.c index b358f8d7090..6b8449aeecc 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -312,12 +312,23 @@ bool target_check_error(target_s *target) return false; } +bool skip_swap = false; + /* Memory access functions */ bool target_mem32_read(target_s *const target, void *const dest, const target_addr_t src, const size_t len) { return target_mem64_read(target, dest, src, len); } +/* Memory access functions */ +bool target_mem32_read_unswapped(target_s *const target, void *const dest, const target_addr_t src, const size_t len) +{ + skip_swap = true; + bool val = target_mem64_read(target, dest, src, len); + skip_swap = false; + return val; +} + bool target_mem64_read(target_s *const target, void *const dest, const target_addr64_t src, const size_t len) { /* If we're processing a semihosting syscall and it needs IO redirected, handle that instead */ @@ -339,6 +350,14 @@ bool target_mem32_write(target_s *const target, const target_addr_t dest, const return target_mem64_write(target, dest, src, len); } +bool target_mem32_write_unswapped(target_s *const target, const target_addr_t dest, const void *const src, const size_t len) +{ + skip_swap = true; + bool val = target_mem64_write(target, dest, src, len); + skip_swap = false; + return val; +} + bool target_mem64_write(target_s *const target, const target_addr64_t dest, const void *const src, const size_t len) { /* If we're processing a semihosting syscall and it needs IO redirected, handle that instead */ @@ -406,7 +425,6 @@ void target_reset(target_s *target) void target_halt_request(target_s *target) { - DEBUG_TARGET("Halting target\n"); if (target->halt_request) target->halt_request(target); } @@ -439,10 +457,10 @@ target_halt_reason_e target_halt_poll(target_s *target, target_addr64_t *watch) { if (target->halt_poll) { const target_halt_reason_e reason = target->halt_poll(target, watch); -#ifndef DEBUG_TARGET_IS_NOOP - if (reason != TARGET_HALT_RUNNING) - DEBUG_TARGET("Target halted: %s\n", target_halt_reason_str(reason)); -#endif +// #ifndef DEBUG_TARGET_IS_NOOP +// if (reason != TARGET_HALT_RUNNING) +// DEBUG_TARGET("Target halted: %s\n", target_halt_reason_str(reason)); +// #endif return reason; } /* XXX: Is this actually the desired fallback behaviour? */ @@ -451,7 +469,7 @@ target_halt_reason_e target_halt_poll(target_s *target, target_addr64_t *watch) void target_halt_resume(target_s *target, bool step) { - DEBUG_TARGET("%s target\n", step ? "Single stepping" : "Resuming"); + // DEBUG_TARGET("%s target\n", step ? "Single stepping" : "Resuming"); if (target->halt_resume) target->halt_resume(target, step); } diff --git a/src/target/target_internal.h b/src/target/target_internal.h index f93238e2a75..2a96b37d943 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -168,6 +168,7 @@ struct target { union { bool unsafe_enabled; bool ke04_mode; + bool tms570_flash_initialized; }; bool attached; diff --git a/src/target/target_probe.c b/src/target/target_probe.c index 0171dccb644..3993647f8a7 100644 --- a/src/target/target_probe.c +++ b/src/target/target_probe.c @@ -103,6 +103,7 @@ CORTEXM_PROBE_WEAK_NOP(nrf51_ctrl_ap_probe) CORTEXM_PROBE_WEAK_NOP(nrf54l_ctrl_ap_probe) CORTEXM_PROBE_WEAK_NOP(rp2040_rescue_probe) +TARGET_PROBE_WEAK_NOP(am335x_cm3_probe) TARGET_PROBE_WEAK_NOP(apollo_3_probe) TARGET_PROBE_WEAK_NOP(at32f40x_probe) TARGET_PROBE_WEAK_NOP(at32f43x_probe) @@ -156,6 +157,7 @@ TARGET_PROBE_WEAK_NOP(stm32l4_probe) TARGET_PROBE_WEAK_NOP(stm32mp15_ca7_probe) TARGET_PROBE_WEAK_NOP(stm32mp15_cm4_probe) TARGET_PROBE_WEAK_NOP(stm32wb0_probe) +TARGET_PROBE_WEAK_NOP(ti_tms570_probe) TARGET_PROBE_WEAK_NOP(zynq7_probe) LPC55_DP_PREPARE_WEAK_NOP(lpc55_dp_prepare) diff --git a/src/target/target_probe.h b/src/target/target_probe.h index 9c906cb3ef0..9703fb607f6 100644 --- a/src/target/target_probe.h +++ b/src/target/target_probe.h @@ -54,6 +54,7 @@ bool nrf51_ctrl_ap_probe(adiv5_access_port_s *ap); bool nrf54l_ctrl_ap_probe(adiv5_access_port_s *ap); bool rp2040_rescue_probe(adiv5_access_port_s *ap); +bool am335x_cm3_probe(target_s *target); bool at32f40x_probe(target_s *target); // STM32 clones from Artery bool apollo_3_probe(target_s *target); bool at32f43x_probe(target_s *target); @@ -107,6 +108,7 @@ bool stm32l4_probe(target_s *target); bool stm32mp15_ca7_probe(target_s *target); bool stm32mp15_cm4_probe(target_s *target); bool stm32wb0_probe(target_s *target); +bool ti_tms570_probe(target_s *target); bool zynq7_probe(target_s *target); void lpc55_dp_prepare(adiv5_debug_port_s *dp); diff --git a/src/target/ti_tms570.c b/src/target/ti_tms570.c new file mode 100644 index 00000000000..7343cf1e811 --- /dev/null +++ b/src/target/ti_tms570.c @@ -0,0 +1,64 @@ +#include "general.h" +#include "target.h" +#include "target_internal.h" +#include "cortexar.h" +#include "buffer_utils.h" + +#define TMS570_SYS_BASE 0xFFFFFF00U +#define TMS570_SYS_DEVID (TMS570_SYS_BASE + 0xF0U) +#define TMS570_SCM_DEVID_ID_MASK 0x0700FE7FU /* Note: value is swapped since target is BE */ +#define TMS570_SCM_REVID_ID_TMS570 0x05004400U /* Note: value is swapped since target is BE */ + +#define TMS570_OTP_BANK0_MEMORY_INFORMATION 0xF008015CU +#define TMS570_OTP_BANK0_MEMORY_SIZE_MASK 0xFFFFU + +/* Base address for the OCRAM regions, including their mirrors (including RETRAM) */ +#define TMS570_SRAM_BASE 0x08000000U +#define TMS570_SRAM_ECC_BASE 0x08400000U +#define TMS570_SRAM_SIZE 0x80000U + +#define TMS570_FLASH_BASE_ADDR 0x00000000U +#define TMS570_FLASH_SECTOR_ADDR (TMS570_L2FMC_BASE_ADDR + 0x408U) +#define TMS570_FLASH_SECTOR_SIZE + +#define TMS570_L2FMC_BASE_ADDR 0xFFF87000U +#define TMS570_L2FMC_FSPRD_ADDR (TMS570_FLASH_BASE_ADDR + 0x4U) +#define TMS570_L2FMC_FMAC_ADDR (TMS570_FLASH_BASE_ADDR + 0x50U) +#define TMS570_L2FMC_FLOCK_ADDR (TMS570_FLASH_BASE_ADDR + 0x64U) /* Undocumented */ +#define TMS570_L2FMC_FVREADCT_ADDR (TMS570_FLASH_BASE_ADDR + 0x80U) /* Undocumented */ +#define TMS570_L2FMC_FVNVCT_ADDR (TMS570_FLASH_BASE_ADDR + 0x8CU) /* Undocumented */ +#define TMS570_L2FMC_FVPPCT_ADDR (TMS570_FLASH_BASE_ADDR + 0x90U) /* Undocumented */ +#define TMS570_L2FMC_FVWLCT_ADDR (TMS570_FLASH_BASE_ADDR + 0x94U) /* Undocumented */ +#define TMS570_L2FMC_FEFUSE_ADDR (TMS570_FLASH_BASE_ADDR + 0x98U) /* Undocumented */ +#define TMS570_L2FMC_FBSTROBES_ADDR (TMS570_FLASH_BASE_ADDR + 0x100U) /* Undocumented */ +#define TMS570_L2FMC_FPSTROBES_ADDR (TMS570_FLASH_BASE_ADDR + 0x104U) /* Undocumented */ +#define TMS570_L2FMC_FBMODE_ADDR (TMS570_FLASH_BASE_ADDR + 0x108U) /* Undocumented */ +#define TMS570_L2FMC_FTCR_ADDR (TMS570_FLASH_BASE_ADDR + 0x10CU) /* Undocumented */ +#define TMS570_L2FMC_FSM_WR_ENA_ADDR (TMS570_FLASH_BASE_ADDR + 0x288U) + +#define TMS570_OTP_PACKAGE_AND_FLASH_MEMORY_SIZE 0xf008015cU + +#define TMS570_OTP_BANK0_BASE 0xF0080000U +#define TMS570_FLASH_OTP_BASE (TMS570_OTP_BANK0_BASE + 0x170) + +/* + * Flash functions + */ + +bool ti_tms570_probe(target_s *const target) +{ + const uint32_t part_id = target_mem32_read32(target, TMS570_SYS_DEVID); + if (!part_id || ((part_id & TMS570_SCM_DEVID_ID_MASK) != TMS570_SCM_REVID_ID_TMS570)) { + DEBUG_ERROR("Part ID 0x%08" PRIx32 " was unrecognized\n", part_id); + return false; + } + + target->driver = "TMS570"; + target_add_ram32(target, TMS570_SRAM_BASE, TMS570_SRAM_SIZE); + target_add_ram32(target, TMS570_SRAM_ECC_BASE, TMS570_SRAM_SIZE); + + // Avoid toggling NRST, which will reset the icepick. + target->target_options |= TOPT_INHIBIT_NRST; + + return true; +}