bool arm11_config_memwrite_burst = true;
bool arm11_config_memwrite_error_fatal = true;
uint32_t arm11_vcr = 0;
-bool arm11_config_memrw_no_increment = false;
bool arm11_config_step_irq_enable = false;
bool arm11_config_hardware_step = false;
#define ARM11_HANDLER(x) \
.x = arm11_##x
+
+static int arm11_mrc(target_t *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value);
+static int arm11_mcr(target_t *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value);
+
target_type_t arm11_target =
{
.name = "arm11",
ARM11_HANDLER(target_create),
ARM11_HANDLER(init_target),
ARM11_HANDLER(examine),
- ARM11_HANDLER(quit),
+ .mrc = arm11_mrc,
+ .mcr = arm11_mcr,
+
};
int arm11_regs_arch_type = -1;
}
#endif
- arm11_run_instr_data_prepare(arm11);
+ retval = arm11_run_instr_data_prepare(arm11);
+ if (retval != ERROR_OK)
+ return retval;
/* save r0 - r14 */
if (R(DSCR) & ARM11_DSCR_RDTR_FULL)
{
/* MRC p14,0,R0,c0,c5,0 (move rDTR -> r0 (-> wDTR -> local var)) */
- arm11_run_instr_data_from_core_via_r0(arm11, 0xEE100E15, &R(RDTR));
+ retval = arm11_run_instr_data_from_core_via_r0(arm11, 0xEE100E15, &R(RDTR));
+ if (retval != ERROR_OK)
+ return retval;
}
else
{
/* save CPSR */
/* MRS r0,CPSR (move CPSR -> r0 (-> wDTR -> local var)) */
- arm11_run_instr_data_from_core_via_r0(arm11, 0xE10F0000, &R(CPSR));
+ retval = arm11_run_instr_data_from_core_via_r0(arm11, 0xE10F0000, &R(CPSR));
+ if (retval != ERROR_OK)
+ return retval;
/* save PC */
/* Write 0 (reset value) to Control register 0 to disable MMU/Cache etc. */
/* MCR p15,0,R0,c1,c0,0 */
- arm11_run_instr_data_to_core_via_r0(arm11, 0xee010f10, 0);
+ retval = arm11_run_instr_data_to_core_via_r0(arm11, 0xee010f10, 0);
+ if (retval != ERROR_OK)
+ return retval;
}
- arm11_run_instr_data_finish(arm11);
+ retval = arm11_run_instr_data_finish(arm11);
+ if (retval != ERROR_OK)
+ return retval;
arm11_dump_reg_changes(arm11);
int arm11_leave_debug_state(arm11_common_t * arm11)
{
FNC_INFO;
+ int retval;
- arm11_run_instr_data_prepare(arm11);
+ retval = arm11_run_instr_data_prepare(arm11);
+ if (retval != ERROR_OK)
+ return retval;
/** \todo TODO: handle other mode registers */
// LOG_DEBUG("RESTORE R" ZU " %08x", i, R(RX + i));
}
- arm11_run_instr_data_finish(arm11);
+ retval = arm11_run_instr_data_finish(arm11);
+ if (retval != ERROR_OK)
+ return retval;
/* spec says clear wDTR and rDTR; we assume they are clear as
otherwise our programming would be sloppy */
if (DSCR & (ARM11_DSCR_RDTR_FULL | ARM11_DSCR_WDTR_FULL))
{
+ /*
+ The wDTR/rDTR two registers that are used to send/receive data to/from
+ the core in tandem with corresponding instruction codes that are
+ written into the core. The RDTR FULL/WDTR FULL flag indicates that the
+ registers hold data that was written by one side (CPU or JTAG) and not
+ read out by the other side.
+ */
LOG_ERROR("wDTR/rDTR inconsistent (DSCR %08" PRIx32 ")", DSCR);
+ return ERROR_FAIL;
}
}
- arm11_run_instr_data_prepare(arm11);
+ retval = arm11_run_instr_data_prepare(arm11);
+ if (retval != ERROR_OK)
+ return retval;
/* restore original wDTR */
if ((R(DSCR) & ARM11_DSCR_WDTR_FULL) || arm11->reg_list[ARM11_RC_WDTR].dirty)
{
/* MCR p14,0,R0,c0,c5,0 */
- arm11_run_instr_data_to_core_via_r0(arm11, 0xee000e15, R(WDTR));
+ retval = arm11_run_instr_data_to_core_via_r0(arm11, 0xee000e15, R(WDTR));
+ if (retval != ERROR_OK)
+ return retval;
}
/* restore CPSR */
/* MSR CPSR,R0*/
- arm11_run_instr_data_to_core_via_r0(arm11, 0xe129f000, R(CPSR));
+ retval = arm11_run_instr_data_to_core_via_r0(arm11, 0xe129f000, R(CPSR));
+ if (retval != ERROR_OK)
+ return retval;
+
/* restore PC */
/* MOV PC,R0 */
- arm11_run_instr_data_to_core_via_r0(arm11, 0xe1a0f000, R(PC));
+ retval = arm11_run_instr_data_to_core_via_r0(arm11, 0xe1a0f000, R(PC));
+ if (retval != ERROR_OK)
+ return retval;
+
/* restore R0 */
/* MRC p14,0,r0,c0,c5,0 */
arm11_run_instr_data_to_core1(arm11, 0xee100e15, R(R0));
- arm11_run_instr_data_finish(arm11);
+ retval = arm11_run_instr_data_finish(arm11);
+ if (retval != ERROR_OK)
+ return retval;
/* restore DSCR */
arm11_common_t * arm11 = target->arch_info;
- if (arm11->trst_active)
- return ERROR_OK;
-
uint32_t dscr;
CHECK_RETVAL(arm11_read_DSCR(arm11, &dscr));
return ERROR_OK;
}
- if (arm11->trst_active)
- {
- arm11->halt_requested = true;
- return ERROR_OK;
- }
-
arm11_add_IR(arm11, ARM11_HALT, TAP_IDLE);
CHECK_RETVAL(jtag_execute_queue());
return ERROR_OK;
}
-/* target reset control */
-int arm11_assert_reset(struct target_s *target)
+int arm11_assert_reset(target_t *target)
{
FNC_INFO;
-
-#if 0
- /* assert reset lines */
- /* resets only the DBGTAP, not the ARM */
-
- jtag_add_reset(1, 0);
- jtag_add_sleep(5000);
+ int retval;
arm11_common_t * arm11 = target->arch_info;
- arm11->trst_active = true;
-#endif
+ retval = arm11_check_init(arm11, NULL);
+ if (retval != ERROR_OK)
+ return retval;
+
+ target->state = TARGET_UNKNOWN;
+ /* we would very much like to reset into the halted, state,
+ * but resetting and halting is second best... */
if (target->reset_halt)
{
CHECK_RETVAL(target_halt(target));
}
- return ERROR_OK;
-}
-int arm11_deassert_reset(struct target_s *target)
-{
- FNC_INFO;
+ /* srst is funny. We can not do *anything* else while it's asserted
+ * and it has unkonwn side effects. Make sure no other code runs
+ * meanwhile.
+ *
+ * Code below assumes srst:
+ *
+ * - Causes power-on-reset (but of what parts of the system?). Bug
+ * in arm11?
+ *
+ * - Messes us TAP state without asserting trst.
+ *
+ * - There is another bug in the arm11 core. When you generate an access to
+ * external logic (for example ddr controller via AHB bus) and that block
+ * is not configured (perhaps it is still held in reset), that transaction
+ * will never complete. This will hang arm11 core but it will also hang
+ * JTAG controller. Nothing, short of srst assertion will bring it out of
+ * this.
+ *
+ * Mysteries:
+ *
+ * - What should the PC be after an srst reset when starting in the halted
+ * state?
+ */
-#if 0
- LOG_DEBUG("target->state: %s",
- target_state_name(target));
+ jtag_add_reset(0, 1);
+ jtag_add_reset(0, 0);
+ /* How long do we have to wait? */
+ jtag_add_sleep(5000);
- /* deassert reset lines */
- jtag_add_reset(0, 0);
+ /* un-mess up TAP state */
+ jtag_add_tlr();
- arm11_common_t * arm11 = target->arch_info;
- arm11->trst_active = false;
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ {
+ return retval;
+ }
- if (arm11->halt_requested)
- return arm11_halt(target);
-#endif
+ return ERROR_OK;
+}
+int arm11_deassert_reset(target_t *target)
+{
return ERROR_OK;
}
/* target memory access
* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)
* count: number of items of <size>
+ *
+ * arm11_config_memrw_no_increment - in the future we may want to be able
+ * to read/write a range of data to a "port". a "port" is an action on
+ * read memory address for some peripheral.
*/
-int arm11_read_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+int arm11_read_memory_inner(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer,
+ bool arm11_config_memrw_no_increment)
{
/** \todo TODO: check if buffer cast to uint32_t* and uint16_t* might cause alignment problems */
+ int retval;
FNC_INFO;
arm11_common_t * arm11 = target->arch_info;
- arm11_run_instr_data_prepare(arm11);
+ retval = arm11_run_instr_data_prepare(arm11);
+ if (retval != ERROR_OK)
+ return retval;
/* MRC p14,0,r0,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
+ retval = arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
+ if (retval != ERROR_OK)
+ return retval;
switch (size)
{
}
}
- arm11_run_instr_data_finish(arm11);
+ return arm11_run_instr_data_finish(arm11);
+}
- return ERROR_OK;
+int arm11_read_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ return arm11_read_memory_inner(target, address, size, count, buffer, false);
}
-int arm11_write_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+/*
+* arm11_config_memrw_no_increment - in the future we may want to be able
+* to read/write a range of data to a "port". a "port" is an action on
+* read memory address for some peripheral.
+*/
+int arm11_write_memory_inner(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer,
+ bool arm11_config_memrw_no_increment)
{
+ int retval;
FNC_INFO;
if (target->state != TARGET_HALTED)
arm11_common_t * arm11 = target->arch_info;
- arm11_run_instr_data_prepare(arm11);
+ retval = arm11_run_instr_data_prepare(arm11);
+ if (retval != ERROR_OK)
+ return retval;
/* MRC p14,0,r0,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
+ retval = arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* burst writes are not used for single words as those may well be
+ * reset init script writes.
+ *
+ * The other advantage is that as burst writes are default, we'll
+ * now exercise both burst and non-burst code paths with the
+ * default settings, increasing code coverage.
+ */
+ bool burst = arm11_config_memwrite_burst && (count > 1);
switch (size)
{
for (size_t i = 0; i < count; i++)
{
/* MRC p14,0,r1,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++);
+ retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++);
+ if (retval != ERROR_OK)
+ return retval;
/* strb r1, [r0], #1 */
/* strb r1, [r0] */
- arm11_run_instr_no_data1(arm11,
+ retval = arm11_run_instr_no_data1(arm11,
!arm11_config_memrw_no_increment ? 0xe4c01001 : 0xe5c01000);
+ if (retval != ERROR_OK)
+ return retval;
}
break;
memcpy(&value, buffer + i * sizeof(uint16_t), sizeof(uint16_t));
/* MRC p14,0,r1,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee101e15, value);
+ retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, value);
+ if (retval != ERROR_OK)
+ return retval;
/* strh r1, [r0], #2 */
/* strh r1, [r0] */
- arm11_run_instr_no_data1(arm11,
+ retval = arm11_run_instr_no_data1(arm11,
!arm11_config_memrw_no_increment ? 0xe0c010b2 : 0xe1c010b0);
+ if (retval != ERROR_OK)
+ return retval;
}
break;
/** \todo TODO: buffer cast to uint32_t* causes alignment warnings */
uint32_t *words = (uint32_t*)buffer;
- if (!arm11_config_memwrite_burst)
+ if (!burst)
{
/* STC p14,c5,[R0],#4 */
/* STC p14,c5,[R0]*/
- arm11_run_instr_data_to_core(arm11, instr, words, count);
+ retval = arm11_run_instr_data_to_core(arm11, instr, words, count);
+ if (retval != ERROR_OK)
+ return retval;
}
else
{
/* STC p14,c5,[R0],#4 */
/* STC p14,c5,[R0]*/
- arm11_run_instr_data_to_core_noack(arm11, instr, words, count);
+ retval = arm11_run_instr_data_to_core_noack(arm11, instr, words, count);
+ if (retval != ERROR_OK)
+ return retval;
}
break;
}
}
-#if 1
/* r0 verification */
if (!arm11_config_memrw_no_increment)
{
uint32_t r0;
/* MCR p14,0,R0,c0,c5,0 */
- arm11_run_instr_data_from_core(arm11, 0xEE000E15, &r0, 1);
+ retval = arm11_run_instr_data_from_core(arm11, 0xEE000E15, &r0, 1);
+ if (retval != ERROR_OK)
+ return retval;
if (address + size * count != r0)
{
- LOG_ERROR("Data transfer failed. Expected end address 0x%08x, got 0x%08x",
- address + size * count, r0);
+ LOG_ERROR("Data transfer failed. Expected end "
+ "address 0x%08x, got 0x%08x",
+ (unsigned) (address + size * count),
+ (unsigned) r0);
- if (arm11_config_memwrite_burst)
+ if (burst)
LOG_ERROR("use 'arm11 memwrite burst disable' to disable fast burst mode");
if (arm11_config_memwrite_error_fatal)
return ERROR_FAIL;
}
}
-#endif
- arm11_run_instr_data_finish(arm11);
-
- return ERROR_OK;
+ return arm11_run_instr_data_finish(arm11);
}
+int arm11_write_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ return arm11_write_memory_inner(target, address, size, count, buffer, false);
+}
/* write target memory in multiples of 4 byte, optimized for writing large quantities of data */
int arm11_bulk_write_memory(struct target_s *target, uint32_t address, uint32_t count, uint8_t *buffer)
// return ERROR_FAIL;
// Save regs
- for (size_t i = 0; i < 16; i++)
+ for (unsigned i = 0; i < 16; i++)
{
context[i] = buf_get_u32((uint8_t*)(&arm11->reg_values[i]),0,32);
- LOG_DEBUG("Save %zi: 0x%" PRIx32 "",i,context[i]);
+ LOG_DEBUG("Save %u: 0x%" PRIx32 "", i, context[i]);
}
cpsr = buf_get_u32((uint8_t*)(arm11->reg_values + ARM11_RC_CPSR),0,32);
/* talk to the target and set things up */
int arm11_examine(struct target_s *target)
{
+ int retval;
+
FNC_INFO;
arm11_common_t * arm11 = target->arch_info;
* as suggested by the spec.
*/
- arm11_check_init(arm11, NULL);
+ retval = arm11_check_init(arm11, NULL);
+ if (retval != ERROR_OK)
+ return retval;
target_set_examined(target);
return ERROR_OK;
}
-int arm11_quit(void)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
/** Load a register that is marked !valid in the register cache */
int arm11_get_reg(reg_t *reg)
BOOL_WRAPPER(memwrite_burst, "memory write burst mode")
BOOL_WRAPPER(memwrite_error_fatal, "fatal error mode for memory writes")
-BOOL_WRAPPER(memrw_no_increment, "\"no increment\" mode for memory transfers")
BOOL_WRAPPER(step_irq_enable, "IRQs while stepping")
BOOL_WRAPPER(hardware_step, "hardware single step")
int arm11_handle_mrc_mcr(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, bool read)
{
+ int retval;
+
if (argc != (read ? 6 : 7))
{
LOG_ERROR("Invalid number of arguments.");
if (read)
instr |= 0x00100000;
- arm11_run_instr_data_prepare(arm11);
+ retval = arm11_run_instr_data_prepare(arm11);
+ if (retval != ERROR_OK)
+ return retval;
if (read)
{
uint32_t result;
- arm11_run_instr_data_from_core_via_r0(arm11, instr, &result);
+ retval = arm11_run_instr_data_from_core_via_r0(arm11, instr, &result);
+ if (retval != ERROR_OK)
+ return retval;
LOG_INFO("MRC p%d, %d, R0, c%d, c%d, %d = 0x%08" PRIx32 " (%" PRId32 ")",
(int)(values[0]),
}
else
{
- arm11_run_instr_data_to_core_via_r0(arm11, instr, values[5]);
+ retval = arm11_run_instr_data_to_core_via_r0(arm11, instr, values[5]);
+ if (retval != ERROR_OK)
+ return retval;
LOG_INFO("MRC p%d, %d, R0 (#0x%08" PRIx32 "), c%d, c%d, %d",
(int)(values[0]), (int)(values[1]),
(int)(values[2]), (int)(values[3]), (int)(values[4]));
}
- arm11_run_instr_data_finish(arm11);
-
-
- return ERROR_OK;
+ return arm11_run_instr_data_finish(arm11);
}
int arm11_handle_mrc(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
return arm11_handle_mrc_mcr(cmd_ctx, cmd, args, argc, false);
}
+static int arm11_mrc_inner(target_t *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value, bool read)
+{
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ {
+ LOG_ERROR("Target not halted");
+ return ERROR_FAIL;
+ }
+
+ arm11_common_t * arm11 = target->arch_info;
+
+ uint32_t instr = 0xEE000010 |
+ (cpnum << 8) |
+ (op1 << 21) |
+ (CRn << 16) |
+ (CRm << 0) |
+ (op2 << 5);
+
+ if (read)
+ instr |= 0x00100000;
+
+ retval = arm11_run_instr_data_prepare(arm11);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (read)
+ {
+ retval = arm11_run_instr_data_from_core_via_r0(arm11, instr, value);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ else
+ {
+ retval = arm11_run_instr_data_to_core_via_r0(arm11, instr, *value);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ return arm11_run_instr_data_finish(arm11);
+}
+
+static int arm11_mrc(target_t *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value)
+{
+ return arm11_mrc_inner(target, cpnum, op1, op2, CRn, CRm, value, true);
+}
+
+static int arm11_mcr(target_t *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value)
+{
+ return arm11_mrc_inner(target, cpnum, op1, op2, CRn, CRm, &value, false);
+}
+
+
int arm11_register_commands(struct command_context_s *cmd_ctx)
{
FNC_INFO;
register_command(cmd_ctx, top_cmd, "mrc",
arm11_handle_mrc, COMMAND_ANY,
"Read Coprocessor register. mrc <jtag_target> <coprocessor> <opcode 1> <CRn> <CRm> <opcode 2>. All parameters are numbers only.");
- register_command(cmd_ctx, top_cmd, "no_increment",
- arm11_handle_bool_memrw_no_increment, COMMAND_ANY,
- "Don't increment address on multi-read/-write"
- " (default: disabled)");
register_command(cmd_ctx, top_cmd, "step_irq_enable",
arm11_handle_bool_step_irq_enable, COMMAND_ANY,
"Enable interrupts while stepping"