qemu-devel
[Top][All Lists]
Advanced

[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;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]