]> git.proxmox.com Git - qemu.git/blame - target-arm/translate.c
WIn32 compile fix.
[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
529 dp = ((insn & 0xf00) == 0xb00);
530 switch ((insn >> 24) & 0xf) {
531 case 0xe:
532 if (insn & (1 << 4)) {
533 /* single register transfer */
534 if ((insn & 0x6f) != 0x00)
535 return 1;
536 rd = (insn >> 12) & 0xf;
537 if (dp) {
538 if (insn & 0x80)
539 return 1;
540 rn = (insn >> 16) & 0xf;
541 /* Get the existing value even for arm->vfp moves because
542 we only set half the register. */
543 gen_mov_F0_vreg(1, rn);
544 gen_op_vfp_mrrd();
545 if (insn & (1 << 20)) {
546 /* vfp->arm */
547 if (insn & (1 << 21))
548 gen_movl_reg_T1(s, rd);
549 else
550 gen_movl_reg_T0(s, rd);
551 } else {
552 /* arm->vfp */
553 if (insn & (1 << 21))
554 gen_movl_T1_reg(s, rd);
555 else
556 gen_movl_T0_reg(s, rd);
557 gen_op_vfp_mdrr();
558 gen_mov_vreg_F0(dp, rn);
559 }
560 } else {
561 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
562 if (insn & (1 << 20)) {
563 /* vfp->arm */
564 if (insn & (1 << 21)) {
565 /* system register */
566 switch (rn) {
567 case 0: /* fpsid */
568 n = 0x0091A0000;
569 break;
570 case 2: /* fpscr */
571 if (rd == 15)
572 gen_op_vfp_movl_T0_fpscr_flags();
573 else
574 gen_op_vfp_movl_T0_fpscr();
575 break;
576 default:
577 return 1;
578 }
579 } else {
580 gen_mov_F0_vreg(0, rn);
581 gen_op_vfp_mrs();
582 }
583 if (rd == 15) {
b5ff1b31
FB
584 /* Set the 4 flag bits in the CPSR. */
585 gen_op_movl_cpsr_T0(0xf0000000);
b7bcbe95
FB
586 } else
587 gen_movl_reg_T0(s, rd);
588 } else {
589 /* arm->vfp */
590 gen_movl_T0_reg(s, rd);
591 if (insn & (1 << 21)) {
592 /* system register */
593 switch (rn) {
594 case 0: /* fpsid */
595 /* Writes are ignored. */
596 break;
597 case 2: /* fpscr */
598 gen_op_vfp_movl_fpscr_T0();
599 /* This could change vector settings, so jump to
600 the next instuction. */
b5ff1b31 601 gen_lookup_tb(s);
b7bcbe95
FB
602 break;
603 default:
604 return 1;
605 }
606 } else {
607 gen_op_vfp_msr();
608 gen_mov_vreg_F0(0, rn);
609 }
610 }
611 }
612 } else {
613 /* data processing */
614 /* The opcode is in bits 23, 21, 20 and 6. */
615 op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
616 if (dp) {
617 if (op == 15) {
618 /* rn is opcode */
619 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
620 } else {
621 /* rn is register number */
622 if (insn & (1 << 7))
623 return 1;
624 rn = (insn >> 16) & 0xf;
625 }
626
627 if (op == 15 && (rn == 15 || rn > 17)) {
628 /* Integer or single precision destination. */
629 rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
630 } else {
631 if (insn & (1 << 22))
632 return 1;
633 rd = (insn >> 12) & 0xf;
634 }
635
636 if (op == 15 && (rn == 16 || rn == 17)) {
637 /* Integer source. */
638 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
639 } else {
640 if (insn & (1 << 5))
641 return 1;
642 rm = insn & 0xf;
643 }
644 } else {
645 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
646 if (op == 15 && rn == 15) {
647 /* Double precision destination. */
648 if (insn & (1 << 22))
649 return 1;
650 rd = (insn >> 12) & 0xf;
651 } else
652 rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
653 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
654 }
655
656 veclen = env->vfp.vec_len;
657 if (op == 15 && rn > 3)
658 veclen = 0;
659
660 /* Shut up compiler warnings. */
661 delta_m = 0;
662 delta_d = 0;
663 bank_mask = 0;
664
665 if (veclen > 0) {
666 if (dp)
667 bank_mask = 0xc;
668 else
669 bank_mask = 0x18;
670
671 /* Figure out what type of vector operation this is. */
672 if ((rd & bank_mask) == 0) {
673 /* scalar */
674 veclen = 0;
675 } else {
676 if (dp)
677 delta_d = (env->vfp.vec_stride >> 1) + 1;
678 else
679 delta_d = env->vfp.vec_stride + 1;
680
681 if ((rm & bank_mask) == 0) {
682 /* mixed scalar/vector */
683 delta_m = 0;
684 } else {
685 /* vector */
686 delta_m = delta_d;
687 }
688 }
689 }
690
691 /* Load the initial operands. */
692 if (op == 15) {
693 switch (rn) {
694 case 16:
695 case 17:
696 /* Integer source */
697 gen_mov_F0_vreg(0, rm);
698 break;
699 case 8:
700 case 9:
701 /* Compare */
702 gen_mov_F0_vreg(dp, rd);
703 gen_mov_F1_vreg(dp, rm);
704 break;
705 case 10:
706 case 11:
707 /* Compare with zero */
708 gen_mov_F0_vreg(dp, rd);
709 gen_vfp_F1_ld0(dp);
710 break;
711 default:
712 /* One source operand. */
713 gen_mov_F0_vreg(dp, rm);
714 }
715 } else {
716 /* Two source operands. */
717 gen_mov_F0_vreg(dp, rn);
718 gen_mov_F1_vreg(dp, rm);
719 }
720
721 for (;;) {
722 /* Perform the calculation. */
723 switch (op) {
724 case 0: /* mac: fd + (fn * fm) */
725 gen_vfp_mul(dp);
726 gen_mov_F1_vreg(dp, rd);
727 gen_vfp_add(dp);
728 break;
729 case 1: /* nmac: fd - (fn * fm) */
730 gen_vfp_mul(dp);
731 gen_vfp_neg(dp);
732 gen_mov_F1_vreg(dp, rd);
733 gen_vfp_add(dp);
734 break;
735 case 2: /* msc: -fd + (fn * fm) */
736 gen_vfp_mul(dp);
737 gen_mov_F1_vreg(dp, rd);
738 gen_vfp_sub(dp);
739 break;
740 case 3: /* nmsc: -fd - (fn * fm) */
741 gen_vfp_mul(dp);
742 gen_mov_F1_vreg(dp, rd);
743 gen_vfp_add(dp);
744 gen_vfp_neg(dp);
745 break;
746 case 4: /* mul: fn * fm */
747 gen_vfp_mul(dp);
748 break;
749 case 5: /* nmul: -(fn * fm) */
750 gen_vfp_mul(dp);
751 gen_vfp_neg(dp);
752 break;
753 case 6: /* add: fn + fm */
754 gen_vfp_add(dp);
755 break;
756 case 7: /* sub: fn - fm */
757 gen_vfp_sub(dp);
758 break;
759 case 8: /* div: fn / fm */
760 gen_vfp_div(dp);
761 break;
762 case 15: /* extension space */
763 switch (rn) {
764 case 0: /* cpy */
765 /* no-op */
766 break;
767 case 1: /* abs */
768 gen_vfp_abs(dp);
769 break;
770 case 2: /* neg */
771 gen_vfp_neg(dp);
772 break;
773 case 3: /* sqrt */
774 gen_vfp_sqrt(dp);
775 break;
776 case 8: /* cmp */
777 gen_vfp_cmp(dp);
778 break;
779 case 9: /* cmpe */
780 gen_vfp_cmpe(dp);
781 break;
782 case 10: /* cmpz */
783 gen_vfp_cmp(dp);
784 break;
785 case 11: /* cmpez */
786 gen_vfp_F1_ld0(dp);
787 gen_vfp_cmpe(dp);
788 break;
789 case 15: /* single<->double conversion */
790 if (dp)
791 gen_op_vfp_fcvtsd();
792 else
793 gen_op_vfp_fcvtds();
794 break;
795 case 16: /* fuito */
796 gen_vfp_uito(dp);
797 break;
798 case 17: /* fsito */
799 gen_vfp_sito(dp);
800 break;
801 case 24: /* ftoui */
802 gen_vfp_toui(dp);
803 break;
804 case 25: /* ftouiz */
805 gen_vfp_touiz(dp);
806 break;
807 case 26: /* ftosi */
808 gen_vfp_tosi(dp);
809 break;
810 case 27: /* ftosiz */
811 gen_vfp_tosiz(dp);
812 break;
813 default: /* undefined */
814 printf ("rn:%d\n", rn);
815 return 1;
816 }
817 break;
818 default: /* undefined */
819 printf ("op:%d\n", op);
820 return 1;
821 }
822
823 /* Write back the result. */
824 if (op == 15 && (rn >= 8 && rn <= 11))
825 ; /* Comparison, do nothing. */
826 else if (op == 15 && rn > 17)
827 /* Integer result. */
828 gen_mov_vreg_F0(0, rd);
829 else if (op == 15 && rn == 15)
830 /* conversion */
831 gen_mov_vreg_F0(!dp, rd);
832 else
833 gen_mov_vreg_F0(dp, rd);
834
835 /* break out of the loop if we have finished */
836 if (veclen == 0)
837 break;
838
839 if (op == 15 && delta_m == 0) {
840 /* single source one-many */
841 while (veclen--) {
842 rd = ((rd + delta_d) & (bank_mask - 1))
843 | (rd & bank_mask);
844 gen_mov_vreg_F0(dp, rd);
845 }
846 break;
847 }
848 /* Setup the next operands. */
849 veclen--;
850 rd = ((rd + delta_d) & (bank_mask - 1))
851 | (rd & bank_mask);
852
853 if (op == 15) {
854 /* One source operand. */
855 rm = ((rm + delta_m) & (bank_mask - 1))
856 | (rm & bank_mask);
857 gen_mov_F0_vreg(dp, rm);
858 } else {
859 /* Two source operands. */
860 rn = ((rn + delta_d) & (bank_mask - 1))
861 | (rn & bank_mask);
862 gen_mov_F0_vreg(dp, rn);
863 if (delta_m) {
864 rm = ((rm + delta_m) & (bank_mask - 1))
865 | (rm & bank_mask);
866 gen_mov_F1_vreg(dp, rm);
867 }
868 }
869 }
870 }
871 break;
872 case 0xc:
873 case 0xd:
874 if (dp && (insn & (1 << 22))) {
875 /* two-register transfer */
876 rn = (insn >> 16) & 0xf;
877 rd = (insn >> 12) & 0xf;
878 if (dp) {
879 if (insn & (1 << 5))
880 return 1;
881 rm = insn & 0xf;
882 } else
883 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
884
885 if (insn & (1 << 20)) {
886 /* vfp->arm */
887 if (dp) {
888 gen_mov_F0_vreg(1, rm);
889 gen_op_vfp_mrrd();
890 gen_movl_reg_T0(s, rd);
891 gen_movl_reg_T1(s, rn);
892 } else {
893 gen_mov_F0_vreg(0, rm);
894 gen_op_vfp_mrs();
895 gen_movl_reg_T0(s, rn);
896 gen_mov_F0_vreg(0, rm + 1);
897 gen_op_vfp_mrs();
898 gen_movl_reg_T0(s, rd);
899 }
900 } else {
901 /* arm->vfp */
902 if (dp) {
903 gen_movl_T0_reg(s, rd);
904 gen_movl_T1_reg(s, rn);
905 gen_op_vfp_mdrr();
906 gen_mov_vreg_F0(1, rm);
907 } else {
908 gen_movl_T0_reg(s, rn);
909 gen_op_vfp_msr();
910 gen_mov_vreg_F0(0, rm);
911 gen_movl_T0_reg(s, rd);
912 gen_op_vfp_msr();
913 gen_mov_vreg_F0(0, rm + 1);
914 }
915 }
916 } else {
917 /* Load/store */
918 rn = (insn >> 16) & 0xf;
919 if (dp)
920 rd = (insn >> 12) & 0xf;
921 else
922 rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
923 gen_movl_T1_reg(s, rn);
924 if ((insn & 0x01200000) == 0x01000000) {
925 /* Single load/store */
926 offset = (insn & 0xff) << 2;
927 if ((insn & (1 << 23)) == 0)
928 offset = -offset;
929 gen_op_addl_T1_im(offset);
930 if (insn & (1 << 20)) {
b5ff1b31 931 gen_vfp_ld(s, dp);
b7bcbe95
FB
932 gen_mov_vreg_F0(dp, rd);
933 } else {
934 gen_mov_F0_vreg(dp, rd);
b5ff1b31 935 gen_vfp_st(s, dp);
b7bcbe95
FB
936 }
937 } else {
938 /* load/store multiple */
939 if (dp)
940 n = (insn >> 1) & 0x7f;
941 else
942 n = insn & 0xff;
943
944 if (insn & (1 << 24)) /* pre-decrement */
945 gen_op_addl_T1_im(-((insn & 0xff) << 2));
946
947 if (dp)
948 offset = 8;
949 else
950 offset = 4;
951 for (i = 0; i < n; i++) {
952 if (insn & (1 << 20)) {
953 /* load */
b5ff1b31 954 gen_vfp_ld(s, dp);
b7bcbe95
FB
955 gen_mov_vreg_F0(dp, rd + i);
956 } else {
957 /* store */
958 gen_mov_F0_vreg(dp, rd + i);
b5ff1b31 959 gen_vfp_st(s, dp);
b7bcbe95
FB
960 }
961 gen_op_addl_T1_im(offset);
962 }
963 if (insn & (1 << 21)) {
964 /* writeback */
965 if (insn & (1 << 24))
966 offset = -offset * n;
967 else if (dp && (insn & 1))
968 offset = 4;
969 else
970 offset = 0;
971
972 if (offset != 0)
973 gen_op_addl_T1_im(offset);
974 gen_movl_reg_T1(s, rn);
975 }
976 }
977 }
978 break;
979 default:
980 /* Should never happen. */
981 return 1;
982 }
983 return 0;
984}
985
6e256c93 986static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
c53be334 987{
6e256c93
FB
988 TranslationBlock *tb;
989
990 tb = s->tb;
991 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
992 if (n == 0)
993 gen_op_goto_tb0(TBPARAM(tb));
994 else
995 gen_op_goto_tb1(TBPARAM(tb));
996 gen_op_movl_T0_im(dest);
997 gen_op_movl_r15_T0();
998 gen_op_movl_T0_im((long)tb + n);
999 gen_op_exit_tb();
1000 } else {
1001 gen_op_movl_T0_im(dest);
1002 gen_op_movl_r15_T0();
1003 gen_op_movl_T0_0();
1004 gen_op_exit_tb();
1005 }
c53be334
FB
1006}
1007
8aaca4c0
FB
1008static inline void gen_jmp (DisasContext *s, uint32_t dest)
1009{
1010 if (__builtin_expect(s->singlestep_enabled, 0)) {
1011 /* An indirect jump so that we still trigger the debug exception. */
5899f386
FB
1012 if (s->thumb)
1013 dest |= 1;
8aaca4c0
FB
1014 gen_op_movl_T0_im(dest);
1015 gen_bx(s);
1016 } else {
6e256c93 1017 gen_goto_tb(s, 0, dest);
8aaca4c0
FB
1018 s->is_jmp = DISAS_TB_JUMP;
1019 }
1020}
1021
b5ff1b31
FB
1022static inline void gen_mulxy(int x, int y)
1023{
ee097184 1024 if (x)
b5ff1b31
FB
1025 gen_op_sarl_T0_im(16);
1026 else
1027 gen_op_sxth_T0();
ee097184 1028 if (y)
b5ff1b31
FB
1029 gen_op_sarl_T1_im(16);
1030 else
1031 gen_op_sxth_T1();
1032 gen_op_mul_T0_T1();
1033}
1034
1035/* Return the mask of PSR bits set by a MSR instruction. */
2ae23e75 1036static uint32_t msr_mask(DisasContext *s, int flags, int spsr) {
b5ff1b31
FB
1037 uint32_t mask;
1038
1039 mask = 0;
1040 if (flags & (1 << 0))
1041 mask |= 0xff;
1042 if (flags & (1 << 1))
1043 mask |= 0xff00;
1044 if (flags & (1 << 2))
1045 mask |= 0xff0000;
1046 if (flags & (1 << 3))
1047 mask |= 0xff000000;
2ae23e75
PB
1048 /* Mask out undefined bits. */
1049 mask &= 0xf90f03ff;
1050 /* Mask out state bits. */
1051 if (!spsr)
1052 mask &= ~0x01000020;
b5ff1b31
FB
1053 /* Mask out privileged bits. */
1054 if (IS_USER(s))
1055 mask &= 0xf80f0200;
1056 return mask;
1057}
1058
1059/* Returns nonzero if access to the PSR is not permitted. */
1060static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr)
1061{
1062 if (spsr) {
1063 /* ??? This is also undefined in system mode. */
1064 if (IS_USER(s))
1065 return 1;
1066 gen_op_movl_spsr_T0(mask);
1067 } else {
1068 gen_op_movl_cpsr_T0(mask);
1069 }
1070 gen_lookup_tb(s);
1071 return 0;
1072}
1073
1074static void gen_exception_return(DisasContext *s)
1075{
1076 gen_op_movl_reg_TN[0][15]();
1077 gen_op_movl_T0_spsr();
1078 gen_op_movl_cpsr_T0(0xffffffff);
1079 s->is_jmp = DISAS_UPDATE;
1080}
1081
b7bcbe95 1082static void disas_arm_insn(CPUState * env, DisasContext *s)
2c0262af
FB
1083{
1084 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
1085
b5ff1b31 1086 insn = ldl_code(s->pc);
2c0262af
FB
1087 s->pc += 4;
1088
1089 cond = insn >> 28;
99c475ab 1090 if (cond == 0xf){
b7bcbe95 1091 /* Unconditional instructions. */
99c475ab
FB
1092 if ((insn & 0x0d70f000) == 0x0550f000)
1093 return; /* PLD */
1094 else if ((insn & 0x0e000000) == 0x0a000000) {
1095 /* branch link and change to thumb (blx <offset>) */
1096 int32_t offset;
1097
1098 val = (uint32_t)s->pc;
1099 gen_op_movl_T0_im(val);
1100 gen_movl_reg_T0(s, 14);
1101 /* Sign-extend the 24-bit offset */
1102 offset = (((int32_t)insn) << 8) >> 8;
1103 /* offset * 4 + bit24 * 2 + (thumb bit) */
1104 val += (offset << 2) | ((insn >> 23) & 2) | 1;
1105 /* pipeline offset */
1106 val += 4;
1107 gen_op_movl_T0_im(val);
1108 gen_bx(s);
1109 return;
b7bcbe95
FB
1110 } else if ((insn & 0x0fe00000) == 0x0c400000) {
1111 /* Coprocessor double register transfer. */
1112 } else if ((insn & 0x0f000010) == 0x0e000010) {
1113 /* Additional coprocessor register transfer. */
b5ff1b31
FB
1114 } else if ((insn & 0x0ff10010) == 0x01000000) {
1115 /* cps (privileged) */
1116 } else if ((insn & 0x0ffffdff) == 0x01010000) {
1117 /* setend */
1118 if (insn & (1 << 9)) {
1119 /* BE8 mode not implemented. */
1120 goto illegal_op;
1121 }
1122 return;
99c475ab 1123 }
2c0262af 1124 goto illegal_op;
99c475ab 1125 }
2c0262af
FB
1126 if (cond != 0xe) {
1127 /* if not always execute, we generate a conditional jump to
1128 next instruction */
e50e6a20
FB
1129 s->condlabel = gen_new_label();
1130 gen_test_cc[cond ^ 1](s->condlabel);
1131 s->condjmp = 1;
1132 //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
1133 //s->is_jmp = DISAS_JUMP_NEXT;
2c0262af 1134 }
99c475ab 1135 if ((insn & 0x0f900000) == 0x03000000) {
b5ff1b31 1136 if ((insn & 0x0fb0f000) != 0x0320f000)
99c475ab
FB
1137 goto illegal_op;
1138 /* CPSR = immediate */
1139 val = insn & 0xff;
1140 shift = ((insn >> 8) & 0xf) * 2;
1141 if (shift)
1142 val = (val >> shift) | (val << (32 - shift));
1143 gen_op_movl_T0_im(val);
2ae23e75
PB
1144 i = ((insn & (1 << 22)) != 0);
1145 if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
b5ff1b31 1146 goto illegal_op;
99c475ab
FB
1147 } else if ((insn & 0x0f900000) == 0x01000000
1148 && (insn & 0x00000090) != 0x00000090) {
1149 /* miscellaneous instructions */
1150 op1 = (insn >> 21) & 3;
1151 sh = (insn >> 4) & 0xf;
1152 rm = insn & 0xf;
1153 switch (sh) {
1154 case 0x0: /* move program status register */
99c475ab 1155 if (op1 & 1) {
b5ff1b31 1156 /* PSR = reg */
99c475ab 1157 gen_movl_T0_reg(s, rm);
2ae23e75
PB
1158 i = ((op1 & 2) != 0);
1159 if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
b5ff1b31 1160 goto illegal_op;
99c475ab 1161 } else {
2ae23e75 1162 /* reg = PSR */
99c475ab 1163 rd = (insn >> 12) & 0xf;
b5ff1b31
FB
1164 if (op1 & 2) {
1165 if (IS_USER(s))
1166 goto illegal_op;
1167 gen_op_movl_T0_spsr();
1168 } else {
1169 gen_op_movl_T0_cpsr();
1170 }
99c475ab
FB
1171 gen_movl_reg_T0(s, rd);
1172 }
b8a9e8f1 1173 break;
99c475ab
FB
1174 case 0x1:
1175 if (op1 == 1) {
1176 /* branch/exchange thumb (bx). */
1177 gen_movl_T0_reg(s, rm);
1178 gen_bx(s);
1179 } else if (op1 == 3) {
1180 /* clz */
1181 rd = (insn >> 12) & 0xf;
1182 gen_movl_T0_reg(s, rm);
1183 gen_op_clz_T0();
1184 gen_movl_reg_T0(s, rd);
1185 } else {
1186 goto illegal_op;
1187 }
1188 break;
b5ff1b31
FB
1189 case 0x2:
1190 if (op1 == 1) {
1191 ARCH(5J); /* bxj */
1192 /* Trivial implementation equivalent to bx. */
1193 gen_movl_T0_reg(s, rm);
1194 gen_bx(s);
1195 } else {
1196 goto illegal_op;
1197 }
1198 break;
99c475ab
FB
1199 case 0x3:
1200 if (op1 != 1)
1201 goto illegal_op;
1202
1203 /* branch link/exchange thumb (blx) */
1204 val = (uint32_t)s->pc;
1205 gen_op_movl_T0_im(val);
1206 gen_movl_reg_T0(s, 14);
1207 gen_movl_T0_reg(s, rm);
1208 gen_bx(s);
1209 break;
1210 case 0x5: /* saturating add/subtract */
1211 rd = (insn >> 12) & 0xf;
1212 rn = (insn >> 16) & 0xf;
ff8263a9
FB
1213 gen_movl_T0_reg(s, rm);
1214 gen_movl_T1_reg(s, rn);
1215 if (op1 & 2)
1216 gen_op_double_T1_saturate();
99c475ab
FB
1217 if (op1 & 1)
1218 gen_op_subl_T0_T1_saturate();
1219 else
1220 gen_op_addl_T0_T1_saturate();
ff8263a9 1221 gen_movl_reg_T0(s, rd);
99c475ab 1222 break;
06c949e6
PB
1223 case 7: /* bkpt */
1224 gen_op_movl_T0_im((long)s->pc - 4);
1225 gen_op_movl_reg_TN[0][15]();
1226 gen_op_bkpt();
1227 s->is_jmp = DISAS_JUMP;
1228 break;
99c475ab
FB
1229 case 0x8: /* signed multiply */
1230 case 0xa:
1231 case 0xc:
1232 case 0xe:
1233 rs = (insn >> 8) & 0xf;
1234 rn = (insn >> 12) & 0xf;
1235 rd = (insn >> 16) & 0xf;
1236 if (op1 == 1) {
1237 /* (32 * 16) >> 16 */
1238 gen_movl_T0_reg(s, rm);
1239 gen_movl_T1_reg(s, rs);
1240 if (sh & 4)
1241 gen_op_sarl_T1_im(16);
1242 else
b5ff1b31 1243 gen_op_sxth_T1();
99c475ab
FB
1244 gen_op_imulw_T0_T1();
1245 if ((sh & 2) == 0) {
1246 gen_movl_T1_reg(s, rn);
1247 gen_op_addl_T0_T1_setq();
1248 }
1249 gen_movl_reg_T0(s, rd);
1250 } else {
1251 /* 16 * 16 */
1252 gen_movl_T0_reg(s, rm);
99c475ab 1253 gen_movl_T1_reg(s, rs);
b5ff1b31 1254 gen_mulxy(sh & 2, sh & 4);
99c475ab 1255 if (op1 == 2) {
b5ff1b31 1256 gen_op_signbit_T1_T0();
99c475ab
FB
1257 gen_op_addq_T0_T1(rn, rd);
1258 gen_movl_reg_T0(s, rn);
1259 gen_movl_reg_T1(s, rd);
1260 } else {
99c475ab
FB
1261 if (op1 == 0) {
1262 gen_movl_T1_reg(s, rn);
1263 gen_op_addl_T0_T1_setq();
1264 }
1265 gen_movl_reg_T0(s, rd);
1266 }
1267 }
1268 break;
1269 default:
1270 goto illegal_op;
1271 }
1272 } else if (((insn & 0x0e000000) == 0 &&
1273 (insn & 0x00000090) != 0x90) ||
1274 ((insn & 0x0e000000) == (1 << 25))) {
2c0262af
FB
1275 int set_cc, logic_cc, shiftop;
1276
1277 op1 = (insn >> 21) & 0xf;
1278 set_cc = (insn >> 20) & 1;
1279 logic_cc = table_logic_cc[op1] & set_cc;
1280
1281 /* data processing instruction */
1282 if (insn & (1 << 25)) {
1283 /* immediate operand */
1284 val = insn & 0xff;
1285 shift = ((insn >> 8) & 0xf) * 2;
1286 if (shift)
1287 val = (val >> shift) | (val << (32 - shift));
1288 gen_op_movl_T1_im(val);
7ff4d218
FB
1289 if (logic_cc && shift)
1290 gen_op_mov_CF_T1();
2c0262af
FB
1291 } else {
1292 /* register */
1293 rm = (insn) & 0xf;
1294 gen_movl_T1_reg(s, rm);
1295 shiftop = (insn >> 5) & 3;
1296 if (!(insn & (1 << 4))) {
1297 shift = (insn >> 7) & 0x1f;
1298 if (shift != 0) {
1299 if (logic_cc) {
1300 gen_shift_T1_im_cc[shiftop](shift);
1301 } else {
1302 gen_shift_T1_im[shiftop](shift);
1303 }
1e8d4eec
FB
1304 } else if (shiftop != 0) {
1305 if (logic_cc) {
1306 gen_shift_T1_0_cc[shiftop]();
1307 } else {
1308 gen_shift_T1_0[shiftop]();
1309 }
2c0262af
FB
1310 }
1311 } else {
1312 rs = (insn >> 8) & 0xf;
1313 gen_movl_T0_reg(s, rs);
1314 if (logic_cc) {
1315 gen_shift_T1_T0_cc[shiftop]();
1316 } else {
1317 gen_shift_T1_T0[shiftop]();
1318 }
1319 }
1320 }
1321 if (op1 != 0x0f && op1 != 0x0d) {
1322 rn = (insn >> 16) & 0xf;
1323 gen_movl_T0_reg(s, rn);
1324 }
1325 rd = (insn >> 12) & 0xf;
1326 switch(op1) {
1327 case 0x00:
1328 gen_op_andl_T0_T1();
1329 gen_movl_reg_T0(s, rd);
1330 if (logic_cc)
1331 gen_op_logic_T0_cc();
1332 break;
1333 case 0x01:
1334 gen_op_xorl_T0_T1();
1335 gen_movl_reg_T0(s, rd);
1336 if (logic_cc)
1337 gen_op_logic_T0_cc();
1338 break;
1339 case 0x02:
b5ff1b31
FB
1340 if (set_cc && rd == 15) {
1341 /* SUBS r15, ... is used for exception return. */
1342 if (IS_USER(s))
1343 goto illegal_op;
2c0262af 1344 gen_op_subl_T0_T1_cc();
b5ff1b31
FB
1345 gen_exception_return(s);
1346 } else {
1347 if (set_cc)
1348 gen_op_subl_T0_T1_cc();
1349 else
1350 gen_op_subl_T0_T1();
1351 gen_movl_reg_T0(s, rd);
1352 }
2c0262af
FB
1353 break;
1354 case 0x03:
1355 if (set_cc)
1356 gen_op_rsbl_T0_T1_cc();
1357 else
1358 gen_op_rsbl_T0_T1();
1359 gen_movl_reg_T0(s, rd);
1360 break;
1361 case 0x04:
1362 if (set_cc)
1363 gen_op_addl_T0_T1_cc();
1364 else
1365 gen_op_addl_T0_T1();
1366 gen_movl_reg_T0(s, rd);
1367 break;
1368 case 0x05:
1369 if (set_cc)
1370 gen_op_adcl_T0_T1_cc();
1371 else
1372 gen_op_adcl_T0_T1();
1373 gen_movl_reg_T0(s, rd);
1374 break;
1375 case 0x06:
1376 if (set_cc)
1377 gen_op_sbcl_T0_T1_cc();
1378 else
1379 gen_op_sbcl_T0_T1();
1380 gen_movl_reg_T0(s, rd);
1381 break;
1382 case 0x07:
1383 if (set_cc)
1384 gen_op_rscl_T0_T1_cc();
1385 else
1386 gen_op_rscl_T0_T1();
1387 gen_movl_reg_T0(s, rd);
1388 break;
1389 case 0x08:
1390 if (set_cc) {
1391 gen_op_andl_T0_T1();
1392 gen_op_logic_T0_cc();
1393 }
1394 break;
1395 case 0x09:
1396 if (set_cc) {
1397 gen_op_xorl_T0_T1();
1398 gen_op_logic_T0_cc();
1399 }
1400 break;
1401 case 0x0a:
1402 if (set_cc) {
1403 gen_op_subl_T0_T1_cc();
1404 }
1405 break;
1406 case 0x0b:
1407 if (set_cc) {
1408 gen_op_addl_T0_T1_cc();
1409 }
1410 break;
1411 case 0x0c:
1412 gen_op_orl_T0_T1();
1413 gen_movl_reg_T0(s, rd);
1414 if (logic_cc)
1415 gen_op_logic_T0_cc();
1416 break;
1417 case 0x0d:
b5ff1b31
FB
1418 if (logic_cc && rd == 15) {
1419 /* MOVS r15, ... is used for exception return. */
1420 if (IS_USER(s))
1421 goto illegal_op;
1422 gen_op_movl_T0_T1();
1423 gen_exception_return(s);
1424 } else {
1425 gen_movl_reg_T1(s, rd);
1426 if (logic_cc)
1427 gen_op_logic_T1_cc();
1428 }
2c0262af
FB
1429 break;
1430 case 0x0e:
1431 gen_op_bicl_T0_T1();
1432 gen_movl_reg_T0(s, rd);
1433 if (logic_cc)
1434 gen_op_logic_T0_cc();
1435 break;
1436 default:
1437 case 0x0f:
1438 gen_op_notl_T1();
1439 gen_movl_reg_T1(s, rd);
1440 if (logic_cc)
1441 gen_op_logic_T1_cc();
1442 break;
1443 }
1444 } else {
1445 /* other instructions */
1446 op1 = (insn >> 24) & 0xf;
1447 switch(op1) {
1448 case 0x0:
1449 case 0x1:
99c475ab 1450 /* multiplies, extra load/stores */
2c0262af
FB
1451 sh = (insn >> 5) & 3;
1452 if (sh == 0) {
1453 if (op1 == 0x0) {
1454 rd = (insn >> 16) & 0xf;
1455 rn = (insn >> 12) & 0xf;
1456 rs = (insn >> 8) & 0xf;
1457 rm = (insn) & 0xf;
99c475ab 1458 if (((insn >> 22) & 3) == 0) {
2c0262af
FB
1459 /* 32 bit mul */
1460 gen_movl_T0_reg(s, rs);
1461 gen_movl_T1_reg(s, rm);
1462 gen_op_mul_T0_T1();
1463 if (insn & (1 << 21)) {
1464 gen_movl_T1_reg(s, rn);
1465 gen_op_addl_T0_T1();
1466 }
1467 if (insn & (1 << 20))
1468 gen_op_logic_T0_cc();
1469 gen_movl_reg_T0(s, rd);
1470 } else {
1471 /* 64 bit mul */
1472 gen_movl_T0_reg(s, rs);
1473 gen_movl_T1_reg(s, rm);
1474 if (insn & (1 << 22))
2c0262af 1475 gen_op_imull_T0_T1();
2e134c9c
FB
1476 else
1477 gen_op_mull_T0_T1();
99c475ab 1478 if (insn & (1 << 21)) /* mult accumulate */
2c0262af 1479 gen_op_addq_T0_T1(rn, rd);
99c475ab 1480 if (!(insn & (1 << 23))) { /* double accumulate */
b5ff1b31 1481 ARCH(6);
99c475ab
FB
1482 gen_op_addq_lo_T0_T1(rn);
1483 gen_op_addq_lo_T0_T1(rd);
1484 }
2c0262af
FB
1485 if (insn & (1 << 20))
1486 gen_op_logicq_cc();
1487 gen_movl_reg_T0(s, rn);
1488 gen_movl_reg_T1(s, rd);
1489 }
1490 } else {
2c0262af
FB
1491 rn = (insn >> 16) & 0xf;
1492 rd = (insn >> 12) & 0xf;
99c475ab
FB
1493 if (insn & (1 << 23)) {
1494 /* load/store exclusive */
1495 goto illegal_op;
2c0262af 1496 } else {
99c475ab
FB
1497 /* SWP instruction */
1498 rm = (insn) & 0xf;
1499
1500 gen_movl_T0_reg(s, rm);
1501 gen_movl_T1_reg(s, rn);
1502 if (insn & (1 << 22)) {
b5ff1b31 1503 gen_ldst(swpb, s);
99c475ab 1504 } else {
b5ff1b31 1505 gen_ldst(swpl, s);
99c475ab
FB
1506 }
1507 gen_movl_reg_T0(s, rd);
2c0262af 1508 }
2c0262af
FB
1509 }
1510 } else {
99c475ab 1511 /* Misc load/store */
2c0262af
FB
1512 rn = (insn >> 16) & 0xf;
1513 rd = (insn >> 12) & 0xf;
1514 gen_movl_T1_reg(s, rn);
beddab75
FB
1515 if (insn & (1 << 24))
1516 gen_add_datah_offset(s, insn);
2c0262af
FB
1517 if (insn & (1 << 20)) {
1518 /* load */
1519 switch(sh) {
1520 case 1:
b5ff1b31 1521 gen_ldst(lduw, s);
2c0262af
FB
1522 break;
1523 case 2:
b5ff1b31 1524 gen_ldst(ldsb, s);
2c0262af
FB
1525 break;
1526 default:
1527 case 3:
b5ff1b31 1528 gen_ldst(ldsw, s);
2c0262af
FB
1529 break;
1530 }
e748ba4f 1531 gen_movl_reg_T0(s, rd);
99c475ab
FB
1532 } else if (sh & 2) {
1533 /* doubleword */
1534 if (sh & 1) {
1535 /* store */
1536 gen_movl_T0_reg(s, rd);
b5ff1b31 1537 gen_ldst(stl, s);
99c475ab
FB
1538 gen_op_addl_T1_im(4);
1539 gen_movl_T0_reg(s, rd + 1);
b5ff1b31 1540 gen_ldst(stl, s);
99c475ab
FB
1541 if ((insn & (1 << 24)) || (insn & (1 << 20)))
1542 gen_op_addl_T1_im(-4);
1543 } else {
1544 /* load */
b5ff1b31 1545 gen_ldst(ldl, s);
99c475ab
FB
1546 gen_movl_reg_T0(s, rd);
1547 gen_op_addl_T1_im(4);
b5ff1b31 1548 gen_ldst(ldl, s);
99c475ab
FB
1549 gen_movl_reg_T0(s, rd + 1);
1550 if ((insn & (1 << 24)) || (insn & (1 << 20)))
1551 gen_op_addl_T1_im(-4);
1552 }
2c0262af
FB
1553 } else {
1554 /* store */
e748ba4f 1555 gen_movl_T0_reg(s, rd);
b5ff1b31 1556 gen_ldst(stw, s);
2c0262af
FB
1557 }
1558 if (!(insn & (1 << 24))) {
1559 gen_add_datah_offset(s, insn);
1560 gen_movl_reg_T1(s, rn);
1561 } else if (insn & (1 << 21)) {
1562 gen_movl_reg_T1(s, rn);
1563 }
1564 }
1565 break;
1566 case 0x4:
1567 case 0x5:
1568 case 0x6:
1569 case 0x7:
1570 /* load/store byte/word */
1571 rn = (insn >> 16) & 0xf;
1572 rd = (insn >> 12) & 0xf;
1573 gen_movl_T1_reg(s, rn);
b5ff1b31 1574 i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
2c0262af
FB
1575 if (insn & (1 << 24))
1576 gen_add_data_offset(s, insn);
1577 if (insn & (1 << 20)) {
1578 /* load */
b5ff1b31 1579#if defined(CONFIG_USER_ONLY)
2c0262af 1580 if (insn & (1 << 22))
b5ff1b31 1581 gen_op_ldub_raw();
2c0262af 1582 else
b5ff1b31
FB
1583 gen_op_ldl_raw();
1584#else
1585 if (insn & (1 << 22)) {
1586 if (i)
1587 gen_op_ldub_user();
1588 else
1589 gen_op_ldub_kernel();
1590 } else {
1591 if (i)
1592 gen_op_ldl_user();
1593 else
1594 gen_op_ldl_kernel();
1595 }
1596#endif
99c475ab
FB
1597 if (rd == 15)
1598 gen_bx(s);
1599 else
1600 gen_movl_reg_T0(s, rd);
2c0262af
FB
1601 } else {
1602 /* store */
1603 gen_movl_T0_reg(s, rd);
b5ff1b31 1604#if defined(CONFIG_USER_ONLY)
2c0262af 1605 if (insn & (1 << 22))
b5ff1b31 1606 gen_op_stb_raw();
2c0262af 1607 else
b5ff1b31
FB
1608 gen_op_stl_raw();
1609#else
1610 if (insn & (1 << 22)) {
1611 if (i)
1612 gen_op_stb_user();
1613 else
1614 gen_op_stb_kernel();
1615 } else {
1616 if (i)
1617 gen_op_stl_user();
1618 else
1619 gen_op_stl_kernel();
1620 }
1621#endif
2c0262af
FB
1622 }
1623 if (!(insn & (1 << 24))) {
1624 gen_add_data_offset(s, insn);
1625 gen_movl_reg_T1(s, rn);
1626 } else if (insn & (1 << 21))
1627 gen_movl_reg_T1(s, rn); {
1628 }
1629 break;
1630 case 0x08:
1631 case 0x09:
1632 {
191abaa2 1633 int j, n, user, loaded_base;
2c0262af
FB
1634 /* load/store multiple words */
1635 /* XXX: store correct base if write back */
b5ff1b31
FB
1636 user = 0;
1637 if (insn & (1 << 22)) {
1638 if (IS_USER(s))
1639 goto illegal_op; /* only usable in supervisor mode */
1640
1641 if ((insn & (1 << 15)) == 0)
1642 user = 1;
1643 }
2c0262af
FB
1644 rn = (insn >> 16) & 0xf;
1645 gen_movl_T1_reg(s, rn);
1646
1647 /* compute total size */
191abaa2 1648 loaded_base = 0;
2c0262af
FB
1649 n = 0;
1650 for(i=0;i<16;i++) {
1651 if (insn & (1 << i))
1652 n++;
1653 }
1654 /* XXX: test invalid n == 0 case ? */
1655 if (insn & (1 << 23)) {
1656 if (insn & (1 << 24)) {
1657 /* pre increment */
1658 gen_op_addl_T1_im(4);
1659 } else {
1660 /* post increment */
1661 }
1662 } else {
1663 if (insn & (1 << 24)) {
1664 /* pre decrement */
1665 gen_op_addl_T1_im(-(n * 4));
1666 } else {
1667 /* post decrement */
1668 if (n != 1)
1669 gen_op_addl_T1_im(-((n - 1) * 4));
1670 }
1671 }
1672 j = 0;
1673 for(i=0;i<16;i++) {
1674 if (insn & (1 << i)) {
1675 if (insn & (1 << 20)) {
1676 /* load */
b5ff1b31
FB
1677 gen_ldst(ldl, s);
1678 if (i == 15) {
99c475ab 1679 gen_bx(s);
b5ff1b31
FB
1680 } else if (user) {
1681 gen_op_movl_user_T0(i);
191abaa2
PB
1682 } else if (i == rn) {
1683 gen_op_movl_T2_T0();
1684 loaded_base = 1;
b5ff1b31 1685 } else {
99c475ab 1686 gen_movl_reg_T0(s, i);
b5ff1b31 1687 }
2c0262af
FB
1688 } else {
1689 /* store */
1690 if (i == 15) {
1691 /* special case: r15 = PC + 12 */
1692 val = (long)s->pc + 8;
1693 gen_op_movl_TN_im[0](val);
b5ff1b31
FB
1694 } else if (user) {
1695 gen_op_movl_T0_user(i);
2c0262af
FB
1696 } else {
1697 gen_movl_T0_reg(s, i);
1698 }
b5ff1b31 1699 gen_ldst(stl, s);
2c0262af
FB
1700 }
1701 j++;
1702 /* no need to add after the last transfer */
1703 if (j != n)
1704 gen_op_addl_T1_im(4);
1705 }
1706 }
1707 if (insn & (1 << 21)) {
1708 /* write back */
1709 if (insn & (1 << 23)) {
1710 if (insn & (1 << 24)) {
1711 /* pre increment */
1712 } else {
1713 /* post increment */
1714 gen_op_addl_T1_im(4);
1715 }
1716 } else {
1717 if (insn & (1 << 24)) {
1718 /* pre decrement */
1719 if (n != 1)
1720 gen_op_addl_T1_im(-((n - 1) * 4));
1721 } else {
1722 /* post decrement */
1723 gen_op_addl_T1_im(-(n * 4));
1724 }
1725 }
1726 gen_movl_reg_T1(s, rn);
1727 }
191abaa2
PB
1728 if (loaded_base) {
1729 gen_op_movl_T0_T2();
1730 gen_movl_reg_T0(s, rn);
1731 }
b5ff1b31
FB
1732 if ((insn & (1 << 22)) && !user) {
1733 /* Restore CPSR from SPSR. */
1734 gen_op_movl_T0_spsr();
1735 gen_op_movl_cpsr_T0(0xffffffff);
1736 s->is_jmp = DISAS_UPDATE;
1737 }
2c0262af
FB
1738 }
1739 break;
1740 case 0xa:
1741 case 0xb:
1742 {
99c475ab 1743 int32_t offset;
2c0262af
FB
1744
1745 /* branch (and link) */
99c475ab 1746 val = (int32_t)s->pc;
2c0262af
FB
1747 if (insn & (1 << 24)) {
1748 gen_op_movl_T0_im(val);
1749 gen_op_movl_reg_TN[0][14]();
1750 }
99c475ab 1751 offset = (((int32_t)insn << 8) >> 8);
2c0262af 1752 val += (offset << 2) + 4;
8aaca4c0 1753 gen_jmp(s, val);
2c0262af
FB
1754 }
1755 break;
b7bcbe95
FB
1756 case 0xc:
1757 case 0xd:
1758 case 0xe:
1759 /* Coprocessor. */
1760 op1 = (insn >> 8) & 0xf;
1761 switch (op1) {
1762 case 10:
1763 case 11:
1764 if (disas_vfp_insn (env, s, insn))
1765 goto illegal_op;
1766 break;
b5ff1b31
FB
1767 case 15:
1768 if (disas_cp15_insn (s, insn))
1769 goto illegal_op;
1770 break;
b7bcbe95
FB
1771 default:
1772 /* unknown coprocessor. */
1773 goto illegal_op;
1774 }
1775 break;
2c0262af
FB
1776 case 0xf:
1777 /* swi */
1778 gen_op_movl_T0_im((long)s->pc);
1779 gen_op_movl_reg_TN[0][15]();
1780 gen_op_swi();
1781 s->is_jmp = DISAS_JUMP;
1782 break;
2c0262af
FB
1783 default:
1784 illegal_op:
1785 gen_op_movl_T0_im((long)s->pc - 4);
1786 gen_op_movl_reg_TN[0][15]();
1787 gen_op_undef_insn();
1788 s->is_jmp = DISAS_JUMP;
1789 break;
1790 }
1791 }
1792}
1793
99c475ab
FB
1794static void disas_thumb_insn(DisasContext *s)
1795{
1796 uint32_t val, insn, op, rm, rn, rd, shift, cond;
1797 int32_t offset;
1798 int i;
1799
b5ff1b31 1800 insn = lduw_code(s->pc);
99c475ab 1801 s->pc += 2;
b5ff1b31 1802
99c475ab
FB
1803 switch (insn >> 12) {
1804 case 0: case 1:
1805 rd = insn & 7;
1806 op = (insn >> 11) & 3;
1807 if (op == 3) {
1808 /* add/subtract */
1809 rn = (insn >> 3) & 7;
1810 gen_movl_T0_reg(s, rn);
1811 if (insn & (1 << 10)) {
1812 /* immediate */
1813 gen_op_movl_T1_im((insn >> 6) & 7);
1814 } else {
1815 /* reg */
1816 rm = (insn >> 6) & 7;
1817 gen_movl_T1_reg(s, rm);
1818 }
1819 if (insn & (1 << 9))
5899f386 1820 gen_op_subl_T0_T1_cc();
99c475ab
FB
1821 else
1822 gen_op_addl_T0_T1_cc();
1823 gen_movl_reg_T0(s, rd);
1824 } else {
1825 /* shift immediate */
1826 rm = (insn >> 3) & 7;
1827 shift = (insn >> 6) & 0x1f;
1828 gen_movl_T0_reg(s, rm);
1829 gen_shift_T0_im_thumb[op](shift);
1830 gen_movl_reg_T0(s, rd);
1831 }
1832 break;
1833 case 2: case 3:
1834 /* arithmetic large immediate */
1835 op = (insn >> 11) & 3;
1836 rd = (insn >> 8) & 0x7;
1837 if (op == 0) {
1838 gen_op_movl_T0_im(insn & 0xff);
1839 } else {
1840 gen_movl_T0_reg(s, rd);
1841 gen_op_movl_T1_im(insn & 0xff);
1842 }
1843 switch (op) {
1844 case 0: /* mov */
1845 gen_op_logic_T0_cc();
1846 break;
1847 case 1: /* cmp */
1848 gen_op_subl_T0_T1_cc();
1849 break;
1850 case 2: /* add */
1851 gen_op_addl_T0_T1_cc();
1852 break;
1853 case 3: /* sub */
1854 gen_op_subl_T0_T1_cc();
1855 break;
1856 }
1857 if (op != 1)
1858 gen_movl_reg_T0(s, rd);
1859 break;
1860 case 4:
1861 if (insn & (1 << 11)) {
1862 rd = (insn >> 8) & 7;
5899f386
FB
1863 /* load pc-relative. Bit 1 of PC is ignored. */
1864 val = s->pc + 2 + ((insn & 0xff) * 4);
1865 val &= ~(uint32_t)2;
99c475ab 1866 gen_op_movl_T1_im(val);
b5ff1b31 1867 gen_ldst(ldl, s);
99c475ab
FB
1868 gen_movl_reg_T0(s, rd);
1869 break;
1870 }
1871 if (insn & (1 << 10)) {
1872 /* data processing extended or blx */
1873 rd = (insn & 7) | ((insn >> 4) & 8);
1874 rm = (insn >> 3) & 0xf;
1875 op = (insn >> 8) & 3;
1876 switch (op) {
1877 case 0: /* add */
1878 gen_movl_T0_reg(s, rd);
1879 gen_movl_T1_reg(s, rm);
1880 gen_op_addl_T0_T1();
1881 gen_movl_reg_T0(s, rd);
1882 break;
1883 case 1: /* cmp */
1884 gen_movl_T0_reg(s, rd);
1885 gen_movl_T1_reg(s, rm);
1886 gen_op_subl_T0_T1_cc();
1887 break;
1888 case 2: /* mov/cpy */
1889 gen_movl_T0_reg(s, rm);
1890 gen_movl_reg_T0(s, rd);
1891 break;
1892 case 3:/* branch [and link] exchange thumb register */
1893 if (insn & (1 << 7)) {
1894 val = (uint32_t)s->pc | 1;
1895 gen_op_movl_T1_im(val);
1896 gen_movl_reg_T1(s, 14);
1897 }
1898 gen_movl_T0_reg(s, rm);
1899 gen_bx(s);
1900 break;
1901 }
1902 break;
1903 }
1904
1905 /* data processing register */
1906 rd = insn & 7;
1907 rm = (insn >> 3) & 7;
1908 op = (insn >> 6) & 0xf;
1909 if (op == 2 || op == 3 || op == 4 || op == 7) {
1910 /* the shift/rotate ops want the operands backwards */
1911 val = rm;
1912 rm = rd;
1913 rd = val;
1914 val = 1;
1915 } else {
1916 val = 0;
1917 }
1918
1919 if (op == 9) /* neg */
1920 gen_op_movl_T0_im(0);
1921 else if (op != 0xf) /* mvn doesn't read its first operand */
1922 gen_movl_T0_reg(s, rd);
1923
1924 gen_movl_T1_reg(s, rm);
5899f386 1925 switch (op) {
99c475ab
FB
1926 case 0x0: /* and */
1927 gen_op_andl_T0_T1();
1928 gen_op_logic_T0_cc();
1929 break;
1930 case 0x1: /* eor */
1931 gen_op_xorl_T0_T1();
1932 gen_op_logic_T0_cc();
1933 break;
1934 case 0x2: /* lsl */
1935 gen_op_shll_T1_T0_cc();
3aa22b4b 1936 gen_op_logic_T1_cc();
99c475ab
FB
1937 break;
1938 case 0x3: /* lsr */
1939 gen_op_shrl_T1_T0_cc();
3aa22b4b 1940 gen_op_logic_T1_cc();
99c475ab
FB
1941 break;
1942 case 0x4: /* asr */
1943 gen_op_sarl_T1_T0_cc();
3aa22b4b 1944 gen_op_logic_T1_cc();
99c475ab
FB
1945 break;
1946 case 0x5: /* adc */
1947 gen_op_adcl_T0_T1_cc();
1948 break;
1949 case 0x6: /* sbc */
1950 gen_op_sbcl_T0_T1_cc();
1951 break;
1952 case 0x7: /* ror */
1953 gen_op_rorl_T1_T0_cc();
3aa22b4b 1954 gen_op_logic_T1_cc();
99c475ab
FB
1955 break;
1956 case 0x8: /* tst */
1957 gen_op_andl_T0_T1();
1958 gen_op_logic_T0_cc();
1959 rd = 16;
5899f386 1960 break;
99c475ab 1961 case 0x9: /* neg */
5899f386 1962 gen_op_subl_T0_T1_cc();
99c475ab
FB
1963 break;
1964 case 0xa: /* cmp */
1965 gen_op_subl_T0_T1_cc();
1966 rd = 16;
1967 break;
1968 case 0xb: /* cmn */
1969 gen_op_addl_T0_T1_cc();
1970 rd = 16;
1971 break;
1972 case 0xc: /* orr */
1973 gen_op_orl_T0_T1();
1974 gen_op_logic_T0_cc();
1975 break;
1976 case 0xd: /* mul */
1977 gen_op_mull_T0_T1();
1978 gen_op_logic_T0_cc();
1979 break;
1980 case 0xe: /* bic */
1981 gen_op_bicl_T0_T1();
1982 gen_op_logic_T0_cc();
1983 break;
1984 case 0xf: /* mvn */
1985 gen_op_notl_T1();
1986 gen_op_logic_T1_cc();
1987 val = 1;
5899f386 1988 rm = rd;
99c475ab
FB
1989 break;
1990 }
1991 if (rd != 16) {
1992 if (val)
5899f386 1993 gen_movl_reg_T1(s, rm);
99c475ab
FB
1994 else
1995 gen_movl_reg_T0(s, rd);
1996 }
1997 break;
1998
1999 case 5:
2000 /* load/store register offset. */
2001 rd = insn & 7;
2002 rn = (insn >> 3) & 7;
2003 rm = (insn >> 6) & 7;
2004 op = (insn >> 9) & 7;
2005 gen_movl_T1_reg(s, rn);
2006 gen_movl_T2_reg(s, rm);
2007 gen_op_addl_T1_T2();
2008
2009 if (op < 3) /* store */
2010 gen_movl_T0_reg(s, rd);
2011
2012 switch (op) {
2013 case 0: /* str */
b5ff1b31 2014 gen_ldst(stl, s);
99c475ab
FB
2015 break;
2016 case 1: /* strh */
b5ff1b31 2017 gen_ldst(stw, s);
99c475ab
FB
2018 break;
2019 case 2: /* strb */
b5ff1b31 2020 gen_ldst(stb, s);
99c475ab
FB
2021 break;
2022 case 3: /* ldrsb */
b5ff1b31 2023 gen_ldst(ldsb, s);
99c475ab
FB
2024 break;
2025 case 4: /* ldr */
b5ff1b31 2026 gen_ldst(ldl, s);
99c475ab
FB
2027 break;
2028 case 5: /* ldrh */
b5ff1b31 2029 gen_ldst(lduw, s);
99c475ab
FB
2030 break;
2031 case 6: /* ldrb */
b5ff1b31 2032 gen_ldst(ldub, s);
99c475ab
FB
2033 break;
2034 case 7: /* ldrsh */
b5ff1b31 2035 gen_ldst(ldsw, s);
99c475ab
FB
2036 break;
2037 }
2038 if (op >= 3) /* load */
2039 gen_movl_reg_T0(s, rd);
2040 break;
2041
2042 case 6:
2043 /* load/store word immediate offset */
2044 rd = insn & 7;
2045 rn = (insn >> 3) & 7;
2046 gen_movl_T1_reg(s, rn);
2047 val = (insn >> 4) & 0x7c;
2048 gen_op_movl_T2_im(val);
2049 gen_op_addl_T1_T2();
2050
2051 if (insn & (1 << 11)) {
2052 /* load */
b5ff1b31 2053 gen_ldst(ldl, s);
99c475ab
FB
2054 gen_movl_reg_T0(s, rd);
2055 } else {
2056 /* store */
2057 gen_movl_T0_reg(s, rd);
b5ff1b31 2058 gen_ldst(stl, s);
99c475ab
FB
2059 }
2060 break;
2061
2062 case 7:
2063 /* load/store byte immediate offset */
2064 rd = insn & 7;
2065 rn = (insn >> 3) & 7;
2066 gen_movl_T1_reg(s, rn);
2067 val = (insn >> 6) & 0x1f;
2068 gen_op_movl_T2_im(val);
2069 gen_op_addl_T1_T2();
2070
2071 if (insn & (1 << 11)) {
2072 /* load */
b5ff1b31 2073 gen_ldst(ldub, s);
99c475ab
FB
2074 gen_movl_reg_T0(s, rd);
2075 } else {
2076 /* store */
2077 gen_movl_T0_reg(s, rd);
b5ff1b31 2078 gen_ldst(stb, s);
99c475ab
FB
2079 }
2080 break;
2081
2082 case 8:
2083 /* load/store halfword immediate offset */
2084 rd = insn & 7;
2085 rn = (insn >> 3) & 7;
2086 gen_movl_T1_reg(s, rn);
2087 val = (insn >> 5) & 0x3e;
2088 gen_op_movl_T2_im(val);
2089 gen_op_addl_T1_T2();
2090
2091 if (insn & (1 << 11)) {
2092 /* load */
b5ff1b31 2093 gen_ldst(lduw, s);
99c475ab
FB
2094 gen_movl_reg_T0(s, rd);
2095 } else {
2096 /* store */
2097 gen_movl_T0_reg(s, rd);
b5ff1b31 2098 gen_ldst(stw, s);
99c475ab
FB
2099 }
2100 break;
2101
2102 case 9:
2103 /* load/store from stack */
2104 rd = (insn >> 8) & 7;
2105 gen_movl_T1_reg(s, 13);
2106 val = (insn & 0xff) * 4;
2107 gen_op_movl_T2_im(val);
2108 gen_op_addl_T1_T2();
2109
2110 if (insn & (1 << 11)) {
2111 /* load */
b5ff1b31 2112 gen_ldst(ldl, s);
99c475ab
FB
2113 gen_movl_reg_T0(s, rd);
2114 } else {
2115 /* store */
2116 gen_movl_T0_reg(s, rd);
b5ff1b31 2117 gen_ldst(stl, s);
99c475ab
FB
2118 }
2119 break;
2120
2121 case 10:
2122 /* add to high reg */
2123 rd = (insn >> 8) & 7;
5899f386
FB
2124 if (insn & (1 << 11)) {
2125 /* SP */
2126 gen_movl_T0_reg(s, 13);
2127 } else {
2128 /* PC. bit 1 is ignored. */
2129 gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2);
2130 }
99c475ab
FB
2131 val = (insn & 0xff) * 4;
2132 gen_op_movl_T1_im(val);
2133 gen_op_addl_T0_T1();
2134 gen_movl_reg_T0(s, rd);
2135 break;
2136
2137 case 11:
2138 /* misc */
2139 op = (insn >> 8) & 0xf;
2140 switch (op) {
2141 case 0:
2142 /* adjust stack pointer */
2143 gen_movl_T1_reg(s, 13);
2144 val = (insn & 0x7f) * 4;
2145 if (insn & (1 << 7))
2146 val = -(int32_t)val;
2147 gen_op_movl_T2_im(val);
2148 gen_op_addl_T1_T2();
2149 gen_movl_reg_T1(s, 13);
2150 break;
2151
2152 case 4: case 5: case 0xc: case 0xd:
2153 /* push/pop */
2154 gen_movl_T1_reg(s, 13);
5899f386
FB
2155 if (insn & (1 << 8))
2156 offset = 4;
99c475ab 2157 else
5899f386
FB
2158 offset = 0;
2159 for (i = 0; i < 8; i++) {
2160 if (insn & (1 << i))
2161 offset += 4;
2162 }
2163 if ((insn & (1 << 11)) == 0) {
2164 gen_op_movl_T2_im(-offset);
2165 gen_op_addl_T1_T2();
2166 }
2167 gen_op_movl_T2_im(4);
99c475ab
FB
2168 for (i = 0; i < 8; i++) {
2169 if (insn & (1 << i)) {
2170 if (insn & (1 << 11)) {
2171 /* pop */
b5ff1b31 2172 gen_ldst(ldl, s);
99c475ab
FB
2173 gen_movl_reg_T0(s, i);
2174 } else {
2175 /* push */
2176 gen_movl_T0_reg(s, i);
b5ff1b31 2177 gen_ldst(stl, s);
99c475ab 2178 }
5899f386 2179 /* advance to the next address. */
99c475ab
FB
2180 gen_op_addl_T1_T2();
2181 }
2182 }
2183 if (insn & (1 << 8)) {
2184 if (insn & (1 << 11)) {
2185 /* pop pc */
b5ff1b31 2186 gen_ldst(ldl, s);
99c475ab
FB
2187 /* don't set the pc until the rest of the instruction
2188 has completed */
2189 } else {
2190 /* push lr */
2191 gen_movl_T0_reg(s, 14);
b5ff1b31 2192 gen_ldst(stl, s);
99c475ab
FB
2193 }
2194 gen_op_addl_T1_T2();
2195 }
5899f386
FB
2196 if ((insn & (1 << 11)) == 0) {
2197 gen_op_movl_T2_im(-offset);
2198 gen_op_addl_T1_T2();
2199 }
99c475ab
FB
2200 /* write back the new stack pointer */
2201 gen_movl_reg_T1(s, 13);
2202 /* set the new PC value */
2203 if ((insn & 0x0900) == 0x0900)
2204 gen_bx(s);
2205 break;
2206
06c949e6
PB
2207 case 0xe: /* bkpt */
2208 gen_op_movl_T0_im((long)s->pc - 2);
2209 gen_op_movl_reg_TN[0][15]();
2210 gen_op_bkpt();
2211 s->is_jmp = DISAS_JUMP;
2212 break;
2213
99c475ab
FB
2214 default:
2215 goto undef;
2216 }
2217 break;
2218
2219 case 12:
2220 /* load/store multiple */
2221 rn = (insn >> 8) & 0x7;
2222 gen_movl_T1_reg(s, rn);
2223 gen_op_movl_T2_im(4);
99c475ab
FB
2224 for (i = 0; i < 8; i++) {
2225 if (insn & (1 << i)) {
99c475ab
FB
2226 if (insn & (1 << 11)) {
2227 /* load */
b5ff1b31 2228 gen_ldst(ldl, s);
99c475ab
FB
2229 gen_movl_reg_T0(s, i);
2230 } else {
2231 /* store */
2232 gen_movl_T0_reg(s, i);
b5ff1b31 2233 gen_ldst(stl, s);
99c475ab 2234 }
5899f386
FB
2235 /* advance to the next address */
2236 gen_op_addl_T1_T2();
99c475ab
FB
2237 }
2238 }
5899f386 2239 /* Base register writeback. */
b5ff1b31
FB
2240 if ((insn & (1 << rn)) == 0)
2241 gen_movl_reg_T1(s, rn);
99c475ab
FB
2242 break;
2243
2244 case 13:
2245 /* conditional branch or swi */
2246 cond = (insn >> 8) & 0xf;
2247 if (cond == 0xe)
2248 goto undef;
2249
2250 if (cond == 0xf) {
2251 /* swi */
2252 gen_op_movl_T0_im((long)s->pc | 1);
2253 /* Don't set r15. */
2254 gen_op_movl_reg_TN[0][15]();
2255 gen_op_swi();
2256 s->is_jmp = DISAS_JUMP;
2257 break;
2258 }
2259 /* generate a conditional jump to next instruction */
e50e6a20
FB
2260 s->condlabel = gen_new_label();
2261 gen_test_cc[cond ^ 1](s->condlabel);
2262 s->condjmp = 1;
2263 //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
2264 //s->is_jmp = DISAS_JUMP_NEXT;
99c475ab
FB
2265 gen_movl_T1_reg(s, 15);
2266
2267 /* jump to the offset */
5899f386 2268 val = (uint32_t)s->pc + 2;
99c475ab 2269 offset = ((int32_t)insn << 24) >> 24;
5899f386 2270 val += offset << 1;
8aaca4c0 2271 gen_jmp(s, val);
99c475ab
FB
2272 break;
2273
2274 case 14:
2275 /* unconditional branch */
2276 if (insn & (1 << 11))
2277 goto undef; /* Second half of a blx */
2278 val = (uint32_t)s->pc;
2279 offset = ((int32_t)insn << 21) >> 21;
2280 val += (offset << 1) + 2;
8aaca4c0 2281 gen_jmp(s, val);
99c475ab
FB
2282 break;
2283
2284 case 15:
2285 /* branch and link [and switch to arm] */
2286 offset = ((int32_t)insn << 21) >> 10;
b5ff1b31 2287 insn = lduw_code(s->pc);
99c475ab
FB
2288 offset |= insn & 0x7ff;
2289
2290 val = (uint32_t)s->pc + 2;
2291 gen_op_movl_T1_im(val | 1);
2292 gen_movl_reg_T1(s, 14);
2293
5899f386 2294 val += offset << 1;
2531fc7b 2295 if (insn & (1 << 12)) {
99c475ab 2296 /* bl */
8aaca4c0 2297 gen_jmp(s, val);
99c475ab
FB
2298 } else {
2299 /* blx */
5899f386 2300 val &= ~(uint32_t)2;
99c475ab
FB
2301 gen_op_movl_T0_im(val);
2302 gen_bx(s);
2303 }
2304 }
2305 return;
2306undef:
5899f386 2307 gen_op_movl_T0_im((long)s->pc - 2);
99c475ab
FB
2308 gen_op_movl_reg_TN[0][15]();
2309 gen_op_undef_insn();
2310 s->is_jmp = DISAS_JUMP;
2311}
2312
2c0262af
FB
2313/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
2314 basic block 'tb'. If search_pc is TRUE, also generate PC
2315 information for each intermediate instruction. */
2316static inline int gen_intermediate_code_internal(CPUState *env,
2317 TranslationBlock *tb,
2318 int search_pc)
2319{
2320 DisasContext dc1, *dc = &dc1;
2321 uint16_t *gen_opc_end;
2322 int j, lj;
0fa85d43 2323 target_ulong pc_start;
b5ff1b31 2324 uint32_t next_page_start;
2c0262af
FB
2325
2326 /* generate intermediate code */
0fa85d43 2327 pc_start = tb->pc;
2c0262af
FB
2328
2329 dc->tb = tb;
2330
2331 gen_opc_ptr = gen_opc_buf;
2332 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2333 gen_opparam_ptr = gen_opparam_buf;
2334
2335 dc->is_jmp = DISAS_NEXT;
2336 dc->pc = pc_start;
8aaca4c0 2337 dc->singlestep_enabled = env->singlestep_enabled;
e50e6a20 2338 dc->condjmp = 0;
5899f386 2339 dc->thumb = env->thumb;
b5ff1b31
FB
2340#if !defined(CONFIG_USER_ONLY)
2341 dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
2342#endif
2343 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
e50e6a20 2344 nb_gen_labels = 0;
2c0262af
FB
2345 lj = -1;
2346 do {
1fddef4b
FB
2347 if (env->nb_breakpoints > 0) {
2348 for(j = 0; j < env->nb_breakpoints; j++) {
2349 if (env->breakpoints[j] == dc->pc) {
2350 gen_op_movl_T0_im((long)dc->pc);
2351 gen_op_movl_reg_TN[0][15]();
2352 gen_op_debug();
2353 dc->is_jmp = DISAS_JUMP;
2354 break;
2355 }
2356 }
2357 }
2c0262af
FB
2358 if (search_pc) {
2359 j = gen_opc_ptr - gen_opc_buf;
2360 if (lj < j) {
2361 lj++;
2362 while (lj < j)
2363 gen_opc_instr_start[lj++] = 0;
2364 }
0fa85d43 2365 gen_opc_pc[lj] = dc->pc;
2c0262af
FB
2366 gen_opc_instr_start[lj] = 1;
2367 }
e50e6a20 2368
99c475ab
FB
2369 if (env->thumb)
2370 disas_thumb_insn(dc);
2371 else
b7bcbe95 2372 disas_arm_insn(env, dc);
e50e6a20
FB
2373
2374 if (dc->condjmp && !dc->is_jmp) {
2375 gen_set_label(dc->condlabel);
2376 dc->condjmp = 0;
2377 }
2378 /* Translation stops when a conditional branch is enoutered.
2379 * Otherwise the subsequent code could get translated several times.
b5ff1b31
FB
2380 * Also stop translation when a page boundary is reached. This
2381 * ensures prefech aborts occur at the right place. */
1fddef4b
FB
2382 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
2383 !env->singlestep_enabled &&
b5ff1b31
FB
2384 dc->pc < next_page_start);
2385 /* At this stage dc->condjmp will only be set when the skipped
2386 * instruction was a conditional branch, and the PC has already been
e50e6a20 2387 * written. */
8aaca4c0
FB
2388 if (__builtin_expect(env->singlestep_enabled, 0)) {
2389 /* Make sure the pc is updated, and raise a debug exception. */
e50e6a20
FB
2390 if (dc->condjmp) {
2391 gen_op_debug();
2392 gen_set_label(dc->condlabel);
2393 }
2394 if (dc->condjmp || !dc->is_jmp) {
8aaca4c0
FB
2395 gen_op_movl_T0_im((long)dc->pc);
2396 gen_op_movl_reg_TN[0][15]();
e50e6a20 2397 dc->condjmp = 0;
8aaca4c0
FB
2398 }
2399 gen_op_debug();
2400 } else {
2401 switch(dc->is_jmp) {
8aaca4c0 2402 case DISAS_NEXT:
6e256c93 2403 gen_goto_tb(dc, 1, dc->pc);
8aaca4c0
FB
2404 break;
2405 default:
2406 case DISAS_JUMP:
2407 case DISAS_UPDATE:
2408 /* indicate that the hash table must be used to find the next TB */
2409 gen_op_movl_T0_0();
2410 gen_op_exit_tb();
2411 break;
2412 case DISAS_TB_JUMP:
2413 /* nothing more to generate */
2414 break;
2415 }
e50e6a20
FB
2416 if (dc->condjmp) {
2417 gen_set_label(dc->condlabel);
6e256c93 2418 gen_goto_tb(dc, 1, dc->pc);
e50e6a20
FB
2419 dc->condjmp = 0;
2420 }
2c0262af
FB
2421 }
2422 *gen_opc_ptr = INDEX_op_end;
2423
2424#ifdef DEBUG_DISAS
e19e89a5 2425 if (loglevel & CPU_LOG_TB_IN_ASM) {
2c0262af
FB
2426 fprintf(logfile, "----------------\n");
2427 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
5899f386 2428 target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
2c0262af 2429 fprintf(logfile, "\n");
e19e89a5
FB
2430 if (loglevel & (CPU_LOG_TB_OP)) {
2431 fprintf(logfile, "OP:\n");
2432 dump_ops(gen_opc_buf, gen_opparam_buf);
2433 fprintf(logfile, "\n");
2434 }
2c0262af
FB
2435 }
2436#endif
b5ff1b31
FB
2437 if (search_pc) {
2438 j = gen_opc_ptr - gen_opc_buf;
2439 lj++;
2440 while (lj <= j)
2441 gen_opc_instr_start[lj++] = 0;
2442 tb->size = 0;
2443 } else {
2c0262af 2444 tb->size = dc->pc - pc_start;
b5ff1b31 2445 }
2c0262af
FB
2446 return 0;
2447}
2448
2449int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
2450{
2451 return gen_intermediate_code_internal(env, tb, 0);
2452}
2453
2454int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
2455{
2456 return gen_intermediate_code_internal(env, tb, 1);
2457}
2458
b5ff1b31
FB
2459void cpu_reset(CPUARMState *env)
2460{
2461#if defined (CONFIG_USER_ONLY)
68998c5d
FB
2462 env->uncached_cpsr = ARM_CPU_MODE_USR;
2463#else
b5ff1b31
FB
2464 /* SVC mode with interrupts disabled. */
2465 env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
b5ff1b31
FB
2466#endif
2467 env->regs[15] = 0;
2468}
2469
2c0262af
FB
2470CPUARMState *cpu_arm_init(void)
2471{
2472 CPUARMState *env;
2473
173d6cfe 2474 env = qemu_mallocz(sizeof(CPUARMState));
2c0262af
FB
2475 if (!env)
2476 return NULL;
173d6cfe 2477 cpu_exec_init(env);
b5ff1b31
FB
2478 cpu_reset(env);
2479 tlb_flush(env, 1);
2c0262af
FB
2480 return env;
2481}
2482
2483void cpu_arm_close(CPUARMState *env)
2484{
2485 free(env);
2486}
2487
b5ff1b31
FB
2488static const char *cpu_mode_names[16] = {
2489 "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
2490 "???", "???", "???", "und", "???", "???", "???", "sys"
2491};
7fe48483
FB
2492void cpu_dump_state(CPUState *env, FILE *f,
2493 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2494 int flags)
2c0262af
FB
2495{
2496 int i;
bc380d17 2497 union {
b7bcbe95
FB
2498 uint32_t i;
2499 float s;
2500 } s0, s1;
2501 CPU_DoubleU d;
b5ff1b31 2502 uint32_t psr;
2c0262af
FB
2503
2504 for(i=0;i<16;i++) {
7fe48483 2505 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
2c0262af 2506 if ((i % 4) == 3)
7fe48483 2507 cpu_fprintf(f, "\n");
2c0262af 2508 else
7fe48483 2509 cpu_fprintf(f, " ");
2c0262af 2510 }
b5ff1b31
FB
2511 psr = cpsr_read(env);
2512 cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d %x\n",
2513 psr,
2514 psr & (1 << 31) ? 'N' : '-',
2515 psr & (1 << 30) ? 'Z' : '-',
2516 psr & (1 << 29) ? 'C' : '-',
2517 psr & (1 << 28) ? 'V' : '-',
2518 psr & CPSR_T ? 'T' : 'A',
2519 cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
b7bcbe95
FB
2520
2521 for (i = 0; i < 16; i++) {
8e96005d
FB
2522 d.d = env->vfp.regs[i];
2523 s0.i = d.l.lower;
2524 s1.i = d.l.upper;
b7bcbe95
FB
2525 cpu_fprintf(f, "s%02d=%08x(%8f) s%02d=%08x(%8f) d%02d=%08x%08x(%8f)\n",
2526 i * 2, (int)s0.i, s0.s,
2527 i * 2 + 1, (int)s0.i, s0.s,
2528 i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
2529 d.d);
b7bcbe95 2530 }
74c161bd 2531 cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr);
2c0262af 2532}
a6b025d3 2533