]> git.proxmox.com Git - qemu.git/blame - target-arm/translate.c
Implement iwMMXt instruction set for the PXA270 cpu.
[qemu.git] / target-arm / translate.c
CommitLineData
2c0262af
FB
1/*
2 * ARM translation
3 *
4 * Copyright (c) 2003 Fabrice Bellard
b7bcbe95 5 * Copyright (c) 2005 CodeSourcery, LLC
18c9b560 6 * Copyright (c) 2007 OpenedHand, Ltd.
2c0262af
FB
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22#include <stdarg.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <inttypes.h>
27
28#include "cpu.h"
29#include "exec-all.h"
30#include "disas.h"
31
b5ff1b31
FB
32#define ENABLE_ARCH_5J 0
33#define ENABLE_ARCH_6 1
34#define ENABLE_ARCH_6T2 1
35
36#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op;
37
2c0262af
FB
38/* internal defines */
39typedef struct DisasContext {
0fa85d43 40 target_ulong pc;
2c0262af 41 int is_jmp;
e50e6a20
FB
42 /* Nonzero if this instruction has been conditionally skipped. */
43 int condjmp;
44 /* The label that will be jumped to when the instruction is skipped. */
45 int condlabel;
2c0262af 46 struct TranslationBlock *tb;
8aaca4c0 47 int singlestep_enabled;
5899f386 48 int thumb;
6658ffb8 49 int is_mem;
b5ff1b31
FB
50#if !defined(CONFIG_USER_ONLY)
51 int user;
52#endif
2c0262af
FB
53} DisasContext;
54
b5ff1b31
FB
55#if defined(CONFIG_USER_ONLY)
56#define IS_USER(s) 1
57#else
58#define IS_USER(s) (s->user)
59#endif
60
2c0262af
FB
61#define DISAS_JUMP_NEXT 4
62
c53be334
FB
63#ifdef USE_DIRECT_JUMP
64#define TBPARAM(x)
65#else
66#define TBPARAM(x) (long)(x)
67#endif
68
2c0262af
FB
69/* XXX: move that elsewhere */
70static uint16_t *gen_opc_ptr;
71static uint32_t *gen_opparam_ptr;
72extern FILE *logfile;
73extern int loglevel;
74
75enum {
76#define DEF(s, n, copy_size) INDEX_op_ ## s,
77#include "opc.h"
78#undef DEF
79 NB_OPS,
80};
81
82#include "gen-op.h"
83
e50e6a20 84static GenOpFunc1 *gen_test_cc[14] = {
2c0262af
FB
85 gen_op_test_eq,
86 gen_op_test_ne,
87 gen_op_test_cs,
88 gen_op_test_cc,
89 gen_op_test_mi,
90 gen_op_test_pl,
91 gen_op_test_vs,
92 gen_op_test_vc,
93 gen_op_test_hi,
94 gen_op_test_ls,
95 gen_op_test_ge,
96 gen_op_test_lt,
97 gen_op_test_gt,
98 gen_op_test_le,
99};
100
101const uint8_t table_logic_cc[16] = {
102 1, /* and */
103 1, /* xor */
104 0, /* sub */
105 0, /* rsb */
106 0, /* add */
107 0, /* adc */
108 0, /* sbc */
109 0, /* rsc */
110 1, /* andl */
111 1, /* xorl */
112 0, /* cmp */
113 0, /* cmn */
114 1, /* orr */
115 1, /* mov */
116 1, /* bic */
117 1, /* mvn */
118};
119
120static GenOpFunc1 *gen_shift_T1_im[4] = {
121 gen_op_shll_T1_im,
122 gen_op_shrl_T1_im,
123 gen_op_sarl_T1_im,
124 gen_op_rorl_T1_im,
125};
126
1e8d4eec
FB
127static GenOpFunc *gen_shift_T1_0[4] = {
128 NULL,
129 gen_op_shrl_T1_0,
130 gen_op_sarl_T1_0,
131 gen_op_rrxl_T1,
132};
133
2c0262af
FB
134static GenOpFunc1 *gen_shift_T2_im[4] = {
135 gen_op_shll_T2_im,
136 gen_op_shrl_T2_im,
137 gen_op_sarl_T2_im,
138 gen_op_rorl_T2_im,
139};
140
1e8d4eec
FB
141static GenOpFunc *gen_shift_T2_0[4] = {
142 NULL,
143 gen_op_shrl_T2_0,
144 gen_op_sarl_T2_0,
145 gen_op_rrxl_T2,
146};
147
2c0262af
FB
148static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
149 gen_op_shll_T1_im_cc,
150 gen_op_shrl_T1_im_cc,
151 gen_op_sarl_T1_im_cc,
152 gen_op_rorl_T1_im_cc,
153};
154
1e8d4eec
FB
155static GenOpFunc *gen_shift_T1_0_cc[4] = {
156 NULL,
157 gen_op_shrl_T1_0_cc,
158 gen_op_sarl_T1_0_cc,
159 gen_op_rrxl_T1_cc,
160};
161
2c0262af
FB
162static GenOpFunc *gen_shift_T1_T0[4] = {
163 gen_op_shll_T1_T0,
164 gen_op_shrl_T1_T0,
165 gen_op_sarl_T1_T0,
166 gen_op_rorl_T1_T0,
167};
168
169static GenOpFunc *gen_shift_T1_T0_cc[4] = {
170 gen_op_shll_T1_T0_cc,
171 gen_op_shrl_T1_T0_cc,
172 gen_op_sarl_T1_T0_cc,
173 gen_op_rorl_T1_T0_cc,
174};
175
176static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
177 {
178 gen_op_movl_T0_r0,
179 gen_op_movl_T0_r1,
180 gen_op_movl_T0_r2,
181 gen_op_movl_T0_r3,
182 gen_op_movl_T0_r4,
183 gen_op_movl_T0_r5,
184 gen_op_movl_T0_r6,
185 gen_op_movl_T0_r7,
186 gen_op_movl_T0_r8,
187 gen_op_movl_T0_r9,
188 gen_op_movl_T0_r10,
189 gen_op_movl_T0_r11,
190 gen_op_movl_T0_r12,
191 gen_op_movl_T0_r13,
192 gen_op_movl_T0_r14,
193 gen_op_movl_T0_r15,
194 },
195 {
196 gen_op_movl_T1_r0,
197 gen_op_movl_T1_r1,
198 gen_op_movl_T1_r2,
199 gen_op_movl_T1_r3,
200 gen_op_movl_T1_r4,
201 gen_op_movl_T1_r5,
202 gen_op_movl_T1_r6,
203 gen_op_movl_T1_r7,
204 gen_op_movl_T1_r8,
205 gen_op_movl_T1_r9,
206 gen_op_movl_T1_r10,
207 gen_op_movl_T1_r11,
208 gen_op_movl_T1_r12,
209 gen_op_movl_T1_r13,
210 gen_op_movl_T1_r14,
211 gen_op_movl_T1_r15,
212 },
213 {
214 gen_op_movl_T2_r0,
215 gen_op_movl_T2_r1,
216 gen_op_movl_T2_r2,
217 gen_op_movl_T2_r3,
218 gen_op_movl_T2_r4,
219 gen_op_movl_T2_r5,
220 gen_op_movl_T2_r6,
221 gen_op_movl_T2_r7,
222 gen_op_movl_T2_r8,
223 gen_op_movl_T2_r9,
224 gen_op_movl_T2_r10,
225 gen_op_movl_T2_r11,
226 gen_op_movl_T2_r12,
227 gen_op_movl_T2_r13,
228 gen_op_movl_T2_r14,
229 gen_op_movl_T2_r15,
230 },
231};
232
233static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
234 {
235 gen_op_movl_r0_T0,
236 gen_op_movl_r1_T0,
237 gen_op_movl_r2_T0,
238 gen_op_movl_r3_T0,
239 gen_op_movl_r4_T0,
240 gen_op_movl_r5_T0,
241 gen_op_movl_r6_T0,
242 gen_op_movl_r7_T0,
243 gen_op_movl_r8_T0,
244 gen_op_movl_r9_T0,
245 gen_op_movl_r10_T0,
246 gen_op_movl_r11_T0,
247 gen_op_movl_r12_T0,
248 gen_op_movl_r13_T0,
249 gen_op_movl_r14_T0,
250 gen_op_movl_r15_T0,
251 },
252 {
253 gen_op_movl_r0_T1,
254 gen_op_movl_r1_T1,
255 gen_op_movl_r2_T1,
256 gen_op_movl_r3_T1,
257 gen_op_movl_r4_T1,
258 gen_op_movl_r5_T1,
259 gen_op_movl_r6_T1,
260 gen_op_movl_r7_T1,
261 gen_op_movl_r8_T1,
262 gen_op_movl_r9_T1,
263 gen_op_movl_r10_T1,
264 gen_op_movl_r11_T1,
265 gen_op_movl_r12_T1,
266 gen_op_movl_r13_T1,
267 gen_op_movl_r14_T1,
268 gen_op_movl_r15_T1,
269 },
270};
271
272static GenOpFunc1 *gen_op_movl_TN_im[3] = {
273 gen_op_movl_T0_im,
274 gen_op_movl_T1_im,
275 gen_op_movl_T2_im,
276};
277
99c475ab
FB
278static GenOpFunc1 *gen_shift_T0_im_thumb[3] = {
279 gen_op_shll_T0_im_thumb,
280 gen_op_shrl_T0_im_thumb,
281 gen_op_sarl_T0_im_thumb,
282};
283
284static inline void gen_bx(DisasContext *s)
285{
286 s->is_jmp = DISAS_UPDATE;
287 gen_op_bx_T0();
288}
289
b5ff1b31
FB
290
291#if defined(CONFIG_USER_ONLY)
292#define gen_ldst(name, s) gen_op_##name##_raw()
293#else
294#define gen_ldst(name, s) do { \
6658ffb8 295 s->is_mem = 1; \
b5ff1b31
FB
296 if (IS_USER(s)) \
297 gen_op_##name##_user(); \
298 else \
299 gen_op_##name##_kernel(); \
300 } while (0)
301#endif
302
2c0262af
FB
303static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
304{
305 int val;
306
307 if (reg == 15) {
5899f386
FB
308 /* normaly, since we updated PC, we need only to add one insn */
309 if (s->thumb)
310 val = (long)s->pc + 2;
311 else
312 val = (long)s->pc + 4;
2c0262af
FB
313 gen_op_movl_TN_im[t](val);
314 } else {
315 gen_op_movl_TN_reg[t][reg]();
316 }
317}
318
319static inline void gen_movl_T0_reg(DisasContext *s, int reg)
320{
321 gen_movl_TN_reg(s, reg, 0);
322}
323
324static inline void gen_movl_T1_reg(DisasContext *s, int reg)
325{
326 gen_movl_TN_reg(s, reg, 1);
327}
328
329static inline void gen_movl_T2_reg(DisasContext *s, int reg)
330{
331 gen_movl_TN_reg(s, reg, 2);
332}
333
334static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
335{
336 gen_op_movl_reg_TN[t][reg]();
337 if (reg == 15) {
338 s->is_jmp = DISAS_JUMP;
339 }
340}
341
342static inline void gen_movl_reg_T0(DisasContext *s, int reg)
343{
344 gen_movl_reg_TN(s, reg, 0);
345}
346
347static inline void gen_movl_reg_T1(DisasContext *s, int reg)
348{
349 gen_movl_reg_TN(s, reg, 1);
350}
351
b5ff1b31
FB
352/* Force a TB lookup after an instruction that changes the CPU state. */
353static inline void gen_lookup_tb(DisasContext *s)
354{
355 gen_op_movl_T0_im(s->pc);
356 gen_movl_reg_T0(s, 15);
357 s->is_jmp = DISAS_UPDATE;
358}
359
2c0262af
FB
360static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
361{
1e8d4eec 362 int val, rm, shift, shiftop;
2c0262af
FB
363
364 if (!(insn & (1 << 25))) {
365 /* immediate */
366 val = insn & 0xfff;
367 if (!(insn & (1 << 23)))
368 val = -val;
537730b9
FB
369 if (val != 0)
370 gen_op_addl_T1_im(val);
2c0262af
FB
371 } else {
372 /* shift/register */
373 rm = (insn) & 0xf;
374 shift = (insn >> 7) & 0x1f;
375 gen_movl_T2_reg(s, rm);
1e8d4eec 376 shiftop = (insn >> 5) & 3;
2c0262af 377 if (shift != 0) {
1e8d4eec
FB
378 gen_shift_T2_im[shiftop](shift);
379 } else if (shiftop != 0) {
380 gen_shift_T2_0[shiftop]();
2c0262af
FB
381 }
382 if (!(insn & (1 << 23)))
383 gen_op_subl_T1_T2();
384 else
385 gen_op_addl_T1_T2();
386 }
387}
388
191f9a93
PB
389static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
390 int extra)
2c0262af
FB
391{
392 int val, rm;
393
394 if (insn & (1 << 22)) {
395 /* immediate */
396 val = (insn & 0xf) | ((insn >> 4) & 0xf0);
397 if (!(insn & (1 << 23)))
398 val = -val;
18acad92 399 val += extra;
537730b9
FB
400 if (val != 0)
401 gen_op_addl_T1_im(val);
2c0262af
FB
402 } else {
403 /* register */
191f9a93
PB
404 if (extra)
405 gen_op_addl_T1_im(extra);
2c0262af
FB
406 rm = (insn) & 0xf;
407 gen_movl_T2_reg(s, rm);
408 if (!(insn & (1 << 23)))
409 gen_op_subl_T1_T2();
410 else
411 gen_op_addl_T1_T2();
412 }
413}
414
b7bcbe95
FB
415#define VFP_OP(name) \
416static inline void gen_vfp_##name(int dp) \
417{ \
418 if (dp) \
419 gen_op_vfp_##name##d(); \
420 else \
421 gen_op_vfp_##name##s(); \
422}
423
424VFP_OP(add)
425VFP_OP(sub)
426VFP_OP(mul)
427VFP_OP(div)
428VFP_OP(neg)
429VFP_OP(abs)
430VFP_OP(sqrt)
431VFP_OP(cmp)
432VFP_OP(cmpe)
433VFP_OP(F1_ld0)
434VFP_OP(uito)
435VFP_OP(sito)
436VFP_OP(toui)
437VFP_OP(touiz)
438VFP_OP(tosi)
439VFP_OP(tosiz)
b7bcbe95
FB
440
441#undef VFP_OP
442
b5ff1b31
FB
443static inline void gen_vfp_ld(DisasContext *s, int dp)
444{
445 if (dp)
446 gen_ldst(vfp_ldd, s);
447 else
448 gen_ldst(vfp_lds, s);
449}
450
451static inline void gen_vfp_st(DisasContext *s, int dp)
452{
453 if (dp)
454 gen_ldst(vfp_std, s);
455 else
456 gen_ldst(vfp_sts, s);
457}
458
8e96005d
FB
459static inline long
460vfp_reg_offset (int dp, int reg)
461{
462 if (dp)
463 return offsetof(CPUARMState, vfp.regs[reg]);
464 else if (reg & 1) {
465 return offsetof(CPUARMState, vfp.regs[reg >> 1])
466 + offsetof(CPU_DoubleU, l.upper);
467 } else {
468 return offsetof(CPUARMState, vfp.regs[reg >> 1])
469 + offsetof(CPU_DoubleU, l.lower);
470 }
471}
b7bcbe95
FB
472static inline void gen_mov_F0_vreg(int dp, int reg)
473{
474 if (dp)
8e96005d 475 gen_op_vfp_getreg_F0d(vfp_reg_offset(dp, reg));
b7bcbe95 476 else
8e96005d 477 gen_op_vfp_getreg_F0s(vfp_reg_offset(dp, reg));
b7bcbe95
FB
478}
479
480static inline void gen_mov_F1_vreg(int dp, int reg)
481{
482 if (dp)
8e96005d 483 gen_op_vfp_getreg_F1d(vfp_reg_offset(dp, reg));
b7bcbe95 484 else
8e96005d 485 gen_op_vfp_getreg_F1s(vfp_reg_offset(dp, reg));
b7bcbe95
FB
486}
487
488static inline void gen_mov_vreg_F0(int dp, int reg)
489{
490 if (dp)
8e96005d 491 gen_op_vfp_setreg_F0d(vfp_reg_offset(dp, reg));
b7bcbe95 492 else
8e96005d 493 gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
b7bcbe95
FB
494}
495
18c9b560
AZ
496#define ARM_CP_RW_BIT (1 << 20)
497
498static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn)
499{
500 int rd;
501 uint32_t offset;
502
503 rd = (insn >> 16) & 0xf;
504 gen_movl_T1_reg(s, rd);
505
506 offset = (insn & 0xff) << ((insn >> 7) & 2);
507 if (insn & (1 << 24)) {
508 /* Pre indexed */
509 if (insn & (1 << 23))
510 gen_op_addl_T1_im(offset);
511 else
512 gen_op_addl_T1_im(-offset);
513
514 if (insn & (1 << 21))
515 gen_movl_reg_T1(s, rd);
516 } else if (insn & (1 << 21)) {
517 /* Post indexed */
518 if (insn & (1 << 23))
519 gen_op_movl_T0_im(offset);
520 else
521 gen_op_movl_T0_im(- offset);
522 gen_op_addl_T0_T1();
523 gen_movl_reg_T0(s, rd);
524 } else if (!(insn & (1 << 23)))
525 return 1;
526 return 0;
527}
528
529static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask)
530{
531 int rd = (insn >> 0) & 0xf;
532
533 if (insn & (1 << 8))
534 if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3)
535 return 1;
536 else
537 gen_op_iwmmxt_movl_T0_wCx(rd);
538 else
539 gen_op_iwmmxt_movl_T0_T1_wRn(rd);
540
541 gen_op_movl_T1_im(mask);
542 gen_op_andl_T0_T1();
543 return 0;
544}
545
546/* Disassemble an iwMMXt instruction. Returns nonzero if an error occured
547 (ie. an undefined instruction). */
548static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
549{
550 int rd, wrd;
551 int rdhi, rdlo, rd0, rd1, i;
552
553 if ((insn & 0x0e000e00) == 0x0c000000) {
554 if ((insn & 0x0fe00ff0) == 0x0c400000) {
555 wrd = insn & 0xf;
556 rdlo = (insn >> 12) & 0xf;
557 rdhi = (insn >> 16) & 0xf;
558 if (insn & ARM_CP_RW_BIT) { /* TMRRC */
559 gen_op_iwmmxt_movl_T0_T1_wRn(wrd);
560 gen_movl_reg_T0(s, rdlo);
561 gen_movl_reg_T1(s, rdhi);
562 } else { /* TMCRR */
563 gen_movl_T0_reg(s, rdlo);
564 gen_movl_T1_reg(s, rdhi);
565 gen_op_iwmmxt_movl_wRn_T0_T1(wrd);
566 gen_op_iwmmxt_set_mup();
567 }
568 return 0;
569 }
570
571 wrd = (insn >> 12) & 0xf;
572 if (gen_iwmmxt_address(s, insn))
573 return 1;
574 if (insn & ARM_CP_RW_BIT) {
575 if ((insn >> 28) == 0xf) { /* WLDRW wCx */
576 gen_ldst(ldl, s);
577 gen_op_iwmmxt_movl_wCx_T0(wrd);
578 } else {
579 if (insn & (1 << 8))
580 if (insn & (1 << 22)) /* WLDRD */
581 gen_ldst(iwmmxt_ldq, s);
582 else /* WLDRW wRd */
583 gen_ldst(iwmmxt_ldl, s);
584 else
585 if (insn & (1 << 22)) /* WLDRH */
586 gen_ldst(iwmmxt_ldw, s);
587 else /* WLDRB */
588 gen_ldst(iwmmxt_ldb, s);
589 gen_op_iwmmxt_movq_wRn_M0(wrd);
590 }
591 } else {
592 if ((insn >> 28) == 0xf) { /* WSTRW wCx */
593 gen_op_iwmmxt_movl_T0_wCx(wrd);
594 gen_ldst(stl, s);
595 } else {
596 gen_op_iwmmxt_movq_M0_wRn(wrd);
597 if (insn & (1 << 8))
598 if (insn & (1 << 22)) /* WSTRD */
599 gen_ldst(iwmmxt_stq, s);
600 else /* WSTRW wRd */
601 gen_ldst(iwmmxt_stl, s);
602 else
603 if (insn & (1 << 22)) /* WSTRH */
604 gen_ldst(iwmmxt_ldw, s);
605 else /* WSTRB */
606 gen_ldst(iwmmxt_stb, s);
607 }
608 }
609 return 0;
610 }
611
612 if ((insn & 0x0f000000) != 0x0e000000)
613 return 1;
614
615 switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
616 case 0x000: /* WOR */
617 wrd = (insn >> 12) & 0xf;
618 rd0 = (insn >> 0) & 0xf;
619 rd1 = (insn >> 16) & 0xf;
620 gen_op_iwmmxt_movq_M0_wRn(rd0);
621 gen_op_iwmmxt_orq_M0_wRn(rd1);
622 gen_op_iwmmxt_setpsr_nz();
623 gen_op_iwmmxt_movq_wRn_M0(wrd);
624 gen_op_iwmmxt_set_mup();
625 gen_op_iwmmxt_set_cup();
626 break;
627 case 0x011: /* TMCR */
628 if (insn & 0xf)
629 return 1;
630 rd = (insn >> 12) & 0xf;
631 wrd = (insn >> 16) & 0xf;
632 switch (wrd) {
633 case ARM_IWMMXT_wCID:
634 case ARM_IWMMXT_wCASF:
635 break;
636 case ARM_IWMMXT_wCon:
637 gen_op_iwmmxt_set_cup();
638 /* Fall through. */
639 case ARM_IWMMXT_wCSSF:
640 gen_op_iwmmxt_movl_T0_wCx(wrd);
641 gen_movl_T1_reg(s, rd);
642 gen_op_bicl_T0_T1();
643 gen_op_iwmmxt_movl_wCx_T0(wrd);
644 break;
645 case ARM_IWMMXT_wCGR0:
646 case ARM_IWMMXT_wCGR1:
647 case ARM_IWMMXT_wCGR2:
648 case ARM_IWMMXT_wCGR3:
649 gen_op_iwmmxt_set_cup();
650 gen_movl_reg_T0(s, rd);
651 gen_op_iwmmxt_movl_wCx_T0(wrd);
652 break;
653 default:
654 return 1;
655 }
656 break;
657 case 0x100: /* WXOR */
658 wrd = (insn >> 12) & 0xf;
659 rd0 = (insn >> 0) & 0xf;
660 rd1 = (insn >> 16) & 0xf;
661 gen_op_iwmmxt_movq_M0_wRn(rd0);
662 gen_op_iwmmxt_xorq_M0_wRn(rd1);
663 gen_op_iwmmxt_setpsr_nz();
664 gen_op_iwmmxt_movq_wRn_M0(wrd);
665 gen_op_iwmmxt_set_mup();
666 gen_op_iwmmxt_set_cup();
667 break;
668 case 0x111: /* TMRC */
669 if (insn & 0xf)
670 return 1;
671 rd = (insn >> 12) & 0xf;
672 wrd = (insn >> 16) & 0xf;
673 gen_op_iwmmxt_movl_T0_wCx(wrd);
674 gen_movl_reg_T0(s, rd);
675 break;
676 case 0x300: /* WANDN */
677 wrd = (insn >> 12) & 0xf;
678 rd0 = (insn >> 0) & 0xf;
679 rd1 = (insn >> 16) & 0xf;
680 gen_op_iwmmxt_movq_M0_wRn(rd0);
681 gen_op_iwmmxt_negq_M0();
682 gen_op_iwmmxt_andq_M0_wRn(rd1);
683 gen_op_iwmmxt_setpsr_nz();
684 gen_op_iwmmxt_movq_wRn_M0(wrd);
685 gen_op_iwmmxt_set_mup();
686 gen_op_iwmmxt_set_cup();
687 break;
688 case 0x200: /* WAND */
689 wrd = (insn >> 12) & 0xf;
690 rd0 = (insn >> 0) & 0xf;
691 rd1 = (insn >> 16) & 0xf;
692 gen_op_iwmmxt_movq_M0_wRn(rd0);
693 gen_op_iwmmxt_andq_M0_wRn(rd1);
694 gen_op_iwmmxt_setpsr_nz();
695 gen_op_iwmmxt_movq_wRn_M0(wrd);
696 gen_op_iwmmxt_set_mup();
697 gen_op_iwmmxt_set_cup();
698 break;
699 case 0x810: case 0xa10: /* WMADD */
700 wrd = (insn >> 12) & 0xf;
701 rd0 = (insn >> 0) & 0xf;
702 rd1 = (insn >> 16) & 0xf;
703 gen_op_iwmmxt_movq_M0_wRn(rd0);
704 if (insn & (1 << 21))
705 gen_op_iwmmxt_maddsq_M0_wRn(rd1);
706 else
707 gen_op_iwmmxt_madduq_M0_wRn(rd1);
708 gen_op_iwmmxt_movq_wRn_M0(wrd);
709 gen_op_iwmmxt_set_mup();
710 break;
711 case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */
712 wrd = (insn >> 12) & 0xf;
713 rd0 = (insn >> 16) & 0xf;
714 rd1 = (insn >> 0) & 0xf;
715 gen_op_iwmmxt_movq_M0_wRn(rd0);
716 switch ((insn >> 22) & 3) {
717 case 0:
718 gen_op_iwmmxt_unpacklb_M0_wRn(rd1);
719 break;
720 case 1:
721 gen_op_iwmmxt_unpacklw_M0_wRn(rd1);
722 break;
723 case 2:
724 gen_op_iwmmxt_unpackll_M0_wRn(rd1);
725 break;
726 case 3:
727 return 1;
728 }
729 gen_op_iwmmxt_movq_wRn_M0(wrd);
730 gen_op_iwmmxt_set_mup();
731 gen_op_iwmmxt_set_cup();
732 break;
733 case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */
734 wrd = (insn >> 12) & 0xf;
735 rd0 = (insn >> 16) & 0xf;
736 rd1 = (insn >> 0) & 0xf;
737 gen_op_iwmmxt_movq_M0_wRn(rd0);
738 switch ((insn >> 22) & 3) {
739 case 0:
740 gen_op_iwmmxt_unpackhb_M0_wRn(rd1);
741 break;
742 case 1:
743 gen_op_iwmmxt_unpackhw_M0_wRn(rd1);
744 break;
745 case 2:
746 gen_op_iwmmxt_unpackhl_M0_wRn(rd1);
747 break;
748 case 3:
749 return 1;
750 }
751 gen_op_iwmmxt_movq_wRn_M0(wrd);
752 gen_op_iwmmxt_set_mup();
753 gen_op_iwmmxt_set_cup();
754 break;
755 case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */
756 wrd = (insn >> 12) & 0xf;
757 rd0 = (insn >> 16) & 0xf;
758 rd1 = (insn >> 0) & 0xf;
759 gen_op_iwmmxt_movq_M0_wRn(rd0);
760 if (insn & (1 << 22))
761 gen_op_iwmmxt_sadw_M0_wRn(rd1);
762 else
763 gen_op_iwmmxt_sadb_M0_wRn(rd1);
764 if (!(insn & (1 << 20)))
765 gen_op_iwmmxt_addl_M0_wRn(wrd);
766 gen_op_iwmmxt_movq_wRn_M0(wrd);
767 gen_op_iwmmxt_set_mup();
768 break;
769 case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */
770 wrd = (insn >> 12) & 0xf;
771 rd0 = (insn >> 16) & 0xf;
772 rd1 = (insn >> 0) & 0xf;
773 gen_op_iwmmxt_movq_M0_wRn(rd0);
774 if (insn & (1 << 21))
775 gen_op_iwmmxt_mulsw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0);
776 else
777 gen_op_iwmmxt_muluw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0);
778 gen_op_iwmmxt_movq_wRn_M0(wrd);
779 gen_op_iwmmxt_set_mup();
780 break;
781 case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */
782 wrd = (insn >> 12) & 0xf;
783 rd0 = (insn >> 16) & 0xf;
784 rd1 = (insn >> 0) & 0xf;
785 gen_op_iwmmxt_movq_M0_wRn(rd0);
786 if (insn & (1 << 21))
787 gen_op_iwmmxt_macsw_M0_wRn(rd1);
788 else
789 gen_op_iwmmxt_macuw_M0_wRn(rd1);
790 if (!(insn & (1 << 20))) {
791 if (insn & (1 << 21))
792 gen_op_iwmmxt_addsq_M0_wRn(wrd);
793 else
794 gen_op_iwmmxt_adduq_M0_wRn(wrd);
795 }
796 gen_op_iwmmxt_movq_wRn_M0(wrd);
797 gen_op_iwmmxt_set_mup();
798 break;
799 case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */
800 wrd = (insn >> 12) & 0xf;
801 rd0 = (insn >> 16) & 0xf;
802 rd1 = (insn >> 0) & 0xf;
803 gen_op_iwmmxt_movq_M0_wRn(rd0);
804 switch ((insn >> 22) & 3) {
805 case 0:
806 gen_op_iwmmxt_cmpeqb_M0_wRn(rd1);
807 break;
808 case 1:
809 gen_op_iwmmxt_cmpeqw_M0_wRn(rd1);
810 break;
811 case 2:
812 gen_op_iwmmxt_cmpeql_M0_wRn(rd1);
813 break;
814 case 3:
815 return 1;
816 }
817 gen_op_iwmmxt_movq_wRn_M0(wrd);
818 gen_op_iwmmxt_set_mup();
819 gen_op_iwmmxt_set_cup();
820 break;
821 case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */
822 wrd = (insn >> 12) & 0xf;
823 rd0 = (insn >> 16) & 0xf;
824 rd1 = (insn >> 0) & 0xf;
825 gen_op_iwmmxt_movq_M0_wRn(rd0);
826 if (insn & (1 << 22))
827 gen_op_iwmmxt_avgw_M0_wRn(rd1, (insn >> 20) & 1);
828 else
829 gen_op_iwmmxt_avgb_M0_wRn(rd1, (insn >> 20) & 1);
830 gen_op_iwmmxt_movq_wRn_M0(wrd);
831 gen_op_iwmmxt_set_mup();
832 gen_op_iwmmxt_set_cup();
833 break;
834 case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */
835 wrd = (insn >> 12) & 0xf;
836 rd0 = (insn >> 16) & 0xf;
837 rd1 = (insn >> 0) & 0xf;
838 gen_op_iwmmxt_movq_M0_wRn(rd0);
839 gen_op_iwmmxt_movl_T0_wCx(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
840 gen_op_movl_T1_im(7);
841 gen_op_andl_T0_T1();
842 gen_op_iwmmxt_align_M0_T0_wRn(rd1);
843 gen_op_iwmmxt_movq_wRn_M0(wrd);
844 gen_op_iwmmxt_set_mup();
845 break;
846 case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */
847 rd = (insn >> 12) & 0xf;
848 wrd = (insn >> 16) & 0xf;
849 gen_movl_T0_reg(s, rd);
850 gen_op_iwmmxt_movq_M0_wRn(wrd);
851 switch ((insn >> 6) & 3) {
852 case 0:
853 gen_op_movl_T1_im(0xff);
854 gen_op_iwmmxt_insr_M0_T0_T1((insn & 7) << 3);
855 break;
856 case 1:
857 gen_op_movl_T1_im(0xffff);
858 gen_op_iwmmxt_insr_M0_T0_T1((insn & 3) << 4);
859 break;
860 case 2:
861 gen_op_movl_T1_im(0xffffffff);
862 gen_op_iwmmxt_insr_M0_T0_T1((insn & 1) << 5);
863 break;
864 case 3:
865 return 1;
866 }
867 gen_op_iwmmxt_movq_wRn_M0(wrd);
868 gen_op_iwmmxt_set_mup();
869 break;
870 case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */
871 rd = (insn >> 12) & 0xf;
872 wrd = (insn >> 16) & 0xf;
873 if (rd == 15)
874 return 1;
875 gen_op_iwmmxt_movq_M0_wRn(wrd);
876 switch ((insn >> 22) & 3) {
877 case 0:
878 if (insn & 8)
879 gen_op_iwmmxt_extrsb_T0_M0((insn & 7) << 3);
880 else {
881 gen_op_movl_T1_im(0xff);
882 gen_op_iwmmxt_extru_T0_M0_T1((insn & 7) << 3);
883 }
884 break;
885 case 1:
886 if (insn & 8)
887 gen_op_iwmmxt_extrsw_T0_M0((insn & 3) << 4);
888 else {
889 gen_op_movl_T1_im(0xffff);
890 gen_op_iwmmxt_extru_T0_M0_T1((insn & 3) << 4);
891 }
892 break;
893 case 2:
894 gen_op_movl_T1_im(0xffffffff);
895 gen_op_iwmmxt_extru_T0_M0_T1((insn & 1) << 5);
896 break;
897 case 3:
898 return 1;
899 }
900 gen_op_movl_reg_TN[0][rd]();
901 break;
902 case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */
903 if ((insn & 0x000ff008) != 0x0003f000)
904 return 1;
905 gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
906 switch ((insn >> 22) & 3) {
907 case 0:
908 gen_op_shrl_T1_im(((insn & 7) << 2) + 0);
909 break;
910 case 1:
911 gen_op_shrl_T1_im(((insn & 3) << 3) + 4);
912 break;
913 case 2:
914 gen_op_shrl_T1_im(((insn & 1) << 4) + 12);
915 break;
916 case 3:
917 return 1;
918 }
919 gen_op_shll_T1_im(28);
920 gen_op_movl_T0_T1();
921 gen_op_movl_cpsr_T0(0xf0000000);
922 break;
923 case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */
924 rd = (insn >> 12) & 0xf;
925 wrd = (insn >> 16) & 0xf;
926 gen_movl_T0_reg(s, rd);
927 switch ((insn >> 6) & 3) {
928 case 0:
929 gen_op_iwmmxt_bcstb_M0_T0();
930 break;
931 case 1:
932 gen_op_iwmmxt_bcstw_M0_T0();
933 break;
934 case 2:
935 gen_op_iwmmxt_bcstl_M0_T0();
936 break;
937 case 3:
938 return 1;
939 }
940 gen_op_iwmmxt_movq_wRn_M0(wrd);
941 gen_op_iwmmxt_set_mup();
942 break;
943 case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */
944 if ((insn & 0x000ff00f) != 0x0003f000)
945 return 1;
946 gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
947 switch ((insn >> 22) & 3) {
948 case 0:
949 for (i = 0; i < 7; i ++) {
950 gen_op_shll_T1_im(4);
951 gen_op_andl_T0_T1();
952 }
953 break;
954 case 1:
955 for (i = 0; i < 3; i ++) {
956 gen_op_shll_T1_im(8);
957 gen_op_andl_T0_T1();
958 }
959 break;
960 case 2:
961 gen_op_shll_T1_im(16);
962 gen_op_andl_T0_T1();
963 break;
964 case 3:
965 return 1;
966 }
967 gen_op_movl_cpsr_T0(0xf0000000);
968 break;
969 case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */
970 wrd = (insn >> 12) & 0xf;
971 rd0 = (insn >> 16) & 0xf;
972 gen_op_iwmmxt_movq_M0_wRn(rd0);
973 switch ((insn >> 22) & 3) {
974 case 0:
975 gen_op_iwmmxt_addcb_M0();
976 break;
977 case 1:
978 gen_op_iwmmxt_addcw_M0();
979 break;
980 case 2:
981 gen_op_iwmmxt_addcl_M0();
982 break;
983 case 3:
984 return 1;
985 }
986 gen_op_iwmmxt_movq_wRn_M0(wrd);
987 gen_op_iwmmxt_set_mup();
988 break;
989 case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */
990 if ((insn & 0x000ff00f) != 0x0003f000)
991 return 1;
992 gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
993 switch ((insn >> 22) & 3) {
994 case 0:
995 for (i = 0; i < 7; i ++) {
996 gen_op_shll_T1_im(4);
997 gen_op_orl_T0_T1();
998 }
999 break;
1000 case 1:
1001 for (i = 0; i < 3; i ++) {
1002 gen_op_shll_T1_im(8);
1003 gen_op_orl_T0_T1();
1004 }
1005 break;
1006 case 2:
1007 gen_op_shll_T1_im(16);
1008 gen_op_orl_T0_T1();
1009 break;
1010 case 3:
1011 return 1;
1012 }
1013 gen_op_movl_T1_im(0xf0000000);
1014 gen_op_andl_T0_T1();
1015 gen_op_movl_cpsr_T0(0xf0000000);
1016 break;
1017 case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */
1018 rd = (insn >> 12) & 0xf;
1019 rd0 = (insn >> 16) & 0xf;
1020 if ((insn & 0xf) != 0)
1021 return 1;
1022 gen_op_iwmmxt_movq_M0_wRn(rd0);
1023 switch ((insn >> 22) & 3) {
1024 case 0:
1025 gen_op_iwmmxt_msbb_T0_M0();
1026 break;
1027 case 1:
1028 gen_op_iwmmxt_msbw_T0_M0();
1029 break;
1030 case 2:
1031 gen_op_iwmmxt_msbl_T0_M0();
1032 break;
1033 case 3:
1034 return 1;
1035 }
1036 gen_movl_reg_T0(s, rd);
1037 break;
1038 case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */
1039 case 0x906: case 0xb06: case 0xd06: case 0xf06:
1040 wrd = (insn >> 12) & 0xf;
1041 rd0 = (insn >> 16) & 0xf;
1042 rd1 = (insn >> 0) & 0xf;
1043 gen_op_iwmmxt_movq_M0_wRn(rd0);
1044 switch ((insn >> 22) & 3) {
1045 case 0:
1046 if (insn & (1 << 21))
1047 gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1);
1048 else
1049 gen_op_iwmmxt_cmpgtub_M0_wRn(rd1);
1050 break;
1051 case 1:
1052 if (insn & (1 << 21))
1053 gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1);
1054 else
1055 gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1);
1056 break;
1057 case 2:
1058 if (insn & (1 << 21))
1059 gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1);
1060 else
1061 gen_op_iwmmxt_cmpgtul_M0_wRn(rd1);
1062 break;
1063 case 3:
1064 return 1;
1065 }
1066 gen_op_iwmmxt_movq_wRn_M0(wrd);
1067 gen_op_iwmmxt_set_mup();
1068 gen_op_iwmmxt_set_cup();
1069 break;
1070 case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */
1071 case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
1072 wrd = (insn >> 12) & 0xf;
1073 rd0 = (insn >> 16) & 0xf;
1074 gen_op_iwmmxt_movq_M0_wRn(rd0);
1075 switch ((insn >> 22) & 3) {
1076 case 0:
1077 if (insn & (1 << 21))
1078 gen_op_iwmmxt_unpacklsb_M0();
1079 else
1080 gen_op_iwmmxt_unpacklub_M0();
1081 break;
1082 case 1:
1083 if (insn & (1 << 21))
1084 gen_op_iwmmxt_unpacklsw_M0();
1085 else
1086 gen_op_iwmmxt_unpackluw_M0();
1087 break;
1088 case 2:
1089 if (insn & (1 << 21))
1090 gen_op_iwmmxt_unpacklsl_M0();
1091 else
1092 gen_op_iwmmxt_unpacklul_M0();
1093 break;
1094 case 3:
1095 return 1;
1096 }
1097 gen_op_iwmmxt_movq_wRn_M0(wrd);
1098 gen_op_iwmmxt_set_mup();
1099 gen_op_iwmmxt_set_cup();
1100 break;
1101 case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */
1102 case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
1103 wrd = (insn >> 12) & 0xf;
1104 rd0 = (insn >> 16) & 0xf;
1105 gen_op_iwmmxt_movq_M0_wRn(rd0);
1106 switch ((insn >> 22) & 3) {
1107 case 0:
1108 if (insn & (1 << 21))
1109 gen_op_iwmmxt_unpackhsb_M0();
1110 else
1111 gen_op_iwmmxt_unpackhub_M0();
1112 break;
1113 case 1:
1114 if (insn & (1 << 21))
1115 gen_op_iwmmxt_unpackhsw_M0();
1116 else
1117 gen_op_iwmmxt_unpackhuw_M0();
1118 break;
1119 case 2:
1120 if (insn & (1 << 21))
1121 gen_op_iwmmxt_unpackhsl_M0();
1122 else
1123 gen_op_iwmmxt_unpackhul_M0();
1124 break;
1125 case 3:
1126 return 1;
1127 }
1128 gen_op_iwmmxt_movq_wRn_M0(wrd);
1129 gen_op_iwmmxt_set_mup();
1130 gen_op_iwmmxt_set_cup();
1131 break;
1132 case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */
1133 case 0x214: case 0x614: case 0xa14: case 0xe14:
1134 wrd = (insn >> 12) & 0xf;
1135 rd0 = (insn >> 16) & 0xf;
1136 gen_op_iwmmxt_movq_M0_wRn(rd0);
1137 if (gen_iwmmxt_shift(insn, 0xff))
1138 return 1;
1139 switch ((insn >> 22) & 3) {
1140 case 0:
1141 return 1;
1142 case 1:
1143 gen_op_iwmmxt_srlw_M0_T0();
1144 break;
1145 case 2:
1146 gen_op_iwmmxt_srll_M0_T0();
1147 break;
1148 case 3:
1149 gen_op_iwmmxt_srlq_M0_T0();
1150 break;
1151 }
1152 gen_op_iwmmxt_movq_wRn_M0(wrd);
1153 gen_op_iwmmxt_set_mup();
1154 gen_op_iwmmxt_set_cup();
1155 break;
1156 case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */
1157 case 0x014: case 0x414: case 0x814: case 0xc14:
1158 wrd = (insn >> 12) & 0xf;
1159 rd0 = (insn >> 16) & 0xf;
1160 gen_op_iwmmxt_movq_M0_wRn(rd0);
1161 if (gen_iwmmxt_shift(insn, 0xff))
1162 return 1;
1163 switch ((insn >> 22) & 3) {
1164 case 0:
1165 return 1;
1166 case 1:
1167 gen_op_iwmmxt_sraw_M0_T0();
1168 break;
1169 case 2:
1170 gen_op_iwmmxt_sral_M0_T0();
1171 break;
1172 case 3:
1173 gen_op_iwmmxt_sraq_M0_T0();
1174 break;
1175 }
1176 gen_op_iwmmxt_movq_wRn_M0(wrd);
1177 gen_op_iwmmxt_set_mup();
1178 gen_op_iwmmxt_set_cup();
1179 break;
1180 case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */
1181 case 0x114: case 0x514: case 0x914: case 0xd14:
1182 wrd = (insn >> 12) & 0xf;
1183 rd0 = (insn >> 16) & 0xf;
1184 gen_op_iwmmxt_movq_M0_wRn(rd0);
1185 if (gen_iwmmxt_shift(insn, 0xff))
1186 return 1;
1187 switch ((insn >> 22) & 3) {
1188 case 0:
1189 return 1;
1190 case 1:
1191 gen_op_iwmmxt_sllw_M0_T0();
1192 break;
1193 case 2:
1194 gen_op_iwmmxt_slll_M0_T0();
1195 break;
1196 case 3:
1197 gen_op_iwmmxt_sllq_M0_T0();
1198 break;
1199 }
1200 gen_op_iwmmxt_movq_wRn_M0(wrd);
1201 gen_op_iwmmxt_set_mup();
1202 gen_op_iwmmxt_set_cup();
1203 break;
1204 case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */
1205 case 0x314: case 0x714: case 0xb14: case 0xf14:
1206 wrd = (insn >> 12) & 0xf;
1207 rd0 = (insn >> 16) & 0xf;
1208 gen_op_iwmmxt_movq_M0_wRn(rd0);
1209 switch ((insn >> 22) & 3) {
1210 case 0:
1211 return 1;
1212 case 1:
1213 if (gen_iwmmxt_shift(insn, 0xf))
1214 return 1;
1215 gen_op_iwmmxt_rorw_M0_T0();
1216 break;
1217 case 2:
1218 if (gen_iwmmxt_shift(insn, 0x1f))
1219 return 1;
1220 gen_op_iwmmxt_rorl_M0_T0();
1221 break;
1222 case 3:
1223 if (gen_iwmmxt_shift(insn, 0x3f))
1224 return 1;
1225 gen_op_iwmmxt_rorq_M0_T0();
1226 break;
1227 }
1228 gen_op_iwmmxt_movq_wRn_M0(wrd);
1229 gen_op_iwmmxt_set_mup();
1230 gen_op_iwmmxt_set_cup();
1231 break;
1232 case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */
1233 case 0x916: case 0xb16: case 0xd16: case 0xf16:
1234 wrd = (insn >> 12) & 0xf;
1235 rd0 = (insn >> 16) & 0xf;
1236 rd1 = (insn >> 0) & 0xf;
1237 gen_op_iwmmxt_movq_M0_wRn(rd0);
1238 switch ((insn >> 22) & 3) {
1239 case 0:
1240 if (insn & (1 << 21))
1241 gen_op_iwmmxt_minsb_M0_wRn(rd1);
1242 else
1243 gen_op_iwmmxt_minub_M0_wRn(rd1);
1244 break;
1245 case 1:
1246 if (insn & (1 << 21))
1247 gen_op_iwmmxt_minsw_M0_wRn(rd1);
1248 else
1249 gen_op_iwmmxt_minuw_M0_wRn(rd1);
1250 break;
1251 case 2:
1252 if (insn & (1 << 21))
1253 gen_op_iwmmxt_minsl_M0_wRn(rd1);
1254 else
1255 gen_op_iwmmxt_minul_M0_wRn(rd1);
1256 break;
1257 case 3:
1258 return 1;
1259 }
1260 gen_op_iwmmxt_movq_wRn_M0(wrd);
1261 gen_op_iwmmxt_set_mup();
1262 break;
1263 case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */
1264 case 0x816: case 0xa16: case 0xc16: case 0xe16:
1265 wrd = (insn >> 12) & 0xf;
1266 rd0 = (insn >> 16) & 0xf;
1267 rd1 = (insn >> 0) & 0xf;
1268 gen_op_iwmmxt_movq_M0_wRn(rd0);
1269 switch ((insn >> 22) & 3) {
1270 case 0:
1271 if (insn & (1 << 21))
1272 gen_op_iwmmxt_maxsb_M0_wRn(rd1);
1273 else
1274 gen_op_iwmmxt_maxub_M0_wRn(rd1);
1275 break;
1276 case 1:
1277 if (insn & (1 << 21))
1278 gen_op_iwmmxt_maxsw_M0_wRn(rd1);
1279 else
1280 gen_op_iwmmxt_maxuw_M0_wRn(rd1);
1281 break;
1282 case 2:
1283 if (insn & (1 << 21))
1284 gen_op_iwmmxt_maxsl_M0_wRn(rd1);
1285 else
1286 gen_op_iwmmxt_maxul_M0_wRn(rd1);
1287 break;
1288 case 3:
1289 return 1;
1290 }
1291 gen_op_iwmmxt_movq_wRn_M0(wrd);
1292 gen_op_iwmmxt_set_mup();
1293 break;
1294 case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */
1295 case 0x402: case 0x502: case 0x602: case 0x702:
1296 wrd = (insn >> 12) & 0xf;
1297 rd0 = (insn >> 16) & 0xf;
1298 rd1 = (insn >> 0) & 0xf;
1299 gen_op_iwmmxt_movq_M0_wRn(rd0);
1300 gen_op_movl_T0_im((insn >> 20) & 3);
1301 gen_op_iwmmxt_align_M0_T0_wRn(rd1);
1302 gen_op_iwmmxt_movq_wRn_M0(wrd);
1303 gen_op_iwmmxt_set_mup();
1304 break;
1305 case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */
1306 case 0x41a: case 0x51a: case 0x61a: case 0x71a:
1307 case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
1308 case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
1309 wrd = (insn >> 12) & 0xf;
1310 rd0 = (insn >> 16) & 0xf;
1311 rd1 = (insn >> 0) & 0xf;
1312 gen_op_iwmmxt_movq_M0_wRn(rd0);
1313 switch ((insn >> 20) & 0xf) {
1314 case 0x0:
1315 gen_op_iwmmxt_subnb_M0_wRn(rd1);
1316 break;
1317 case 0x1:
1318 gen_op_iwmmxt_subub_M0_wRn(rd1);
1319 break;
1320 case 0x3:
1321 gen_op_iwmmxt_subsb_M0_wRn(rd1);
1322 break;
1323 case 0x4:
1324 gen_op_iwmmxt_subnw_M0_wRn(rd1);
1325 break;
1326 case 0x5:
1327 gen_op_iwmmxt_subuw_M0_wRn(rd1);
1328 break;
1329 case 0x7:
1330 gen_op_iwmmxt_subsw_M0_wRn(rd1);
1331 break;
1332 case 0x8:
1333 gen_op_iwmmxt_subnl_M0_wRn(rd1);
1334 break;
1335 case 0x9:
1336 gen_op_iwmmxt_subul_M0_wRn(rd1);
1337 break;
1338 case 0xb:
1339 gen_op_iwmmxt_subsl_M0_wRn(rd1);
1340 break;
1341 default:
1342 return 1;
1343 }
1344 gen_op_iwmmxt_movq_wRn_M0(wrd);
1345 gen_op_iwmmxt_set_mup();
1346 gen_op_iwmmxt_set_cup();
1347 break;
1348 case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */
1349 case 0x41e: case 0x51e: case 0x61e: case 0x71e:
1350 case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
1351 case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
1352 wrd = (insn >> 12) & 0xf;
1353 rd0 = (insn >> 16) & 0xf;
1354 gen_op_iwmmxt_movq_M0_wRn(rd0);
1355 gen_op_movl_T0_im(((insn >> 16) & 0xf0) | (insn & 0x0f));
1356 gen_op_iwmmxt_shufh_M0_T0();
1357 gen_op_iwmmxt_movq_wRn_M0(wrd);
1358 gen_op_iwmmxt_set_mup();
1359 gen_op_iwmmxt_set_cup();
1360 break;
1361 case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */
1362 case 0x418: case 0x518: case 0x618: case 0x718:
1363 case 0x818: case 0x918: case 0xa18: case 0xb18:
1364 case 0xc18: case 0xd18: case 0xe18: case 0xf18:
1365 wrd = (insn >> 12) & 0xf;
1366 rd0 = (insn >> 16) & 0xf;
1367 rd1 = (insn >> 0) & 0xf;
1368 gen_op_iwmmxt_movq_M0_wRn(rd0);
1369 switch ((insn >> 20) & 0xf) {
1370 case 0x0:
1371 gen_op_iwmmxt_addnb_M0_wRn(rd1);
1372 break;
1373 case 0x1:
1374 gen_op_iwmmxt_addub_M0_wRn(rd1);
1375 break;
1376 case 0x3:
1377 gen_op_iwmmxt_addsb_M0_wRn(rd1);
1378 break;
1379 case 0x4:
1380 gen_op_iwmmxt_addnw_M0_wRn(rd1);
1381 break;
1382 case 0x5:
1383 gen_op_iwmmxt_adduw_M0_wRn(rd1);
1384 break;
1385 case 0x7:
1386 gen_op_iwmmxt_addsw_M0_wRn(rd1);
1387 break;
1388 case 0x8:
1389 gen_op_iwmmxt_addnl_M0_wRn(rd1);
1390 break;
1391 case 0x9:
1392 gen_op_iwmmxt_addul_M0_wRn(rd1);
1393 break;
1394 case 0xb:
1395 gen_op_iwmmxt_addsl_M0_wRn(rd1);
1396 break;
1397 default:
1398 return 1;
1399 }
1400 gen_op_iwmmxt_movq_wRn_M0(wrd);
1401 gen_op_iwmmxt_set_mup();
1402 gen_op_iwmmxt_set_cup();
1403 break;
1404 case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */
1405 case 0x408: case 0x508: case 0x608: case 0x708:
1406 case 0x808: case 0x908: case 0xa08: case 0xb08:
1407 case 0xc08: case 0xd08: case 0xe08: case 0xf08:
1408 wrd = (insn >> 12) & 0xf;
1409 rd0 = (insn >> 16) & 0xf;
1410 rd1 = (insn >> 0) & 0xf;
1411 gen_op_iwmmxt_movq_M0_wRn(rd0);
1412 if (!(insn & (1 << 20)))
1413 return 1;
1414 switch ((insn >> 22) & 3) {
1415 case 0:
1416 return 1;
1417 case 1:
1418 if (insn & (1 << 21))
1419 gen_op_iwmmxt_packsw_M0_wRn(rd1);
1420 else
1421 gen_op_iwmmxt_packuw_M0_wRn(rd1);
1422 break;
1423 case 2:
1424 if (insn & (1 << 21))
1425 gen_op_iwmmxt_packsl_M0_wRn(rd1);
1426 else
1427 gen_op_iwmmxt_packul_M0_wRn(rd1);
1428 break;
1429 case 3:
1430 if (insn & (1 << 21))
1431 gen_op_iwmmxt_packsq_M0_wRn(rd1);
1432 else
1433 gen_op_iwmmxt_packuq_M0_wRn(rd1);
1434 break;
1435 }
1436 gen_op_iwmmxt_movq_wRn_M0(wrd);
1437 gen_op_iwmmxt_set_mup();
1438 gen_op_iwmmxt_set_cup();
1439 break;
1440 case 0x201: case 0x203: case 0x205: case 0x207:
1441 case 0x209: case 0x20b: case 0x20d: case 0x20f:
1442 case 0x211: case 0x213: case 0x215: case 0x217:
1443 case 0x219: case 0x21b: case 0x21d: case 0x21f:
1444 wrd = (insn >> 5) & 0xf;
1445 rd0 = (insn >> 12) & 0xf;
1446 rd1 = (insn >> 0) & 0xf;
1447 if (rd0 == 0xf || rd1 == 0xf)
1448 return 1;
1449 gen_op_iwmmxt_movq_M0_wRn(wrd);
1450 switch ((insn >> 16) & 0xf) {
1451 case 0x0: /* TMIA */
1452 gen_op_movl_TN_reg[0][rd0]();
1453 gen_op_movl_TN_reg[1][rd1]();
1454 gen_op_iwmmxt_muladdsl_M0_T0_T1();
1455 break;
1456 case 0x8: /* TMIAPH */
1457 gen_op_movl_TN_reg[0][rd0]();
1458 gen_op_movl_TN_reg[1][rd1]();
1459 gen_op_iwmmxt_muladdsw_M0_T0_T1();
1460 break;
1461 case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */
1462 gen_op_movl_TN_reg[1][rd0]();
1463 if (insn & (1 << 16))
1464 gen_op_shrl_T1_im(16);
1465 gen_op_movl_T0_T1();
1466 gen_op_movl_TN_reg[1][rd1]();
1467 if (insn & (1 << 17))
1468 gen_op_shrl_T1_im(16);
1469 gen_op_iwmmxt_muladdswl_M0_T0_T1();
1470 break;
1471 default:
1472 return 1;
1473 }
1474 gen_op_iwmmxt_movq_wRn_M0(wrd);
1475 gen_op_iwmmxt_set_mup();
1476 break;
1477 default:
1478 return 1;
1479 }
1480
1481 return 0;
1482}
1483
1484/* Disassemble an XScale DSP instruction. Returns nonzero if an error occured
1485 (ie. an undefined instruction). */
1486static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
1487{
1488 int acc, rd0, rd1, rdhi, rdlo;
1489
1490 if ((insn & 0x0ff00f10) == 0x0e200010) {
1491 /* Multiply with Internal Accumulate Format */
1492 rd0 = (insn >> 12) & 0xf;
1493 rd1 = insn & 0xf;
1494 acc = (insn >> 5) & 7;
1495
1496 if (acc != 0)
1497 return 1;
1498
1499 switch ((insn >> 16) & 0xf) {
1500 case 0x0: /* MIA */
1501 gen_op_movl_TN_reg[0][rd0]();
1502 gen_op_movl_TN_reg[1][rd1]();
1503 gen_op_iwmmxt_muladdsl_M0_T0_T1();
1504 break;
1505 case 0x8: /* MIAPH */
1506 gen_op_movl_TN_reg[0][rd0]();
1507 gen_op_movl_TN_reg[1][rd1]();
1508 gen_op_iwmmxt_muladdsw_M0_T0_T1();
1509 break;
1510 case 0xc: /* MIABB */
1511 case 0xd: /* MIABT */
1512 case 0xe: /* MIATB */
1513 case 0xf: /* MIATT */
1514 gen_op_movl_TN_reg[1][rd0]();
1515 if (insn & (1 << 16))
1516 gen_op_shrl_T1_im(16);
1517 gen_op_movl_T0_T1();
1518 gen_op_movl_TN_reg[1][rd1]();
1519 if (insn & (1 << 17))
1520 gen_op_shrl_T1_im(16);
1521 gen_op_iwmmxt_muladdswl_M0_T0_T1();
1522 break;
1523 default:
1524 return 1;
1525 }
1526
1527 gen_op_iwmmxt_movq_wRn_M0(acc);
1528 return 0;
1529 }
1530
1531 if ((insn & 0x0fe00ff8) == 0x0c400000) {
1532 /* Internal Accumulator Access Format */
1533 rdhi = (insn >> 16) & 0xf;
1534 rdlo = (insn >> 12) & 0xf;
1535 acc = insn & 7;
1536
1537 if (acc != 0)
1538 return 1;
1539
1540 if (insn & ARM_CP_RW_BIT) { /* MRA */
1541 gen_op_iwmmxt_movl_T0_T1_wRn(acc);
1542 gen_op_movl_reg_TN[0][rdlo]();
1543 gen_op_movl_T0_im((1 << (40 - 32)) - 1);
1544 gen_op_andl_T0_T1();
1545 gen_op_movl_reg_TN[0][rdhi]();
1546 } else { /* MAR */
1547 gen_op_movl_TN_reg[0][rdlo]();
1548 gen_op_movl_TN_reg[1][rdhi]();
1549 gen_op_iwmmxt_movl_wRn_T0_T1(acc);
1550 }
1551 return 0;
1552 }
1553
1554 return 1;
1555}
1556
c1713132
AZ
1557/* Disassemble system coprocessor instruction. Return nonzero if
1558 instruction is not defined. */
1559static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
1560{
1561 uint32_t rd = (insn >> 12) & 0xf;
1562 uint32_t cp = (insn >> 8) & 0xf;
1563 if (IS_USER(s)) {
1564 return 1;
1565 }
1566
18c9b560 1567 if (insn & ARM_CP_RW_BIT) {
c1713132
AZ
1568 if (!env->cp[cp].cp_read)
1569 return 1;
1570 gen_op_movl_T0_im((uint32_t) s->pc);
1571 gen_op_movl_reg_TN[0][15]();
1572 gen_op_movl_T0_cp(insn);
1573 gen_movl_reg_T0(s, rd);
1574 } else {
1575 if (!env->cp[cp].cp_write)
1576 return 1;
1577 gen_op_movl_T0_im((uint32_t) s->pc);
1578 gen_op_movl_reg_TN[0][15]();
1579 gen_movl_T0_reg(s, rd);
1580 gen_op_movl_cp_T0(insn);
1581 }
1582 return 0;
1583}
1584
b5ff1b31
FB
1585/* Disassemble system coprocessor (cp15) instruction. Return nonzero if
1586 instruction is not defined. */
1587static int disas_cp15_insn(DisasContext *s, uint32_t insn)
1588{
1589 uint32_t rd;
1590
1591 /* ??? Some cp15 registers are accessible from userspace. */
1592 if (IS_USER(s)) {
1593 return 1;
1594 }
9332f9da
FB
1595 if ((insn & 0x0fff0fff) == 0x0e070f90
1596 || (insn & 0x0fff0fff) == 0x0e070f58) {
1597 /* Wait for interrupt. */
1598 gen_op_movl_T0_im((long)s->pc);
1599 gen_op_movl_reg_TN[0][15]();
1600 gen_op_wfi();
1601 s->is_jmp = DISAS_JUMP;
1602 return 0;
1603 }
b5ff1b31 1604 rd = (insn >> 12) & 0xf;
18c9b560 1605 if (insn & ARM_CP_RW_BIT) {
b5ff1b31
FB
1606 gen_op_movl_T0_cp15(insn);
1607 /* If the destination register is r15 then sets condition codes. */
1608 if (rd != 15)
1609 gen_movl_reg_T0(s, rd);
1610 } else {
1611 gen_movl_T0_reg(s, rd);
1612 gen_op_movl_cp15_T0(insn);
1613 }
1614 gen_lookup_tb(s);
1615 return 0;
1616}
1617
b7bcbe95
FB
1618/* Disassemble a VFP instruction. Returns nonzero if an error occured
1619 (ie. an undefined instruction). */
1620static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
1621{
1622 uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
1623 int dp, veclen;
1624
40f137e1
PB
1625 if (!arm_feature(env, ARM_FEATURE_VFP))
1626 return 1;
1627
1628 if ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) == 0) {
1629 /* VFP disabled. Only allow fmxr/fmrx to/from fpexc and fpsid. */
1630 if ((insn & 0x0fe00fff) != 0x0ee00a10)
1631 return 1;
1632 rn = (insn >> 16) & 0xf;
1633 if (rn != 0 && rn != 8)
1634 return 1;
1635 }
b7bcbe95
FB
1636 dp = ((insn & 0xf00) == 0xb00);
1637 switch ((insn >> 24) & 0xf) {
1638 case 0xe:
1639 if (insn & (1 << 4)) {
1640 /* single register transfer */
1641 if ((insn & 0x6f) != 0x00)
1642 return 1;
1643 rd = (insn >> 12) & 0xf;
1644 if (dp) {
1645 if (insn & 0x80)
1646 return 1;
1647 rn = (insn >> 16) & 0xf;
1648 /* Get the existing value even for arm->vfp moves because
1649 we only set half the register. */
1650 gen_mov_F0_vreg(1, rn);
1651 gen_op_vfp_mrrd();
18c9b560 1652 if (insn & ARM_CP_RW_BIT) {
b7bcbe95
FB
1653 /* vfp->arm */
1654 if (insn & (1 << 21))
1655 gen_movl_reg_T1(s, rd);
1656 else
1657 gen_movl_reg_T0(s, rd);
1658 } else {
1659 /* arm->vfp */
1660 if (insn & (1 << 21))
1661 gen_movl_T1_reg(s, rd);
1662 else
1663 gen_movl_T0_reg(s, rd);
1664 gen_op_vfp_mdrr();
1665 gen_mov_vreg_F0(dp, rn);
1666 }
1667 } else {
1668 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
18c9b560 1669 if (insn & ARM_CP_RW_BIT) {
b7bcbe95
FB
1670 /* vfp->arm */
1671 if (insn & (1 << 21)) {
1672 /* system register */
40f137e1 1673 rn >>= 1;
b7bcbe95 1674 switch (rn) {
40f137e1
PB
1675 case ARM_VFP_FPSID:
1676 case ARM_VFP_FPEXC:
1677 case ARM_VFP_FPINST:
1678 case ARM_VFP_FPINST2:
1679 gen_op_vfp_movl_T0_xreg(rn);
b7bcbe95 1680 break;
40f137e1 1681 case ARM_VFP_FPSCR:
b7bcbe95
FB
1682 if (rd == 15)
1683 gen_op_vfp_movl_T0_fpscr_flags();
1684 else
1685 gen_op_vfp_movl_T0_fpscr();
1686 break;
1687 default:
1688 return 1;
1689 }
1690 } else {
1691 gen_mov_F0_vreg(0, rn);
1692 gen_op_vfp_mrs();
1693 }
1694 if (rd == 15) {
b5ff1b31
FB
1695 /* Set the 4 flag bits in the CPSR. */
1696 gen_op_movl_cpsr_T0(0xf0000000);
b7bcbe95
FB
1697 } else
1698 gen_movl_reg_T0(s, rd);
1699 } else {
1700 /* arm->vfp */
1701 gen_movl_T0_reg(s, rd);
1702 if (insn & (1 << 21)) {
40f137e1 1703 rn >>= 1;
b7bcbe95
FB
1704 /* system register */
1705 switch (rn) {
40f137e1 1706 case ARM_VFP_FPSID:
b7bcbe95
FB
1707 /* Writes are ignored. */
1708 break;
40f137e1 1709 case ARM_VFP_FPSCR:
b7bcbe95 1710 gen_op_vfp_movl_fpscr_T0();
b5ff1b31 1711 gen_lookup_tb(s);
b7bcbe95 1712 break;
40f137e1
PB
1713 case ARM_VFP_FPEXC:
1714 gen_op_vfp_movl_xreg_T0(rn);
1715 gen_lookup_tb(s);
1716 break;
1717 case ARM_VFP_FPINST:
1718 case ARM_VFP_FPINST2:
1719 gen_op_vfp_movl_xreg_T0(rn);
1720 break;
b7bcbe95
FB
1721 default:
1722 return 1;
1723 }
1724 } else {
1725 gen_op_vfp_msr();
1726 gen_mov_vreg_F0(0, rn);
1727 }
1728 }
1729 }
1730 } else {
1731 /* data processing */
1732 /* The opcode is in bits 23, 21, 20 and 6. */
1733 op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
1734 if (dp) {
1735 if (op == 15) {
1736 /* rn is opcode */
1737 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
1738 } else {
1739 /* rn is register number */
1740 if (insn & (1 << 7))
1741 return 1;
1742 rn = (insn >> 16) & 0xf;
1743 }
1744
1745 if (op == 15 && (rn == 15 || rn > 17)) {
1746 /* Integer or single precision destination. */
1747 rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
1748 } else {
1749 if (insn & (1 << 22))
1750 return 1;
1751 rd = (insn >> 12) & 0xf;
1752 }
1753
1754 if (op == 15 && (rn == 16 || rn == 17)) {
1755 /* Integer source. */
1756 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
1757 } else {
1758 if (insn & (1 << 5))
1759 return 1;
1760 rm = insn & 0xf;
1761 }
1762 } else {
1763 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
1764 if (op == 15 && rn == 15) {
1765 /* Double precision destination. */
1766 if (insn & (1 << 22))
1767 return 1;
1768 rd = (insn >> 12) & 0xf;
1769 } else
1770 rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
1771 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
1772 }
1773
1774 veclen = env->vfp.vec_len;
1775 if (op == 15 && rn > 3)
1776 veclen = 0;
1777
1778 /* Shut up compiler warnings. */
1779 delta_m = 0;
1780 delta_d = 0;
1781 bank_mask = 0;
1782
1783 if (veclen > 0) {
1784 if (dp)
1785 bank_mask = 0xc;
1786 else
1787 bank_mask = 0x18;
1788
1789 /* Figure out what type of vector operation this is. */
1790 if ((rd & bank_mask) == 0) {
1791 /* scalar */
1792 veclen = 0;
1793 } else {
1794 if (dp)
1795 delta_d = (env->vfp.vec_stride >> 1) + 1;
1796 else
1797 delta_d = env->vfp.vec_stride + 1;
1798
1799 if ((rm & bank_mask) == 0) {
1800 /* mixed scalar/vector */
1801 delta_m = 0;
1802 } else {
1803 /* vector */
1804 delta_m = delta_d;
1805 }
1806 }
1807 }
1808
1809 /* Load the initial operands. */
1810 if (op == 15) {
1811 switch (rn) {
1812 case 16:
1813 case 17:
1814 /* Integer source */
1815 gen_mov_F0_vreg(0, rm);
1816 break;
1817 case 8:
1818 case 9:
1819 /* Compare */
1820 gen_mov_F0_vreg(dp, rd);
1821 gen_mov_F1_vreg(dp, rm);
1822 break;
1823 case 10:
1824 case 11:
1825 /* Compare with zero */
1826 gen_mov_F0_vreg(dp, rd);
1827 gen_vfp_F1_ld0(dp);
1828 break;
1829 default:
1830 /* One source operand. */
1831 gen_mov_F0_vreg(dp, rm);
1832 }
1833 } else {
1834 /* Two source operands. */
1835 gen_mov_F0_vreg(dp, rn);
1836 gen_mov_F1_vreg(dp, rm);
1837 }
1838
1839 for (;;) {
1840 /* Perform the calculation. */
1841 switch (op) {
1842 case 0: /* mac: fd + (fn * fm) */
1843 gen_vfp_mul(dp);
1844 gen_mov_F1_vreg(dp, rd);
1845 gen_vfp_add(dp);
1846 break;
1847 case 1: /* nmac: fd - (fn * fm) */
1848 gen_vfp_mul(dp);
1849 gen_vfp_neg(dp);
1850 gen_mov_F1_vreg(dp, rd);
1851 gen_vfp_add(dp);
1852 break;
1853 case 2: /* msc: -fd + (fn * fm) */
1854 gen_vfp_mul(dp);
1855 gen_mov_F1_vreg(dp, rd);
1856 gen_vfp_sub(dp);
1857 break;
1858 case 3: /* nmsc: -fd - (fn * fm) */
1859 gen_vfp_mul(dp);
1860 gen_mov_F1_vreg(dp, rd);
1861 gen_vfp_add(dp);
1862 gen_vfp_neg(dp);
1863 break;
1864 case 4: /* mul: fn * fm */
1865 gen_vfp_mul(dp);
1866 break;
1867 case 5: /* nmul: -(fn * fm) */
1868 gen_vfp_mul(dp);
1869 gen_vfp_neg(dp);
1870 break;
1871 case 6: /* add: fn + fm */
1872 gen_vfp_add(dp);
1873 break;
1874 case 7: /* sub: fn - fm */
1875 gen_vfp_sub(dp);
1876 break;
1877 case 8: /* div: fn / fm */
1878 gen_vfp_div(dp);
1879 break;
1880 case 15: /* extension space */
1881 switch (rn) {
1882 case 0: /* cpy */
1883 /* no-op */
1884 break;
1885 case 1: /* abs */
1886 gen_vfp_abs(dp);
1887 break;
1888 case 2: /* neg */
1889 gen_vfp_neg(dp);
1890 break;
1891 case 3: /* sqrt */
1892 gen_vfp_sqrt(dp);
1893 break;
1894 case 8: /* cmp */
1895 gen_vfp_cmp(dp);
1896 break;
1897 case 9: /* cmpe */
1898 gen_vfp_cmpe(dp);
1899 break;
1900 case 10: /* cmpz */
1901 gen_vfp_cmp(dp);
1902 break;
1903 case 11: /* cmpez */
1904 gen_vfp_F1_ld0(dp);
1905 gen_vfp_cmpe(dp);
1906 break;
1907 case 15: /* single<->double conversion */
1908 if (dp)
1909 gen_op_vfp_fcvtsd();
1910 else
1911 gen_op_vfp_fcvtds();
1912 break;
1913 case 16: /* fuito */
1914 gen_vfp_uito(dp);
1915 break;
1916 case 17: /* fsito */
1917 gen_vfp_sito(dp);
1918 break;
1919 case 24: /* ftoui */
1920 gen_vfp_toui(dp);
1921 break;
1922 case 25: /* ftouiz */
1923 gen_vfp_touiz(dp);
1924 break;
1925 case 26: /* ftosi */
1926 gen_vfp_tosi(dp);
1927 break;
1928 case 27: /* ftosiz */
1929 gen_vfp_tosiz(dp);
1930 break;
1931 default: /* undefined */
1932 printf ("rn:%d\n", rn);
1933 return 1;
1934 }
1935 break;
1936 default: /* undefined */
1937 printf ("op:%d\n", op);
1938 return 1;
1939 }
1940
1941 /* Write back the result. */
1942 if (op == 15 && (rn >= 8 && rn <= 11))
1943 ; /* Comparison, do nothing. */
1944 else if (op == 15 && rn > 17)
1945 /* Integer result. */
1946 gen_mov_vreg_F0(0, rd);
1947 else if (op == 15 && rn == 15)
1948 /* conversion */
1949 gen_mov_vreg_F0(!dp, rd);
1950 else
1951 gen_mov_vreg_F0(dp, rd);
1952
1953 /* break out of the loop if we have finished */
1954 if (veclen == 0)
1955 break;
1956
1957 if (op == 15 && delta_m == 0) {
1958 /* single source one-many */
1959 while (veclen--) {
1960 rd = ((rd + delta_d) & (bank_mask - 1))
1961 | (rd & bank_mask);
1962 gen_mov_vreg_F0(dp, rd);
1963 }
1964 break;
1965 }
1966 /* Setup the next operands. */
1967 veclen--;
1968 rd = ((rd + delta_d) & (bank_mask - 1))
1969 | (rd & bank_mask);
1970
1971 if (op == 15) {
1972 /* One source operand. */
1973 rm = ((rm + delta_m) & (bank_mask - 1))
1974 | (rm & bank_mask);
1975 gen_mov_F0_vreg(dp, rm);
1976 } else {
1977 /* Two source operands. */
1978 rn = ((rn + delta_d) & (bank_mask - 1))
1979 | (rn & bank_mask);
1980 gen_mov_F0_vreg(dp, rn);
1981 if (delta_m) {
1982 rm = ((rm + delta_m) & (bank_mask - 1))
1983 | (rm & bank_mask);
1984 gen_mov_F1_vreg(dp, rm);
1985 }
1986 }
1987 }
1988 }
1989 break;
1990 case 0xc:
1991 case 0xd:
1992 if (dp && (insn & (1 << 22))) {
1993 /* two-register transfer */
1994 rn = (insn >> 16) & 0xf;
1995 rd = (insn >> 12) & 0xf;
1996 if (dp) {
1997 if (insn & (1 << 5))
1998 return 1;
1999 rm = insn & 0xf;
2000 } else
2001 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
2002
18c9b560 2003 if (insn & ARM_CP_RW_BIT) {
b7bcbe95
FB
2004 /* vfp->arm */
2005 if (dp) {
2006 gen_mov_F0_vreg(1, rm);
2007 gen_op_vfp_mrrd();
2008 gen_movl_reg_T0(s, rd);
2009 gen_movl_reg_T1(s, rn);
2010 } else {
2011 gen_mov_F0_vreg(0, rm);
2012 gen_op_vfp_mrs();
2013 gen_movl_reg_T0(s, rn);
2014 gen_mov_F0_vreg(0, rm + 1);
2015 gen_op_vfp_mrs();
2016 gen_movl_reg_T0(s, rd);
2017 }
2018 } else {
2019 /* arm->vfp */
2020 if (dp) {
2021 gen_movl_T0_reg(s, rd);
2022 gen_movl_T1_reg(s, rn);
2023 gen_op_vfp_mdrr();
2024 gen_mov_vreg_F0(1, rm);
2025 } else {
2026 gen_movl_T0_reg(s, rn);
2027 gen_op_vfp_msr();
2028 gen_mov_vreg_F0(0, rm);
2029 gen_movl_T0_reg(s, rd);
2030 gen_op_vfp_msr();
2031 gen_mov_vreg_F0(0, rm + 1);
2032 }
2033 }
2034 } else {
2035 /* Load/store */
2036 rn = (insn >> 16) & 0xf;
2037 if (dp)
2038 rd = (insn >> 12) & 0xf;
2039 else
2040 rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
2041 gen_movl_T1_reg(s, rn);
2042 if ((insn & 0x01200000) == 0x01000000) {
2043 /* Single load/store */
2044 offset = (insn & 0xff) << 2;
2045 if ((insn & (1 << 23)) == 0)
2046 offset = -offset;
2047 gen_op_addl_T1_im(offset);
2048 if (insn & (1 << 20)) {
b5ff1b31 2049 gen_vfp_ld(s, dp);
b7bcbe95
FB
2050 gen_mov_vreg_F0(dp, rd);
2051 } else {
2052 gen_mov_F0_vreg(dp, rd);
b5ff1b31 2053 gen_vfp_st(s, dp);
b7bcbe95
FB
2054 }
2055 } else {
2056 /* load/store multiple */
2057 if (dp)
2058 n = (insn >> 1) & 0x7f;
2059 else
2060 n = insn & 0xff;
2061
2062 if (insn & (1 << 24)) /* pre-decrement */
2063 gen_op_addl_T1_im(-((insn & 0xff) << 2));
2064
2065 if (dp)
2066 offset = 8;
2067 else
2068 offset = 4;
2069 for (i = 0; i < n; i++) {
18c9b560 2070 if (insn & ARM_CP_RW_BIT) {
b7bcbe95 2071 /* load */
b5ff1b31 2072 gen_vfp_ld(s, dp);
b7bcbe95
FB
2073 gen_mov_vreg_F0(dp, rd + i);
2074 } else {
2075 /* store */
2076 gen_mov_F0_vreg(dp, rd + i);
b5ff1b31 2077 gen_vfp_st(s, dp);
b7bcbe95
FB
2078 }
2079 gen_op_addl_T1_im(offset);
2080 }
2081 if (insn & (1 << 21)) {
2082 /* writeback */
2083 if (insn & (1 << 24))
2084 offset = -offset * n;
2085 else if (dp && (insn & 1))
2086 offset = 4;
2087 else
2088 offset = 0;
2089
2090 if (offset != 0)
2091 gen_op_addl_T1_im(offset);
2092 gen_movl_reg_T1(s, rn);
2093 }
2094 }
2095 }
2096 break;
2097 default:
2098 /* Should never happen. */
2099 return 1;
2100 }
2101 return 0;
2102}
2103
6e256c93 2104static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
c53be334 2105{
6e256c93
FB
2106 TranslationBlock *tb;
2107
2108 tb = s->tb;
2109 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
2110 if (n == 0)
2111 gen_op_goto_tb0(TBPARAM(tb));
2112 else
2113 gen_op_goto_tb1(TBPARAM(tb));
2114 gen_op_movl_T0_im(dest);
2115 gen_op_movl_r15_T0();
2116 gen_op_movl_T0_im((long)tb + n);
2117 gen_op_exit_tb();
2118 } else {
2119 gen_op_movl_T0_im(dest);
2120 gen_op_movl_r15_T0();
2121 gen_op_movl_T0_0();
2122 gen_op_exit_tb();
2123 }
c53be334
FB
2124}
2125
8aaca4c0
FB
2126static inline void gen_jmp (DisasContext *s, uint32_t dest)
2127{
2128 if (__builtin_expect(s->singlestep_enabled, 0)) {
2129 /* An indirect jump so that we still trigger the debug exception. */
5899f386
FB
2130 if (s->thumb)
2131 dest |= 1;
8aaca4c0
FB
2132 gen_op_movl_T0_im(dest);
2133 gen_bx(s);
2134 } else {
6e256c93 2135 gen_goto_tb(s, 0, dest);
8aaca4c0
FB
2136 s->is_jmp = DISAS_TB_JUMP;
2137 }
2138}
2139
b5ff1b31
FB
2140static inline void gen_mulxy(int x, int y)
2141{
ee097184 2142 if (x)
b5ff1b31
FB
2143 gen_op_sarl_T0_im(16);
2144 else
2145 gen_op_sxth_T0();
ee097184 2146 if (y)
b5ff1b31
FB
2147 gen_op_sarl_T1_im(16);
2148 else
2149 gen_op_sxth_T1();
2150 gen_op_mul_T0_T1();
2151}
2152
2153/* Return the mask of PSR bits set by a MSR instruction. */
2ae23e75 2154static uint32_t msr_mask(DisasContext *s, int flags, int spsr) {
b5ff1b31
FB
2155 uint32_t mask;
2156
2157 mask = 0;
2158 if (flags & (1 << 0))
2159 mask |= 0xff;
2160 if (flags & (1 << 1))
2161 mask |= 0xff00;
2162 if (flags & (1 << 2))
2163 mask |= 0xff0000;
2164 if (flags & (1 << 3))
2165 mask |= 0xff000000;
2ae23e75
PB
2166 /* Mask out undefined bits. */
2167 mask &= 0xf90f03ff;
2168 /* Mask out state bits. */
2169 if (!spsr)
2170 mask &= ~0x01000020;
b5ff1b31
FB
2171 /* Mask out privileged bits. */
2172 if (IS_USER(s))
2173 mask &= 0xf80f0200;
2174 return mask;
2175}
2176
2177/* Returns nonzero if access to the PSR is not permitted. */
2178static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr)
2179{
2180 if (spsr) {
2181 /* ??? This is also undefined in system mode. */
2182 if (IS_USER(s))
2183 return 1;
2184 gen_op_movl_spsr_T0(mask);
2185 } else {
2186 gen_op_movl_cpsr_T0(mask);
2187 }
2188 gen_lookup_tb(s);
2189 return 0;
2190}
2191
2192static void gen_exception_return(DisasContext *s)
2193{
2194 gen_op_movl_reg_TN[0][15]();
2195 gen_op_movl_T0_spsr();
2196 gen_op_movl_cpsr_T0(0xffffffff);
2197 s->is_jmp = DISAS_UPDATE;
2198}
2199
b7bcbe95 2200static void disas_arm_insn(CPUState * env, DisasContext *s)
2c0262af
FB
2201{
2202 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
2203
b5ff1b31 2204 insn = ldl_code(s->pc);
2c0262af
FB
2205 s->pc += 4;
2206
2207 cond = insn >> 28;
99c475ab 2208 if (cond == 0xf){
b7bcbe95 2209 /* Unconditional instructions. */
99c475ab
FB
2210 if ((insn & 0x0d70f000) == 0x0550f000)
2211 return; /* PLD */
2212 else if ((insn & 0x0e000000) == 0x0a000000) {
2213 /* branch link and change to thumb (blx <offset>) */
2214 int32_t offset;
2215
2216 val = (uint32_t)s->pc;
2217 gen_op_movl_T0_im(val);
2218 gen_movl_reg_T0(s, 14);
2219 /* Sign-extend the 24-bit offset */
2220 offset = (((int32_t)insn) << 8) >> 8;
2221 /* offset * 4 + bit24 * 2 + (thumb bit) */
2222 val += (offset << 2) | ((insn >> 23) & 2) | 1;
2223 /* pipeline offset */
2224 val += 4;
2225 gen_op_movl_T0_im(val);
2226 gen_bx(s);
2227 return;
b7bcbe95
FB
2228 } else if ((insn & 0x0fe00000) == 0x0c400000) {
2229 /* Coprocessor double register transfer. */
2230 } else if ((insn & 0x0f000010) == 0x0e000010) {
2231 /* Additional coprocessor register transfer. */
b5ff1b31
FB
2232 } else if ((insn & 0x0ff10010) == 0x01000000) {
2233 /* cps (privileged) */
2234 } else if ((insn & 0x0ffffdff) == 0x01010000) {
2235 /* setend */
2236 if (insn & (1 << 9)) {
2237 /* BE8 mode not implemented. */
2238 goto illegal_op;
2239 }
2240 return;
99c475ab 2241 }
2c0262af 2242 goto illegal_op;
99c475ab 2243 }
2c0262af
FB
2244 if (cond != 0xe) {
2245 /* if not always execute, we generate a conditional jump to
2246 next instruction */
e50e6a20
FB
2247 s->condlabel = gen_new_label();
2248 gen_test_cc[cond ^ 1](s->condlabel);
2249 s->condjmp = 1;
2250 //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
2251 //s->is_jmp = DISAS_JUMP_NEXT;
2c0262af 2252 }
99c475ab 2253 if ((insn & 0x0f900000) == 0x03000000) {
b5ff1b31 2254 if ((insn & 0x0fb0f000) != 0x0320f000)
99c475ab
FB
2255 goto illegal_op;
2256 /* CPSR = immediate */
2257 val = insn & 0xff;
2258 shift = ((insn >> 8) & 0xf) * 2;
2259 if (shift)
2260 val = (val >> shift) | (val << (32 - shift));
2261 gen_op_movl_T0_im(val);
2ae23e75
PB
2262 i = ((insn & (1 << 22)) != 0);
2263 if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
b5ff1b31 2264 goto illegal_op;
99c475ab
FB
2265 } else if ((insn & 0x0f900000) == 0x01000000
2266 && (insn & 0x00000090) != 0x00000090) {
2267 /* miscellaneous instructions */
2268 op1 = (insn >> 21) & 3;
2269 sh = (insn >> 4) & 0xf;
2270 rm = insn & 0xf;
2271 switch (sh) {
2272 case 0x0: /* move program status register */
99c475ab 2273 if (op1 & 1) {
b5ff1b31 2274 /* PSR = reg */
99c475ab 2275 gen_movl_T0_reg(s, rm);
2ae23e75
PB
2276 i = ((op1 & 2) != 0);
2277 if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
b5ff1b31 2278 goto illegal_op;
99c475ab 2279 } else {
2ae23e75 2280 /* reg = PSR */
99c475ab 2281 rd = (insn >> 12) & 0xf;
b5ff1b31
FB
2282 if (op1 & 2) {
2283 if (IS_USER(s))
2284 goto illegal_op;
2285 gen_op_movl_T0_spsr();
2286 } else {
2287 gen_op_movl_T0_cpsr();
2288 }
99c475ab
FB
2289 gen_movl_reg_T0(s, rd);
2290 }
b8a9e8f1 2291 break;
99c475ab
FB
2292 case 0x1:
2293 if (op1 == 1) {
2294 /* branch/exchange thumb (bx). */
2295 gen_movl_T0_reg(s, rm);
2296 gen_bx(s);
2297 } else if (op1 == 3) {
2298 /* clz */
2299 rd = (insn >> 12) & 0xf;
2300 gen_movl_T0_reg(s, rm);
2301 gen_op_clz_T0();
2302 gen_movl_reg_T0(s, rd);
2303 } else {
2304 goto illegal_op;
2305 }
2306 break;
b5ff1b31
FB
2307 case 0x2:
2308 if (op1 == 1) {
2309 ARCH(5J); /* bxj */
2310 /* Trivial implementation equivalent to bx. */
2311 gen_movl_T0_reg(s, rm);
2312 gen_bx(s);
2313 } else {
2314 goto illegal_op;
2315 }
2316 break;
99c475ab
FB
2317 case 0x3:
2318 if (op1 != 1)
2319 goto illegal_op;
2320
2321 /* branch link/exchange thumb (blx) */
2322 val = (uint32_t)s->pc;
2323 gen_op_movl_T0_im(val);
2324 gen_movl_reg_T0(s, 14);
2325 gen_movl_T0_reg(s, rm);
2326 gen_bx(s);
2327 break;
2328 case 0x5: /* saturating add/subtract */
2329 rd = (insn >> 12) & 0xf;
2330 rn = (insn >> 16) & 0xf;
ff8263a9
FB
2331 gen_movl_T0_reg(s, rm);
2332 gen_movl_T1_reg(s, rn);
2333 if (op1 & 2)
2334 gen_op_double_T1_saturate();
99c475ab
FB
2335 if (op1 & 1)
2336 gen_op_subl_T0_T1_saturate();
2337 else
2338 gen_op_addl_T0_T1_saturate();
ff8263a9 2339 gen_movl_reg_T0(s, rd);
99c475ab 2340 break;
06c949e6
PB
2341 case 7: /* bkpt */
2342 gen_op_movl_T0_im((long)s->pc - 4);
2343 gen_op_movl_reg_TN[0][15]();
2344 gen_op_bkpt();
2345 s->is_jmp = DISAS_JUMP;
2346 break;
99c475ab
FB
2347 case 0x8: /* signed multiply */
2348 case 0xa:
2349 case 0xc:
2350 case 0xe:
2351 rs = (insn >> 8) & 0xf;
2352 rn = (insn >> 12) & 0xf;
2353 rd = (insn >> 16) & 0xf;
2354 if (op1 == 1) {
2355 /* (32 * 16) >> 16 */
2356 gen_movl_T0_reg(s, rm);
2357 gen_movl_T1_reg(s, rs);
2358 if (sh & 4)
2359 gen_op_sarl_T1_im(16);
2360 else
b5ff1b31 2361 gen_op_sxth_T1();
99c475ab
FB
2362 gen_op_imulw_T0_T1();
2363 if ((sh & 2) == 0) {
2364 gen_movl_T1_reg(s, rn);
2365 gen_op_addl_T0_T1_setq();
2366 }
2367 gen_movl_reg_T0(s, rd);
2368 } else {
2369 /* 16 * 16 */
2370 gen_movl_T0_reg(s, rm);
99c475ab 2371 gen_movl_T1_reg(s, rs);
b5ff1b31 2372 gen_mulxy(sh & 2, sh & 4);
99c475ab 2373 if (op1 == 2) {
b5ff1b31 2374 gen_op_signbit_T1_T0();
99c475ab
FB
2375 gen_op_addq_T0_T1(rn, rd);
2376 gen_movl_reg_T0(s, rn);
2377 gen_movl_reg_T1(s, rd);
2378 } else {
99c475ab
FB
2379 if (op1 == 0) {
2380 gen_movl_T1_reg(s, rn);
2381 gen_op_addl_T0_T1_setq();
2382 }
2383 gen_movl_reg_T0(s, rd);
2384 }
2385 }
2386 break;
2387 default:
2388 goto illegal_op;
2389 }
2390 } else if (((insn & 0x0e000000) == 0 &&
2391 (insn & 0x00000090) != 0x90) ||
2392 ((insn & 0x0e000000) == (1 << 25))) {
2c0262af
FB
2393 int set_cc, logic_cc, shiftop;
2394
2395 op1 = (insn >> 21) & 0xf;
2396 set_cc = (insn >> 20) & 1;
2397 logic_cc = table_logic_cc[op1] & set_cc;
2398
2399 /* data processing instruction */
2400 if (insn & (1 << 25)) {
2401 /* immediate operand */
2402 val = insn & 0xff;
2403 shift = ((insn >> 8) & 0xf) * 2;
2404 if (shift)
2405 val = (val >> shift) | (val << (32 - shift));
2406 gen_op_movl_T1_im(val);
7ff4d218
FB
2407 if (logic_cc && shift)
2408 gen_op_mov_CF_T1();
2c0262af
FB
2409 } else {
2410 /* register */
2411 rm = (insn) & 0xf;
2412 gen_movl_T1_reg(s, rm);
2413 shiftop = (insn >> 5) & 3;
2414 if (!(insn & (1 << 4))) {
2415 shift = (insn >> 7) & 0x1f;
2416 if (shift != 0) {
2417 if (logic_cc) {
2418 gen_shift_T1_im_cc[shiftop](shift);
2419 } else {
2420 gen_shift_T1_im[shiftop](shift);
2421 }
1e8d4eec
FB
2422 } else if (shiftop != 0) {
2423 if (logic_cc) {
2424 gen_shift_T1_0_cc[shiftop]();
2425 } else {
2426 gen_shift_T1_0[shiftop]();
2427 }
2c0262af
FB
2428 }
2429 } else {
2430 rs = (insn >> 8) & 0xf;
2431 gen_movl_T0_reg(s, rs);
2432 if (logic_cc) {
2433 gen_shift_T1_T0_cc[shiftop]();
2434 } else {
2435 gen_shift_T1_T0[shiftop]();
2436 }
2437 }
2438 }
2439 if (op1 != 0x0f && op1 != 0x0d) {
2440 rn = (insn >> 16) & 0xf;
2441 gen_movl_T0_reg(s, rn);
2442 }
2443 rd = (insn >> 12) & 0xf;
2444 switch(op1) {
2445 case 0x00:
2446 gen_op_andl_T0_T1();
2447 gen_movl_reg_T0(s, rd);
2448 if (logic_cc)
2449 gen_op_logic_T0_cc();
2450 break;
2451 case 0x01:
2452 gen_op_xorl_T0_T1();
2453 gen_movl_reg_T0(s, rd);
2454 if (logic_cc)
2455 gen_op_logic_T0_cc();
2456 break;
2457 case 0x02:
b5ff1b31
FB
2458 if (set_cc && rd == 15) {
2459 /* SUBS r15, ... is used for exception return. */
2460 if (IS_USER(s))
2461 goto illegal_op;
2c0262af 2462 gen_op_subl_T0_T1_cc();
b5ff1b31
FB
2463 gen_exception_return(s);
2464 } else {
2465 if (set_cc)
2466 gen_op_subl_T0_T1_cc();
2467 else
2468 gen_op_subl_T0_T1();
2469 gen_movl_reg_T0(s, rd);
2470 }
2c0262af
FB
2471 break;
2472 case 0x03:
2473 if (set_cc)
2474 gen_op_rsbl_T0_T1_cc();
2475 else
2476 gen_op_rsbl_T0_T1();
2477 gen_movl_reg_T0(s, rd);
2478 break;
2479 case 0x04:
2480 if (set_cc)
2481 gen_op_addl_T0_T1_cc();
2482 else
2483 gen_op_addl_T0_T1();
2484 gen_movl_reg_T0(s, rd);
2485 break;
2486 case 0x05:
2487 if (set_cc)
2488 gen_op_adcl_T0_T1_cc();
2489 else
2490 gen_op_adcl_T0_T1();
2491 gen_movl_reg_T0(s, rd);
2492 break;
2493 case 0x06:
2494 if (set_cc)
2495 gen_op_sbcl_T0_T1_cc();
2496 else
2497 gen_op_sbcl_T0_T1();
2498 gen_movl_reg_T0(s, rd);
2499 break;
2500 case 0x07:
2501 if (set_cc)
2502 gen_op_rscl_T0_T1_cc();
2503 else
2504 gen_op_rscl_T0_T1();
2505 gen_movl_reg_T0(s, rd);
2506 break;
2507 case 0x08:
2508 if (set_cc) {
2509 gen_op_andl_T0_T1();
2510 gen_op_logic_T0_cc();
2511 }
2512 break;
2513 case 0x09:
2514 if (set_cc) {
2515 gen_op_xorl_T0_T1();
2516 gen_op_logic_T0_cc();
2517 }
2518 break;
2519 case 0x0a:
2520 if (set_cc) {
2521 gen_op_subl_T0_T1_cc();
2522 }
2523 break;
2524 case 0x0b:
2525 if (set_cc) {
2526 gen_op_addl_T0_T1_cc();
2527 }
2528 break;
2529 case 0x0c:
2530 gen_op_orl_T0_T1();
2531 gen_movl_reg_T0(s, rd);
2532 if (logic_cc)
2533 gen_op_logic_T0_cc();
2534 break;
2535 case 0x0d:
b5ff1b31
FB
2536 if (logic_cc && rd == 15) {
2537 /* MOVS r15, ... is used for exception return. */
2538 if (IS_USER(s))
2539 goto illegal_op;
2540 gen_op_movl_T0_T1();
2541 gen_exception_return(s);
2542 } else {
2543 gen_movl_reg_T1(s, rd);
2544 if (logic_cc)
2545 gen_op_logic_T1_cc();
2546 }
2c0262af
FB
2547 break;
2548 case 0x0e:
2549 gen_op_bicl_T0_T1();
2550 gen_movl_reg_T0(s, rd);
2551 if (logic_cc)
2552 gen_op_logic_T0_cc();
2553 break;
2554 default:
2555 case 0x0f:
2556 gen_op_notl_T1();
2557 gen_movl_reg_T1(s, rd);
2558 if (logic_cc)
2559 gen_op_logic_T1_cc();
2560 break;
2561 }
2562 } else {
2563 /* other instructions */
2564 op1 = (insn >> 24) & 0xf;
2565 switch(op1) {
2566 case 0x0:
2567 case 0x1:
99c475ab 2568 /* multiplies, extra load/stores */
2c0262af
FB
2569 sh = (insn >> 5) & 3;
2570 if (sh == 0) {
2571 if (op1 == 0x0) {
2572 rd = (insn >> 16) & 0xf;
2573 rn = (insn >> 12) & 0xf;
2574 rs = (insn >> 8) & 0xf;
2575 rm = (insn) & 0xf;
99c475ab 2576 if (((insn >> 22) & 3) == 0) {
2c0262af
FB
2577 /* 32 bit mul */
2578 gen_movl_T0_reg(s, rs);
2579 gen_movl_T1_reg(s, rm);
2580 gen_op_mul_T0_T1();
2581 if (insn & (1 << 21)) {
2582 gen_movl_T1_reg(s, rn);
2583 gen_op_addl_T0_T1();
2584 }
2585 if (insn & (1 << 20))
2586 gen_op_logic_T0_cc();
2587 gen_movl_reg_T0(s, rd);
2588 } else {
2589 /* 64 bit mul */
2590 gen_movl_T0_reg(s, rs);
2591 gen_movl_T1_reg(s, rm);
2592 if (insn & (1 << 22))
2c0262af 2593 gen_op_imull_T0_T1();
2e134c9c
FB
2594 else
2595 gen_op_mull_T0_T1();
99c475ab 2596 if (insn & (1 << 21)) /* mult accumulate */
2c0262af 2597 gen_op_addq_T0_T1(rn, rd);
99c475ab 2598 if (!(insn & (1 << 23))) { /* double accumulate */
b5ff1b31 2599 ARCH(6);
99c475ab
FB
2600 gen_op_addq_lo_T0_T1(rn);
2601 gen_op_addq_lo_T0_T1(rd);
2602 }
2c0262af
FB
2603 if (insn & (1 << 20))
2604 gen_op_logicq_cc();
2605 gen_movl_reg_T0(s, rn);
2606 gen_movl_reg_T1(s, rd);
2607 }
2608 } else {
2c0262af
FB
2609 rn = (insn >> 16) & 0xf;
2610 rd = (insn >> 12) & 0xf;
99c475ab
FB
2611 if (insn & (1 << 23)) {
2612 /* load/store exclusive */
2613 goto illegal_op;
2c0262af 2614 } else {
99c475ab
FB
2615 /* SWP instruction */
2616 rm = (insn) & 0xf;
2617
2618 gen_movl_T0_reg(s, rm);
2619 gen_movl_T1_reg(s, rn);
2620 if (insn & (1 << 22)) {
b5ff1b31 2621 gen_ldst(swpb, s);
99c475ab 2622 } else {
b5ff1b31 2623 gen_ldst(swpl, s);
99c475ab
FB
2624 }
2625 gen_movl_reg_T0(s, rd);
2c0262af 2626 }
2c0262af
FB
2627 }
2628 } else {
191f9a93 2629 int address_offset;
5fd46862 2630 int load;
99c475ab 2631 /* Misc load/store */
2c0262af
FB
2632 rn = (insn >> 16) & 0xf;
2633 rd = (insn >> 12) & 0xf;
2634 gen_movl_T1_reg(s, rn);
beddab75 2635 if (insn & (1 << 24))
191f9a93
PB
2636 gen_add_datah_offset(s, insn, 0);
2637 address_offset = 0;
2c0262af
FB
2638 if (insn & (1 << 20)) {
2639 /* load */
2640 switch(sh) {
2641 case 1:
b5ff1b31 2642 gen_ldst(lduw, s);
2c0262af
FB
2643 break;
2644 case 2:
b5ff1b31 2645 gen_ldst(ldsb, s);
2c0262af
FB
2646 break;
2647 default:
2648 case 3:
b5ff1b31 2649 gen_ldst(ldsw, s);
2c0262af
FB
2650 break;
2651 }
5fd46862 2652 load = 1;
99c475ab
FB
2653 } else if (sh & 2) {
2654 /* doubleword */
2655 if (sh & 1) {
2656 /* store */
2657 gen_movl_T0_reg(s, rd);
b5ff1b31 2658 gen_ldst(stl, s);
99c475ab
FB
2659 gen_op_addl_T1_im(4);
2660 gen_movl_T0_reg(s, rd + 1);
b5ff1b31 2661 gen_ldst(stl, s);
5fd46862 2662 load = 0;
99c475ab
FB
2663 } else {
2664 /* load */
b5ff1b31 2665 gen_ldst(ldl, s);
99c475ab
FB
2666 gen_movl_reg_T0(s, rd);
2667 gen_op_addl_T1_im(4);
b5ff1b31 2668 gen_ldst(ldl, s);
5fd46862
PB
2669 rd++;
2670 load = 1;
99c475ab 2671 }
191f9a93 2672 address_offset = -4;
2c0262af
FB
2673 } else {
2674 /* store */
e748ba4f 2675 gen_movl_T0_reg(s, rd);
b5ff1b31 2676 gen_ldst(stw, s);
5fd46862 2677 load = 0;
2c0262af 2678 }
5fd46862
PB
2679 /* Perform base writeback before the loaded value to
2680 ensure correct behavior with overlapping index registers.
2681 ldrd with base writeback is is undefined if the
2682 destination and index registers overlap. */
2c0262af 2683 if (!(insn & (1 << 24))) {
191f9a93 2684 gen_add_datah_offset(s, insn, address_offset);
2c0262af
FB
2685 gen_movl_reg_T1(s, rn);
2686 } else if (insn & (1 << 21)) {
191f9a93
PB
2687 if (address_offset)
2688 gen_op_addl_T1_im(address_offset);
2c0262af
FB
2689 gen_movl_reg_T1(s, rn);
2690 }
5fd46862
PB
2691 if (load) {
2692 /* Complete the load. */
2693 gen_movl_reg_T0(s, rd);
2694 }
2c0262af
FB
2695 }
2696 break;
2697 case 0x4:
2698 case 0x5:
2699 case 0x6:
2700 case 0x7:
159f3663
FB
2701 /* Check for undefined extension instructions
2702 * per the ARM Bible IE:
2703 * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
2704 */
2705 sh = (0xf << 20) | (0xf << 4);
2706 if (op1 == 0x7 && ((insn & sh) == sh))
2707 {
2708 goto illegal_op;
2709 }
2c0262af
FB
2710 /* load/store byte/word */
2711 rn = (insn >> 16) & 0xf;
2712 rd = (insn >> 12) & 0xf;
2713 gen_movl_T1_reg(s, rn);
b5ff1b31 2714 i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
2c0262af
FB
2715 if (insn & (1 << 24))
2716 gen_add_data_offset(s, insn);
2717 if (insn & (1 << 20)) {
2718 /* load */
6658ffb8 2719 s->is_mem = 1;
b5ff1b31 2720#if defined(CONFIG_USER_ONLY)
2c0262af 2721 if (insn & (1 << 22))
b5ff1b31 2722 gen_op_ldub_raw();
2c0262af 2723 else
b5ff1b31
FB
2724 gen_op_ldl_raw();
2725#else
2726 if (insn & (1 << 22)) {
2727 if (i)
2728 gen_op_ldub_user();
2729 else
2730 gen_op_ldub_kernel();
2731 } else {
2732 if (i)
2733 gen_op_ldl_user();
2734 else
2735 gen_op_ldl_kernel();
2736 }
2737#endif
2c0262af
FB
2738 } else {
2739 /* store */
2740 gen_movl_T0_reg(s, rd);
b5ff1b31 2741#if defined(CONFIG_USER_ONLY)
2c0262af 2742 if (insn & (1 << 22))
b5ff1b31 2743 gen_op_stb_raw();
2c0262af 2744 else
b5ff1b31
FB
2745 gen_op_stl_raw();
2746#else
2747 if (insn & (1 << 22)) {
2748 if (i)
2749 gen_op_stb_user();
2750 else
2751 gen_op_stb_kernel();
2752 } else {
2753 if (i)
2754 gen_op_stl_user();
2755 else
2756 gen_op_stl_kernel();
2757 }
2758#endif
2c0262af
FB
2759 }
2760 if (!(insn & (1 << 24))) {
2761 gen_add_data_offset(s, insn);
2762 gen_movl_reg_T1(s, rn);
2763 } else if (insn & (1 << 21))
2764 gen_movl_reg_T1(s, rn); {
2765 }
5fd46862
PB
2766 if (insn & (1 << 20)) {
2767 /* Complete the load. */
2768 if (rd == 15)
2769 gen_bx(s);
2770 else
2771 gen_movl_reg_T0(s, rd);
2772 }
2c0262af
FB
2773 break;
2774 case 0x08:
2775 case 0x09:
2776 {
191abaa2 2777 int j, n, user, loaded_base;
2c0262af
FB
2778 /* load/store multiple words */
2779 /* XXX: store correct base if write back */
b5ff1b31
FB
2780 user = 0;
2781 if (insn & (1 << 22)) {
2782 if (IS_USER(s))
2783 goto illegal_op; /* only usable in supervisor mode */
2784
2785 if ((insn & (1 << 15)) == 0)
2786 user = 1;
2787 }
2c0262af
FB
2788 rn = (insn >> 16) & 0xf;
2789 gen_movl_T1_reg(s, rn);
2790
2791 /* compute total size */
191abaa2 2792 loaded_base = 0;
2c0262af
FB
2793 n = 0;
2794 for(i=0;i<16;i++) {
2795 if (insn & (1 << i))
2796 n++;
2797 }
2798 /* XXX: test invalid n == 0 case ? */
2799 if (insn & (1 << 23)) {
2800 if (insn & (1 << 24)) {
2801 /* pre increment */
2802 gen_op_addl_T1_im(4);
2803 } else {
2804 /* post increment */
2805 }
2806 } else {
2807 if (insn & (1 << 24)) {
2808 /* pre decrement */
2809 gen_op_addl_T1_im(-(n * 4));
2810 } else {
2811 /* post decrement */
2812 if (n != 1)
2813 gen_op_addl_T1_im(-((n - 1) * 4));
2814 }
2815 }
2816 j = 0;
2817 for(i=0;i<16;i++) {
2818 if (insn & (1 << i)) {
2819 if (insn & (1 << 20)) {
2820 /* load */
b5ff1b31
FB
2821 gen_ldst(ldl, s);
2822 if (i == 15) {
99c475ab 2823 gen_bx(s);
b5ff1b31
FB
2824 } else if (user) {
2825 gen_op_movl_user_T0(i);
191abaa2
PB
2826 } else if (i == rn) {
2827 gen_op_movl_T2_T0();
2828 loaded_base = 1;
b5ff1b31 2829 } else {
99c475ab 2830 gen_movl_reg_T0(s, i);
b5ff1b31 2831 }
2c0262af
FB
2832 } else {
2833 /* store */
2834 if (i == 15) {
2835 /* special case: r15 = PC + 12 */
2836 val = (long)s->pc + 8;
2837 gen_op_movl_TN_im[0](val);
b5ff1b31
FB
2838 } else if (user) {
2839 gen_op_movl_T0_user(i);
2c0262af
FB
2840 } else {
2841 gen_movl_T0_reg(s, i);
2842 }
b5ff1b31 2843 gen_ldst(stl, s);
2c0262af
FB
2844 }
2845 j++;
2846 /* no need to add after the last transfer */
2847 if (j != n)
2848 gen_op_addl_T1_im(4);
2849 }
2850 }
2851 if (insn & (1 << 21)) {
2852 /* write back */
2853 if (insn & (1 << 23)) {
2854 if (insn & (1 << 24)) {
2855 /* pre increment */
2856 } else {
2857 /* post increment */
2858 gen_op_addl_T1_im(4);
2859 }
2860 } else {
2861 if (insn & (1 << 24)) {
2862 /* pre decrement */
2863 if (n != 1)
2864 gen_op_addl_T1_im(-((n - 1) * 4));
2865 } else {
2866 /* post decrement */
2867 gen_op_addl_T1_im(-(n * 4));
2868 }
2869 }
2870 gen_movl_reg_T1(s, rn);
2871 }
191abaa2
PB
2872 if (loaded_base) {
2873 gen_op_movl_T0_T2();
2874 gen_movl_reg_T0(s, rn);
2875 }
b5ff1b31
FB
2876 if ((insn & (1 << 22)) && !user) {
2877 /* Restore CPSR from SPSR. */
2878 gen_op_movl_T0_spsr();
2879 gen_op_movl_cpsr_T0(0xffffffff);
2880 s->is_jmp = DISAS_UPDATE;
2881 }
2c0262af
FB
2882 }
2883 break;
2884 case 0xa:
2885 case 0xb:
2886 {
99c475ab 2887 int32_t offset;
2c0262af
FB
2888
2889 /* branch (and link) */
99c475ab 2890 val = (int32_t)s->pc;
2c0262af
FB
2891 if (insn & (1 << 24)) {
2892 gen_op_movl_T0_im(val);
2893 gen_op_movl_reg_TN[0][14]();
2894 }
99c475ab 2895 offset = (((int32_t)insn << 8) >> 8);
2c0262af 2896 val += (offset << 2) + 4;
8aaca4c0 2897 gen_jmp(s, val);
2c0262af
FB
2898 }
2899 break;
b7bcbe95
FB
2900 case 0xc:
2901 case 0xd:
2902 case 0xe:
2903 /* Coprocessor. */
2904 op1 = (insn >> 8) & 0xf;
c1713132
AZ
2905 if (arm_feature(env, ARM_FEATURE_XSCALE) &&
2906 ((env->cp15.c15_cpar ^ 0x3fff) & (1 << op1)))
2907 goto illegal_op;
b7bcbe95 2908 switch (op1) {
c1713132 2909 case 0 ... 1:
18c9b560
AZ
2910 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
2911 if (disas_iwmmxt_insn(env, s, insn))
2912 goto illegal_op;
2913 } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
2914 if (disas_dsp_insn(env, s, insn))
2915 goto illegal_op;
2916 } else
2917 goto illegal_op;
2918 break;
c1713132
AZ
2919 case 2 ... 9:
2920 case 12 ... 14:
2921 if (disas_cp_insn (env, s, insn))
2922 goto illegal_op;
2923 break;
b7bcbe95
FB
2924 case 10:
2925 case 11:
2926 if (disas_vfp_insn (env, s, insn))
2927 goto illegal_op;
2928 break;
b5ff1b31
FB
2929 case 15:
2930 if (disas_cp15_insn (s, insn))
2931 goto illegal_op;
2932 break;
b7bcbe95
FB
2933 default:
2934 /* unknown coprocessor. */
2935 goto illegal_op;
2936 }
2937 break;
2c0262af
FB
2938 case 0xf:
2939 /* swi */
2940 gen_op_movl_T0_im((long)s->pc);
2941 gen_op_movl_reg_TN[0][15]();
2942 gen_op_swi();
2943 s->is_jmp = DISAS_JUMP;
2944 break;
2c0262af
FB
2945 default:
2946 illegal_op:
2947 gen_op_movl_T0_im((long)s->pc - 4);
2948 gen_op_movl_reg_TN[0][15]();
2949 gen_op_undef_insn();
2950 s->is_jmp = DISAS_JUMP;
2951 break;
2952 }
2953 }
2954}
2955
99c475ab
FB
2956static void disas_thumb_insn(DisasContext *s)
2957{
2958 uint32_t val, insn, op, rm, rn, rd, shift, cond;
2959 int32_t offset;
2960 int i;
2961
b5ff1b31 2962 insn = lduw_code(s->pc);
99c475ab 2963 s->pc += 2;
b5ff1b31 2964
99c475ab
FB
2965 switch (insn >> 12) {
2966 case 0: case 1:
2967 rd = insn & 7;
2968 op = (insn >> 11) & 3;
2969 if (op == 3) {
2970 /* add/subtract */
2971 rn = (insn >> 3) & 7;
2972 gen_movl_T0_reg(s, rn);
2973 if (insn & (1 << 10)) {
2974 /* immediate */
2975 gen_op_movl_T1_im((insn >> 6) & 7);
2976 } else {
2977 /* reg */
2978 rm = (insn >> 6) & 7;
2979 gen_movl_T1_reg(s, rm);
2980 }
2981 if (insn & (1 << 9))
5899f386 2982 gen_op_subl_T0_T1_cc();
99c475ab
FB
2983 else
2984 gen_op_addl_T0_T1_cc();
2985 gen_movl_reg_T0(s, rd);
2986 } else {
2987 /* shift immediate */
2988 rm = (insn >> 3) & 7;
2989 shift = (insn >> 6) & 0x1f;
2990 gen_movl_T0_reg(s, rm);
2991 gen_shift_T0_im_thumb[op](shift);
2992 gen_movl_reg_T0(s, rd);
2993 }
2994 break;
2995 case 2: case 3:
2996 /* arithmetic large immediate */
2997 op = (insn >> 11) & 3;
2998 rd = (insn >> 8) & 0x7;
2999 if (op == 0) {
3000 gen_op_movl_T0_im(insn & 0xff);
3001 } else {
3002 gen_movl_T0_reg(s, rd);
3003 gen_op_movl_T1_im(insn & 0xff);
3004 }
3005 switch (op) {
3006 case 0: /* mov */
3007 gen_op_logic_T0_cc();
3008 break;
3009 case 1: /* cmp */
3010 gen_op_subl_T0_T1_cc();
3011 break;
3012 case 2: /* add */
3013 gen_op_addl_T0_T1_cc();
3014 break;
3015 case 3: /* sub */
3016 gen_op_subl_T0_T1_cc();
3017 break;
3018 }
3019 if (op != 1)
3020 gen_movl_reg_T0(s, rd);
3021 break;
3022 case 4:
3023 if (insn & (1 << 11)) {
3024 rd = (insn >> 8) & 7;
5899f386
FB
3025 /* load pc-relative. Bit 1 of PC is ignored. */
3026 val = s->pc + 2 + ((insn & 0xff) * 4);
3027 val &= ~(uint32_t)2;
99c475ab 3028 gen_op_movl_T1_im(val);
b5ff1b31 3029 gen_ldst(ldl, s);
99c475ab
FB
3030 gen_movl_reg_T0(s, rd);
3031 break;
3032 }
3033 if (insn & (1 << 10)) {
3034 /* data processing extended or blx */
3035 rd = (insn & 7) | ((insn >> 4) & 8);
3036 rm = (insn >> 3) & 0xf;
3037 op = (insn >> 8) & 3;
3038 switch (op) {
3039 case 0: /* add */
3040 gen_movl_T0_reg(s, rd);
3041 gen_movl_T1_reg(s, rm);
3042 gen_op_addl_T0_T1();
3043 gen_movl_reg_T0(s, rd);
3044 break;
3045 case 1: /* cmp */
3046 gen_movl_T0_reg(s, rd);
3047 gen_movl_T1_reg(s, rm);
3048 gen_op_subl_T0_T1_cc();
3049 break;
3050 case 2: /* mov/cpy */
3051 gen_movl_T0_reg(s, rm);
3052 gen_movl_reg_T0(s, rd);
3053 break;
3054 case 3:/* branch [and link] exchange thumb register */
3055 if (insn & (1 << 7)) {
3056 val = (uint32_t)s->pc | 1;
3057 gen_op_movl_T1_im(val);
3058 gen_movl_reg_T1(s, 14);
3059 }
3060 gen_movl_T0_reg(s, rm);
3061 gen_bx(s);
3062 break;
3063 }
3064 break;
3065 }
3066
3067 /* data processing register */
3068 rd = insn & 7;
3069 rm = (insn >> 3) & 7;
3070 op = (insn >> 6) & 0xf;
3071 if (op == 2 || op == 3 || op == 4 || op == 7) {
3072 /* the shift/rotate ops want the operands backwards */
3073 val = rm;
3074 rm = rd;
3075 rd = val;
3076 val = 1;
3077 } else {
3078 val = 0;
3079 }
3080
3081 if (op == 9) /* neg */
3082 gen_op_movl_T0_im(0);
3083 else if (op != 0xf) /* mvn doesn't read its first operand */
3084 gen_movl_T0_reg(s, rd);
3085
3086 gen_movl_T1_reg(s, rm);
5899f386 3087 switch (op) {
99c475ab
FB
3088 case 0x0: /* and */
3089 gen_op_andl_T0_T1();
3090 gen_op_logic_T0_cc();
3091 break;
3092 case 0x1: /* eor */
3093 gen_op_xorl_T0_T1();
3094 gen_op_logic_T0_cc();
3095 break;
3096 case 0x2: /* lsl */
3097 gen_op_shll_T1_T0_cc();
3aa22b4b 3098 gen_op_logic_T1_cc();
99c475ab
FB
3099 break;
3100 case 0x3: /* lsr */
3101 gen_op_shrl_T1_T0_cc();
3aa22b4b 3102 gen_op_logic_T1_cc();
99c475ab
FB
3103 break;
3104 case 0x4: /* asr */
3105 gen_op_sarl_T1_T0_cc();
3aa22b4b 3106 gen_op_logic_T1_cc();
99c475ab
FB
3107 break;
3108 case 0x5: /* adc */
3109 gen_op_adcl_T0_T1_cc();
3110 break;
3111 case 0x6: /* sbc */
3112 gen_op_sbcl_T0_T1_cc();
3113 break;
3114 case 0x7: /* ror */
3115 gen_op_rorl_T1_T0_cc();
3aa22b4b 3116 gen_op_logic_T1_cc();
99c475ab
FB
3117 break;
3118 case 0x8: /* tst */
3119 gen_op_andl_T0_T1();
3120 gen_op_logic_T0_cc();
3121 rd = 16;
5899f386 3122 break;
99c475ab 3123 case 0x9: /* neg */
5899f386 3124 gen_op_subl_T0_T1_cc();
99c475ab
FB
3125 break;
3126 case 0xa: /* cmp */
3127 gen_op_subl_T0_T1_cc();
3128 rd = 16;
3129 break;
3130 case 0xb: /* cmn */
3131 gen_op_addl_T0_T1_cc();
3132 rd = 16;
3133 break;
3134 case 0xc: /* orr */
3135 gen_op_orl_T0_T1();
3136 gen_op_logic_T0_cc();
3137 break;
3138 case 0xd: /* mul */
3139 gen_op_mull_T0_T1();
3140 gen_op_logic_T0_cc();
3141 break;
3142 case 0xe: /* bic */
3143 gen_op_bicl_T0_T1();
3144 gen_op_logic_T0_cc();
3145 break;
3146 case 0xf: /* mvn */
3147 gen_op_notl_T1();
3148 gen_op_logic_T1_cc();
3149 val = 1;
5899f386 3150 rm = rd;
99c475ab
FB
3151 break;
3152 }
3153 if (rd != 16) {
3154 if (val)
5899f386 3155 gen_movl_reg_T1(s, rm);
99c475ab
FB
3156 else
3157 gen_movl_reg_T0(s, rd);
3158 }
3159 break;
3160
3161 case 5:
3162 /* load/store register offset. */
3163 rd = insn & 7;
3164 rn = (insn >> 3) & 7;
3165 rm = (insn >> 6) & 7;
3166 op = (insn >> 9) & 7;
3167 gen_movl_T1_reg(s, rn);
3168 gen_movl_T2_reg(s, rm);
3169 gen_op_addl_T1_T2();
3170
3171 if (op < 3) /* store */
3172 gen_movl_T0_reg(s, rd);
3173
3174 switch (op) {
3175 case 0: /* str */
b5ff1b31 3176 gen_ldst(stl, s);
99c475ab
FB
3177 break;
3178 case 1: /* strh */
b5ff1b31 3179 gen_ldst(stw, s);
99c475ab
FB
3180 break;
3181 case 2: /* strb */
b5ff1b31 3182 gen_ldst(stb, s);
99c475ab
FB
3183 break;
3184 case 3: /* ldrsb */
b5ff1b31 3185 gen_ldst(ldsb, s);
99c475ab
FB
3186 break;
3187 case 4: /* ldr */
b5ff1b31 3188 gen_ldst(ldl, s);
99c475ab
FB
3189 break;
3190 case 5: /* ldrh */
b5ff1b31 3191 gen_ldst(lduw, s);
99c475ab
FB
3192 break;
3193 case 6: /* ldrb */
b5ff1b31 3194 gen_ldst(ldub, s);
99c475ab
FB
3195 break;
3196 case 7: /* ldrsh */
b5ff1b31 3197 gen_ldst(ldsw, s);
99c475ab
FB
3198 break;
3199 }
3200 if (op >= 3) /* load */
3201 gen_movl_reg_T0(s, rd);
3202 break;
3203
3204 case 6:
3205 /* load/store word immediate offset */
3206 rd = insn & 7;
3207 rn = (insn >> 3) & 7;
3208 gen_movl_T1_reg(s, rn);
3209 val = (insn >> 4) & 0x7c;
3210 gen_op_movl_T2_im(val);
3211 gen_op_addl_T1_T2();
3212
3213 if (insn & (1 << 11)) {
3214 /* load */
b5ff1b31 3215 gen_ldst(ldl, s);
99c475ab
FB
3216 gen_movl_reg_T0(s, rd);
3217 } else {
3218 /* store */
3219 gen_movl_T0_reg(s, rd);
b5ff1b31 3220 gen_ldst(stl, s);
99c475ab
FB
3221 }
3222 break;
3223
3224 case 7:
3225 /* load/store byte immediate offset */
3226 rd = insn & 7;
3227 rn = (insn >> 3) & 7;
3228 gen_movl_T1_reg(s, rn);
3229 val = (insn >> 6) & 0x1f;
3230 gen_op_movl_T2_im(val);
3231 gen_op_addl_T1_T2();
3232
3233 if (insn & (1 << 11)) {
3234 /* load */
b5ff1b31 3235 gen_ldst(ldub, s);
99c475ab
FB
3236 gen_movl_reg_T0(s, rd);
3237 } else {
3238 /* store */
3239 gen_movl_T0_reg(s, rd);
b5ff1b31 3240 gen_ldst(stb, s);
99c475ab
FB
3241 }
3242 break;
3243
3244 case 8:
3245 /* load/store halfword immediate offset */
3246 rd = insn & 7;
3247 rn = (insn >> 3) & 7;
3248 gen_movl_T1_reg(s, rn);
3249 val = (insn >> 5) & 0x3e;
3250 gen_op_movl_T2_im(val);
3251 gen_op_addl_T1_T2();
3252
3253 if (insn & (1 << 11)) {
3254 /* load */
b5ff1b31 3255 gen_ldst(lduw, s);
99c475ab
FB
3256 gen_movl_reg_T0(s, rd);
3257 } else {
3258 /* store */
3259 gen_movl_T0_reg(s, rd);
b5ff1b31 3260 gen_ldst(stw, s);
99c475ab
FB
3261 }
3262 break;
3263
3264 case 9:
3265 /* load/store from stack */
3266 rd = (insn >> 8) & 7;
3267 gen_movl_T1_reg(s, 13);
3268 val = (insn & 0xff) * 4;
3269 gen_op_movl_T2_im(val);
3270 gen_op_addl_T1_T2();
3271
3272 if (insn & (1 << 11)) {
3273 /* load */
b5ff1b31 3274 gen_ldst(ldl, s);
99c475ab
FB
3275 gen_movl_reg_T0(s, rd);
3276 } else {
3277 /* store */
3278 gen_movl_T0_reg(s, rd);
b5ff1b31 3279 gen_ldst(stl, s);
99c475ab
FB
3280 }
3281 break;
3282
3283 case 10:
3284 /* add to high reg */
3285 rd = (insn >> 8) & 7;
5899f386
FB
3286 if (insn & (1 << 11)) {
3287 /* SP */
3288 gen_movl_T0_reg(s, 13);
3289 } else {
3290 /* PC. bit 1 is ignored. */
3291 gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2);
3292 }
99c475ab
FB
3293 val = (insn & 0xff) * 4;
3294 gen_op_movl_T1_im(val);
3295 gen_op_addl_T0_T1();
3296 gen_movl_reg_T0(s, rd);
3297 break;
3298
3299 case 11:
3300 /* misc */
3301 op = (insn >> 8) & 0xf;
3302 switch (op) {
3303 case 0:
3304 /* adjust stack pointer */
3305 gen_movl_T1_reg(s, 13);
3306 val = (insn & 0x7f) * 4;
3307 if (insn & (1 << 7))
3308 val = -(int32_t)val;
3309 gen_op_movl_T2_im(val);
3310 gen_op_addl_T1_T2();
3311 gen_movl_reg_T1(s, 13);
3312 break;
3313
3314 case 4: case 5: case 0xc: case 0xd:
3315 /* push/pop */
3316 gen_movl_T1_reg(s, 13);
5899f386
FB
3317 if (insn & (1 << 8))
3318 offset = 4;
99c475ab 3319 else
5899f386
FB
3320 offset = 0;
3321 for (i = 0; i < 8; i++) {
3322 if (insn & (1 << i))
3323 offset += 4;
3324 }
3325 if ((insn & (1 << 11)) == 0) {
3326 gen_op_movl_T2_im(-offset);
3327 gen_op_addl_T1_T2();
3328 }
3329 gen_op_movl_T2_im(4);
99c475ab
FB
3330 for (i = 0; i < 8; i++) {
3331 if (insn & (1 << i)) {
3332 if (insn & (1 << 11)) {
3333 /* pop */
b5ff1b31 3334 gen_ldst(ldl, s);
99c475ab
FB
3335 gen_movl_reg_T0(s, i);
3336 } else {
3337 /* push */
3338 gen_movl_T0_reg(s, i);
b5ff1b31 3339 gen_ldst(stl, s);
99c475ab 3340 }
5899f386 3341 /* advance to the next address. */
99c475ab
FB
3342 gen_op_addl_T1_T2();
3343 }
3344 }
3345 if (insn & (1 << 8)) {
3346 if (insn & (1 << 11)) {
3347 /* pop pc */
b5ff1b31 3348 gen_ldst(ldl, s);
99c475ab
FB
3349 /* don't set the pc until the rest of the instruction
3350 has completed */
3351 } else {
3352 /* push lr */
3353 gen_movl_T0_reg(s, 14);
b5ff1b31 3354 gen_ldst(stl, s);
99c475ab
FB
3355 }
3356 gen_op_addl_T1_T2();
3357 }
5899f386
FB
3358 if ((insn & (1 << 11)) == 0) {
3359 gen_op_movl_T2_im(-offset);
3360 gen_op_addl_T1_T2();
3361 }
99c475ab
FB
3362 /* write back the new stack pointer */
3363 gen_movl_reg_T1(s, 13);
3364 /* set the new PC value */
3365 if ((insn & 0x0900) == 0x0900)
3366 gen_bx(s);
3367 break;
3368
06c949e6
PB
3369 case 0xe: /* bkpt */
3370 gen_op_movl_T0_im((long)s->pc - 2);
3371 gen_op_movl_reg_TN[0][15]();
3372 gen_op_bkpt();
3373 s->is_jmp = DISAS_JUMP;
3374 break;
3375
99c475ab
FB
3376 default:
3377 goto undef;
3378 }
3379 break;
3380
3381 case 12:
3382 /* load/store multiple */
3383 rn = (insn >> 8) & 0x7;
3384 gen_movl_T1_reg(s, rn);
3385 gen_op_movl_T2_im(4);
99c475ab
FB
3386 for (i = 0; i < 8; i++) {
3387 if (insn & (1 << i)) {
99c475ab
FB
3388 if (insn & (1 << 11)) {
3389 /* load */
b5ff1b31 3390 gen_ldst(ldl, s);
99c475ab
FB
3391 gen_movl_reg_T0(s, i);
3392 } else {
3393 /* store */
3394 gen_movl_T0_reg(s, i);
b5ff1b31 3395 gen_ldst(stl, s);
99c475ab 3396 }
5899f386
FB
3397 /* advance to the next address */
3398 gen_op_addl_T1_T2();
99c475ab
FB
3399 }
3400 }
5899f386 3401 /* Base register writeback. */
b5ff1b31
FB
3402 if ((insn & (1 << rn)) == 0)
3403 gen_movl_reg_T1(s, rn);
99c475ab
FB
3404 break;
3405
3406 case 13:
3407 /* conditional branch or swi */
3408 cond = (insn >> 8) & 0xf;
3409 if (cond == 0xe)
3410 goto undef;
3411
3412 if (cond == 0xf) {
3413 /* swi */
3414 gen_op_movl_T0_im((long)s->pc | 1);
3415 /* Don't set r15. */
3416 gen_op_movl_reg_TN[0][15]();
3417 gen_op_swi();
3418 s->is_jmp = DISAS_JUMP;
3419 break;
3420 }
3421 /* generate a conditional jump to next instruction */
e50e6a20
FB
3422 s->condlabel = gen_new_label();
3423 gen_test_cc[cond ^ 1](s->condlabel);
3424 s->condjmp = 1;
3425 //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
3426 //s->is_jmp = DISAS_JUMP_NEXT;
99c475ab
FB
3427 gen_movl_T1_reg(s, 15);
3428
3429 /* jump to the offset */
5899f386 3430 val = (uint32_t)s->pc + 2;
99c475ab 3431 offset = ((int32_t)insn << 24) >> 24;
5899f386 3432 val += offset << 1;
8aaca4c0 3433 gen_jmp(s, val);
99c475ab
FB
3434 break;
3435
3436 case 14:
3437 /* unconditional branch */
358bf29e
PB
3438 if (insn & (1 << 11)) {
3439 /* Second half of blx. */
3440 offset = ((insn & 0x7ff) << 1);
3441 gen_movl_T0_reg(s, 14);
3442 gen_op_movl_T1_im(offset);
3443 gen_op_addl_T0_T1();
3444 gen_op_movl_T1_im(0xfffffffc);
3445 gen_op_andl_T0_T1();
3446
3447 val = (uint32_t)s->pc;
3448 gen_op_movl_T1_im(val | 1);
3449 gen_movl_reg_T1(s, 14);
3450 gen_bx(s);
3451 break;
3452 }
99c475ab
FB
3453 val = (uint32_t)s->pc;
3454 offset = ((int32_t)insn << 21) >> 21;
3455 val += (offset << 1) + 2;
8aaca4c0 3456 gen_jmp(s, val);
99c475ab
FB
3457 break;
3458
3459 case 15:
3460 /* branch and link [and switch to arm] */
358bf29e
PB
3461 if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
3462 /* Instruction spans a page boundary. Implement it as two
3463 16-bit instructions in case the second half causes an
3464 prefetch abort. */
3465 offset = ((int32_t)insn << 21) >> 9;
3466 val = s->pc + 2 + offset;
3467 gen_op_movl_T0_im(val);
3468 gen_movl_reg_T0(s, 14);
3469 break;
3470 }
3471 if (insn & (1 << 11)) {
3472 /* Second half of bl. */
3473 offset = ((insn & 0x7ff) << 1) | 1;
3474 gen_movl_T0_reg(s, 14);
3475 gen_op_movl_T1_im(offset);
3476 gen_op_addl_T0_T1();
3477
3478 val = (uint32_t)s->pc;
3479 gen_op_movl_T1_im(val | 1);
3480 gen_movl_reg_T1(s, 14);
3481 gen_bx(s);
3482 break;
3483 }
99c475ab 3484 offset = ((int32_t)insn << 21) >> 10;
b5ff1b31 3485 insn = lduw_code(s->pc);
99c475ab
FB
3486 offset |= insn & 0x7ff;
3487
3488 val = (uint32_t)s->pc + 2;
3489 gen_op_movl_T1_im(val | 1);
3490 gen_movl_reg_T1(s, 14);
3491
5899f386 3492 val += offset << 1;
2531fc7b 3493 if (insn & (1 << 12)) {
99c475ab 3494 /* bl */
8aaca4c0 3495 gen_jmp(s, val);
99c475ab
FB
3496 } else {
3497 /* blx */
5899f386 3498 val &= ~(uint32_t)2;
99c475ab
FB
3499 gen_op_movl_T0_im(val);
3500 gen_bx(s);
3501 }
3502 }
3503 return;
3504undef:
5899f386 3505 gen_op_movl_T0_im((long)s->pc - 2);
99c475ab
FB
3506 gen_op_movl_reg_TN[0][15]();
3507 gen_op_undef_insn();
3508 s->is_jmp = DISAS_JUMP;
3509}
3510
2c0262af
FB
3511/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
3512 basic block 'tb'. If search_pc is TRUE, also generate PC
3513 information for each intermediate instruction. */
3514static inline int gen_intermediate_code_internal(CPUState *env,
3515 TranslationBlock *tb,
3516 int search_pc)
3517{
3518 DisasContext dc1, *dc = &dc1;
3519 uint16_t *gen_opc_end;
3520 int j, lj;
0fa85d43 3521 target_ulong pc_start;
b5ff1b31 3522 uint32_t next_page_start;
2c0262af
FB
3523
3524 /* generate intermediate code */
0fa85d43 3525 pc_start = tb->pc;
2c0262af
FB
3526
3527 dc->tb = tb;
3528
3529 gen_opc_ptr = gen_opc_buf;
3530 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
3531 gen_opparam_ptr = gen_opparam_buf;
3532
3533 dc->is_jmp = DISAS_NEXT;
3534 dc->pc = pc_start;
8aaca4c0 3535 dc->singlestep_enabled = env->singlestep_enabled;
e50e6a20 3536 dc->condjmp = 0;
5899f386 3537 dc->thumb = env->thumb;
6658ffb8 3538 dc->is_mem = 0;
b5ff1b31
FB
3539#if !defined(CONFIG_USER_ONLY)
3540 dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
3541#endif
3542 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
e50e6a20 3543 nb_gen_labels = 0;
2c0262af
FB
3544 lj = -1;
3545 do {
1fddef4b
FB
3546 if (env->nb_breakpoints > 0) {
3547 for(j = 0; j < env->nb_breakpoints; j++) {
3548 if (env->breakpoints[j] == dc->pc) {
3549 gen_op_movl_T0_im((long)dc->pc);
3550 gen_op_movl_reg_TN[0][15]();
3551 gen_op_debug();
3552 dc->is_jmp = DISAS_JUMP;
3553 break;
3554 }
3555 }
3556 }
2c0262af
FB
3557 if (search_pc) {
3558 j = gen_opc_ptr - gen_opc_buf;
3559 if (lj < j) {
3560 lj++;
3561 while (lj < j)
3562 gen_opc_instr_start[lj++] = 0;
3563 }
0fa85d43 3564 gen_opc_pc[lj] = dc->pc;
2c0262af
FB
3565 gen_opc_instr_start[lj] = 1;
3566 }
e50e6a20 3567
99c475ab
FB
3568 if (env->thumb)
3569 disas_thumb_insn(dc);
3570 else
b7bcbe95 3571 disas_arm_insn(env, dc);
e50e6a20
FB
3572
3573 if (dc->condjmp && !dc->is_jmp) {
3574 gen_set_label(dc->condlabel);
3575 dc->condjmp = 0;
3576 }
6658ffb8
PB
3577 /* Terminate the TB on memory ops if watchpoints are present. */
3578 /* FIXME: This should be replacd by the deterministic execution
3579 * IRQ raising bits. */
3580 if (dc->is_mem && env->nb_watchpoints)
3581 break;
3582
e50e6a20
FB
3583 /* Translation stops when a conditional branch is enoutered.
3584 * Otherwise the subsequent code could get translated several times.
b5ff1b31
FB
3585 * Also stop translation when a page boundary is reached. This
3586 * ensures prefech aborts occur at the right place. */
1fddef4b
FB
3587 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
3588 !env->singlestep_enabled &&
b5ff1b31
FB
3589 dc->pc < next_page_start);
3590 /* At this stage dc->condjmp will only be set when the skipped
3591 * instruction was a conditional branch, and the PC has already been
e50e6a20 3592 * written. */
8aaca4c0
FB
3593 if (__builtin_expect(env->singlestep_enabled, 0)) {
3594 /* Make sure the pc is updated, and raise a debug exception. */
e50e6a20
FB
3595 if (dc->condjmp) {
3596 gen_op_debug();
3597 gen_set_label(dc->condlabel);
3598 }
3599 if (dc->condjmp || !dc->is_jmp) {
8aaca4c0
FB
3600 gen_op_movl_T0_im((long)dc->pc);
3601 gen_op_movl_reg_TN[0][15]();
e50e6a20 3602 dc->condjmp = 0;
8aaca4c0
FB
3603 }
3604 gen_op_debug();
3605 } else {
3606 switch(dc->is_jmp) {
8aaca4c0 3607 case DISAS_NEXT:
6e256c93 3608 gen_goto_tb(dc, 1, dc->pc);
8aaca4c0
FB
3609 break;
3610 default:
3611 case DISAS_JUMP:
3612 case DISAS_UPDATE:
3613 /* indicate that the hash table must be used to find the next TB */
3614 gen_op_movl_T0_0();
3615 gen_op_exit_tb();
3616 break;
3617 case DISAS_TB_JUMP:
3618 /* nothing more to generate */
3619 break;
3620 }
e50e6a20
FB
3621 if (dc->condjmp) {
3622 gen_set_label(dc->condlabel);
6e256c93 3623 gen_goto_tb(dc, 1, dc->pc);
e50e6a20
FB
3624 dc->condjmp = 0;
3625 }
2c0262af
FB
3626 }
3627 *gen_opc_ptr = INDEX_op_end;
3628
3629#ifdef DEBUG_DISAS
e19e89a5 3630 if (loglevel & CPU_LOG_TB_IN_ASM) {
2c0262af
FB
3631 fprintf(logfile, "----------------\n");
3632 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
5899f386 3633 target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
2c0262af 3634 fprintf(logfile, "\n");
e19e89a5
FB
3635 if (loglevel & (CPU_LOG_TB_OP)) {
3636 fprintf(logfile, "OP:\n");
3637 dump_ops(gen_opc_buf, gen_opparam_buf);
3638 fprintf(logfile, "\n");
3639 }
2c0262af
FB
3640 }
3641#endif
b5ff1b31
FB
3642 if (search_pc) {
3643 j = gen_opc_ptr - gen_opc_buf;
3644 lj++;
3645 while (lj <= j)
3646 gen_opc_instr_start[lj++] = 0;
3647 tb->size = 0;
3648 } else {
2c0262af 3649 tb->size = dc->pc - pc_start;
b5ff1b31 3650 }
2c0262af
FB
3651 return 0;
3652}
3653
3654int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
3655{
3656 return gen_intermediate_code_internal(env, tb, 0);
3657}
3658
3659int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
3660{
3661 return gen_intermediate_code_internal(env, tb, 1);
3662}
3663
b5ff1b31
FB
3664static const char *cpu_mode_names[16] = {
3665 "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
3666 "???", "???", "???", "und", "???", "???", "???", "sys"
3667};
7fe48483
FB
3668void cpu_dump_state(CPUState *env, FILE *f,
3669 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
3670 int flags)
2c0262af
FB
3671{
3672 int i;
bc380d17 3673 union {
b7bcbe95
FB
3674 uint32_t i;
3675 float s;
3676 } s0, s1;
3677 CPU_DoubleU d;
a94a6abf
PB
3678 /* ??? This assumes float64 and double have the same layout.
3679 Oh well, it's only debug dumps. */
3680 union {
3681 float64 f64;
3682 double d;
3683 } d0;
b5ff1b31 3684 uint32_t psr;
2c0262af
FB
3685
3686 for(i=0;i<16;i++) {
7fe48483 3687 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
2c0262af 3688 if ((i % 4) == 3)
7fe48483 3689 cpu_fprintf(f, "\n");
2c0262af 3690 else
7fe48483 3691 cpu_fprintf(f, " ");
2c0262af 3692 }
b5ff1b31 3693 psr = cpsr_read(env);
687fa640
TS
3694 cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
3695 psr,
b5ff1b31
FB
3696 psr & (1 << 31) ? 'N' : '-',
3697 psr & (1 << 30) ? 'Z' : '-',
3698 psr & (1 << 29) ? 'C' : '-',
3699 psr & (1 << 28) ? 'V' : '-',
3700 psr & CPSR_T ? 'T' : 'A',
3701 cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
b7bcbe95
FB
3702
3703 for (i = 0; i < 16; i++) {
8e96005d
FB
3704 d.d = env->vfp.regs[i];
3705 s0.i = d.l.lower;
3706 s1.i = d.l.upper;
a94a6abf
PB
3707 d0.f64 = d.d;
3708 cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
b7bcbe95 3709 i * 2, (int)s0.i, s0.s,
a94a6abf 3710 i * 2 + 1, (int)s1.i, s1.s,
b7bcbe95 3711 i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
a94a6abf 3712 d0.d);
b7bcbe95 3713 }
40f137e1 3714 cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
2c0262af 3715}
a6b025d3 3716