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