]> git.proxmox.com Git - mirror_qemu.git/commitdiff
sparc support
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 29 Apr 2003 21:26:53 +0000 (21:26 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 29 Apr 2003 21:26:53 +0000 (21:26 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@119 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-i386.h
dyngen.c
exec-i386.c
exec-i386.h
op-i386.c
translate-i386.c

index ca33791351a44096ed6084853d7b4f64c7304504..4b8aef12adf74b867bddaced1dc4af5c47ee572c 100644 (file)
@@ -180,6 +180,12 @@ typedef struct CPUX86State {
 
     /* emulator internal variables */
     CPU86_LDouble ft0;
+    union {
+       float f;
+        double d;
+       int i32;
+        int64_t i64;
+    } fp_convert;
     
     /* segments */
     uint32_t segs[6]; /* selector values */
index 66f735bee3cc5ec8c5b75df7d5484f9af2a7151a..6d06c73fd77ba20e270b194b6d25717ccc343c3e 100644 (file)
--- a/dyngen.c
+++ b/dyngen.c
 #define elf_check_arch(x) ((x) == EM_IA_64)
 #define ELF_USES_RELOCA
 
+#elif defined(HOST_SPARC)
+
+#define ELF_CLASS      ELFCLASS32
+#define ELF_ARCH       EM_SPARC
+#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
+#define ELF_USES_RELOCA
+
+#elif defined(HOST_SPARC64)
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_ARCH       EM_SPARCV9
+#define elf_check_arch(x) ((x) == EM_SPARCV9)
+#define ELF_USES_RELOCA
+
 #else
 #error unsupported CPU - please update the code
 #endif
@@ -326,6 +340,47 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
             copy_size = p - p_start;
        }
         break;
+    case EM_SPARC:
+    case EM_SPARC32PLUS:
+       {
+            uint8_t *p;
+            p = (void *)(p_end - 8);
+            if (p <= p_start)
+                error("empty code for %s", name);
+           if (get32((uint32_t *)(p_start + 0x0)) != 0x9de3bf98)
+                error("save %%sp,-104,%%sp expected at the start of %s "
+                     "found [%08x]",
+                     name, get32((uint32_t *)(p_start + 0x0)));
+            if (get32((uint32_t *)(p + 0x0)) != 0x81c7e008 ||
+               get32((uint32_t *)(p + 0x4)) != 0x81e80000)
+                error("ret; restore; expected at the end of %s found [%08x:%08x]",
+                     name,
+                     get32((uint32_t *)(p + 0x0)),
+                     get32((uint32_t *)(p + 0x4)));
+
+            copy_size = p - p_start;
+       }
+       break;
+    case EM_SPARCV9:
+       {
+            uint8_t *p;
+            p = (void *)(p_end - 8);
+            if (p <= p_start)
+                error("empty code for %s", name);
+           if (get32((uint32_t *)(p_start + 0x0)) != 0x9de3bf40)
+                error("save %%sp,-192,%%sp expected at the start of %s "
+                     "found [%08x]",
+                     name, get32((uint32_t *)(p_start + 0x0)));
+            if (get32((uint32_t *)(p + 0x0)) != 0x81cfe008 ||
+               get32((uint32_t *)(p + 0x4)) != 0x01000000)
+                error("rett %%i7+8; nop; expected at the end of %s "
+                     "found [%08x:%08x]",
+                     name,
+                     get32((uint32_t *)(p + 0x0)),
+                     get32((uint32_t *)(p + 0x4)));
+            copy_size = p - p_start;
+       }
+       break;
     default:
        error("unknown ELF architecture");
     }
@@ -375,6 +430,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
             if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
                 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
                 if (!strstart(sym_name, "__op_param", &p)) {
+#if defined(HOST_SPARC)
+                   if (sym_name[0] == '.') {
+                       fprintf(outfile,
+                               "extern char __dot_%s __asm__(\"%s\");\n",
+                               sym_name+1, sym_name);
+                       continue;
+                   }
+#endif
                     fprintf(outfile, "extern char %s;\n", sym_name);
                 }
             }
@@ -554,6 +617,126 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     }
                 }
             }
+#elif defined(HOST_SPARC)
+            {
+                char name[256];
+                int type;
+                int addend;
+                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+                    if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
+                        sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
+                        if (strstart(sym_name, "__op_param", &p)) {
+                            snprintf(name, sizeof(name), "param%s", p);
+                        } else {
+                               if (sym_name[0] == '.')
+                                       snprintf(name, sizeof(name),
+                                                "(long)(&__dot_%s)",
+                                                sym_name + 1);
+                               else
+                                       snprintf(name, sizeof(name),
+                                                "(long)(&%s)", sym_name);
+                        }
+                        type = ELF32_R_TYPE(rel->r_info);
+                        addend = rel->r_addend;
+                        switch(type) {
+                        case R_SPARC_32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
+                                    rel->r_offset - offset, name, addend);
+                           break;
+                       case R_SPARC_HI22:
+                            fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3fffff) "
+                                   " | ((%s + %d) & 0x3fffff);\n",
+                                    rel->r_offset - offset,
+                                   rel->r_offset - offset,
+                                   name, addend);
+                           break;
+                       case R_SPARC_LO10:
+                            fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3ff) "
+                                   " | ((%s + %d) & 0x3ff);\n",
+                                    rel->r_offset - offset,
+                                   rel->r_offset - offset,
+                                   name, addend);
+                           break;
+                       case R_SPARC_WDISP30:
+                           fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3fffffff) "
+                                   " | ((((%s + %d) - (long)gen_code_ptr)>>2) "
+                                   "    & 0x3fffffff);\n",
+                                   rel->r_offset - offset,
+                                   rel->r_offset - offset,
+                                   name, addend);
+                           break;
+                        default:
+                            error("unsupported sparc relocation (%d)", type);
+                        }
+                    }
+                }
+            }
+#elif defined(HOST_SPARC64)
+            {
+                char name[256];
+                int type;
+                int addend;
+                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+                    if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
+                        sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
+                        if (strstart(sym_name, "__op_param", &p)) {
+                            snprintf(name, sizeof(name), "param%s", p);
+                        } else {
+                            snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
+                        }
+                        type = ELF64_R_TYPE(rel->r_info);
+                        addend = rel->r_addend;
+                        switch(type) {
+                        case R_SPARC_32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                    rel->r_offset - offset, name, addend);
+                           break;
+                       case R_SPARC_HI22:
+                            fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3fffff) "
+                                   " | ((%s + %d) & 0x3fffff);\n",
+                                    rel->r_offset - offset,
+                                   rel->r_offset - offset,
+                                   name, addend);
+                           break;
+                       case R_SPARC_LO10:
+                            fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3ff) "
+                                   " | ((%s + %d) & 0x3ff);\n",
+                                    rel->r_offset - offset,
+                                   rel->r_offset - offset,
+                                   name, addend);
+                           break;
+                       case R_SPARC_WDISP30:
+                           fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3fffffff) "
+                                   " | ((((%s + %d) - (long)gen_code_ptr)>>2) "
+                                   "    & 0x3fffffff);\n",
+                                   rel->r_offset - offset,
+                                   rel->r_offset - offset,
+                                   name, addend);
+                           break;
+                        default:
+                           error("unsupported sparc64 relocation (%d)", type);
+                        }
+                    }
+                }
+            }
 #else
 #error unsupported CPU
 #endif
@@ -759,6 +942,14 @@ fprintf(outfile,
     case EM_IA_64:
         fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n");
         break;
+    case EM_SPARC:
+    case EM_SPARC32PLUS:
+    case EM_SPARCV9:
+       /* Fill the delay slot. */
+       fprintf(outfile, "*((uint32_t *)gen_code_ptr) = *((uint32_t *)gen_code_ptr - 1); /* delay slot */\n");
+       fprintf(outfile, "*((uint32_t *)gen_code_ptr - 1) = 0x81c3e008; /* retl */\n");
+       fprintf(outfile, "gen_code_ptr++;\n");
+        break;
     default:
        error("unknown ELF architecture");
     }
index 508d0688245ed2bf634641de1be7a6c4600c7e32..ecb7adc9d64e9fe6c5a796dcfbeafe95d52595be 100644 (file)
@@ -121,6 +121,20 @@ int testandset (int *p)
 }
 #endif
 
+#ifdef __sparc__
+static inline int testandset (int *p)
+{
+       int ret;
+
+       __asm__ __volatile__("ldstub    [%1], %0"
+                            : "=r" (ret)
+                            : "r" (p)
+                            : "memory");
+
+       return (ret ? 1 : 0);
+}
+#endif
+
 int global_cpu_lock = 0;
 
 void cpu_lock(void)
index b4f5a0013f24f8efe8c116ca99a3331facf13458..4f7f4ceb326bb7edbdc7cc883f2a234a5c25f37c 100644 (file)
@@ -93,6 +93,7 @@ register unsigned int T0 asm("l0");
 register unsigned int T1 asm("l1");
 register unsigned int A0 asm("l2");
 register struct CPUX86State *env asm("l3");
+#define USE_FP_CONVERT
 #endif
 #ifdef __s390__
 register unsigned int T0 asm("r7");
@@ -160,6 +161,10 @@ register struct CPUX86State *env asm("r27");
 #define ST(n)  (env->fpregs[(env->fpstt + (n)) & 7])
 #define ST1    ST(1)
 
+#ifdef USE_FP_CONVERT
+#define FP_CONVERT  (env->fp_convert)
+#endif
+
 extern int __op_param1, __op_param2, __op_param3;
 #define PARAM1 ((long)(&__op_param1))
 #define PARAM2 ((long)(&__op_param2))
index 323fce33d2092aacd5dfaf8fa6485206f6c4553a..ede63eabdc9ec03db8bb7c31da960b428530a72d 100644 (file)
--- a/op-i386.c
+++ b/op-i386.c
@@ -1605,12 +1605,22 @@ typedef union {
 
 void OPPROTO op_flds_FT0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i32 = ldl((void *)A0);
+    FT0 = FP_CONVERT.f;
+#else
     FT0 = ldfl((void *)A0);
+#endif
 }
 
 void OPPROTO op_fldl_FT0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i64 = ldq((void *)A0);
+    FT0 = FP_CONVERT.d;
+#else
     FT0 = ldfq((void *)A0);
+#endif
 }
 
 /* helpers are needed to avoid static constant reference. XXX: find a better way */
@@ -1650,17 +1660,32 @@ void OPPROTO op_fildll_FT0_A0(void)
 
 void OPPROTO op_fild_FT0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i32 = ldsw((void *)A0);
+    FT0 = (CPU86_LDouble)FP_CONVERT.i32;
+#else
     FT0 = (CPU86_LDouble)ldsw((void *)A0);
+#endif
 }
 
 void OPPROTO op_fildl_FT0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
+    FT0 = (CPU86_LDouble)FP_CONVERT.i32;
+#else
     FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
+#endif
 }
 
 void OPPROTO op_fildll_FT0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
+    FT0 = (CPU86_LDouble)FP_CONVERT.i64;
+#else
     FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
+#endif
 }
 #endif
 
@@ -1668,12 +1693,22 @@ void OPPROTO op_fildll_FT0_A0(void)
 
 void OPPROTO op_flds_ST0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i32 = ldl((void *)A0);
+    ST0 = FP_CONVERT.f;
+#else
     ST0 = ldfl((void *)A0);
+#endif
 }
 
 void OPPROTO op_fldl_ST0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i64 = ldq((void *)A0);
+    ST0 = FP_CONVERT.d;
+#else
     ST0 = ldfq((void *)A0);
+#endif
 }
 
 #ifdef USE_X86LDOUBLE
@@ -1738,17 +1773,32 @@ void OPPROTO op_fildll_ST0_A0(void)
 
 void OPPROTO op_fild_ST0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i32 = ldsw((void *)A0);
+    ST0 = (CPU86_LDouble)FP_CONVERT.i32;
+#else
     ST0 = (CPU86_LDouble)ldsw((void *)A0);
+#endif
 }
 
 void OPPROTO op_fildl_ST0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
+    ST0 = (CPU86_LDouble)FP_CONVERT.i32;
+#else
     ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
+#endif
 }
 
 void OPPROTO op_fildll_ST0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
+    ST0 = (CPU86_LDouble)FP_CONVERT.i64;
+#else
     ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
+#endif
 }
 
 #endif
@@ -1757,7 +1807,12 @@ void OPPROTO op_fildll_ST0_A0(void)
 
 void OPPROTO op_fsts_ST0_A0(void)
 {
+#ifdef USE_FP_CONVERT
+    FP_CONVERT.d = ST0;
+    stfl((void *)A0, FP_CONVERT.f);
+#else
     stfl((void *)A0, (float)ST0);
+#endif
 }
 
 void OPPROTO op_fstl_ST0_A0(void)
@@ -1792,22 +1847,43 @@ void OPPROTO op_fstt_ST0_A0(void)
 
 void OPPROTO op_fist_ST0_A0(void)
 {
+#if defined(__sparc__) && !defined(__sparc_v9__)
+    register CPU86_LDouble d asm("o0");
+#else
+    CPU86_LDouble d;
+#endif
     int val;
-    val = lrint(ST0);
+
+    d = ST0;
+    val = lrint(d);
     stw((void *)A0, val);
 }
 
 void OPPROTO op_fistl_ST0_A0(void)
 {
+#if defined(__sparc__) && !defined(__sparc_v9__)
+    register CPU86_LDouble d asm("o0");
+#else
+    CPU86_LDouble d;
+#endif
     int val;
-    val = lrint(ST0);
+
+    d = ST0;
+    val = lrint(d);
     stl((void *)A0, val);
 }
 
 void OPPROTO op_fistll_ST0_A0(void)
 {
+#if defined(__sparc__) && !defined(__sparc_v9__)
+    register CPU86_LDouble d asm("o0");
+#else
+    CPU86_LDouble d;
+#endif
     int64_t val;
-    val = llrint(ST0);
+
+    d = ST0;
+    val = llrint(d);
     stq((void *)A0, val);
 }
 
index e23ff677749a3e503d33fb72aa8620bdca366eb1..1cdad2d90808a35da13dfedc4bd896cf67cede46 100644 (file)
@@ -89,6 +89,21 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
 }
 #endif
 
+#ifdef __sparc__
+
+static void inline flush_icache_range(unsigned long start, unsigned long stop)
+{
+       unsigned long p;
+
+       p = start & ~(8UL - 1UL);
+       stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
+
+       for (; p < stop; p += 8)
+               __asm__ __volatile__("flush\t%0" : : "r" (p));
+}
+
+#endif
+
 extern FILE *logfile;
 extern int loglevel;