1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2006 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
7 * Copyright (C) 2008 by Hongtao Zheng *
9 ***************************************************************************/
17 #include "arm_disassembler.h"
18 #include "arm_simulator.h"
19 #include <helper/binarybuffer.h>
21 #include <helper/log.h>
23 static uint32_t arm_shift(uint8_t shift
, uint32_t rm
,
24 uint32_t shift_amount
, uint8_t *carry
)
26 uint32_t return_value
= 0;
29 if (shift
== 0x0) { /* LSL */
30 if ((shift_amount
> 0) && (shift_amount
<= 32)) {
31 return_value
= rm
<< shift_amount
;
32 *carry
= rm
>> (32 - shift_amount
);
33 } else if (shift_amount
> 32) {
36 } else /* (shift_amount == 0) */
38 } else if (shift
== 0x1) { /* LSR */
39 if ((shift_amount
> 0) && (shift_amount
<= 32)) {
40 return_value
= rm
>> shift_amount
;
41 *carry
= (rm
>> (shift_amount
- 1)) & 1;
42 } else if (shift_amount
> 32) {
45 } else /* (shift_amount == 0) */
47 } else if (shift
== 0x2) { /* ASR */
48 if ((shift_amount
> 0) && (shift_amount
<= 32)) {
49 /* C right shifts of unsigned values are guaranteed to
50 * be logical (shift in zeroes); simulate an arithmetic
51 * shift (shift in signed-bit) by adding the sign bit
54 return_value
= rm
>> shift_amount
;
56 return_value
|= 0xffffffff << (32 - shift_amount
);
57 } else if (shift_amount
> 32) {
58 if (rm
& 0x80000000) {
59 return_value
= 0xffffffff;
65 } else /* (shift_amount == 0) */
67 } else if (shift
== 0x3) { /* ROR */
68 if (shift_amount
== 0)
71 shift_amount
= shift_amount
% 32;
72 return_value
= (rm
>> shift_amount
) | (rm
<< (32 - shift_amount
));
73 *carry
= (return_value
>> 31) & 0x1;
75 } else if (shift
== 0x4) { /* RRX */
76 return_value
= rm
>> 1;
86 static uint32_t arm_shifter_operand(struct arm_sim_interface
*sim
,
87 int variant
, union arm_shifter_operand shifter_operand
,
88 uint8_t *shifter_carry_out
)
90 uint32_t return_value
;
93 if (sim
->get_state(sim
) == ARM_STATE_ARM
)
98 *shifter_carry_out
= sim
->get_cpsr(sim
, 29, 1);
100 if (variant
== 0) /* 32-bit immediate */
101 return_value
= shifter_operand
.immediate
.immediate
;
102 else if (variant
== 1) {/* immediate shift */
103 uint32_t rm
= sim
->get_reg_mode(sim
, shifter_operand
.immediate_shift
.rm
);
105 /* adjust RM in case the PC is being read */
106 if (shifter_operand
.immediate_shift
.rm
== 15)
107 rm
+= 2 * instruction_size
;
109 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
,
110 rm
, shifter_operand
.immediate_shift
.shift_imm
,
112 } else if (variant
== 2) { /* register shift */
113 uint32_t rm
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.rm
);
114 uint32_t rs
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.rs
);
116 /* adjust RM in case the PC is being read */
117 if (shifter_operand
.register_shift
.rm
== 15)
118 rm
+= 2 * instruction_size
;
120 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
,
121 rm
, rs
, shifter_carry_out
);
123 LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
124 return_value
= 0xffffffff;
130 static int pass_condition(uint32_t cpsr
, uint32_t opcode
)
132 switch ((opcode
& 0xf0000000) >> 28) {
134 if (cpsr
& 0x40000000)
139 if (!(cpsr
& 0x40000000))
144 if (cpsr
& 0x20000000)
149 if (!(cpsr
& 0x20000000))
154 if (cpsr
& 0x80000000)
159 if (!(cpsr
& 0x80000000))
164 if (cpsr
& 0x10000000)
169 if (!(cpsr
& 0x10000000))
174 if ((cpsr
& 0x20000000) && !(cpsr
& 0x40000000))
179 if (!(cpsr
& 0x20000000) || (cpsr
& 0x40000000))
184 if (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
185 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000)))
190 if (((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
191 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
196 if (!(cpsr
& 0x40000000) &&
197 (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
198 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000))))
203 if ((cpsr
& 0x40000000) ||
204 ((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
205 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
215 LOG_ERROR("BUG: should never get here");
219 static int thumb_pass_branch_condition(uint32_t cpsr
, uint16_t opcode
)
221 return pass_condition(cpsr
, (opcode
& 0x0f00) << 20);
224 /* simulate a single step (if possible)
225 * if the dry_run_pc argument is provided, no state is changed,
226 * but the new pc is stored in the variable pointed at by the argument
228 static int arm_simulate_step_core(struct target
*target
,
229 uint32_t *dry_run_pc
, struct arm_sim_interface
*sim
)
231 uint32_t current_pc
= sim
->get_reg(sim
, 15);
232 struct arm_instruction instruction
;
233 int instruction_size
;
234 int retval
= ERROR_OK
;
236 if (sim
->get_state(sim
) == ARM_STATE_ARM
) {
239 /* get current instruction, and identify it */
240 retval
= target_read_u32(target
, current_pc
, &opcode
);
241 if (retval
!= ERROR_OK
)
243 retval
= arm_evaluate_opcode(opcode
, current_pc
, &instruction
);
244 if (retval
!= ERROR_OK
)
246 instruction_size
= 4;
248 /* check condition code (for all instructions) */
249 if (!pass_condition(sim
->get_cpsr(sim
, 0, 32), opcode
)) {
251 *dry_run_pc
= current_pc
+ instruction_size
;
253 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
260 retval
= target_read_u16(target
, current_pc
, &opcode
);
261 if (retval
!= ERROR_OK
)
263 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
264 if (retval
!= ERROR_OK
)
266 instruction_size
= 2;
268 /* check condition code (only for branch (1) instructions) */
269 if ((opcode
& 0xf000) == 0xd000
270 && !thumb_pass_branch_condition(
271 sim
->get_cpsr(sim
, 0, 32), opcode
)) {
273 *dry_run_pc
= current_pc
+ instruction_size
;
275 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
280 /* Deal with 32-bit BL/BLX */
281 if ((opcode
& 0xf800) == 0xf000) {
282 uint32_t high
= instruction
.info
.b_bl_bx_blx
.target_address
;
283 retval
= target_read_u16(target
, current_pc
+2, &opcode
);
284 if (retval
!= ERROR_OK
)
286 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
287 if (retval
!= ERROR_OK
)
289 instruction
.info
.b_bl_bx_blx
.target_address
+= high
;
293 /* examine instruction type */
295 /* branch instructions */
296 if ((instruction
.type
>= ARM_B
) && (instruction
.type
<= ARM_BLX
)) {
297 uint32_t target_address
;
299 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== -1)
300 target_address
= instruction
.info
.b_bl_bx_blx
.target_address
;
302 target_address
= sim
->get_reg_mode(sim
,
303 instruction
.info
.b_bl_bx_blx
.reg_operand
);
304 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== 15)
305 target_address
+= 2 * instruction_size
;
309 *dry_run_pc
= target_address
& ~1;
312 if (instruction
.type
== ARM_B
)
313 sim
->set_reg(sim
, 15, target_address
);
314 else if (instruction
.type
== ARM_BL
) {
315 uint32_t old_pc
= sim
->get_reg(sim
, 15);
316 int t
= (sim
->get_state(sim
) == ARM_STATE_THUMB
);
317 sim
->set_reg_mode(sim
, 14, old_pc
+ 4 + t
);
318 sim
->set_reg(sim
, 15, target_address
);
319 } else if (instruction
.type
== ARM_BX
) {
320 if (target_address
& 0x1)
321 sim
->set_state(sim
, ARM_STATE_THUMB
);
323 sim
->set_state(sim
, ARM_STATE_ARM
);
324 sim
->set_reg(sim
, 15, target_address
& 0xfffffffe);
325 } else if (instruction
.type
== ARM_BLX
) {
326 uint32_t old_pc
= sim
->get_reg(sim
, 15);
327 int t
= (sim
->get_state(sim
) == ARM_STATE_THUMB
);
328 sim
->set_reg_mode(sim
, 14, old_pc
+ 4 + t
);
330 if (target_address
& 0x1)
331 sim
->set_state(sim
, ARM_STATE_THUMB
);
333 sim
->set_state(sim
, ARM_STATE_ARM
);
334 sim
->set_reg(sim
, 15, target_address
& 0xfffffffe);
340 /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
341 else if (((instruction
.type
>= ARM_AND
) && (instruction
.type
<= ARM_RSC
))
342 || ((instruction
.type
>= ARM_ORR
) && (instruction
.type
<= ARM_MVN
))) {
343 uint32_t rd
, rn
, shifter_operand
;
344 uint8_t c
= sim
->get_cpsr(sim
, 29, 1);
348 /* ARM_MOV and ARM_MVN does not use Rn */
349 if ((instruction
.type
!= ARM_MOV
) && (instruction
.type
!= ARM_MVN
))
350 rn
= sim
->get_reg_mode(sim
, instruction
.info
.data_proc
.rn
);
354 shifter_operand
= arm_shifter_operand(sim
,
355 instruction
.info
.data_proc
.variant
,
356 instruction
.info
.data_proc
.shifter_operand
,
359 /* adjust Rn in case the PC is being read */
360 if (instruction
.info
.data_proc
.rn
== 15)
361 rn
+= 2 * instruction_size
;
363 if (instruction
.type
== ARM_AND
)
364 rd
= rn
& shifter_operand
;
365 else if (instruction
.type
== ARM_EOR
)
366 rd
= rn
^ shifter_operand
;
367 else if (instruction
.type
== ARM_SUB
)
368 rd
= rn
- shifter_operand
;
369 else if (instruction
.type
== ARM_RSB
)
370 rd
= shifter_operand
- rn
;
371 else if (instruction
.type
== ARM_ADD
)
372 rd
= rn
+ shifter_operand
;
373 else if (instruction
.type
== ARM_ADC
)
374 rd
= rn
+ shifter_operand
+ (c
& 1);
375 else if (instruction
.type
== ARM_SBC
)
376 rd
= rn
- shifter_operand
- (c
& 1) ? 0 : 1;
377 else if (instruction
.type
== ARM_RSC
)
378 rd
= shifter_operand
- rn
- (c
& 1) ? 0 : 1;
379 else if (instruction
.type
== ARM_ORR
)
380 rd
= rn
| shifter_operand
;
381 else if (instruction
.type
== ARM_BIC
)
382 rd
= rn
& ~(shifter_operand
);
383 else if (instruction
.type
== ARM_MOV
)
384 rd
= shifter_operand
;
385 else if (instruction
.type
== ARM_MVN
)
386 rd
= ~shifter_operand
;
388 LOG_WARNING("unhandled instruction type");
391 if (instruction
.info
.data_proc
.rd
== 15)
392 *dry_run_pc
= rd
& ~1;
394 *dry_run_pc
= current_pc
+ instruction_size
;
398 if (instruction
.info
.data_proc
.rd
== 15) {
399 sim
->set_reg_mode(sim
, 15, rd
& ~1);
401 sim
->set_state(sim
, ARM_STATE_THUMB
);
403 sim
->set_state(sim
, ARM_STATE_ARM
);
406 sim
->set_reg_mode(sim
, instruction
.info
.data_proc
.rd
, rd
);
407 LOG_WARNING("no updating of flags yet");
410 /* compare instructions (CMP, CMN, TST, TEQ) */
411 else if ((instruction
.type
>= ARM_TST
) && (instruction
.type
<= ARM_CMN
)) {
413 *dry_run_pc
= current_pc
+ instruction_size
;
416 LOG_WARNING("no updating of flags yet");
418 /* load register instructions */
419 else if ((instruction
.type
>= ARM_LDR
) && (instruction
.type
<= ARM_LDRSH
)) {
420 uint32_t load_address
= 0, modified_address
= 0, load_value
= 0;
421 uint32_t rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store
.rn
);
423 /* adjust Rn in case the PC is being read */
424 if (instruction
.info
.load_store
.rn
== 15)
425 rn
+= 2 * instruction_size
;
427 if (instruction
.info
.load_store
.offset_mode
== 0) {
428 if (instruction
.info
.load_store
.u
)
429 modified_address
= rn
+ instruction
.info
.load_store
.offset
.offset
;
431 modified_address
= rn
- instruction
.info
.load_store
.offset
.offset
;
432 } else if (instruction
.info
.load_store
.offset_mode
== 1) {
434 uint32_t rm
= sim
->get_reg_mode(sim
,
435 instruction
.info
.load_store
.offset
.reg
.rm
);
436 uint8_t shift
= instruction
.info
.load_store
.offset
.reg
.shift
;
437 uint8_t shift_imm
= instruction
.info
.load_store
.offset
.reg
.shift_imm
;
438 uint8_t carry
= sim
->get_cpsr(sim
, 29, 1);
440 offset
= arm_shift(shift
, rm
, shift_imm
, &carry
);
442 if (instruction
.info
.load_store
.u
)
443 modified_address
= rn
+ offset
;
445 modified_address
= rn
- offset
;
447 LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
449 if (instruction
.info
.load_store
.index_mode
== 0) {
451 * we load from the modified address, but don't change
452 * the base address register
454 load_address
= modified_address
;
455 modified_address
= rn
;
456 } else if (instruction
.info
.load_store
.index_mode
== 1) {
458 * we load from the modified address, and write it
459 * back to the base address register
461 load_address
= modified_address
;
462 } else if (instruction
.info
.load_store
.index_mode
== 2) {
464 * we load from the unmodified address, and write the
465 * modified address back
470 if ((!dry_run_pc
) || (instruction
.info
.load_store
.rd
== 15)) {
471 retval
= target_read_u32(target
, load_address
, &load_value
);
472 if (retval
!= ERROR_OK
)
477 if (instruction
.info
.load_store
.rd
== 15)
478 *dry_run_pc
= load_value
& ~1;
480 *dry_run_pc
= current_pc
+ instruction_size
;
483 if ((instruction
.info
.load_store
.index_mode
== 1) ||
484 (instruction
.info
.load_store
.index_mode
== 2))
485 sim
->set_reg_mode(sim
,
486 instruction
.info
.load_store
.rn
,
489 if (instruction
.info
.load_store
.rd
== 15) {
490 sim
->set_reg_mode(sim
, 15, load_value
& ~1);
492 sim
->set_state(sim
, ARM_STATE_THUMB
);
494 sim
->set_state(sim
, ARM_STATE_ARM
);
497 sim
->set_reg_mode(sim
, instruction
.info
.load_store
.rd
, load_value
);
500 /* load multiple instruction */
501 else if (instruction
.type
== ARM_LDM
) {
503 uint32_t rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store_multiple
.rn
);
504 uint32_t load_values
[16];
507 for (i
= 0; i
< 16; i
++) {
508 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
512 switch (instruction
.info
.load_store_multiple
.addressing_mode
) {
513 case 0: /* Increment after */
516 case 1: /* Increment before */
519 case 2: /* Decrement after */
520 rn
= rn
- (bits_set
* 4) + 4;
522 case 3: /* Decrement before */
523 rn
= rn
- (bits_set
* 4);
527 for (i
= 0; i
< 16; i
++) {
528 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
)) {
529 if ((!dry_run_pc
) || (i
== 15))
530 target_read_u32(target
, rn
, &load_values
[i
]);
536 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000) {
537 *dry_run_pc
= load_values
[15] & ~1;
543 if (instruction
.info
.load_store_multiple
.s
) {
544 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
548 for (i
= 0; i
< 16; i
++) {
549 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
)) {
551 uint32_t val
= load_values
[i
];
552 sim
->set_reg_mode(sim
, i
, val
& ~1);
554 sim
->set_state(sim
, ARM_STATE_THUMB
);
556 sim
->set_state(sim
, ARM_STATE_ARM
);
558 sim
->set_reg_mode(sim
, i
, load_values
[i
]);
563 uint32_t spsr
= sim
->get_reg_mode(sim
, 16);
564 sim
->set_reg(sim
, ARMV4_5_CPSR
, spsr
);
567 /* base register writeback */
568 if (instruction
.info
.load_store_multiple
.w
)
569 sim
->set_reg_mode(sim
, instruction
.info
.load_store_multiple
.rn
, rn
);
572 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
576 /* store multiple instruction */
577 else if (instruction
.type
== ARM_STM
) {
581 /* STM wont affect PC (advance by instruction size */
583 uint32_t rn
= sim
->get_reg_mode(sim
,
584 instruction
.info
.load_store_multiple
.rn
);
587 for (i
= 0; i
< 16; i
++) {
588 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
592 switch (instruction
.info
.load_store_multiple
.addressing_mode
) {
593 case 0: /* Increment after */
596 case 1: /* Increment before */
599 case 2: /* Decrement after */
600 rn
= rn
- (bits_set
* 4) + 4;
602 case 3: /* Decrement before */
603 rn
= rn
- (bits_set
* 4);
607 for (i
= 0; i
< 16; i
++) {
608 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
)) {
609 target_write_u32(target
, rn
, sim
->get_reg_mode(sim
, i
));
614 /* base register writeback */
615 if (instruction
.info
.load_store_multiple
.w
)
616 sim
->set_reg_mode(sim
,
617 instruction
.info
.load_store_multiple
.rn
, rn
);
620 } else if (!dry_run_pc
) {
621 /* the instruction wasn't handled, but we're supposed to simulate it
623 LOG_ERROR("Unimplemented instruction, could not simulate it.");
628 *dry_run_pc
= current_pc
+ instruction_size
;
631 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
637 static uint32_t armv4_5_get_reg(struct arm_sim_interface
*sim
, int reg
)
639 struct arm
*arm
= (struct arm
*)sim
->user_data
;
641 return buf_get_u32(arm
->core_cache
->reg_list
[reg
].value
, 0, 32);
644 static void armv4_5_set_reg(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
646 struct arm
*arm
= (struct arm
*)sim
->user_data
;
648 buf_set_u32(arm
->core_cache
->reg_list
[reg
].value
, 0, 32, value
);
651 static uint32_t armv4_5_get_reg_mode(struct arm_sim_interface
*sim
, int reg
)
653 struct arm
*arm
= (struct arm
*)sim
->user_data
;
655 return buf_get_u32(ARMV4_5_CORE_REG_MODE(arm
->core_cache
,
656 arm
->core_mode
, reg
).value
, 0, 32);
659 static void armv4_5_set_reg_mode(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
661 struct arm
*arm
= (struct arm
*)sim
->user_data
;
663 buf_set_u32(ARMV4_5_CORE_REG_MODE(arm
->core_cache
,
664 arm
->core_mode
, reg
).value
, 0, 32, value
);
667 static uint32_t armv4_5_get_cpsr(struct arm_sim_interface
*sim
, int pos
, int bits
)
669 struct arm
*arm
= (struct arm
*)sim
->user_data
;
671 return buf_get_u32(arm
->cpsr
->value
, pos
, bits
);
674 static enum arm_state
armv4_5_get_state(struct arm_sim_interface
*sim
)
676 struct arm
*arm
= (struct arm
*)sim
->user_data
;
678 return arm
->core_state
;
681 static void armv4_5_set_state(struct arm_sim_interface
*sim
, enum arm_state mode
)
683 struct arm
*arm
= (struct arm
*)sim
->user_data
;
685 arm
->core_state
= mode
;
688 static enum arm_mode
armv4_5_get_mode(struct arm_sim_interface
*sim
)
690 struct arm
*arm
= (struct arm
*)sim
->user_data
;
692 return arm
->core_mode
;
695 int arm_simulate_step(struct target
*target
, uint32_t *dry_run_pc
)
697 struct arm
*arm
= target_to_arm(target
);
698 struct arm_sim_interface sim
;
701 sim
.get_reg
= &armv4_5_get_reg
;
702 sim
.set_reg
= &armv4_5_set_reg
;
703 sim
.get_reg_mode
= &armv4_5_get_reg_mode
;
704 sim
.set_reg_mode
= &armv4_5_set_reg_mode
;
705 sim
.get_cpsr
= &armv4_5_get_cpsr
;
706 sim
.get_mode
= &armv4_5_get_mode
;
707 sim
.get_state
= &armv4_5_get_state
;
708 sim
.set_state
= &armv4_5_set_state
;
710 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)