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
;
275 int retval
= ERROR_OK
;
277 if (armv4_5
->core_state
== ARMV4_5_STATE_ARM
)
281 /* get current instruction, and identify it */
282 if((retval
= target_read_u32(target
, current_pc
, &opcode
)) != ERROR_OK
)
286 if((retval
= arm_evaluate_opcode(opcode
, current_pc
, &instruction
)) != ERROR_OK
)
290 instruction_size
= 4;
292 /* check condition code (for all instructions) */
293 if (!pass_condition(buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32), opcode
))
297 *dry_run_pc
= current_pc
+ instruction_size
;
301 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, current_pc
+ instruction_size
);
311 if((retval
= target_read_u16(target
, current_pc
, &opcode
)) != ERROR_OK
)
315 if((retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
)) != ERROR_OK
)
319 instruction_size
= 2;
321 /* check condition code (only for branch instructions) */
322 if ((!thumb_pass_branch_condition(buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32), opcode
)) &&
323 (instruction
.type
== ARM_B
))
327 *dry_run_pc
= current_pc
+ instruction_size
;
331 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, current_pc
+ instruction_size
);
338 /* examine instruction type */
340 /* branch instructions */
341 if ((instruction
.type
>= ARM_B
) && (instruction
.type
<= ARM_BLX
))
345 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== -1)
347 target
= instruction
.info
.b_bl_bx_blx
.target_address
;
351 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);
356 *dry_run_pc
= target
;
361 if (instruction
.type
== ARM_B
)
363 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
);
365 else if (instruction
.type
== ARM_BL
)
367 u32 old_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
368 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 14).value
, 0, 32, old_pc
+ 4);
369 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
);
371 else if (instruction
.type
== ARM_BX
)
375 armv4_5
->core_state
= ARMV4_5_STATE_THUMB
;
379 armv4_5
->core_state
= ARMV4_5_STATE_ARM
;
381 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
& 0xfffffffe);
383 else if (instruction
.type
== ARM_BLX
)
385 u32 old_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
386 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 14).value
, 0, 32, old_pc
+ 4);
390 armv4_5
->core_state
= ARMV4_5_STATE_THUMB
;
394 armv4_5
->core_state
= ARMV4_5_STATE_ARM
;
396 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
& 0xfffffffe);
402 /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
403 else if (((instruction
.type
>= ARM_AND
) && (instruction
.type
<= ARM_RSC
))
404 || ((instruction
.type
>= ARM_ORR
) && (instruction
.type
<= ARM_MVN
)))
406 u32 Rd
, Rn
, shifter_operand
;
407 u8 C
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
411 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);
412 shifter_operand
= arm_shifter_operand(armv4_5
, instruction
.info
.data_proc
.variant
, instruction
.info
.data_proc
.shifter_operand
, &carry_out
);
414 /* adjust Rn in case the PC is being read */
415 if (instruction
.info
.data_proc
.Rn
== 15)
416 Rn
+= 2 * instruction_size
;
418 if (instruction
.type
== ARM_AND
)
419 Rd
= Rn
& shifter_operand
;
420 else if (instruction
.type
== ARM_EOR
)
421 Rd
= Rn
^ shifter_operand
;
422 else if (instruction
.type
== ARM_SUB
)
423 Rd
= Rn
- shifter_operand
;
424 else if (instruction
.type
== ARM_RSB
)
425 Rd
= shifter_operand
- Rn
;
426 else if (instruction
.type
== ARM_ADD
)
427 Rd
= Rn
+ shifter_operand
;
428 else if (instruction
.type
== ARM_ADC
)
429 Rd
= Rn
+ shifter_operand
+ (C
& 1);
430 else if (instruction
.type
== ARM_SBC
)
431 Rd
= Rn
- shifter_operand
- (C
& 1) ? 0 : 1;
432 else if (instruction
.type
== ARM_RSC
)
433 Rd
= shifter_operand
- Rn
- (C
& 1) ? 0 : 1;
434 else if (instruction
.type
== ARM_ORR
)
435 Rd
= Rn
| shifter_operand
;
436 else if (instruction
.type
== ARM_BIC
)
437 Rd
= Rn
& ~(shifter_operand
);
438 else if (instruction
.type
== ARM_MOV
)
439 Rd
= shifter_operand
;
440 else if (instruction
.type
== ARM_MVN
)
441 Rd
= ~shifter_operand
;
445 if (instruction
.info
.data_proc
.Rd
== 15)
452 *dry_run_pc
= current_pc
+ instruction_size
;
459 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
);
460 LOG_WARNING("no updating of flags yet");
462 if (instruction
.info
.data_proc
.Rd
== 15)
466 /* compare instructions (CMP, CMN, TST, TEQ) */
467 else if ((instruction
.type
>= ARM_TST
) && (instruction
.type
<= ARM_CMN
))
471 *dry_run_pc
= current_pc
+ instruction_size
;
476 LOG_WARNING("no updating of flags yet");
479 /* load register instructions */
480 else if ((instruction
.type
>= ARM_LDR
) && (instruction
.type
<= ARM_LDRSH
))
482 u32 load_address
= 0, modified_address
= 0, load_value
;
483 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);
485 /* adjust Rn in case the PC is being read */
486 if (instruction
.info
.load_store
.Rn
== 15)
487 Rn
+= 2 * instruction_size
;
489 if (instruction
.info
.load_store
.offset_mode
== 0)
491 if (instruction
.info
.load_store
.U
)
492 modified_address
= Rn
+ instruction
.info
.load_store
.offset
.offset
;
494 modified_address
= Rn
- instruction
.info
.load_store
.offset
.offset
;
496 else if (instruction
.info
.load_store
.offset_mode
== 1)
499 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);
500 u8 shift
= instruction
.info
.load_store
.offset
.reg
.shift
;
501 u8 shift_imm
= instruction
.info
.load_store
.offset
.reg
.shift_imm
;
502 u8 carry
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
504 offset
= arm_shift(shift
, Rm
, shift_imm
, &carry
);
506 if (instruction
.info
.load_store
.U
)
507 modified_address
= Rn
+ offset
;
509 modified_address
= Rn
- offset
;
513 LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
516 if (instruction
.info
.load_store
.index_mode
== 0)
519 * we load from the modified address, but don't change the base address register */
520 load_address
= modified_address
;
521 modified_address
= Rn
;
523 else if (instruction
.info
.load_store
.index_mode
== 1)
526 * we load from the modified address, and write it back to the base address register */
527 load_address
= modified_address
;
529 else if (instruction
.info
.load_store
.index_mode
== 2)
532 * we load from the unmodified address, and write the modified address back */
536 if((!dry_run_pc
) || (instruction
.info
.load_store
.Rd
== 15))
538 if((retval
= target_read_u32(target
, load_address
, &load_value
)) != ERROR_OK
)
546 if (instruction
.info
.load_store
.Rd
== 15)
548 *dry_run_pc
= load_value
;
553 *dry_run_pc
= current_pc
+ instruction_size
;
560 if ((instruction
.info
.load_store
.index_mode
== 1) ||
561 (instruction
.info
.load_store
.index_mode
== 2))
563 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
);
565 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
);
567 if (instruction
.info
.load_store
.Rd
== 15)
571 /* load multiple instruction */
572 else if (instruction
.type
== ARM_LDM
)
575 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);
579 for (i
= 0; i
< 16; i
++)
581 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
585 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
587 case 0: /* Increment after */
590 case 1: /* Increment before */
593 case 2: /* Decrement after */
594 Rn
= Rn
- (bits_set
* 4) + 4;
596 case 3: /* Decrement before */
597 Rn
= Rn
- (bits_set
* 4);
601 for (i
= 0; i
< 16; i
++)
603 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
605 if((!dry_run_pc
) || (i
== 15))
607 target_read_u32(target
, Rn
, &load_values
[i
]);
615 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
617 *dry_run_pc
= load_values
[15];
623 enum armv4_5_mode mode
= armv4_5
->core_mode
;
626 if (instruction
.info
.load_store_multiple
.S
)
628 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
631 mode
= ARMV4_5_MODE_USR
;
634 for (i
= 0; i
< 16; i
++)
636 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
638 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, mode
, i
).value
, 0, 32, load_values
[i
]);
644 u32 spsr
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 16).value
, 0, 32);
645 buf_set_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32, spsr
);
648 /* base register writeback */
649 if (instruction
.info
.load_store_multiple
.W
)
650 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
);
652 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
656 /* store multiple instruction */
657 else if (instruction
.type
== ARM_STM
)
663 /* STM wont affect PC (advance by instruction size */
667 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);
669 enum armv4_5_mode mode
= armv4_5
->core_mode
;
671 for (i
= 0; i
< 16; i
++)
673 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
677 if (instruction
.info
.load_store_multiple
.S
)
679 mode
= ARMV4_5_MODE_USR
;
682 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
684 case 0: /* Increment after */
687 case 1: /* Increment before */
690 case 2: /* Decrement after */
691 Rn
= Rn
- (bits_set
* 4) + 4;
693 case 3: /* Decrement before */
694 Rn
= Rn
- (bits_set
* 4);
698 for (i
= 0; i
< 16; i
++)
700 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
702 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));
707 /* base register writeback */
708 if (instruction
.info
.load_store_multiple
.W
)
709 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
);
713 else if (!dry_run_pc
)
715 /* the instruction wasn't handled, but we're supposed to simulate it
717 return ERROR_ARM_SIMULATOR_NOT_IMPLEMENTED
;
722 *dry_run_pc
= current_pc
+ instruction_size
;
727 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)