sparc support

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@119 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2003-04-29 21:26:53 +00:00
parent a98fd896cd
commit d014c98c8d
6 changed files with 310 additions and 3 deletions

View 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 */

191
dyngen.c
View File

@ -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");
}

View 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)

View 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))

View File

@ -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);
}

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