jtag newtap change & huge manual update
[openocd.git] / src / target / arm_simulator.c
1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2008 by Hongtao Zheng *
6 * hontor@126.com *
7 * *
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. *
12 * *
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. *
17 * *
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 ***************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "target.h"
28 #include "armv4_5.h"
29 #include "arm_disassembler.h"
30 #include "arm_simulator.h"
31 #include "log.h"
32 #include "binarybuffer.h"
33
34 #include <string.h>
35
36 u32 arm_shift(u8 shift, u32 Rm, u32 shift_amount, u8 *carry)
37 {
38 u32 return_value = 0;
39 shift_amount &= 0xff;
40
41 if (shift == 0x0) /* LSL */
42 {
43 if ((shift_amount > 0) && (shift_amount <= 32))
44 {
45 return_value = Rm << shift_amount;
46 *carry = Rm >> (32 - shift_amount);
47 }
48 else if (shift_amount > 32)
49 {
50 return_value = 0x0;
51 *carry = 0x0;
52 }
53 else /* (shift_amount == 0) */
54 {
55 return_value = Rm;
56 }
57 }
58 else if (shift == 0x1) /* LSR */
59 {
60 if ((shift_amount > 0) && (shift_amount <= 32))
61 {
62 return_value = Rm >> shift_amount;
63 *carry = (Rm >> (shift_amount - 1)) & 1;
64 }
65 else if (shift_amount > 32)
66 {
67 return_value = 0x0;
68 *carry = 0x0;
69 }
70 else /* (shift_amount == 0) */
71 {
72 return_value = Rm;
73 }
74 }
75 else if (shift == 0x2) /* ASR */
76 {
77 if ((shift_amount > 0) && (shift_amount <= 32))
78 {
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;
82 if (Rm & 0x80000000)
83 return_value |= 0xffffffff << (32 - shift_amount);
84 }
85 else if (shift_amount > 32)
86 {
87 if (Rm & 0x80000000)
88 {
89 return_value = 0xffffffff;
90 *carry = 0x1;
91 }
92 else
93 {
94 return_value = 0x0;
95 *carry = 0x0;
96 }
97 }
98 else /* (shift_amount == 0) */
99 {
100 return_value = Rm;
101 }
102 }
103 else if (shift == 0x3) /* ROR */
104 {
105 if (shift_amount == 0)
106 {
107 return_value = Rm;
108 }
109 else
110 {
111 shift_amount = shift_amount % 32;
112 return_value = (Rm >> shift_amount) | (Rm << (32 - shift_amount));
113 *carry = (return_value >> 31) & 0x1;
114 }
115 }
116 else if (shift == 0x4) /* RRX */
117 {
118 return_value = Rm >> 1;
119 if (*carry)
120 Rm |= 0x80000000;
121 *carry = Rm & 0x1;
122 }
123
124 return return_value;
125 }
126
127 u32 arm_shifter_operand(armv4_5_common_t *armv4_5, int variant, union arm_shifter_operand shifter_operand, u8 *shifter_carry_out)
128 {
129 u32 return_value;
130 int instruction_size;
131
132 if (armv4_5->core_state == ARMV4_5_STATE_ARM)
133 instruction_size = 4;
134 else
135 instruction_size = 2;
136
137 *shifter_carry_out = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 29, 1);
138
139 if (variant == 0) /* 32-bit immediate */
140 {
141 return_value = shifter_operand.immediate.immediate;
142 }
143 else if (variant == 1) /* immediate shift */
144 {
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);
146
147 /* adjust RM in case the PC is being read */
148 if (shifter_operand.immediate_shift.Rm == 15)
149 Rm += 2 * instruction_size;
150
151 return_value = arm_shift(shifter_operand.immediate_shift.shift, Rm, shifter_operand.immediate_shift.shift_imm, shifter_carry_out);
152 }
153 else if (variant == 2) /* register shift */
154 {
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);
157
158 /* adjust RM in case the PC is being read */
159 if (shifter_operand.register_shift.Rm == 15)
160 Rm += 2 * instruction_size;
161
162 return_value = arm_shift(shifter_operand.immediate_shift.shift, Rm, Rs, shifter_carry_out);
163 }
164 else
165 {
166 LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
167 return_value = 0xffffffff;
168 }
169
170 return return_value;
171 }
172
173 int pass_condition(u32 cpsr, u32 opcode)
174 {
175 switch ((opcode & 0xf0000000) >> 28)
176 {
177 case 0x0: /* EQ */
178 if (cpsr & 0x40000000)
179 return 1;
180 else
181 return 0;
182 case 0x1: /* NE */
183 if (!(cpsr & 0x40000000))
184 return 1;
185 else
186 return 0;
187 case 0x2: /* CS */
188 if (cpsr & 0x20000000)
189 return 1;
190 else
191 return 0;
192 case 0x3: /* CC */
193 if (!(cpsr & 0x20000000))
194 return 1;
195 else
196 return 0;
197 case 0x4: /* MI */
198 if (cpsr & 0x80000000)
199 return 1;
200 else
201 return 0;
202 case 0x5: /* PL */
203 if (!(cpsr & 0x80000000))
204 return 1;
205 else
206 return 0;
207 case 0x6: /* VS */
208 if (cpsr & 0x10000000)
209 return 1;
210 else
211 return 0;
212 case 0x7: /* VC */
213 if (!(cpsr & 0x10000000))
214 return 1;
215 else
216 return 0;
217 case 0x8: /* HI */
218 if ((cpsr & 0x20000000) && !(cpsr & 0x40000000))
219 return 1;
220 else
221 return 0;
222 case 0x9: /* LS */
223 if (!(cpsr & 0x20000000) || (cpsr & 0x40000000))
224 return 1;
225 else
226 return 0;
227 case 0xa: /* GE */
228 if (((cpsr & 0x80000000) && (cpsr & 0x10000000))
229 || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000)))
230 return 1;
231 else
232 return 0;
233 case 0xb: /* LT */
234 if (((cpsr & 0x80000000) && !(cpsr & 0x10000000))
235 || (!(cpsr & 0x80000000) && (cpsr & 0x10000000)))
236 return 1;
237 else
238 return 0;
239 case 0xc: /* GT */
240 if (!(cpsr & 0x40000000) &&
241 (((cpsr & 0x80000000) && (cpsr & 0x10000000))
242 || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000))))
243 return 1;
244 else
245 return 0;
246 case 0xd: /* LE */
247 if ((cpsr & 0x40000000) &&
248 (((cpsr & 0x80000000) && !(cpsr & 0x10000000))
249 || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))))
250 return 1;
251 else
252 return 0;
253 case 0xe:
254 case 0xf:
255 return 1;
256
257 }
258
259 LOG_ERROR("BUG: should never get here");
260 return 0;
261 }
262
263 int thumb_pass_branch_condition(u32 cpsr, u16 opcode)
264 {
265 return pass_condition(cpsr, (opcode & 0x0f00) << 20);
266 }
267
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
271 */
272 int arm_simulate_step(target_t *target, u32 *dry_run_pc)
273 {
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;
279
280 if (armv4_5->core_state == ARMV4_5_STATE_ARM)
281 {
282 u32 opcode;
283
284 /* get current instruction, and identify it */
285 if((retval = target_read_u32(target, current_pc, &opcode)) != ERROR_OK)
286 {
287 return retval;
288 }
289 if((retval = arm_evaluate_opcode(opcode, current_pc, &instruction)) != ERROR_OK)
290 {
291 return retval;
292 }
293 instruction_size = 4;
294
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))
297 {
298 if (dry_run_pc)
299 {
300 *dry_run_pc = current_pc + instruction_size;
301 }
302 else
303 {
304 buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
305 }
306
307 return ERROR_OK;
308 }
309 }
310 else
311 {
312 u16 opcode;
313
314 if((retval = target_read_u16(target, current_pc, &opcode)) != ERROR_OK)
315 {
316 return retval;
317 }
318 if((retval = thumb_evaluate_opcode(opcode, current_pc, &instruction)) != ERROR_OK)
319 {
320 return retval;
321 }
322 instruction_size = 2;
323
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))
327 {
328 if (dry_run_pc)
329 {
330 *dry_run_pc = current_pc + instruction_size;
331 }
332 else
333 {
334 buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
335 }
336
337 return ERROR_OK;
338 }
339 }
340
341 /* examine instruction type */
342
343 /* branch instructions */
344 if ((instruction.type >= ARM_B) && (instruction.type <= ARM_BLX))
345 {
346 u32 target;
347
348 if (instruction.info.b_bl_bx_blx.reg_operand == -1)
349 {
350 target = instruction.info.b_bl_bx_blx.target_address;
351 }
352 else
353 {
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)
356 {
357 target += 2 * instruction_size;
358 }
359 }
360
361 if (dry_run_pc)
362 {
363 *dry_run_pc = target;
364 return ERROR_OK;
365 }
366 else
367 {
368 if (instruction.type == ARM_B)
369 {
370 buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, target);
371 }
372 else if (instruction.type == ARM_BL)
373 {
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);
377 }
378 else if (instruction.type == ARM_BX)
379 {
380 if (target & 0x1)
381 {
382 armv4_5->core_state = ARMV4_5_STATE_THUMB;
383 }
384 else
385 {
386 armv4_5->core_state = ARMV4_5_STATE_ARM;
387 }
388 buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, target & 0xfffffffe);
389 }
390 else if (instruction.type == ARM_BLX)
391 {
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);
394
395 if (target & 0x1)
396 {
397 armv4_5->core_state = ARMV4_5_STATE_THUMB;
398 }
399 else
400 {
401 armv4_5->core_state = ARMV4_5_STATE_ARM;
402 }
403 buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, target & 0xfffffffe);
404 }
405
406 return ERROR_OK;
407 }
408 }
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)))
412 {
413 u32 Rd, Rn, shifter_operand;
414 u8 C = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 29, 1);
415 u8 carry_out;
416
417 Rd = 0x0;
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);
420
421 /* adjust Rn in case the PC is being read */
422 if (instruction.info.data_proc.Rn == 15)
423 Rn += 2 * instruction_size;
424
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;
449
450 if (dry_run_pc)
451 {
452 if (instruction.info.data_proc.Rd == 15)
453 {
454 *dry_run_pc = Rd;
455 return ERROR_OK;
456 }
457 else
458 {
459 *dry_run_pc = current_pc + instruction_size;
460 }
461
462 return ERROR_OK;
463 }
464 else
465 {
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");
468
469 if (instruction.info.data_proc.Rd == 15)
470 return ERROR_OK;
471 }
472 }
473 /* compare instructions (CMP, CMN, TST, TEQ) */
474 else if ((instruction.type >= ARM_TST) && (instruction.type <= ARM_CMN))
475 {
476 if (dry_run_pc)
477 {
478 *dry_run_pc = current_pc + instruction_size;
479 return ERROR_OK;
480 }
481 else
482 {
483 LOG_WARNING("no updating of flags yet");
484 }
485 }
486 /* load register instructions */
487 else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH))
488 {
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);
491
492 /* adjust Rn in case the PC is being read */
493 if (instruction.info.load_store.Rn == 15)
494 Rn += 2 * instruction_size;
495
496 if (instruction.info.load_store.offset_mode == 0)
497 {
498 if (instruction.info.load_store.U)
499 modified_address = Rn + instruction.info.load_store.offset.offset;
500 else
501 modified_address = Rn - instruction.info.load_store.offset.offset;
502 }
503 else if (instruction.info.load_store.offset_mode == 1)
504 {
505 u32 offset;
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);
510
511 offset = arm_shift(shift, Rm, shift_imm, &carry);
512
513 if (instruction.info.load_store.U)
514 modified_address = Rn + offset;
515 else
516 modified_address = Rn - offset;
517 }
518 else
519 {
520 LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
521 }
522
523 if (instruction.info.load_store.index_mode == 0)
524 {
525 /* offset mode
526 * we load from the modified address, but don't change the base address register */
527 load_address = modified_address;
528 modified_address = Rn;
529 }
530 else if (instruction.info.load_store.index_mode == 1)
531 {
532 /* pre-indexed mode
533 * we load from the modified address, and write it back to the base address register */
534 load_address = modified_address;
535 }
536 else if (instruction.info.load_store.index_mode == 2)
537 {
538 /* post-indexed mode
539 * we load from the unmodified address, and write the modified address back */
540 load_address = Rn;
541 }
542
543 if((!dry_run_pc) || (instruction.info.load_store.Rd == 15))
544 {
545 if((retval = target_read_u32(target, load_address, &load_value)) != ERROR_OK)
546 {
547 return retval;
548 }
549 }
550
551 if (dry_run_pc)
552 {
553 if (instruction.info.load_store.Rd == 15)
554 {
555 *dry_run_pc = load_value;
556 return ERROR_OK;
557 }
558 else
559 {
560 *dry_run_pc = current_pc + instruction_size;
561 }
562
563 return ERROR_OK;
564 }
565 else
566 {
567 if ((instruction.info.load_store.index_mode == 1) ||
568 (instruction.info.load_store.index_mode == 2))
569 {
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);
571 }
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);
573
574 if (instruction.info.load_store.Rd == 15)
575 return ERROR_OK;
576 }
577 }
578 /* load multiple instruction */
579 else if (instruction.type == ARM_LDM)
580 {
581 int i;
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);
583 u32 load_values[16];
584 int bits_set = 0;
585
586 for (i = 0; i < 16; i++)
587 {
588 if (instruction.info.load_store_multiple.register_list & (1 << i))
589 bits_set++;
590 }
591
592 switch (instruction.info.load_store_multiple.addressing_mode)
593 {
594 case 0: /* Increment after */
595 Rn = Rn;
596 break;
597 case 1: /* Increment before */
598 Rn = Rn + 4;
599 break;
600 case 2: /* Decrement after */
601 Rn = Rn - (bits_set * 4) + 4;
602 break;
603 case 3: /* Decrement before */
604 Rn = Rn - (bits_set * 4);
605 break;
606 }
607
608 for (i = 0; i < 16; i++)
609 {
610 if (instruction.info.load_store_multiple.register_list & (1 << i))
611 {
612 if((!dry_run_pc) || (i == 15))
613 {
614 target_read_u32(target, Rn, &load_values[i]);
615 }
616 Rn += 4;
617 }
618 }
619
620 if (dry_run_pc)
621 {
622 if (instruction.info.load_store_multiple.register_list & 0x8000)
623 {
624 *dry_run_pc = load_values[15];
625 return ERROR_OK;
626 }
627 }
628 else
629 {
630 enum armv4_5_mode mode = armv4_5->core_mode;
631 int update_cpsr = 0;
632
633 if (instruction.info.load_store_multiple.S)
634 {
635 if (instruction.info.load_store_multiple.register_list & 0x8000)
636 update_cpsr = 1;
637 else
638 mode = ARMV4_5_MODE_USR;
639 }
640
641 for (i = 0; i < 16; i++)
642 {
643 if (instruction.info.load_store_multiple.register_list & (1 << i))
644 {
645 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, i).value, 0, 32, load_values[i]);
646 }
647 }
648
649 if (update_cpsr)
650 {
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);
653 }
654
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);
658
659 if (instruction.info.load_store_multiple.register_list & 0x8000)
660 return ERROR_OK;
661 }
662 }
663 /* store multiple instruction */
664 else if (instruction.type == ARM_STM)
665 {
666 int i;
667
668 if (dry_run_pc)
669 {
670 /* STM wont affect PC (advance by instruction size */
671 }
672 else
673 {
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);
675 int bits_set = 0;
676 enum armv4_5_mode mode = armv4_5->core_mode;
677
678 for (i = 0; i < 16; i++)
679 {
680 if (instruction.info.load_store_multiple.register_list & (1 << i))
681 bits_set++;
682 }
683
684 if (instruction.info.load_store_multiple.S)
685 {
686 mode = ARMV4_5_MODE_USR;
687 }
688
689 switch (instruction.info.load_store_multiple.addressing_mode)
690 {
691 case 0: /* Increment after */
692 Rn = Rn;
693 break;
694 case 1: /* Increment before */
695 Rn = Rn + 4;
696 break;
697 case 2: /* Decrement after */
698 Rn = Rn - (bits_set * 4) + 4;
699 break;
700 case 3: /* Decrement before */
701 Rn = Rn - (bits_set * 4);
702 break;
703 }
704
705 for (i = 0; i < 16; i++)
706 {
707 if (instruction.info.load_store_multiple.register_list & (1 << i))
708 {
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));
710 Rn += 4;
711 }
712 }
713
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);
717
718 }
719 }
720 else if (!dry_run_pc)
721 {
722 /* the instruction wasn't handled, but we're supposed to simulate it
723 */
724 return ERROR_ARM_SIMULATOR_NOT_IMPLEMENTED;
725 }
726
727 if (dry_run_pc)
728 {
729 *dry_run_pc = current_pc + instruction_size;
730 return ERROR_OK;
731 }
732 else
733 {
734 buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
735 return ERROR_OK;
736 }
737
738 }

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)