if (IS_USER(s)) {
return 1;
}
+ if ((insn & 0x0fff0fff) == 0x0e070f90
+ || (insn & 0x0fff0fff) == 0x0e070f58) {
+ /* Wait for interrupt. */
+ gen_op_movl_T0_im((long)s->pc);
+ gen_op_movl_reg_TN[0][15]();
+ gen_op_wfi();
+ s->is_jmp = DISAS_JUMP;
+ return 0;
+ }
rd = (insn >> 12) & 0xf;
if (insn & (1 << 20)) {
gen_op_movl_T0_cp15(insn);
uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
int dp, veclen;
+ if (!arm_feature(env, ARM_FEATURE_VFP))
+ return 1;
+
+ if ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) == 0) {
+ /* VFP disabled. Only allow fmxr/fmrx to/from fpexc and fpsid. */
+ if ((insn & 0x0fe00fff) != 0x0ee00a10)
+ return 1;
+ rn = (insn >> 16) & 0xf;
+ if (rn != 0 && rn != 8)
+ return 1;
+ }
dp = ((insn & 0xf00) == 0xb00);
switch ((insn >> 24) & 0xf) {
case 0xe:
/* vfp->arm */
if (insn & (1 << 21)) {
/* system register */
+ rn >>= 1;
switch (rn) {
- case 0: /* fpsid */
- n = 0x0091A0000;
+ case ARM_VFP_FPSID:
+ case ARM_VFP_FPEXC:
+ case ARM_VFP_FPINST:
+ case ARM_VFP_FPINST2:
+ gen_op_vfp_movl_T0_xreg(rn);
break;
- case 2: /* fpscr */
+ case ARM_VFP_FPSCR:
if (rd == 15)
gen_op_vfp_movl_T0_fpscr_flags();
else
/* arm->vfp */
gen_movl_T0_reg(s, rd);
if (insn & (1 << 21)) {
+ rn >>= 1;
/* system register */
switch (rn) {
- case 0: /* fpsid */
+ case ARM_VFP_FPSID:
/* Writes are ignored. */
break;
- case 2: /* fpscr */
+ case ARM_VFP_FPSCR:
gen_op_vfp_movl_fpscr_T0();
- /* This could change vector settings, so jump to
- the next instuction. */
gen_lookup_tb(s);
break;
+ case ARM_VFP_FPEXC:
+ gen_op_vfp_movl_xreg_T0(rn);
+ gen_lookup_tb(s);
+ break;
+ case ARM_VFP_FPINST:
+ case ARM_VFP_FPINST2:
+ gen_op_vfp_movl_xreg_T0(rn);
+ break;
default:
return 1;
}
static inline void gen_mulxy(int x, int y)
{
- if (x & 2)
+ if (x)
gen_op_sarl_T0_im(16);
else
gen_op_sxth_T0();
- if (y & 1)
+ if (y)
gen_op_sarl_T1_im(16);
else
gen_op_sxth_T1();
}
/* Return the mask of PSR bits set by a MSR instruction. */
-static uint32_t msr_mask(DisasContext *s, int flags) {
+static uint32_t msr_mask(DisasContext *s, int flags, int spsr) {
uint32_t mask;
mask = 0;
mask |= 0xff0000;
if (flags & (1 << 3))
mask |= 0xff000000;
- /* Mask out undefined bits and state bits. */
- mask &= 0xf89f03df;
+ /* Mask out undefined bits. */
+ mask &= 0xf90f03ff;
+ /* Mask out state bits. */
+ if (!spsr)
+ mask &= ~0x01000020;
/* Mask out privileged bits. */
if (IS_USER(s))
mask &= 0xf80f0200;
if (shift)
val = (val >> shift) | (val << (32 - shift));
gen_op_movl_T0_im(val);
- if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf),
- (insn & (1 << 22)) != 0))
+ i = ((insn & (1 << 22)) != 0);
+ if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
goto illegal_op;
} else if ((insn & 0x0f900000) == 0x01000000
&& (insn & 0x00000090) != 0x00000090) {
if (op1 & 1) {
/* PSR = reg */
gen_movl_T0_reg(s, rm);
- if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf),
- (op1 & 2) != 0))
+ i = ((op1 & 2) != 0);
+ if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
goto illegal_op;
} else {
- /* reg = CPSR */
+ /* reg = PSR */
rd = (insn >> 12) & 0xf;
if (op1 & 2) {
if (IS_USER(s))
gen_op_addl_T0_T1_saturate();
gen_movl_reg_T0(s, rd);
break;
+ case 7: /* bkpt */
+ gen_op_movl_T0_im((long)s->pc - 4);
+ gen_op_movl_reg_TN[0][15]();
+ gen_op_bkpt();
+ s->is_jmp = DISAS_JUMP;
+ break;
case 0x8: /* signed multiply */
case 0xa:
case 0xc:
case 0x08:
case 0x09:
{
- int j, n, user;
+ int j, n, user, loaded_base;
/* load/store multiple words */
/* XXX: store correct base if write back */
user = 0;
gen_movl_T1_reg(s, rn);
/* compute total size */
+ loaded_base = 0;
n = 0;
for(i=0;i<16;i++) {
if (insn & (1 << i))
gen_bx(s);
} else if (user) {
gen_op_movl_user_T0(i);
+ } else if (i == rn) {
+ gen_op_movl_T2_T0();
+ loaded_base = 1;
} else {
gen_movl_reg_T0(s, i);
}
}
gen_movl_reg_T1(s, rn);
}
+ if (loaded_base) {
+ gen_op_movl_T0_T2();
+ gen_movl_reg_T0(s, rn);
+ }
if ((insn & (1 << 22)) && !user) {
/* Restore CPSR from SPSR. */
gen_op_movl_T0_spsr();
break;
case 0x2: /* lsl */
gen_op_shll_T1_T0_cc();
+ gen_op_logic_T1_cc();
break;
case 0x3: /* lsr */
gen_op_shrl_T1_T0_cc();
+ gen_op_logic_T1_cc();
break;
case 0x4: /* asr */
gen_op_sarl_T1_T0_cc();
+ gen_op_logic_T1_cc();
break;
case 0x5: /* adc */
gen_op_adcl_T0_T1_cc();
break;
case 0x7: /* ror */
gen_op_rorl_T1_T0_cc();
+ gen_op_logic_T1_cc();
break;
case 0x8: /* tst */
gen_op_andl_T0_T1();
gen_bx(s);
break;
+ case 0xe: /* bkpt */
+ gen_op_movl_T0_im((long)s->pc - 2);
+ gen_op_movl_reg_TN[0][15]();
+ gen_op_bkpt();
+ s->is_jmp = DISAS_JUMP;
+ break;
+
default:
goto undef;
}
case 14:
/* unconditional branch */
- if (insn & (1 << 11))
- goto undef; /* Second half of a blx */
+ if (insn & (1 << 11)) {
+ /* Second half of blx. */
+ offset = ((insn & 0x7ff) << 1);
+ gen_movl_T0_reg(s, 14);
+ gen_op_movl_T1_im(offset);
+ gen_op_addl_T0_T1();
+ gen_op_movl_T1_im(0xfffffffc);
+ gen_op_andl_T0_T1();
+
+ val = (uint32_t)s->pc;
+ gen_op_movl_T1_im(val | 1);
+ gen_movl_reg_T1(s, 14);
+ gen_bx(s);
+ break;
+ }
val = (uint32_t)s->pc;
offset = ((int32_t)insn << 21) >> 21;
val += (offset << 1) + 2;
case 15:
/* branch and link [and switch to arm] */
+ if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
+ /* Instruction spans a page boundary. Implement it as two
+ 16-bit instructions in case the second half causes an
+ prefetch abort. */
+ offset = ((int32_t)insn << 21) >> 9;
+ val = s->pc + 2 + offset;
+ gen_op_movl_T0_im(val);
+ gen_movl_reg_T0(s, 14);
+ break;
+ }
+ if (insn & (1 << 11)) {
+ /* Second half of bl. */
+ offset = ((insn & 0x7ff) << 1) | 1;
+ gen_movl_T0_reg(s, 14);
+ gen_op_movl_T1_im(offset);
+ gen_op_addl_T0_T1();
+
+ val = (uint32_t)s->pc;
+ gen_op_movl_T1_im(val | 1);
+ gen_movl_reg_T1(s, 14);
+ gen_bx(s);
+ break;
+ }
offset = ((int32_t)insn << 21) >> 10;
insn = lduw_code(s->pc);
offset |= insn & 0x7ff;
return gen_intermediate_code_internal(env, tb, 1);
}
-void cpu_reset(CPUARMState *env)
-{
-#if defined (CONFIG_USER_ONLY)
- /* SVC mode with interrupts disabled. */
- env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
-#else
- env->uncached_cpsr = ARM_CPU_MODE_USR;
-#endif
- env->regs[15] = 0;
-}
-
-CPUARMState *cpu_arm_init(void)
-{
- CPUARMState *env;
-
- env = qemu_mallocz(sizeof(CPUARMState));
- if (!env)
- return NULL;
- cpu_exec_init(env);
- cpu_reset(env);
- tlb_flush(env, 1);
- return env;
-}
-
-void cpu_arm_close(CPUARMState *env)
-{
- free(env);
-}
-
static const char *cpu_mode_names[16] = {
"usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
"???", "???", "???", "und", "???", "???", "???", "sys"
i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
d.d);
}
- cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr);
+ cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
}