diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-04-29 21:26:53 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-04-29 21:26:53 +0000 |
commit | d014c98c8dce88c3b6cc19bd2e0e558900f5c1d0 (patch) | |
tree | 89cb45f50dcf91a6445f6aa312cd8ac24136705c | |
parent | a98fd896cdcab506e734de7555304da16e775277 (diff) |
sparc support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@119 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | cpu-i386.h | 6 | ||||
-rw-r--r-- | dyngen.c | 191 | ||||
-rw-r--r-- | exec-i386.c | 14 | ||||
-rw-r--r-- | exec-i386.h | 5 | ||||
-rw-r--r-- | op-i386.c | 82 | ||||
-rw-r--r-- | translate-i386.c | 15 |
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 */ @@ -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)) @@ -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; |