static int or1k_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { struct timeval timeout, now; struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); int retval = ERROR_OK; gettimeofday(&timeout, NULL); timeval_add_time(&timeout, seconds, 0); LOG_INFO("Starting or1k profiling. Sampling npc as fast as we can..."); /* 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 (;;) { uint32_t reg_value; retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, GROUP0 + 16 /* NPC */, 1, ®_value); if (retval != ERROR_OK) { LOG_ERROR("Error while reading NPC"); return retval; } samples[sample_count++] = reg_value; gettimeofday(&now, NULL); if ((sample_count >= max_num_samples) || ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) { LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); break; } } *num_samples = sample_count; return retval; }
static int xtensa_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { int res; int icountLevel = 1; int originalIntenable = 0; uint32_t dosr; struct xtensa_common *xtensa = target_to_xtensa(target); static const uint32_t icount_val = -2; /* ICOUNT value to load for 1 step */ if (target->state != TARGET_HALTED) { LOG_WARNING("%s: target not halted", __func__); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("%s current=%d address=%"PRIx32, __func__, current, address); /* Load debug level into ICOUNTLEVEL Originally had DEBUGLEVEL (ie 2) set here, not 1, but seemed to result in occasionally stepping out into inaccessible bits of ROM (low level interrupt handlers?) and never quite recovering... One loop started at 0x40000050. Re-attaching with ICOUNTLEVEL 1 caused this to immediately step into an interrupt handler. ICOUNTLEVEL 1 still steps into interrupt handlers, but also seems to recover. TODO: Experiment more, look into CPU exception nuances, consider making this step level a configuration command. */ res = xtensa_read_register(target, XT_REG_IDX_PS, 0); if (res == ERROR_OK) { int psValue = buf_get_u32(xtensa->core_cache->reg_list[XT_REG_IDX_PS].value, 0, 8); if (psValue & 0x10) { //We are executing code in the exception mode. Setting ICOUNTLEVEL to 1 would step into the first instruction that gets executed after the exception handler is done. //What we actually want is to step into the next instruction of the code we are debugging (i.e. an exception handler). Hence we ned to set ICOUNTLEVEL to 2 in order to count exception mode instructions as well. icountLevel = 2; } } if (s_DisableInterruptsForStepping) { res = xtensa_read_register(target, XT_REG_IDX_INTENABLE, 0); if (res != ERROR_OK) LOG_ERROR("%s: Failed to read the INTENABLE register during single step", __func__); else { originalIntenable = buf_get_u32(xtensa->core_cache->reg_list[XT_REG_IDX_INTENABLE].value, 0, 32); if (originalIntenable) { buf_set_u32(xtensa->core_cache->reg_list[XT_REG_IDX_INTENABLE].value, 0, 32, 0); xtensa->core_cache->reg_list[XT_REG_IDX_INTENABLE].dirty = 1; } } } res = xtensa_tap_queue_write_sr(target, XT_REG_IDX_ICOUNTLEVEL, icountLevel); if(res != ERROR_OK) return res; /* load ICOUNT step count value */ res = xtensa_tap_queue_write_sr(target, XT_REG_IDX_ICOUNT, icount_val); if(res != ERROR_OK) return res; res = xtensa_tap_queue_cpu_inst(target, XT_INS_ISYNC); if (res != ERROR_OK) return res; res = xtensa_tap_queue_cpu_inst(target, XT_INS_ISYNC); if (res != ERROR_OK) return res; res = jtag_execute_queue(); if(res != ERROR_OK) return res; /* Wait for everything to settle, seems necessary to avoid bad resumes */ do { res = xtensa_tap_exec(target, TAP_INS_READ_DOSR, 0, &dosr); if(res != ERROR_OK) { LOG_ERROR("Failed to read DOSR. Not Xtensa OCD?"); return ERROR_FAIL; } } while(!(dosr & DOSR_IN_OCD_MODE) || (dosr & DOSR_EXCEPTION)); /* Now ICOUNT is set, we can resume as if we were going to run */ res = xtensa_resume(target, current, address, 0, 0); if(res != ERROR_OK) { LOG_ERROR("%s: Failed to resume after setting up single step", __func__); return res; } /* Wait for stepping to complete */ int64_t start = timeval_ms(); while(target->state != TARGET_HALTED && timeval_ms() < start+500) { res = target_poll(target); if(res != ERROR_OK) return res; if(target->state != TARGET_HALTED) usleep(50000); } if(target->state != TARGET_HALTED) { xtensa_halt(target); LOG_ERROR("%s: Timed out waiting for target to finish stepping.", __func__); return ERROR_TARGET_TIMEOUT; } if (originalIntenable) { buf_set_u32(xtensa->core_cache->reg_list[XT_REG_IDX_INTENABLE].value, 0, 32, originalIntenable); xtensa->core_cache->reg_list[XT_REG_IDX_INTENABLE].dirty = 1; } /* write ICOUNTLEVEL back to zero */ res = xtensa_tap_queue_write_sr(target, XT_REG_IDX_ICOUNTLEVEL, 0); if(res != ERROR_OK) return res; res = jtag_execute_queue(); return res; }