1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
26 #include "arm_disassembler.h"
27 #include "arm_simulator.h"
29 #include "binarybuffer.h"
33 u32
arm_shift(u8 shift
, u32 Rm
, u32 shift_amount
, u8
*carry
)
38 if (shift
== 0x0) /* LSL */
40 if ((shift_amount
> 0) && (shift_amount
<= 32))
42 return_value
= Rm
<< shift_amount
;
43 *carry
= Rm
>> (32 - shift_amount
);
45 else if (shift_amount
> 32)
50 else /* (shift_amount == 0) */
55 else if (shift
== 0x1) /* LSR */
57 if ((shift_amount
> 0) && (shift_amount
<= 32))
59 return_value
= Rm
>> shift_amount
;
60 *carry
= (Rm
>> (shift_amount
- 1)) & 1;
62 else if (shift_amount
> 32)
67 else /* (shift_amount == 0) */
72 else if (shift
== 0x2) /* ASR */
74 if ((shift_amount
> 0) && (shift_amount
<= 32))
76 /* right shifts of unsigned values are guaranteed to be logical (shift in zeroes)
77 * simulate an arithmetic shift (shift in signed-bit) by adding the signed-bit manually */
78 return_value
= Rm
>> shift_amount
;
80 return_value
|= 0xffffffff << (32 - shift_amount
);
82 else if (shift_amount
> 32)
86 return_value
= 0xffffffff;
95 else /* (shift_amount == 0) */
100 else if (shift
== 0x3) /* ROR */
102 if (shift_amount
== 0)
108 shift_amount
= shift_amount
% 32;
109 return_value
= (Rm
>> shift_amount
) | (Rm
<< (32 - shift_amount
));
110 *carry
= (return_value
>> 31) & 0x1;
113 else if (shift
== 0x4) /* RRX */
115 return_value
= Rm
>> 1;
124 u32
arm_shifter_operand(armv4_5_common_t
*armv4_5
, int variant
, union arm_shifter_operand shifter_operand
, u8
*shifter_carry_out
)
127 int instruction_size
;
129 if (armv4_5
->core_state
== ARMV4_5_STATE_ARM
)
130 instruction_size
= 4;
132 instruction_size
= 2;
134 *shifter_carry_out
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
136 if (variant
== 0) /* 32-bit immediate */
138 return_value
= shifter_operand
.immediate
.immediate
;
140 else if (variant
== 1) /* immediate shift */
142 u32 Rm
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, shifter_operand
.immediate_shift
.Rm
).value
, 0, 32);
144 /* adjust RM in case the PC is being read */
145 if (shifter_operand
.immediate_shift
.Rm
== 15)
146 Rm
+= 2 * instruction_size
;
148 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
, Rm
, shifter_operand
.immediate_shift
.shift_imm
, shifter_carry_out
);
150 else if (variant
== 2) /* register shift */
152 u32 Rm
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, shifter_operand
.register_shift
.Rm
).value
, 0, 32);
153 u32 Rs
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, shifter_operand
.register_shift
.Rs
).value
, 0, 32);
155 /* adjust RM in case the PC is being read */
156 if (shifter_operand
.register_shift
.Rm
== 15)
157 Rm
+= 2 * instruction_size
;
159 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
, Rm
, Rs
, shifter_carry_out
);
163 LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
164 return_value
= 0xffffffff;
170 int pass_condition(u32 cpsr
, u32 opcode
)
172 switch ((opcode
& 0xf0000000) >> 28)
175 if (cpsr
& 0x40000000)
180 if (!(cpsr
& 0x40000000))
185 if (cpsr
& 0x20000000)
190 if (!(cpsr
& 0x20000000))
195 if (cpsr
& 0x80000000)
200 if (!(cpsr
& 0x80000000))
205 if (cpsr
& 0x10000000)
210 if (!(cpsr
& 0x10000000))
215 if ((cpsr
& 0x20000000) && !(cpsr
& 0x40000000))
220 if (!(cpsr
& 0x20000000) || (cpsr
& 0x40000000))
225 if (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
226 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000)))
231 if (((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
232 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
237 if (!(cpsr
& 0x40000000) &&
238 (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
239 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000))))
244 if ((cpsr
& 0x40000000) &&
245 (((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
246 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000))))
256 LOG_ERROR("BUG: should never get here");
260 int thumb_pass_branch_condition(u32 cpsr
, u16 opcode
)
262 return pass_condition(cpsr
, (opcode
& 0x0f00) << 20);
265 /* simulate a single step (if possible)
266 * if the dry_run_pc argument is provided, no state is changed,
267 * but the new pc is stored in the variable pointed at by the argument
269 int arm_simulate_step(target_t
*target
, u32
*dry_run_pc
)
271 armv4_5_common_t
*armv4_5
= target
->arch_info
;
272 u32 current_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
273 arm_instruction_t instruction
;
274 int instruction_size
;
276 if (armv4_5
->core_state
== ARMV4_5_STATE_ARM
)
280 /* get current instruction, and identify it */
281 target_read_u32(target
, current_pc
, &opcode
);
282 arm_evaluate_opcode(opcode
, current_pc
, &instruction
);
283 instruction_size
= 4;
285 /* check condition code (for all instructions) */
286 if (!pass_condition(buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32), opcode
))
290 *dry_run_pc
= current_pc
+ instruction_size
;
294 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, current_pc
+ instruction_size
);
304 target_read_u16(target
, current_pc
, &opcode
);
305 thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
306 instruction_size
= 2;
308 /* check condition code (only for branch instructions) */
309 if ((!thumb_pass_branch_condition(buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32), opcode
)) &&
310 (instruction
.type
== ARM_B
))
314 *dry_run_pc
= current_pc
+ instruction_size
;
318 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, current_pc
+ instruction_size
);
325 /* examine instruction type */
327 /* branch instructions */
328 if ((instruction
.type
>= ARM_B
) && (instruction
.type
<= ARM_BLX
))
332 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== -1)
334 target
= instruction
.info
.b_bl_bx_blx
.target_address
;
338 target
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, instruction
.info
.b_bl_bx_blx
.reg_operand
).value
, 0, 32);
343 *dry_run_pc
= target
;
348 if (instruction
.type
== ARM_B
)
350 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
);
352 else if (instruction
.type
== ARM_BL
)
354 u32 old_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
355 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 14).value
, 0, 32, old_pc
+ 4);
356 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
);
358 else if (instruction
.type
== ARM_BX
)
362 armv4_5
->core_state
= ARMV4_5_STATE_THUMB
;
366 armv4_5
->core_state
= ARMV4_5_STATE_ARM
;
368 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
& 0xfffffffe);
370 else if (instruction
.type
== ARM_BLX
)
372 u32 old_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
373 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 14).value
, 0, 32, old_pc
+ 4);
377 armv4_5
->core_state
= ARMV4_5_STATE_THUMB
;
381 armv4_5
->core_state
= ARMV4_5_STATE_ARM
;
383 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
& 0xfffffffe);
389 /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
390 else if (((instruction
.type
>= ARM_AND
) && (instruction
.type
<= ARM_RSC
))
391 || ((instruction
.type
>= ARM_ORR
) && (instruction
.type
<= ARM_MVN
)))
393 u32 Rd
, Rn
, shifter_operand
;
394 u8 C
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
398 Rn
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, instruction
.info
.data_proc
.Rn
).value
, 0, 32);
399 shifter_operand
= arm_shifter_operand(armv4_5
, instruction
.info
.data_proc
.variant
, instruction
.info
.data_proc
.shifter_operand
, &carry_out
);
401 /* adjust Rn in case the PC is being read */
402 if (instruction
.info
.data_proc
.Rn
== 15)
403 Rn
+= 2 * instruction_size
;
405 if (instruction
.type
== ARM_AND
)
406 Rd
= Rn
& shifter_operand
;
407 else if (instruction
.type
== ARM_EOR
)
408 Rd
= Rn
^ shifter_operand
;
409 else if (instruction
.type
== ARM_SUB
)
410 Rd
= Rn
- shifter_operand
;
411 else if (instruction
.type
== ARM_RSB
)
412 Rd
= shifter_operand
- Rn
;
413 else if (instruction
.type
== ARM_ADD
)
414 Rd
= Rn
+ shifter_operand
;
415 else if (instruction
.type
== ARM_ADC
)
416 Rd
= Rn
+ shifter_operand
+ (C
& 1);
417 else if (instruction
.type
== ARM_SBC
)
418 Rd
= Rn
- shifter_operand
- (C
& 1) ? 0 : 1;
419 else if (instruction
.type
== ARM_RSC
)
420 Rd
= shifter_operand
- Rn
- (C
& 1) ? 0 : 1;
421 else if (instruction
.type
== ARM_ORR
)
422 Rd
= Rn
| shifter_operand
;
423 else if (instruction
.type
== ARM_BIC
)
424 Rd
= Rn
& ~(shifter_operand
);
425 else if (instruction
.type
== ARM_MOV
)
426 Rd
= shifter_operand
;
427 else if (instruction
.type
== ARM_MVN
)
428 Rd
= ~shifter_operand
;
432 if (instruction
.info
.data_proc
.Rd
== 15)
439 *dry_run_pc
= current_pc
+ instruction_size
;
446 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
);
447 LOG_WARNING("no updating of flags yet");
449 if (instruction
.info
.data_proc
.Rd
== 15)
453 /* compare instructions (CMP, CMN, TST, TEQ) */
454 else if ((instruction
.type
>= ARM_TST
) && (instruction
.type
<= ARM_CMN
))
458 *dry_run_pc
= current_pc
+ instruction_size
;
463 LOG_WARNING("no updating of flags yet");
466 /* load register instructions */
467 else if ((instruction
.type
>= ARM_LDR
) && (instruction
.type
<= ARM_LDRSH
))
469 u32 load_address
= 0, modified_address
= 0, load_value
;
470 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);
472 /* adjust Rn in case the PC is being read */
473 if (instruction
.info
.load_store
.Rn
== 15)
474 Rn
+= 2 * instruction_size
;
476 if (instruction
.info
.load_store
.offset_mode
== 0)
478 if (instruction
.info
.load_store
.U
)
479 modified_address
= Rn
+ instruction
.info
.load_store
.offset
.offset
;
481 modified_address
= Rn
- instruction
.info
.load_store
.offset
.offset
;
483 else if (instruction
.info
.load_store
.offset_mode
== 1)
486 u32 Rm
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, instruction
.info
.load_store
.offset
.reg
.Rm
).value
, 0, 32);
487 u8 shift
= instruction
.info
.load_store
.offset
.reg
.shift
;
488 u8 shift_imm
= instruction
.info
.load_store
.offset
.reg
.shift_imm
;
489 u8 carry
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
491 offset
= arm_shift(shift
, Rm
, shift_imm
, &carry
);
493 if (instruction
.info
.load_store
.U
)
494 modified_address
= Rn
+ offset
;
496 modified_address
= Rn
- offset
;
500 LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
503 if (instruction
.info
.load_store
.index_mode
== 0)
506 * we load from the modified address, but don't change the base address register */
507 load_address
= modified_address
;
508 modified_address
= Rn
;
510 else if (instruction
.info
.load_store
.index_mode
== 1)
513 * we load from the modified address, and write it back to the base address register */
514 load_address
= modified_address
;
516 else if (instruction
.info
.load_store
.index_mode
== 2)
519 * we load from the unmodified address, and write the modified address back */
523 target_read_u32(target
, load_address
, &load_value
);
527 if (instruction
.info
.load_store
.Rd
== 15)
529 *dry_run_pc
= load_value
;
534 *dry_run_pc
= current_pc
+ instruction_size
;
541 if ((instruction
.info
.load_store
.index_mode
== 1) ||
542 (instruction
.info
.load_store
.index_mode
== 2))
544 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, instruction
.info
.load_store
.Rn
).value
, 0, 32, modified_address
);
546 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, instruction
.info
.load_store
.Rd
).value
, 0, 32, load_value
);
548 if (instruction
.info
.load_store
.Rd
== 15)
552 /* load multiple instruction */
553 else if (instruction
.type
== ARM_LDM
)
556 u32 Rn
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, instruction
.info
.load_store_multiple
.Rn
).value
, 0, 32);
560 for (i
= 0; i
< 16; i
++)
562 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
566 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
568 case 0: /* Increment after */
571 case 1: /* Increment before */
574 case 2: /* Decrement after */
575 Rn
= Rn
- (bits_set
* 4) + 4;
577 case 3: /* Decrement before */
578 Rn
= Rn
- (bits_set
* 4);
582 for (i
= 0; i
< 16; i
++)
584 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
586 target_read_u32(target
, Rn
, &load_values
[i
]);
593 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
595 *dry_run_pc
= load_values
[15];
601 enum armv4_5_mode mode
= armv4_5
->core_mode
;
604 if (instruction
.info
.load_store_multiple
.S
)
606 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
609 mode
= ARMV4_5_MODE_USR
;
612 for (i
= 0; i
< 16; i
++)
614 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
616 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, mode
, i
).value
, 0, 32, load_values
[i
]);
622 u32 spsr
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 16).value
, 0, 32);
623 buf_set_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32, spsr
);
626 /* base register writeback */
627 if (instruction
.info
.load_store_multiple
.W
)
628 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, instruction
.info
.load_store_multiple
.Rn
).value
, 0, 32, Rn
);
630 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
634 /* store multiple instruction */
635 else if (instruction
.type
== ARM_STM
)
641 /* STM wont affect PC (advance by instruction size */
645 u32 Rn
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, instruction
.info
.load_store_multiple
.Rn
).value
, 0, 32);
647 enum armv4_5_mode mode
= armv4_5
->core_mode
;
649 for (i
= 0; i
< 16; i
++)
651 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
655 if (instruction
.info
.load_store_multiple
.S
)
657 mode
= ARMV4_5_MODE_USR
;
660 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
662 case 0: /* Increment after */
665 case 1: /* Increment before */
668 case 2: /* Decrement after */
669 Rn
= Rn
- (bits_set
* 4) + 4;
671 case 3: /* Decrement before */
672 Rn
= Rn
- (bits_set
* 4);
676 for (i
= 0; i
< 16; i
++)
678 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
680 target_write_u32(target
, Rn
, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, i
).value
, 0, 32));
685 /* base register writeback */
686 if (instruction
.info
.load_store_multiple
.W
)
687 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, instruction
.info
.load_store_multiple
.Rn
).value
, 0, 32, Rn
);
691 else if (!dry_run_pc
)
693 /* the instruction wasn't handled, but we're supposed to simulate it
695 return ERROR_ARM_SIMULATOR_NOT_IMPLEMENTED
;
700 *dry_run_pc
= current_pc
+ instruction_size
;
705 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, current_pc
+ instruction_size
);
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)