1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2008 by Hongtao Zheng *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
29 #include "arm_disassembler.h"
30 #include "arm_simulator.h"
32 #include "binarybuffer.h"
36 u32
arm_shift(u8 shift
, u32 Rm
, u32 shift_amount
, u8
*carry
)
41 if (shift
== 0x0) /* LSL */
43 if ((shift_amount
> 0) && (shift_amount
<= 32))
45 return_value
= Rm
<< shift_amount
;
46 *carry
= Rm
>> (32 - shift_amount
);
48 else if (shift_amount
> 32)
53 else /* (shift_amount == 0) */
58 else if (shift
== 0x1) /* LSR */
60 if ((shift_amount
> 0) && (shift_amount
<= 32))
62 return_value
= Rm
>> shift_amount
;
63 *carry
= (Rm
>> (shift_amount
- 1)) & 1;
65 else if (shift_amount
> 32)
70 else /* (shift_amount == 0) */
75 else if (shift
== 0x2) /* ASR */
77 if ((shift_amount
> 0) && (shift_amount
<= 32))
79 /* right shifts of unsigned values are guaranteed to be logical (shift in zeroes)
80 * simulate an arithmetic shift (shift in signed-bit) by adding the signed-bit manually */
81 return_value
= Rm
>> shift_amount
;
83 return_value
|= 0xffffffff << (32 - shift_amount
);
85 else if (shift_amount
> 32)
89 return_value
= 0xffffffff;
98 else /* (shift_amount == 0) */
103 else if (shift
== 0x3) /* ROR */
105 if (shift_amount
== 0)
111 shift_amount
= shift_amount
% 32;
112 return_value
= (Rm
>> shift_amount
) | (Rm
<< (32 - shift_amount
));
113 *carry
= (return_value
>> 31) & 0x1;
116 else if (shift
== 0x4) /* RRX */
118 return_value
= Rm
>> 1;
127 u32
arm_shifter_operand(armv4_5_common_t
*armv4_5
, int variant
, union arm_shifter_operand shifter_operand
, u8
*shifter_carry_out
)
130 int instruction_size
;
132 if (armv4_5
->core_state
== ARMV4_5_STATE_ARM
)
133 instruction_size
= 4;
135 instruction_size
= 2;
137 *shifter_carry_out
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
139 if (variant
== 0) /* 32-bit immediate */
141 return_value
= shifter_operand
.immediate
.immediate
;
143 else if (variant
== 1) /* immediate shift */
145 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);
147 /* adjust RM in case the PC is being read */
148 if (shifter_operand
.immediate_shift
.Rm
== 15)
149 Rm
+= 2 * instruction_size
;
151 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
, Rm
, shifter_operand
.immediate_shift
.shift_imm
, shifter_carry_out
);
153 else if (variant
== 2) /* register shift */
155 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);
156 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);
158 /* adjust RM in case the PC is being read */
159 if (shifter_operand
.register_shift
.Rm
== 15)
160 Rm
+= 2 * instruction_size
;
162 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
, Rm
, Rs
, shifter_carry_out
);
166 LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
167 return_value
= 0xffffffff;
173 int pass_condition(u32 cpsr
, u32 opcode
)
175 switch ((opcode
& 0xf0000000) >> 28)
178 if (cpsr
& 0x40000000)
183 if (!(cpsr
& 0x40000000))
188 if (cpsr
& 0x20000000)
193 if (!(cpsr
& 0x20000000))
198 if (cpsr
& 0x80000000)
203 if (!(cpsr
& 0x80000000))
208 if (cpsr
& 0x10000000)
213 if (!(cpsr
& 0x10000000))
218 if ((cpsr
& 0x20000000) && !(cpsr
& 0x40000000))
223 if (!(cpsr
& 0x20000000) || (cpsr
& 0x40000000))
228 if (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
229 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000)))
234 if (((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
235 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
240 if (!(cpsr
& 0x40000000) &&
241 (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
242 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000))))
247 if ((cpsr
& 0x40000000) &&
248 (((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
249 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000))))
259 LOG_ERROR("BUG: should never get here");
263 int thumb_pass_branch_condition(u32 cpsr
, u16 opcode
)
265 return pass_condition(cpsr
, (opcode
& 0x0f00) << 20);
268 /* simulate a single step (if possible)
269 * if the dry_run_pc argument is provided, no state is changed,
270 * but the new pc is stored in the variable pointed at by the argument
272 int arm_simulate_step(target_t
*target
, u32
*dry_run_pc
)
274 armv4_5_common_t
*armv4_5
= target
->arch_info
;
275 u32 current_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
276 arm_instruction_t instruction
;
277 int instruction_size
;
278 int retval
= ERROR_OK
;
280 if (armv4_5
->core_state
== ARMV4_5_STATE_ARM
)
284 /* get current instruction, and identify it */
285 if((retval
= target_read_u32(target
, current_pc
, &opcode
)) != ERROR_OK
)
289 if((retval
= arm_evaluate_opcode(opcode
, current_pc
, &instruction
)) != ERROR_OK
)
293 instruction_size
= 4;
295 /* check condition code (for all instructions) */
296 if (!pass_condition(buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32), opcode
))
300 *dry_run_pc
= current_pc
+ instruction_size
;
304 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, current_pc
+ instruction_size
);
314 if((retval
= target_read_u16(target
, current_pc
, &opcode
)) != ERROR_OK
)
318 if((retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
)) != ERROR_OK
)
322 instruction_size
= 2;
324 /* check condition code (only for branch instructions) */
325 if ((!thumb_pass_branch_condition(buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32), opcode
)) &&
326 (instruction
.type
== ARM_B
))
330 *dry_run_pc
= current_pc
+ instruction_size
;
334 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, current_pc
+ instruction_size
);
341 /* examine instruction type */
343 /* branch instructions */
344 if ((instruction
.type
>= ARM_B
) && (instruction
.type
<= ARM_BLX
))
348 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== -1)
350 target
= instruction
.info
.b_bl_bx_blx
.target_address
;
354 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);
355 if(instruction
.info
.b_bl_bx_blx
.reg_operand
== 15)
357 target
+= 2 * instruction_size
;
363 *dry_run_pc
= target
;
368 if (instruction
.type
== ARM_B
)
370 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
);
372 else if (instruction
.type
== ARM_BL
)
374 u32 old_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
375 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 14).value
, 0, 32, old_pc
+ 4);
376 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
);
378 else if (instruction
.type
== ARM_BX
)
382 armv4_5
->core_state
= ARMV4_5_STATE_THUMB
;
386 armv4_5
->core_state
= ARMV4_5_STATE_ARM
;
388 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
& 0xfffffffe);
390 else if (instruction
.type
== ARM_BLX
)
392 u32 old_pc
= buf_get_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32);
393 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 14).value
, 0, 32, old_pc
+ 4);
397 armv4_5
->core_state
= ARMV4_5_STATE_THUMB
;
401 armv4_5
->core_state
= ARMV4_5_STATE_ARM
;
403 buf_set_u32(armv4_5
->core_cache
->reg_list
[15].value
, 0, 32, target
& 0xfffffffe);
409 /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
410 else if (((instruction
.type
>= ARM_AND
) && (instruction
.type
<= ARM_RSC
))
411 || ((instruction
.type
>= ARM_ORR
) && (instruction
.type
<= ARM_MVN
)))
413 u32 Rd
, Rn
, shifter_operand
;
414 u8 C
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
418 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);
419 shifter_operand
= arm_shifter_operand(armv4_5
, instruction
.info
.data_proc
.variant
, instruction
.info
.data_proc
.shifter_operand
, &carry_out
);
421 /* adjust Rn in case the PC is being read */
422 if (instruction
.info
.data_proc
.Rn
== 15)
423 Rn
+= 2 * instruction_size
;
425 if (instruction
.type
== ARM_AND
)
426 Rd
= Rn
& shifter_operand
;
427 else if (instruction
.type
== ARM_EOR
)
428 Rd
= Rn
^ shifter_operand
;
429 else if (instruction
.type
== ARM_SUB
)
430 Rd
= Rn
- shifter_operand
;
431 else if (instruction
.type
== ARM_RSB
)
432 Rd
= shifter_operand
- Rn
;
433 else if (instruction
.type
== ARM_ADD
)
434 Rd
= Rn
+ shifter_operand
;
435 else if (instruction
.type
== ARM_ADC
)
436 Rd
= Rn
+ shifter_operand
+ (C
& 1);
437 else if (instruction
.type
== ARM_SBC
)
438 Rd
= Rn
- shifter_operand
- (C
& 1) ? 0 : 1;
439 else if (instruction
.type
== ARM_RSC
)
440 Rd
= shifter_operand
- Rn
- (C
& 1) ? 0 : 1;
441 else if (instruction
.type
== ARM_ORR
)
442 Rd
= Rn
| shifter_operand
;
443 else if (instruction
.type
== ARM_BIC
)
444 Rd
= Rn
& ~(shifter_operand
);
445 else if (instruction
.type
== ARM_MOV
)
446 Rd
= shifter_operand
;
447 else if (instruction
.type
== ARM_MVN
)
448 Rd
= ~shifter_operand
;
452 if (instruction
.info
.data_proc
.Rd
== 15)
459 *dry_run_pc
= current_pc
+ instruction_size
;
466 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
);
467 LOG_WARNING("no updating of flags yet");
469 if (instruction
.info
.data_proc
.Rd
== 15)
473 /* compare instructions (CMP, CMN, TST, TEQ) */
474 else if ((instruction
.type
>= ARM_TST
) && (instruction
.type
<= ARM_CMN
))
478 *dry_run_pc
= current_pc
+ instruction_size
;
483 LOG_WARNING("no updating of flags yet");
486 /* load register instructions */
487 else if ((instruction
.type
>= ARM_LDR
) && (instruction
.type
<= ARM_LDRSH
))
489 u32 load_address
= 0, modified_address
= 0, load_value
;
490 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);
492 /* adjust Rn in case the PC is being read */
493 if (instruction
.info
.load_store
.Rn
== 15)
494 Rn
+= 2 * instruction_size
;
496 if (instruction
.info
.load_store
.offset_mode
== 0)
498 if (instruction
.info
.load_store
.U
)
499 modified_address
= Rn
+ instruction
.info
.load_store
.offset
.offset
;
501 modified_address
= Rn
- instruction
.info
.load_store
.offset
.offset
;
503 else if (instruction
.info
.load_store
.offset_mode
== 1)
506 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);
507 u8 shift
= instruction
.info
.load_store
.offset
.reg
.shift
;
508 u8 shift_imm
= instruction
.info
.load_store
.offset
.reg
.shift_imm
;
509 u8 carry
= buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 29, 1);
511 offset
= arm_shift(shift
, Rm
, shift_imm
, &carry
);
513 if (instruction
.info
.load_store
.U
)
514 modified_address
= Rn
+ offset
;
516 modified_address
= Rn
- offset
;
520 LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
523 if (instruction
.info
.load_store
.index_mode
== 0)
526 * we load from the modified address, but don't change the base address register */
527 load_address
= modified_address
;
528 modified_address
= Rn
;
530 else if (instruction
.info
.load_store
.index_mode
== 1)
533 * we load from the modified address, and write it back to the base address register */
534 load_address
= modified_address
;
536 else if (instruction
.info
.load_store
.index_mode
== 2)
539 * we load from the unmodified address, and write the modified address back */
543 if((!dry_run_pc
) || (instruction
.info
.load_store
.Rd
== 15))
545 if((retval
= target_read_u32(target
, load_address
, &load_value
)) != ERROR_OK
)
553 if (instruction
.info
.load_store
.Rd
== 15)
555 *dry_run_pc
= load_value
;
560 *dry_run_pc
= current_pc
+ instruction_size
;
567 if ((instruction
.info
.load_store
.index_mode
== 1) ||
568 (instruction
.info
.load_store
.index_mode
== 2))
570 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
);
572 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
);
574 if (instruction
.info
.load_store
.Rd
== 15)
578 /* load multiple instruction */
579 else if (instruction
.type
== ARM_LDM
)
582 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);
586 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
)
594 case 0: /* Increment after */
597 case 1: /* Increment before */
600 case 2: /* Decrement after */
601 Rn
= Rn
- (bits_set
* 4) + 4;
603 case 3: /* Decrement before */
604 Rn
= Rn
- (bits_set
* 4);
608 for (i
= 0; i
< 16; i
++)
610 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
612 if((!dry_run_pc
) || (i
== 15))
614 target_read_u32(target
, Rn
, &load_values
[i
]);
622 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
624 *dry_run_pc
= load_values
[15];
630 enum armv4_5_mode mode
= armv4_5
->core_mode
;
633 if (instruction
.info
.load_store_multiple
.S
)
635 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
638 mode
= ARMV4_5_MODE_USR
;
641 for (i
= 0; i
< 16; i
++)
643 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
645 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, mode
, i
).value
, 0, 32, load_values
[i
]);
651 u32 spsr
= buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
, armv4_5
->core_mode
, 16).value
, 0, 32);
652 buf_set_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, 0, 32, spsr
);
655 /* base register writeback */
656 if (instruction
.info
.load_store_multiple
.W
)
657 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
);
659 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
663 /* store multiple instruction */
664 else if (instruction
.type
== ARM_STM
)
670 /* STM wont affect PC (advance by instruction size */
674 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);
676 enum armv4_5_mode mode
= armv4_5
->core_mode
;
678 for (i
= 0; i
< 16; i
++)
680 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
684 if (instruction
.info
.load_store_multiple
.S
)
686 mode
= ARMV4_5_MODE_USR
;
689 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
691 case 0: /* Increment after */
694 case 1: /* Increment before */
697 case 2: /* Decrement after */
698 Rn
= Rn
- (bits_set
* 4) + 4;
700 case 3: /* Decrement before */
701 Rn
= Rn
- (bits_set
* 4);
705 for (i
= 0; i
< 16; i
++)
707 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
709 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));
714 /* base register writeback */
715 if (instruction
.info
.load_store_multiple
.W
)
716 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
);
720 else if (!dry_run_pc
)
722 /* the instruction wasn't handled, but we're supposed to simulate it
724 return ERROR_ARM_SIMULATOR_NOT_IMPLEMENTED
;
729 *dry_run_pc
= current_pc
+ instruction_size
;
734 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)