u32 arm_shift(u8 shift, u32 Rm, u32 shift_amount, u8 *carry)
{
- u32 return_value;
+ u32 return_value = 0;
shift_amount &= 0xff;
if (shift == 0x0) /* LSL */
}
else
{
- ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
+ LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
return_value = 0xffffffff;
}
}
- ERROR("BUG: should never get here");
+ LOG_ERROR("BUG: should never get here");
return 0;
}
+int thumb_pass_branch_condition(u32 cpsr, u16 opcode)
+{
+ return pass_condition(cpsr, (opcode & 0x0f00) << 20);
+}
+
/* simulate a single step (if possible)
* if the dry_run_pc argument is provided, no state is changed,
* but the new pc is stored in the variable pointed at by the argument
int arm_simulate_step(target_t *target, u32 *dry_run_pc)
{
armv4_5_common_t *armv4_5 = target->arch_info;
- u32 opcode;
u32 current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
arm_instruction_t instruction;
int instruction_size;
if (armv4_5->core_state == ARMV4_5_STATE_ARM)
{
+ u32 opcode;
+
/* get current instruction, and identify it */
target_read_u32(target, current_pc, &opcode);
arm_evaluate_opcode(opcode, current_pc, &instruction);
instruction_size = 4;
+
+ /* check condition code (for all instructions) */
+ if (!pass_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode))
+ {
+ if (dry_run_pc)
+ {
+ *dry_run_pc = current_pc + instruction_size;
+ }
+ else
+ {
+ buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
+ }
+
+ return ERROR_OK;
+ }
}
else
{
- /* TODO: add support for Thumb instruction set */
+ u16 opcode;
+
+ target_read_u16(target, current_pc, &opcode);
+ thumb_evaluate_opcode(opcode, current_pc, &instruction);
instruction_size = 2;
- }
-
- /* check condition code */
- if (!pass_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode))
- {
- if (dry_run_pc)
- {
- *dry_run_pc = current_pc + instruction_size;
- }
- else
+
+ /* check condition code (only for branch instructions) */
+ if ((!thumb_pass_branch_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode)) &&
+ (instruction.type == ARM_B))
{
- buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
+ if (dry_run_pc)
+ {
+ *dry_run_pc = current_pc + instruction_size;
+ }
+ else
+ {
+ buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
+ }
+
+ return ERROR_OK;
}
-
- return ERROR_OK;
}
/* examine instruction type */
else
{
buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.data_proc.Rd).value, 0, 32, Rd);
- WARNING("no updating of flags yet");
+ LOG_WARNING("no updating of flags yet");
if (instruction.info.data_proc.Rd == 15)
return ERROR_OK;
}
else
{
- WARNING("no updating of flags yet");
+ LOG_WARNING("no updating of flags yet");
}
}
/* load register instructions */
else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH))
{
- u32 load_address, modified_address, load_value;
+ u32 load_address = 0, modified_address = 0, load_value;
u32 Rn = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.load_store.Rn).value, 0, 32);
/* adjust Rn in case the PC is being read */
}
else
{
- ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
+ LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
}
if (instruction.info.load_store.index_mode == 0)