]> git.sur5r.net Git - openocd/blobdiff - src/target/arm_simulator.c
retired fast_memory_access. It's always fast now.
[openocd] / src / target / arm_simulator.c
index fd0b309cec7338cfd0740df58f021d9dd22ae456..40ca35671d4ac164cef86bf06d4565aad4073575 100644 (file)
@@ -32,7 +32,7 @@
 
 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 */
@@ -160,7 +160,7 @@ u32 arm_shifter_operand(armv4_5_common_t *armv4_5, int variant, union arm_shifte
        }
        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;
        }
        
@@ -253,10 +253,15 @@ int pass_condition(u32 cpsr, u32 opcode)
                                
        }
        
-       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
@@ -264,37 +269,57 @@ int pass_condition(u32 cpsr, u32 opcode)
 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 */
@@ -419,7 +444,7 @@ int arm_simulate_step(target_t *target, u32 *dry_run_pc)
                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;
@@ -435,13 +460,13 @@ int arm_simulate_step(target_t *target, u32 *dry_run_pc)
                }
                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 */
@@ -472,7 +497,7 @@ int arm_simulate_step(target_t *target, u32 *dry_run_pc)
                }
                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)