diff options
Diffstat (limited to 'target-arm')
-rw-r--r-- | target-arm/cpu.h | 38 | ||||
-rw-r--r-- | target-arm/exec.h | 2 | ||||
-rw-r--r-- | target-arm/helper.c | 135 | ||||
-rw-r--r-- | target-arm/op.c | 14 | ||||
-rw-r--r-- | target-arm/translate.c | 37 |
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)) |