aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-04-29 21:26:53 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-04-29 21:26:53 +0000
commitd014c98c8dce88c3b6cc19bd2e0e558900f5c1d0 (patch)
tree89cb45f50dcf91a6445f6aa312cd8ac24136705c
parenta98fd896cdcab506e734de7555304da16e775277 (diff)
sparc support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@119 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--cpu-i386.h6
-rw-r--r--dyngen.c191
-rw-r--r--exec-i386.c14
-rw-r--r--exec-i386.h5
-rw-r--r--op-i386.c82
-rw-r--r--translate-i386.c15
6 files changed, 310 insertions, 3 deletions
diff --git a/cpu-i386.h b/cpu-i386.h
index ca33791351..4b8aef12ad 100644
--- a/cpu-i386.h
+++ b/cpu-i386.h
@@ -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 */
diff --git a/dyngen.c b/dyngen.c
index 66f735bee3..6d06c73fd7 100644
--- a/dyngen.c
+++ b/dyngen.c
@@ -65,6 +65,20 @@
#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");
}
diff --git a/exec-i386.c b/exec-i386.c
index 508d068824..ecb7adc9d6 100644
--- a/exec-i386.c
+++ b/exec-i386.c
@@ -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)
diff --git a/exec-i386.h b/exec-i386.h
index b4f5a0013f..4f7f4ceb32 100644
--- a/exec-i386.h
+++ b/exec-i386.h
@@ -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))
diff --git a/op-i386.c b/op-i386.c
index 323fce33d2..ede63eabdc 100644
--- 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);
}
diff --git a/translate-i386.c b/translate-i386.c
index e23ff67774..1cdad2d908 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -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;