Statistics
| Branch: | Revision:

root / target-arm / translate.c @ c1713132

History | View | Annotate | Download (78.6 kB)

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 */
38
typedef 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
    int is_mem;
49
#if !defined(CONFIG_USER_ONLY)
50
    int user;
51
#endif
52
} DisasContext;
53

    
54
#if defined(CONFIG_USER_ONLY)
55
#define IS_USER(s) 1
56
#else
57
#define IS_USER(s) (s->user)
58
#endif
59

    
60
#define DISAS_JUMP_NEXT 4
61

    
62
#ifdef USE_DIRECT_JUMP
63
#define TBPARAM(x)
64
#else
65
#define TBPARAM(x) (long)(x)
66
#endif
67

    
68
/* XXX: move that elsewhere */
69
static uint16_t *gen_opc_ptr;
70
static uint32_t *gen_opparam_ptr;
71
extern FILE *logfile;
72
extern int loglevel;
73

    
74
enum {
75
#define DEF(s, n, copy_size) INDEX_op_ ## s,
76
#include "opc.h"
77
#undef DEF
78
    NB_OPS,
79
};
80

    
81
#include "gen-op.h"
82

    
83
static GenOpFunc1 *gen_test_cc[14] = {
84
    gen_op_test_eq,
85
    gen_op_test_ne,
86
    gen_op_test_cs,
87
    gen_op_test_cc,
88
    gen_op_test_mi,
89
    gen_op_test_pl,
90
    gen_op_test_vs,
91
    gen_op_test_vc,
92
    gen_op_test_hi,
93
    gen_op_test_ls,
94
    gen_op_test_ge,
95
    gen_op_test_lt,
96
    gen_op_test_gt,
97
    gen_op_test_le,
98
};
99

    
100
const uint8_t table_logic_cc[16] = {
101
    1, /* and */
102
    1, /* xor */
103
    0, /* sub */
104
    0, /* rsb */
105
    0, /* add */
106
    0, /* adc */
107
    0, /* sbc */
108
    0, /* rsc */
109
    1, /* andl */
110
    1, /* xorl */
111
    0, /* cmp */
112
    0, /* cmn */
113
    1, /* orr */
114
    1, /* mov */
115
    1, /* bic */
116
    1, /* mvn */
117
};
118
    
119
static GenOpFunc1 *gen_shift_T1_im[4] = {
120
    gen_op_shll_T1_im,
121
    gen_op_shrl_T1_im,
122
    gen_op_sarl_T1_im,
123
    gen_op_rorl_T1_im,
124
};
125

    
126
static GenOpFunc *gen_shift_T1_0[4] = {
127
    NULL,
128
    gen_op_shrl_T1_0,
129
    gen_op_sarl_T1_0,
130
    gen_op_rrxl_T1,
131
};
132

    
133
static GenOpFunc1 *gen_shift_T2_im[4] = {
134
    gen_op_shll_T2_im,
135
    gen_op_shrl_T2_im,
136
    gen_op_sarl_T2_im,
137
    gen_op_rorl_T2_im,
138
};
139

    
140
static GenOpFunc *gen_shift_T2_0[4] = {
141
    NULL,
142
    gen_op_shrl_T2_0,
143
    gen_op_sarl_T2_0,
144
    gen_op_rrxl_T2,
145
};
146

    
147
static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
148
    gen_op_shll_T1_im_cc,
149
    gen_op_shrl_T1_im_cc,
150
    gen_op_sarl_T1_im_cc,
151
    gen_op_rorl_T1_im_cc,
152
};
153

    
154
static GenOpFunc *gen_shift_T1_0_cc[4] = {
155
    NULL,
156
    gen_op_shrl_T1_0_cc,
157
    gen_op_sarl_T1_0_cc,
158
    gen_op_rrxl_T1_cc,
159
};
160

    
161
static GenOpFunc *gen_shift_T1_T0[4] = {
162
    gen_op_shll_T1_T0,
163
    gen_op_shrl_T1_T0,
164
    gen_op_sarl_T1_T0,
165
    gen_op_rorl_T1_T0,
166
};
167

    
168
static GenOpFunc *gen_shift_T1_T0_cc[4] = {
169
    gen_op_shll_T1_T0_cc,
170
    gen_op_shrl_T1_T0_cc,
171
    gen_op_sarl_T1_T0_cc,
172
    gen_op_rorl_T1_T0_cc,
173
};
174

    
175
static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
176
    {
177
        gen_op_movl_T0_r0,
178
        gen_op_movl_T0_r1,
179
        gen_op_movl_T0_r2,
180
        gen_op_movl_T0_r3,
181
        gen_op_movl_T0_r4,
182
        gen_op_movl_T0_r5,
183
        gen_op_movl_T0_r6,
184
        gen_op_movl_T0_r7,
185
        gen_op_movl_T0_r8,
186
        gen_op_movl_T0_r9,
187
        gen_op_movl_T0_r10,
188
        gen_op_movl_T0_r11,
189
        gen_op_movl_T0_r12,
190
        gen_op_movl_T0_r13,
191
        gen_op_movl_T0_r14,
192
        gen_op_movl_T0_r15,
193
    },
194
    {
195
        gen_op_movl_T1_r0,
196
        gen_op_movl_T1_r1,
197
        gen_op_movl_T1_r2,
198
        gen_op_movl_T1_r3,
199
        gen_op_movl_T1_r4,
200
        gen_op_movl_T1_r5,
201
        gen_op_movl_T1_r6,
202
        gen_op_movl_T1_r7,
203
        gen_op_movl_T1_r8,
204
        gen_op_movl_T1_r9,
205
        gen_op_movl_T1_r10,
206
        gen_op_movl_T1_r11,
207
        gen_op_movl_T1_r12,
208
        gen_op_movl_T1_r13,
209
        gen_op_movl_T1_r14,
210
        gen_op_movl_T1_r15,
211
    },
212
    {
213
        gen_op_movl_T2_r0,
214
        gen_op_movl_T2_r1,
215
        gen_op_movl_T2_r2,
216
        gen_op_movl_T2_r3,
217
        gen_op_movl_T2_r4,
218
        gen_op_movl_T2_r5,
219
        gen_op_movl_T2_r6,
220
        gen_op_movl_T2_r7,
221
        gen_op_movl_T2_r8,
222
        gen_op_movl_T2_r9,
223
        gen_op_movl_T2_r10,
224
        gen_op_movl_T2_r11,
225
        gen_op_movl_T2_r12,
226
        gen_op_movl_T2_r13,
227
        gen_op_movl_T2_r14,
228
        gen_op_movl_T2_r15,
229
    },
230
};
231

    
232
static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
233
    {
234
        gen_op_movl_r0_T0,
235
        gen_op_movl_r1_T0,
236
        gen_op_movl_r2_T0,
237
        gen_op_movl_r3_T0,
238
        gen_op_movl_r4_T0,
239
        gen_op_movl_r5_T0,
240
        gen_op_movl_r6_T0,
241
        gen_op_movl_r7_T0,
242
        gen_op_movl_r8_T0,
243
        gen_op_movl_r9_T0,
244
        gen_op_movl_r10_T0,
245
        gen_op_movl_r11_T0,
246
        gen_op_movl_r12_T0,
247
        gen_op_movl_r13_T0,
248
        gen_op_movl_r14_T0,
249
        gen_op_movl_r15_T0,
250
    },
251
    {
252
        gen_op_movl_r0_T1,
253
        gen_op_movl_r1_T1,
254
        gen_op_movl_r2_T1,
255
        gen_op_movl_r3_T1,
256
        gen_op_movl_r4_T1,
257
        gen_op_movl_r5_T1,
258
        gen_op_movl_r6_T1,
259
        gen_op_movl_r7_T1,
260
        gen_op_movl_r8_T1,
261
        gen_op_movl_r9_T1,
262
        gen_op_movl_r10_T1,
263
        gen_op_movl_r11_T1,
264
        gen_op_movl_r12_T1,
265
        gen_op_movl_r13_T1,
266
        gen_op_movl_r14_T1,
267
        gen_op_movl_r15_T1,
268
    },
269
};
270

    
271
static GenOpFunc1 *gen_op_movl_TN_im[3] = {
272
    gen_op_movl_T0_im,
273
    gen_op_movl_T1_im,
274
    gen_op_movl_T2_im,
275
};
276

    
277
static GenOpFunc1 *gen_shift_T0_im_thumb[3] = {
278
    gen_op_shll_T0_im_thumb,
279
    gen_op_shrl_T0_im_thumb,
280
    gen_op_sarl_T0_im_thumb,
281
};
282

    
283
static inline void gen_bx(DisasContext *s)
284
{
285
  s->is_jmp = DISAS_UPDATE;
286
  gen_op_bx_T0();
287
}
288

    
289

    
290
#if defined(CONFIG_USER_ONLY)
291
#define gen_ldst(name, s) gen_op_##name##_raw()
292
#else
293
#define gen_ldst(name, s) do { \
294
    s->is_mem = 1; \
295
    if (IS_USER(s)) \
296
        gen_op_##name##_user(); \
297
    else \
298
        gen_op_##name##_kernel(); \
299
    } while (0)
300
#endif
301

    
302
static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
303
{
304
    int val;
305

    
306
    if (reg == 15) {
307
        /* normaly, since we updated PC, we need only to add one insn */
308
        if (s->thumb)
309
            val = (long)s->pc + 2;
310
        else
311
            val = (long)s->pc + 4;
312
        gen_op_movl_TN_im[t](val);
313
    } else {
314
        gen_op_movl_TN_reg[t][reg]();
315
    }
316
}
317

    
318
static inline void gen_movl_T0_reg(DisasContext *s, int reg)
319
{
320
    gen_movl_TN_reg(s, reg, 0);
321
}
322

    
323
static inline void gen_movl_T1_reg(DisasContext *s, int reg)
324
{
325
    gen_movl_TN_reg(s, reg, 1);
326
}
327

    
328
static inline void gen_movl_T2_reg(DisasContext *s, int reg)
329
{
330
    gen_movl_TN_reg(s, reg, 2);
331
}
332

    
333
static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
334
{
335
    gen_op_movl_reg_TN[t][reg]();
336
    if (reg == 15) {
337
        s->is_jmp = DISAS_JUMP;
338
    }
339
}
340

    
341
static inline void gen_movl_reg_T0(DisasContext *s, int reg)
342
{
343
    gen_movl_reg_TN(s, reg, 0);
344
}
345

    
346
static inline void gen_movl_reg_T1(DisasContext *s, int reg)
347
{
348
    gen_movl_reg_TN(s, reg, 1);
349
}
350

    
351
/* Force a TB lookup after an instruction that changes the CPU state.  */
352
static inline void gen_lookup_tb(DisasContext *s)
353
{
354
    gen_op_movl_T0_im(s->pc);
355
    gen_movl_reg_T0(s, 15);
356
    s->is_jmp = DISAS_UPDATE;
357
}
358

    
359
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
360
{
361
    int val, rm, shift, shiftop;
362

    
363
    if (!(insn & (1 << 25))) {
364
        /* immediate */
365
        val = insn & 0xfff;
366
        if (!(insn & (1 << 23)))
367
            val = -val;
368
        if (val != 0)
369
            gen_op_addl_T1_im(val);
370
    } else {
371
        /* shift/register */
372
        rm = (insn) & 0xf;
373
        shift = (insn >> 7) & 0x1f;
374
        gen_movl_T2_reg(s, rm);
375
        shiftop = (insn >> 5) & 3;
376
        if (shift != 0) {
377
            gen_shift_T2_im[shiftop](shift);
378
        } else if (shiftop != 0) {
379
            gen_shift_T2_0[shiftop]();
380
        }
381
        if (!(insn & (1 << 23)))
382
            gen_op_subl_T1_T2();
383
        else
384
            gen_op_addl_T1_T2();
385
    }
386
}
387

    
388
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
389
                                        int extra)
390
{
391
    int val, rm;
392
    
393
    if (insn & (1 << 22)) {
394
        /* immediate */
395
        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
396
        if (!(insn & (1 << 23)))
397
            val = -val;
398
        val += extra;
399
        if (val != 0)
400
            gen_op_addl_T1_im(val);
401
    } else {
402
        /* register */
403
        if (extra)
404
            gen_op_addl_T1_im(extra);
405
        rm = (insn) & 0xf;
406
        gen_movl_T2_reg(s, rm);
407
        if (!(insn & (1 << 23)))
408
            gen_op_subl_T1_T2();
409
        else
410
            gen_op_addl_T1_T2();
411
    }
412
}
413

    
414
#define VFP_OP(name)                      \
415
static inline void gen_vfp_##name(int dp) \
416
{                                         \
417
    if (dp)                               \
418
        gen_op_vfp_##name##d();           \
419
    else                                  \
420
        gen_op_vfp_##name##s();           \
421
}
422

    
423
VFP_OP(add)
424
VFP_OP(sub)
425
VFP_OP(mul)
426
VFP_OP(div)
427
VFP_OP(neg)
428
VFP_OP(abs)
429
VFP_OP(sqrt)
430
VFP_OP(cmp)
431
VFP_OP(cmpe)
432
VFP_OP(F1_ld0)
433
VFP_OP(uito)
434
VFP_OP(sito)
435
VFP_OP(toui)
436
VFP_OP(touiz)
437
VFP_OP(tosi)
438
VFP_OP(tosiz)
439

    
440
#undef VFP_OP
441

    
442
static inline void gen_vfp_ld(DisasContext *s, int dp)
443
{
444
    if (dp)
445
        gen_ldst(vfp_ldd, s);
446
    else
447
        gen_ldst(vfp_lds, s);
448
}
449

    
450
static inline void gen_vfp_st(DisasContext *s, int dp)
451
{
452
    if (dp)
453
        gen_ldst(vfp_std, s);
454
    else
455
        gen_ldst(vfp_sts, s);
456
}
457

    
458
static inline long
459
vfp_reg_offset (int dp, int reg)
460
{
461
    if (dp)
462
        return offsetof(CPUARMState, vfp.regs[reg]);
463
    else if (reg & 1) {
464
        return offsetof(CPUARMState, vfp.regs[reg >> 1])
465
          + offsetof(CPU_DoubleU, l.upper);
466
    } else {
467
        return offsetof(CPUARMState, vfp.regs[reg >> 1])
468
          + offsetof(CPU_DoubleU, l.lower);
469
    }
470
}
471
static inline void gen_mov_F0_vreg(int dp, int reg)
472
{
473
    if (dp)
474
        gen_op_vfp_getreg_F0d(vfp_reg_offset(dp, reg));
475
    else
476
        gen_op_vfp_getreg_F0s(vfp_reg_offset(dp, reg));
477
}
478

    
479
static inline void gen_mov_F1_vreg(int dp, int reg)
480
{
481
    if (dp)
482
        gen_op_vfp_getreg_F1d(vfp_reg_offset(dp, reg));
483
    else
484
        gen_op_vfp_getreg_F1s(vfp_reg_offset(dp, reg));
485
}
486

    
487
static inline void gen_mov_vreg_F0(int dp, int reg)
488
{
489
    if (dp)
490
        gen_op_vfp_setreg_F0d(vfp_reg_offset(dp, reg));
491
    else
492
        gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
493
}
494

    
495
/* Disassemble system coprocessor instruction.  Return nonzero if
496
   instruction is not defined.  */
497
static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
498
{
499
    uint32_t rd = (insn >> 12) & 0xf;
500
    uint32_t cp = (insn >> 8) & 0xf;
501
    if (IS_USER(s)) {
502
        return 1;
503
    }
504

    
505
    if (insn & (1 << 20)) {
506
        if (!env->cp[cp].cp_read)
507
            return 1;
508
        gen_op_movl_T0_im((uint32_t) s->pc);
509
        gen_op_movl_reg_TN[0][15]();
510
        gen_op_movl_T0_cp(insn);
511
        gen_movl_reg_T0(s, rd);
512
    } else {
513
        if (!env->cp[cp].cp_write)
514
            return 1;
515
        gen_op_movl_T0_im((uint32_t) s->pc);
516
        gen_op_movl_reg_TN[0][15]();
517
        gen_movl_T0_reg(s, rd);
518
        gen_op_movl_cp_T0(insn);
519
    }
520
    return 0;
521
}
522

    
523
/* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
524
   instruction is not defined.  */
525
static int disas_cp15_insn(DisasContext *s, uint32_t insn)
526
{
527
    uint32_t rd;
528

    
529
    /* ??? Some cp15 registers are accessible from userspace.  */
530
    if (IS_USER(s)) {
531
        return 1;
532
    }
533
    if ((insn & 0x0fff0fff) == 0x0e070f90
534
        || (insn & 0x0fff0fff) == 0x0e070f58) {
535
        /* Wait for interrupt.  */
536
        gen_op_movl_T0_im((long)s->pc);
537
        gen_op_movl_reg_TN[0][15]();
538
        gen_op_wfi();
539
        s->is_jmp = DISAS_JUMP;
540
        return 0;
541
    }
542
    rd = (insn >> 12) & 0xf;
543
    if (insn & (1 << 20)) {
544
        gen_op_movl_T0_cp15(insn);
545
        /* If the destination register is r15 then sets condition codes.  */
546
        if (rd != 15)
547
            gen_movl_reg_T0(s, rd);
548
    } else {
549
        gen_movl_T0_reg(s, rd);
550
        gen_op_movl_cp15_T0(insn);
551
    }
552
    gen_lookup_tb(s);
553
    return 0;
554
}
555

    
556
/* Disassemble a VFP instruction.  Returns nonzero if an error occured
557
   (ie. an undefined instruction).  */
558
static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
559
{
560
    uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
561
    int dp, veclen;
562

    
563
    if (!arm_feature(env, ARM_FEATURE_VFP))
564
        return 1;
565

    
566
    if ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) == 0) {
567
        /* VFP disabled.  Only allow fmxr/fmrx to/from fpexc and fpsid.  */
568
        if ((insn & 0x0fe00fff) != 0x0ee00a10)
569
            return 1;
570
        rn = (insn >> 16) & 0xf;
571
        if (rn != 0 && rn != 8)
572
            return 1;
573
    }
574
    dp = ((insn & 0xf00) == 0xb00);
575
    switch ((insn >> 24) & 0xf) {
576
    case 0xe:
577
        if (insn & (1 << 4)) {
578
            /* single register transfer */
579
            if ((insn & 0x6f) != 0x00)
580
                return 1;
581
            rd = (insn >> 12) & 0xf;
582
            if (dp) {
583
                if (insn & 0x80)
584
                    return 1;
585
                rn = (insn >> 16) & 0xf;
586
                /* Get the existing value even for arm->vfp moves because
587
                   we only set half the register.  */
588
                gen_mov_F0_vreg(1, rn);
589
                gen_op_vfp_mrrd();
590
                if (insn & (1 << 20)) {
591
                    /* vfp->arm */
592
                    if (insn & (1 << 21))
593
                        gen_movl_reg_T1(s, rd);
594
                    else
595
                        gen_movl_reg_T0(s, rd);
596
                } else {
597
                    /* arm->vfp */
598
                    if (insn & (1 << 21))
599
                        gen_movl_T1_reg(s, rd);
600
                    else
601
                        gen_movl_T0_reg(s, rd);
602
                    gen_op_vfp_mdrr();
603
                    gen_mov_vreg_F0(dp, rn);
604
                }
605
            } else {
606
                rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
607
                if (insn & (1 << 20)) {
608
                    /* vfp->arm */
609
                    if (insn & (1 << 21)) {
610
                        /* system register */
611
                        rn >>= 1;
612
                        switch (rn) {
613
                        case ARM_VFP_FPSID:
614
                        case ARM_VFP_FPEXC:
615
                        case ARM_VFP_FPINST:
616
                        case ARM_VFP_FPINST2:
617
                            gen_op_vfp_movl_T0_xreg(rn);
618
                            break;
619
                        case ARM_VFP_FPSCR:
620
                            if (rd == 15)
621
                                gen_op_vfp_movl_T0_fpscr_flags();
622
                            else
623
                                gen_op_vfp_movl_T0_fpscr();
624
                            break;
625
                        default:
626
                            return 1;
627
                        }
628
                    } else {
629
                        gen_mov_F0_vreg(0, rn);
630
                        gen_op_vfp_mrs();
631
                    }
632
                    if (rd == 15) {
633
                        /* Set the 4 flag bits in the CPSR.  */
634
                        gen_op_movl_cpsr_T0(0xf0000000);
635
                    } else
636
                        gen_movl_reg_T0(s, rd);
637
                } else {
638
                    /* arm->vfp */
639
                    gen_movl_T0_reg(s, rd);
640
                    if (insn & (1 << 21)) {
641
                        rn >>= 1;
642
                        /* system register */
643
                        switch (rn) {
644
                        case ARM_VFP_FPSID:
645
                            /* Writes are ignored.  */
646
                            break;
647
                        case ARM_VFP_FPSCR:
648
                            gen_op_vfp_movl_fpscr_T0();
649
                            gen_lookup_tb(s);
650
                            break;
651
                        case ARM_VFP_FPEXC:
652
                            gen_op_vfp_movl_xreg_T0(rn);
653
                            gen_lookup_tb(s);
654
                            break;
655
                        case ARM_VFP_FPINST:
656
                        case ARM_VFP_FPINST2:
657
                            gen_op_vfp_movl_xreg_T0(rn);
658
                            break;
659
                        default:
660
                            return 1;
661
                        }
662
                    } else {
663
                        gen_op_vfp_msr();
664
                        gen_mov_vreg_F0(0, rn);
665
                    }
666
                }
667
            }
668
        } else {
669
            /* data processing */
670
            /* The opcode is in bits 23, 21, 20 and 6.  */
671
            op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
672
            if (dp) {
673
                if (op == 15) {
674
                    /* rn is opcode */
675
                    rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
676
                } else {
677
                    /* rn is register number */
678
                    if (insn & (1 << 7))
679
                        return 1;
680
                    rn = (insn >> 16) & 0xf;
681
                }
682

    
683
                if (op == 15 && (rn == 15 || rn > 17)) {
684
                    /* Integer or single precision destination.  */
685
                    rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
686
                } else {
687
                    if (insn & (1 << 22))
688
                        return 1;
689
                    rd = (insn >> 12) & 0xf;
690
                }
691

    
692
                if (op == 15 && (rn == 16 || rn == 17)) {
693
                    /* Integer source.  */
694
                    rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
695
                } else {
696
                    if (insn & (1 << 5))
697
                        return 1;
698
                    rm = insn & 0xf;
699
                }
700
            } else {
701
                rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
702
                if (op == 15 && rn == 15) {
703
                    /* Double precision destination.  */
704
                    if (insn & (1 << 22))
705
                        return 1;
706
                    rd = (insn >> 12) & 0xf;
707
                } else
708
                    rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
709
                rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
710
            }
711

    
712
            veclen = env->vfp.vec_len;
713
            if (op == 15 && rn > 3)
714
                veclen = 0;
715

    
716
            /* Shut up compiler warnings.  */
717
            delta_m = 0;
718
            delta_d = 0;
719
            bank_mask = 0;
720
            
721
            if (veclen > 0) {
722
                if (dp)
723
                    bank_mask = 0xc;
724
                else
725
                    bank_mask = 0x18;
726

    
727
                /* Figure out what type of vector operation this is.  */
728
                if ((rd & bank_mask) == 0) {
729
                    /* scalar */
730
                    veclen = 0;
731
                } else {
732
                    if (dp)
733
                        delta_d = (env->vfp.vec_stride >> 1) + 1;
734
                    else
735
                        delta_d = env->vfp.vec_stride + 1;
736

    
737
                    if ((rm & bank_mask) == 0) {
738
                        /* mixed scalar/vector */
739
                        delta_m = 0;
740
                    } else {
741
                        /* vector */
742
                        delta_m = delta_d;
743
                    }
744
                }
745
            }
746

    
747
            /* Load the initial operands.  */
748
            if (op == 15) {
749
                switch (rn) {
750
                case 16:
751
                case 17:
752
                    /* Integer source */
753
                    gen_mov_F0_vreg(0, rm);
754
                    break;
755
                case 8:
756
                case 9:
757
                    /* Compare */
758
                    gen_mov_F0_vreg(dp, rd);
759
                    gen_mov_F1_vreg(dp, rm);
760
                    break;
761
                case 10:
762
                case 11:
763
                    /* Compare with zero */
764
                    gen_mov_F0_vreg(dp, rd);
765
                    gen_vfp_F1_ld0(dp);
766
                    break;
767
                default:
768
                    /* One source operand.  */
769
                    gen_mov_F0_vreg(dp, rm);
770
                }
771
            } else {
772
                /* Two source operands.  */
773
                gen_mov_F0_vreg(dp, rn);
774
                gen_mov_F1_vreg(dp, rm);
775
            }
776

    
777
            for (;;) {
778
                /* Perform the calculation.  */
779
                switch (op) {
780
                case 0: /* mac: fd + (fn * fm) */
781
                    gen_vfp_mul(dp);
782
                    gen_mov_F1_vreg(dp, rd);
783
                    gen_vfp_add(dp);
784
                    break;
785
                case 1: /* nmac: fd - (fn * fm) */
786
                    gen_vfp_mul(dp);
787
                    gen_vfp_neg(dp);
788
                    gen_mov_F1_vreg(dp, rd);
789
                    gen_vfp_add(dp);
790
                    break;
791
                case 2: /* msc: -fd + (fn * fm) */
792
                    gen_vfp_mul(dp);
793
                    gen_mov_F1_vreg(dp, rd);
794
                    gen_vfp_sub(dp);
795
                    break;
796
                case 3: /* nmsc: -fd - (fn * fm)  */
797
                    gen_vfp_mul(dp);
798
                    gen_mov_F1_vreg(dp, rd);
799
                    gen_vfp_add(dp);
800
                    gen_vfp_neg(dp);
801
                    break;
802
                case 4: /* mul: fn * fm */
803
                    gen_vfp_mul(dp);
804
                    break;
805
                case 5: /* nmul: -(fn * fm) */
806
                    gen_vfp_mul(dp);
807
                    gen_vfp_neg(dp);
808
                    break;
809
                case 6: /* add: fn + fm */
810
                    gen_vfp_add(dp);
811
                    break;
812
                case 7: /* sub: fn - fm */
813
                    gen_vfp_sub(dp);
814
                    break;
815
                case 8: /* div: fn / fm */
816
                    gen_vfp_div(dp);
817
                    break;
818
                case 15: /* extension space */
819
                    switch (rn) {
820
                    case 0: /* cpy */
821
                        /* no-op */
822
                        break;
823
                    case 1: /* abs */
824
                        gen_vfp_abs(dp);
825
                        break;
826
                    case 2: /* neg */
827
                        gen_vfp_neg(dp);
828
                        break;
829
                    case 3: /* sqrt */
830
                        gen_vfp_sqrt(dp);
831
                        break;
832
                    case 8: /* cmp */
833
                        gen_vfp_cmp(dp);
834
                        break;
835
                    case 9: /* cmpe */
836
                        gen_vfp_cmpe(dp);
837
                        break;
838
                    case 10: /* cmpz */
839
                        gen_vfp_cmp(dp);
840
                        break;
841
                    case 11: /* cmpez */
842
                        gen_vfp_F1_ld0(dp);
843
                        gen_vfp_cmpe(dp);
844
                        break;
845
                    case 15: /* single<->double conversion */
846
                        if (dp)
847
                            gen_op_vfp_fcvtsd();
848
                        else
849
                            gen_op_vfp_fcvtds();
850
                        break;
851
                    case 16: /* fuito */
852
                        gen_vfp_uito(dp);
853
                        break;
854
                    case 17: /* fsito */
855
                        gen_vfp_sito(dp);
856
                        break;
857
                    case 24: /* ftoui */
858
                        gen_vfp_toui(dp);
859
                        break;
860
                    case 25: /* ftouiz */
861
                        gen_vfp_touiz(dp);
862
                        break;
863
                    case 26: /* ftosi */
864
                        gen_vfp_tosi(dp);
865
                        break;
866
                    case 27: /* ftosiz */
867
                        gen_vfp_tosiz(dp);
868
                        break;
869
                    default: /* undefined */
870
                        printf ("rn:%d\n", rn);
871
                        return 1;
872
                    }
873
                    break;
874
                default: /* undefined */
875
                    printf ("op:%d\n", op);
876
                    return 1;
877
                }
878

    
879
                /* Write back the result.  */
880
                if (op == 15 && (rn >= 8 && rn <= 11))
881
                    ; /* Comparison, do nothing.  */
882
                else if (op == 15 && rn > 17)
883
                    /* Integer result.  */
884
                    gen_mov_vreg_F0(0, rd);
885
                else if (op == 15 && rn == 15)
886
                    /* conversion */
887
                    gen_mov_vreg_F0(!dp, rd);
888
                else
889
                    gen_mov_vreg_F0(dp, rd);
890

    
891
                /* break out of the loop if we have finished  */
892
                if (veclen == 0)
893
                    break;
894

    
895
                if (op == 15 && delta_m == 0) {
896
                    /* single source one-many */
897
                    while (veclen--) {
898
                        rd = ((rd + delta_d) & (bank_mask - 1))
899
                             | (rd & bank_mask);
900
                        gen_mov_vreg_F0(dp, rd);
901
                    }
902
                    break;
903
                }
904
                /* Setup the next operands.  */
905
                veclen--;
906
                rd = ((rd + delta_d) & (bank_mask - 1))
907
                     | (rd & bank_mask);
908

    
909
                if (op == 15) {
910
                    /* One source operand.  */
911
                    rm = ((rm + delta_m) & (bank_mask - 1))
912
                         | (rm & bank_mask);
913
                    gen_mov_F0_vreg(dp, rm);
914
                } else {
915
                    /* Two source operands.  */
916
                    rn = ((rn + delta_d) & (bank_mask - 1))
917
                         | (rn & bank_mask);
918
                    gen_mov_F0_vreg(dp, rn);
919
                    if (delta_m) {
920
                        rm = ((rm + delta_m) & (bank_mask - 1))
921
                             | (rm & bank_mask);
922
                        gen_mov_F1_vreg(dp, rm);
923
                    }
924
                }
925
            }
926
        }
927
        break;
928
    case 0xc:
929
    case 0xd:
930
        if (dp && (insn & (1 << 22))) {
931
            /* two-register transfer */
932
            rn = (insn >> 16) & 0xf;
933
            rd = (insn >> 12) & 0xf;
934
            if (dp) {
935
                if (insn & (1 << 5))
936
                    return 1;
937
                rm = insn & 0xf;
938
            } else
939
                rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
940

    
941
            if (insn & (1 << 20)) {
942
                /* vfp->arm */
943
                if (dp) {
944
                    gen_mov_F0_vreg(1, rm);
945
                    gen_op_vfp_mrrd();
946
                    gen_movl_reg_T0(s, rd);
947
                    gen_movl_reg_T1(s, rn);
948
                } else {
949
                    gen_mov_F0_vreg(0, rm);
950
                    gen_op_vfp_mrs();
951
                    gen_movl_reg_T0(s, rn);
952
                    gen_mov_F0_vreg(0, rm + 1);
953
                    gen_op_vfp_mrs();
954
                    gen_movl_reg_T0(s, rd);
955
                }
956
            } else {
957
                /* arm->vfp */
958
                if (dp) {
959
                    gen_movl_T0_reg(s, rd);
960
                    gen_movl_T1_reg(s, rn);
961
                    gen_op_vfp_mdrr();
962
                    gen_mov_vreg_F0(1, rm);
963
                } else {
964
                    gen_movl_T0_reg(s, rn);
965
                    gen_op_vfp_msr();
966
                    gen_mov_vreg_F0(0, rm);
967
                    gen_movl_T0_reg(s, rd);
968
                    gen_op_vfp_msr();
969
                    gen_mov_vreg_F0(0, rm + 1);
970
                }
971
            }
972
        } else {
973
            /* Load/store */
974
            rn = (insn >> 16) & 0xf;
975
            if (dp)
976
                rd = (insn >> 12) & 0xf;
977
            else
978
                rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
979
            gen_movl_T1_reg(s, rn);
980
            if ((insn & 0x01200000) == 0x01000000) {
981
                /* Single load/store */
982
                offset = (insn & 0xff) << 2;
983
                if ((insn & (1 << 23)) == 0)
984
                    offset = -offset;
985
                gen_op_addl_T1_im(offset);
986
                if (insn & (1 << 20)) {
987
                    gen_vfp_ld(s, dp);
988
                    gen_mov_vreg_F0(dp, rd);
989
                } else {
990
                    gen_mov_F0_vreg(dp, rd);
991
                    gen_vfp_st(s, dp);
992
                }
993
            } else {
994
                /* load/store multiple */
995
                if (dp)
996
                    n = (insn >> 1) & 0x7f;
997
                else
998
                    n = insn & 0xff;
999

    
1000
                if (insn & (1 << 24)) /* pre-decrement */
1001
                    gen_op_addl_T1_im(-((insn & 0xff) << 2));
1002

    
1003
                if (dp)
1004
                    offset = 8;
1005
                else
1006
                    offset = 4;
1007
                for (i = 0; i < n; i++) {
1008
                    if (insn & (1 << 20)) {
1009
                        /* load */
1010
                        gen_vfp_ld(s, dp);
1011
                        gen_mov_vreg_F0(dp, rd + i);
1012
                    } else {
1013
                        /* store */
1014
                        gen_mov_F0_vreg(dp, rd + i);
1015
                        gen_vfp_st(s, dp);
1016
                    }
1017
                    gen_op_addl_T1_im(offset);
1018
                }
1019
                if (insn & (1 << 21)) {
1020
                    /* writeback */
1021
                    if (insn & (1 << 24))
1022
                        offset = -offset * n;
1023
                    else if (dp && (insn & 1))
1024
                        offset = 4;
1025
                    else
1026
                        offset = 0;
1027

    
1028
                    if (offset != 0)
1029
                        gen_op_addl_T1_im(offset);
1030
                    gen_movl_reg_T1(s, rn);
1031
                }
1032
            }
1033
        }
1034
        break;
1035
    default:
1036
        /* Should never happen.  */
1037
        return 1;
1038
    }
1039
    return 0;
1040
}
1041

    
1042
static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
1043
{
1044
    TranslationBlock *tb;
1045

    
1046
    tb = s->tb;
1047
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
1048
        if (n == 0)
1049
            gen_op_goto_tb0(TBPARAM(tb));
1050
        else
1051
            gen_op_goto_tb1(TBPARAM(tb));
1052
        gen_op_movl_T0_im(dest);
1053
        gen_op_movl_r15_T0();
1054
        gen_op_movl_T0_im((long)tb + n);
1055
        gen_op_exit_tb();
1056
    } else {
1057
        gen_op_movl_T0_im(dest);
1058
        gen_op_movl_r15_T0();
1059
        gen_op_movl_T0_0();
1060
        gen_op_exit_tb();
1061
    }
1062
}
1063

    
1064
static inline void gen_jmp (DisasContext *s, uint32_t dest)
1065
{
1066
    if (__builtin_expect(s->singlestep_enabled, 0)) {
1067
        /* An indirect jump so that we still trigger the debug exception.  */
1068
        if (s->thumb)
1069
          dest |= 1;
1070
        gen_op_movl_T0_im(dest);
1071
        gen_bx(s);
1072
    } else {
1073
        gen_goto_tb(s, 0, dest);
1074
        s->is_jmp = DISAS_TB_JUMP;
1075
    }
1076
}
1077

    
1078
static inline void gen_mulxy(int x, int y)
1079
{
1080
    if (x)
1081
        gen_op_sarl_T0_im(16);
1082
    else
1083
        gen_op_sxth_T0();
1084
    if (y)
1085
        gen_op_sarl_T1_im(16);
1086
    else
1087
        gen_op_sxth_T1();
1088
    gen_op_mul_T0_T1();
1089
}
1090

    
1091
/* Return the mask of PSR bits set by a MSR instruction.  */
1092
static uint32_t msr_mask(DisasContext *s, int flags, int spsr) {
1093
    uint32_t mask;
1094

    
1095
    mask = 0;
1096
    if (flags & (1 << 0))
1097
        mask |= 0xff;
1098
    if (flags & (1 << 1))
1099
        mask |= 0xff00;
1100
    if (flags & (1 << 2))
1101
        mask |= 0xff0000;
1102
    if (flags & (1 << 3))
1103
        mask |= 0xff000000;
1104
    /* Mask out undefined bits.  */
1105
    mask &= 0xf90f03ff;
1106
    /* Mask out state bits.  */
1107
    if (!spsr)
1108
        mask &= ~0x01000020;
1109
    /* Mask out privileged bits.  */
1110
    if (IS_USER(s))
1111
        mask &= 0xf80f0200;
1112
    return mask;
1113
}
1114

    
1115
/* Returns nonzero if access to the PSR is not permitted.  */
1116
static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr)
1117
{
1118
    if (spsr) {
1119
        /* ??? This is also undefined in system mode.  */
1120
        if (IS_USER(s))
1121
            return 1;
1122
        gen_op_movl_spsr_T0(mask);
1123
    } else {
1124
        gen_op_movl_cpsr_T0(mask);
1125
    }
1126
    gen_lookup_tb(s);
1127
    return 0;
1128
}
1129

    
1130
static void gen_exception_return(DisasContext *s)
1131
{
1132
    gen_op_movl_reg_TN[0][15]();
1133
    gen_op_movl_T0_spsr();
1134
    gen_op_movl_cpsr_T0(0xffffffff);
1135
    s->is_jmp = DISAS_UPDATE;
1136
}
1137

    
1138
static void disas_arm_insn(CPUState * env, DisasContext *s)
1139
{
1140
    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
1141
    
1142
    insn = ldl_code(s->pc);
1143
    s->pc += 4;
1144
    
1145
    cond = insn >> 28;
1146
    if (cond == 0xf){
1147
        /* Unconditional instructions.  */
1148
        if ((insn & 0x0d70f000) == 0x0550f000)
1149
            return; /* PLD */
1150
        else if ((insn & 0x0e000000) == 0x0a000000) {
1151
            /* branch link and change to thumb (blx <offset>) */
1152
            int32_t offset;
1153

    
1154
            val = (uint32_t)s->pc;
1155
            gen_op_movl_T0_im(val);
1156
            gen_movl_reg_T0(s, 14);
1157
            /* Sign-extend the 24-bit offset */
1158
            offset = (((int32_t)insn) << 8) >> 8;
1159
            /* offset * 4 + bit24 * 2 + (thumb bit) */
1160
            val += (offset << 2) | ((insn >> 23) & 2) | 1;
1161
            /* pipeline offset */
1162
            val += 4;
1163
            gen_op_movl_T0_im(val);
1164
            gen_bx(s);
1165
            return;
1166
        } else if ((insn & 0x0fe00000) == 0x0c400000) {
1167
            /* Coprocessor double register transfer.  */
1168
        } else if ((insn & 0x0f000010) == 0x0e000010) {
1169
            /* Additional coprocessor register transfer.  */
1170
        } else if ((insn & 0x0ff10010) == 0x01000000) {
1171
            /* cps (privileged) */
1172
        } else if ((insn & 0x0ffffdff) == 0x01010000) {
1173
            /* setend */
1174
            if (insn & (1 << 9)) {
1175
                /* BE8 mode not implemented.  */
1176
                goto illegal_op;
1177
            }
1178
            return;
1179
        }
1180
        goto illegal_op;
1181
    }
1182
    if (cond != 0xe) {
1183
        /* if not always execute, we generate a conditional jump to
1184
           next instruction */
1185
        s->condlabel = gen_new_label();
1186
        gen_test_cc[cond ^ 1](s->condlabel);
1187
        s->condjmp = 1;
1188
        //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
1189
        //s->is_jmp = DISAS_JUMP_NEXT;
1190
    }
1191
    if ((insn & 0x0f900000) == 0x03000000) {
1192
        if ((insn & 0x0fb0f000) != 0x0320f000)
1193
            goto illegal_op;
1194
        /* CPSR = immediate */
1195
        val = insn & 0xff;
1196
        shift = ((insn >> 8) & 0xf) * 2;
1197
        if (shift)
1198
            val = (val >> shift) | (val << (32 - shift));
1199
        gen_op_movl_T0_im(val);
1200
        i = ((insn & (1 << 22)) != 0);
1201
        if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
1202
            goto illegal_op;
1203
    } else if ((insn & 0x0f900000) == 0x01000000
1204
               && (insn & 0x00000090) != 0x00000090) {
1205
        /* miscellaneous instructions */
1206
        op1 = (insn >> 21) & 3;
1207
        sh = (insn >> 4) & 0xf;
1208
        rm = insn & 0xf;
1209
        switch (sh) {
1210
        case 0x0: /* move program status register */
1211
            if (op1 & 1) {
1212
                /* PSR = reg */
1213
                gen_movl_T0_reg(s, rm);
1214
                i = ((op1 & 2) != 0);
1215
                if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
1216
                    goto illegal_op;
1217
            } else {
1218
                /* reg = PSR */
1219
                rd = (insn >> 12) & 0xf;
1220
                if (op1 & 2) {
1221
                    if (IS_USER(s))
1222
                        goto illegal_op;
1223
                    gen_op_movl_T0_spsr();
1224
                } else {
1225
                    gen_op_movl_T0_cpsr();
1226
                }
1227
                gen_movl_reg_T0(s, rd);
1228
            }
1229
            break;
1230
        case 0x1:
1231
            if (op1 == 1) {
1232
                /* branch/exchange thumb (bx).  */
1233
                gen_movl_T0_reg(s, rm);
1234
                gen_bx(s);
1235
            } else if (op1 == 3) {
1236
                /* clz */
1237
                rd = (insn >> 12) & 0xf;
1238
                gen_movl_T0_reg(s, rm);
1239
                gen_op_clz_T0();
1240
                gen_movl_reg_T0(s, rd);
1241
            } else {
1242
                goto illegal_op;
1243
            }
1244
            break;
1245
        case 0x2:
1246
            if (op1 == 1) {
1247
                ARCH(5J); /* bxj */
1248
                /* Trivial implementation equivalent to bx.  */
1249
                gen_movl_T0_reg(s, rm);
1250
                gen_bx(s);
1251
            } else {
1252
                goto illegal_op;
1253
            }
1254
            break;
1255
        case 0x3:
1256
            if (op1 != 1)
1257
              goto illegal_op;
1258

    
1259
            /* branch link/exchange thumb (blx) */
1260
            val = (uint32_t)s->pc;
1261
            gen_op_movl_T0_im(val);
1262
            gen_movl_reg_T0(s, 14);
1263
            gen_movl_T0_reg(s, rm);
1264
            gen_bx(s);
1265
            break;
1266
        case 0x5: /* saturating add/subtract */
1267
            rd = (insn >> 12) & 0xf;
1268
            rn = (insn >> 16) & 0xf;
1269
            gen_movl_T0_reg(s, rm);
1270
            gen_movl_T1_reg(s, rn);
1271
            if (op1 & 2)
1272
                gen_op_double_T1_saturate();
1273
            if (op1 & 1)
1274
                gen_op_subl_T0_T1_saturate();
1275
            else
1276
                gen_op_addl_T0_T1_saturate();
1277
            gen_movl_reg_T0(s, rd);
1278
            break;
1279
        case 7: /* bkpt */
1280
            gen_op_movl_T0_im((long)s->pc - 4);
1281
            gen_op_movl_reg_TN[0][15]();
1282
            gen_op_bkpt();
1283
            s->is_jmp = DISAS_JUMP;
1284
            break;
1285
        case 0x8: /* signed multiply */
1286
        case 0xa:
1287
        case 0xc:
1288
        case 0xe:
1289
            rs = (insn >> 8) & 0xf;
1290
            rn = (insn >> 12) & 0xf;
1291
            rd = (insn >> 16) & 0xf;
1292
            if (op1 == 1) {
1293
                /* (32 * 16) >> 16 */
1294
                gen_movl_T0_reg(s, rm);
1295
                gen_movl_T1_reg(s, rs);
1296
                if (sh & 4)
1297
                    gen_op_sarl_T1_im(16);
1298
                else
1299
                    gen_op_sxth_T1();
1300
                gen_op_imulw_T0_T1();
1301
                if ((sh & 2) == 0) {
1302
                    gen_movl_T1_reg(s, rn);
1303
                    gen_op_addl_T0_T1_setq();
1304
                }
1305
                gen_movl_reg_T0(s, rd);
1306
            } else {
1307
                /* 16 * 16 */
1308
                gen_movl_T0_reg(s, rm);
1309
                gen_movl_T1_reg(s, rs);
1310
                gen_mulxy(sh & 2, sh & 4);
1311
                if (op1 == 2) {
1312
                    gen_op_signbit_T1_T0();
1313
                    gen_op_addq_T0_T1(rn, rd);
1314
                    gen_movl_reg_T0(s, rn);
1315
                    gen_movl_reg_T1(s, rd);
1316
                } else {
1317
                    if (op1 == 0) {
1318
                        gen_movl_T1_reg(s, rn);
1319
                        gen_op_addl_T0_T1_setq();
1320
                    }
1321
                    gen_movl_reg_T0(s, rd);
1322
                }
1323
            }
1324
            break;
1325
        default:
1326
            goto illegal_op;
1327
        }
1328
    } else if (((insn & 0x0e000000) == 0 &&
1329
                (insn & 0x00000090) != 0x90) ||
1330
               ((insn & 0x0e000000) == (1 << 25))) {
1331
        int set_cc, logic_cc, shiftop;
1332
        
1333
        op1 = (insn >> 21) & 0xf;
1334
        set_cc = (insn >> 20) & 1;
1335
        logic_cc = table_logic_cc[op1] & set_cc;
1336

    
1337
        /* data processing instruction */
1338
        if (insn & (1 << 25)) {
1339
            /* immediate operand */
1340
            val = insn & 0xff;
1341
            shift = ((insn >> 8) & 0xf) * 2;
1342
            if (shift)
1343
                val = (val >> shift) | (val << (32 - shift));
1344
            gen_op_movl_T1_im(val);
1345
            if (logic_cc && shift)
1346
                gen_op_mov_CF_T1();
1347
        } else {
1348
            /* register */
1349
            rm = (insn) & 0xf;
1350
            gen_movl_T1_reg(s, rm);
1351
            shiftop = (insn >> 5) & 3;
1352
            if (!(insn & (1 << 4))) {
1353
                shift = (insn >> 7) & 0x1f;
1354
                if (shift != 0) {
1355
                    if (logic_cc) {
1356
                        gen_shift_T1_im_cc[shiftop](shift);
1357
                    } else {
1358
                        gen_shift_T1_im[shiftop](shift);
1359
                    }
1360
                } else if (shiftop != 0) {
1361
                    if (logic_cc) {
1362
                        gen_shift_T1_0_cc[shiftop]();
1363
                    } else {
1364
                        gen_shift_T1_0[shiftop]();
1365
                    }
1366
                }
1367
            } else {
1368
                rs = (insn >> 8) & 0xf;
1369
                gen_movl_T0_reg(s, rs);
1370
                if (logic_cc) {
1371
                    gen_shift_T1_T0_cc[shiftop]();
1372
                } else {
1373
                    gen_shift_T1_T0[shiftop]();
1374
                }
1375
            }
1376
        }
1377
        if (op1 != 0x0f && op1 != 0x0d) {
1378
            rn = (insn >> 16) & 0xf;
1379
            gen_movl_T0_reg(s, rn);
1380
        }
1381
        rd = (insn >> 12) & 0xf;
1382
        switch(op1) {
1383
        case 0x00:
1384
            gen_op_andl_T0_T1();
1385
            gen_movl_reg_T0(s, rd);
1386
            if (logic_cc)
1387
                gen_op_logic_T0_cc();
1388
            break;
1389
        case 0x01:
1390
            gen_op_xorl_T0_T1();
1391
            gen_movl_reg_T0(s, rd);
1392
            if (logic_cc)
1393
                gen_op_logic_T0_cc();
1394
            break;
1395
        case 0x02:
1396
            if (set_cc && rd == 15) {
1397
                /* SUBS r15, ... is used for exception return.  */
1398
                if (IS_USER(s))
1399
                    goto illegal_op;
1400
                gen_op_subl_T0_T1_cc();
1401
                gen_exception_return(s);
1402
            } else {
1403
                if (set_cc)
1404
                    gen_op_subl_T0_T1_cc();
1405
                else
1406
                    gen_op_subl_T0_T1();
1407
                gen_movl_reg_T0(s, rd);
1408
            }
1409
            break;
1410
        case 0x03:
1411
            if (set_cc)
1412
                gen_op_rsbl_T0_T1_cc();
1413
            else
1414
                gen_op_rsbl_T0_T1();
1415
            gen_movl_reg_T0(s, rd);
1416
            break;
1417
        case 0x04:
1418
            if (set_cc)
1419
                gen_op_addl_T0_T1_cc();
1420
            else
1421
                gen_op_addl_T0_T1();
1422
            gen_movl_reg_T0(s, rd);
1423
            break;
1424
        case 0x05:
1425
            if (set_cc)
1426
                gen_op_adcl_T0_T1_cc();
1427
            else
1428
                gen_op_adcl_T0_T1();
1429
            gen_movl_reg_T0(s, rd);
1430
            break;
1431
        case 0x06:
1432
            if (set_cc)
1433
                gen_op_sbcl_T0_T1_cc();
1434
            else
1435
                gen_op_sbcl_T0_T1();
1436
            gen_movl_reg_T0(s, rd);
1437
            break;
1438
        case 0x07:
1439
            if (set_cc)
1440
                gen_op_rscl_T0_T1_cc();
1441
            else
1442
                gen_op_rscl_T0_T1();
1443
            gen_movl_reg_T0(s, rd);
1444
            break;
1445
        case 0x08:
1446
            if (set_cc) {
1447
                gen_op_andl_T0_T1();
1448
                gen_op_logic_T0_cc();
1449
            }
1450
            break;
1451
        case 0x09:
1452
            if (set_cc) {
1453
                gen_op_xorl_T0_T1();
1454
                gen_op_logic_T0_cc();
1455
            }
1456
            break;
1457
        case 0x0a:
1458
            if (set_cc) {
1459
                gen_op_subl_T0_T1_cc();
1460
            }
1461
            break;
1462
        case 0x0b:
1463
            if (set_cc) {
1464
                gen_op_addl_T0_T1_cc();
1465
            }
1466
            break;
1467
        case 0x0c:
1468
            gen_op_orl_T0_T1();
1469
            gen_movl_reg_T0(s, rd);
1470
            if (logic_cc)
1471
                gen_op_logic_T0_cc();
1472
            break;
1473
        case 0x0d:
1474
            if (logic_cc && rd == 15) {
1475
                /* MOVS r15, ... is used for exception return.  */
1476
                if (IS_USER(s))
1477
                    goto illegal_op;
1478
                gen_op_movl_T0_T1();
1479
                gen_exception_return(s);
1480
            } else {
1481
                gen_movl_reg_T1(s, rd);
1482
                if (logic_cc)
1483
                    gen_op_logic_T1_cc();
1484
            }
1485
            break;
1486
        case 0x0e:
1487
            gen_op_bicl_T0_T1();
1488
            gen_movl_reg_T0(s, rd);
1489
            if (logic_cc)
1490
                gen_op_logic_T0_cc();
1491
            break;
1492
        default:
1493
        case 0x0f:
1494
            gen_op_notl_T1();
1495
            gen_movl_reg_T1(s, rd);
1496
            if (logic_cc)
1497
                gen_op_logic_T1_cc();
1498
            break;
1499
        }
1500
    } else {
1501
        /* other instructions */
1502
        op1 = (insn >> 24) & 0xf;
1503
        switch(op1) {
1504
        case 0x0:
1505
        case 0x1:
1506
            /* multiplies, extra load/stores */
1507
            sh = (insn >> 5) & 3;
1508
            if (sh == 0) {
1509
                if (op1 == 0x0) {
1510
                    rd = (insn >> 16) & 0xf;
1511
                    rn = (insn >> 12) & 0xf;
1512
                    rs = (insn >> 8) & 0xf;
1513
                    rm = (insn) & 0xf;
1514
                    if (((insn >> 22) & 3) == 0) {
1515
                        /* 32 bit mul */
1516
                        gen_movl_T0_reg(s, rs);
1517
                        gen_movl_T1_reg(s, rm);
1518
                        gen_op_mul_T0_T1();
1519
                        if (insn & (1 << 21)) {
1520
                            gen_movl_T1_reg(s, rn);
1521
                            gen_op_addl_T0_T1();
1522
                        }
1523
                        if (insn & (1 << 20)) 
1524
                            gen_op_logic_T0_cc();
1525
                        gen_movl_reg_T0(s, rd);
1526
                    } else {
1527
                        /* 64 bit mul */
1528
                        gen_movl_T0_reg(s, rs);
1529
                        gen_movl_T1_reg(s, rm);
1530
                        if (insn & (1 << 22)) 
1531
                            gen_op_imull_T0_T1();
1532
                        else
1533
                            gen_op_mull_T0_T1();
1534
                        if (insn & (1 << 21)) /* mult accumulate */
1535
                            gen_op_addq_T0_T1(rn, rd);
1536
                        if (!(insn & (1 << 23))) { /* double accumulate */
1537
                            ARCH(6);
1538
                            gen_op_addq_lo_T0_T1(rn);
1539
                            gen_op_addq_lo_T0_T1(rd);
1540
                        }
1541
                        if (insn & (1 << 20)) 
1542
                            gen_op_logicq_cc();
1543
                        gen_movl_reg_T0(s, rn);
1544
                        gen_movl_reg_T1(s, rd);
1545
                    }
1546
                } else {
1547
                    rn = (insn >> 16) & 0xf;
1548
                    rd = (insn >> 12) & 0xf;
1549
                    if (insn & (1 << 23)) {
1550
                        /* load/store exclusive */
1551
                        goto illegal_op;
1552
                    } else {
1553
                        /* SWP instruction */
1554
                        rm = (insn) & 0xf;
1555
                        
1556
                        gen_movl_T0_reg(s, rm);
1557
                        gen_movl_T1_reg(s, rn);
1558
                        if (insn & (1 << 22)) {
1559
                            gen_ldst(swpb, s);
1560
                        } else {
1561
                            gen_ldst(swpl, s);
1562
                        }
1563
                        gen_movl_reg_T0(s, rd);
1564
                    }
1565
                }
1566
            } else {
1567
                int address_offset;
1568
                int load;
1569
                /* Misc load/store */
1570
                rn = (insn >> 16) & 0xf;
1571
                rd = (insn >> 12) & 0xf;
1572
                gen_movl_T1_reg(s, rn);
1573
                if (insn & (1 << 24))
1574
                    gen_add_datah_offset(s, insn, 0);
1575
                address_offset = 0;
1576
                if (insn & (1 << 20)) {
1577
                    /* load */
1578
                    switch(sh) {
1579
                    case 1:
1580
                        gen_ldst(lduw, s);
1581
                        break;
1582
                    case 2:
1583
                        gen_ldst(ldsb, s);
1584
                        break;
1585
                    default:
1586
                    case 3:
1587
                        gen_ldst(ldsw, s);
1588
                        break;
1589
                    }
1590
                    load = 1;
1591
                } else if (sh & 2) {
1592
                    /* doubleword */
1593
                    if (sh & 1) {
1594
                        /* store */
1595
                        gen_movl_T0_reg(s, rd);
1596
                        gen_ldst(stl, s);
1597
                        gen_op_addl_T1_im(4);
1598
                        gen_movl_T0_reg(s, rd + 1);
1599
                        gen_ldst(stl, s);
1600
                        load = 0;
1601
                    } else {
1602
                        /* load */
1603
                        gen_ldst(ldl, s);
1604
                        gen_movl_reg_T0(s, rd);
1605
                        gen_op_addl_T1_im(4);
1606
                        gen_ldst(ldl, s);
1607
                        rd++;
1608
                        load = 1;
1609
                    }
1610
                    address_offset = -4;
1611
                } else {
1612
                    /* store */
1613
                    gen_movl_T0_reg(s, rd);
1614
                    gen_ldst(stw, s);
1615
                    load = 0;
1616
                }
1617
                /* Perform base writeback before the loaded value to
1618
                   ensure correct behavior with overlapping index registers.
1619
                   ldrd with base writeback is is undefined if the
1620
                   destination and index registers overlap.  */
1621
                if (!(insn & (1 << 24))) {
1622
                    gen_add_datah_offset(s, insn, address_offset);
1623
                    gen_movl_reg_T1(s, rn);
1624
                } else if (insn & (1 << 21)) {
1625
                    if (address_offset)
1626
                        gen_op_addl_T1_im(address_offset);
1627
                    gen_movl_reg_T1(s, rn);
1628
                }
1629
                if (load) {
1630
                    /* Complete the load.  */
1631
                    gen_movl_reg_T0(s, rd);
1632
                }
1633
            }
1634
            break;
1635
        case 0x4:
1636
        case 0x5:
1637
        case 0x6:
1638
        case 0x7:
1639
            /* Check for undefined extension instructions
1640
             * per the ARM Bible IE:
1641
             * xxxx 0111 1111 xxxx  xxxx xxxx 1111 xxxx
1642
             */
1643
            sh = (0xf << 20) | (0xf << 4);
1644
            if (op1 == 0x7 && ((insn & sh) == sh))
1645
            {
1646
                goto illegal_op;
1647
            }
1648
            /* load/store byte/word */
1649
            rn = (insn >> 16) & 0xf;
1650
            rd = (insn >> 12) & 0xf;
1651
            gen_movl_T1_reg(s, rn);
1652
            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
1653
            if (insn & (1 << 24))
1654
                gen_add_data_offset(s, insn);
1655
            if (insn & (1 << 20)) {
1656
                /* load */
1657
                s->is_mem = 1;
1658
#if defined(CONFIG_USER_ONLY)
1659
                if (insn & (1 << 22))
1660
                    gen_op_ldub_raw();
1661
                else
1662
                    gen_op_ldl_raw();
1663
#else
1664
                if (insn & (1 << 22)) {
1665
                    if (i)
1666
                        gen_op_ldub_user();
1667
                    else
1668
                        gen_op_ldub_kernel();
1669
                } else {
1670
                    if (i)
1671
                        gen_op_ldl_user();
1672
                    else
1673
                        gen_op_ldl_kernel();
1674
                }
1675
#endif
1676
            } else {
1677
                /* store */
1678
                gen_movl_T0_reg(s, rd);
1679
#if defined(CONFIG_USER_ONLY)
1680
                if (insn & (1 << 22))
1681
                    gen_op_stb_raw();
1682
                else
1683
                    gen_op_stl_raw();
1684
#else
1685
                if (insn & (1 << 22)) {
1686
                    if (i)
1687
                        gen_op_stb_user();
1688
                    else
1689
                        gen_op_stb_kernel();
1690
                } else {
1691
                    if (i)
1692
                        gen_op_stl_user();
1693
                    else
1694
                        gen_op_stl_kernel();
1695
                }
1696
#endif
1697
            }
1698
            if (!(insn & (1 << 24))) {
1699
                gen_add_data_offset(s, insn);
1700
                gen_movl_reg_T1(s, rn);
1701
            } else if (insn & (1 << 21))
1702
                gen_movl_reg_T1(s, rn); {
1703
            }
1704
            if (insn & (1 << 20)) {
1705
                /* Complete the load.  */
1706
                if (rd == 15)
1707
                    gen_bx(s);
1708
                else
1709
                    gen_movl_reg_T0(s, rd);
1710
            }
1711
            break;
1712
        case 0x08:
1713
        case 0x09:
1714
            {
1715
                int j, n, user, loaded_base;
1716
                /* load/store multiple words */
1717
                /* XXX: store correct base if write back */
1718
                user = 0;
1719
                if (insn & (1 << 22)) {
1720
                    if (IS_USER(s))
1721
                        goto illegal_op; /* only usable in supervisor mode */
1722

    
1723
                    if ((insn & (1 << 15)) == 0)
1724
                        user = 1;
1725
                }
1726
                rn = (insn >> 16) & 0xf;
1727
                gen_movl_T1_reg(s, rn);
1728
                
1729
                /* compute total size */
1730
                loaded_base = 0;
1731
                n = 0;
1732
                for(i=0;i<16;i++) {
1733
                    if (insn & (1 << i))
1734
                        n++;
1735
                }
1736
                /* XXX: test invalid n == 0 case ? */
1737
                if (insn & (1 << 23)) {
1738
                    if (insn & (1 << 24)) {
1739
                        /* pre increment */
1740
                        gen_op_addl_T1_im(4);
1741
                    } else {
1742
                        /* post increment */
1743
                    }
1744
                } else {
1745
                    if (insn & (1 << 24)) {
1746
                        /* pre decrement */
1747
                        gen_op_addl_T1_im(-(n * 4));
1748
                    } else {
1749
                        /* post decrement */
1750
                        if (n != 1)
1751
                            gen_op_addl_T1_im(-((n - 1) * 4));
1752
                    }
1753
                }
1754
                j = 0;
1755
                for(i=0;i<16;i++) {
1756
                    if (insn & (1 << i)) {
1757
                        if (insn & (1 << 20)) {
1758
                            /* load */
1759
                            gen_ldst(ldl, s);
1760
                            if (i == 15) {
1761
                                gen_bx(s);
1762
                            } else if (user) {
1763
                                gen_op_movl_user_T0(i);
1764
                            } else if (i == rn) {
1765
                                gen_op_movl_T2_T0();
1766
                                loaded_base = 1;
1767
                            } else {
1768
                                gen_movl_reg_T0(s, i);
1769
                            }
1770
                        } else {
1771
                            /* store */
1772
                            if (i == 15) {
1773
                                /* special case: r15 = PC + 12 */
1774
                                val = (long)s->pc + 8;
1775
                                gen_op_movl_TN_im[0](val);
1776
                            } else if (user) {
1777
                                gen_op_movl_T0_user(i);
1778
                            } else {
1779
                                gen_movl_T0_reg(s, i);
1780
                            }
1781
                            gen_ldst(stl, s);
1782
                        }
1783
                        j++;
1784
                        /* no need to add after the last transfer */
1785
                        if (j != n)
1786
                            gen_op_addl_T1_im(4);
1787
                    }
1788
                }
1789
                if (insn & (1 << 21)) {
1790
                    /* write back */
1791
                    if (insn & (1 << 23)) {
1792
                        if (insn & (1 << 24)) {
1793
                            /* pre increment */
1794
                        } else {
1795
                            /* post increment */
1796
                            gen_op_addl_T1_im(4);
1797
                        }
1798
                    } else {
1799
                        if (insn & (1 << 24)) {
1800
                            /* pre decrement */
1801
                            if (n != 1)
1802
                                gen_op_addl_T1_im(-((n - 1) * 4));
1803
                        } else {
1804
                            /* post decrement */
1805
                            gen_op_addl_T1_im(-(n * 4));
1806
                        }
1807
                    }
1808
                    gen_movl_reg_T1(s, rn);
1809
                }
1810
                if (loaded_base) {
1811
                    gen_op_movl_T0_T2();
1812
                    gen_movl_reg_T0(s, rn);
1813
                }
1814
                if ((insn & (1 << 22)) && !user) {
1815
                    /* Restore CPSR from SPSR.  */
1816
                    gen_op_movl_T0_spsr();
1817
                    gen_op_movl_cpsr_T0(0xffffffff);
1818
                    s->is_jmp = DISAS_UPDATE;
1819
                }
1820
            }
1821
            break;
1822
        case 0xa:
1823
        case 0xb:
1824
            {
1825
                int32_t offset;
1826
                
1827
                /* branch (and link) */
1828
                val = (int32_t)s->pc;
1829
                if (insn & (1 << 24)) {
1830
                    gen_op_movl_T0_im(val);
1831
                    gen_op_movl_reg_TN[0][14]();
1832
                }
1833
                offset = (((int32_t)insn << 8) >> 8);
1834
                val += (offset << 2) + 4;
1835
                gen_jmp(s, val);
1836
            }
1837
            break;
1838
        case 0xc:
1839
        case 0xd:
1840
        case 0xe:
1841
            /* Coprocessor.  */
1842
            op1 = (insn >> 8) & 0xf;
1843
            if (arm_feature(env, ARM_FEATURE_XSCALE) &&
1844
                    ((env->cp15.c15_cpar ^ 0x3fff) & (1 << op1)))
1845
                goto illegal_op;
1846
            switch (op1) {
1847
            case 0 ... 1:
1848
            case 2 ... 9:
1849
            case 12 ... 14:
1850
                if (disas_cp_insn (env, s, insn))
1851
                    goto illegal_op;
1852
                break;
1853
            case 10:
1854
            case 11:
1855
                if (disas_vfp_insn (env, s, insn))
1856
                    goto illegal_op;
1857
                break;
1858
            case 15:
1859
                if (disas_cp15_insn (s, insn))
1860
                    goto illegal_op;
1861
                break;
1862
            default:
1863
                /* unknown coprocessor.  */
1864
                goto illegal_op;
1865
            }
1866
            break;
1867
        case 0xf:
1868
            /* swi */
1869
            gen_op_movl_T0_im((long)s->pc);
1870
            gen_op_movl_reg_TN[0][15]();
1871
            gen_op_swi();
1872
            s->is_jmp = DISAS_JUMP;
1873
            break;
1874
        default:
1875
        illegal_op:
1876
            gen_op_movl_T0_im((long)s->pc - 4);
1877
            gen_op_movl_reg_TN[0][15]();
1878
            gen_op_undef_insn();
1879
            s->is_jmp = DISAS_JUMP;
1880
            break;
1881
        }
1882
    }
1883
}
1884

    
1885
static void disas_thumb_insn(DisasContext *s)
1886
{
1887
    uint32_t val, insn, op, rm, rn, rd, shift, cond;
1888
    int32_t offset;
1889
    int i;
1890

    
1891
    insn = lduw_code(s->pc);
1892
    s->pc += 2;
1893

    
1894
    switch (insn >> 12) {
1895
    case 0: case 1:
1896
        rd = insn & 7;
1897
        op = (insn >> 11) & 3;
1898
        if (op == 3) {
1899
            /* add/subtract */
1900
            rn = (insn >> 3) & 7;
1901
            gen_movl_T0_reg(s, rn);
1902
            if (insn & (1 << 10)) {
1903
                /* immediate */
1904
                gen_op_movl_T1_im((insn >> 6) & 7);
1905
            } else {
1906
                /* reg */
1907
                rm = (insn >> 6) & 7;
1908
                gen_movl_T1_reg(s, rm);
1909
            }
1910
            if (insn & (1 << 9))
1911
                gen_op_subl_T0_T1_cc();
1912
            else
1913
                gen_op_addl_T0_T1_cc();
1914
            gen_movl_reg_T0(s, rd);
1915
        } else {
1916
            /* shift immediate */
1917
            rm = (insn >> 3) & 7;
1918
            shift = (insn >> 6) & 0x1f;
1919
            gen_movl_T0_reg(s, rm);
1920
            gen_shift_T0_im_thumb[op](shift);
1921
            gen_movl_reg_T0(s, rd);
1922
        }
1923
        break;
1924
    case 2: case 3:
1925
        /* arithmetic large immediate */
1926
        op = (insn >> 11) & 3;
1927
        rd = (insn >> 8) & 0x7;
1928
        if (op == 0) {
1929
            gen_op_movl_T0_im(insn & 0xff);
1930
        } else {
1931
            gen_movl_T0_reg(s, rd);
1932
            gen_op_movl_T1_im(insn & 0xff);
1933
        }
1934
        switch (op) {
1935
        case 0: /* mov */
1936
            gen_op_logic_T0_cc();
1937
            break;
1938
        case 1: /* cmp */
1939
            gen_op_subl_T0_T1_cc();
1940
            break;
1941
        case 2: /* add */
1942
            gen_op_addl_T0_T1_cc();
1943
            break;
1944
        case 3: /* sub */
1945
            gen_op_subl_T0_T1_cc();
1946
            break;
1947
        }
1948
        if (op != 1)
1949
            gen_movl_reg_T0(s, rd);
1950
        break;
1951
    case 4:
1952
        if (insn & (1 << 11)) {
1953
            rd = (insn >> 8) & 7;
1954
            /* load pc-relative.  Bit 1 of PC is ignored.  */
1955
            val = s->pc + 2 + ((insn & 0xff) * 4);
1956
            val &= ~(uint32_t)2;
1957
            gen_op_movl_T1_im(val);
1958
            gen_ldst(ldl, s);
1959
            gen_movl_reg_T0(s, rd);
1960
            break;
1961
        }
1962
        if (insn & (1 << 10)) {
1963
            /* data processing extended or blx */
1964
            rd = (insn & 7) | ((insn >> 4) & 8);
1965
            rm = (insn >> 3) & 0xf;
1966
            op = (insn >> 8) & 3;
1967
            switch (op) {
1968
            case 0: /* add */
1969
                gen_movl_T0_reg(s, rd);
1970
                gen_movl_T1_reg(s, rm);
1971
                gen_op_addl_T0_T1();
1972
                gen_movl_reg_T0(s, rd);
1973
                break;
1974
            case 1: /* cmp */
1975
                gen_movl_T0_reg(s, rd);
1976
                gen_movl_T1_reg(s, rm);
1977
                gen_op_subl_T0_T1_cc();
1978
                break;
1979
            case 2: /* mov/cpy */
1980
                gen_movl_T0_reg(s, rm);
1981
                gen_movl_reg_T0(s, rd);
1982
                break;
1983
            case 3:/* branch [and link] exchange thumb register */
1984
                if (insn & (1 << 7)) {
1985
                    val = (uint32_t)s->pc | 1;
1986
                    gen_op_movl_T1_im(val);
1987
                    gen_movl_reg_T1(s, 14);
1988
                }
1989
                gen_movl_T0_reg(s, rm);
1990
                gen_bx(s);
1991
                break;
1992
            }
1993
            break;
1994
        }
1995

    
1996
        /* data processing register */
1997
        rd = insn & 7;
1998
        rm = (insn >> 3) & 7;
1999
        op = (insn >> 6) & 0xf;
2000
        if (op == 2 || op == 3 || op == 4 || op == 7) {
2001
            /* the shift/rotate ops want the operands backwards */
2002
            val = rm;
2003
            rm = rd;
2004
            rd = val;
2005
            val = 1;
2006
        } else {
2007
            val = 0;
2008
        }
2009

    
2010
        if (op == 9) /* neg */
2011
            gen_op_movl_T0_im(0);
2012
        else if (op != 0xf) /* mvn doesn't read its first operand */
2013
            gen_movl_T0_reg(s, rd);
2014

    
2015
        gen_movl_T1_reg(s, rm);
2016
        switch (op) {
2017
        case 0x0: /* and */
2018
            gen_op_andl_T0_T1();
2019
            gen_op_logic_T0_cc();
2020
            break;
2021
        case 0x1: /* eor */
2022
            gen_op_xorl_T0_T1();
2023
            gen_op_logic_T0_cc();
2024
            break;
2025
        case 0x2: /* lsl */
2026
            gen_op_shll_T1_T0_cc();
2027
            gen_op_logic_T1_cc();
2028
            break;
2029
        case 0x3: /* lsr */
2030
            gen_op_shrl_T1_T0_cc();
2031
            gen_op_logic_T1_cc();
2032
            break;
2033
        case 0x4: /* asr */
2034
            gen_op_sarl_T1_T0_cc();
2035
            gen_op_logic_T1_cc();
2036
            break;
2037
        case 0x5: /* adc */
2038
            gen_op_adcl_T0_T1_cc();
2039
            break;
2040
        case 0x6: /* sbc */
2041
            gen_op_sbcl_T0_T1_cc();
2042
            break;
2043
        case 0x7: /* ror */
2044
            gen_op_rorl_T1_T0_cc();
2045
            gen_op_logic_T1_cc();
2046
            break;
2047
        case 0x8: /* tst */
2048
            gen_op_andl_T0_T1();
2049
            gen_op_logic_T0_cc();
2050
            rd = 16;
2051
            break;
2052
        case 0x9: /* neg */
2053
            gen_op_subl_T0_T1_cc();
2054
            break;
2055
        case 0xa: /* cmp */
2056
            gen_op_subl_T0_T1_cc();
2057
            rd = 16;
2058
            break;
2059
        case 0xb: /* cmn */
2060
            gen_op_addl_T0_T1_cc();
2061
            rd = 16;
2062
            break;
2063
        case 0xc: /* orr */
2064
            gen_op_orl_T0_T1();
2065
            gen_op_logic_T0_cc();
2066
            break;
2067
        case 0xd: /* mul */
2068
            gen_op_mull_T0_T1();
2069
            gen_op_logic_T0_cc();
2070
            break;
2071
        case 0xe: /* bic */
2072
            gen_op_bicl_T0_T1();
2073
            gen_op_logic_T0_cc();
2074
            break;
2075
        case 0xf: /* mvn */
2076
            gen_op_notl_T1();
2077
            gen_op_logic_T1_cc();
2078
            val = 1;
2079
            rm = rd;
2080
            break;
2081
        }
2082
        if (rd != 16) {
2083
            if (val)
2084
                gen_movl_reg_T1(s, rm);
2085
            else
2086
                gen_movl_reg_T0(s, rd);
2087
        }
2088
        break;
2089

    
2090
    case 5:
2091
        /* load/store register offset.  */
2092
        rd = insn & 7;
2093
        rn = (insn >> 3) & 7;
2094
        rm = (insn >> 6) & 7;
2095
        op = (insn >> 9) & 7;
2096
        gen_movl_T1_reg(s, rn);
2097
        gen_movl_T2_reg(s, rm);
2098
        gen_op_addl_T1_T2();
2099

    
2100
        if (op < 3) /* store */
2101
            gen_movl_T0_reg(s, rd);
2102

    
2103
        switch (op) {
2104
        case 0: /* str */
2105
            gen_ldst(stl, s);
2106
            break;
2107
        case 1: /* strh */
2108
            gen_ldst(stw, s);
2109
            break;
2110
        case 2: /* strb */
2111
            gen_ldst(stb, s);
2112
            break;
2113
        case 3: /* ldrsb */
2114
            gen_ldst(ldsb, s);
2115
            break;
2116
        case 4: /* ldr */
2117
            gen_ldst(ldl, s);
2118
            break;
2119
        case 5: /* ldrh */
2120
            gen_ldst(lduw, s);
2121
            break;
2122
        case 6: /* ldrb */
2123
            gen_ldst(ldub, s);
2124
            break;
2125
        case 7: /* ldrsh */
2126
            gen_ldst(ldsw, s);
2127
            break;
2128
        }
2129
        if (op >= 3) /* load */
2130
            gen_movl_reg_T0(s, rd);
2131
        break;
2132

    
2133
    case 6:
2134
        /* load/store word immediate offset */
2135
        rd = insn & 7;
2136
        rn = (insn >> 3) & 7;
2137
        gen_movl_T1_reg(s, rn);
2138
        val = (insn >> 4) & 0x7c;
2139
        gen_op_movl_T2_im(val);
2140
        gen_op_addl_T1_T2();
2141

    
2142
        if (insn & (1 << 11)) {
2143
            /* load */
2144
            gen_ldst(ldl, s);
2145
            gen_movl_reg_T0(s, rd);
2146
        } else {
2147
            /* store */
2148
            gen_movl_T0_reg(s, rd);
2149
            gen_ldst(stl, s);
2150
        }
2151
        break;
2152

    
2153
    case 7:
2154
        /* load/store byte immediate offset */
2155
        rd = insn & 7;
2156
        rn = (insn >> 3) & 7;
2157
        gen_movl_T1_reg(s, rn);
2158
        val = (insn >> 6) & 0x1f;
2159
        gen_op_movl_T2_im(val);
2160
        gen_op_addl_T1_T2();
2161

    
2162
        if (insn & (1 << 11)) {
2163
            /* load */
2164
            gen_ldst(ldub, s);
2165
            gen_movl_reg_T0(s, rd);
2166
        } else {
2167
            /* store */
2168
            gen_movl_T0_reg(s, rd);
2169
            gen_ldst(stb, s);
2170
        }
2171
        break;
2172

    
2173
    case 8:
2174
        /* load/store halfword immediate offset */
2175
        rd = insn & 7;
2176
        rn = (insn >> 3) & 7;
2177
        gen_movl_T1_reg(s, rn);
2178
        val = (insn >> 5) & 0x3e;
2179
        gen_op_movl_T2_im(val);
2180
        gen_op_addl_T1_T2();
2181

    
2182
        if (insn & (1 << 11)) {
2183
            /* load */
2184
            gen_ldst(lduw, s);
2185
            gen_movl_reg_T0(s, rd);
2186
        } else {
2187
            /* store */
2188
            gen_movl_T0_reg(s, rd);
2189
            gen_ldst(stw, s);
2190
        }
2191
        break;
2192

    
2193
    case 9:
2194
        /* load/store from stack */
2195
        rd = (insn >> 8) & 7;
2196
        gen_movl_T1_reg(s, 13);
2197
        val = (insn & 0xff) * 4;
2198
        gen_op_movl_T2_im(val);
2199
        gen_op_addl_T1_T2();
2200

    
2201
        if (insn & (1 << 11)) {
2202
            /* load */
2203
            gen_ldst(ldl, s);
2204
            gen_movl_reg_T0(s, rd);
2205
        } else {
2206
            /* store */
2207
            gen_movl_T0_reg(s, rd);
2208
            gen_ldst(stl, s);
2209
        }
2210
        break;
2211

    
2212
    case 10:
2213
        /* add to high reg */
2214
        rd = (insn >> 8) & 7;
2215
        if (insn & (1 << 11)) {
2216
            /* SP */
2217
            gen_movl_T0_reg(s, 13);
2218
        } else {
2219
            /* PC. bit 1 is ignored.  */
2220
            gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2);
2221
        }
2222
        val = (insn & 0xff) * 4;
2223
        gen_op_movl_T1_im(val);
2224
        gen_op_addl_T0_T1();
2225
        gen_movl_reg_T0(s, rd);
2226
        break;
2227

    
2228
    case 11:
2229
        /* misc */
2230
        op = (insn >> 8) & 0xf;
2231
        switch (op) {
2232
        case 0:
2233
            /* adjust stack pointer */
2234
            gen_movl_T1_reg(s, 13);
2235
            val = (insn & 0x7f) * 4;
2236
            if (insn & (1 << 7))
2237
              val = -(int32_t)val;
2238
            gen_op_movl_T2_im(val);
2239
            gen_op_addl_T1_T2();
2240
            gen_movl_reg_T1(s, 13);
2241
            break;
2242

    
2243
        case 4: case 5: case 0xc: case 0xd:
2244
            /* push/pop */
2245
            gen_movl_T1_reg(s, 13);
2246
            if (insn & (1 << 8))
2247
                offset = 4;
2248
            else
2249
                offset = 0;
2250
            for (i = 0; i < 8; i++) {
2251
                if (insn & (1 << i))
2252
                    offset += 4;
2253
            }
2254
            if ((insn & (1 << 11)) == 0) {
2255
                gen_op_movl_T2_im(-offset);
2256
                gen_op_addl_T1_T2();
2257
            }
2258
            gen_op_movl_T2_im(4);
2259
            for (i = 0; i < 8; i++) {
2260
                if (insn & (1 << i)) {
2261
                    if (insn & (1 << 11)) {
2262
                        /* pop */
2263
                        gen_ldst(ldl, s);
2264
                        gen_movl_reg_T0(s, i);
2265
                    } else {
2266
                        /* push */
2267
                        gen_movl_T0_reg(s, i);
2268
                        gen_ldst(stl, s);
2269
                    }
2270
                    /* advance to the next address.  */
2271
                    gen_op_addl_T1_T2();
2272
                }
2273
            }
2274
            if (insn & (1 << 8)) {
2275
                if (insn & (1 << 11)) {
2276
                    /* pop pc */
2277
                    gen_ldst(ldl, s);
2278
                    /* don't set the pc until the rest of the instruction
2279
                       has completed */
2280
                } else {
2281
                    /* push lr */
2282
                    gen_movl_T0_reg(s, 14);
2283
                    gen_ldst(stl, s);
2284
                }
2285
                gen_op_addl_T1_T2();
2286
            }
2287
            if ((insn & (1 << 11)) == 0) {
2288
                gen_op_movl_T2_im(-offset);
2289
                gen_op_addl_T1_T2();
2290
            }
2291
            /* write back the new stack pointer */
2292
            gen_movl_reg_T1(s, 13);
2293
            /* set the new PC value */
2294
            if ((insn & 0x0900) == 0x0900)
2295
                gen_bx(s);
2296
            break;
2297

    
2298
        case 0xe: /* bkpt */
2299
            gen_op_movl_T0_im((long)s->pc - 2);
2300
            gen_op_movl_reg_TN[0][15]();
2301
            gen_op_bkpt();
2302
            s->is_jmp = DISAS_JUMP;
2303
            break;
2304

    
2305
        default:
2306
            goto undef;
2307
        }
2308
        break;
2309

    
2310
    case 12:
2311
        /* load/store multiple */
2312
        rn = (insn >> 8) & 0x7;
2313
        gen_movl_T1_reg(s, rn);
2314
        gen_op_movl_T2_im(4);
2315
        for (i = 0; i < 8; i++) {
2316
            if (insn & (1 << i)) {
2317
                if (insn & (1 << 11)) {
2318
                    /* load */
2319
                    gen_ldst(ldl, s);
2320
                    gen_movl_reg_T0(s, i);
2321
                } else {
2322
                    /* store */
2323
                    gen_movl_T0_reg(s, i);
2324
                    gen_ldst(stl, s);
2325
                }
2326
                /* advance to the next address */
2327
                gen_op_addl_T1_T2();
2328
            }
2329
        }
2330
        /* Base register writeback.  */
2331
        if ((insn & (1 << rn)) == 0)
2332
            gen_movl_reg_T1(s, rn);
2333
        break;
2334

    
2335
    case 13:
2336
        /* conditional branch or swi */
2337
        cond = (insn >> 8) & 0xf;
2338
        if (cond == 0xe)
2339
            goto undef;
2340

    
2341
        if (cond == 0xf) {
2342
            /* swi */
2343
            gen_op_movl_T0_im((long)s->pc | 1);
2344
            /* Don't set r15.  */
2345
            gen_op_movl_reg_TN[0][15]();
2346
            gen_op_swi();
2347
            s->is_jmp = DISAS_JUMP;
2348
            break;
2349
        }
2350
        /* generate a conditional jump to next instruction */
2351
        s->condlabel = gen_new_label();
2352
        gen_test_cc[cond ^ 1](s->condlabel);
2353
        s->condjmp = 1;
2354
        //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
2355
        //s->is_jmp = DISAS_JUMP_NEXT;
2356
        gen_movl_T1_reg(s, 15);
2357

    
2358
        /* jump to the offset */
2359
        val = (uint32_t)s->pc + 2;
2360
        offset = ((int32_t)insn << 24) >> 24;
2361
        val += offset << 1;
2362
        gen_jmp(s, val);
2363
        break;
2364

    
2365
    case 14:
2366
        /* unconditional branch */
2367
        if (insn & (1 << 11)) {
2368
            /* Second half of blx.  */
2369
            offset = ((insn & 0x7ff) << 1);
2370
            gen_movl_T0_reg(s, 14);
2371
            gen_op_movl_T1_im(offset);
2372
            gen_op_addl_T0_T1();
2373
            gen_op_movl_T1_im(0xfffffffc);
2374
            gen_op_andl_T0_T1();
2375

    
2376
            val = (uint32_t)s->pc;
2377
            gen_op_movl_T1_im(val | 1);
2378
            gen_movl_reg_T1(s, 14);
2379
            gen_bx(s);
2380
            break;
2381
        }
2382
        val = (uint32_t)s->pc;
2383
        offset = ((int32_t)insn << 21) >> 21;
2384
        val += (offset << 1) + 2;
2385
        gen_jmp(s, val);
2386
        break;
2387

    
2388
    case 15:
2389
        /* branch and link [and switch to arm] */
2390
        if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
2391
            /* Instruction spans a page boundary.  Implement it as two
2392
               16-bit instructions in case the second half causes an
2393
               prefetch abort.  */
2394
            offset = ((int32_t)insn << 21) >> 9;
2395
            val = s->pc + 2 + offset;
2396
            gen_op_movl_T0_im(val);
2397
            gen_movl_reg_T0(s, 14);
2398
            break;
2399
        }
2400
        if (insn & (1 << 11)) {
2401
            /* Second half of bl.  */
2402
            offset = ((insn & 0x7ff) << 1) | 1;
2403
            gen_movl_T0_reg(s, 14);
2404
            gen_op_movl_T1_im(offset);
2405
            gen_op_addl_T0_T1();
2406

    
2407
            val = (uint32_t)s->pc;
2408
            gen_op_movl_T1_im(val | 1);
2409
            gen_movl_reg_T1(s, 14);
2410
            gen_bx(s);
2411
            break;
2412
        }
2413
        offset = ((int32_t)insn << 21) >> 10;
2414
        insn = lduw_code(s->pc);
2415
        offset |= insn & 0x7ff;
2416

    
2417
        val = (uint32_t)s->pc + 2;
2418
        gen_op_movl_T1_im(val | 1);
2419
        gen_movl_reg_T1(s, 14);
2420
        
2421
        val += offset << 1;
2422
        if (insn & (1 << 12)) {
2423
            /* bl */
2424
            gen_jmp(s, val);
2425
        } else {
2426
            /* blx */
2427
            val &= ~(uint32_t)2;
2428
            gen_op_movl_T0_im(val);
2429
            gen_bx(s);
2430
        }
2431
    }
2432
    return;
2433
undef:
2434
    gen_op_movl_T0_im((long)s->pc - 2);
2435
    gen_op_movl_reg_TN[0][15]();
2436
    gen_op_undef_insn();
2437
    s->is_jmp = DISAS_JUMP;
2438
}
2439

    
2440
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
2441
   basic block 'tb'. If search_pc is TRUE, also generate PC
2442
   information for each intermediate instruction. */
2443
static inline int gen_intermediate_code_internal(CPUState *env, 
2444
                                                 TranslationBlock *tb, 
2445
                                                 int search_pc)
2446
{
2447
    DisasContext dc1, *dc = &dc1;
2448
    uint16_t *gen_opc_end;
2449
    int j, lj;
2450
    target_ulong pc_start;
2451
    uint32_t next_page_start;
2452
    
2453
    /* generate intermediate code */
2454
    pc_start = tb->pc;
2455
       
2456
    dc->tb = tb;
2457

    
2458
    gen_opc_ptr = gen_opc_buf;
2459
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2460
    gen_opparam_ptr = gen_opparam_buf;
2461

    
2462
    dc->is_jmp = DISAS_NEXT;
2463
    dc->pc = pc_start;
2464
    dc->singlestep_enabled = env->singlestep_enabled;
2465
    dc->condjmp = 0;
2466
    dc->thumb = env->thumb;
2467
    dc->is_mem = 0;
2468
#if !defined(CONFIG_USER_ONLY)
2469
    dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
2470
#endif
2471
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
2472
    nb_gen_labels = 0;
2473
    lj = -1;
2474
    do {
2475
        if (env->nb_breakpoints > 0) {
2476
            for(j = 0; j < env->nb_breakpoints; j++) {
2477
                if (env->breakpoints[j] == dc->pc) {
2478
                    gen_op_movl_T0_im((long)dc->pc);
2479
                    gen_op_movl_reg_TN[0][15]();
2480
                    gen_op_debug();
2481
                    dc->is_jmp = DISAS_JUMP;
2482
                    break;
2483
                }
2484
            }
2485
        }
2486
        if (search_pc) {
2487
            j = gen_opc_ptr - gen_opc_buf;
2488
            if (lj < j) {
2489
                lj++;
2490
                while (lj < j)
2491
                    gen_opc_instr_start[lj++] = 0;
2492
            }
2493
            gen_opc_pc[lj] = dc->pc;
2494
            gen_opc_instr_start[lj] = 1;
2495
        }
2496

    
2497
        if (env->thumb)
2498
          disas_thumb_insn(dc);
2499
        else
2500
          disas_arm_insn(env, dc);
2501

    
2502
        if (dc->condjmp && !dc->is_jmp) {
2503
            gen_set_label(dc->condlabel);
2504
            dc->condjmp = 0;
2505
        }
2506
        /* Terminate the TB on memory ops if watchpoints are present.  */
2507
        /* FIXME: This should be replacd by the deterministic execution
2508
         * IRQ raising bits.  */
2509
        if (dc->is_mem && env->nb_watchpoints)
2510
            break;
2511

    
2512
        /* Translation stops when a conditional branch is enoutered.
2513
         * Otherwise the subsequent code could get translated several times.
2514
         * Also stop translation when a page boundary is reached.  This
2515
         * ensures prefech aborts occur at the right place.  */
2516
    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
2517
             !env->singlestep_enabled &&
2518
             dc->pc < next_page_start);
2519
    /* At this stage dc->condjmp will only be set when the skipped
2520
     * instruction was a conditional branch, and the PC has already been
2521
     * written.  */
2522
    if (__builtin_expect(env->singlestep_enabled, 0)) {
2523
        /* Make sure the pc is updated, and raise a debug exception.  */
2524
        if (dc->condjmp) {
2525
            gen_op_debug();
2526
            gen_set_label(dc->condlabel);
2527
        }
2528
        if (dc->condjmp || !dc->is_jmp) {
2529
            gen_op_movl_T0_im((long)dc->pc);
2530
            gen_op_movl_reg_TN[0][15]();
2531
            dc->condjmp = 0;
2532
        }
2533
        gen_op_debug();
2534
    } else {
2535
        switch(dc->is_jmp) {
2536
        case DISAS_NEXT:
2537
            gen_goto_tb(dc, 1, dc->pc);
2538
            break;
2539
        default:
2540
        case DISAS_JUMP:
2541
        case DISAS_UPDATE:
2542
            /* indicate that the hash table must be used to find the next TB */
2543
            gen_op_movl_T0_0();
2544
            gen_op_exit_tb();
2545
            break;
2546
        case DISAS_TB_JUMP:
2547
            /* nothing more to generate */
2548
            break;
2549
        }
2550
        if (dc->condjmp) {
2551
            gen_set_label(dc->condlabel);
2552
            gen_goto_tb(dc, 1, dc->pc);
2553
            dc->condjmp = 0;
2554
        }
2555
    }
2556
    *gen_opc_ptr = INDEX_op_end;
2557

    
2558
#ifdef DEBUG_DISAS
2559
    if (loglevel & CPU_LOG_TB_IN_ASM) {
2560
        fprintf(logfile, "----------------\n");
2561
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
2562
        target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
2563
        fprintf(logfile, "\n");
2564
        if (loglevel & (CPU_LOG_TB_OP)) {
2565
            fprintf(logfile, "OP:\n");
2566
            dump_ops(gen_opc_buf, gen_opparam_buf);
2567
            fprintf(logfile, "\n");
2568
        }
2569
    }
2570
#endif
2571
    if (search_pc) {
2572
        j = gen_opc_ptr - gen_opc_buf;
2573
        lj++;
2574
        while (lj <= j)
2575
            gen_opc_instr_start[lj++] = 0;
2576
        tb->size = 0;
2577
    } else {
2578
        tb->size = dc->pc - pc_start;
2579
    }
2580
    return 0;
2581
}
2582

    
2583
int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
2584
{
2585
    return gen_intermediate_code_internal(env, tb, 0);
2586
}
2587

    
2588
int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
2589
{
2590
    return gen_intermediate_code_internal(env, tb, 1);
2591
}
2592

    
2593
static const char *cpu_mode_names[16] = {
2594
  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
2595
  "???", "???", "???", "und", "???", "???", "???", "sys"
2596
};
2597
void cpu_dump_state(CPUState *env, FILE *f, 
2598
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2599
                    int flags)
2600
{
2601
    int i;
2602
    union {
2603
        uint32_t i;
2604
        float s;
2605
    } s0, s1;
2606
    CPU_DoubleU d;
2607
    /* ??? This assumes float64 and double have the same layout.
2608
       Oh well, it's only debug dumps.  */
2609
    union {
2610
        float64 f64;
2611
        double d;
2612
    } d0;
2613
    uint32_t psr;
2614

    
2615
    for(i=0;i<16;i++) {
2616
        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
2617
        if ((i % 4) == 3)
2618
            cpu_fprintf(f, "\n");
2619
        else
2620
            cpu_fprintf(f, " ");
2621
    }
2622
    psr = cpsr_read(env);
2623
    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
2624
                psr,
2625
                psr & (1 << 31) ? 'N' : '-',
2626
                psr & (1 << 30) ? 'Z' : '-',
2627
                psr & (1 << 29) ? 'C' : '-',
2628
                psr & (1 << 28) ? 'V' : '-',
2629
                psr & CPSR_T ? 'T' : 'A', 
2630
                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
2631

    
2632
    for (i = 0; i < 16; i++) {
2633
        d.d = env->vfp.regs[i];
2634
        s0.i = d.l.lower;
2635
        s1.i = d.l.upper;
2636
        d0.f64 = d.d;
2637
        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
2638
                    i * 2, (int)s0.i, s0.s,
2639
                    i * 2 + 1, (int)s1.i, s1.s,
2640
                    i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
2641
                    d0.d);
2642
    }
2643
    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
2644
}
2645