aboutsummaryrefslogtreecommitdiff
path: root/target-arm
diff options
context:
space:
mode:
Diffstat (limited to 'target-arm')
-rw-r--r--target-arm/cpu.h32
-rw-r--r--target-arm/helper.c63
-rw-r--r--target-arm/op.c12
-rw-r--r--target-arm/op_helper.c12
-rw-r--r--target-arm/translate.c67
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]);
}