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