translate.c revision 413f05aaf54fa08c0ae7e997327a4f4a473c0a8d
1/*
2 *  ARM translation
3 *
4 *  Copyright (c) 2003 Fabrice Bellard
5 *  Copyright (c) 2005 CodeSourcery, LLC
6 *
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.
11 *
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.
16 *
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
20 */
21#include <stdarg.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <inttypes.h>
26
27#include "cpu.h"
28#include "exec-all.h"
29#include "disas.h"
30
31#define ENABLE_ARCH_5J  0
32#define ENABLE_ARCH_6   1
33#define ENABLE_ARCH_6T2 1
34
35#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op;
36
37/* internal defines */
38typedef struct DisasContext {
39    target_ulong pc;
40    int is_jmp;
41    /* Nonzero if this instruction has been conditionally skipped.  */
42    int condjmp;
43    /* The label that will be jumped to when the instruction is skipped.  */
44    int condlabel;
45    struct TranslationBlock *tb;
46    int singlestep_enabled;
47    int thumb;
48#if !defined(CONFIG_USER_ONLY)
49    int user;
50#endif
51} DisasContext;
52
53#if defined(CONFIG_USER_ONLY)
54#define IS_USER(s) 1
55#else
56#define IS_USER(s) (s->user)
57#endif
58
59#define DISAS_JUMP_NEXT 4
60
61#ifdef USE_DIRECT_JUMP
62#define TBPARAM(x)
63#else
64#define TBPARAM(x) (long)(x)
65#endif
66
67/* XXX: move that elsewhere */
68static uint16_t *gen_opc_ptr;
69static uint32_t *gen_opparam_ptr;
70extern FILE *logfile;
71extern int loglevel;
72
73enum {
74#define DEF(s, n, copy_size) INDEX_op_ ## s,
75#include "opc.h"
76#undef DEF
77    NB_OPS,
78};
79
80#include "gen-op.h"
81
82static GenOpFunc1 *gen_test_cc[14] = {
83    gen_op_test_eq,
84    gen_op_test_ne,
85    gen_op_test_cs,
86    gen_op_test_cc,
87    gen_op_test_mi,
88    gen_op_test_pl,
89    gen_op_test_vs,
90    gen_op_test_vc,
91    gen_op_test_hi,
92    gen_op_test_ls,
93    gen_op_test_ge,
94    gen_op_test_lt,
95    gen_op_test_gt,
96    gen_op_test_le,
97};
98
99const uint8_t table_logic_cc[16] = {
100    1, /* and */
101    1, /* xor */
102    0, /* sub */
103    0, /* rsb */
104    0, /* add */
105    0, /* adc */
106    0, /* sbc */
107    0, /* rsc */
108    1, /* andl */
109    1, /* xorl */
110    0, /* cmp */
111    0, /* cmn */
112    1, /* orr */
113    1, /* mov */
114    1, /* bic */
115    1, /* mvn */
116};
117
118static GenOpFunc1 *gen_shift_T1_im[4] = {
119    gen_op_shll_T1_im,
120    gen_op_shrl_T1_im,
121    gen_op_sarl_T1_im,
122    gen_op_rorl_T1_im,
123};
124
125static GenOpFunc *gen_shift_T1_0[4] = {
126    NULL,
127    gen_op_shrl_T1_0,
128    gen_op_sarl_T1_0,
129    gen_op_rrxl_T1,
130};
131
132static GenOpFunc1 *gen_shift_T2_im[4] = {
133    gen_op_shll_T2_im,
134    gen_op_shrl_T2_im,
135    gen_op_sarl_T2_im,
136    gen_op_rorl_T2_im,
137};
138
139static GenOpFunc *gen_shift_T2_0[4] = {
140    NULL,
141    gen_op_shrl_T2_0,
142    gen_op_sarl_T2_0,
143    gen_op_rrxl_T2,
144};
145
146static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
147    gen_op_shll_T1_im_cc,
148    gen_op_shrl_T1_im_cc,
149    gen_op_sarl_T1_im_cc,
150    gen_op_rorl_T1_im_cc,
151};
152
153static GenOpFunc *gen_shift_T1_0_cc[4] = {
154    NULL,
155    gen_op_shrl_T1_0_cc,
156    gen_op_sarl_T1_0_cc,
157    gen_op_rrxl_T1_cc,
158};
159
160static GenOpFunc *gen_shift_T1_T0[4] = {
161    gen_op_shll_T1_T0,
162    gen_op_shrl_T1_T0,
163    gen_op_sarl_T1_T0,
164    gen_op_rorl_T1_T0,
165};
166
167static GenOpFunc *gen_shift_T1_T0_cc[4] = {
168    gen_op_shll_T1_T0_cc,
169    gen_op_shrl_T1_T0_cc,
170    gen_op_sarl_T1_T0_cc,
171    gen_op_rorl_T1_T0_cc,
172};
173
174static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
175    {
176        gen_op_movl_T0_r0,
177        gen_op_movl_T0_r1,
178        gen_op_movl_T0_r2,
179        gen_op_movl_T0_r3,
180        gen_op_movl_T0_r4,
181        gen_op_movl_T0_r5,
182        gen_op_movl_T0_r6,
183        gen_op_movl_T0_r7,
184        gen_op_movl_T0_r8,
185        gen_op_movl_T0_r9,
186        gen_op_movl_T0_r10,
187        gen_op_movl_T0_r11,
188        gen_op_movl_T0_r12,
189        gen_op_movl_T0_r13,
190        gen_op_movl_T0_r14,
191        gen_op_movl_T0_r15,
192    },
193    {
194        gen_op_movl_T1_r0,
195        gen_op_movl_T1_r1,
196        gen_op_movl_T1_r2,
197        gen_op_movl_T1_r3,
198        gen_op_movl_T1_r4,
199        gen_op_movl_T1_r5,
200        gen_op_movl_T1_r6,
201        gen_op_movl_T1_r7,
202        gen_op_movl_T1_r8,
203        gen_op_movl_T1_r9,
204        gen_op_movl_T1_r10,
205        gen_op_movl_T1_r11,
206        gen_op_movl_T1_r12,
207        gen_op_movl_T1_r13,
208        gen_op_movl_T1_r14,
209        gen_op_movl_T1_r15,
210    },
211    {
212        gen_op_movl_T2_r0,
213        gen_op_movl_T2_r1,
214        gen_op_movl_T2_r2,
215        gen_op_movl_T2_r3,
216        gen_op_movl_T2_r4,
217        gen_op_movl_T2_r5,
218        gen_op_movl_T2_r6,
219        gen_op_movl_T2_r7,
220        gen_op_movl_T2_r8,
221        gen_op_movl_T2_r9,
222        gen_op_movl_T2_r10,
223        gen_op_movl_T2_r11,
224        gen_op_movl_T2_r12,
225        gen_op_movl_T2_r13,
226        gen_op_movl_T2_r14,
227        gen_op_movl_T2_r15,
228    },
229};
230
231static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
232    {
233        gen_op_movl_r0_T0,
234        gen_op_movl_r1_T0,
235        gen_op_movl_r2_T0,
236        gen_op_movl_r3_T0,
237        gen_op_movl_r4_T0,
238        gen_op_movl_r5_T0,
239        gen_op_movl_r6_T0,
240        gen_op_movl_r7_T0,
241        gen_op_movl_r8_T0,
242        gen_op_movl_r9_T0,
243        gen_op_movl_r10_T0,
244        gen_op_movl_r11_T0,
245        gen_op_movl_r12_T0,
246        gen_op_movl_r13_T0,
247        gen_op_movl_r14_T0,
248        gen_op_movl_r15_T0,
249    },
250    {
251        gen_op_movl_r0_T1,
252        gen_op_movl_r1_T1,
253        gen_op_movl_r2_T1,
254        gen_op_movl_r3_T1,
255        gen_op_movl_r4_T1,
256        gen_op_movl_r5_T1,
257        gen_op_movl_r6_T1,
258        gen_op_movl_r7_T1,
259        gen_op_movl_r8_T1,
260        gen_op_movl_r9_T1,
261        gen_op_movl_r10_T1,
262        gen_op_movl_r11_T1,
263        gen_op_movl_r12_T1,
264        gen_op_movl_r13_T1,
265        gen_op_movl_r14_T1,
266        gen_op_movl_r15_T1,
267    },
268};
269
270static GenOpFunc1 *gen_op_movl_TN_im[3] = {
271    gen_op_movl_T0_im,
272    gen_op_movl_T1_im,
273    gen_op_movl_T2_im,
274};
275
276static GenOpFunc1 *gen_shift_T0_im_thumb[3] = {
277    gen_op_shll_T0_im_thumb,
278    gen_op_shrl_T0_im_thumb,
279    gen_op_sarl_T0_im_thumb,
280};
281
282static inline void gen_bx(DisasContext *s)
283{
284  s->is_jmp = DISAS_UPDATE;
285  gen_op_bx_T0();
286}
287
288
289#if defined(CONFIG_USER_ONLY)
290#define gen_ldst(name, s) gen_op_##name##_raw()
291#else
292#define gen_ldst(name, s) do { \
293    if (IS_USER(s)) \
294        gen_op_##name##_user(); \
295    else \
296        gen_op_##name##_kernel(); \
297    } while (0)
298#endif
299
300static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
301{
302    int val;
303
304    if (reg == 15) {
305        /* normaly, since we updated PC, we need only to add one insn */
306        if (s->thumb)
307            val = (long)s->pc + 2;
308        else
309            val = (long)s->pc + 4;
310        gen_op_movl_TN_im[t](val);
311    } else {
312        gen_op_movl_TN_reg[t][reg]();
313    }
314}
315
316static inline void gen_movl_T0_reg(DisasContext *s, int reg)
317{
318    gen_movl_TN_reg(s, reg, 0);
319}
320
321static inline void gen_movl_T1_reg(DisasContext *s, int reg)
322{
323    gen_movl_TN_reg(s, reg, 1);
324}
325
326static inline void gen_movl_T2_reg(DisasContext *s, int reg)
327{
328    gen_movl_TN_reg(s, reg, 2);
329}
330
331static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
332{
333    gen_op_movl_reg_TN[t][reg]();
334    if (reg == 15) {
335        s->is_jmp = DISAS_JUMP;
336    }
337}
338
339static inline void gen_movl_reg_T0(DisasContext *s, int reg)
340{
341    gen_movl_reg_TN(s, reg, 0);
342}
343
344static inline void gen_movl_reg_T1(DisasContext *s, int reg)
345{
346    gen_movl_reg_TN(s, reg, 1);
347}
348
349/* Force a TB lookup after an instruction that changes the CPU state.  */
350static inline void gen_lookup_tb(DisasContext *s)
351{
352    gen_op_movl_T0_im(s->pc);
353    gen_movl_reg_T0(s, 15);
354    s->is_jmp = DISAS_UPDATE;
355}
356
357static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
358{
359    int val, rm, shift, shiftop;
360
361    if (!(insn & (1 << 25))) {
362        /* immediate */
363        val = insn & 0xfff;
364        if (!(insn & (1 << 23)))
365            val = -val;
366        if (val != 0)
367            gen_op_addl_T1_im(val);
368    } else {
369        /* shift/register */
370        rm = (insn) & 0xf;
371        shift = (insn >> 7) & 0x1f;
372        gen_movl_T2_reg(s, rm);
373        shiftop = (insn >> 5) & 3;
374        if (shift != 0) {
375            gen_shift_T2_im[shiftop](shift);
376        } else if (shiftop != 0) {
377            gen_shift_T2_0[shiftop]();
378        }
379        if (!(insn & (1 << 23)))
380            gen_op_subl_T1_T2();
381        else
382            gen_op_addl_T1_T2();
383    }
384}
385
386static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
387                                        int extra)
388{
389    int val, rm;
390
391    if (insn & (1 << 22)) {
392        /* immediate */
393        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
394        val += extra;
395        if (!(insn & (1 << 23)))
396            val = -val;
397        if (val != 0)
398            gen_op_addl_T1_im(val);
399    } else {
400        /* register */
401        if (extra)
402            gen_op_addl_T1_im(extra);
403        rm = (insn) & 0xf;
404        gen_movl_T2_reg(s, rm);
405        if (!(insn & (1 << 23)))
406            gen_op_subl_T1_T2();
407        else
408            gen_op_addl_T1_T2();
409    }
410}
411
412#define VFP_OP(name)                      \
413static inline void gen_vfp_##name(int dp) \
414{                                         \
415    if (dp)                               \
416        gen_op_vfp_##name##d();           \
417    else                                  \
418        gen_op_vfp_##name##s();           \
419}
420
421VFP_OP(add)
422VFP_OP(sub)
423VFP_OP(mul)
424VFP_OP(div)
425VFP_OP(neg)
426VFP_OP(abs)
427VFP_OP(sqrt)
428VFP_OP(cmp)
429VFP_OP(cmpe)
430VFP_OP(F1_ld0)
431VFP_OP(uito)
432VFP_OP(sito)
433VFP_OP(toui)
434VFP_OP(touiz)
435VFP_OP(tosi)
436VFP_OP(tosiz)
437
438#undef VFP_OP
439
440static inline void gen_vfp_ld(DisasContext *s, int dp)
441{
442    if (dp)
443        gen_ldst(vfp_ldd, s);
444    else
445        gen_ldst(vfp_lds, s);
446}
447
448static inline void gen_vfp_st(DisasContext *s, int dp)
449{
450    if (dp)
451        gen_ldst(vfp_std, s);
452    else
453        gen_ldst(vfp_sts, s);
454}
455
456static inline long
457vfp_reg_offset (int dp, int reg)
458{
459    if (dp)
460        return offsetof(CPUARMState, vfp.regs[reg]);
461    else if (reg & 1) {
462        return offsetof(CPUARMState, vfp.regs[reg >> 1])
463          + offsetof(CPU_DoubleU, l.upper);
464    } else {
465        return offsetof(CPUARMState, vfp.regs[reg >> 1])
466          + offsetof(CPU_DoubleU, l.lower);
467    }
468}
469static inline void gen_mov_F0_vreg(int dp, int reg)
470{
471    if (dp)
472        gen_op_vfp_getreg_F0d(vfp_reg_offset(dp, reg));
473    else
474        gen_op_vfp_getreg_F0s(vfp_reg_offset(dp, reg));
475}
476
477static inline void gen_mov_F1_vreg(int dp, int reg)
478{
479    if (dp)
480        gen_op_vfp_getreg_F1d(vfp_reg_offset(dp, reg));
481    else
482        gen_op_vfp_getreg_F1s(vfp_reg_offset(dp, reg));
483}
484
485static inline void gen_mov_vreg_F0(int dp, int reg)
486{
487    if (dp)
488        gen_op_vfp_setreg_F0d(vfp_reg_offset(dp, reg));
489    else
490        gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
491}
492
493/* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
494   instruction is not defined.  */
495static int disas_cp15_insn(DisasContext *s, uint32_t insn)
496{
497    uint32_t rd;
498
499    /* ??? Some cp15 registers are accessible from userspace.  */
500    if (IS_USER(s)) {
501        return 1;
502    }
503    if ((insn & 0x0fff0fff) == 0x0e070f90
504        || (insn & 0x0fff0fff) == 0x0e070f58) {
505        /* Wait for interrupt.  */
506        gen_op_movl_T0_im((long)s->pc);
507        gen_op_movl_reg_TN[0][15]();
508        gen_op_wfi();
509        s->is_jmp = DISAS_JUMP;
510        return 0;
511    }
512    rd = (insn >> 12) & 0xf;
513    if (insn & (1 << 20)) {
514        gen_op_movl_T0_cp15(insn);
515        /* If the destination register is r15 then sets condition codes.  */
516        if (rd != 15)
517            gen_movl_reg_T0(s, rd);
518    } else {
519        gen_movl_T0_reg(s, rd);
520        gen_op_movl_cp15_T0(insn);
521    }
522    gen_lookup_tb(s);
523    return 0;
524}
525
526/* Disassemble a VFP instruction.  Returns nonzero if an error occured
527   (ie. an undefined instruction).  */
528static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
529{
530    uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
531    int dp, veclen;
532
533    if (!arm_feature(env, ARM_FEATURE_VFP))
534        return 1;
535
536    if ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) == 0) {
537        /* VFP disabled.  Only allow fmxr/fmrx to/from fpexc and fpsid.  */
538        if ((insn & 0x0fe00fff) != 0x0ee00a10)
539            return 1;
540        rn = (insn >> 16) & 0xf;
541        if (rn != 0 && rn != 8)
542            return 1;
543    }
544    dp = ((insn & 0xf00) == 0xb00);
545    switch ((insn >> 24) & 0xf) {
546    case 0xe:
547        if (insn & (1 << 4)) {
548            /* single register transfer */
549            if ((insn & 0x6f) != 0x00)
550                return 1;
551            rd = (insn >> 12) & 0xf;
552            if (dp) {
553                if (insn & 0x80)
554                    return 1;
555                rn = (insn >> 16) & 0xf;
556                /* Get the existing value even for arm->vfp moves because
557                   we only set half the register.  */
558                gen_mov_F0_vreg(1, rn);
559                gen_op_vfp_mrrd();
560                if (insn & (1 << 20)) {
561                    /* vfp->arm */
562                    if (insn & (1 << 21))
563                        gen_movl_reg_T1(s, rd);
564                    else
565                        gen_movl_reg_T0(s, rd);
566                } else {
567                    /* arm->vfp */
568                    if (insn & (1 << 21))
569                        gen_movl_T1_reg(s, rd);
570                    else
571                        gen_movl_T0_reg(s, rd);
572                    gen_op_vfp_mdrr();
573                    gen_mov_vreg_F0(dp, rn);
574                }
575            } else {
576                rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
577                if (insn & (1 << 20)) {
578                    /* vfp->arm */
579                    if (insn & (1 << 21)) {
580                        /* system register */
581                        rn >>= 1;
582                        switch (rn) {
583                        case ARM_VFP_FPSID:
584                        case ARM_VFP_FPEXC:
585                        case ARM_VFP_FPINST:
586                        case ARM_VFP_FPINST2:
587                            gen_op_vfp_movl_T0_xreg(rn);
588                            break;
589                        case ARM_VFP_FPSCR:
590			    if (rd == 15)
591				gen_op_vfp_movl_T0_fpscr_flags();
592			    else
593				gen_op_vfp_movl_T0_fpscr();
594                            break;
595                        default:
596                            return 1;
597                        }
598                    } else {
599                        gen_mov_F0_vreg(0, rn);
600                        gen_op_vfp_mrs();
601                    }
602                    if (rd == 15) {
603                        /* Set the 4 flag bits in the CPSR.  */
604                        gen_op_movl_cpsr_T0(0xf0000000);
605                    } else
606                        gen_movl_reg_T0(s, rd);
607                } else {
608                    /* arm->vfp */
609                    gen_movl_T0_reg(s, rd);
610                    if (insn & (1 << 21)) {
611                        rn >>= 1;
612                        /* system register */
613                        switch (rn) {
614                        case ARM_VFP_FPSID:
615                            /* Writes are ignored.  */
616                            break;
617                        case ARM_VFP_FPSCR:
618                            gen_op_vfp_movl_fpscr_T0();
619                            gen_lookup_tb(s);
620                            break;
621                        case ARM_VFP_FPEXC:
622                            gen_op_vfp_movl_xreg_T0(rn);
623                            gen_lookup_tb(s);
624                            break;
625                        case ARM_VFP_FPINST:
626                        case ARM_VFP_FPINST2:
627                            gen_op_vfp_movl_xreg_T0(rn);
628                            break;
629                        default:
630                            return 1;
631                        }
632                    } else {
633                        gen_op_vfp_msr();
634                        gen_mov_vreg_F0(0, rn);
635                    }
636                }
637            }
638        } else {
639            /* data processing */
640            /* The opcode is in bits 23, 21, 20 and 6.  */
641            op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
642            if (dp) {
643                if (op == 15) {
644                    /* rn is opcode */
645                    rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
646                } else {
647                    /* rn is register number */
648                    if (insn & (1 << 7))
649                        return 1;
650                    rn = (insn >> 16) & 0xf;
651                }
652
653                if (op == 15 && (rn == 15 || rn > 17)) {
654                    /* Integer or single precision destination.  */
655                    rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
656                } else {
657                    if (insn & (1 << 22))
658                        return 1;
659                    rd = (insn >> 12) & 0xf;
660                }
661
662                if (op == 15 && (rn == 16 || rn == 17)) {
663                    /* Integer source.  */
664                    rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
665                } else {
666                    if (insn & (1 << 5))
667                        return 1;
668                    rm = insn & 0xf;
669                }
670            } else {
671                rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
672                if (op == 15 && rn == 15) {
673                    /* Double precision destination.  */
674                    if (insn & (1 << 22))
675                        return 1;
676                    rd = (insn >> 12) & 0xf;
677                } else
678                    rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
679                rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
680            }
681
682            veclen = env->vfp.vec_len;
683            if (op == 15 && rn > 3)
684                veclen = 0;
685
686            /* Shut up compiler warnings.  */
687            delta_m = 0;
688            delta_d = 0;
689            bank_mask = 0;
690
691            if (veclen > 0) {
692                if (dp)
693                    bank_mask = 0xc;
694                else
695                    bank_mask = 0x18;
696
697                /* Figure out what type of vector operation this is.  */
698                if ((rd & bank_mask) == 0) {
699                    /* scalar */
700                    veclen = 0;
701                } else {
702                    if (dp)
703                        delta_d = (env->vfp.vec_stride >> 1) + 1;
704                    else
705                        delta_d = env->vfp.vec_stride + 1;
706
707                    if ((rm & bank_mask) == 0) {
708                        /* mixed scalar/vector */
709                        delta_m = 0;
710                    } else {
711                        /* vector */
712                        delta_m = delta_d;
713                    }
714                }
715            }
716
717            /* Load the initial operands.  */
718            if (op == 15) {
719                switch (rn) {
720                case 16:
721                case 17:
722                    /* Integer source */
723                    gen_mov_F0_vreg(0, rm);
724                    break;
725                case 8:
726                case 9:
727                    /* Compare */
728                    gen_mov_F0_vreg(dp, rd);
729                    gen_mov_F1_vreg(dp, rm);
730                    break;
731                case 10:
732                case 11:
733                    /* Compare with zero */
734                    gen_mov_F0_vreg(dp, rd);
735                    gen_vfp_F1_ld0(dp);
736                    break;
737                default:
738                    /* One source operand.  */
739                    gen_mov_F0_vreg(dp, rm);
740                }
741            } else {
742                /* Two source operands.  */
743                gen_mov_F0_vreg(dp, rn);
744                gen_mov_F1_vreg(dp, rm);
745            }
746
747            for (;;) {
748                /* Perform the calculation.  */
749                switch (op) {
750                case 0: /* mac: fd + (fn * fm) */
751                    gen_vfp_mul(dp);
752                    gen_mov_F1_vreg(dp, rd);
753                    gen_vfp_add(dp);
754                    break;
755                case 1: /* nmac: fd - (fn * fm) */
756                    gen_vfp_mul(dp);
757                    gen_vfp_neg(dp);
758                    gen_mov_F1_vreg(dp, rd);
759                    gen_vfp_add(dp);
760                    break;
761                case 2: /* msc: -fd + (fn * fm) */
762                    gen_vfp_mul(dp);
763                    gen_mov_F1_vreg(dp, rd);
764                    gen_vfp_sub(dp);
765                    break;
766                case 3: /* nmsc: -fd - (fn * fm)  */
767                    gen_vfp_mul(dp);
768                    gen_mov_F1_vreg(dp, rd);
769                    gen_vfp_add(dp);
770                    gen_vfp_neg(dp);
771                    break;
772                case 4: /* mul: fn * fm */
773                    gen_vfp_mul(dp);
774                    break;
775                case 5: /* nmul: -(fn * fm) */
776                    gen_vfp_mul(dp);
777                    gen_vfp_neg(dp);
778                    break;
779                case 6: /* add: fn + fm */
780                    gen_vfp_add(dp);
781                    break;
782                case 7: /* sub: fn - fm */
783                    gen_vfp_sub(dp);
784                    break;
785                case 8: /* div: fn / fm */
786                    gen_vfp_div(dp);
787                    break;
788                case 15: /* extension space */
789                    switch (rn) {
790                    case 0: /* cpy */
791                        /* no-op */
792                        break;
793                    case 1: /* abs */
794                        gen_vfp_abs(dp);
795                        break;
796                    case 2: /* neg */
797                        gen_vfp_neg(dp);
798                        break;
799                    case 3: /* sqrt */
800                        gen_vfp_sqrt(dp);
801                        break;
802                    case 8: /* cmp */
803                        gen_vfp_cmp(dp);
804                        break;
805                    case 9: /* cmpe */
806                        gen_vfp_cmpe(dp);
807                        break;
808                    case 10: /* cmpz */
809                        gen_vfp_cmp(dp);
810                        break;
811                    case 11: /* cmpez */
812                        gen_vfp_F1_ld0(dp);
813                        gen_vfp_cmpe(dp);
814                        break;
815                    case 15: /* single<->double conversion */
816                        if (dp)
817                            gen_op_vfp_fcvtsd();
818                        else
819                            gen_op_vfp_fcvtds();
820                        break;
821                    case 16: /* fuito */
822                        gen_vfp_uito(dp);
823                        break;
824                    case 17: /* fsito */
825                        gen_vfp_sito(dp);
826                        break;
827                    case 24: /* ftoui */
828                        gen_vfp_toui(dp);
829                        break;
830                    case 25: /* ftouiz */
831                        gen_vfp_touiz(dp);
832                        break;
833                    case 26: /* ftosi */
834                        gen_vfp_tosi(dp);
835                        break;
836                    case 27: /* ftosiz */
837                        gen_vfp_tosiz(dp);
838                        break;
839                    default: /* undefined */
840                        printf ("rn:%d\n", rn);
841                        return 1;
842                    }
843                    break;
844                default: /* undefined */
845                    printf ("op:%d\n", op);
846                    return 1;
847                }
848
849                /* Write back the result.  */
850                if (op == 15 && (rn >= 8 && rn <= 11))
851                    ; /* Comparison, do nothing.  */
852                else if (op == 15 && rn > 17)
853                    /* Integer result.  */
854                    gen_mov_vreg_F0(0, rd);
855                else if (op == 15 && rn == 15)
856                    /* conversion */
857                    gen_mov_vreg_F0(!dp, rd);
858                else
859                    gen_mov_vreg_F0(dp, rd);
860
861                /* break out of the loop if we have finished  */
862                if (veclen == 0)
863                    break;
864
865                if (op == 15 && delta_m == 0) {
866                    /* single source one-many */
867                    while (veclen--) {
868                        rd = ((rd + delta_d) & (bank_mask - 1))
869                             | (rd & bank_mask);
870                        gen_mov_vreg_F0(dp, rd);
871                    }
872                    break;
873                }
874                /* Setup the next operands.  */
875                veclen--;
876                rd = ((rd + delta_d) & (bank_mask - 1))
877                     | (rd & bank_mask);
878
879                if (op == 15) {
880                    /* One source operand.  */
881                    rm = ((rm + delta_m) & (bank_mask - 1))
882                         | (rm & bank_mask);
883                    gen_mov_F0_vreg(dp, rm);
884                } else {
885                    /* Two source operands.  */
886                    rn = ((rn + delta_d) & (bank_mask - 1))
887                         | (rn & bank_mask);
888                    gen_mov_F0_vreg(dp, rn);
889                    if (delta_m) {
890                        rm = ((rm + delta_m) & (bank_mask - 1))
891                             | (rm & bank_mask);
892                        gen_mov_F1_vreg(dp, rm);
893                    }
894                }
895            }
896        }
897        break;
898    case 0xc:
899    case 0xd:
900        if (dp && (insn & (1 << 22))) {
901            /* two-register transfer */
902            rn = (insn >> 16) & 0xf;
903            rd = (insn >> 12) & 0xf;
904            if (dp) {
905                if (insn & (1 << 5))
906                    return 1;
907                rm = insn & 0xf;
908            } else
909                rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
910
911            if (insn & (1 << 20)) {
912                /* vfp->arm */
913                if (dp) {
914                    gen_mov_F0_vreg(1, rm);
915                    gen_op_vfp_mrrd();
916                    gen_movl_reg_T0(s, rd);
917                    gen_movl_reg_T1(s, rn);
918                } else {
919                    gen_mov_F0_vreg(0, rm);
920                    gen_op_vfp_mrs();
921                    gen_movl_reg_T0(s, rn);
922                    gen_mov_F0_vreg(0, rm + 1);
923                    gen_op_vfp_mrs();
924                    gen_movl_reg_T0(s, rd);
925                }
926            } else {
927                /* arm->vfp */
928                if (dp) {
929                    gen_movl_T0_reg(s, rd);
930                    gen_movl_T1_reg(s, rn);
931                    gen_op_vfp_mdrr();
932                    gen_mov_vreg_F0(1, rm);
933                } else {
934                    gen_movl_T0_reg(s, rn);
935                    gen_op_vfp_msr();
936                    gen_mov_vreg_F0(0, rm);
937                    gen_movl_T0_reg(s, rd);
938                    gen_op_vfp_msr();
939                    gen_mov_vreg_F0(0, rm + 1);
940                }
941            }
942        } else {
943            /* Load/store */
944            rn = (insn >> 16) & 0xf;
945            if (dp)
946                rd = (insn >> 12) & 0xf;
947            else
948                rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
949            gen_movl_T1_reg(s, rn);
950            if ((insn & 0x01200000) == 0x01000000) {
951                /* Single load/store */
952                offset = (insn & 0xff) << 2;
953                if ((insn & (1 << 23)) == 0)
954                    offset = -offset;
955                gen_op_addl_T1_im(offset);
956                if (insn & (1 << 20)) {
957                    gen_vfp_ld(s, dp);
958                    gen_mov_vreg_F0(dp, rd);
959                } else {
960                    gen_mov_F0_vreg(dp, rd);
961                    gen_vfp_st(s, dp);
962                }
963            } else {
964                /* load/store multiple */
965                if (dp)
966                    n = (insn >> 1) & 0x7f;
967                else
968                    n = insn & 0xff;
969
970                if (insn & (1 << 24)) /* pre-decrement */
971                    gen_op_addl_T1_im(-((insn & 0xff) << 2));
972
973                if (dp)
974                    offset = 8;
975                else
976                    offset = 4;
977                for (i = 0; i < n; i++) {
978                    if (insn & (1 << 20)) {
979                        /* load */
980                        gen_vfp_ld(s, dp);
981                        gen_mov_vreg_F0(dp, rd + i);
982                    } else {
983                        /* store */
984                        gen_mov_F0_vreg(dp, rd + i);
985                        gen_vfp_st(s, dp);
986                    }
987                    gen_op_addl_T1_im(offset);
988                }
989                if (insn & (1 << 21)) {
990                    /* writeback */
991                    if (insn & (1 << 24))
992                        offset = -offset * n;
993                    else if (dp && (insn & 1))
994                        offset = 4;
995                    else
996                        offset = 0;
997
998                    if (offset != 0)
999                        gen_op_addl_T1_im(offset);
1000                    gen_movl_reg_T1(s, rn);
1001                }
1002            }
1003        }
1004        break;
1005    default:
1006        /* Should never happen.  */
1007        return 1;
1008    }
1009    return 0;
1010}
1011
1012static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
1013{
1014    TranslationBlock *tb;
1015
1016    tb = s->tb;
1017    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
1018        if (n == 0)
1019            gen_op_goto_tb0(TBPARAM(tb));
1020        else
1021            gen_op_goto_tb1(TBPARAM(tb));
1022        gen_op_movl_T0_im(dest);
1023        gen_op_movl_r15_T0();
1024        gen_op_movl_T0_im((long)tb + n);
1025        gen_op_exit_tb();
1026    } else {
1027        gen_op_movl_T0_im(dest);
1028        gen_op_movl_r15_T0();
1029        gen_op_movl_T0_0();
1030        gen_op_exit_tb();
1031    }
1032}
1033
1034static inline void gen_jmp (DisasContext *s, uint32_t dest)
1035{
1036    if (__builtin_expect(s->singlestep_enabled, 0)) {
1037        /* An indirect jump so that we still trigger the debug exception.  */
1038        if (s->thumb)
1039          dest |= 1;
1040        gen_op_movl_T0_im(dest);
1041        gen_bx(s);
1042    } else {
1043        gen_goto_tb(s, 0, dest);
1044        s->is_jmp = DISAS_TB_JUMP;
1045    }
1046}
1047
1048static inline void gen_mulxy(int x, int y)
1049{
1050    if (x)
1051        gen_op_sarl_T0_im(16);
1052    else
1053        gen_op_sxth_T0();
1054    if (y)
1055        gen_op_sarl_T1_im(16);
1056    else
1057        gen_op_sxth_T1();
1058    gen_op_mul_T0_T1();
1059}
1060
1061/* Return the mask of PSR bits set by a MSR instruction.  */
1062static uint32_t msr_mask(DisasContext *s, int flags, int spsr) {
1063    uint32_t mask;
1064
1065    mask = 0;
1066    if (flags & (1 << 0))
1067        mask |= 0xff;
1068    if (flags & (1 << 1))
1069        mask |= 0xff00;
1070    if (flags & (1 << 2))
1071        mask |= 0xff0000;
1072    if (flags & (1 << 3))
1073        mask |= 0xff000000;
1074    /* Mask out undefined bits.  */
1075    mask &= 0xf90f03ff;
1076    /* Mask out state bits.  */
1077    if (!spsr)
1078        mask &= ~0x01000020;
1079    /* Mask out privileged bits.  */
1080    if (IS_USER(s))
1081        mask &= 0xf80f0200;
1082    return mask;
1083}
1084
1085/* Returns nonzero if access to the PSR is not permitted.  */
1086static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr)
1087{
1088    if (spsr) {
1089        /* ??? This is also undefined in system mode.  */
1090        if (IS_USER(s))
1091            return 1;
1092        gen_op_movl_spsr_T0(mask);
1093    } else {
1094        gen_op_movl_cpsr_T0(mask);
1095    }
1096    gen_lookup_tb(s);
1097    return 0;
1098}
1099
1100static void gen_exception_return(DisasContext *s)
1101{
1102    gen_op_movl_reg_TN[0][15]();
1103    gen_op_movl_T0_spsr();
1104    gen_op_movl_cpsr_T0(0xffffffff);
1105    s->is_jmp = DISAS_UPDATE;
1106}
1107
1108static void disas_arm_insn(CPUState * env, DisasContext *s)
1109{
1110    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
1111
1112    insn = ldl_code(s->pc);
1113    s->pc += 4;
1114
1115    cond = insn >> 28;
1116    if (cond == 0xf){
1117        /* Unconditional instructions.  */
1118        if ((insn & 0x0d70f000) == 0x0550f000)
1119            return; /* PLD */
1120        else if ((insn & 0x0e000000) == 0x0a000000) {
1121            /* branch link and change to thumb (blx <offset>) */
1122            int32_t offset;
1123
1124            val = (uint32_t)s->pc;
1125            gen_op_movl_T0_im(val);
1126            gen_movl_reg_T0(s, 14);
1127            /* Sign-extend the 24-bit offset */
1128            offset = (((int32_t)insn) << 8) >> 8;
1129            /* offset * 4 + bit24 * 2 + (thumb bit) */
1130            val += (offset << 2) | ((insn >> 23) & 2) | 1;
1131            /* pipeline offset */
1132            val += 4;
1133            gen_op_movl_T0_im(val);
1134            gen_bx(s);
1135            return;
1136        } else if ((insn & 0x0fe00000) == 0x0c400000) {
1137            /* Coprocessor double register transfer.  */
1138        } else if ((insn & 0x0f000010) == 0x0e000010) {
1139            /* Additional coprocessor register transfer.  */
1140        } else if ((insn & 0x0ff10010) == 0x01000000) {
1141            /* cps (privileged) */
1142        } else if ((insn & 0x0ffffdff) == 0x01010000) {
1143            /* setend */
1144            if (insn & (1 << 9)) {
1145                /* BE8 mode not implemented.  */
1146                goto illegal_op;
1147            }
1148            return;
1149        }
1150        goto illegal_op;
1151    }
1152    if (cond != 0xe) {
1153        /* if not always execute, we generate a conditional jump to
1154           next instruction */
1155        s->condlabel = gen_new_label();
1156        gen_test_cc[cond ^ 1](s->condlabel);
1157        s->condjmp = 1;
1158        //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
1159        //s->is_jmp = DISAS_JUMP_NEXT;
1160    }
1161    if ((insn & 0x0f900000) == 0x03000000) {
1162        if ((insn & 0x0fb0f000) != 0x0320f000)
1163            goto illegal_op;
1164        /* CPSR = immediate */
1165        val = insn & 0xff;
1166        shift = ((insn >> 8) & 0xf) * 2;
1167        if (shift)
1168            val = (val >> shift) | (val << (32 - shift));
1169        gen_op_movl_T0_im(val);
1170        i = ((insn & (1 << 22)) != 0);
1171        if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
1172            goto illegal_op;
1173    } else if ((insn & 0x0f900000) == 0x01000000
1174               && (insn & 0x00000090) != 0x00000090) {
1175        /* miscellaneous instructions */
1176        op1 = (insn >> 21) & 3;
1177        sh = (insn >> 4) & 0xf;
1178        rm = insn & 0xf;
1179        switch (sh) {
1180        case 0x0: /* move program status register */
1181            if (op1 & 1) {
1182                /* PSR = reg */
1183                gen_movl_T0_reg(s, rm);
1184                i = ((op1 & 2) != 0);
1185                if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
1186                    goto illegal_op;
1187            } else {
1188                /* reg = PSR */
1189                rd = (insn >> 12) & 0xf;
1190                if (op1 & 2) {
1191                    if (IS_USER(s))
1192                        goto illegal_op;
1193                    gen_op_movl_T0_spsr();
1194                } else {
1195                    gen_op_movl_T0_cpsr();
1196                }
1197                gen_movl_reg_T0(s, rd);
1198            }
1199            break;
1200        case 0x1:
1201            if (op1 == 1) {
1202                /* branch/exchange thumb (bx).  */
1203                gen_movl_T0_reg(s, rm);
1204                gen_bx(s);
1205            } else if (op1 == 3) {
1206                /* clz */
1207                rd = (insn >> 12) & 0xf;
1208                gen_movl_T0_reg(s, rm);
1209                gen_op_clz_T0();
1210                gen_movl_reg_T0(s, rd);
1211            } else {
1212                goto illegal_op;
1213            }
1214            break;
1215        case 0x2:
1216            if (op1 == 1) {
1217                ARCH(5J); /* bxj */
1218                /* Trivial implementation equivalent to bx.  */
1219                gen_movl_T0_reg(s, rm);
1220                gen_bx(s);
1221            } else {
1222                goto illegal_op;
1223            }
1224            break;
1225        case 0x3:
1226            if (op1 != 1)
1227              goto illegal_op;
1228
1229            /* branch link/exchange thumb (blx) */
1230            val = (uint32_t)s->pc;
1231            gen_op_movl_T0_im(val);
1232            gen_movl_reg_T0(s, 14);
1233            gen_movl_T0_reg(s, rm);
1234            gen_bx(s);
1235            break;
1236        case 0x5: /* saturating add/subtract */
1237            rd = (insn >> 12) & 0xf;
1238            rn = (insn >> 16) & 0xf;
1239            gen_movl_T0_reg(s, rm);
1240            gen_movl_T1_reg(s, rn);
1241            if (op1 & 2)
1242                gen_op_double_T1_saturate();
1243            if (op1 & 1)
1244                gen_op_subl_T0_T1_saturate();
1245            else
1246                gen_op_addl_T0_T1_saturate();
1247            gen_movl_reg_T0(s, rd);
1248            break;
1249        case 7: /* bkpt */
1250            gen_op_movl_T0_im((long)s->pc - 4);
1251            gen_op_movl_reg_TN[0][15]();
1252            gen_op_bkpt();
1253            s->is_jmp = DISAS_JUMP;
1254            break;
1255        case 0x8: /* signed multiply */
1256        case 0xa:
1257        case 0xc:
1258        case 0xe:
1259            rs = (insn >> 8) & 0xf;
1260            rn = (insn >> 12) & 0xf;
1261            rd = (insn >> 16) & 0xf;
1262            if (op1 == 1) {
1263                /* (32 * 16) >> 16 */
1264                gen_movl_T0_reg(s, rm);
1265                gen_movl_T1_reg(s, rs);
1266                if (sh & 4)
1267                    gen_op_sarl_T1_im(16);
1268                else
1269                    gen_op_sxth_T1();
1270                gen_op_imulw_T0_T1();
1271                if ((sh & 2) == 0) {
1272                    gen_movl_T1_reg(s, rn);
1273                    gen_op_addl_T0_T1_setq();
1274                }
1275                gen_movl_reg_T0(s, rd);
1276            } else {
1277                /* 16 * 16 */
1278                gen_movl_T0_reg(s, rm);
1279                gen_movl_T1_reg(s, rs);
1280                gen_mulxy(sh & 2, sh & 4);
1281                if (op1 == 2) {
1282                    gen_op_signbit_T1_T0();
1283                    gen_op_addq_T0_T1(rn, rd);
1284                    gen_movl_reg_T0(s, rn);
1285                    gen_movl_reg_T1(s, rd);
1286                } else {
1287                    if (op1 == 0) {
1288                        gen_movl_T1_reg(s, rn);
1289                        gen_op_addl_T0_T1_setq();
1290                    }
1291                    gen_movl_reg_T0(s, rd);
1292                }
1293            }
1294            break;
1295        default:
1296            goto illegal_op;
1297        }
1298    } else if (((insn & 0x0e000000) == 0 &&
1299                (insn & 0x00000090) != 0x90) ||
1300               ((insn & 0x0e000000) == (1 << 25))) {
1301        int set_cc, logic_cc, shiftop;
1302
1303        op1 = (insn >> 21) & 0xf;
1304        set_cc = (insn >> 20) & 1;
1305        logic_cc = table_logic_cc[op1] & set_cc;
1306
1307        /* data processing instruction */
1308        if (insn & (1 << 25)) {
1309            /* immediate operand */
1310            val = insn & 0xff;
1311            shift = ((insn >> 8) & 0xf) * 2;
1312            if (shift)
1313                val = (val >> shift) | (val << (32 - shift));
1314            gen_op_movl_T1_im(val);
1315            if (logic_cc && shift)
1316                gen_op_mov_CF_T1();
1317        } else {
1318            /* register */
1319            rm = (insn) & 0xf;
1320            gen_movl_T1_reg(s, rm);
1321            shiftop = (insn >> 5) & 3;
1322            if (!(insn & (1 << 4))) {
1323                shift = (insn >> 7) & 0x1f;
1324                if (shift != 0) {
1325                    if (logic_cc) {
1326                        gen_shift_T1_im_cc[shiftop](shift);
1327                    } else {
1328                        gen_shift_T1_im[shiftop](shift);
1329                    }
1330                } else if (shiftop != 0) {
1331                    if (logic_cc) {
1332                        gen_shift_T1_0_cc[shiftop]();
1333                    } else {
1334                        gen_shift_T1_0[shiftop]();
1335                    }
1336                }
1337            } else {
1338                rs = (insn >> 8) & 0xf;
1339                gen_movl_T0_reg(s, rs);
1340                if (logic_cc) {
1341                    gen_shift_T1_T0_cc[shiftop]();
1342                } else {
1343                    gen_shift_T1_T0[shiftop]();
1344                }
1345            }
1346        }
1347        if (op1 != 0x0f && op1 != 0x0d) {
1348            rn = (insn >> 16) & 0xf;
1349            gen_movl_T0_reg(s, rn);
1350        }
1351        rd = (insn >> 12) & 0xf;
1352        switch(op1) {
1353        case 0x00:
1354            gen_op_andl_T0_T1();
1355            gen_movl_reg_T0(s, rd);
1356            if (logic_cc)
1357                gen_op_logic_T0_cc();
1358            break;
1359        case 0x01:
1360            gen_op_xorl_T0_T1();
1361            gen_movl_reg_T0(s, rd);
1362            if (logic_cc)
1363                gen_op_logic_T0_cc();
1364            break;
1365        case 0x02:
1366            if (set_cc && rd == 15) {
1367                /* SUBS r15, ... is used for exception return.  */
1368                if (IS_USER(s))
1369                    goto illegal_op;
1370                gen_op_subl_T0_T1_cc();
1371                gen_exception_return(s);
1372            } else {
1373                if (set_cc)
1374                    gen_op_subl_T0_T1_cc();
1375                else
1376                    gen_op_subl_T0_T1();
1377                gen_movl_reg_T0(s, rd);
1378            }
1379            break;
1380        case 0x03:
1381            if (set_cc)
1382                gen_op_rsbl_T0_T1_cc();
1383            else
1384                gen_op_rsbl_T0_T1();
1385            gen_movl_reg_T0(s, rd);
1386            break;
1387        case 0x04:
1388            if (set_cc)
1389                gen_op_addl_T0_T1_cc();
1390            else
1391                gen_op_addl_T0_T1();
1392            gen_movl_reg_T0(s, rd);
1393            break;
1394        case 0x05:
1395            if (set_cc)
1396                gen_op_adcl_T0_T1_cc();
1397            else
1398                gen_op_adcl_T0_T1();
1399            gen_movl_reg_T0(s, rd);
1400            break;
1401        case 0x06:
1402            if (set_cc)
1403                gen_op_sbcl_T0_T1_cc();
1404            else
1405                gen_op_sbcl_T0_T1();
1406            gen_movl_reg_T0(s, rd);
1407            break;
1408        case 0x07:
1409            if (set_cc)
1410                gen_op_rscl_T0_T1_cc();
1411            else
1412                gen_op_rscl_T0_T1();
1413            gen_movl_reg_T0(s, rd);
1414            break;
1415        case 0x08:
1416            if (set_cc) {
1417                gen_op_andl_T0_T1();
1418                gen_op_logic_T0_cc();
1419            }
1420            break;
1421        case 0x09:
1422            if (set_cc) {
1423                gen_op_xorl_T0_T1();
1424                gen_op_logic_T0_cc();
1425            }
1426            break;
1427        case 0x0a:
1428            if (set_cc) {
1429                gen_op_subl_T0_T1_cc();
1430            }
1431            break;
1432        case 0x0b:
1433            if (set_cc) {
1434                gen_op_addl_T0_T1_cc();
1435            }
1436            break;
1437        case 0x0c:
1438            gen_op_orl_T0_T1();
1439            gen_movl_reg_T0(s, rd);
1440            if (logic_cc)
1441                gen_op_logic_T0_cc();
1442            break;
1443        case 0x0d:
1444            if (logic_cc && rd == 15) {
1445                /* MOVS r15, ... is used for exception return.  */
1446                if (IS_USER(s))
1447                    goto illegal_op;
1448                gen_op_movl_T0_T1();
1449                gen_exception_return(s);
1450            } else {
1451                gen_movl_reg_T1(s, rd);
1452                if (logic_cc)
1453                    gen_op_logic_T1_cc();
1454            }
1455            break;
1456        case 0x0e:
1457            gen_op_bicl_T0_T1();
1458            gen_movl_reg_T0(s, rd);
1459            if (logic_cc)
1460                gen_op_logic_T0_cc();
1461            break;
1462        default:
1463        case 0x0f:
1464            gen_op_notl_T1();
1465            gen_movl_reg_T1(s, rd);
1466            if (logic_cc)
1467                gen_op_logic_T1_cc();
1468            break;
1469        }
1470    } else {
1471        /* other instructions */
1472        op1 = (insn >> 24) & 0xf;
1473        switch(op1) {
1474        case 0x0:
1475        case 0x1:
1476            /* multiplies, extra load/stores */
1477            sh = (insn >> 5) & 3;
1478            if (sh == 0) {
1479                if (op1 == 0x0) {
1480                    rd = (insn >> 16) & 0xf;
1481                    rn = (insn >> 12) & 0xf;
1482                    rs = (insn >> 8) & 0xf;
1483                    rm = (insn) & 0xf;
1484                    if (((insn >> 22) & 3) == 0) {
1485                        /* 32 bit mul */
1486                        gen_movl_T0_reg(s, rs);
1487                        gen_movl_T1_reg(s, rm);
1488                        gen_op_mul_T0_T1();
1489                        if (insn & (1 << 21)) {
1490                            gen_movl_T1_reg(s, rn);
1491                            gen_op_addl_T0_T1();
1492                        }
1493                        if (insn & (1 << 20))
1494                            gen_op_logic_T0_cc();
1495                        gen_movl_reg_T0(s, rd);
1496                    } else {
1497                        /* 64 bit mul */
1498                        gen_movl_T0_reg(s, rs);
1499                        gen_movl_T1_reg(s, rm);
1500                        if (insn & (1 << 22))
1501                            gen_op_imull_T0_T1();
1502                        else
1503                            gen_op_mull_T0_T1();
1504                        if (insn & (1 << 21)) /* mult accumulate */
1505                            gen_op_addq_T0_T1(rn, rd);
1506                        if (!(insn & (1 << 23))) { /* double accumulate */
1507                            ARCH(6);
1508                            gen_op_addq_lo_T0_T1(rn);
1509                            gen_op_addq_lo_T0_T1(rd);
1510                        }
1511                        if (insn & (1 << 20))
1512                            gen_op_logicq_cc();
1513                        gen_movl_reg_T0(s, rn);
1514                        gen_movl_reg_T1(s, rd);
1515                    }
1516                } else {
1517                    rn = (insn >> 16) & 0xf;
1518                    rd = (insn >> 12) & 0xf;
1519                    if (insn & (1 << 23)) {
1520                        /* load/store exclusive */
1521                        goto illegal_op;
1522                    } else {
1523                        /* SWP instruction */
1524                        rm = (insn) & 0xf;
1525
1526                        gen_movl_T0_reg(s, rm);
1527                        gen_movl_T1_reg(s, rn);
1528                        if (insn & (1 << 22)) {
1529                            gen_ldst(swpb, s);
1530                        } else {
1531                            gen_ldst(swpl, s);
1532                        }
1533                        gen_movl_reg_T0(s, rd);
1534                    }
1535                }
1536            } else {
1537                int address_offset;
1538                /* Misc load/store */
1539                rn = (insn >> 16) & 0xf;
1540                rd = (insn >> 12) & 0xf;
1541                gen_movl_T1_reg(s, rn);
1542                if (insn & (1 << 24))
1543                    gen_add_datah_offset(s, insn, 0);
1544                address_offset = 0;
1545                if (insn & (1 << 20)) {
1546                    /* load */
1547                    switch(sh) {
1548                    case 1:
1549                        gen_ldst(lduw, s);
1550                        break;
1551                    case 2:
1552                        gen_ldst(ldsb, s);
1553                        break;
1554                    default:
1555                    case 3:
1556                        gen_ldst(ldsw, s);
1557                        break;
1558                    }
1559                    gen_movl_reg_T0(s, rd);
1560                } else if (sh & 2) {
1561                    /* doubleword */
1562                    if (sh & 1) {
1563                        /* store */
1564                        gen_movl_T0_reg(s, rd);
1565                        gen_ldst(stl, s);
1566                        gen_op_addl_T1_im(4);
1567                        gen_movl_T0_reg(s, rd + 1);
1568                        gen_ldst(stl, s);
1569                    } else {
1570                        /* load */
1571                        gen_ldst(ldl, s);
1572                        gen_movl_reg_T0(s, rd);
1573                        gen_op_addl_T1_im(4);
1574                        gen_ldst(ldl, s);
1575                        gen_movl_reg_T0(s, rd + 1);
1576                    }
1577                    address_offset = -4;
1578                } else {
1579                    /* store */
1580                    gen_movl_T0_reg(s, rd);
1581                    gen_ldst(stw, s);
1582                }
1583                if (!(insn & (1 << 24))) {
1584                    gen_add_datah_offset(s, insn, address_offset);
1585                    gen_movl_reg_T1(s, rn);
1586                } else if (insn & (1 << 21)) {
1587                    if (address_offset)
1588                        gen_op_addl_T1_im(address_offset);
1589                    gen_movl_reg_T1(s, rn);
1590                }
1591            }
1592            break;
1593        case 0x4:
1594        case 0x5:
1595        case 0x6:
1596        case 0x7:
1597            /* Check for undefined extension instructions
1598             * per the ARM Bible IE:
1599             * xxxx 0111 1111 xxxx  xxxx xxxx 1111 xxxx
1600             */
1601            sh = (0xf << 20) | (0xf << 4);
1602            if (op1 == 0x7 && ((insn & sh) == sh))
1603            {
1604                goto illegal_op;
1605            }
1606            /* load/store byte/word */
1607            rn = (insn >> 16) & 0xf;
1608            rd = (insn >> 12) & 0xf;
1609            gen_movl_T1_reg(s, rn);
1610            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
1611            if (insn & (1 << 24))
1612                gen_add_data_offset(s, insn);
1613            if (insn & (1 << 20)) {
1614                /* load */
1615#if defined(CONFIG_USER_ONLY)
1616                if (insn & (1 << 22))
1617                    gen_op_ldub_raw();
1618                else
1619                    gen_op_ldl_raw();
1620#else
1621                if (insn & (1 << 22)) {
1622                    if (i)
1623                        gen_op_ldub_user();
1624                    else
1625                        gen_op_ldub_kernel();
1626                } else {
1627                    if (i)
1628                        gen_op_ldl_user();
1629                    else
1630                        gen_op_ldl_kernel();
1631                }
1632#endif
1633                if (rd == 15)
1634                    gen_bx(s);
1635                else
1636                    gen_movl_reg_T0(s, rd);
1637            } else {
1638                /* store */
1639                gen_movl_T0_reg(s, rd);
1640#if defined(CONFIG_USER_ONLY)
1641                if (insn & (1 << 22))
1642                    gen_op_stb_raw();
1643                else
1644                    gen_op_stl_raw();
1645#else
1646                if (insn & (1 << 22)) {
1647                    if (i)
1648                        gen_op_stb_user();
1649                    else
1650                        gen_op_stb_kernel();
1651                } else {
1652                    if (i)
1653                        gen_op_stl_user();
1654                    else
1655                        gen_op_stl_kernel();
1656                }
1657#endif
1658            }
1659            if (!(insn & (1 << 24))) {
1660                gen_add_data_offset(s, insn);
1661                gen_movl_reg_T1(s, rn);
1662            } else if (insn & (1 << 21))
1663                gen_movl_reg_T1(s, rn); {
1664            }
1665            break;
1666        case 0x08:
1667        case 0x09:
1668            {
1669                int j, n, user, loaded_base;
1670                /* load/store multiple words */
1671                /* XXX: store correct base if write back */
1672                user = 0;
1673                if (insn & (1 << 22)) {
1674                    if (IS_USER(s))
1675                        goto illegal_op; /* only usable in supervisor mode */
1676
1677                    if ((insn & (1 << 15)) == 0)
1678                        user = 1;
1679                }
1680                rn = (insn >> 16) & 0xf;
1681                gen_movl_T1_reg(s, rn);
1682
1683                /* compute total size */
1684                loaded_base = 0;
1685                n = 0;
1686                for(i=0;i<16;i++) {
1687                    if (insn & (1 << i))
1688                        n++;
1689                }
1690                /* XXX: test invalid n == 0 case ? */
1691                if (insn & (1 << 23)) {
1692                    if (insn & (1 << 24)) {
1693                        /* pre increment */
1694                        gen_op_addl_T1_im(4);
1695                    } else {
1696                        /* post increment */
1697                    }
1698                } else {
1699                    if (insn & (1 << 24)) {
1700                        /* pre decrement */
1701                        gen_op_addl_T1_im(-(n * 4));
1702                    } else {
1703                        /* post decrement */
1704                        if (n != 1)
1705                            gen_op_addl_T1_im(-((n - 1) * 4));
1706                    }
1707                }
1708                j = 0;
1709                for(i=0;i<16;i++) {
1710                    if (insn & (1 << i)) {
1711                        if (insn & (1 << 20)) {
1712                            /* load */
1713                            gen_ldst(ldl, s);
1714                            if (i == 15) {
1715                                gen_bx(s);
1716                            } else if (user) {
1717                                gen_op_movl_user_T0(i);
1718                            } else if (i == rn) {
1719                                gen_op_movl_T2_T0();
1720                                loaded_base = 1;
1721                            } else {
1722                                gen_movl_reg_T0(s, i);
1723                            }
1724                        } else {
1725                            /* store */
1726                            if (i == 15) {
1727                                /* special case: r15 = PC + 12 */
1728                                val = (long)s->pc + 8;
1729                                gen_op_movl_TN_im[0](val);
1730                            } else if (user) {
1731                                gen_op_movl_T0_user(i);
1732                            } else {
1733                                gen_movl_T0_reg(s, i);
1734                            }
1735                            gen_ldst(stl, s);
1736                        }
1737                        j++;
1738                        /* no need to add after the last transfer */
1739                        if (j != n)
1740                            gen_op_addl_T1_im(4);
1741                    }
1742                }
1743                if (insn & (1 << 21)) {
1744                    /* write back */
1745                    if (insn & (1 << 23)) {
1746                        if (insn & (1 << 24)) {
1747                            /* pre increment */
1748                        } else {
1749                            /* post increment */
1750                            gen_op_addl_T1_im(4);
1751                        }
1752                    } else {
1753                        if (insn & (1 << 24)) {
1754                            /* pre decrement */
1755                            if (n != 1)
1756                                gen_op_addl_T1_im(-((n - 1) * 4));
1757                        } else {
1758                            /* post decrement */
1759                            gen_op_addl_T1_im(-(n * 4));
1760                        }
1761                    }
1762                    gen_movl_reg_T1(s, rn);
1763                }
1764                if (loaded_base) {
1765                    gen_op_movl_T0_T2();
1766                    gen_movl_reg_T0(s, rn);
1767                }
1768                if ((insn & (1 << 22)) && !user) {
1769                    /* Restore CPSR from SPSR.  */
1770                    gen_op_movl_T0_spsr();
1771                    gen_op_movl_cpsr_T0(0xffffffff);
1772                    s->is_jmp = DISAS_UPDATE;
1773                }
1774            }
1775            break;
1776        case 0xa:
1777        case 0xb:
1778            {
1779                int32_t offset;
1780
1781                /* branch (and link) */
1782                val = (int32_t)s->pc;
1783                if (insn & (1 << 24)) {
1784                    gen_op_movl_T0_im(val);
1785                    gen_op_movl_reg_TN[0][14]();
1786                }
1787                offset = (((int32_t)insn << 8) >> 8);
1788                val += (offset << 2) + 4;
1789                gen_jmp(s, val);
1790            }
1791            break;
1792        case 0xc:
1793        case 0xd:
1794        case 0xe:
1795            /* Coprocessor.  */
1796            op1 = (insn >> 8) & 0xf;
1797            switch (op1) {
1798            case 10:
1799            case 11:
1800                if (disas_vfp_insn (env, s, insn))
1801                    goto illegal_op;
1802                break;
1803            case 15:
1804                if (disas_cp15_insn (s, insn))
1805                    goto illegal_op;
1806                break;
1807            default:
1808                /* unknown coprocessor.  */
1809                goto illegal_op;
1810            }
1811            break;
1812        case 0xf:
1813            /* swi */
1814            gen_op_movl_T0_im((long)s->pc);
1815            gen_op_movl_reg_TN[0][15]();
1816            gen_op_swi();
1817            s->is_jmp = DISAS_JUMP;
1818            break;
1819        default:
1820        illegal_op:
1821            gen_op_movl_T0_im((long)s->pc - 4);
1822            gen_op_movl_reg_TN[0][15]();
1823            gen_op_undef_insn();
1824            s->is_jmp = DISAS_JUMP;
1825            break;
1826        }
1827    }
1828}
1829
1830static void disas_thumb_insn(DisasContext *s)
1831{
1832    uint32_t val, insn, op, rm, rn, rd, shift, cond;
1833    int32_t offset;
1834    int i;
1835
1836    insn = lduw_code(s->pc);
1837    s->pc += 2;
1838
1839    switch (insn >> 12) {
1840    case 0: case 1:
1841        rd = insn & 7;
1842        op = (insn >> 11) & 3;
1843        if (op == 3) {
1844            /* add/subtract */
1845            rn = (insn >> 3) & 7;
1846            gen_movl_T0_reg(s, rn);
1847            if (insn & (1 << 10)) {
1848                /* immediate */
1849                gen_op_movl_T1_im((insn >> 6) & 7);
1850            } else {
1851                /* reg */
1852                rm = (insn >> 6) & 7;
1853                gen_movl_T1_reg(s, rm);
1854            }
1855            if (insn & (1 << 9))
1856                gen_op_subl_T0_T1_cc();
1857            else
1858                gen_op_addl_T0_T1_cc();
1859            gen_movl_reg_T0(s, rd);
1860        } else {
1861            /* shift immediate */
1862            rm = (insn >> 3) & 7;
1863            shift = (insn >> 6) & 0x1f;
1864            gen_movl_T0_reg(s, rm);
1865            gen_shift_T0_im_thumb[op](shift);
1866            gen_movl_reg_T0(s, rd);
1867        }
1868        break;
1869    case 2: case 3:
1870        /* arithmetic large immediate */
1871        op = (insn >> 11) & 3;
1872        rd = (insn >> 8) & 0x7;
1873        if (op == 0) {
1874            gen_op_movl_T0_im(insn & 0xff);
1875        } else {
1876            gen_movl_T0_reg(s, rd);
1877            gen_op_movl_T1_im(insn & 0xff);
1878        }
1879        switch (op) {
1880        case 0: /* mov */
1881            gen_op_logic_T0_cc();
1882            break;
1883        case 1: /* cmp */
1884            gen_op_subl_T0_T1_cc();
1885            break;
1886        case 2: /* add */
1887            gen_op_addl_T0_T1_cc();
1888            break;
1889        case 3: /* sub */
1890            gen_op_subl_T0_T1_cc();
1891            break;
1892        }
1893        if (op != 1)
1894            gen_movl_reg_T0(s, rd);
1895        break;
1896    case 4:
1897        if (insn & (1 << 11)) {
1898            rd = (insn >> 8) & 7;
1899            /* load pc-relative.  Bit 1 of PC is ignored.  */
1900            val = s->pc + 2 + ((insn & 0xff) * 4);
1901            val &= ~(uint32_t)2;
1902            gen_op_movl_T1_im(val);
1903            gen_ldst(ldl, s);
1904            gen_movl_reg_T0(s, rd);
1905            break;
1906        }
1907        if (insn & (1 << 10)) {
1908            /* data processing extended or blx */
1909            rd = (insn & 7) | ((insn >> 4) & 8);
1910            rm = (insn >> 3) & 0xf;
1911            op = (insn >> 8) & 3;
1912            switch (op) {
1913            case 0: /* add */
1914                gen_movl_T0_reg(s, rd);
1915                gen_movl_T1_reg(s, rm);
1916                gen_op_addl_T0_T1();
1917                gen_movl_reg_T0(s, rd);
1918                break;
1919            case 1: /* cmp */
1920                gen_movl_T0_reg(s, rd);
1921                gen_movl_T1_reg(s, rm);
1922                gen_op_subl_T0_T1_cc();
1923                break;
1924            case 2: /* mov/cpy */
1925                gen_movl_T0_reg(s, rm);
1926                gen_movl_reg_T0(s, rd);
1927                break;
1928            case 3:/* branch [and link] exchange thumb register */
1929                if (insn & (1 << 7)) {
1930                    val = (uint32_t)s->pc | 1;
1931                    gen_op_movl_T1_im(val);
1932                    gen_movl_reg_T1(s, 14);
1933                }
1934                gen_movl_T0_reg(s, rm);
1935                gen_bx(s);
1936                break;
1937            }
1938            break;
1939        }
1940
1941        /* data processing register */
1942        rd = insn & 7;
1943        rm = (insn >> 3) & 7;
1944        op = (insn >> 6) & 0xf;
1945        if (op == 2 || op == 3 || op == 4 || op == 7) {
1946            /* the shift/rotate ops want the operands backwards */
1947            val = rm;
1948            rm = rd;
1949            rd = val;
1950            val = 1;
1951        } else {
1952            val = 0;
1953        }
1954
1955        if (op == 9) /* neg */
1956            gen_op_movl_T0_im(0);
1957        else if (op != 0xf) /* mvn doesn't read its first operand */
1958            gen_movl_T0_reg(s, rd);
1959
1960        gen_movl_T1_reg(s, rm);
1961        switch (op) {
1962        case 0x0: /* and */
1963            gen_op_andl_T0_T1();
1964            gen_op_logic_T0_cc();
1965            break;
1966        case 0x1: /* eor */
1967            gen_op_xorl_T0_T1();
1968            gen_op_logic_T0_cc();
1969            break;
1970        case 0x2: /* lsl */
1971            gen_op_shll_T1_T0_cc();
1972            gen_op_logic_T1_cc();
1973            break;
1974        case 0x3: /* lsr */
1975            gen_op_shrl_T1_T0_cc();
1976            gen_op_logic_T1_cc();
1977            break;
1978        case 0x4: /* asr */
1979            gen_op_sarl_T1_T0_cc();
1980            gen_op_logic_T1_cc();
1981            break;
1982        case 0x5: /* adc */
1983            gen_op_adcl_T0_T1_cc();
1984            break;
1985        case 0x6: /* sbc */
1986            gen_op_sbcl_T0_T1_cc();
1987            break;
1988        case 0x7: /* ror */
1989            gen_op_rorl_T1_T0_cc();
1990            gen_op_logic_T1_cc();
1991            break;
1992        case 0x8: /* tst */
1993            gen_op_andl_T0_T1();
1994            gen_op_logic_T0_cc();
1995            rd = 16;
1996            break;
1997        case 0x9: /* neg */
1998            gen_op_subl_T0_T1_cc();
1999            break;
2000        case 0xa: /* cmp */
2001            gen_op_subl_T0_T1_cc();
2002            rd = 16;
2003            break;
2004        case 0xb: /* cmn */
2005            gen_op_addl_T0_T1_cc();
2006            rd = 16;
2007            break;
2008        case 0xc: /* orr */
2009            gen_op_orl_T0_T1();
2010            gen_op_logic_T0_cc();
2011            break;
2012        case 0xd: /* mul */
2013            gen_op_mull_T0_T1();
2014            gen_op_logic_T0_cc();
2015            break;
2016        case 0xe: /* bic */
2017            gen_op_bicl_T0_T1();
2018            gen_op_logic_T0_cc();
2019            break;
2020        case 0xf: /* mvn */
2021            gen_op_notl_T1();
2022            gen_op_logic_T1_cc();
2023            val = 1;
2024            rm = rd;
2025            break;
2026        }
2027        if (rd != 16) {
2028            if (val)
2029                gen_movl_reg_T1(s, rm);
2030            else
2031                gen_movl_reg_T0(s, rd);
2032        }
2033        break;
2034
2035    case 5:
2036        /* load/store register offset.  */
2037        rd = insn & 7;
2038        rn = (insn >> 3) & 7;
2039        rm = (insn >> 6) & 7;
2040        op = (insn >> 9) & 7;
2041        gen_movl_T1_reg(s, rn);
2042        gen_movl_T2_reg(s, rm);
2043        gen_op_addl_T1_T2();
2044
2045        if (op < 3) /* store */
2046            gen_movl_T0_reg(s, rd);
2047
2048        switch (op) {
2049        case 0: /* str */
2050            gen_ldst(stl, s);
2051            break;
2052        case 1: /* strh */
2053            gen_ldst(stw, s);
2054            break;
2055        case 2: /* strb */
2056            gen_ldst(stb, s);
2057            break;
2058        case 3: /* ldrsb */
2059            gen_ldst(ldsb, s);
2060            break;
2061        case 4: /* ldr */
2062            gen_ldst(ldl, s);
2063            break;
2064        case 5: /* ldrh */
2065            gen_ldst(lduw, s);
2066            break;
2067        case 6: /* ldrb */
2068            gen_ldst(ldub, s);
2069            break;
2070        case 7: /* ldrsh */
2071            gen_ldst(ldsw, s);
2072            break;
2073        }
2074        if (op >= 3) /* load */
2075            gen_movl_reg_T0(s, rd);
2076        break;
2077
2078    case 6:
2079        /* load/store word immediate offset */
2080        rd = insn & 7;
2081        rn = (insn >> 3) & 7;
2082        gen_movl_T1_reg(s, rn);
2083        val = (insn >> 4) & 0x7c;
2084        gen_op_movl_T2_im(val);
2085        gen_op_addl_T1_T2();
2086
2087        if (insn & (1 << 11)) {
2088            /* load */
2089            gen_ldst(ldl, s);
2090            gen_movl_reg_T0(s, rd);
2091        } else {
2092            /* store */
2093            gen_movl_T0_reg(s, rd);
2094            gen_ldst(stl, s);
2095        }
2096        break;
2097
2098    case 7:
2099        /* load/store byte immediate offset */
2100        rd = insn & 7;
2101        rn = (insn >> 3) & 7;
2102        gen_movl_T1_reg(s, rn);
2103        val = (insn >> 6) & 0x1f;
2104        gen_op_movl_T2_im(val);
2105        gen_op_addl_T1_T2();
2106
2107        if (insn & (1 << 11)) {
2108            /* load */
2109            gen_ldst(ldub, s);
2110            gen_movl_reg_T0(s, rd);
2111        } else {
2112            /* store */
2113            gen_movl_T0_reg(s, rd);
2114            gen_ldst(stb, s);
2115        }
2116        break;
2117
2118    case 8:
2119        /* load/store halfword immediate offset */
2120        rd = insn & 7;
2121        rn = (insn >> 3) & 7;
2122        gen_movl_T1_reg(s, rn);
2123        val = (insn >> 5) & 0x3e;
2124        gen_op_movl_T2_im(val);
2125        gen_op_addl_T1_T2();
2126
2127        if (insn & (1 << 11)) {
2128            /* load */
2129            gen_ldst(lduw, s);
2130            gen_movl_reg_T0(s, rd);
2131        } else {
2132            /* store */
2133            gen_movl_T0_reg(s, rd);
2134            gen_ldst(stw, s);
2135        }
2136        break;
2137
2138    case 9:
2139        /* load/store from stack */
2140        rd = (insn >> 8) & 7;
2141        gen_movl_T1_reg(s, 13);
2142        val = (insn & 0xff) * 4;
2143        gen_op_movl_T2_im(val);
2144        gen_op_addl_T1_T2();
2145
2146        if (insn & (1 << 11)) {
2147            /* load */
2148            gen_ldst(ldl, s);
2149            gen_movl_reg_T0(s, rd);
2150        } else {
2151            /* store */
2152            gen_movl_T0_reg(s, rd);
2153            gen_ldst(stl, s);
2154        }
2155        break;
2156
2157    case 10:
2158        /* add to high reg */
2159        rd = (insn >> 8) & 7;
2160        if (insn & (1 << 11)) {
2161            /* SP */
2162            gen_movl_T0_reg(s, 13);
2163        } else {
2164            /* PC. bit 1 is ignored.  */
2165            gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2);
2166        }
2167        val = (insn & 0xff) * 4;
2168        gen_op_movl_T1_im(val);
2169        gen_op_addl_T0_T1();
2170        gen_movl_reg_T0(s, rd);
2171        break;
2172
2173    case 11:
2174        /* misc */
2175        op = (insn >> 8) & 0xf;
2176        switch (op) {
2177        case 0:
2178            /* adjust stack pointer */
2179            gen_movl_T1_reg(s, 13);
2180            val = (insn & 0x7f) * 4;
2181            if (insn & (1 << 7))
2182              val = -(int32_t)val;
2183            gen_op_movl_T2_im(val);
2184            gen_op_addl_T1_T2();
2185            gen_movl_reg_T1(s, 13);
2186            break;
2187
2188        case 4: case 5: case 0xc: case 0xd:
2189            /* push/pop */
2190            gen_movl_T1_reg(s, 13);
2191            if (insn & (1 << 8))
2192                offset = 4;
2193            else
2194                offset = 0;
2195            for (i = 0; i < 8; i++) {
2196                if (insn & (1 << i))
2197                    offset += 4;
2198            }
2199            if ((insn & (1 << 11)) == 0) {
2200                gen_op_movl_T2_im(-offset);
2201                gen_op_addl_T1_T2();
2202            }
2203            gen_op_movl_T2_im(4);
2204            for (i = 0; i < 8; i++) {
2205                if (insn & (1 << i)) {
2206                    if (insn & (1 << 11)) {
2207                        /* pop */
2208                        gen_ldst(ldl, s);
2209                        gen_movl_reg_T0(s, i);
2210                    } else {
2211                        /* push */
2212                        gen_movl_T0_reg(s, i);
2213                        gen_ldst(stl, s);
2214                    }
2215                    /* advance to the next address.  */
2216                    gen_op_addl_T1_T2();
2217                }
2218            }
2219            if (insn & (1 << 8)) {
2220                if (insn & (1 << 11)) {
2221                    /* pop pc */
2222                    gen_ldst(ldl, s);
2223                    /* don't set the pc until the rest of the instruction
2224                       has completed */
2225                } else {
2226                    /* push lr */
2227                    gen_movl_T0_reg(s, 14);
2228                    gen_ldst(stl, s);
2229                }
2230                gen_op_addl_T1_T2();
2231            }
2232            if ((insn & (1 << 11)) == 0) {
2233                gen_op_movl_T2_im(-offset);
2234                gen_op_addl_T1_T2();
2235            }
2236            /* write back the new stack pointer */
2237            gen_movl_reg_T1(s, 13);
2238            /* set the new PC value */
2239            if ((insn & 0x0900) == 0x0900)
2240                gen_bx(s);
2241            break;
2242
2243        case 0xe: /* bkpt */
2244            gen_op_movl_T0_im((long)s->pc - 2);
2245            gen_op_movl_reg_TN[0][15]();
2246            gen_op_bkpt();
2247            s->is_jmp = DISAS_JUMP;
2248            break;
2249
2250        default:
2251            goto undef;
2252        }
2253        break;
2254
2255    case 12:
2256        /* load/store multiple */
2257        rn = (insn >> 8) & 0x7;
2258        gen_movl_T1_reg(s, rn);
2259        gen_op_movl_T2_im(4);
2260        for (i = 0; i < 8; i++) {
2261            if (insn & (1 << i)) {
2262                if (insn & (1 << 11)) {
2263                    /* load */
2264                    gen_ldst(ldl, s);
2265                    gen_movl_reg_T0(s, i);
2266                } else {
2267                    /* store */
2268                    gen_movl_T0_reg(s, i);
2269                    gen_ldst(stl, s);
2270                }
2271                /* advance to the next address */
2272                gen_op_addl_T1_T2();
2273            }
2274        }
2275        /* Base register writeback.  */
2276        if ((insn & (1 << rn)) == 0)
2277            gen_movl_reg_T1(s, rn);
2278        break;
2279
2280    case 13:
2281        /* conditional branch or swi */
2282        cond = (insn >> 8) & 0xf;
2283        if (cond == 0xe)
2284            goto undef;
2285
2286        if (cond == 0xf) {
2287            /* swi */
2288            gen_op_movl_T0_im((long)s->pc | 1);
2289            /* Don't set r15.  */
2290            gen_op_movl_reg_TN[0][15]();
2291            gen_op_swi();
2292            s->is_jmp = DISAS_JUMP;
2293            break;
2294        }
2295        /* generate a conditional jump to next instruction */
2296        s->condlabel = gen_new_label();
2297        gen_test_cc[cond ^ 1](s->condlabel);
2298        s->condjmp = 1;
2299        //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
2300        //s->is_jmp = DISAS_JUMP_NEXT;
2301        gen_movl_T1_reg(s, 15);
2302
2303        /* jump to the offset */
2304        val = (uint32_t)s->pc + 2;
2305        offset = ((int32_t)insn << 24) >> 24;
2306        val += offset << 1;
2307        gen_jmp(s, val);
2308        break;
2309
2310    case 14:
2311        /* unconditional branch */
2312        if (insn & (1 << 11)) {
2313            /* Second half of blx.  */
2314            offset = ((insn & 0x7ff) << 1);
2315            gen_movl_T0_reg(s, 14);
2316            gen_op_movl_T1_im(offset);
2317            gen_op_addl_T0_T1();
2318            gen_op_movl_T1_im(0xfffffffc);
2319            gen_op_andl_T0_T1();
2320
2321            val = (uint32_t)s->pc;
2322            gen_op_movl_T1_im(val | 1);
2323            gen_movl_reg_T1(s, 14);
2324            gen_bx(s);
2325            break;
2326        }
2327        val = (uint32_t)s->pc;
2328        offset = ((int32_t)insn << 21) >> 21;
2329        val += (offset << 1) + 2;
2330        gen_jmp(s, val);
2331        break;
2332
2333    case 15:
2334        /* branch and link [and switch to arm] */
2335        if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
2336            /* Instruction spans a page boundary.  Implement it as two
2337               16-bit instructions in case the second half causes an
2338               prefetch abort.  */
2339            offset = ((int32_t)insn << 21) >> 9;
2340            val = s->pc + 2 + offset;
2341            gen_op_movl_T0_im(val);
2342            gen_movl_reg_T0(s, 14);
2343            break;
2344        }
2345        if (insn & (1 << 11)) {
2346            /* Second half of bl.  */
2347            offset = ((insn & 0x7ff) << 1) | 1;
2348            gen_movl_T0_reg(s, 14);
2349            gen_op_movl_T1_im(offset);
2350            gen_op_addl_T0_T1();
2351
2352            val = (uint32_t)s->pc;
2353            gen_op_movl_T1_im(val | 1);
2354            gen_movl_reg_T1(s, 14);
2355            gen_bx(s);
2356            break;
2357        }
2358        offset = ((int32_t)insn << 21) >> 10;
2359        insn = lduw_code(s->pc);
2360        offset |= insn & 0x7ff;
2361
2362        val = (uint32_t)s->pc + 2;
2363        gen_op_movl_T1_im(val | 1);
2364        gen_movl_reg_T1(s, 14);
2365
2366        val += offset << 1;
2367        if (insn & (1 << 12)) {
2368            /* bl */
2369            gen_jmp(s, val);
2370        } else {
2371            /* blx */
2372            val &= ~(uint32_t)2;
2373            gen_op_movl_T0_im(val);
2374            gen_bx(s);
2375        }
2376    }
2377    return;
2378undef:
2379    gen_op_movl_T0_im((long)s->pc - 2);
2380    gen_op_movl_reg_TN[0][15]();
2381    gen_op_undef_insn();
2382    s->is_jmp = DISAS_JUMP;
2383}
2384
2385/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
2386   basic block 'tb'. If search_pc is TRUE, also generate PC
2387   information for each intermediate instruction. */
2388static inline int gen_intermediate_code_internal(CPUState *env,
2389                                                 TranslationBlock *tb,
2390                                                 int search_pc)
2391{
2392    DisasContext dc1, *dc = &dc1;
2393    uint16_t *gen_opc_end;
2394    int j, lj;
2395    target_ulong pc_start;
2396    uint32_t next_page_start;
2397
2398    /* generate intermediate code */
2399    pc_start = tb->pc;
2400
2401    dc->tb = tb;
2402
2403    gen_opc_ptr = gen_opc_buf;
2404    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2405    gen_opparam_ptr = gen_opparam_buf;
2406
2407    dc->is_jmp = DISAS_NEXT;
2408    dc->pc = pc_start;
2409    dc->singlestep_enabled = env->singlestep_enabled;
2410    dc->condjmp = 0;
2411    dc->thumb = env->thumb;
2412#if !defined(CONFIG_USER_ONLY)
2413    dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
2414#endif
2415    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
2416    nb_gen_labels = 0;
2417    lj = -1;
2418    do {
2419        if (env->nb_breakpoints > 0) {
2420            for(j = 0; j < env->nb_breakpoints; j++) {
2421                if (env->breakpoints[j] == dc->pc) {
2422                    gen_op_movl_T0_im((long)dc->pc);
2423                    gen_op_movl_reg_TN[0][15]();
2424                    gen_op_debug();
2425                    dc->is_jmp = DISAS_JUMP;
2426                    break;
2427                }
2428            }
2429        }
2430        if (search_pc) {
2431            j = gen_opc_ptr - gen_opc_buf;
2432            if (lj < j) {
2433                lj++;
2434                while (lj < j)
2435                    gen_opc_instr_start[lj++] = 0;
2436            }
2437            gen_opc_pc[lj] = dc->pc;
2438            gen_opc_instr_start[lj] = 1;
2439        }
2440
2441        if (env->thumb)
2442          disas_thumb_insn(dc);
2443        else
2444          disas_arm_insn(env, dc);
2445
2446        if (dc->condjmp && !dc->is_jmp) {
2447            gen_set_label(dc->condlabel);
2448            dc->condjmp = 0;
2449        }
2450        /* Translation stops when a conditional branch is enoutered.
2451         * Otherwise the subsequent code could get translated several times.
2452         * Also stop translation when a page boundary is reached.  This
2453         * ensures prefech aborts occur at the right place.  */
2454    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
2455             !env->singlestep_enabled &&
2456             dc->pc < next_page_start);
2457    /* At this stage dc->condjmp will only be set when the skipped
2458     * instruction was a conditional branch, and the PC has already been
2459     * written.  */
2460    if (__builtin_expect(env->singlestep_enabled, 0)) {
2461        /* Make sure the pc is updated, and raise a debug exception.  */
2462        if (dc->condjmp) {
2463            gen_op_debug();
2464            gen_set_label(dc->condlabel);
2465        }
2466        if (dc->condjmp || !dc->is_jmp) {
2467            gen_op_movl_T0_im((long)dc->pc);
2468            gen_op_movl_reg_TN[0][15]();
2469            dc->condjmp = 0;
2470        }
2471        gen_op_debug();
2472    } else {
2473        switch(dc->is_jmp) {
2474        case DISAS_NEXT:
2475            gen_goto_tb(dc, 1, dc->pc);
2476            break;
2477        default:
2478        case DISAS_JUMP:
2479        case DISAS_UPDATE:
2480            /* indicate that the hash table must be used to find the next TB */
2481            gen_op_movl_T0_0();
2482            gen_op_exit_tb();
2483            break;
2484        case DISAS_TB_JUMP:
2485            /* nothing more to generate */
2486            break;
2487        }
2488        if (dc->condjmp) {
2489            gen_set_label(dc->condlabel);
2490            gen_goto_tb(dc, 1, dc->pc);
2491            dc->condjmp = 0;
2492        }
2493    }
2494    *gen_opc_ptr = INDEX_op_end;
2495
2496#ifdef DEBUG_DISAS
2497    if (loglevel & CPU_LOG_TB_IN_ASM) {
2498        fprintf(logfile, "----------------\n");
2499        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
2500        target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
2501        fprintf(logfile, "\n");
2502        if (loglevel & (CPU_LOG_TB_OP)) {
2503            fprintf(logfile, "OP:\n");
2504            dump_ops(gen_opc_buf, gen_opparam_buf);
2505            fprintf(logfile, "\n");
2506        }
2507    }
2508#endif
2509    if (search_pc) {
2510        j = gen_opc_ptr - gen_opc_buf;
2511        lj++;
2512        while (lj <= j)
2513            gen_opc_instr_start[lj++] = 0;
2514        tb->size = 0;
2515    } else {
2516        tb->size = dc->pc - pc_start;
2517    }
2518    return 0;
2519}
2520
2521int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
2522{
2523    return gen_intermediate_code_internal(env, tb, 0);
2524}
2525
2526int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
2527{
2528    return gen_intermediate_code_internal(env, tb, 1);
2529}
2530
2531static const char *cpu_mode_names[16] = {
2532  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
2533  "???", "???", "???", "und", "???", "???", "???", "sys"
2534};
2535void cpu_dump_state(CPUState *env, FILE *f,
2536                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2537                    int flags)
2538{
2539    int i;
2540    union {
2541        uint32_t i;
2542        float s;
2543    } s0, s1;
2544    CPU_DoubleU d;
2545    uint32_t psr;
2546
2547    for(i=0;i<16;i++) {
2548        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
2549        if ((i % 4) == 3)
2550            cpu_fprintf(f, "\n");
2551        else
2552            cpu_fprintf(f, " ");
2553    }
2554    psr = cpsr_read(env);
2555    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d %x\n",
2556                psr,
2557                psr & (1 << 31) ? 'N' : '-',
2558                psr & (1 << 30) ? 'Z' : '-',
2559                psr & (1 << 29) ? 'C' : '-',
2560                psr & (1 << 28) ? 'V' : '-',
2561                psr & CPSR_T ? 'T' : 'A',
2562                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
2563
2564    for (i = 0; i < 16; i++) {
2565        d.d = env->vfp.regs[i];
2566        s0.i = d.l.lower;
2567        s1.i = d.l.upper;
2568        cpu_fprintf(f, "s%02d=%08x(%8f) s%02d=%08x(%8f) d%02d=%08x%08x(%8f)\n",
2569                    i * 2, (int)s0.i, s0.s,
2570                    i * 2 + 1, (int)s0.i, s0.s,
2571                    i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
2572                    d.d);
2573    }
2574    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
2575}
2576
2577