diff options
Diffstat (limited to 'target-arm')
-rw-r--r-- | target-arm/cpu.h | 32 | ||||
-rw-r--r-- | target-arm/helper.c | 63 | ||||
-rw-r--r-- | target-arm/op.c | 12 | ||||
-rw-r--r-- | target-arm/op_helper.c | 12 | ||||
-rw-r--r-- | target-arm/translate.c | 67 |
5 files changed, 138 insertions, 48 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 052634cd50..75a1f1314b 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -72,6 +72,7 @@ typedef struct CPUARMState { /* System control coprocessor (cp15) */ struct { + uint32_t c0_cpuid; uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ uint32_t c2; /* MMU translation table base. */ @@ -85,7 +86,10 @@ typedef struct CPUARMState { uint32_t c13_fcse; /* FCSE PID. */ uint32_t c13_context; /* Context ID. */ } cp15; - + + /* Internal CPU feature flags. */ + uint32_t features; + /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; @@ -97,12 +101,11 @@ typedef struct CPUARMState { struct { float64 regs[16]; + uint32_t xregs[16]; /* We store these fpcsr fields separately for convenience. */ int vec_len; int vec_stride; - uint32_t fpscr; - /* Temporary variables if we don't have spare fp regs. */ float32 tmp0s, tmp1s; float64 tmp0d, tmp1d; @@ -187,6 +190,29 @@ enum arm_cpu_mode { ARM_CPU_MODE_SYS = 0x1f }; +/* VFP system registers. */ +#define ARM_VFP_FPSID 0 +#define ARM_VFP_FPSCR 1 +#define ARM_VFP_FPEXC 8 +#define ARM_VFP_FPINST 9 +#define ARM_VFP_FPINST2 10 + + +enum arm_features { + ARM_FEATURE_VFP, + ARM_FEATURE_AUXCR /* ARM1026 Auxiliary control register. */ +}; + +static inline int arm_feature(CPUARMState *env, int feature) +{ + return (env->features & (1u << feature)) != 0; +} + +void cpu_arm_set_model(CPUARMState *env, uint32_t id); + +#define ARM_CPUID_ARM1026 0x4106a262 +#define ARM_CPUID_ARM926 0x41069265 + #if defined(CONFIG_USER_ONLY) #define TARGET_PAGE_BITS 12 #else diff --git a/target-arm/helper.c b/target-arm/helper.c index 5804df8264..d0cd6d8e54 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5,6 +5,61 @@ #include "cpu.h" #include "exec-all.h" +void cpu_reset(CPUARMState *env) +{ +#if defined (CONFIG_USER_ONLY) + env->uncached_cpsr = ARM_CPU_MODE_USR; + env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30; +#else + /* SVC mode with interrupts disabled. */ + env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; + env->vfp.xregs[ARM_VFP_FPEXC] = 0; +#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; +} + +static inline void set_feature(CPUARMState *env, int feature) +{ + env->features |= 1u << feature; +} + +void cpu_arm_set_model(CPUARMState *env, uint32_t id) +{ + env->cp15.c0_cpuid = id; + switch (id) { + case ARM_CPUID_ARM926: + set_feature(env, ARM_FEATURE_VFP); + env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; + break; + case ARM_CPUID_ARM1026: + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; + break; + default: + cpu_abort(env, "Bad CPU ID: %x\n", id); + break; + } +} + +void cpu_arm_close(CPUARMState *env) +{ + free(env); +} + #if defined(CONFIG_USER_ONLY) void do_interrupt (CPUState *env) @@ -469,7 +524,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 0: /* ID codes. */ switch (op2) { default: /* Device ID. */ - return 0x4106a262; + return env->cp15.c0_cpuid; case 1: /* Cache Type. */ return 0x1dd20d2; case 2: /* TCM status. */ @@ -480,7 +535,9 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 0: /* Control register. */ return env->cp15.c1_sys; case 1: /* Auxiliary control register. */ - return 1; + if (arm_feature(env, ARM_FEATURE_AUXCR)) + return 1; + goto bad_reg; case 2: /* Coprocessor access register. */ return env->cp15.c1_coproc; default: @@ -506,6 +563,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 0: return env->cp15.c6_data; case 1: + /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't + do any harm. */ return env->cp15.c6_insn; default: goto bad_reg; diff --git a/target-arm/op.c b/target-arm/op.c index f06b06b908..619066d29e 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -1094,7 +1094,7 @@ void OPPROTO op_vfp_movl_T0_fpscr(void) void OPPROTO op_vfp_movl_T0_fpscr_flags(void) { - T0 = env->vfp.fpscr & (0xf << 28); + T0 = env->vfp.xregs[ARM_VFP_FPSCR] & (0xf << 28); } void OPPROTO op_vfp_movl_fpscr_T0(void) @@ -1102,6 +1102,16 @@ void OPPROTO op_vfp_movl_fpscr_T0(void) do_vfp_set_fpscr(); } +void OPPROTO op_vfp_movl_T0_xreg(void) +{ + T0 = env->vfp.xregs[PARAM1]; +} + +void OPPROTO op_vfp_movl_xreg_T0(void) +{ + env->vfp.xregs[PARAM1] = T0; +} + /* Move between FT0s to T0 */ void OPPROTO op_vfp_mrs(void) { diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index c075b53fcb..af5c61d0b4 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -72,7 +72,8 @@ void do_vfp_cmp##p(void) \ case 1: flags = 0x2; break;\ default: case 2: flags = 0x3; break;\ }\ - env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ FORCE_RET(); \ }\ \ @@ -85,7 +86,8 @@ void do_vfp_cmpe##p(void) \ case 1: flags = 0x2; break;\ default: case 2: flags = 0x3; break;\ }\ - env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ FORCE_RET(); \ } DO_VFP_cmp(s, 32) @@ -133,8 +135,8 @@ void do_vfp_set_fpscr(void) int i; uint32_t changed; - changed = env->vfp.fpscr; - env->vfp.fpscr = (T0 & 0xffc8ffff); + changed = env->vfp.xregs[ARM_VFP_FPSCR]; + env->vfp.xregs[ARM_VFP_FPSCR] = (T0 & 0xffc8ffff); env->vfp.vec_len = (T0 >> 16) & 7; env->vfp.vec_stride = (T0 >> 20) & 3; @@ -167,7 +169,7 @@ void do_vfp_get_fpscr(void) { int i; - T0 = (env->vfp.fpscr & 0xffc8ffff) | (env->vfp.vec_len << 16) + T0 = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) | (env->vfp.vec_len << 16) | (env->vfp.vec_stride << 20); i = get_float_exception_flags(&env->vfp.fp_status); T0 |= vfp_exceptbits_from_host(i); diff --git a/target-arm/translate.c b/target-arm/translate.c index 93905793a0..1f8a4853bb 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -526,6 +526,17 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t 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: @@ -563,11 +574,15 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) /* 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 @@ -589,17 +604,24 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) /* 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; } @@ -2456,35 +2478,6 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } -void cpu_reset(CPUARMState *env) -{ -#if defined (CONFIG_USER_ONLY) - env->uncached_cpsr = ARM_CPU_MODE_USR; -#else - /* SVC mode with interrupts disabled. */ - env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; -#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" @@ -2528,6 +2521,6 @@ void cpu_dump_state(CPUState *env, FILE *f, 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]); } |