[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] ARM XScale extension
From: |
Thorsten Zitterell |
Subject: |
[Qemu-devel] ARM XScale extension |
Date: |
Wed, 04 Oct 2006 23:49:23 +0200 |
User-agent: |
Thunderbird 1.5.0.7 (X11/20061003) |
Hi,
the attached file includes preliminary support for the Intel XScale CPU.
I have also written code which emulates a Gumstix [1] system in QEMU -
based on this processor - and got a Linux kernel up and running.
Could you please apply this patch to CVS?
Comments?
I will send further patches if this is all right so far...
--
Thorsten
[1] http://www.gumstix.org
diff -u -r qemu.orig/target-arm/cpu.h qemu.new/target-arm/cpu.h
--- qemu.orig/target-arm/cpu.h 2006-02-20 01:33:36.000000000 +0100
+++ qemu.new/target-arm/cpu.h 2006-10-04 22:11:15.532962000 +0200
@@ -47,6 +47,8 @@
typedef struct CPUARMState {
/* Regs for current mode. */
uint32_t regs[16];
+ /* Accumulator for XScale, by now only ACC0 supported */
+ uint64_t acc[8];
/* Frequently accessed CPSR bits are stored separately for efficiently.
This contains all the other bits. Use cpsr_{read,write} to accless
the whole CPSR. */
@@ -69,6 +71,14 @@
uint32_t QF; /* 0 or 1 */
int thumb; /* 0 = arm mode, 1 = thumb mode */
+
+ /* System control coprocessor (cp14) */
+ struct {
+ uint32_t pmnc; /* Performance Monitor Control Register */
+ uint32_t ccnt; /* Clock Counter Register */
+ uint32_t pmn0; /* Performance Count Register 0 */
+ uint32_t pmn1; /* Performance Count Register 1 */
+ } cp14;
/* System control coprocessor (cp15) */
struct {
@@ -200,7 +210,8 @@
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)
@@ -212,6 +223,7 @@
#define ARM_CPUID_ARM1026 0x4106a262
#define ARM_CPUID_ARM926 0x41069265
+#define ARM_CPUID_PXA255 0x69052d00
#if defined(CONFIG_USER_ONLY)
#define TARGET_PAGE_BITS 12
diff -u -r qemu.orig/target-arm/exec.h qemu.new/target-arm/exec.h
--- qemu.orig/target-arm/exec.h 2005-11-26 11:38:39.000000000 +0100
+++ qemu.new/target-arm/exec.h 2006-07-05 16:00:25.000000000 +0200
@@ -53,6 +53,8 @@
void cpu_lock(void);
void cpu_unlock(void);
+void helper_set_cp14(CPUState *, uint32_t, uint32_t);
+uint32_t helper_get_cp14(CPUState *, uint32_t);
void helper_set_cp15(CPUState *, uint32_t, uint32_t);
uint32_t helper_get_cp15(CPUState *, uint32_t);
diff -u -r qemu.orig/target-arm/helper.c qemu.new/target-arm/helper.c
--- qemu.orig/target-arm/helper.c 2006-09-09 16:36:26.000000000 +0200
+++ qemu.new/target-arm/helper.c 2006-10-04 22:12:11.995788000 +0200
@@ -40,6 +40,9 @@
{
env->cp15.c0_cpuid = id;
switch (id) {
+ case ARM_CPUID_PXA255:
+ set_feature(env, ARM_FEATURE_XSCALE);
+ break;
case ARM_CPUID_ARM926:
set_feature(env, ARM_FEATURE_VFP);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
@@ -322,13 +325,17 @@
phys_addr = (desc & 0xfffff000) | (address & 0xfff);
ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
break;
- case 3: /* 1k page. */
- if (type == 1) {
- /* Page translation fault. */
- code = 7;
- goto do_fault;
+ case 3: /* 1k page. */
+ 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:
@@ -391,6 +398,62 @@
return phys_addr;
}
+void helper_set_cp14(CPUState *env, uint32_t insn, uint32_t val)
+{
+ uint32_t op2;
+
+ op2 = (insn >> 5) & 7;
+ switch ((insn >> 16) & 0xf) {
+ case 0: /* Performance Monitor Control Register */
+ env->cp14.pmnc = val;
+ printf("Performance registers unsupported!\n");
+ break;
+ case 1: /* Performance Monitor Control Register */
+ env->cp14.ccnt = val;
+ printf("Performance registers unsupported!\n");
+ break;
+ case 2: /* Performance Monitor Control Register 0 */
+ env->cp14.pmn0 = val;
+ printf("Performance registers unsupported!\n");
+ break;
+ case 3: /* Performance Monitor Control Register 1 */
+ env->cp14.pmn1 = val;
+ printf("Performance registers unsupported!\n");
+ break;
+ }
+ return;
+bad_reg:
+ /* ??? For debugging only. Should raise illegal instruction exception. */
+ cpu_abort(env, "Unimplemented cp14 register read\n");
+ return;
+}
+
+uint32_t helper_get_cp14(CPUState *env, uint32_t insn)
+{
+ uint32_t op2;
+
+ op2 = (insn >> 5) & 7;
+ switch ((insn >> 16) & 0xf) {
+ case 0: /* Performance Monitor Control Register */
+ printf("Performance registers unsupported!\n");
+ return env->cp14.pmnc;
+ case 1: /* Performance Monitor Control Register */
+ printf("Performance registers unsupported!\n");
+ return env->cp14.ccnt;
+ case 2: /* Performance Monitor Control Register 0 */
+ printf("Performance registers unsupported!\n");
+ return env->cp14.pmn0;
+ case 3: /* Performance Monitor Control Register 1 */
+ printf("Performance registers unsupported!\n");
+ return env->cp14.pmn1;
+ }
+ return 0;
+bad_reg:
+ /* ??? For debugging only. Should raise illegal instruction exception. */
+ cpu_abort(env, "Unimplemented cp14 register read\n");
+ return 0;
+}
+
void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
{
uint32_t op2;
diff -u -r qemu.orig/target-arm/op.c qemu.new/target-arm/op.c
--- qemu.orig/target-arm/op.c 2006-06-26 21:55:19.000000000 +0200
+++ qemu.new/target-arm/op.c 2006-10-04 23:29:19.499215000 +0200
@@ -85,6 +85,21 @@
#define SET_REG(x) REG = x & ~(uint32_t)1
#include "op_template.h"
+void OPPROTO op_acc0_T0_T1(void)
+{
+ uint64_t res;
+ res = ((uint64_t)T0 << 32) | T1;
+ env->acc[0] = res;
+}
+
+void OPPROTO op_T0_T1_acc0(void)
+{
+ uint64_t res;
+ res = env->acc[0];
+ T0 = res >> 32;
+ T1 = res & 0xffffffff;
+}
+
void OPPROTO op_bx_T0(void)
{
env->regs[15] = T0 & ~(uint32_t)1;
@@ -1148,6 +1163,19 @@
T1 = (int32_t)T0 >> 31;
}
+void OPPROTO op_movl_cp14_T0(void)
+{
+ helper_set_cp14(env, PARAM1, T0);
+ FORCE_RET();
+}
+
+void OPPROTO op_movl_T0_cp14(void)
+{
+ T0 = helper_get_cp14(env, PARAM1);
+ FORCE_RET();
+}
+
+
void OPPROTO op_movl_cp15_T0(void)
{
helper_set_cp15(env, PARAM1, T0);
diff -u -r qemu.orig/target-arm/translate.c qemu.new/target-arm/translate.c
--- qemu.orig/target-arm/translate.c 2006-06-14 16:36:07.000000000 +0200
+++ qemu.new/target-arm/translate.c 2006-10-04 22:59:51.695175000 +0200
@@ -490,6 +490,63 @@
gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
}
+/* Disassemble system coprocessor (cp0) instruction. Return nonzero if
+ instruction is not defined. */
+static int disas_cp0_insn(DisasContext *s, uint32_t insn)
+{
+ uint32_t rdhi, rdlo;
+ if ((insn & 0x0fe00f10) == 0x0e200010) {
+ printf ("cp0 multiply\n");
+ return 1;
+ } else if ((insn & 0x0fe00ff8) == 0x0c400000) {
+ rdhi = (insn >> 16) & 0xf;
+ rdlo = (insn >> 12) & 0xf;
+ if (insn & (1 << 20)) {
+ /* write ACC */
+ gen_op_T0_T1_acc0;
+ gen_op_movl_TN_reg[0][rdhi]();
+ gen_op_movl_TN_reg[1][rdlo]();
+ } else {
+ /* read ACC */
+ gen_op_movl_reg_TN[0][rdhi]();
+ gen_op_movl_reg_TN[1][rdlo]();
+ gen_op_acc0_T0_T1;
+ }
+ return 0;
+ } else printf("Unknown cp0 instruction\n");
+ return 1;
+}
+
+/* Disassemble system coprocessor (cp14) instruction. Return nonzero if
+ instruction is not defined. */
+static int disas_cp14_insn(DisasContext *s, uint32_t insn)
+{
+ uint32_t rd;
+ /*
+ xxxx1110 oooLNNNN ddddpppp qqq1MMMM MRC/MCR
+ MCR/MCR p,o,Rd,CRN,CRM,q
+ */
+
+ if (IS_USER(s)) {
+ return 1;
+ }
+ if ((insn & 0x0f000f00) == 0x0e000e00) { /* fixme */
+ rd = (insn >> 12) & 0xf;
+ if (insn & (1 << 20)) { /* 0/1 Store/Load */
+ gen_op_movl_T0_cp14(insn);
+ gen_movl_reg_T0(s, rd);
+ } else {
+ gen_movl_T0_reg(s, rd);
+ gen_op_movl_cp14_T0(insn);
+ }
+ return 0;
+ } else printf("Unknown cp14 instruction\n");
+ return 1;
+
+ printf("cp14 instruction %x\n",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)
@@ -1795,11 +1852,19 @@
/* Coprocessor. */
op1 = (insn >> 8) & 0xf;
switch (op1) {
+ case 0:
+ if (disas_cp0_insn (s, insn))
+ goto illegal_op;
+ break;
case 10:
case 11:
if (disas_vfp_insn (env, s, insn))
goto illegal_op;
break;
+ case 14:
+ if (disas_cp14_insn (s, insn))
+ goto illegal_op;
+ break;
case 15:
if (disas_cp15_insn (s, insn))
goto illegal_op;
- [Qemu-devel] ARM XScale extension,
Thorsten Zitterell <=