aboutsummaryrefslogtreecommitdiff
path: root/target-arm
diff options
context:
space:
mode:
Diffstat (limited to 'target-arm')
-rw-r--r--target-arm/cpu.h38
-rw-r--r--target-arm/exec.h2
-rw-r--r--target-arm/helper.c135
-rw-r--r--target-arm/op.c14
-rw-r--r--target-arm/translate.c37
5 files changed, 210 insertions, 16 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 68bf3fd0f4..6e2ae905fe 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -38,6 +38,11 @@
#define EXCP_FIQ 6
#define EXCP_BKPT 7
+typedef void ARMWriteCPFunc(void *opaque, int cp_info,
+ int srcreg, int operand, uint32_t value);
+typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
+ int dstreg, int operand);
+
/* We currently assume float and double are IEEE single and double
precision respectively.
Doing runtime conversions is tricky because VFP registers may contain
@@ -75,6 +80,7 @@ typedef struct CPUARMState {
/* System control coprocessor (cp15) */
struct {
uint32_t c0_cpuid;
+ uint32_t c0_cachetype;
uint32_t c1_sys; /* System control register. */
uint32_t c1_coproc; /* Coprocessor access register. */
uint32_t c2; /* MMU translation table base. */
@@ -87,8 +93,16 @@ typedef struct CPUARMState {
uint32_t c9_data;
uint32_t c13_fcse; /* FCSE PID. */
uint32_t c13_context; /* Context ID. */
+ uint32_t c15_cpar; /* XScale Coprocessor Access Register */
} cp15;
+ /* Coprocessor IO used by peripherals */
+ struct {
+ ARMReadCPFunc *cp_read;
+ ARMWriteCPFunc *cp_write;
+ void *opaque;
+ } cp[15];
+
/* Internal CPU feature flags. */
uint32_t features;
@@ -204,10 +218,10 @@ enum arm_cpu_mode {
#define ARM_VFP_FPINST 9
#define ARM_VFP_FPINST2 10
-
enum arm_features {
ARM_FEATURE_VFP,
- ARM_FEATURE_AUXCR /* ARM1026 Auxiliary control register. */
+ ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
+ ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
};
static inline int arm_feature(CPUARMState *env, int feature)
@@ -218,8 +232,24 @@ static inline int arm_feature(CPUARMState *env, int feature)
void arm_cpu_list(void);
void cpu_arm_set_model(CPUARMState *env, const char *name);
-#define ARM_CPUID_ARM1026 0x4106a262
-#define ARM_CPUID_ARM926 0x41069265
+void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
+ ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
+ void *opaque);
+
+#define ARM_CPUID_ARM1026 0x4106a262
+#define ARM_CPUID_ARM926 0x41069265
+#define ARM_CPUID_PXA250 0x69052100
+#define ARM_CPUID_PXA255 0x69052d00
+#define ARM_CPUID_PXA260 0x69052903
+#define ARM_CPUID_PXA261 0x69052d05
+#define ARM_CPUID_PXA262 0x69052d06
+#define ARM_CPUID_PXA270 0x69054110
+#define ARM_CPUID_PXA270_A0 0x69054110
+#define ARM_CPUID_PXA270_A1 0x69054111
+#define ARM_CPUID_PXA270_B0 0x69054112
+#define ARM_CPUID_PXA270_B1 0x69054113
+#define ARM_CPUID_PXA270_C0 0x69054114
+#define ARM_CPUID_PXA270_C5 0x69054117
#if defined(CONFIG_USER_ONLY)
#define TARGET_PAGE_BITS 12
diff --git a/target-arm/exec.h b/target-arm/exec.h
index e73e12dc5c..87c41b218e 100644
--- a/target-arm/exec.h
+++ b/target-arm/exec.h
@@ -54,6 +54,8 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
void cpu_lock(void);
void cpu_unlock(void);
+void helper_set_cp(CPUState *, uint32_t, uint32_t);
+uint32_t helper_get_cp(CPUState *, uint32_t);
void helper_set_cp15(CPUState *, uint32_t, uint32_t);
uint32_t helper_get_cp15(CPUState *, uint32_t);
diff --git a/target-arm/helper.c b/target-arm/helper.c
index bae4c9fdb7..798df304e1 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -17,11 +17,32 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_ARM926:
set_feature(env, ARM_FEATURE_VFP);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
+ env->cp15.c0_cachetype = 0x1dd20d2;
break;
case ARM_CPUID_ARM1026:
set_feature(env, ARM_FEATURE_VFP);
set_feature(env, ARM_FEATURE_AUXCR);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
+ env->cp15.c0_cachetype = 0x1dd20d2;
+ break;
+ case ARM_CPUID_PXA250:
+ case ARM_CPUID_PXA255:
+ case ARM_CPUID_PXA260:
+ case ARM_CPUID_PXA261:
+ case ARM_CPUID_PXA262:
+ set_feature(env, ARM_FEATURE_XSCALE);
+ /* JTAG_ID is ((id << 28) | 0x09265013) */
+ env->cp15.c0_cachetype = 0xd172172;
+ break;
+ case ARM_CPUID_PXA270_A0:
+ case ARM_CPUID_PXA270_A1:
+ case ARM_CPUID_PXA270_B0:
+ case ARM_CPUID_PXA270_B1:
+ case ARM_CPUID_PXA270_C0:
+ case ARM_CPUID_PXA270_C5:
+ set_feature(env, ARM_FEATURE_XSCALE);
+ /* JTAG_ID is ((id << 28) | 0x09265013) */
+ env->cp15.c0_cachetype = 0xd172172;
break;
default:
cpu_abort(env, "Bad CPU ID: %x\n", id);
@@ -68,6 +89,18 @@ struct arm_cpu_t {
static const struct arm_cpu_t arm_cpu_names[] = {
{ ARM_CPUID_ARM926, "arm926"},
{ ARM_CPUID_ARM1026, "arm1026"},
+ { ARM_CPUID_PXA250, "pxa250" },
+ { ARM_CPUID_PXA255, "pxa255" },
+ { ARM_CPUID_PXA260, "pxa260" },
+ { ARM_CPUID_PXA261, "pxa261" },
+ { ARM_CPUID_PXA262, "pxa262" },
+ { ARM_CPUID_PXA270, "pxa270" },
+ { ARM_CPUID_PXA270_A0, "pxa270-a0" },
+ { ARM_CPUID_PXA270_A1, "pxa270-a1" },
+ { ARM_CPUID_PXA270_B0, "pxa270-b0" },
+ { ARM_CPUID_PXA270_B1, "pxa270-b1" },
+ { ARM_CPUID_PXA270_C0, "pxa270-c0" },
+ { ARM_CPUID_PXA270_C5, "pxa270-c5" },
{ 0, NULL}
};
@@ -132,6 +165,20 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
}
/* These should probably raise undefined insn exceptions. */
+void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
+{
+ int op1 = (insn >> 8) & 0xf;
+ cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+ return;
+}
+
+uint32_t helper_get_cp(CPUState *env, uint32_t insn)
+{
+ int op1 = (insn >> 8) & 0xf;
+ cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+ return 0;
+}
+
void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
{
cpu_abort(env, "cp15 insn %08x\n", insn);
@@ -393,12 +440,16 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type,
ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
break;
case 3: /* 1k page. */
- if (type == 1) {
- /* Page translation fault. */
- code = 7;
- goto do_fault;
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+ else {
+ if (type == 1) {
+ /* Page translation fault. */
+ code = 7;
+ goto do_fault;
+ }
+ phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
}
- phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
ap = (desc >> 4) & 3;
break;
default:
@@ -461,6 +512,31 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
return phys_addr;
}
+void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
+{
+ int cp_num = (insn >> 8) & 0xf;
+ int cp_info = (insn >> 5) & 7;
+ int src = (insn >> 16) & 0xf;
+ int operand = insn & 0xf;
+
+ if (env->cp[cp_num].cp_write)
+ env->cp[cp_num].cp_write(env->cp[cp_num].opaque,
+ cp_info, src, operand, val);
+}
+
+uint32_t helper_get_cp(CPUState *env, uint32_t insn)
+{
+ int cp_num = (insn >> 8) & 0xf;
+ int cp_info = (insn >> 5) & 7;
+ int dest = (insn >> 16) & 0xf;
+ int operand = insn & 0xf;
+
+ if (env->cp[cp_num].cp_read)
+ return env->cp[cp_num].cp_read(env->cp[cp_num].opaque,
+ cp_info, dest, operand);
+ return 0;
+}
+
void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
{
uint32_t op2;
@@ -472,15 +548,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
case 1: /* System configuration. */
switch (op2) {
case 0:
- env->cp15.c1_sys = val;
+ if (!arm_feature(env, ARM_FEATURE_XSCALE) || (insn & 0xf) == 0)
+ env->cp15.c1_sys = val;
/* ??? Lots of these bits are not implemented. */
/* This may enable/disable the MMU, so do a TLB flush. */
tlb_flush(env, 1);
break;
+ case 1:
+ /* XScale doesn't implement AUX CR (P-Bit) but allows
+ * writing with zero and reading. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ break;
+ goto bad_reg;
case 2:
env->cp15.c1_coproc = val;
/* ??? Is this safe when called from within a TB? */
tb_flush(env);
+ break;
default:
goto bad_reg;
}
@@ -584,13 +668,21 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
case 14: /* Reserved. */
goto bad_reg;
case 15: /* Implementation specific. */
- /* ??? Internal registers not implemented. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ if (op2 == 0 && (insn & 0xf) == 1) {
+ /* Changes cp0 to cp13 behavior, so needs a TB flush. */
+ tb_flush(env);
+ env->cp15.c15_cpar = (val & 0x3fff) | 2;
+ break;
+ }
+ goto bad_reg;
+ }
break;
}
return;
bad_reg:
/* ??? For debugging only. Should raise illegal instruction exception. */
- cpu_abort(env, "Unimplemented cp15 register read\n");
+ cpu_abort(env, "Unimplemented cp15 register write\n");
}
uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
@@ -604,7 +696,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
default: /* Device ID. */
return env->cp15.c0_cpuid;
case 1: /* Cache Type. */
- return 0x1dd20d2;
+ return env->cp15.c0_cachetype;
case 2: /* TCM status. */
return 0;
}
@@ -615,6 +707,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
case 1: /* Auxiliary control register. */
if (arm_feature(env, ARM_FEATURE_AUXCR))
return 1;
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ return 0;
goto bad_reg;
case 2: /* Coprocessor access register. */
return env->cp15.c1_coproc;
@@ -649,7 +743,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
}
case 7: /* Cache control. */
/* ??? This is for test, clean and invaidate operations that set the
- Z flag. We can't represent N = Z = 1, so it also clears clears
+ Z flag. We can't represent N = Z = 1, so it also clears
the N flag. Oh well. */
env->NZF = 0;
return 0;
@@ -682,7 +776,12 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
case 14: /* Reserved. */
goto bad_reg;
case 15: /* Implementation specific. */
- /* ??? Internal registers not implemented. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ if (op2 == 0 && (insn & 0xf) == 1)
+ return env->cp15.c15_cpar;
+
+ goto bad_reg;
+ }
return 0;
}
bad_reg:
@@ -691,4 +790,18 @@ bad_reg:
return 0;
}
+void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
+ ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
+ void *opaque)
+{
+ if (cpnum < 0 || cpnum > 14) {
+ cpu_abort(env, "Bad coprocessor number: %i\n", cpnum);
+ return;
+ }
+
+ env->cp[cpnum].cp_read = cp_read;
+ env->cp[cpnum].cp_write = cp_write;
+ env->cp[cpnum].opaque = opaque;
+}
+
#endif
diff --git a/target-arm/op.c b/target-arm/op.c
index f17b812737..9cfb46237b 100644
--- a/target-arm/op.c
+++ b/target-arm/op.c
@@ -1142,12 +1142,24 @@ void OPPROTO op_vfp_mdrr(void)
FT0d = u.d;
}
-/* Copy the most significant bit to T0 to all bits of T1. */
+/* Copy the most significant bit of T0 to all bits of T1. */
void OPPROTO op_signbit_T1_T0(void)
{
T1 = (int32_t)T0 >> 31;
}
+void OPPROTO op_movl_cp_T0(void)
+{
+ helper_set_cp(env, PARAM1, T0);
+ FORCE_RET();
+}
+
+void OPPROTO op_movl_T0_cp(void)
+{
+ T0 = helper_get_cp(env, PARAM1);
+ FORCE_RET();
+}
+
void OPPROTO op_movl_cp15_T0(void)
{
helper_set_cp15(env, PARAM1, T0);
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 1631fcd312..65d234ae00 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -492,6 +492,34 @@ static inline void gen_mov_vreg_F0(int dp, int reg)
gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
}
+/* Disassemble system coprocessor instruction. Return nonzero if
+ instruction is not defined. */
+static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+ uint32_t rd = (insn >> 12) & 0xf;
+ uint32_t cp = (insn >> 8) & 0xf;
+ if (IS_USER(s)) {
+ return 1;
+ }
+
+ if (insn & (1 << 20)) {
+ if (!env->cp[cp].cp_read)
+ return 1;
+ gen_op_movl_T0_im((uint32_t) s->pc);
+ gen_op_movl_reg_TN[0][15]();
+ gen_op_movl_T0_cp(insn);
+ gen_movl_reg_T0(s, rd);
+ } else {
+ if (!env->cp[cp].cp_write)
+ return 1;
+ gen_op_movl_T0_im((uint32_t) s->pc);
+ gen_op_movl_reg_TN[0][15]();
+ gen_movl_T0_reg(s, rd);
+ gen_op_movl_cp_T0(insn);
+ }
+ return 0;
+}
+
/* Disassemble system coprocessor (cp15) instruction. Return nonzero if
instruction is not defined. */
static int disas_cp15_insn(DisasContext *s, uint32_t insn)
@@ -1812,7 +1840,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 0xe:
/* Coprocessor. */
op1 = (insn >> 8) & 0xf;
+ if (arm_feature(env, ARM_FEATURE_XSCALE) &&
+ ((env->cp15.c15_cpar ^ 0x3fff) & (1 << op1)))
+ goto illegal_op;
switch (op1) {
+ case 0 ... 1:
+ case 2 ... 9:
+ case 12 ... 14:
+ if (disas_cp_insn (env, s, insn))
+ goto illegal_op;
+ break;
case 10:
case 11:
if (disas_vfp_insn (env, s, insn))