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