Commit 99c475abf16b10923baac09682a9d801ae421ac6

Authored by bellard
1 parent dfe86665

armv5te support (Paul Brook)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1258 c046a42c-6fe2-441c-8c8c-71466251a162
Changelog
... ... @@ -13,6 +13,8 @@ version 0.6.2:
13 13 - initial APIC support
14 14 - MMX/SSE/SSE2/PNI support
15 15 - PC parallel port support (Mark Jonckheere)
  16 + - initial SPARC64 support (Blue Swirl)
  17 + - armv5te user mode support (Paul Brook)
16 18  
17 19 version 0.6.1:
18 20  
... ...
cpu-exec.c
... ... @@ -160,7 +160,8 @@ int cpu_exec(CPUState *env1)
160 160 env->CF = (psr >> 29) & 1;
161 161 env->NZF = (psr & 0xc0000000) ^ 0x40000000;
162 162 env->VF = (psr << 3) & 0x80000000;
163   - env->cpsr = psr & ~0xf0000000;
  163 + env->QF = (psr >> 27) & 1;
  164 + env->cpsr = psr & ~CACHED_CPSR_BITS;
164 165 }
165 166 #elif defined(TARGET_SPARC)
166 167 #elif defined(TARGET_PPC)
... ... @@ -303,7 +304,7 @@ int cpu_exec(CPUState *env1)
303 304 #elif defined(TARGET_ARM)
304 305 env->cpsr = compute_cpsr();
305 306 cpu_dump_state(env, logfile, fprintf, 0);
306   - env->cpsr &= ~0xf0000000;
  307 + env->cpsr &= ~CACHED_CPSR_BITS;
307 308 #elif defined(TARGET_SPARC)
308 309 cpu_dump_state (env, logfile, fprintf, 0);
309 310 #elif defined(TARGET_PPC)
... ... @@ -322,7 +323,7 @@ int cpu_exec(CPUState *env1)
322 323 cs_base = env->segs[R_CS].base;
323 324 pc = cs_base + env->eip;
324 325 #elif defined(TARGET_ARM)
325   - flags = 0;
  326 + flags = env->thumb;
326 327 cs_base = 0;
327 328 pc = env->regs[15];
328 329 #elif defined(TARGET_SPARC)
... ...
linux-user/arm/syscall.h
... ... @@ -30,7 +30,7 @@ struct target_pt_regs {
30 30 #define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2)
31 31  
32 32 #if defined(TARGET_WORDS_BIGENDIAN)
33   -#define UNAME_MACHINE "armv4b"
  33 +#define UNAME_MACHINE "armv5teb"
34 34 #else
35   -#define UNAME_MACHINE "armv4l"
  35 +#define UNAME_MACHINE "armv5tel"
36 36 #endif
... ...
linux-user/syscall.c
... ... @@ -2944,11 +2944,35 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
2944 2944 #endif
2945 2945 #ifdef TARGET_NR_getgroups32
2946 2946 case TARGET_NR_getgroups32:
2947   - goto unimplemented;
  2947 + {
  2948 + int gidsetsize = arg1;
  2949 + uint32_t *target_grouplist = (void *)arg2;
  2950 + gid_t *grouplist;
  2951 + int i;
  2952 +
  2953 + grouplist = alloca(gidsetsize * sizeof(gid_t));
  2954 + ret = get_errno(getgroups(gidsetsize, grouplist));
  2955 + if (!is_error(ret)) {
  2956 + for(i = 0;i < gidsetsize; i++)
  2957 + put_user(grouplist[i], &target_grouplist[i]);
  2958 + }
  2959 + }
  2960 + break;
2948 2961 #endif
2949 2962 #ifdef TARGET_NR_setgroups32
2950 2963 case TARGET_NR_setgroups32:
2951   - goto unimplemented;
  2964 + {
  2965 + int gidsetsize = arg1;
  2966 + uint32_t *target_grouplist = (void *)arg2;
  2967 + gid_t *grouplist;
  2968 + int i;
  2969 +
  2970 + grouplist = alloca(gidsetsize * sizeof(gid_t));
  2971 + for(i = 0;i < gidsetsize; i++)
  2972 + get_user(grouplist[i], &target_grouplist[i]);
  2973 + ret = get_errno(setgroups(gidsetsize, grouplist));
  2974 + }
  2975 + break;
2952 2976 #endif
2953 2977 #ifdef TARGET_NR_fchown32
2954 2978 case TARGET_NR_fchown32:
... ...
target-arm/cpu.h
... ... @@ -35,6 +35,9 @@ typedef struct CPUARMState {
35 35 uint32_t CF; /* 0 or 1 */
36 36 uint32_t VF; /* V is the bit 31. All other bits are undefined */
37 37 uint32_t NZF; /* N is bit 31. Z is computed from NZF */
  38 + uint32_t QF; /* 0 or 1 */
  39 +
  40 + int thumb; /* 0 = arm mode, 1 = thumb mode */
38 41  
39 42 /* exception/interrupt handling */
40 43 jmp_buf jmp_env;
... ...
target-arm/exec.h
... ... @@ -31,12 +31,14 @@ void cpu_lock(void);
31 31 void cpu_unlock(void);
32 32 void cpu_loop_exit(void);
33 33  
  34 +/* Implemented CPSR bits. */
  35 +#define CACHED_CPSR_BITS 0xf8000000
34 36 static inline int compute_cpsr(void)
35 37 {
36 38 int ZF;
37 39 ZF = (env->NZF == 0);
38 40 return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
39   - (env->CF << 29) | ((env->VF & 0x80000000) >> 3);
  41 + (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27);
40 42 }
41 43  
42 44 static inline void env_to_regs(void)
... ...
target-arm/op.c
... ... @@ -81,8 +81,15 @@
81 81  
82 82 #define REGNAME r15
83 83 #define REG (env->regs[15])
  84 +#define SET_REG(x) REG = x & ~(uint32_t)1
84 85 #include "op_template.h"
85 86  
  87 +void OPPROTO op_bx_T0(void)
  88 +{
  89 + env->regs[15] = T0 & ~(uint32_t)1;
  90 + env->thumb = (T0 & 1) != 0;
  91 +}
  92 +
86 93 void OPPROTO op_movl_T0_0(void)
87 94 {
88 95 T0 = 0;
... ... @@ -382,6 +389,14 @@ void OPPROTO op_imull_T0_T1(void)
382 389 T0 = res;
383 390 }
384 391  
  392 +/* 48 bit signed mul, top 32 bits */
  393 +void OPPROTO op_imulw_T0_T1(void)
  394 +{
  395 + uint64_t res;
  396 + res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
  397 + T0 = res >> 16;
  398 +}
  399 +
385 400 void OPPROTO op_addq_T0_T1(void)
386 401 {
387 402 uint64_t res;
... ... @@ -391,6 +406,15 @@ void OPPROTO op_addq_T0_T1(void)
391 406 T0 = res;
392 407 }
393 408  
  409 +void OPPROTO op_addq_lo_T0_T1(void)
  410 +{
  411 + uint64_t res;
  412 + res = ((uint64_t)T1 << 32) | T0;
  413 + res += (uint64_t)(env->regs[PARAM1]);
  414 + T1 = res >> 32;
  415 + T0 = res;
  416 +}
  417 +
394 418 void OPPROTO op_logicq_cc(void)
395 419 {
396 420 env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0);
... ... @@ -694,6 +718,126 @@ void OPPROTO op_rorl_T1_T0_cc(void)
694 718 FORCE_RET();
695 719 }
696 720  
  721 +/* misc */
  722 +void OPPROTO op_clz_T0(void)
  723 +{
  724 + int count;
  725 + for (count = 32; T0 > 0; count--)
  726 + T0 = T0 >> 1;
  727 + T0 = count;
  728 + FORCE_RET();
  729 +}
  730 +
  731 +void OPPROTO op_sarl_T0_im(void)
  732 +{
  733 + T0 = (int32_t)T0 >> PARAM1;
  734 +}
  735 +
  736 +/* 16->32 Sign extend */
  737 +void OPPROTO op_sxl_T0(void)
  738 +{
  739 + T0 = (int16_t)T0;
  740 +}
  741 +
  742 +void OPPROTO op_sxl_T1(void)
  743 +{
  744 + T1 = (int16_t)T1;
  745 +}
  746 +
  747 +#define SIGNBIT (uint32_t)0x80000000
  748 +/* saturating arithmetic */
  749 +void OPPROTO op_addl_T0_T1_setq(void)
  750 +{
  751 + uint32_t res;
  752 +
  753 + res = T0 + T1;
  754 + if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT))
  755 + env->QF = 1;
  756 +
  757 + T0 = res;
  758 + FORCE_RET();
  759 +}
  760 +
  761 +void OPPROTO op_addl_T0_T1_saturate(void)
  762 +{
  763 + uint32_t res;
  764 +
  765 + res = T0 + T1;
  766 + if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) {
  767 + env->QF = 1;
  768 + if (T0 & SIGNBIT)
  769 + T0 = 0x80000000;
  770 + else
  771 + T0 = 0x7fffffff;
  772 + }
  773 + else
  774 + T0 = res;
  775 +
  776 + FORCE_RET();
  777 +}
  778 +
  779 +void OPPROTO op_subl_T0_T1_saturate(void)
  780 +{
  781 + uint32_t res;
  782 +
  783 + res = T0 - T1;
  784 + if (((res ^ T0) & SIGNBIT) && ((T0 ^ T1) & SIGNBIT)) {
  785 + env->QF = 1;
  786 + if (T0 & SIGNBIT)
  787 + T0 = 0x8000000;
  788 + else
  789 + T0 = 0x7fffffff;
  790 + }
  791 + else
  792 + T0 = res;
  793 +
  794 + FORCE_RET();
  795 +}
  796 +
  797 +/* thumb shift by immediate */
  798 +void OPPROTO op_shll_T0_im_thumb(void)
  799 +{
  800 + int shift;
  801 + shift = PARAM1;
  802 + if (shift != 0) {
  803 + env->CF = (T1 >> (32 - shift)) & 1;
  804 + T0 = T0 << shift;
  805 + }
  806 + env->NZF = T0;
  807 + FORCE_RET();
  808 +}
  809 +
  810 +void OPPROTO op_shrl_T0_im_thumb(void)
  811 +{
  812 + int shift;
  813 +
  814 + shift = PARAM1;
  815 + if (shift == 0) {
  816 + env->CF = 0;
  817 + T0 = 0;
  818 + } else {
  819 + env->CF = (T0 >> (shift - 1)) & 1;
  820 + T0 = T0 >> shift;
  821 + }
  822 + FORCE_RET();
  823 +}
  824 +
  825 +void OPPROTO op_sarl_T0_im_thumb(void)
  826 +{
  827 + int shift;
  828 +
  829 + shift = PARAM1;
  830 + if (shift == 0) {
  831 + T0 = ((int32_t)T0) >> 31;
  832 + env->CF = T0 & 1;
  833 + } else {
  834 + env->CF = (T0 >> (shift - 1)) & 1;
  835 + T0 = ((int32_t)T0) >> shift;
  836 + }
  837 + env->NZF = T0;
  838 + FORCE_RET();
  839 +}
  840 +
697 841 /* exceptions */
698 842  
699 843 void OPPROTO op_swi(void)
... ...
target-arm/op_template.h
... ... @@ -19,6 +19,10 @@
19 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 20 */
21 21  
  22 +#ifndef SET_REG
  23 +#define SET_REG(x) REG = x
  24 +#endif
  25 +
22 26 void OPPROTO glue(op_movl_T0_, REGNAME)(void)
23 27 {
24 28 T0 = REG;
... ... @@ -36,13 +40,14 @@ void OPPROTO glue(op_movl_T2_, REGNAME)(void)
36 40  
37 41 void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void)
38 42 {
39   - REG = T0;
  43 + SET_REG (T0);
40 44 }
41 45  
42 46 void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void)
43 47 {
44   - REG = T1;
  48 + SET_REG (T1);
45 49 }
46 50  
47 51 #undef REG
48 52 #undef REGNAME
  53 +#undef SET_REG
... ...
target-arm/translate.c
... ... @@ -245,6 +245,18 @@ static GenOpFunc1 *gen_op_movl_TN_im[3] = {
245 245 gen_op_movl_T2_im,
246 246 };
247 247  
  248 +static GenOpFunc1 *gen_shift_T0_im_thumb[3] = {
  249 + gen_op_shll_T0_im_thumb,
  250 + gen_op_shrl_T0_im_thumb,
  251 + gen_op_sarl_T0_im_thumb,
  252 +};
  253 +
  254 +static inline void gen_bx(DisasContext *s)
  255 +{
  256 + s->is_jmp = DISAS_UPDATE;
  257 + gen_op_bx_T0();
  258 +}
  259 +
248 260 static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
249 261 {
250 262 int val;
... ... @@ -350,17 +362,166 @@ static void disas_arm_insn(DisasContext *s)
350 362 s->pc += 4;
351 363  
352 364 cond = insn >> 28;
353   - if (cond == 0xf)
  365 + if (cond == 0xf){
  366 + if ((insn & 0x0d70f000) == 0x0550f000)
  367 + return; /* PLD */
  368 + else if ((insn & 0x0e000000) == 0x0a000000) {
  369 + /* branch link and change to thumb (blx <offset>) */
  370 + int32_t offset;
  371 +
  372 + val = (uint32_t)s->pc;
  373 + gen_op_movl_T0_im(val);
  374 + gen_movl_reg_T0(s, 14);
  375 + /* Sign-extend the 24-bit offset */
  376 + offset = (((int32_t)insn) << 8) >> 8;
  377 + /* offset * 4 + bit24 * 2 + (thumb bit) */
  378 + val += (offset << 2) | ((insn >> 23) & 2) | 1;
  379 + /* pipeline offset */
  380 + val += 4;
  381 + gen_op_movl_T0_im(val);
  382 + gen_bx(s);
  383 + return;
  384 + }
354 385 goto illegal_op;
  386 + }
355 387 if (cond != 0xe) {
356 388 /* if not always execute, we generate a conditional jump to
357 389 next instruction */
358 390 gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
359 391 s->is_jmp = DISAS_JUMP_NEXT;
360 392 }
361   - if (((insn & 0x0e000000) == 0 &&
362   - (insn & 0x00000090) != 0x90) ||
363   - ((insn & 0x0e000000) == (1 << 25))) {
  393 + if ((insn & 0x0f900000) == 0x03000000) {
  394 + if ((insn & 0x0ff0f000) != 0x0360f000)
  395 + goto illegal_op;
  396 + /* CPSR = immediate */
  397 + val = insn & 0xff;
  398 + shift = ((insn >> 8) & 0xf) * 2;
  399 + if (shift)
  400 + val = (val >> shift) | (val << (32 - shift));
  401 + gen_op_movl_T0_im(val);
  402 + if (insn & (1 << 19))
  403 + gen_op_movl_psr_T0();
  404 + } else if ((insn & 0x0f900000) == 0x01000000
  405 + && (insn & 0x00000090) != 0x00000090) {
  406 + /* miscellaneous instructions */
  407 + op1 = (insn >> 21) & 3;
  408 + sh = (insn >> 4) & 0xf;
  409 + rm = insn & 0xf;
  410 + switch (sh) {
  411 + case 0x0: /* move program status register */
  412 + if (op1 & 2) {
  413 + /* SPSR not accessible in user mode */
  414 + goto illegal_op;
  415 + }
  416 + if (op1 & 1) {
  417 + /* CPSR = reg */
  418 + gen_movl_T0_reg(s, rm);
  419 + if (insn & (1 << 19))
  420 + gen_op_movl_psr_T0();
  421 + } else {
  422 + /* reg = CPSR */
  423 + rd = (insn >> 12) & 0xf;
  424 + gen_op_movl_T0_psr();
  425 + gen_movl_reg_T0(s, rd);
  426 + }
  427 + case 0x1:
  428 + if (op1 == 1) {
  429 + /* branch/exchange thumb (bx). */
  430 + gen_movl_T0_reg(s, rm);
  431 + gen_bx(s);
  432 + } else if (op1 == 3) {
  433 + /* clz */
  434 + rd = (insn >> 12) & 0xf;
  435 + gen_movl_T0_reg(s, rm);
  436 + gen_op_clz_T0();
  437 + gen_movl_reg_T0(s, rd);
  438 + } else {
  439 + goto illegal_op;
  440 + }
  441 + break;
  442 + case 0x3:
  443 + if (op1 != 1)
  444 + goto illegal_op;
  445 +
  446 + /* branch link/exchange thumb (blx) */
  447 + val = (uint32_t)s->pc;
  448 + gen_op_movl_T0_im(val);
  449 + gen_movl_reg_T0(s, 14);
  450 + gen_movl_T0_reg(s, rm);
  451 + gen_bx(s);
  452 + break;
  453 + case 0x5: /* saturating add/subtract */
  454 + rd = (insn >> 12) & 0xf;
  455 + rn = (insn >> 16) & 0xf;
  456 + gen_movl_T0_reg(s, rn);
  457 + if (op1 & 2) {
  458 + gen_movl_T1_reg(s, rn);
  459 + if (op1 & 1)
  460 + gen_op_subl_T0_T1_saturate();
  461 + else
  462 + gen_op_addl_T0_T1_saturate();
  463 + }
  464 + gen_movl_T1_reg(s, rm);
  465 + if (op1 & 1)
  466 + gen_op_subl_T0_T1_saturate();
  467 + else
  468 + gen_op_addl_T0_T1_saturate();
  469 + gen_movl_reg_T0(s, rn);
  470 + break;
  471 + case 0x8: /* signed multiply */
  472 + case 0xa:
  473 + case 0xc:
  474 + case 0xe:
  475 + rs = (insn >> 8) & 0xf;
  476 + rn = (insn >> 12) & 0xf;
  477 + rd = (insn >> 16) & 0xf;
  478 + if (op1 == 1) {
  479 + /* (32 * 16) >> 16 */
  480 + gen_movl_T0_reg(s, rm);
  481 + gen_movl_T1_reg(s, rs);
  482 + if (sh & 4)
  483 + gen_op_sarl_T1_im(16);
  484 + else
  485 + gen_op_sxl_T1();
  486 + gen_op_imulw_T0_T1();
  487 + if ((sh & 2) == 0) {
  488 + gen_movl_T1_reg(s, rn);
  489 + gen_op_addl_T0_T1_setq();
  490 + }
  491 + gen_movl_reg_T0(s, rd);
  492 + } else {
  493 + /* 16 * 16 */
  494 + gen_movl_T0_reg(s, rm);
  495 + if (sh & 2)
  496 + gen_op_sarl_T0_im(16);
  497 + else
  498 + gen_op_sxl_T0();
  499 + gen_movl_T1_reg(s, rs);
  500 + if (sh & 4)
  501 + gen_op_sarl_T1_im(16);
  502 + else
  503 + gen_op_sxl_T1();
  504 + if (op1 == 2) {
  505 + gen_op_imull_T0_T1();
  506 + gen_op_addq_T0_T1(rn, rd);
  507 + gen_movl_reg_T0(s, rn);
  508 + gen_movl_reg_T1(s, rd);
  509 + } else {
  510 + gen_op_mul_T0_T1();
  511 + if (op1 == 0) {
  512 + gen_movl_T1_reg(s, rn);
  513 + gen_op_addl_T0_T1_setq();
  514 + }
  515 + gen_movl_reg_T0(s, rd);
  516 + }
  517 + }
  518 + break;
  519 + default:
  520 + goto illegal_op;
  521 + }
  522 + } else if (((insn & 0x0e000000) == 0 &&
  523 + (insn & 0x00000090) != 0x90) ||
  524 + ((insn & 0x0e000000) == (1 << 25))) {
364 525 int set_cc, logic_cc, shiftop;
365 526  
366 527 op1 = (insn >> 21) & 0xf;
... ... @@ -519,6 +680,7 @@ static void disas_arm_insn(DisasContext *s)
519 680 switch(op1) {
520 681 case 0x0:
521 682 case 0x1:
  683 + /* multiplies, extra load/stores */
522 684 sh = (insn >> 5) & 3;
523 685 if (sh == 0) {
524 686 if (op1 == 0x0) {
... ... @@ -526,7 +688,7 @@ static void disas_arm_insn(DisasContext *s)
526 688 rn = (insn >> 12) & 0xf;
527 689 rs = (insn >> 8) & 0xf;
528 690 rm = (insn) & 0xf;
529   - if (!(insn & (1 << 23))) {
  691 + if (((insn >> 22) & 3) == 0) {
530 692 /* 32 bit mul */
531 693 gen_movl_T0_reg(s, rs);
532 694 gen_movl_T1_reg(s, rm);
... ... @@ -546,30 +708,39 @@ static void disas_arm_insn(DisasContext *s)
546 708 gen_op_imull_T0_T1();
547 709 else
548 710 gen_op_mull_T0_T1();
549   - if (insn & (1 << 21))
  711 + if (insn & (1 << 21)) /* mult accumulate */
550 712 gen_op_addq_T0_T1(rn, rd);
  713 + if (!(insn & (1 << 23))) { /* double accumulate */
  714 + gen_op_addq_lo_T0_T1(rn);
  715 + gen_op_addq_lo_T0_T1(rd);
  716 + }
551 717 if (insn & (1 << 20))
552 718 gen_op_logicq_cc();
553 719 gen_movl_reg_T0(s, rn);
554 720 gen_movl_reg_T1(s, rd);
555 721 }
556 722 } else {
557   - /* SWP instruction */
558 723 rn = (insn >> 16) & 0xf;
559 724 rd = (insn >> 12) & 0xf;
560   - rm = (insn) & 0xf;
561   -
562   - gen_movl_T0_reg(s, rm);
563   - gen_movl_T1_reg(s, rn);
564   - if (insn & (1 << 22)) {
565   - gen_op_swpb_T0_T1();
  725 + if (insn & (1 << 23)) {
  726 + /* load/store exclusive */
  727 + goto illegal_op;
566 728 } else {
567   - gen_op_swpl_T0_T1();
  729 + /* SWP instruction */
  730 + rm = (insn) & 0xf;
  731 +
  732 + gen_movl_T0_reg(s, rm);
  733 + gen_movl_T1_reg(s, rn);
  734 + if (insn & (1 << 22)) {
  735 + gen_op_swpb_T0_T1();
  736 + } else {
  737 + gen_op_swpl_T0_T1();
  738 + }
  739 + gen_movl_reg_T0(s, rd);
568 740 }
569   - gen_movl_reg_T0(s, rd);
570 741 }
571 742 } else {
572   - /* load/store half word */
  743 + /* Misc load/store */
573 744 rn = (insn >> 16) & 0xf;
574 745 rd = (insn >> 12) & 0xf;
575 746 gen_movl_T1_reg(s, rn);
... ... @@ -590,6 +761,27 @@ static void disas_arm_insn(DisasContext *s)
590 761 break;
591 762 }
592 763 gen_movl_reg_T0(s, rd);
  764 + } else if (sh & 2) {
  765 + /* doubleword */
  766 + if (sh & 1) {
  767 + /* store */
  768 + gen_movl_T0_reg(s, rd);
  769 + gen_op_stl_T0_T1();
  770 + gen_op_addl_T1_im(4);
  771 + gen_movl_T0_reg(s, rd + 1);
  772 + gen_op_stl_T0_T1();
  773 + if ((insn & (1 << 24)) || (insn & (1 << 20)))
  774 + gen_op_addl_T1_im(-4);
  775 + } else {
  776 + /* load */
  777 + gen_op_ldl_T0_T1();
  778 + gen_movl_reg_T0(s, rd);
  779 + gen_op_addl_T1_im(4);
  780 + gen_op_ldl_T0_T1();
  781 + gen_movl_reg_T0(s, rd + 1);
  782 + if ((insn & (1 << 24)) || (insn & (1 << 20)))
  783 + gen_op_addl_T1_im(-4);
  784 + }
593 785 } else {
594 786 /* store */
595 787 gen_movl_T0_reg(s, rd);
... ... @@ -619,7 +811,10 @@ static void disas_arm_insn(DisasContext *s)
619 811 gen_op_ldub_T0_T1();
620 812 else
621 813 gen_op_ldl_T0_T1();
622   - gen_movl_reg_T0(s, rd);
  814 + if (rd == 15)
  815 + gen_bx(s);
  816 + else
  817 + gen_movl_reg_T0(s, rd);
623 818 } else {
624 819 /* store */
625 820 gen_movl_T0_reg(s, rd);
... ... @@ -676,7 +871,10 @@ static void disas_arm_insn(DisasContext *s)
676 871 if (insn & (1 << 20)) {
677 872 /* load */
678 873 gen_op_ldl_T0_T1();
679   - gen_movl_reg_T0(s, i);
  874 + if (i == 15)
  875 + gen_bx(s);
  876 + else
  877 + gen_movl_reg_T0(s, i);
680 878 } else {
681 879 /* store */
682 880 if (i == 15) {
... ... @@ -720,15 +918,15 @@ static void disas_arm_insn(DisasContext *s)
720 918 case 0xa:
721 919 case 0xb:
722 920 {
723   - int offset;
  921 + int32_t offset;
724 922  
725 923 /* branch (and link) */
726   - val = (int)s->pc;
  924 + val = (int32_t)s->pc;
727 925 if (insn & (1 << 24)) {
728 926 gen_op_movl_T0_im(val);
729 927 gen_op_movl_reg_TN[0][14]();
730 928 }
731   - offset = (((int)insn << 8) >> 8);
  929 + offset = (((int32_t)insn << 8) >> 8);
732 930 val += (offset << 2) + 4;
733 931 gen_op_jmp((long)s->tb, val);
734 932 s->is_jmp = DISAS_TB_JUMP;
... ... @@ -752,6 +950,500 @@ static void disas_arm_insn(DisasContext *s)
752 950 }
753 951 }
754 952  
  953 +static void disas_thumb_insn(DisasContext *s)
  954 +{
  955 + uint32_t val, insn, op, rm, rn, rd, shift, cond;
  956 + int32_t offset;
  957 + int i;
  958 +
  959 + insn = lduw(s->pc);
  960 + s->pc += 2;
  961 +
  962 + switch (insn >> 12) {
  963 + case 0: case 1:
  964 + rd = insn & 7;
  965 + op = (insn >> 11) & 3;
  966 + if (op == 3) {
  967 + /* add/subtract */
  968 + rn = (insn >> 3) & 7;
  969 + gen_movl_T0_reg(s, rn);
  970 + if (insn & (1 << 10)) {
  971 + /* immediate */
  972 + gen_op_movl_T1_im((insn >> 6) & 7);
  973 + } else {
  974 + /* reg */
  975 + rm = (insn >> 6) & 7;
  976 + gen_movl_T1_reg(s, rm);
  977 + }
  978 + if (insn & (1 << 9))
  979 + gen_op_addl_T0_T1_cc();
  980 + else
  981 + gen_op_addl_T0_T1_cc();
  982 + gen_movl_reg_T0(s, rd);
  983 + } else {
  984 + /* shift immediate */
  985 + rm = (insn >> 3) & 7;
  986 + shift = (insn >> 6) & 0x1f;
  987 + gen_movl_T0_reg(s, rm);
  988 + gen_shift_T0_im_thumb[op](shift);
  989 + gen_movl_reg_T0(s, rd);
  990 + }
  991 + break;
  992 + case 2: case 3:
  993 + /* arithmetic large immediate */
  994 + op = (insn >> 11) & 3;
  995 + rd = (insn >> 8) & 0x7;
  996 + if (op == 0) {
  997 + gen_op_movl_T0_im(insn & 0xff);
  998 + } else {
  999 + gen_movl_T0_reg(s, rd);
  1000 + gen_op_movl_T1_im(insn & 0xff);
  1001 + }
  1002 + switch (op) {
  1003 + case 0: /* mov */
  1004 + gen_op_logic_T0_cc();
  1005 + break;
  1006 + case 1: /* cmp */
  1007 + gen_op_subl_T0_T1_cc();
  1008 + break;
  1009 + case 2: /* add */
  1010 + gen_op_addl_T0_T1_cc();
  1011 + break;
  1012 + case 3: /* sub */
  1013 + gen_op_subl_T0_T1_cc();
  1014 + break;
  1015 + }
  1016 + if (op != 1)
  1017 + gen_movl_reg_T0(s, rd);
  1018 + break;
  1019 + case 4:
  1020 + if (insn & (1 << 11)) {
  1021 + rd = (insn >> 8) & 7;
  1022 + /* load pc-relative */
  1023 + val = (insn & 0xff) * 4;
  1024 + gen_op_movl_T1_im(val);
  1025 + gen_movl_T2_reg(s, 15);
  1026 + gen_op_addl_T1_T2();
  1027 + gen_op_ldl_T0_T1();
  1028 + gen_movl_reg_T0(s, rd);
  1029 + break;
  1030 + }
  1031 + if (insn & (1 << 10)) {
  1032 + /* data processing extended or blx */
  1033 + rd = (insn & 7) | ((insn >> 4) & 8);
  1034 + rm = (insn >> 3) & 0xf;
  1035 + op = (insn >> 8) & 3;
  1036 + switch (op) {
  1037 + case 0: /* add */
  1038 + gen_movl_T0_reg(s, rd);
  1039 + gen_movl_T1_reg(s, rm);
  1040 + gen_op_addl_T0_T1();
  1041 + gen_movl_reg_T0(s, rd);
  1042 + break;
  1043 + case 1: /* cmp */
  1044 + gen_movl_T0_reg(s, rd);
  1045 + gen_movl_T1_reg(s, rm);
  1046 + gen_op_subl_T0_T1_cc();
  1047 + break;
  1048 + case 2: /* mov/cpy */
  1049 + gen_movl_T0_reg(s, rm);
  1050 + gen_movl_reg_T0(s, rd);
  1051 + break;
  1052 + case 3:/* branch [and link] exchange thumb register */
  1053 + if (insn & (1 << 7)) {
  1054 + val = (uint32_t)s->pc | 1;
  1055 + gen_op_movl_T1_im(val);
  1056 + gen_movl_reg_T1(s, 14);
  1057 + }
  1058 + gen_movl_T0_reg(s, rm);
  1059 + gen_bx(s);
  1060 + break;
  1061 + }
  1062 + break;
  1063 + }
  1064 +
  1065 + /* data processing register */
  1066 + rd = insn & 7;
  1067 + rm = (insn >> 3) & 7;
  1068 + op = (insn >> 6) & 0xf;
  1069 + if (op == 2 || op == 3 || op == 4 || op == 7) {
  1070 + /* the shift/rotate ops want the operands backwards */
  1071 + val = rm;
  1072 + rm = rd;
  1073 + rd = val;
  1074 + val = 1;
  1075 + } else {
  1076 + val = 0;
  1077 + }
  1078 +
  1079 + if (op == 9) /* neg */
  1080 + gen_op_movl_T0_im(0);
  1081 + else if (op != 0xf) /* mvn doesn't read its first operand */
  1082 + gen_movl_T0_reg(s, rd);
  1083 +
  1084 + gen_movl_T1_reg(s, rm);
  1085 + switch (insn >> 6) {
  1086 + case 0x0: /* and */
  1087 + gen_op_andl_T0_T1();
  1088 + gen_op_logic_T0_cc();
  1089 + break;
  1090 + case 0x1: /* eor */
  1091 + gen_op_xorl_T0_T1();
  1092 + gen_op_logic_T0_cc();
  1093 + break;
  1094 + case 0x2: /* lsl */
  1095 + gen_op_shll_T1_T0_cc();
  1096 + break;
  1097 + case 0x3: /* lsr */
  1098 + gen_op_shrl_T1_T0_cc();
  1099 + break;
  1100 + case 0x4: /* asr */
  1101 + gen_op_sarl_T1_T0_cc();
  1102 + break;
  1103 + case 0x5: /* adc */
  1104 + gen_op_adcl_T0_T1_cc();
  1105 + break;
  1106 + case 0x6: /* sbc */
  1107 + gen_op_sbcl_T0_T1_cc();
  1108 + break;
  1109 + case 0x7: /* ror */
  1110 + gen_op_rorl_T1_T0_cc();
  1111 + break;
  1112 + case 0x8: /* tst */
  1113 + gen_op_andl_T0_T1();
  1114 + gen_op_logic_T0_cc();
  1115 + rd = 16;
  1116 + case 0x9: /* neg */
  1117 + gen_op_rsbl_T0_T1_cc();
  1118 + break;
  1119 + case 0xa: /* cmp */
  1120 + gen_op_subl_T0_T1_cc();
  1121 + rd = 16;
  1122 + break;
  1123 + case 0xb: /* cmn */
  1124 + gen_op_addl_T0_T1_cc();
  1125 + rd = 16;
  1126 + break;
  1127 + case 0xc: /* orr */
  1128 + gen_op_orl_T0_T1();
  1129 + gen_op_logic_T0_cc();
  1130 + break;
  1131 + case 0xd: /* mul */
  1132 + gen_op_mull_T0_T1();
  1133 + gen_op_logic_T0_cc();
  1134 + break;
  1135 + case 0xe: /* bic */
  1136 + gen_op_bicl_T0_T1();
  1137 + gen_op_logic_T0_cc();
  1138 + break;
  1139 + case 0xf: /* mvn */
  1140 + gen_op_notl_T1();
  1141 + gen_op_logic_T1_cc();
  1142 + val = 1;
  1143 + break;
  1144 + }
  1145 + if (rd != 16) {
  1146 + if (val)
  1147 + gen_movl_reg_T1(s, rd);
  1148 + else
  1149 + gen_movl_reg_T0(s, rd);
  1150 + }
  1151 + break;
  1152 +
  1153 + case 5:
  1154 + /* load/store register offset. */
  1155 + rd = insn & 7;
  1156 + rn = (insn >> 3) & 7;
  1157 + rm = (insn >> 6) & 7;
  1158 + op = (insn >> 9) & 7;
  1159 + gen_movl_T1_reg(s, rn);
  1160 + gen_movl_T2_reg(s, rm);
  1161 + gen_op_addl_T1_T2();
  1162 +
  1163 + if (op < 3) /* store */
  1164 + gen_movl_T0_reg(s, rd);
  1165 +
  1166 + switch (op) {
  1167 + case 0: /* str */
  1168 + gen_op_stl_T0_T1();
  1169 + break;
  1170 + case 1: /* strh */
  1171 + gen_op_stw_T0_T1();
  1172 + break;
  1173 + case 2: /* strb */
  1174 + gen_op_stb_T0_T1();
  1175 + break;
  1176 + case 3: /* ldrsb */
  1177 + gen_op_ldsb_T0_T1();
  1178 + break;
  1179 + case 4: /* ldr */
  1180 + gen_op_ldl_T0_T1();
  1181 + break;
  1182 + case 5: /* ldrh */
  1183 + gen_op_ldsw_T0_T1();
  1184 + break;
  1185 + case 6: /* ldrb */
  1186 + gen_op_ldub_T0_T1();
  1187 + break;
  1188 + case 7: /* ldrsh */
  1189 + gen_op_ldsw_T0_T1();
  1190 + break;
  1191 + }
  1192 + if (op >= 3) /* load */
  1193 + gen_movl_reg_T0(s, rd);
  1194 + break;
  1195 +
  1196 + case 6:
  1197 + /* load/store word immediate offset */
  1198 + rd = insn & 7;
  1199 + rn = (insn >> 3) & 7;
  1200 + gen_movl_T1_reg(s, rn);
  1201 + val = (insn >> 4) & 0x7c;
  1202 + gen_op_movl_T2_im(val);
  1203 + gen_op_addl_T1_T2();
  1204 +
  1205 + if (insn & (1 << 11)) {
  1206 + /* load */
  1207 + gen_op_ldl_T0_T1();
  1208 + gen_movl_reg_T0(s, rd);
  1209 + } else {
  1210 + /* store */
  1211 + gen_movl_T0_reg(s, rd);
  1212 + gen_op_stl_T0_T1();
  1213 + }
  1214 + break;
  1215 +
  1216 + case 7:
  1217 + /* load/store byte immediate offset */
  1218 + rd = insn & 7;
  1219 + rn = (insn >> 3) & 7;
  1220 + gen_movl_T1_reg(s, rn);
  1221 + val = (insn >> 6) & 0x1f;
  1222 + gen_op_movl_T2_im(val);
  1223 + gen_op_addl_T1_T2();
  1224 +
  1225 + if (insn & (1 << 11)) {
  1226 + /* load */
  1227 + gen_op_ldub_T0_T1();
  1228 + gen_movl_reg_T0(s, rd);
  1229 + } else {
  1230 + /* store */
  1231 + gen_movl_T0_reg(s, rd);
  1232 + gen_op_stb_T0_T1();
  1233 + }
  1234 + break;
  1235 +
  1236 + case 8:
  1237 + /* load/store halfword immediate offset */
  1238 + rd = insn & 7;
  1239 + rn = (insn >> 3) & 7;
  1240 + gen_movl_T1_reg(s, rn);
  1241 + val = (insn >> 5) & 0x3e;
  1242 + gen_op_movl_T2_im(val);
  1243 + gen_op_addl_T1_T2();
  1244 +
  1245 + if (insn & (1 << 11)) {
  1246 + /* load */
  1247 + gen_op_lduw_T0_T1();
  1248 + gen_movl_reg_T0(s, rd);
  1249 + } else {
  1250 + /* store */
  1251 + gen_movl_T0_reg(s, rd);
  1252 + gen_op_stw_T0_T1();
  1253 + }
  1254 + break;
  1255 +
  1256 + case 9:
  1257 + /* load/store from stack */
  1258 + rd = (insn >> 8) & 7;
  1259 + gen_movl_T1_reg(s, 13);
  1260 + val = (insn & 0xff) * 4;
  1261 + gen_op_movl_T2_im(val);
  1262 + gen_op_addl_T1_T2();
  1263 +
  1264 + if (insn & (1 << 11)) {
  1265 + /* load */
  1266 + gen_op_ldl_T0_T1();
  1267 + gen_movl_reg_T0(s, rd);
  1268 + } else {
  1269 + /* store */
  1270 + gen_movl_T0_reg(s, rd);
  1271 + gen_op_stl_T0_T1();
  1272 + }
  1273 + break;
  1274 +
  1275 + case 10:
  1276 + /* add to high reg */
  1277 + rd = (insn >> 8) & 7;
  1278 + if (insn & (1 << 11))
  1279 + rm = 13; /* sp */
  1280 + else
  1281 + rm = 15; /* pc */
  1282 + gen_movl_T0_reg(s, rm);
  1283 + val = (insn & 0xff) * 4;
  1284 + gen_op_movl_T1_im(val);
  1285 + gen_op_addl_T0_T1();
  1286 + gen_movl_reg_T0(s, rd);
  1287 + break;
  1288 +
  1289 + case 11:
  1290 + /* misc */
  1291 + op = (insn >> 8) & 0xf;
  1292 + switch (op) {
  1293 + case 0:
  1294 + /* adjust stack pointer */
  1295 + gen_movl_T1_reg(s, 13);
  1296 + val = (insn & 0x7f) * 4;
  1297 + if (insn & (1 << 7))
  1298 + val = -(int32_t)val;
  1299 + gen_op_movl_T2_im(val);
  1300 + gen_op_addl_T1_T2();
  1301 + gen_movl_reg_T1(s, 13);
  1302 + break;
  1303 +
  1304 + case 4: case 5: case 0xc: case 0xd:
  1305 + /* push/pop */
  1306 + gen_movl_T1_reg(s, 13);
  1307 + if (insn & (1 << 11))
  1308 + val = 4;
  1309 + else
  1310 + val = -4;
  1311 + gen_op_movl_T2_im(val);
  1312 + for (i = 0; i < 8; i++) {
  1313 + if (insn & (1 << i)) {
  1314 + if (insn & (1 << 11)) {
  1315 + /* pop */
  1316 + gen_op_ldl_T0_T1();
  1317 + gen_movl_reg_T0(s, i);
  1318 + } else {
  1319 + /* push */
  1320 + gen_movl_T0_reg(s, i);
  1321 + gen_op_stl_T0_T1();
  1322 + }
  1323 + /* move to the next address */
  1324 + gen_op_addl_T1_T2();
  1325 + }
  1326 + }
  1327 + if (insn & (1 << 8)) {
  1328 + if (insn & (1 << 11)) {
  1329 + /* pop pc */
  1330 + gen_op_ldl_T0_T1();
  1331 + /* don't set the pc until the rest of the instruction
  1332 + has completed */
  1333 + } else {
  1334 + /* push lr */
  1335 + gen_movl_T0_reg(s, 14);
  1336 + gen_op_stl_T0_T1();
  1337 + }
  1338 + gen_op_addl_T1_T2();
  1339 + }
  1340 +
  1341 + /* write back the new stack pointer */
  1342 + gen_movl_reg_T1(s, 13);
  1343 + /* set the new PC value */
  1344 + if ((insn & 0x0900) == 0x0900)
  1345 + gen_bx(s);
  1346 + break;
  1347 +
  1348 + default:
  1349 + goto undef;
  1350 + }
  1351 + break;
  1352 +
  1353 + case 12:
  1354 + /* load/store multiple */
  1355 + rn = (insn >> 8) & 0x7;
  1356 + gen_movl_T1_reg(s, rn);
  1357 + gen_op_movl_T2_im(4);
  1358 + val = 0;
  1359 + for (i = 0; i < 8; i++) {
  1360 + if (insn & (1 << i)) {
  1361 + /* advance to the next address */
  1362 + if (val)
  1363 + gen_op_addl_T1_T2();
  1364 + else
  1365 + val = 1;
  1366 + if (insn & (1 << 11)) {
  1367 + /* load */
  1368 + gen_op_ldl_T0_T1();
  1369 + gen_movl_reg_T0(s, i);
  1370 + } else {
  1371 + /* store */
  1372 + gen_movl_T0_reg(s, i);
  1373 + gen_op_stl_T0_T1();
  1374 + }
  1375 + }
  1376 + }
  1377 + break;
  1378 +
  1379 + case 13:
  1380 + /* conditional branch or swi */
  1381 + cond = (insn >> 8) & 0xf;
  1382 + if (cond == 0xe)
  1383 + goto undef;
  1384 +
  1385 + if (cond == 0xf) {
  1386 + /* swi */
  1387 + gen_op_movl_T0_im((long)s->pc | 1);
  1388 + /* Don't set r15. */
  1389 + gen_op_movl_reg_TN[0][15]();
  1390 + gen_op_swi();
  1391 + s->is_jmp = DISAS_JUMP;
  1392 + break;
  1393 + }
  1394 + /* generate a conditional jump to next instruction */
  1395 + gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
  1396 + s->is_jmp = DISAS_JUMP_NEXT;
  1397 + gen_movl_T1_reg(s, 15);
  1398 +
  1399 + /* jump to the offset */
  1400 + val = (uint32_t)s->pc;
  1401 + offset = ((int32_t)insn << 24) >> 24;
  1402 + val += (offset << 1) + 2;
  1403 + gen_op_jmp((long)s->tb, val);
  1404 + s->is_jmp = DISAS_TB_JUMP;
  1405 + break;
  1406 +
  1407 + case 14:
  1408 + /* unconditional branch */
  1409 + if (insn & (1 << 11))
  1410 + goto undef; /* Second half of a blx */
  1411 + val = (uint32_t)s->pc;
  1412 + offset = ((int32_t)insn << 21) >> 21;
  1413 + val += (offset << 1) + 2;
  1414 + gen_op_jmp((long)s->tb, val);
  1415 + s->is_jmp = DISAS_TB_JUMP;
  1416 + break;
  1417 +
  1418 + case 15:
  1419 + /* branch and link [and switch to arm] */
  1420 + offset = ((int32_t)insn << 21) >> 10;
  1421 + insn = lduw(s->pc);
  1422 + offset |= insn & 0x7ff;
  1423 +
  1424 + val = (uint32_t)s->pc + 2;
  1425 + gen_op_movl_T1_im(val | 1);
  1426 + gen_movl_reg_T1(s, 14);
  1427 +
  1428 + val += offset;
  1429 + if (insn & (1 << 11)) {
  1430 + /* bl */
  1431 + gen_op_jmp((long)s->tb, val);
  1432 + s->is_jmp = DISAS_TB_JUMP;
  1433 + } else {
  1434 + /* blx */
  1435 + gen_op_movl_T0_im(val);
  1436 + gen_bx(s);
  1437 + }
  1438 + }
  1439 + return;
  1440 +undef:
  1441 + gen_op_movl_T0_im((long)s->pc - 4);
  1442 + gen_op_movl_reg_TN[0][15]();
  1443 + gen_op_undef_insn();
  1444 + s->is_jmp = DISAS_JUMP;
  1445 +}
  1446 +
755 1447 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
756 1448 basic block 'tb'. If search_pc is TRUE, also generate PC
757 1449 information for each intermediate instruction. */
... ... @@ -787,7 +1479,10 @@ static inline int gen_intermediate_code_internal(CPUState *env,
787 1479 gen_opc_pc[lj] = dc->pc;
788 1480 gen_opc_instr_start[lj] = 1;
789 1481 }
790   - disas_arm_insn(dc);
  1482 + if (env->thumb)
  1483 + disas_thumb_insn(dc);
  1484 + else
  1485 + disas_arm_insn(dc);
791 1486 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
792 1487 (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
793 1488 switch(dc->is_jmp) {
... ... @@ -797,6 +1492,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
797 1492 break;
798 1493 default:
799 1494 case DISAS_JUMP:
  1495 + case DISAS_UPDATE:
800 1496 /* indicate that the hash table must be used to find the next TB */
801 1497 gen_op_movl_T0_0();
802 1498 gen_op_exit_tb();
... ...