1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2008 by Hongtao Zheng *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
28 #include "arm_disassembler.h"
29 #include "arm_simulator.h"
31 #include "binarybuffer.h"
34 uint32_t arm_shift(uint8_t shift
, uint32_t Rm
, uint32_t shift_amount
, uint8_t *carry
)
36 uint32_t return_value
= 0;
39 if (shift
== 0x0) /* LSL */
41 if ((shift_amount
> 0) && (shift_amount
<= 32))
43 return_value
= Rm
<< shift_amount
;
44 *carry
= Rm
>> (32 - shift_amount
);
46 else if (shift_amount
> 32)
51 else /* (shift_amount == 0) */
56 else if (shift
== 0x1) /* LSR */
58 if ((shift_amount
> 0) && (shift_amount
<= 32))
60 return_value
= Rm
>> shift_amount
;
61 *carry
= (Rm
>> (shift_amount
- 1)) & 1;
63 else if (shift_amount
> 32)
68 else /* (shift_amount == 0) */
73 else if (shift
== 0x2) /* ASR */
75 if ((shift_amount
> 0) && (shift_amount
<= 32))
77 /* right shifts of unsigned values are guaranteed to be logical (shift in zeroes)
78 * simulate an arithmetic shift (shift in signed-bit) by adding the signed-bit manually */
79 return_value
= Rm
>> shift_amount
;
81 return_value
|= 0xffffffff << (32 - shift_amount
);
83 else if (shift_amount
> 32)
87 return_value
= 0xffffffff;
96 else /* (shift_amount == 0) */
101 else if (shift
== 0x3) /* ROR */
103 if (shift_amount
== 0)
109 shift_amount
= shift_amount
% 32;
110 return_value
= (Rm
>> shift_amount
) | (Rm
<< (32 - shift_amount
));
111 *carry
= (return_value
>> 31) & 0x1;
114 else if (shift
== 0x4) /* RRX */
116 return_value
= Rm
>> 1;
126 uint32_t arm_shifter_operand(struct arm_sim_interface
*sim
, int variant
, union arm_shifter_operand shifter_operand
, uint8_t *shifter_carry_out
)
128 uint32_t return_value
;
129 int instruction_size
;
131 if (sim
->get_state(sim
) == ARMV4_5_STATE_ARM
)
132 instruction_size
= 4;
134 instruction_size
= 2;
136 *shifter_carry_out
= sim
->get_cpsr(sim
, 29, 1);
138 if (variant
== 0) /* 32-bit immediate */
140 return_value
= shifter_operand
.immediate
.immediate
;
142 else if (variant
== 1) /* immediate shift */
144 uint32_t Rm
= sim
->get_reg_mode(sim
, shifter_operand
.immediate_shift
.Rm
);
146 /* adjust RM in case the PC is being read */
147 if (shifter_operand
.immediate_shift
.Rm
== 15)
148 Rm
+= 2 * instruction_size
;
150 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
, Rm
, shifter_operand
.immediate_shift
.shift_imm
, shifter_carry_out
);
152 else if (variant
== 2) /* register shift */
154 uint32_t Rm
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.Rm
);
155 uint32_t Rs
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.Rs
);
157 /* adjust RM in case the PC is being read */
158 if (shifter_operand
.register_shift
.Rm
== 15)
159 Rm
+= 2 * instruction_size
;
161 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
, Rm
, Rs
, shifter_carry_out
);
165 LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
166 return_value
= 0xffffffff;
172 int pass_condition(uint32_t cpsr
, uint32_t opcode
)
174 switch ((opcode
& 0xf0000000) >> 28)
177 if (cpsr
& 0x40000000)
182 if (!(cpsr
& 0x40000000))
187 if (cpsr
& 0x20000000)
192 if (!(cpsr
& 0x20000000))
197 if (cpsr
& 0x80000000)
202 if (!(cpsr
& 0x80000000))
207 if (cpsr
& 0x10000000)
212 if (!(cpsr
& 0x10000000))
217 if ((cpsr
& 0x20000000) && !(cpsr
& 0x40000000))
222 if (!(cpsr
& 0x20000000) || (cpsr
& 0x40000000))
227 if (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
228 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000)))
233 if (((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
234 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
239 if (!(cpsr
& 0x40000000) &&
240 (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
241 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000))))
246 if ((cpsr
& 0x40000000) ||
247 ((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
248 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
258 LOG_ERROR("BUG: should never get here");
262 int thumb_pass_branch_condition(uint32_t cpsr
, uint16_t opcode
)
264 return pass_condition(cpsr
, (opcode
& 0x0f00) << 20);
267 /* simulate a single step (if possible)
268 * if the dry_run_pc argument is provided, no state is changed,
269 * but the new pc is stored in the variable pointed at by the argument
271 int arm_simulate_step_core(target_t
*target
, uint32_t *dry_run_pc
, struct arm_sim_interface
*sim
)
273 uint32_t current_pc
= sim
->get_reg(sim
, 15);
274 arm_instruction_t instruction
;
275 int instruction_size
;
276 int retval
= ERROR_OK
;
278 if (sim
->get_state(sim
) == ARMV4_5_STATE_ARM
)
282 /* get current instruction, and identify it */
283 if ((retval
= target_read_u32(target
, current_pc
, &opcode
)) != ERROR_OK
)
287 if ((retval
= arm_evaluate_opcode(opcode
, current_pc
, &instruction
)) != ERROR_OK
)
291 instruction_size
= 4;
293 /* check condition code (for all instructions) */
294 if (!pass_condition(sim
->get_cpsr(sim
, 0, 32), opcode
))
298 *dry_run_pc
= current_pc
+ instruction_size
;
302 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
312 retval
= target_read_u16(target
, current_pc
, &opcode
);
313 if (retval
!= ERROR_OK
)
315 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
316 if (retval
!= ERROR_OK
)
318 instruction_size
= 2;
320 /* check condition code (only for branch instructions) */
321 if (instruction
.type
== ARM_B
&&
322 !thumb_pass_branch_condition(sim
->get_cpsr(sim
, 0, 32), opcode
))
326 *dry_run_pc
= current_pc
+ instruction_size
;
330 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
336 /* Deal with 32-bit BL/BLX */
337 if ((opcode
& 0xf800) == 0xf000) {
338 uint32_t high
= instruction
.info
.b_bl_bx_blx
.target_address
;
339 retval
= target_read_u16(target
, current_pc
+2, &opcode
);
340 if (retval
!= ERROR_OK
)
342 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
343 if (retval
!= ERROR_OK
)
345 instruction
.info
.b_bl_bx_blx
.target_address
+= high
;
349 /* examine instruction type */
351 /* branch instructions */
352 if ((instruction
.type
>= ARM_B
) && (instruction
.type
<= ARM_BLX
))
356 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== -1)
358 target
= instruction
.info
.b_bl_bx_blx
.target_address
;
362 target
= sim
->get_reg_mode(sim
, instruction
.info
.b_bl_bx_blx
.reg_operand
);
363 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== 15)
365 target
+= 2 * instruction_size
;
371 *dry_run_pc
= target
& ~1;
376 if (instruction
.type
== ARM_B
)
378 sim
->set_reg(sim
, 15, target
);
380 else if (instruction
.type
== ARM_BL
)
382 uint32_t old_pc
= sim
->get_reg(sim
, 15);
383 sim
->set_reg_mode(sim
, 14, old_pc
+ 4);
384 sim
->set_reg(sim
, 15, target
);
386 else if (instruction
.type
== ARM_BX
)
390 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
394 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
396 sim
->set_reg(sim
, 15, target
& 0xfffffffe);
398 else if (instruction
.type
== ARM_BLX
)
400 uint32_t old_pc
= sim
->get_reg(sim
, 15);
401 sim
->set_reg_mode(sim
, 14, old_pc
+ 4);
405 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
409 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
411 sim
->set_reg(sim
, 15, target
& 0xfffffffe);
417 /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
418 else if (((instruction
.type
>= ARM_AND
) && (instruction
.type
<= ARM_RSC
))
419 || ((instruction
.type
>= ARM_ORR
) && (instruction
.type
<= ARM_MVN
)))
421 uint32_t Rd
, Rn
, shifter_operand
;
422 uint8_t C
= sim
->get_cpsr(sim
, 29, 1);
426 /* ARM_MOV and ARM_MVN does not use Rn */
427 if ((instruction
.type
!= ARM_MOV
) && (instruction
.type
!= ARM_MVN
))
428 Rn
= sim
->get_reg_mode(sim
, instruction
.info
.data_proc
.Rn
);
432 shifter_operand
= arm_shifter_operand(sim
, instruction
.info
.data_proc
.variant
, instruction
.info
.data_proc
.shifter_operand
, &carry_out
);
434 /* adjust Rn in case the PC is being read */
435 if (instruction
.info
.data_proc
.Rn
== 15)
436 Rn
+= 2 * instruction_size
;
438 if (instruction
.type
== ARM_AND
)
439 Rd
= Rn
& shifter_operand
;
440 else if (instruction
.type
== ARM_EOR
)
441 Rd
= Rn
^ shifter_operand
;
442 else if (instruction
.type
== ARM_SUB
)
443 Rd
= Rn
- shifter_operand
;
444 else if (instruction
.type
== ARM_RSB
)
445 Rd
= shifter_operand
- Rn
;
446 else if (instruction
.type
== ARM_ADD
)
447 Rd
= Rn
+ shifter_operand
;
448 else if (instruction
.type
== ARM_ADC
)
449 Rd
= Rn
+ shifter_operand
+ (C
& 1);
450 else if (instruction
.type
== ARM_SBC
)
451 Rd
= Rn
- shifter_operand
- (C
& 1) ? 0 : 1;
452 else if (instruction
.type
== ARM_RSC
)
453 Rd
= shifter_operand
- Rn
- (C
& 1) ? 0 : 1;
454 else if (instruction
.type
== ARM_ORR
)
455 Rd
= Rn
| shifter_operand
;
456 else if (instruction
.type
== ARM_BIC
)
457 Rd
= Rn
& ~(shifter_operand
);
458 else if (instruction
.type
== ARM_MOV
)
459 Rd
= shifter_operand
;
460 else if (instruction
.type
== ARM_MVN
)
461 Rd
= ~shifter_operand
;
463 LOG_WARNING("unhandled instruction type");
467 if (instruction
.info
.data_proc
.Rd
== 15)
474 *dry_run_pc
= current_pc
+ instruction_size
;
481 sim
->set_reg_mode(sim
, instruction
.info
.data_proc
.Rd
, Rd
);
482 LOG_WARNING("no updating of flags yet");
484 if (instruction
.info
.data_proc
.Rd
== 15)
488 /* compare instructions (CMP, CMN, TST, TEQ) */
489 else if ((instruction
.type
>= ARM_TST
) && (instruction
.type
<= ARM_CMN
))
493 *dry_run_pc
= current_pc
+ instruction_size
;
498 LOG_WARNING("no updating of flags yet");
501 /* load register instructions */
502 else if ((instruction
.type
>= ARM_LDR
) && (instruction
.type
<= ARM_LDRSH
))
504 uint32_t load_address
= 0, modified_address
= 0, load_value
;
505 uint32_t Rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store
.Rn
);
507 /* adjust Rn in case the PC is being read */
508 if (instruction
.info
.load_store
.Rn
== 15)
509 Rn
+= 2 * instruction_size
;
511 if (instruction
.info
.load_store
.offset_mode
== 0)
513 if (instruction
.info
.load_store
.U
)
514 modified_address
= Rn
+ instruction
.info
.load_store
.offset
.offset
;
516 modified_address
= Rn
- instruction
.info
.load_store
.offset
.offset
;
518 else if (instruction
.info
.load_store
.offset_mode
== 1)
521 uint32_t Rm
= sim
->get_reg_mode(sim
, instruction
.info
.load_store
.offset
.reg
.Rm
);
522 uint8_t shift
= instruction
.info
.load_store
.offset
.reg
.shift
;
523 uint8_t shift_imm
= instruction
.info
.load_store
.offset
.reg
.shift_imm
;
524 uint8_t carry
= sim
->get_cpsr(sim
, 29, 1);
526 offset
= arm_shift(shift
, Rm
, shift_imm
, &carry
);
528 if (instruction
.info
.load_store
.U
)
529 modified_address
= Rn
+ offset
;
531 modified_address
= Rn
- offset
;
535 LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
538 if (instruction
.info
.load_store
.index_mode
== 0)
541 * we load from the modified address, but don't change the base address register */
542 load_address
= modified_address
;
543 modified_address
= Rn
;
545 else if (instruction
.info
.load_store
.index_mode
== 1)
548 * we load from the modified address, and write it back to the base address register */
549 load_address
= modified_address
;
551 else if (instruction
.info
.load_store
.index_mode
== 2)
554 * we load from the unmodified address, and write the modified address back */
558 if ((!dry_run_pc
) || (instruction
.info
.load_store
.Rd
== 15))
560 if ((retval
= target_read_u32(target
, load_address
, &load_value
)) != ERROR_OK
)
568 if (instruction
.info
.load_store
.Rd
== 15)
570 *dry_run_pc
= load_value
;
575 *dry_run_pc
= current_pc
+ instruction_size
;
582 if ((instruction
.info
.load_store
.index_mode
== 1) ||
583 (instruction
.info
.load_store
.index_mode
== 2))
585 sim
->set_reg_mode(sim
, instruction
.info
.load_store
.Rn
, modified_address
);
587 sim
->set_reg_mode(sim
, instruction
.info
.load_store
.Rd
, load_value
);
589 if (instruction
.info
.load_store
.Rd
== 15)
593 /* load multiple instruction */
594 else if (instruction
.type
== ARM_LDM
)
597 uint32_t Rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
);
598 uint32_t load_values
[16];
601 for (i
= 0; i
< 16; i
++)
603 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
607 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
609 case 0: /* Increment after */
612 case 1: /* Increment before */
615 case 2: /* Decrement after */
616 Rn
= Rn
- (bits_set
* 4) + 4;
618 case 3: /* Decrement before */
619 Rn
= Rn
- (bits_set
* 4);
623 for (i
= 0; i
< 16; i
++)
625 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
627 if ((!dry_run_pc
) || (i
== 15))
629 target_read_u32(target
, Rn
, &load_values
[i
]);
637 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
639 *dry_run_pc
= load_values
[15];
645 enum armv4_5_mode mode
= sim
->get_mode(sim
);
648 if (instruction
.info
.load_store_multiple
.S
)
650 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
653 mode
= ARMV4_5_MODE_USR
;
656 for (i
= 0; i
< 16; i
++)
658 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
660 sim
->set_reg_mode(sim
, i
, load_values
[i
]);
666 uint32_t spsr
= sim
->get_reg_mode(sim
, 16);
667 sim
->set_reg(sim
, ARMV4_5_CPSR
, spsr
);
670 /* base register writeback */
671 if (instruction
.info
.load_store_multiple
.W
)
672 sim
->set_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
, Rn
);
674 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
678 /* store multiple instruction */
679 else if (instruction
.type
== ARM_STM
)
685 /* STM wont affect PC (advance by instruction size */
689 uint32_t Rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
);
691 enum armv4_5_mode mode
= sim
->get_mode(sim
);
693 for (i
= 0; i
< 16; i
++)
695 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
699 if (instruction
.info
.load_store_multiple
.S
)
701 mode
= ARMV4_5_MODE_USR
;
704 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
706 case 0: /* Increment after */
709 case 1: /* Increment before */
712 case 2: /* Decrement after */
713 Rn
= Rn
- (bits_set
* 4) + 4;
715 case 3: /* Decrement before */
716 Rn
= Rn
- (bits_set
* 4);
720 for (i
= 0; i
< 16; i
++)
722 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
724 target_write_u32(target
, Rn
, sim
->get_reg_mode(sim
, i
));
729 /* base register writeback */
730 if (instruction
.info
.load_store_multiple
.W
)
731 sim
->set_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
, Rn
);
735 else if (!dry_run_pc
)
737 /* the instruction wasn't handled, but we're supposed to simulate it
739 LOG_ERROR("Unimplemented instruction, could not simulate it.");
745 *dry_run_pc
= current_pc
+ instruction_size
;
750 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
756 static uint32_t armv4_5_get_reg(struct arm_sim_interface
*sim
, int reg
)
758 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
760 return buf_get_u32(armv4_5
->core_cache
->reg_list
[reg
].value
, 0, 32);
763 static void armv4_5_set_reg(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
765 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
767 buf_set_u32(armv4_5
->core_cache
->reg_list
[reg
].value
, 0, 32, value
);
770 static uint32_t armv4_5_get_reg_mode(struct arm_sim_interface
*sim
, int reg
)
772 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
774 return buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, reg
).value
, 0, 32);
777 static void armv4_5_set_reg_mode(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
779 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
781 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, reg
).value
, 0, 32, value
);
784 static uint32_t armv4_5_get_cpsr(struct arm_sim_interface
*sim
, int pos
, int bits
)
786 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
788 return buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, pos
, bits
);
791 static enum armv4_5_state
armv4_5_get_state(struct arm_sim_interface
*sim
)
793 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
795 return armv4_5
->core_state
;
798 static void armv4_5_set_state(struct arm_sim_interface
*sim
, enum armv4_5_state mode
)
800 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
802 armv4_5
->core_state
= mode
;
806 static enum armv4_5_mode
armv4_5_get_mode(struct arm_sim_interface
*sim
)
808 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
810 return armv4_5
->core_mode
;
815 int arm_simulate_step(target_t
*target
, uint32_t *dry_run_pc
)
817 armv4_5_common_t
*armv4_5
= target
->arch_info
;
819 struct arm_sim_interface sim
;
821 sim
.user_data
=armv4_5
;
822 sim
.get_reg
=&armv4_5_get_reg
;
823 sim
.set_reg
=&armv4_5_set_reg
;
824 sim
.get_reg_mode
=&armv4_5_get_reg_mode
;
825 sim
.set_reg_mode
=&armv4_5_set_reg_mode
;
826 sim
.get_cpsr
=&armv4_5_get_cpsr
;
827 sim
.get_mode
=&armv4_5_get_mode
;
828 sim
.get_state
=&armv4_5_get_state
;
829 sim
.set_state
=&armv4_5_set_state
;
831 return arm_simulate_step_core(target
, dry_run_pc
, &sim
);
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)