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 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 ERROR("BUG: should never get here");
260 /* simulate a single step (if possible)
261 * if the dry_run_pc argument is provided, no state is changed,
262 * but the new pc is stored in the variable pointed at by the argument
264 int arm_simulate_step(target_t
*target
, u32
*dry_run_pc
)
266 armv4_5_common_t
*armv4_5
= target
->arch_info
;
268 u32 current_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
269 arm_instruction_t instruction
;
270 int instruction_size
;
272 if (armv4_5
->core_state
== ARMV4_5_STATE_ARM
)
274 /* get current instruction, and identify it */
275 target_read_u32(target
, current_pc
, &opcode
);
276 arm_evaluate_opcode(opcode
, current_pc
, &instruction
);
277 instruction_size
= 4;
281 /* TODO: add support for Thumb instruction set */
282 instruction_size
= 2;
285 /* check condition code */
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
);
300 /* examine instruction type */
302 /* branch instructions */
303 if ((instruction
.type
>= ARM_B
) && (instruction
.type
<= ARM_BLX
))
307 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== -1)
309 target
= instruction
.info
.b_bl_bx_blx
.target_address
;
313 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);
318 *dry_run_pc
= target
;
323 if (instruction
.type
== ARM_B
)
325 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
);
327 else if (instruction
.type
== ARM_BL
)
329 u32 old_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
330 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 14).value
, 0, 32, old_pc
+ 4);
331 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
);
333 else if (instruction
.type
== ARM_BX
)
337 armv4_5
->core_state
= ARMV4_5_STATE_THUMB
;
341 armv4_5
->core_state
= ARMV4_5_STATE_ARM
;
343 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
& 0xfffffffe);
345 else if (instruction
.type
== ARM_BLX
)
347 u32 old_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
348 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 14).value
, 0, 32, old_pc
+ 4);
352 armv4_5
->core_state
= ARMV4_5_STATE_THUMB
;
356 armv4_5
->core_state
= ARMV4_5_STATE_ARM
;
358 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
& 0xfffffffe);
364 /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
365 else if (((instruction
.type
>= ARM_AND
) && (instruction
.type
<= ARM_RSC
))
366 || ((instruction
.type
>= ARM_ORR
) && (instruction
.type
<= ARM_MVN
)))
368 u32 Rd
, Rn
, shifter_operand
;
369 u8 C
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
373 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);
374 shifter_operand
= arm_shifter_operand(armv4_5
, instruction
.info
.data_proc
.variant
, instruction
.info
.data_proc
.shifter_operand
, &carry_out
);
376 /* adjust Rn in case the PC is being read */
377 if (instruction
.info
.data_proc
.Rn
== 15)
378 Rn
+= 2 * instruction_size
;
380 if (instruction
.type
== ARM_AND
)
381 Rd
= Rn
& shifter_operand
;
382 else if (instruction
.type
== ARM_EOR
)
383 Rd
= Rn
^ shifter_operand
;
384 else if (instruction
.type
== ARM_SUB
)
385 Rd
= Rn
- shifter_operand
;
386 else if (instruction
.type
== ARM_RSB
)
387 Rd
= shifter_operand
- Rn
;
388 else if (instruction
.type
== ARM_ADD
)
389 Rd
= Rn
+ shifter_operand
;
390 else if (instruction
.type
== ARM_ADC
)
391 Rd
= Rn
+ shifter_operand
+ (C
& 1);
392 else if (instruction
.type
== ARM_SBC
)
393 Rd
= Rn
- shifter_operand
- (C
& 1) ? 0 : 1;
394 else if (instruction
.type
== ARM_RSC
)
395 Rd
= shifter_operand
- Rn
- (C
& 1) ? 0 : 1;
396 else if (instruction
.type
== ARM_ORR
)
397 Rd
= Rn
| shifter_operand
;
398 else if (instruction
.type
== ARM_BIC
)
399 Rd
= Rn
& ~(shifter_operand
);
400 else if (instruction
.type
== ARM_MOV
)
401 Rd
= shifter_operand
;
402 else if (instruction
.type
== ARM_MVN
)
403 Rd
= ~shifter_operand
;
407 if (instruction
.info
.data_proc
.Rd
== 15)
414 *dry_run_pc
= current_pc
+ instruction_size
;
421 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
);
422 WARNING("no updating of flags yet");
424 if (instruction
.info
.data_proc
.Rd
== 15)
428 /* compare instructions (CMP, CMN, TST, TEQ) */
429 else if ((instruction
.type
>= ARM_TST
) && (instruction
.type
<= ARM_CMN
))
433 *dry_run_pc
= current_pc
+ instruction_size
;
438 WARNING("no updating of flags yet");
441 /* load register instructions */
442 else if ((instruction
.type
>= ARM_LDR
) && (instruction
.type
<= ARM_LDRSH
))
444 u32 load_address
, modified_address
, load_value
;
445 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);
447 /* adjust Rn in case the PC is being read */
448 if (instruction
.info
.load_store
.Rn
== 15)
449 Rn
+= 2 * instruction_size
;
451 if (instruction
.info
.load_store
.offset_mode
== 0)
453 if (instruction
.info
.load_store
.U
)
454 modified_address
= Rn
+ instruction
.info
.load_store
.offset
.offset
;
456 modified_address
= Rn
- instruction
.info
.load_store
.offset
.offset
;
458 else if (instruction
.info
.load_store
.offset_mode
== 1)
461 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);
462 u8 shift
= instruction
.info
.load_store
.offset
.reg
.shift
;
463 u8 shift_imm
= instruction
.info
.load_store
.offset
.reg
.shift_imm
;
464 u8 carry
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
466 offset
= arm_shift(shift
, Rm
, shift_imm
, &carry
);
468 if (instruction
.info
.load_store
.U
)
469 modified_address
= Rn
+ offset
;
471 modified_address
= Rn
- offset
;
475 ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
478 if (instruction
.info
.load_store
.index_mode
== 0)
481 * we load from the modified address, but don't change the base address register */
482 load_address
= modified_address
;
483 modified_address
= Rn
;
485 else if (instruction
.info
.load_store
.index_mode
== 1)
488 * we load from the modified address, and write it back to the base address register */
489 load_address
= modified_address
;
491 else if (instruction
.info
.load_store
.index_mode
== 2)
494 * we load from the unmodified address, and write the modified address back */
498 target_read_u32(target
, load_address
, &load_value
);
502 if (instruction
.info
.load_store
.Rd
== 15)
504 *dry_run_pc
= load_value
;
509 *dry_run_pc
= current_pc
+ instruction_size
;
516 if ((instruction
.info
.load_store
.index_mode
== 1) ||
517 (instruction
.info
.load_store
.index_mode
== 2))
519 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
);
521 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
);
523 if (instruction
.info
.load_store
.Rd
== 15)
527 /* load multiple instruction */
528 else if (instruction
.type
== ARM_LDM
)
531 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);
535 for (i
= 0; i
< 16; i
++)
537 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
541 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
543 case 0: /* Increment after */
546 case 1: /* Increment before */
549 case 2: /* Decrement after */
550 Rn
= Rn
- (bits_set
* 4) + 4;
552 case 3: /* Decrement before */
553 Rn
= Rn
- (bits_set
* 4);
557 for (i
= 0; i
< 16; i
++)
559 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
561 target_read_u32(target
, Rn
, &load_values
[i
]);
568 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
570 *dry_run_pc
= load_values
[15];
576 enum armv4_5_mode mode
= armv4_5
->core_mode
;
579 if (instruction
.info
.load_store_multiple
.S
)
581 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
584 mode
= ARMV4_5_MODE_USR
;
587 for (i
= 0; i
< 16; i
++)
589 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
591 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, mode
, i
).value
, 0, 32, load_values
[i
]);
597 u32 spsr
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 16).value
, 0, 32);
598 buf_set_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32, spsr
);
601 /* base register writeback */
602 if (instruction
.info
.load_store_multiple
.W
)
603 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
);
605 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
609 /* store multiple instruction */
610 else if (instruction
.type
== ARM_STM
)
616 /* STM wont affect PC (advance by instruction size */
620 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);
622 enum armv4_5_mode mode
= armv4_5
->core_mode
;
624 for (i
= 0; i
< 16; i
++)
626 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
630 if (instruction
.info
.load_store_multiple
.S
)
632 mode
= ARMV4_5_MODE_USR
;
635 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
637 case 0: /* Increment after */
640 case 1: /* Increment before */
643 case 2: /* Decrement after */
644 Rn
= Rn
- (bits_set
* 4) + 4;
646 case 3: /* Decrement before */
647 Rn
= Rn
- (bits_set
* 4);
651 for (i
= 0; i
< 16; i
++)
653 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
655 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));
660 /* base register writeback */
661 if (instruction
.info
.load_store_multiple
.W
)
662 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
);
666 else if (!dry_run_pc
)
668 /* the instruction wasn't handled, but we're supposed to simulate it
670 return ERROR_ARM_SIMULATOR_NOT_IMPLEMENTED
;
675 *dry_run_pc
= current_pc
+ instruction_size
;
680 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)