use direct jump only for jumps in the same page
[qemu/mini2440.git] / target-arm / translate.c
blobafb9b57c89858f12007e269ddff35b451dc15c4f
1 /*
2 * ARM translation
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 * Copyright (c) 2005 CodeSourcery, LLC
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <inttypes.h>
27 #include "cpu.h"
28 #include "exec-all.h"
29 #include "disas.h"
31 /* internal defines */
32 typedef struct DisasContext {
33 target_ulong pc;
34 int is_jmp;
35 /* Nonzero if this instruction has been conditionally skipped. */
36 int condjmp;
37 /* The label that will be jumped to when the instruction is skipped. */
38 int condlabel;
39 struct TranslationBlock *tb;
40 int singlestep_enabled;
41 int thumb;
42 } DisasContext;
44 #define DISAS_JUMP_NEXT 4
46 #ifdef USE_DIRECT_JUMP
47 #define TBPARAM(x)
48 #else
49 #define TBPARAM(x) (long)(x)
50 #endif
52 /* XXX: move that elsewhere */
53 static uint16_t *gen_opc_ptr;
54 static uint32_t *gen_opparam_ptr;
55 extern FILE *logfile;
56 extern int loglevel;
58 enum {
59 #define DEF(s, n, copy_size) INDEX_op_ ## s,
60 #include "opc.h"
61 #undef DEF
62 NB_OPS,
65 #include "gen-op.h"
67 static GenOpFunc1 *gen_test_cc[14] = {
68 gen_op_test_eq,
69 gen_op_test_ne,
70 gen_op_test_cs,
71 gen_op_test_cc,
72 gen_op_test_mi,
73 gen_op_test_pl,
74 gen_op_test_vs,
75 gen_op_test_vc,
76 gen_op_test_hi,
77 gen_op_test_ls,
78 gen_op_test_ge,
79 gen_op_test_lt,
80 gen_op_test_gt,
81 gen_op_test_le,
84 const uint8_t table_logic_cc[16] = {
85 1, /* and */
86 1, /* xor */
87 0, /* sub */
88 0, /* rsb */
89 0, /* add */
90 0, /* adc */
91 0, /* sbc */
92 0, /* rsc */
93 1, /* andl */
94 1, /* xorl */
95 0, /* cmp */
96 0, /* cmn */
97 1, /* orr */
98 1, /* mov */
99 1, /* bic */
100 1, /* mvn */
103 static GenOpFunc1 *gen_shift_T1_im[4] = {
104 gen_op_shll_T1_im,
105 gen_op_shrl_T1_im,
106 gen_op_sarl_T1_im,
107 gen_op_rorl_T1_im,
110 static GenOpFunc *gen_shift_T1_0[4] = {
111 NULL,
112 gen_op_shrl_T1_0,
113 gen_op_sarl_T1_0,
114 gen_op_rrxl_T1,
117 static GenOpFunc1 *gen_shift_T2_im[4] = {
118 gen_op_shll_T2_im,
119 gen_op_shrl_T2_im,
120 gen_op_sarl_T2_im,
121 gen_op_rorl_T2_im,
124 static GenOpFunc *gen_shift_T2_0[4] = {
125 NULL,
126 gen_op_shrl_T2_0,
127 gen_op_sarl_T2_0,
128 gen_op_rrxl_T2,
131 static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
132 gen_op_shll_T1_im_cc,
133 gen_op_shrl_T1_im_cc,
134 gen_op_sarl_T1_im_cc,
135 gen_op_rorl_T1_im_cc,
138 static GenOpFunc *gen_shift_T1_0_cc[4] = {
139 NULL,
140 gen_op_shrl_T1_0_cc,
141 gen_op_sarl_T1_0_cc,
142 gen_op_rrxl_T1_cc,
145 static GenOpFunc *gen_shift_T1_T0[4] = {
146 gen_op_shll_T1_T0,
147 gen_op_shrl_T1_T0,
148 gen_op_sarl_T1_T0,
149 gen_op_rorl_T1_T0,
152 static GenOpFunc *gen_shift_T1_T0_cc[4] = {
153 gen_op_shll_T1_T0_cc,
154 gen_op_shrl_T1_T0_cc,
155 gen_op_sarl_T1_T0_cc,
156 gen_op_rorl_T1_T0_cc,
159 static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
161 gen_op_movl_T0_r0,
162 gen_op_movl_T0_r1,
163 gen_op_movl_T0_r2,
164 gen_op_movl_T0_r3,
165 gen_op_movl_T0_r4,
166 gen_op_movl_T0_r5,
167 gen_op_movl_T0_r6,
168 gen_op_movl_T0_r7,
169 gen_op_movl_T0_r8,
170 gen_op_movl_T0_r9,
171 gen_op_movl_T0_r10,
172 gen_op_movl_T0_r11,
173 gen_op_movl_T0_r12,
174 gen_op_movl_T0_r13,
175 gen_op_movl_T0_r14,
176 gen_op_movl_T0_r15,
179 gen_op_movl_T1_r0,
180 gen_op_movl_T1_r1,
181 gen_op_movl_T1_r2,
182 gen_op_movl_T1_r3,
183 gen_op_movl_T1_r4,
184 gen_op_movl_T1_r5,
185 gen_op_movl_T1_r6,
186 gen_op_movl_T1_r7,
187 gen_op_movl_T1_r8,
188 gen_op_movl_T1_r9,
189 gen_op_movl_T1_r10,
190 gen_op_movl_T1_r11,
191 gen_op_movl_T1_r12,
192 gen_op_movl_T1_r13,
193 gen_op_movl_T1_r14,
194 gen_op_movl_T1_r15,
197 gen_op_movl_T2_r0,
198 gen_op_movl_T2_r1,
199 gen_op_movl_T2_r2,
200 gen_op_movl_T2_r3,
201 gen_op_movl_T2_r4,
202 gen_op_movl_T2_r5,
203 gen_op_movl_T2_r6,
204 gen_op_movl_T2_r7,
205 gen_op_movl_T2_r8,
206 gen_op_movl_T2_r9,
207 gen_op_movl_T2_r10,
208 gen_op_movl_T2_r11,
209 gen_op_movl_T2_r12,
210 gen_op_movl_T2_r13,
211 gen_op_movl_T2_r14,
212 gen_op_movl_T2_r15,
216 static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
218 gen_op_movl_r0_T0,
219 gen_op_movl_r1_T0,
220 gen_op_movl_r2_T0,
221 gen_op_movl_r3_T0,
222 gen_op_movl_r4_T0,
223 gen_op_movl_r5_T0,
224 gen_op_movl_r6_T0,
225 gen_op_movl_r7_T0,
226 gen_op_movl_r8_T0,
227 gen_op_movl_r9_T0,
228 gen_op_movl_r10_T0,
229 gen_op_movl_r11_T0,
230 gen_op_movl_r12_T0,
231 gen_op_movl_r13_T0,
232 gen_op_movl_r14_T0,
233 gen_op_movl_r15_T0,
236 gen_op_movl_r0_T1,
237 gen_op_movl_r1_T1,
238 gen_op_movl_r2_T1,
239 gen_op_movl_r3_T1,
240 gen_op_movl_r4_T1,
241 gen_op_movl_r5_T1,
242 gen_op_movl_r6_T1,
243 gen_op_movl_r7_T1,
244 gen_op_movl_r8_T1,
245 gen_op_movl_r9_T1,
246 gen_op_movl_r10_T1,
247 gen_op_movl_r11_T1,
248 gen_op_movl_r12_T1,
249 gen_op_movl_r13_T1,
250 gen_op_movl_r14_T1,
251 gen_op_movl_r15_T1,
255 static GenOpFunc1 *gen_op_movl_TN_im[3] = {
256 gen_op_movl_T0_im,
257 gen_op_movl_T1_im,
258 gen_op_movl_T2_im,
261 static GenOpFunc1 *gen_shift_T0_im_thumb[3] = {
262 gen_op_shll_T0_im_thumb,
263 gen_op_shrl_T0_im_thumb,
264 gen_op_sarl_T0_im_thumb,
267 static inline void gen_bx(DisasContext *s)
269 s->is_jmp = DISAS_UPDATE;
270 gen_op_bx_T0();
273 static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
275 int val;
277 if (reg == 15) {
278 /* normaly, since we updated PC, we need only to add one insn */
279 if (s->thumb)
280 val = (long)s->pc + 2;
281 else
282 val = (long)s->pc + 4;
283 gen_op_movl_TN_im[t](val);
284 } else {
285 gen_op_movl_TN_reg[t][reg]();
289 static inline void gen_movl_T0_reg(DisasContext *s, int reg)
291 gen_movl_TN_reg(s, reg, 0);
294 static inline void gen_movl_T1_reg(DisasContext *s, int reg)
296 gen_movl_TN_reg(s, reg, 1);
299 static inline void gen_movl_T2_reg(DisasContext *s, int reg)
301 gen_movl_TN_reg(s, reg, 2);
304 static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
306 gen_op_movl_reg_TN[t][reg]();
307 if (reg == 15) {
308 s->is_jmp = DISAS_JUMP;
312 static inline void gen_movl_reg_T0(DisasContext *s, int reg)
314 gen_movl_reg_TN(s, reg, 0);
317 static inline void gen_movl_reg_T1(DisasContext *s, int reg)
319 gen_movl_reg_TN(s, reg, 1);
322 static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
324 int val, rm, shift, shiftop;
326 if (!(insn & (1 << 25))) {
327 /* immediate */
328 val = insn & 0xfff;
329 if (!(insn & (1 << 23)))
330 val = -val;
331 if (val != 0)
332 gen_op_addl_T1_im(val);
333 } else {
334 /* shift/register */
335 rm = (insn) & 0xf;
336 shift = (insn >> 7) & 0x1f;
337 gen_movl_T2_reg(s, rm);
338 shiftop = (insn >> 5) & 3;
339 if (shift != 0) {
340 gen_shift_T2_im[shiftop](shift);
341 } else if (shiftop != 0) {
342 gen_shift_T2_0[shiftop]();
344 if (!(insn & (1 << 23)))
345 gen_op_subl_T1_T2();
346 else
347 gen_op_addl_T1_T2();
351 static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn)
353 int val, rm;
355 if (insn & (1 << 22)) {
356 /* immediate */
357 val = (insn & 0xf) | ((insn >> 4) & 0xf0);
358 if (!(insn & (1 << 23)))
359 val = -val;
360 if (val != 0)
361 gen_op_addl_T1_im(val);
362 } else {
363 /* register */
364 rm = (insn) & 0xf;
365 gen_movl_T2_reg(s, rm);
366 if (!(insn & (1 << 23)))
367 gen_op_subl_T1_T2();
368 else
369 gen_op_addl_T1_T2();
373 #define VFP_OP(name) \
374 static inline void gen_vfp_##name(int dp) \
376 if (dp) \
377 gen_op_vfp_##name##d(); \
378 else \
379 gen_op_vfp_##name##s(); \
382 VFP_OP(add)
383 VFP_OP(sub)
384 VFP_OP(mul)
385 VFP_OP(div)
386 VFP_OP(neg)
387 VFP_OP(abs)
388 VFP_OP(sqrt)
389 VFP_OP(cmp)
390 VFP_OP(cmpe)
391 VFP_OP(F1_ld0)
392 VFP_OP(uito)
393 VFP_OP(sito)
394 VFP_OP(toui)
395 VFP_OP(touiz)
396 VFP_OP(tosi)
397 VFP_OP(tosiz)
398 VFP_OP(ld)
399 VFP_OP(st)
401 #undef VFP_OP
403 static inline long
404 vfp_reg_offset (int dp, int reg)
406 if (dp)
407 return offsetof(CPUARMState, vfp.regs[reg]);
408 else if (reg & 1) {
409 return offsetof(CPUARMState, vfp.regs[reg >> 1])
410 + offsetof(CPU_DoubleU, l.upper);
411 } else {
412 return offsetof(CPUARMState, vfp.regs[reg >> 1])
413 + offsetof(CPU_DoubleU, l.lower);
416 static inline void gen_mov_F0_vreg(int dp, int reg)
418 if (dp)
419 gen_op_vfp_getreg_F0d(vfp_reg_offset(dp, reg));
420 else
421 gen_op_vfp_getreg_F0s(vfp_reg_offset(dp, reg));
424 static inline void gen_mov_F1_vreg(int dp, int reg)
426 if (dp)
427 gen_op_vfp_getreg_F1d(vfp_reg_offset(dp, reg));
428 else
429 gen_op_vfp_getreg_F1s(vfp_reg_offset(dp, reg));
432 static inline void gen_mov_vreg_F0(int dp, int reg)
434 if (dp)
435 gen_op_vfp_setreg_F0d(vfp_reg_offset(dp, reg));
436 else
437 gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
440 /* Disassemble a VFP instruction. Returns nonzero if an error occured
441 (ie. an undefined instruction). */
442 static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
444 uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
445 int dp, veclen;
447 dp = ((insn & 0xf00) == 0xb00);
448 switch ((insn >> 24) & 0xf) {
449 case 0xe:
450 if (insn & (1 << 4)) {
451 /* single register transfer */
452 if ((insn & 0x6f) != 0x00)
453 return 1;
454 rd = (insn >> 12) & 0xf;
455 if (dp) {
456 if (insn & 0x80)
457 return 1;
458 rn = (insn >> 16) & 0xf;
459 /* Get the existing value even for arm->vfp moves because
460 we only set half the register. */
461 gen_mov_F0_vreg(1, rn);
462 gen_op_vfp_mrrd();
463 if (insn & (1 << 20)) {
464 /* vfp->arm */
465 if (insn & (1 << 21))
466 gen_movl_reg_T1(s, rd);
467 else
468 gen_movl_reg_T0(s, rd);
469 } else {
470 /* arm->vfp */
471 if (insn & (1 << 21))
472 gen_movl_T1_reg(s, rd);
473 else
474 gen_movl_T0_reg(s, rd);
475 gen_op_vfp_mdrr();
476 gen_mov_vreg_F0(dp, rn);
478 } else {
479 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
480 if (insn & (1 << 20)) {
481 /* vfp->arm */
482 if (insn & (1 << 21)) {
483 /* system register */
484 switch (rn) {
485 case 0: /* fpsid */
486 n = 0x0091A0000;
487 break;
488 case 2: /* fpscr */
489 if (rd == 15)
490 gen_op_vfp_movl_T0_fpscr_flags();
491 else
492 gen_op_vfp_movl_T0_fpscr();
493 break;
494 default:
495 return 1;
497 } else {
498 gen_mov_F0_vreg(0, rn);
499 gen_op_vfp_mrs();
501 if (rd == 15) {
502 /* This will only set the 4 flag bits */
503 gen_op_movl_psr_T0();
504 } else
505 gen_movl_reg_T0(s, rd);
506 } else {
507 /* arm->vfp */
508 gen_movl_T0_reg(s, rd);
509 if (insn & (1 << 21)) {
510 /* system register */
511 switch (rn) {
512 case 0: /* fpsid */
513 /* Writes are ignored. */
514 break;
515 case 2: /* fpscr */
516 gen_op_vfp_movl_fpscr_T0();
517 /* This could change vector settings, so jump to
518 the next instuction. */
519 gen_op_movl_T0_im(s->pc);
520 gen_movl_reg_T0(s, 15);
521 s->is_jmp = DISAS_UPDATE;
522 break;
523 default:
524 return 1;
526 } else {
527 gen_op_vfp_msr();
528 gen_mov_vreg_F0(0, rn);
532 } else {
533 /* data processing */
534 /* The opcode is in bits 23, 21, 20 and 6. */
535 op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
536 if (dp) {
537 if (op == 15) {
538 /* rn is opcode */
539 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
540 } else {
541 /* rn is register number */
542 if (insn & (1 << 7))
543 return 1;
544 rn = (insn >> 16) & 0xf;
547 if (op == 15 && (rn == 15 || rn > 17)) {
548 /* Integer or single precision destination. */
549 rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
550 } else {
551 if (insn & (1 << 22))
552 return 1;
553 rd = (insn >> 12) & 0xf;
556 if (op == 15 && (rn == 16 || rn == 17)) {
557 /* Integer source. */
558 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
559 } else {
560 if (insn & (1 << 5))
561 return 1;
562 rm = insn & 0xf;
564 } else {
565 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
566 if (op == 15 && rn == 15) {
567 /* Double precision destination. */
568 if (insn & (1 << 22))
569 return 1;
570 rd = (insn >> 12) & 0xf;
571 } else
572 rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
573 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
576 veclen = env->vfp.vec_len;
577 if (op == 15 && rn > 3)
578 veclen = 0;
580 /* Shut up compiler warnings. */
581 delta_m = 0;
582 delta_d = 0;
583 bank_mask = 0;
585 if (veclen > 0) {
586 if (dp)
587 bank_mask = 0xc;
588 else
589 bank_mask = 0x18;
591 /* Figure out what type of vector operation this is. */
592 if ((rd & bank_mask) == 0) {
593 /* scalar */
594 veclen = 0;
595 } else {
596 if (dp)
597 delta_d = (env->vfp.vec_stride >> 1) + 1;
598 else
599 delta_d = env->vfp.vec_stride + 1;
601 if ((rm & bank_mask) == 0) {
602 /* mixed scalar/vector */
603 delta_m = 0;
604 } else {
605 /* vector */
606 delta_m = delta_d;
611 /* Load the initial operands. */
612 if (op == 15) {
613 switch (rn) {
614 case 16:
615 case 17:
616 /* Integer source */
617 gen_mov_F0_vreg(0, rm);
618 break;
619 case 8:
620 case 9:
621 /* Compare */
622 gen_mov_F0_vreg(dp, rd);
623 gen_mov_F1_vreg(dp, rm);
624 break;
625 case 10:
626 case 11:
627 /* Compare with zero */
628 gen_mov_F0_vreg(dp, rd);
629 gen_vfp_F1_ld0(dp);
630 break;
631 default:
632 /* One source operand. */
633 gen_mov_F0_vreg(dp, rm);
635 } else {
636 /* Two source operands. */
637 gen_mov_F0_vreg(dp, rn);
638 gen_mov_F1_vreg(dp, rm);
641 for (;;) {
642 /* Perform the calculation. */
643 switch (op) {
644 case 0: /* mac: fd + (fn * fm) */
645 gen_vfp_mul(dp);
646 gen_mov_F1_vreg(dp, rd);
647 gen_vfp_add(dp);
648 break;
649 case 1: /* nmac: fd - (fn * fm) */
650 gen_vfp_mul(dp);
651 gen_vfp_neg(dp);
652 gen_mov_F1_vreg(dp, rd);
653 gen_vfp_add(dp);
654 break;
655 case 2: /* msc: -fd + (fn * fm) */
656 gen_vfp_mul(dp);
657 gen_mov_F1_vreg(dp, rd);
658 gen_vfp_sub(dp);
659 break;
660 case 3: /* nmsc: -fd - (fn * fm) */
661 gen_vfp_mul(dp);
662 gen_mov_F1_vreg(dp, rd);
663 gen_vfp_add(dp);
664 gen_vfp_neg(dp);
665 break;
666 case 4: /* mul: fn * fm */
667 gen_vfp_mul(dp);
668 break;
669 case 5: /* nmul: -(fn * fm) */
670 gen_vfp_mul(dp);
671 gen_vfp_neg(dp);
672 break;
673 case 6: /* add: fn + fm */
674 gen_vfp_add(dp);
675 break;
676 case 7: /* sub: fn - fm */
677 gen_vfp_sub(dp);
678 break;
679 case 8: /* div: fn / fm */
680 gen_vfp_div(dp);
681 break;
682 case 15: /* extension space */
683 switch (rn) {
684 case 0: /* cpy */
685 /* no-op */
686 break;
687 case 1: /* abs */
688 gen_vfp_abs(dp);
689 break;
690 case 2: /* neg */
691 gen_vfp_neg(dp);
692 break;
693 case 3: /* sqrt */
694 gen_vfp_sqrt(dp);
695 break;
696 case 8: /* cmp */
697 gen_vfp_cmp(dp);
698 break;
699 case 9: /* cmpe */
700 gen_vfp_cmpe(dp);
701 break;
702 case 10: /* cmpz */
703 gen_vfp_cmp(dp);
704 break;
705 case 11: /* cmpez */
706 gen_vfp_F1_ld0(dp);
707 gen_vfp_cmpe(dp);
708 break;
709 case 15: /* single<->double conversion */
710 if (dp)
711 gen_op_vfp_fcvtsd();
712 else
713 gen_op_vfp_fcvtds();
714 break;
715 case 16: /* fuito */
716 gen_vfp_uito(dp);
717 break;
718 case 17: /* fsito */
719 gen_vfp_sito(dp);
720 break;
721 case 24: /* ftoui */
722 gen_vfp_toui(dp);
723 break;
724 case 25: /* ftouiz */
725 gen_vfp_touiz(dp);
726 break;
727 case 26: /* ftosi */
728 gen_vfp_tosi(dp);
729 break;
730 case 27: /* ftosiz */
731 gen_vfp_tosiz(dp);
732 break;
733 default: /* undefined */
734 printf ("rn:%d\n", rn);
735 return 1;
737 break;
738 default: /* undefined */
739 printf ("op:%d\n", op);
740 return 1;
743 /* Write back the result. */
744 if (op == 15 && (rn >= 8 && rn <= 11))
745 ; /* Comparison, do nothing. */
746 else if (op == 15 && rn > 17)
747 /* Integer result. */
748 gen_mov_vreg_F0(0, rd);
749 else if (op == 15 && rn == 15)
750 /* conversion */
751 gen_mov_vreg_F0(!dp, rd);
752 else
753 gen_mov_vreg_F0(dp, rd);
755 /* break out of the loop if we have finished */
756 if (veclen == 0)
757 break;
759 if (op == 15 && delta_m == 0) {
760 /* single source one-many */
761 while (veclen--) {
762 rd = ((rd + delta_d) & (bank_mask - 1))
763 | (rd & bank_mask);
764 gen_mov_vreg_F0(dp, rd);
766 break;
768 /* Setup the next operands. */
769 veclen--;
770 rd = ((rd + delta_d) & (bank_mask - 1))
771 | (rd & bank_mask);
773 if (op == 15) {
774 /* One source operand. */
775 rm = ((rm + delta_m) & (bank_mask - 1))
776 | (rm & bank_mask);
777 gen_mov_F0_vreg(dp, rm);
778 } else {
779 /* Two source operands. */
780 rn = ((rn + delta_d) & (bank_mask - 1))
781 | (rn & bank_mask);
782 gen_mov_F0_vreg(dp, rn);
783 if (delta_m) {
784 rm = ((rm + delta_m) & (bank_mask - 1))
785 | (rm & bank_mask);
786 gen_mov_F1_vreg(dp, rm);
791 break;
792 case 0xc:
793 case 0xd:
794 if (dp && (insn & (1 << 22))) {
795 /* two-register transfer */
796 rn = (insn >> 16) & 0xf;
797 rd = (insn >> 12) & 0xf;
798 if (dp) {
799 if (insn & (1 << 5))
800 return 1;
801 rm = insn & 0xf;
802 } else
803 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
805 if (insn & (1 << 20)) {
806 /* vfp->arm */
807 if (dp) {
808 gen_mov_F0_vreg(1, rm);
809 gen_op_vfp_mrrd();
810 gen_movl_reg_T0(s, rd);
811 gen_movl_reg_T1(s, rn);
812 } else {
813 gen_mov_F0_vreg(0, rm);
814 gen_op_vfp_mrs();
815 gen_movl_reg_T0(s, rn);
816 gen_mov_F0_vreg(0, rm + 1);
817 gen_op_vfp_mrs();
818 gen_movl_reg_T0(s, rd);
820 } else {
821 /* arm->vfp */
822 if (dp) {
823 gen_movl_T0_reg(s, rd);
824 gen_movl_T1_reg(s, rn);
825 gen_op_vfp_mdrr();
826 gen_mov_vreg_F0(1, rm);
827 } else {
828 gen_movl_T0_reg(s, rn);
829 gen_op_vfp_msr();
830 gen_mov_vreg_F0(0, rm);
831 gen_movl_T0_reg(s, rd);
832 gen_op_vfp_msr();
833 gen_mov_vreg_F0(0, rm + 1);
836 } else {
837 /* Load/store */
838 rn = (insn >> 16) & 0xf;
839 if (dp)
840 rd = (insn >> 12) & 0xf;
841 else
842 rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
843 gen_movl_T1_reg(s, rn);
844 if ((insn & 0x01200000) == 0x01000000) {
845 /* Single load/store */
846 offset = (insn & 0xff) << 2;
847 if ((insn & (1 << 23)) == 0)
848 offset = -offset;
849 gen_op_addl_T1_im(offset);
850 if (insn & (1 << 20)) {
851 gen_vfp_ld(dp);
852 gen_mov_vreg_F0(dp, rd);
853 } else {
854 gen_mov_F0_vreg(dp, rd);
855 gen_vfp_st(dp);
857 } else {
858 /* load/store multiple */
859 if (dp)
860 n = (insn >> 1) & 0x7f;
861 else
862 n = insn & 0xff;
864 if (insn & (1 << 24)) /* pre-decrement */
865 gen_op_addl_T1_im(-((insn & 0xff) << 2));
867 if (dp)
868 offset = 8;
869 else
870 offset = 4;
871 for (i = 0; i < n; i++) {
872 if (insn & (1 << 20)) {
873 /* load */
874 gen_vfp_ld(dp);
875 gen_mov_vreg_F0(dp, rd + i);
876 } else {
877 /* store */
878 gen_mov_F0_vreg(dp, rd + i);
879 gen_vfp_st(dp);
881 gen_op_addl_T1_im(offset);
883 if (insn & (1 << 21)) {
884 /* writeback */
885 if (insn & (1 << 24))
886 offset = -offset * n;
887 else if (dp && (insn & 1))
888 offset = 4;
889 else
890 offset = 0;
892 if (offset != 0)
893 gen_op_addl_T1_im(offset);
894 gen_movl_reg_T1(s, rn);
898 break;
899 default:
900 /* Should never happen. */
901 return 1;
903 return 0;
906 static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
908 TranslationBlock *tb;
910 tb = s->tb;
911 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
912 if (n == 0)
913 gen_op_goto_tb0(TBPARAM(tb));
914 else
915 gen_op_goto_tb1(TBPARAM(tb));
916 gen_op_movl_T0_im(dest);
917 gen_op_movl_r15_T0();
918 gen_op_movl_T0_im((long)tb + n);
919 gen_op_exit_tb();
920 } else {
921 gen_op_movl_T0_im(dest);
922 gen_op_movl_r15_T0();
923 gen_op_movl_T0_0();
924 gen_op_exit_tb();
928 static inline void gen_jmp (DisasContext *s, uint32_t dest)
930 if (__builtin_expect(s->singlestep_enabled, 0)) {
931 /* An indirect jump so that we still trigger the debug exception. */
932 if (s->thumb)
933 dest |= 1;
934 gen_op_movl_T0_im(dest);
935 gen_bx(s);
936 } else {
937 gen_goto_tb(s, 0, dest);
938 s->is_jmp = DISAS_TB_JUMP;
942 static void disas_arm_insn(CPUState * env, DisasContext *s)
944 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
946 insn = ldl(s->pc);
947 s->pc += 4;
949 cond = insn >> 28;
950 if (cond == 0xf){
951 /* Unconditional instructions. */
952 if ((insn & 0x0d70f000) == 0x0550f000)
953 return; /* PLD */
954 else if ((insn & 0x0e000000) == 0x0a000000) {
955 /* branch link and change to thumb (blx <offset>) */
956 int32_t offset;
958 val = (uint32_t)s->pc;
959 gen_op_movl_T0_im(val);
960 gen_movl_reg_T0(s, 14);
961 /* Sign-extend the 24-bit offset */
962 offset = (((int32_t)insn) << 8) >> 8;
963 /* offset * 4 + bit24 * 2 + (thumb bit) */
964 val += (offset << 2) | ((insn >> 23) & 2) | 1;
965 /* pipeline offset */
966 val += 4;
967 gen_op_movl_T0_im(val);
968 gen_bx(s);
969 return;
970 } else if ((insn & 0x0fe00000) == 0x0c400000) {
971 /* Coprocessor double register transfer. */
972 } else if ((insn & 0x0f000010) == 0x0e000010) {
973 /* Additional coprocessor register transfer. */
975 goto illegal_op;
977 if (cond != 0xe) {
978 /* if not always execute, we generate a conditional jump to
979 next instruction */
980 s->condlabel = gen_new_label();
981 gen_test_cc[cond ^ 1](s->condlabel);
982 s->condjmp = 1;
983 //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
984 //s->is_jmp = DISAS_JUMP_NEXT;
986 if ((insn & 0x0f900000) == 0x03000000) {
987 if ((insn & 0x0ff0f000) != 0x0360f000)
988 goto illegal_op;
989 /* CPSR = immediate */
990 val = insn & 0xff;
991 shift = ((insn >> 8) & 0xf) * 2;
992 if (shift)
993 val = (val >> shift) | (val << (32 - shift));
994 gen_op_movl_T0_im(val);
995 if (insn & (1 << 19))
996 gen_op_movl_psr_T0();
997 } else if ((insn & 0x0f900000) == 0x01000000
998 && (insn & 0x00000090) != 0x00000090) {
999 /* miscellaneous instructions */
1000 op1 = (insn >> 21) & 3;
1001 sh = (insn >> 4) & 0xf;
1002 rm = insn & 0xf;
1003 switch (sh) {
1004 case 0x0: /* move program status register */
1005 if (op1 & 2) {
1006 /* SPSR not accessible in user mode */
1007 goto illegal_op;
1009 if (op1 & 1) {
1010 /* CPSR = reg */
1011 gen_movl_T0_reg(s, rm);
1012 if (insn & (1 << 19))
1013 gen_op_movl_psr_T0();
1014 } else {
1015 /* reg = CPSR */
1016 rd = (insn >> 12) & 0xf;
1017 gen_op_movl_T0_psr();
1018 gen_movl_reg_T0(s, rd);
1020 break;
1021 case 0x1:
1022 if (op1 == 1) {
1023 /* branch/exchange thumb (bx). */
1024 gen_movl_T0_reg(s, rm);
1025 gen_bx(s);
1026 } else if (op1 == 3) {
1027 /* clz */
1028 rd = (insn >> 12) & 0xf;
1029 gen_movl_T0_reg(s, rm);
1030 gen_op_clz_T0();
1031 gen_movl_reg_T0(s, rd);
1032 } else {
1033 goto illegal_op;
1035 break;
1036 case 0x3:
1037 if (op1 != 1)
1038 goto illegal_op;
1040 /* branch link/exchange thumb (blx) */
1041 val = (uint32_t)s->pc;
1042 gen_op_movl_T0_im(val);
1043 gen_movl_reg_T0(s, 14);
1044 gen_movl_T0_reg(s, rm);
1045 gen_bx(s);
1046 break;
1047 case 0x5: /* saturating add/subtract */
1048 rd = (insn >> 12) & 0xf;
1049 rn = (insn >> 16) & 0xf;
1050 gen_movl_T0_reg(s, rm);
1051 gen_movl_T1_reg(s, rn);
1052 if (op1 & 2)
1053 gen_op_double_T1_saturate();
1054 if (op1 & 1)
1055 gen_op_subl_T0_T1_saturate();
1056 else
1057 gen_op_addl_T0_T1_saturate();
1058 gen_movl_reg_T0(s, rd);
1059 break;
1060 case 0x8: /* signed multiply */
1061 case 0xa:
1062 case 0xc:
1063 case 0xe:
1064 rs = (insn >> 8) & 0xf;
1065 rn = (insn >> 12) & 0xf;
1066 rd = (insn >> 16) & 0xf;
1067 if (op1 == 1) {
1068 /* (32 * 16) >> 16 */
1069 gen_movl_T0_reg(s, rm);
1070 gen_movl_T1_reg(s, rs);
1071 if (sh & 4)
1072 gen_op_sarl_T1_im(16);
1073 else
1074 gen_op_sxl_T1();
1075 gen_op_imulw_T0_T1();
1076 if ((sh & 2) == 0) {
1077 gen_movl_T1_reg(s, rn);
1078 gen_op_addl_T0_T1_setq();
1080 gen_movl_reg_T0(s, rd);
1081 } else {
1082 /* 16 * 16 */
1083 gen_movl_T0_reg(s, rm);
1084 if (sh & 2)
1085 gen_op_sarl_T0_im(16);
1086 else
1087 gen_op_sxl_T0();
1088 gen_movl_T1_reg(s, rs);
1089 if (sh & 4)
1090 gen_op_sarl_T1_im(16);
1091 else
1092 gen_op_sxl_T1();
1093 if (op1 == 2) {
1094 gen_op_imull_T0_T1();
1095 gen_op_addq_T0_T1(rn, rd);
1096 gen_movl_reg_T0(s, rn);
1097 gen_movl_reg_T1(s, rd);
1098 } else {
1099 gen_op_mul_T0_T1();
1100 if (op1 == 0) {
1101 gen_movl_T1_reg(s, rn);
1102 gen_op_addl_T0_T1_setq();
1104 gen_movl_reg_T0(s, rd);
1107 break;
1108 default:
1109 goto illegal_op;
1111 } else if (((insn & 0x0e000000) == 0 &&
1112 (insn & 0x00000090) != 0x90) ||
1113 ((insn & 0x0e000000) == (1 << 25))) {
1114 int set_cc, logic_cc, shiftop;
1116 op1 = (insn >> 21) & 0xf;
1117 set_cc = (insn >> 20) & 1;
1118 logic_cc = table_logic_cc[op1] & set_cc;
1120 /* data processing instruction */
1121 if (insn & (1 << 25)) {
1122 /* immediate operand */
1123 val = insn & 0xff;
1124 shift = ((insn >> 8) & 0xf) * 2;
1125 if (shift)
1126 val = (val >> shift) | (val << (32 - shift));
1127 gen_op_movl_T1_im(val);
1128 if (logic_cc && shift)
1129 gen_op_mov_CF_T1();
1130 } else {
1131 /* register */
1132 rm = (insn) & 0xf;
1133 gen_movl_T1_reg(s, rm);
1134 shiftop = (insn >> 5) & 3;
1135 if (!(insn & (1 << 4))) {
1136 shift = (insn >> 7) & 0x1f;
1137 if (shift != 0) {
1138 if (logic_cc) {
1139 gen_shift_T1_im_cc[shiftop](shift);
1140 } else {
1141 gen_shift_T1_im[shiftop](shift);
1143 } else if (shiftop != 0) {
1144 if (logic_cc) {
1145 gen_shift_T1_0_cc[shiftop]();
1146 } else {
1147 gen_shift_T1_0[shiftop]();
1150 } else {
1151 rs = (insn >> 8) & 0xf;
1152 gen_movl_T0_reg(s, rs);
1153 if (logic_cc) {
1154 gen_shift_T1_T0_cc[shiftop]();
1155 } else {
1156 gen_shift_T1_T0[shiftop]();
1160 if (op1 != 0x0f && op1 != 0x0d) {
1161 rn = (insn >> 16) & 0xf;
1162 gen_movl_T0_reg(s, rn);
1164 rd = (insn >> 12) & 0xf;
1165 switch(op1) {
1166 case 0x00:
1167 gen_op_andl_T0_T1();
1168 gen_movl_reg_T0(s, rd);
1169 if (logic_cc)
1170 gen_op_logic_T0_cc();
1171 break;
1172 case 0x01:
1173 gen_op_xorl_T0_T1();
1174 gen_movl_reg_T0(s, rd);
1175 if (logic_cc)
1176 gen_op_logic_T0_cc();
1177 break;
1178 case 0x02:
1179 if (set_cc)
1180 gen_op_subl_T0_T1_cc();
1181 else
1182 gen_op_subl_T0_T1();
1183 gen_movl_reg_T0(s, rd);
1184 break;
1185 case 0x03:
1186 if (set_cc)
1187 gen_op_rsbl_T0_T1_cc();
1188 else
1189 gen_op_rsbl_T0_T1();
1190 gen_movl_reg_T0(s, rd);
1191 break;
1192 case 0x04:
1193 if (set_cc)
1194 gen_op_addl_T0_T1_cc();
1195 else
1196 gen_op_addl_T0_T1();
1197 gen_movl_reg_T0(s, rd);
1198 break;
1199 case 0x05:
1200 if (set_cc)
1201 gen_op_adcl_T0_T1_cc();
1202 else
1203 gen_op_adcl_T0_T1();
1204 gen_movl_reg_T0(s, rd);
1205 break;
1206 case 0x06:
1207 if (set_cc)
1208 gen_op_sbcl_T0_T1_cc();
1209 else
1210 gen_op_sbcl_T0_T1();
1211 gen_movl_reg_T0(s, rd);
1212 break;
1213 case 0x07:
1214 if (set_cc)
1215 gen_op_rscl_T0_T1_cc();
1216 else
1217 gen_op_rscl_T0_T1();
1218 gen_movl_reg_T0(s, rd);
1219 break;
1220 case 0x08:
1221 if (set_cc) {
1222 gen_op_andl_T0_T1();
1223 gen_op_logic_T0_cc();
1225 break;
1226 case 0x09:
1227 if (set_cc) {
1228 gen_op_xorl_T0_T1();
1229 gen_op_logic_T0_cc();
1231 break;
1232 case 0x0a:
1233 if (set_cc) {
1234 gen_op_subl_T0_T1_cc();
1236 break;
1237 case 0x0b:
1238 if (set_cc) {
1239 gen_op_addl_T0_T1_cc();
1241 break;
1242 case 0x0c:
1243 gen_op_orl_T0_T1();
1244 gen_movl_reg_T0(s, rd);
1245 if (logic_cc)
1246 gen_op_logic_T0_cc();
1247 break;
1248 case 0x0d:
1249 gen_movl_reg_T1(s, rd);
1250 if (logic_cc)
1251 gen_op_logic_T1_cc();
1252 break;
1253 case 0x0e:
1254 gen_op_bicl_T0_T1();
1255 gen_movl_reg_T0(s, rd);
1256 if (logic_cc)
1257 gen_op_logic_T0_cc();
1258 break;
1259 default:
1260 case 0x0f:
1261 gen_op_notl_T1();
1262 gen_movl_reg_T1(s, rd);
1263 if (logic_cc)
1264 gen_op_logic_T1_cc();
1265 break;
1267 } else {
1268 /* other instructions */
1269 op1 = (insn >> 24) & 0xf;
1270 switch(op1) {
1271 case 0x0:
1272 case 0x1:
1273 /* multiplies, extra load/stores */
1274 sh = (insn >> 5) & 3;
1275 if (sh == 0) {
1276 if (op1 == 0x0) {
1277 rd = (insn >> 16) & 0xf;
1278 rn = (insn >> 12) & 0xf;
1279 rs = (insn >> 8) & 0xf;
1280 rm = (insn) & 0xf;
1281 if (((insn >> 22) & 3) == 0) {
1282 /* 32 bit mul */
1283 gen_movl_T0_reg(s, rs);
1284 gen_movl_T1_reg(s, rm);
1285 gen_op_mul_T0_T1();
1286 if (insn & (1 << 21)) {
1287 gen_movl_T1_reg(s, rn);
1288 gen_op_addl_T0_T1();
1290 if (insn & (1 << 20))
1291 gen_op_logic_T0_cc();
1292 gen_movl_reg_T0(s, rd);
1293 } else {
1294 /* 64 bit mul */
1295 gen_movl_T0_reg(s, rs);
1296 gen_movl_T1_reg(s, rm);
1297 if (insn & (1 << 22))
1298 gen_op_imull_T0_T1();
1299 else
1300 gen_op_mull_T0_T1();
1301 if (insn & (1 << 21)) /* mult accumulate */
1302 gen_op_addq_T0_T1(rn, rd);
1303 if (!(insn & (1 << 23))) { /* double accumulate */
1304 gen_op_addq_lo_T0_T1(rn);
1305 gen_op_addq_lo_T0_T1(rd);
1307 if (insn & (1 << 20))
1308 gen_op_logicq_cc();
1309 gen_movl_reg_T0(s, rn);
1310 gen_movl_reg_T1(s, rd);
1312 } else {
1313 rn = (insn >> 16) & 0xf;
1314 rd = (insn >> 12) & 0xf;
1315 if (insn & (1 << 23)) {
1316 /* load/store exclusive */
1317 goto illegal_op;
1318 } else {
1319 /* SWP instruction */
1320 rm = (insn) & 0xf;
1322 gen_movl_T0_reg(s, rm);
1323 gen_movl_T1_reg(s, rn);
1324 if (insn & (1 << 22)) {
1325 gen_op_swpb_T0_T1();
1326 } else {
1327 gen_op_swpl_T0_T1();
1329 gen_movl_reg_T0(s, rd);
1332 } else {
1333 /* Misc load/store */
1334 rn = (insn >> 16) & 0xf;
1335 rd = (insn >> 12) & 0xf;
1336 gen_movl_T1_reg(s, rn);
1337 if (insn & (1 << 24))
1338 gen_add_datah_offset(s, insn);
1339 if (insn & (1 << 20)) {
1340 /* load */
1341 switch(sh) {
1342 case 1:
1343 gen_op_lduw_T0_T1();
1344 break;
1345 case 2:
1346 gen_op_ldsb_T0_T1();
1347 break;
1348 default:
1349 case 3:
1350 gen_op_ldsw_T0_T1();
1351 break;
1353 gen_movl_reg_T0(s, rd);
1354 } else if (sh & 2) {
1355 /* doubleword */
1356 if (sh & 1) {
1357 /* store */
1358 gen_movl_T0_reg(s, rd);
1359 gen_op_stl_T0_T1();
1360 gen_op_addl_T1_im(4);
1361 gen_movl_T0_reg(s, rd + 1);
1362 gen_op_stl_T0_T1();
1363 if ((insn & (1 << 24)) || (insn & (1 << 20)))
1364 gen_op_addl_T1_im(-4);
1365 } else {
1366 /* load */
1367 gen_op_ldl_T0_T1();
1368 gen_movl_reg_T0(s, rd);
1369 gen_op_addl_T1_im(4);
1370 gen_op_ldl_T0_T1();
1371 gen_movl_reg_T0(s, rd + 1);
1372 if ((insn & (1 << 24)) || (insn & (1 << 20)))
1373 gen_op_addl_T1_im(-4);
1375 } else {
1376 /* store */
1377 gen_movl_T0_reg(s, rd);
1378 gen_op_stw_T0_T1();
1380 if (!(insn & (1 << 24))) {
1381 gen_add_datah_offset(s, insn);
1382 gen_movl_reg_T1(s, rn);
1383 } else if (insn & (1 << 21)) {
1384 gen_movl_reg_T1(s, rn);
1387 break;
1388 case 0x4:
1389 case 0x5:
1390 case 0x6:
1391 case 0x7:
1392 /* load/store byte/word */
1393 rn = (insn >> 16) & 0xf;
1394 rd = (insn >> 12) & 0xf;
1395 gen_movl_T1_reg(s, rn);
1396 if (insn & (1 << 24))
1397 gen_add_data_offset(s, insn);
1398 if (insn & (1 << 20)) {
1399 /* load */
1400 if (insn & (1 << 22))
1401 gen_op_ldub_T0_T1();
1402 else
1403 gen_op_ldl_T0_T1();
1404 if (rd == 15)
1405 gen_bx(s);
1406 else
1407 gen_movl_reg_T0(s, rd);
1408 } else {
1409 /* store */
1410 gen_movl_T0_reg(s, rd);
1411 if (insn & (1 << 22))
1412 gen_op_stb_T0_T1();
1413 else
1414 gen_op_stl_T0_T1();
1416 if (!(insn & (1 << 24))) {
1417 gen_add_data_offset(s, insn);
1418 gen_movl_reg_T1(s, rn);
1419 } else if (insn & (1 << 21))
1420 gen_movl_reg_T1(s, rn); {
1422 break;
1423 case 0x08:
1424 case 0x09:
1426 int j, n;
1427 /* load/store multiple words */
1428 /* XXX: store correct base if write back */
1429 if (insn & (1 << 22))
1430 goto illegal_op; /* only usable in supervisor mode */
1431 rn = (insn >> 16) & 0xf;
1432 gen_movl_T1_reg(s, rn);
1434 /* compute total size */
1435 n = 0;
1436 for(i=0;i<16;i++) {
1437 if (insn & (1 << i))
1438 n++;
1440 /* XXX: test invalid n == 0 case ? */
1441 if (insn & (1 << 23)) {
1442 if (insn & (1 << 24)) {
1443 /* pre increment */
1444 gen_op_addl_T1_im(4);
1445 } else {
1446 /* post increment */
1448 } else {
1449 if (insn & (1 << 24)) {
1450 /* pre decrement */
1451 gen_op_addl_T1_im(-(n * 4));
1452 } else {
1453 /* post decrement */
1454 if (n != 1)
1455 gen_op_addl_T1_im(-((n - 1) * 4));
1458 j = 0;
1459 for(i=0;i<16;i++) {
1460 if (insn & (1 << i)) {
1461 if (insn & (1 << 20)) {
1462 /* load */
1463 gen_op_ldl_T0_T1();
1464 if (i == 15)
1465 gen_bx(s);
1466 else
1467 gen_movl_reg_T0(s, i);
1468 } else {
1469 /* store */
1470 if (i == 15) {
1471 /* special case: r15 = PC + 12 */
1472 val = (long)s->pc + 8;
1473 gen_op_movl_TN_im[0](val);
1474 } else {
1475 gen_movl_T0_reg(s, i);
1477 gen_op_stl_T0_T1();
1479 j++;
1480 /* no need to add after the last transfer */
1481 if (j != n)
1482 gen_op_addl_T1_im(4);
1485 if (insn & (1 << 21)) {
1486 /* write back */
1487 if (insn & (1 << 23)) {
1488 if (insn & (1 << 24)) {
1489 /* pre increment */
1490 } else {
1491 /* post increment */
1492 gen_op_addl_T1_im(4);
1494 } else {
1495 if (insn & (1 << 24)) {
1496 /* pre decrement */
1497 if (n != 1)
1498 gen_op_addl_T1_im(-((n - 1) * 4));
1499 } else {
1500 /* post decrement */
1501 gen_op_addl_T1_im(-(n * 4));
1504 gen_movl_reg_T1(s, rn);
1507 break;
1508 case 0xa:
1509 case 0xb:
1511 int32_t offset;
1513 /* branch (and link) */
1514 val = (int32_t)s->pc;
1515 if (insn & (1 << 24)) {
1516 gen_op_movl_T0_im(val);
1517 gen_op_movl_reg_TN[0][14]();
1519 offset = (((int32_t)insn << 8) >> 8);
1520 val += (offset << 2) + 4;
1521 gen_jmp(s, val);
1523 break;
1524 case 0xc:
1525 case 0xd:
1526 case 0xe:
1527 /* Coprocessor. */
1528 op1 = (insn >> 8) & 0xf;
1529 switch (op1) {
1530 case 10:
1531 case 11:
1532 if (disas_vfp_insn (env, s, insn))
1533 goto illegal_op;
1534 break;
1535 default:
1536 /* unknown coprocessor. */
1537 goto illegal_op;
1539 break;
1540 case 0xf:
1541 /* swi */
1542 gen_op_movl_T0_im((long)s->pc);
1543 gen_op_movl_reg_TN[0][15]();
1544 gen_op_swi();
1545 s->is_jmp = DISAS_JUMP;
1546 break;
1547 default:
1548 illegal_op:
1549 gen_op_movl_T0_im((long)s->pc - 4);
1550 gen_op_movl_reg_TN[0][15]();
1551 gen_op_undef_insn();
1552 s->is_jmp = DISAS_JUMP;
1553 break;
1558 static void disas_thumb_insn(DisasContext *s)
1560 uint32_t val, insn, op, rm, rn, rd, shift, cond;
1561 int32_t offset;
1562 int i;
1564 insn = lduw(s->pc);
1565 s->pc += 2;
1567 switch (insn >> 12) {
1568 case 0: case 1:
1569 rd = insn & 7;
1570 op = (insn >> 11) & 3;
1571 if (op == 3) {
1572 /* add/subtract */
1573 rn = (insn >> 3) & 7;
1574 gen_movl_T0_reg(s, rn);
1575 if (insn & (1 << 10)) {
1576 /* immediate */
1577 gen_op_movl_T1_im((insn >> 6) & 7);
1578 } else {
1579 /* reg */
1580 rm = (insn >> 6) & 7;
1581 gen_movl_T1_reg(s, rm);
1583 if (insn & (1 << 9))
1584 gen_op_subl_T0_T1_cc();
1585 else
1586 gen_op_addl_T0_T1_cc();
1587 gen_movl_reg_T0(s, rd);
1588 } else {
1589 /* shift immediate */
1590 rm = (insn >> 3) & 7;
1591 shift = (insn >> 6) & 0x1f;
1592 gen_movl_T0_reg(s, rm);
1593 gen_shift_T0_im_thumb[op](shift);
1594 gen_movl_reg_T0(s, rd);
1596 break;
1597 case 2: case 3:
1598 /* arithmetic large immediate */
1599 op = (insn >> 11) & 3;
1600 rd = (insn >> 8) & 0x7;
1601 if (op == 0) {
1602 gen_op_movl_T0_im(insn & 0xff);
1603 } else {
1604 gen_movl_T0_reg(s, rd);
1605 gen_op_movl_T1_im(insn & 0xff);
1607 switch (op) {
1608 case 0: /* mov */
1609 gen_op_logic_T0_cc();
1610 break;
1611 case 1: /* cmp */
1612 gen_op_subl_T0_T1_cc();
1613 break;
1614 case 2: /* add */
1615 gen_op_addl_T0_T1_cc();
1616 break;
1617 case 3: /* sub */
1618 gen_op_subl_T0_T1_cc();
1619 break;
1621 if (op != 1)
1622 gen_movl_reg_T0(s, rd);
1623 break;
1624 case 4:
1625 if (insn & (1 << 11)) {
1626 rd = (insn >> 8) & 7;
1627 /* load pc-relative. Bit 1 of PC is ignored. */
1628 val = s->pc + 2 + ((insn & 0xff) * 4);
1629 val &= ~(uint32_t)2;
1630 gen_op_movl_T1_im(val);
1631 gen_op_ldl_T0_T1();
1632 gen_movl_reg_T0(s, rd);
1633 break;
1635 if (insn & (1 << 10)) {
1636 /* data processing extended or blx */
1637 rd = (insn & 7) | ((insn >> 4) & 8);
1638 rm = (insn >> 3) & 0xf;
1639 op = (insn >> 8) & 3;
1640 switch (op) {
1641 case 0: /* add */
1642 gen_movl_T0_reg(s, rd);
1643 gen_movl_T1_reg(s, rm);
1644 gen_op_addl_T0_T1();
1645 gen_movl_reg_T0(s, rd);
1646 break;
1647 case 1: /* cmp */
1648 gen_movl_T0_reg(s, rd);
1649 gen_movl_T1_reg(s, rm);
1650 gen_op_subl_T0_T1_cc();
1651 break;
1652 case 2: /* mov/cpy */
1653 gen_movl_T0_reg(s, rm);
1654 gen_movl_reg_T0(s, rd);
1655 break;
1656 case 3:/* branch [and link] exchange thumb register */
1657 if (insn & (1 << 7)) {
1658 val = (uint32_t)s->pc | 1;
1659 gen_op_movl_T1_im(val);
1660 gen_movl_reg_T1(s, 14);
1662 gen_movl_T0_reg(s, rm);
1663 gen_bx(s);
1664 break;
1666 break;
1669 /* data processing register */
1670 rd = insn & 7;
1671 rm = (insn >> 3) & 7;
1672 op = (insn >> 6) & 0xf;
1673 if (op == 2 || op == 3 || op == 4 || op == 7) {
1674 /* the shift/rotate ops want the operands backwards */
1675 val = rm;
1676 rm = rd;
1677 rd = val;
1678 val = 1;
1679 } else {
1680 val = 0;
1683 if (op == 9) /* neg */
1684 gen_op_movl_T0_im(0);
1685 else if (op != 0xf) /* mvn doesn't read its first operand */
1686 gen_movl_T0_reg(s, rd);
1688 gen_movl_T1_reg(s, rm);
1689 switch (op) {
1690 case 0x0: /* and */
1691 gen_op_andl_T0_T1();
1692 gen_op_logic_T0_cc();
1693 break;
1694 case 0x1: /* eor */
1695 gen_op_xorl_T0_T1();
1696 gen_op_logic_T0_cc();
1697 break;
1698 case 0x2: /* lsl */
1699 gen_op_shll_T1_T0_cc();
1700 break;
1701 case 0x3: /* lsr */
1702 gen_op_shrl_T1_T0_cc();
1703 break;
1704 case 0x4: /* asr */
1705 gen_op_sarl_T1_T0_cc();
1706 break;
1707 case 0x5: /* adc */
1708 gen_op_adcl_T0_T1_cc();
1709 break;
1710 case 0x6: /* sbc */
1711 gen_op_sbcl_T0_T1_cc();
1712 break;
1713 case 0x7: /* ror */
1714 gen_op_rorl_T1_T0_cc();
1715 break;
1716 case 0x8: /* tst */
1717 gen_op_andl_T0_T1();
1718 gen_op_logic_T0_cc();
1719 rd = 16;
1720 break;
1721 case 0x9: /* neg */
1722 gen_op_subl_T0_T1_cc();
1723 break;
1724 case 0xa: /* cmp */
1725 gen_op_subl_T0_T1_cc();
1726 rd = 16;
1727 break;
1728 case 0xb: /* cmn */
1729 gen_op_addl_T0_T1_cc();
1730 rd = 16;
1731 break;
1732 case 0xc: /* orr */
1733 gen_op_orl_T0_T1();
1734 gen_op_logic_T0_cc();
1735 break;
1736 case 0xd: /* mul */
1737 gen_op_mull_T0_T1();
1738 gen_op_logic_T0_cc();
1739 break;
1740 case 0xe: /* bic */
1741 gen_op_bicl_T0_T1();
1742 gen_op_logic_T0_cc();
1743 break;
1744 case 0xf: /* mvn */
1745 gen_op_notl_T1();
1746 gen_op_logic_T1_cc();
1747 val = 1;
1748 rm = rd;
1749 break;
1751 if (rd != 16) {
1752 if (val)
1753 gen_movl_reg_T1(s, rm);
1754 else
1755 gen_movl_reg_T0(s, rd);
1757 break;
1759 case 5:
1760 /* load/store register offset. */
1761 rd = insn & 7;
1762 rn = (insn >> 3) & 7;
1763 rm = (insn >> 6) & 7;
1764 op = (insn >> 9) & 7;
1765 gen_movl_T1_reg(s, rn);
1766 gen_movl_T2_reg(s, rm);
1767 gen_op_addl_T1_T2();
1769 if (op < 3) /* store */
1770 gen_movl_T0_reg(s, rd);
1772 switch (op) {
1773 case 0: /* str */
1774 gen_op_stl_T0_T1();
1775 break;
1776 case 1: /* strh */
1777 gen_op_stw_T0_T1();
1778 break;
1779 case 2: /* strb */
1780 gen_op_stb_T0_T1();
1781 break;
1782 case 3: /* ldrsb */
1783 gen_op_ldsb_T0_T1();
1784 break;
1785 case 4: /* ldr */
1786 gen_op_ldl_T0_T1();
1787 break;
1788 case 5: /* ldrh */
1789 gen_op_lduw_T0_T1();
1790 break;
1791 case 6: /* ldrb */
1792 gen_op_ldub_T0_T1();
1793 break;
1794 case 7: /* ldrsh */
1795 gen_op_ldsw_T0_T1();
1796 break;
1798 if (op >= 3) /* load */
1799 gen_movl_reg_T0(s, rd);
1800 break;
1802 case 6:
1803 /* load/store word immediate offset */
1804 rd = insn & 7;
1805 rn = (insn >> 3) & 7;
1806 gen_movl_T1_reg(s, rn);
1807 val = (insn >> 4) & 0x7c;
1808 gen_op_movl_T2_im(val);
1809 gen_op_addl_T1_T2();
1811 if (insn & (1 << 11)) {
1812 /* load */
1813 gen_op_ldl_T0_T1();
1814 gen_movl_reg_T0(s, rd);
1815 } else {
1816 /* store */
1817 gen_movl_T0_reg(s, rd);
1818 gen_op_stl_T0_T1();
1820 break;
1822 case 7:
1823 /* load/store byte immediate offset */
1824 rd = insn & 7;
1825 rn = (insn >> 3) & 7;
1826 gen_movl_T1_reg(s, rn);
1827 val = (insn >> 6) & 0x1f;
1828 gen_op_movl_T2_im(val);
1829 gen_op_addl_T1_T2();
1831 if (insn & (1 << 11)) {
1832 /* load */
1833 gen_op_ldub_T0_T1();
1834 gen_movl_reg_T0(s, rd);
1835 } else {
1836 /* store */
1837 gen_movl_T0_reg(s, rd);
1838 gen_op_stb_T0_T1();
1840 break;
1842 case 8:
1843 /* load/store halfword immediate offset */
1844 rd = insn & 7;
1845 rn = (insn >> 3) & 7;
1846 gen_movl_T1_reg(s, rn);
1847 val = (insn >> 5) & 0x3e;
1848 gen_op_movl_T2_im(val);
1849 gen_op_addl_T1_T2();
1851 if (insn & (1 << 11)) {
1852 /* load */
1853 gen_op_lduw_T0_T1();
1854 gen_movl_reg_T0(s, rd);
1855 } else {
1856 /* store */
1857 gen_movl_T0_reg(s, rd);
1858 gen_op_stw_T0_T1();
1860 break;
1862 case 9:
1863 /* load/store from stack */
1864 rd = (insn >> 8) & 7;
1865 gen_movl_T1_reg(s, 13);
1866 val = (insn & 0xff) * 4;
1867 gen_op_movl_T2_im(val);
1868 gen_op_addl_T1_T2();
1870 if (insn & (1 << 11)) {
1871 /* load */
1872 gen_op_ldl_T0_T1();
1873 gen_movl_reg_T0(s, rd);
1874 } else {
1875 /* store */
1876 gen_movl_T0_reg(s, rd);
1877 gen_op_stl_T0_T1();
1879 break;
1881 case 10:
1882 /* add to high reg */
1883 rd = (insn >> 8) & 7;
1884 if (insn & (1 << 11)) {
1885 /* SP */
1886 gen_movl_T0_reg(s, 13);
1887 } else {
1888 /* PC. bit 1 is ignored. */
1889 gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2);
1891 val = (insn & 0xff) * 4;
1892 gen_op_movl_T1_im(val);
1893 gen_op_addl_T0_T1();
1894 gen_movl_reg_T0(s, rd);
1895 break;
1897 case 11:
1898 /* misc */
1899 op = (insn >> 8) & 0xf;
1900 switch (op) {
1901 case 0:
1902 /* adjust stack pointer */
1903 gen_movl_T1_reg(s, 13);
1904 val = (insn & 0x7f) * 4;
1905 if (insn & (1 << 7))
1906 val = -(int32_t)val;
1907 gen_op_movl_T2_im(val);
1908 gen_op_addl_T1_T2();
1909 gen_movl_reg_T1(s, 13);
1910 break;
1912 case 4: case 5: case 0xc: case 0xd:
1913 /* push/pop */
1914 gen_movl_T1_reg(s, 13);
1915 if (insn & (1 << 8))
1916 offset = 4;
1917 else
1918 offset = 0;
1919 for (i = 0; i < 8; i++) {
1920 if (insn & (1 << i))
1921 offset += 4;
1923 if ((insn & (1 << 11)) == 0) {
1924 gen_op_movl_T2_im(-offset);
1925 gen_op_addl_T1_T2();
1927 gen_op_movl_T2_im(4);
1928 for (i = 0; i < 8; i++) {
1929 if (insn & (1 << i)) {
1930 if (insn & (1 << 11)) {
1931 /* pop */
1932 gen_op_ldl_T0_T1();
1933 gen_movl_reg_T0(s, i);
1934 } else {
1935 /* push */
1936 gen_movl_T0_reg(s, i);
1937 gen_op_stl_T0_T1();
1939 /* advance to the next address. */
1940 gen_op_addl_T1_T2();
1943 if (insn & (1 << 8)) {
1944 if (insn & (1 << 11)) {
1945 /* pop pc */
1946 gen_op_ldl_T0_T1();
1947 /* don't set the pc until the rest of the instruction
1948 has completed */
1949 } else {
1950 /* push lr */
1951 gen_movl_T0_reg(s, 14);
1952 gen_op_stl_T0_T1();
1954 gen_op_addl_T1_T2();
1956 if ((insn & (1 << 11)) == 0) {
1957 gen_op_movl_T2_im(-offset);
1958 gen_op_addl_T1_T2();
1960 /* write back the new stack pointer */
1961 gen_movl_reg_T1(s, 13);
1962 /* set the new PC value */
1963 if ((insn & 0x0900) == 0x0900)
1964 gen_bx(s);
1965 break;
1967 default:
1968 goto undef;
1970 break;
1972 case 12:
1973 /* load/store multiple */
1974 rn = (insn >> 8) & 0x7;
1975 gen_movl_T1_reg(s, rn);
1976 gen_op_movl_T2_im(4);
1977 for (i = 0; i < 8; i++) {
1978 if (insn & (1 << i)) {
1979 if (insn & (1 << 11)) {
1980 /* load */
1981 gen_op_ldl_T0_T1();
1982 gen_movl_reg_T0(s, i);
1983 } else {
1984 /* store */
1985 gen_movl_T0_reg(s, i);
1986 gen_op_stl_T0_T1();
1988 /* advance to the next address */
1989 gen_op_addl_T1_T2();
1992 /* Base register writeback. */
1993 gen_movl_reg_T1(s, rn);
1994 break;
1996 case 13:
1997 /* conditional branch or swi */
1998 cond = (insn >> 8) & 0xf;
1999 if (cond == 0xe)
2000 goto undef;
2002 if (cond == 0xf) {
2003 /* swi */
2004 gen_op_movl_T0_im((long)s->pc | 1);
2005 /* Don't set r15. */
2006 gen_op_movl_reg_TN[0][15]();
2007 gen_op_swi();
2008 s->is_jmp = DISAS_JUMP;
2009 break;
2011 /* generate a conditional jump to next instruction */
2012 s->condlabel = gen_new_label();
2013 gen_test_cc[cond ^ 1](s->condlabel);
2014 s->condjmp = 1;
2015 //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
2016 //s->is_jmp = DISAS_JUMP_NEXT;
2017 gen_movl_T1_reg(s, 15);
2019 /* jump to the offset */
2020 val = (uint32_t)s->pc + 2;
2021 offset = ((int32_t)insn << 24) >> 24;
2022 val += offset << 1;
2023 gen_jmp(s, val);
2024 break;
2026 case 14:
2027 /* unconditional branch */
2028 if (insn & (1 << 11))
2029 goto undef; /* Second half of a blx */
2030 val = (uint32_t)s->pc;
2031 offset = ((int32_t)insn << 21) >> 21;
2032 val += (offset << 1) + 2;
2033 gen_jmp(s, val);
2034 break;
2036 case 15:
2037 /* branch and link [and switch to arm] */
2038 offset = ((int32_t)insn << 21) >> 10;
2039 insn = lduw(s->pc);
2040 offset |= insn & 0x7ff;
2042 val = (uint32_t)s->pc + 2;
2043 gen_op_movl_T1_im(val | 1);
2044 gen_movl_reg_T1(s, 14);
2046 val += offset << 1;
2047 if (insn & (1 << 12)) {
2048 /* bl */
2049 gen_jmp(s, val);
2050 } else {
2051 /* blx */
2052 val &= ~(uint32_t)2;
2053 gen_op_movl_T0_im(val);
2054 gen_bx(s);
2057 return;
2058 undef:
2059 gen_op_movl_T0_im((long)s->pc - 2);
2060 gen_op_movl_reg_TN[0][15]();
2061 gen_op_undef_insn();
2062 s->is_jmp = DISAS_JUMP;
2065 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
2066 basic block 'tb'. If search_pc is TRUE, also generate PC
2067 information for each intermediate instruction. */
2068 static inline int gen_intermediate_code_internal(CPUState *env,
2069 TranslationBlock *tb,
2070 int search_pc)
2072 DisasContext dc1, *dc = &dc1;
2073 uint16_t *gen_opc_end;
2074 int j, lj;
2075 target_ulong pc_start;
2077 /* generate intermediate code */
2078 pc_start = tb->pc;
2080 dc->tb = tb;
2082 gen_opc_ptr = gen_opc_buf;
2083 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2084 gen_opparam_ptr = gen_opparam_buf;
2086 dc->is_jmp = DISAS_NEXT;
2087 dc->pc = pc_start;
2088 dc->singlestep_enabled = env->singlestep_enabled;
2089 dc->condjmp = 0;
2090 dc->thumb = env->thumb;
2091 nb_gen_labels = 0;
2092 lj = -1;
2093 do {
2094 if (env->nb_breakpoints > 0) {
2095 for(j = 0; j < env->nb_breakpoints; j++) {
2096 if (env->breakpoints[j] == dc->pc) {
2097 gen_op_movl_T0_im((long)dc->pc);
2098 gen_op_movl_reg_TN[0][15]();
2099 gen_op_debug();
2100 dc->is_jmp = DISAS_JUMP;
2101 break;
2105 if (search_pc) {
2106 j = gen_opc_ptr - gen_opc_buf;
2107 if (lj < j) {
2108 lj++;
2109 while (lj < j)
2110 gen_opc_instr_start[lj++] = 0;
2112 gen_opc_pc[lj] = dc->pc;
2113 gen_opc_instr_start[lj] = 1;
2116 if (env->thumb)
2117 disas_thumb_insn(dc);
2118 else
2119 disas_arm_insn(env, dc);
2121 if (dc->condjmp && !dc->is_jmp) {
2122 gen_set_label(dc->condlabel);
2123 dc->condjmp = 0;
2125 /* Translation stops when a conditional branch is enoutered.
2126 * Otherwise the subsequent code could get translated several times.
2128 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
2129 !env->singlestep_enabled &&
2130 (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
2131 /* It this stage dc->condjmp will only be set when the skipped
2132 * instruction was a conditional branch, and teh PC has already been
2133 * written. */
2134 if (__builtin_expect(env->singlestep_enabled, 0)) {
2135 /* Make sure the pc is updated, and raise a debug exception. */
2136 if (dc->condjmp) {
2137 gen_op_debug();
2138 gen_set_label(dc->condlabel);
2140 if (dc->condjmp || !dc->is_jmp) {
2141 gen_op_movl_T0_im((long)dc->pc);
2142 gen_op_movl_reg_TN[0][15]();
2143 dc->condjmp = 0;
2145 gen_op_debug();
2146 } else {
2147 switch(dc->is_jmp) {
2148 case DISAS_NEXT:
2149 gen_goto_tb(dc, 1, dc->pc);
2150 break;
2151 default:
2152 case DISAS_JUMP:
2153 case DISAS_UPDATE:
2154 /* indicate that the hash table must be used to find the next TB */
2155 gen_op_movl_T0_0();
2156 gen_op_exit_tb();
2157 break;
2158 case DISAS_TB_JUMP:
2159 /* nothing more to generate */
2160 break;
2162 if (dc->condjmp) {
2163 gen_set_label(dc->condlabel);
2164 gen_goto_tb(dc, 1, dc->pc);
2165 dc->condjmp = 0;
2168 *gen_opc_ptr = INDEX_op_end;
2170 #ifdef DEBUG_DISAS
2171 if (loglevel & CPU_LOG_TB_IN_ASM) {
2172 fprintf(logfile, "----------------\n");
2173 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
2174 target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
2175 fprintf(logfile, "\n");
2176 if (loglevel & (CPU_LOG_TB_OP)) {
2177 fprintf(logfile, "OP:\n");
2178 dump_ops(gen_opc_buf, gen_opparam_buf);
2179 fprintf(logfile, "\n");
2182 #endif
2183 if (!search_pc)
2184 tb->size = dc->pc - pc_start;
2185 return 0;
2188 int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
2190 return gen_intermediate_code_internal(env, tb, 0);
2193 int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
2195 return gen_intermediate_code_internal(env, tb, 1);
2198 CPUARMState *cpu_arm_init(void)
2200 CPUARMState *env;
2202 cpu_exec_init();
2204 env = malloc(sizeof(CPUARMState));
2205 if (!env)
2206 return NULL;
2207 memset(env, 0, sizeof(CPUARMState));
2208 cpu_single_env = env;
2209 return env;
2212 void cpu_arm_close(CPUARMState *env)
2214 free(env);
2217 void cpu_dump_state(CPUState *env, FILE *f,
2218 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2219 int flags)
2221 int i;
2222 union {
2223 uint32_t i;
2224 float s;
2225 } s0, s1;
2226 CPU_DoubleU d;
2228 for(i=0;i<16;i++) {
2229 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
2230 if ((i % 4) == 3)
2231 cpu_fprintf(f, "\n");
2232 else
2233 cpu_fprintf(f, " ");
2235 cpu_fprintf(f, "PSR=%08x %c%c%c%c %c\n",
2236 env->cpsr,
2237 env->cpsr & (1 << 31) ? 'N' : '-',
2238 env->cpsr & (1 << 30) ? 'Z' : '-',
2239 env->cpsr & (1 << 29) ? 'C' : '-',
2240 env->cpsr & (1 << 28) ? 'V' : '-',
2241 env->thumb ? 'T' : 'A');
2243 for (i = 0; i < 16; i++) {
2244 d.d = env->vfp.regs[i];
2245 s0.i = d.l.lower;
2246 s1.i = d.l.upper;
2247 cpu_fprintf(f, "s%02d=%08x(%8f) s%02d=%08x(%8f) d%02d=%08x%08x(%8f)\n",
2248 i * 2, (int)s0.i, s0.s,
2249 i * 2 + 1, (int)s0.i, s0.s,
2250 i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
2251 d.d);
2253 cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr);
2256 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
2258 return addr;
2261 #if defined(CONFIG_USER_ONLY)
2263 int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
2264 int is_user, int is_softmmu)
2266 env->cp15_6 = address;
2267 if (rw == 2) {
2268 env->exception_index = EXCP_PREFETCH_ABORT;
2269 } else {
2270 env->exception_index = EXCP_DATA_ABORT;
2272 return 1;
2275 #else
2277 #error not implemented
2279 #endif