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((retval
= target_read_u32(target
, load_address
, &load_value
)) != ERROR_OK
)
543 if (instruction
.info
.load_store
.Rd
== 15)
545 *dry_run_pc
= load_value
;
550 *dry_run_pc
= current_pc
+ instruction_size
;
557 if ((instruction
.info
.load_store
.index_mode
== 1) ||
558 (instruction
.info
.load_store
.index_mode
== 2))
560 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
);
562 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
);
564 if (instruction
.info
.load_store
.Rd
== 15)
568 /* load multiple instruction */
569 else if (instruction
.type
== ARM_LDM
)
572 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);
576 for (i
= 0; i
< 16; i
++)
578 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
582 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
584 case 0: /* Increment after */
587 case 1: /* Increment before */
590 case 2: /* Decrement after */
591 Rn
= Rn
- (bits_set
* 4) + 4;
593 case 3: /* Decrement before */
594 Rn
= Rn
- (bits_set
* 4);
598 for (i
= 0; i
< 16; i
++)
600 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
602 target_read_u32(target
, Rn
, &load_values
[i
]);
609 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
611 *dry_run_pc
= load_values
[15];
617 enum armv4_5_mode mode
= armv4_5
->core_mode
;
620 if (instruction
.info
.load_store_multiple
.S
)
622 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
625 mode
= ARMV4_5_MODE_USR
;
628 for (i
= 0; i
< 16; i
++)
630 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
632 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, mode
, i
).value
, 0, 32, load_values
[i
]);
638 u32 spsr
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 16).value
, 0, 32);
639 buf_set_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32, spsr
);
642 /* base register writeback */
643 if (instruction
.info
.load_store_multiple
.W
)
644 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
);
646 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
650 /* store multiple instruction */
651 else if (instruction
.type
== ARM_STM
)
657 /* STM wont affect PC (advance by instruction size */
661 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);
663 enum armv4_5_mode mode
= armv4_5
->core_mode
;
665 for (i
= 0; i
< 16; i
++)
667 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
671 if (instruction
.info
.load_store_multiple
.S
)
673 mode
= ARMV4_5_MODE_USR
;
676 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
678 case 0: /* Increment after */
681 case 1: /* Increment before */
684 case 2: /* Decrement after */
685 Rn
= Rn
- (bits_set
* 4) + 4;
687 case 3: /* Decrement before */
688 Rn
= Rn
- (bits_set
* 4);
692 for (i
= 0; i
< 16; i
++)
694 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
696 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));
701 /* base register writeback */
702 if (instruction
.info
.load_store_multiple
.W
)
703 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
);
707 else if (!dry_run_pc
)
709 /* the instruction wasn't handled, but we're supposed to simulate it
711 return ERROR_ARM_SIMULATOR_NOT_IMPLEMENTED
;
716 *dry_run_pc
= current_pc
+ instruction_size
;
721 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)