* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* *
* Cortex-M3(tm) TRM, ARM DDI 0337E (r1p1) and 0337G (r2p0) *
{
struct cortex_m_common *cortex_m = target_to_cm(target);
struct armv7m_common *armv7m = &cortex_m->armv7m;
- uint32_t dhcsr_save;
int retval;
- /* backup dhcsr reg */
- dhcsr_save = cortex_m->dcb_dhcsr;
-
/* Mask interrupts before clearing halt, if done already. This avoids
* Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing
* HALT can put the core into an unknown state.
LOG_DEBUG(" ");
/* restore dhcsr reg */
- cortex_m->dcb_dhcsr = dhcsr_save;
cortex_m_clear_halt(target);
return ERROR_OK;
if (retval != ERROR_OK)
return retval;
if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) {
- retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_DEBUGEN);
+ retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS);
if (retval != ERROR_OK)
return retval;
}
}
static int cortex_m_resume(struct target *target, int current,
- uint32_t address, int handle_breakpoints, int debug_execution)
+ target_addr_t address, int handle_breakpoints, int debug_execution)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
struct breakpoint *breakpoint = NULL;
/* Single step past breakpoint at current address */
breakpoint = breakpoint_find(target, resume_pc);
if (breakpoint) {
- LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %" PRIu32 ")",
+ LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")",
breakpoint->address,
breakpoint->unique_id);
cortex_m_unset_breakpoint(target, breakpoint);
/* int irqstepcount = 0; */
static int cortex_m_step(struct target *target, int current,
- uint32_t address, int handle_breakpoints)
+ target_addr_t address, int handle_breakpoints)
{
struct cortex_m_common *cortex_m = target_to_cm(target);
struct armv7m_common *armv7m = &cortex_m->armv7m;
bool srst_asserted = false;
+ if (!target_was_examined(target)) {
+ if (jtag_reset_config & RESET_HAS_SRST) {
+ adapter_assert_reset();
+ if (target->reset_halt)
+ LOG_ERROR("Target not examined, will not halt after reset!");
+ return ERROR_OK;
+ } else {
+ LOG_ERROR("Target not examined, reset NOT asserted!");
+ return ERROR_FAIL;
+ }
+ }
+
if ((jtag_reset_config & RESET_HAS_SRST) &&
(jtag_reset_config & RESET_SRST_NO_GATING)) {
adapter_assert_reset();
/* Enable debug requests */
int retval;
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
- if (retval != ERROR_OK)
- return retval;
- if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) {
- retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_DEBUGEN);
- if (retval != ERROR_OK)
- return retval;
- }
+ /* Store important errors instead of failing and proceed to reset assert */
+
+ if (retval != ERROR_OK || !(cortex_m->dcb_dhcsr & C_DEBUGEN))
+ retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS);
/* If the processor is sleeping in a WFI or WFE instruction, the
* C_HALT bit must be asserted to regain control */
- if (cortex_m->dcb_dhcsr & S_SLEEP) {
- retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN);
- if (retval != ERROR_OK)
- return retval;
- }
+ if (retval == ERROR_OK && (cortex_m->dcb_dhcsr & S_SLEEP))
+ retval = cortex_m_write_debug_halt_mask(target, C_HALT, 0);
- retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0);
- if (retval != ERROR_OK)
- return retval;
+ mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0);
+ /* Ignore less important errors */
if (!target->reset_halt) {
/* Set/Clear C_MASKINTS in a separate operation */
- if (cortex_m->dcb_dhcsr & C_MASKINTS) {
- retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR,
- DBGKEY | C_DEBUGEN | C_HALT);
- if (retval != ERROR_OK)
- return retval;
- }
+ if (cortex_m->dcb_dhcsr & C_MASKINTS)
+ cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS);
/* clear any debug flags before resuming */
cortex_m_clear_halt(target);
* bad vector table entries. Should this include MMERR or
* other flags too?
*/
- retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DEMCR,
+ int retval2;
+ retval2 = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DEMCR,
TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
- if (retval != ERROR_OK)
- return retval;
+ if (retval != ERROR_OK || retval2 != ERROR_OK)
+ LOG_INFO("AP write error, reset will not halt");
}
if (jtag_reset_config & RESET_HAS_SRST) {
/* default to asserting srst */
if (!srst_asserted)
adapter_assert_reset();
+
+ /* srst is asserted, ignore AP access errors */
+ retval = ERROR_OK;
} else {
/* Use a standard Cortex-M3 software reset mechanism.
* We default to using VECRESET as it is supported on all current cores.
"handler to reset any peripherals or configure hardware srst support.");
}
- retval = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_AIRCR,
+ int retval3;
+ retval3 = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_AIRCR,
AIRCR_VECTKEY | ((reset_config == CORTEX_M_RESET_SYSRESETREQ)
? AIRCR_SYSRESETREQ : AIRCR_VECTRESET));
- if (retval != ERROR_OK)
+ if (retval3 != ERROR_OK)
LOG_DEBUG("Ignoring AP write error right after reset");
- retval = dap_dp_init(armv7m->debug_ap->dap);
- if (retval != ERROR_OK) {
+ retval3 = dap_dp_init(armv7m->debug_ap->dap);
+ if (retval3 != ERROR_OK)
LOG_ERROR("DP initialisation failed");
- return retval;
- }
- {
+ else {
/* I do not know why this is necessary, but it
* fixes strange effects (step/resume cause NMI
* after reset) on LM3S6918 -- Michael Schwingen
*/
uint32_t tmp;
- retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_AIRCR, &tmp);
- if (retval != ERROR_OK)
- return retval;
+ mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_AIRCR, &tmp);
}
}
register_cache_invalidate(cortex_m->armv7m.arm.core_cache);
+ /* now return stored error code if any */
+ if (retval != ERROR_OK)
+ return retval;
+
if (target->reset_halt) {
retval = target_halt(target);
if (retval != ERROR_OK)
enum reset_types jtag_reset_config = jtag_get_reset_config();
if ((jtag_reset_config & RESET_HAS_SRST) &&
- !(jtag_reset_config & RESET_SRST_NO_GATING)) {
+ !(jtag_reset_config & RESET_SRST_NO_GATING) &&
+ target_was_examined(target)) {
int retval = dap_dp_init(armv7m->debug_ap->dap);
if (retval != ERROR_OK) {
LOG_ERROR("DP initialisation failed");
breakpoint->set = true;
}
- LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)",
+ LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)",
breakpoint->unique_id,
(int)(breakpoint->type),
breakpoint->address,
return ERROR_OK;
}
- LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)",
+ LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)",
breakpoint->unique_id,
(int)(breakpoint->type),
breakpoint->address,
return ERROR_OK;
}
-static int cortex_m_read_memory(struct target *target, uint32_t address,
+static int cortex_m_read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
return mem_ap_read_buf(armv7m->debug_ap, buffer, size, count, address);
}
-static int cortex_m_write_memory(struct target *target, uint32_t address,
+static int cortex_m_write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
struct target *target)
{
armv7m_build_reg_cache(target);
+ arm_semihosting_init(target);
return ERROR_OK;
}
cortex_m_dwt_free(target);
armv7m_free_reg_cache(target);
+ free(target->private_config);
free(cortex_m);
}
+int cortex_m_profiling(struct target *target, uint32_t *samples,
+ uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
+{
+ struct timeval timeout, now;
+ struct armv7m_common *armv7m = target_to_armv7m(target);
+ uint32_t reg_value;
+ bool use_pcsr = false;
+ int retval = ERROR_OK;
+ struct reg *reg;
+
+ gettimeofday(&timeout, NULL);
+ timeval_add_time(&timeout, seconds, 0);
+
+ retval = target_read_u32(target, DWT_PCSR, ®_value);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while reading PCSR");
+ return retval;
+ }
+
+ if (reg_value != 0) {
+ use_pcsr = true;
+ LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can...");
+ } else {
+ LOG_INFO("Starting profiling. Halting and resuming the"
+ " target as often as we can...");
+ reg = register_get_by_name(target->reg_cache, "pc", 1);
+ }
+
+ /* Make sure the target is running */
+ target_poll(target);
+ if (target->state == TARGET_HALTED)
+ retval = target_resume(target, 1, 0, 0, 0);
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while resuming target");
+ return retval;
+ }
+
+ uint32_t sample_count = 0;
+
+ for (;;) {
+ if (use_pcsr) {
+ if (armv7m && armv7m->debug_ap) {
+ uint32_t read_count = max_num_samples - sample_count;
+ if (read_count > 1024)
+ read_count = 1024;
+
+ retval = mem_ap_read_buf_noincr(armv7m->debug_ap,
+ (void *)&samples[sample_count],
+ 4, read_count, DWT_PCSR);
+ sample_count += read_count;
+ } else {
+ target_read_u32(target, DWT_PCSR, &samples[sample_count++]);
+ }
+ } else {
+ target_poll(target);
+ if (target->state == TARGET_HALTED) {
+ reg_value = buf_get_u32(reg->value, 0, 32);
+ /* current pc, addr = 0, do not handle breakpoints, not debugging */
+ retval = target_resume(target, 1, 0, 0, 0);
+ samples[sample_count++] = reg_value;
+ target_poll(target);
+ alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */
+ } else if (target->state == TARGET_RUNNING) {
+ /* We want to quickly sample the PC. */
+ retval = target_halt(target);
+ } else {
+ LOG_INFO("Target not halted or running");
+ retval = ERROR_OK;
+ break;
+ }
+ }
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while reading %s", use_pcsr ? "PCSR" : "target pc");
+ return retval;
+ }
+
+
+ gettimeofday(&now, NULL);
+ if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) {
+ LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
+ break;
+ }
+ }
+
+ *num_samples = sample_count;
+ return retval;
+}
+
+
/* REVISIT cache valid/dirty bits are unmaintained. We could set "valid"
* on r/w if the core is not running, and clear on resume or reset ... or
* at least, in a post_restore_context() method.
DWT_COMPARATOR(1),
DWT_COMPARATOR(2),
DWT_COMPARATOR(3),
+ DWT_COMPARATOR(4),
+ DWT_COMPARATOR(5),
+ DWT_COMPARATOR(6),
+ DWT_COMPARATOR(7),
+ DWT_COMPARATOR(8),
+ DWT_COMPARATOR(9),
+ DWT_COMPARATOR(10),
+ DWT_COMPARATOR(11),
+ DWT_COMPARATOR(12),
+ DWT_COMPARATOR(13),
+ DWT_COMPARATOR(14),
+ DWT_COMPARATOR(15),
#undef DWT_COMPARATOR
};
int reg, i;
target_read_u32(target, DWT_CTRL, &dwtcr);
+ LOG_DEBUG("DWT_CTRL: 0x%" PRIx32, dwtcr);
if (!dwtcr) {
LOG_DEBUG("no DWT");
return;
#define MVFR0_DEFAULT_M4 0x10110021
#define MVFR1_DEFAULT_M4 0x11000011
+#define MVFR0_DEFAULT_M7_SP 0x10110021
+#define MVFR0_DEFAULT_M7_DP 0x10110221
+#define MVFR1_DEFAULT_M7_SP 0x11000011
+#define MVFR1_DEFAULT_M7_DP 0x12000011
+
int cortex_m_examine(struct target *target)
{
int retval;
struct adiv5_dap *swjdp = cortex_m->armv7m.arm.dap;
struct armv7m_common *armv7m = target_to_armv7m(target);
- retval = dap_dp_init(swjdp);
- if (retval != ERROR_OK) {
- LOG_ERROR("Could not initialize the debug port");
- return retval;
- }
-
- /* Search for the MEM-AP */
- retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7m->debug_ap);
- if (retval != ERROR_OK) {
- LOG_ERROR("Could not find MEM-AP to control the core");
- return retval;
- }
-
- /* Leave (only) generic DAP stuff for debugport_init(); */
- armv7m->debug_ap->memaccess_tck = 8;
-
/* stlink shares the examine handler but does not support
* all its calls */
if (!armv7m->stlink) {
+ if (cortex_m->apsel < 0) {
+ /* Search for the MEM-AP */
+ retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7m->debug_ap);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not find MEM-AP to control the core");
+ return retval;
+ }
+ } else {
+ armv7m->debug_ap = dap_ap(swjdp, cortex_m->apsel);
+ }
+
+ /* Leave (only) generic DAP stuff for debugport_init(); */
+ armv7m->debug_ap->memaccess_tck = 8;
+
retval = mem_ap_init(armv7m->debug_ap);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("Cortex-M%d r%" PRId8 "p%" PRId8 " processor detected",
i, (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf));
+ if (i == 7) {
+ uint8_t rev, patch;
+ rev = (cpuid >> 20) & 0xf;
+ patch = (cpuid >> 0) & 0xf;
+ if ((rev == 0) && (patch < 2))
+ LOG_WARNING("Silicon bug: single stepping will enter pending exception handler!");
+ }
LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid);
- /* test for floating point feature on cortex-m4 */
if (i == 4) {
target_read_u32(target, MVFR0, &mvfr0);
target_read_u32(target, MVFR1, &mvfr1);
+ /* test for floating point feature on Cortex-M4 */
if ((mvfr0 == MVFR0_DEFAULT_M4) && (mvfr1 == MVFR1_DEFAULT_M4)) {
LOG_DEBUG("Cortex-M%d floating point feature FPv4_SP found", i);
armv7m->fp_feature = FPv4_SP;
}
+ } else if (i == 7) {
+ target_read_u32(target, MVFR0, &mvfr0);
+ target_read_u32(target, MVFR1, &mvfr1);
+
+ /* test for floating point features on Cortex-M7 */
+ if ((mvfr0 == MVFR0_DEFAULT_M7_SP) && (mvfr1 == MVFR1_DEFAULT_M7_SP)) {
+ LOG_DEBUG("Cortex-M%d floating point feature FPv5_SP found", i);
+ armv7m->fp_feature = FPv5_SP;
+ } else if ((mvfr0 == MVFR0_DEFAULT_M7_DP) && (mvfr1 == MVFR1_DEFAULT_M7_DP)) {
+ LOG_DEBUG("Cortex-M%d floating point feature FPv5_DP found", i);
+ armv7m->fp_feature = FPv5_DP;
+ }
} else if (i == 0) {
/* Cortex-M0 does not support unaligned memory access */
armv7m->arm.is_armv6m = true;
}
- if (armv7m->fp_feature != FPv4_SP &&
+ if (armv7m->fp_feature == FP_NONE &&
armv7m->arm.core_cache->num_regs > ARMV7M_NUM_CORE_REGS_NOFP) {
/* free unavailable FPU registers */
size_t idx;
armv7m->arm.core_cache->num_regs = ARMV7M_NUM_CORE_REGS_NOFP;
}
- if (i == 4 || i == 3) {
- /* Cortex-M3/M4 has 4096 bytes autoincrement range */
- armv7m->debug_ap->tar_autoincr_block = (1 << 12);
+ if (!armv7m->stlink) {
+ if (i == 3 || i == 4)
+ /* Cortex-M3/M4 have 4096 bytes autoincrement range,
+ * s. ARM IHI 0031C: MEM-AP 7.2.2 */
+ armv7m->debug_ap->tar_autoincr_block = (1 << 12);
+ else if (i == 7)
+ /* Cortex-M7 has only 1024 bytes autoincrement range */
+ armv7m->debug_ap->tar_autoincr_block = (1 << 10);
}
/* Configure trace modules */
}
static int cortex_m_init_arch_info(struct target *target,
- struct cortex_m_common *cortex_m, struct jtag_tap *tap)
+ struct cortex_m_common *cortex_m, struct adiv5_dap *dap)
{
struct armv7m_common *armv7m = &cortex_m->armv7m;
armv7m_init_arch_info(target, armv7m);
- /* tap has no dap initialized */
- if (!tap->dap) {
- tap->dap = dap_init();
-
- /* Leave (only) generic DAP stuff for debugport_init() */
- tap->dap->tap = tap;
- }
-
/* default reset mode is to use srst if fitted
* if not it will use CORTEX_M3_RESET_VECTRESET */
cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET;
- armv7m->arm.dap = tap->dap;
-
- /* Leave (only) generic DAP stuff for debugport_init(); */
- tap->dap->ap[dap_ap_get_select(tap->dap)].memaccess_tck = 8;
+ armv7m->arm.dap = dap;
/* register arch-specific functions */
armv7m->examine_debug_reason = cortex_m_examine_debug_reason;
static int cortex_m_target_create(struct target *target, Jim_Interp *interp)
{
struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common));
-
cortex_m->common_magic = CORTEX_M_COMMON_MAGIC;
- cortex_m_init_arch_info(target, cortex_m, target->tap);
+ struct adiv5_private_config *pc;
+
+ pc = (struct adiv5_private_config *)target->private_config;
+ if (adiv5_verify_config(pc) != ERROR_OK)
+ return ERROR_FAIL;
+
+ cortex_m->apsel = pc->ap_num;
+
+ cortex_m_init_arch_info(target, cortex_m, pc->dap);
return ERROR_OK;
}
.commands = cortex_m_command_handlers,
.target_create = cortex_m_target_create,
+ .target_jim_configure = adiv5_jim_configure,
.init_target = cortex_m_init_target,
.examine = cortex_m_examine,
.deinit_target = cortex_m_deinit_target,
+
+ .profiling = cortex_m_profiling,
};