qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Patch: Sparc system emulation (1/3)


From: Blue Swirl
Subject: [Qemu-devel] Patch: Sparc system emulation (1/3)
Date: Sat, 18 Sep 2004 09:31:41 +0200

Hi,

Contents: Privileged and FPU instructions, support for Sparc system emulation, Sparc Reference MMU emulation, breakpoint support (incomplete), trap support (incomplete), and Search PC support for interrupts (incomplete).

With this and the following patch parts, Proll can almost load a file with TFTP (with the TFTP patch, of course).

diff -ruN qemu-0.6.0.orig/exec-all.h qemu-0.6.0/exec-all.h
--- qemu-0.6.0.orig/exec-all.h  2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/exec-all.h       2004-09-08 18:17:58.000000000 +0200
@@ -56,6 +56,7 @@
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
+extern uint32_t gen_opc_npc[OPC_BUF_SIZE];
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];

@@ -541,7 +542,7 @@

extern int tb_invalidated_flag;

-#if (defined(TARGET_I386) || defined(TARGET_PPC)) && \
+#if (defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)) && \
    !defined(CONFIG_USER_ONLY)

void tlb_fill(unsigned long addr, int is_write, int is_user,
@@ -585,6 +586,8 @@
    is_user = ((env->hflags & HF_CPL_MASK) == 3);
#elif defined (TARGET_PPC)
    is_user = msr_pr;
+#elif defined (TARGET_SPARC)
+    is_user = (env->psrs == 0);
#else
#error "Unimplemented !"
#endif
diff -ruN qemu-0.6.0.orig/exec.c qemu-0.6.0/exec.c
--- qemu-0.6.0.orig/exec.c      2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/exec.c   2004-09-15 19:16:22.000000000 +0200
@@ -1052,7 +1052,7 @@
   breakpoint is reached */
int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
{
-#if defined(TARGET_I386) || defined(TARGET_PPC)
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
    int i;

    for(i = 0; i < env->nb_breakpoints; i++) {
@@ -1074,7 +1074,7 @@
/* remove a breakpoint */
int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
{
-#if defined(TARGET_I386) || defined(TARGET_PPC)
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
    int i;
    for(i = 0; i < env->nb_breakpoints; i++) {
        if (env->breakpoints[i] == pc)
@@ -1097,7 +1097,7 @@
   CPU loop after each instruction */
void cpu_single_step(CPUState *env, int enabled)
{
-#if defined(TARGET_I386) || defined(TARGET_PPC)
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
    if (env->singlestep_enabled != enabled) {
        env->singlestep_enabled = enabled;
        /* must flush all the translated code to avoid inconsistancies */
diff -ruN qemu-0.6.0.orig/Makefile.target qemu-0.6.0/Makefile.target
--- qemu-0.6.0.orig/Makefile.target     2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/Makefile.target  2004-09-15 19:59:01.000000000 +0200
@@ -63,6 +63,26 @@
endif # ARCH = amd64

endif # TARGET_ARCH = ppc
+
+ifeq ($(TARGET_ARCH), sparc)
+
+ifeq ($(ARCH), ppc)
+PROGS+=$(QEMU_SYSTEM)
+endif
+
+ifeq ($(ARCH), i386)
+ifdef CONFIG_SOFTMMU
+PROGS+=$(QEMU_SYSTEM)
+endif
+endif # ARCH = i386
+
+ifeq ($(ARCH), amd64)
+ifdef CONFIG_SOFTMMU
+PROGS+=$(QEMU_SYSTEM)
+endif
+endif # ARCH = amd64
+
+endif # TARGET_ARCH = sparc
endif # !CONFIG_USER_ONLY

ifdef CONFIG_STATIC
@@ -198,6 +218,10 @@
LIBOBJS+= op_helper.o helper.o
endif

+ifeq ($(TARGET_ARCH), sparc)
+LIBOBJS+= op_helper.o helper.o
+endif
+
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
@@ -250,6 +274,9 @@
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o
endif
+ifeq ($(TARGET_ARCH), sparc)
+VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o
+endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
endif
@@ -321,7 +348,7 @@
endif

ifeq ($(TARGET_ARCH), sparc)
-op.o: op.c op_template.h
+op.o: op.c op_template.h op_mem.h
endif

ifeq ($(TARGET_ARCH), ppc)
diff -ruN qemu-0.6.0.orig/softmmu_header.h qemu-0.6.0/softmmu_header.h
--- qemu-0.6.0.orig/softmmu_header.h    2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/softmmu_header.h 2004-08-28 16:34:29.000000000 +0200
@@ -55,6 +55,8 @@
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#elif defined (TARGET_PPC)
#define CPU_MEM_INDEX (msr_pr)
+#elif defined (TARGET_SPARC)
+#define CPU_MEM_INDEX ((env->psrs) == 0)
#endif
#define MMUSUFFIX _mmu

@@ -64,6 +66,8 @@
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#elif defined (TARGET_PPC)
#define CPU_MEM_INDEX (msr_pr)
+#elif defined (TARGET_SPARC)
+#define CPU_MEM_INDEX ((env->psrs) == 0)
#endif
#define MMUSUFFIX _cmmu

diff -ruN qemu-0.6.0.orig/target-sparc/cpu.h qemu-0.6.0/target-sparc/cpu.h
--- qemu-0.6.0.orig/target-sparc/cpu.h  2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/target-sparc/cpu.h       2004-09-11 19:00:48.000000000 +0200
@@ -4,13 +4,16 @@
#define TARGET_LONG_BITS 32

#include "cpu-defs.h"
+#include "config.h"

/*#define EXCP_INTERRUPT 0x100*/

/* trap definitions */
#define TT_ILL_INSN 0x02
+#define TT_PRIV_INSN 0x03
#define TT_WIN_OVF  0x05
#define TT_WIN_UNF  0x06
+#define TT_FP_EXCP  0x08
#define TT_DIV_ZERO 0x2a
#define TT_TRAP     0x80

@@ -18,27 +21,95 @@
#define PSR_ZERO  (1<<22)
#define PSR_OVF   (1<<21)
#define PSR_CARRY (1<<20)
+#define PSR_ICC   (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
+#define PSR_S     (1<<7)
+#define PSR_PS    (1<<6)
+#define PSR_ET    (1<<5)
+#define PSR_CWP   0x1f
+
+/* Trap base register */
+#define TBR_BASE_MASK 0xfffff000
+
+/* Fcc */
+#define FSR_RD1        (1<<31)
+#define FSR_RD0        (1<<30)
+#define FSR_RD_MASK    (FSR_RD1 | FSR_RD0)
+#define FSR_RD_NEAREST 0
+#define FSR_RD_ZERO    FSR_RD0
+#define FSR_RD_POS     FSR_RD1
+#define FSR_RD_NEG     (FSR_RD1 | FSR_RD0)
+
+#define FSR_NVM   (1<<27)
+#define FSR_OFM   (1<<26)
+#define FSR_UFM   (1<<25)
+#define FSR_DZM   (1<<24)
+#define FSR_NXM   (1<<23)
+#define FSR_TEM_MASK (FSR_NVM | FSR_OFM | FSR_UFM | FSR_DZM | FSR_NXM)
+
+#define FSR_NVA   (1<<9)
+#define FSR_OFA   (1<<8)
+#define FSR_UFA   (1<<7)
+#define FSR_DZA   (1<<6)
+#define FSR_NXA   (1<<5)
+#define FSR_AEXC_MASK (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA)
+
+#define FSR_NVC   (1<<4)
+#define FSR_OFC   (1<<3)
+#define FSR_UFC   (1<<2)
+#define FSR_DZC   (1<<1)
+#define FSR_NXC   (1<<0)
+#define FSR_CEXC_MASK (FSR_NVC | FSR_OFC | FSR_UFC | FSR_DZC | FSR_NXC)
+
+#define FSR_FTT2   (1<<16)
+#define FSR_FTT1   (1<<15)
+#define FSR_FTT0   (1<<14)
+#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
+
+#define FSR_FCC1  (1<<11)
+#define FSR_FCC0  (1<<10)
+
+/* MMU */
+#define MMU_E    (1<<0)
+#define MMU_NF   (1<<1)
+
+#define PTE_ENTRYTYPE_MASK 3
+#define PTE_ACCESS_MASK    0x1c
+#define PTE_ACCESS_SHIFT   2
+#define PTE_ADDR_MASK      0xffffff00
+
+#define PG_ACCESSED_BIT        5
+#define PG_MODIFIED_BIT        6
+#define PG_CACHE_BIT    7
+
+#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
+#define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT)
+#define PG_CACHE_MASK    (1 << PG_CACHE_BIT)

#define NWINDOWS  32

typedef struct CPUSPARCState {
    uint32_t gregs[8]; /* general registers */
    uint32_t *regwptr; /* pointer to current register window */
-    double   *regfptr; /* floating point registers */
+    float    fpr[32];  /* floating point registers */
    uint32_t pc;       /* program counter */
    uint32_t npc;      /* next program counter */
-    uint32_t sp;       /* stack pointer */
    uint32_t y;        /* multiply/divide register */
    uint32_t psr;      /* processor state register */
+    uint32_t fsr;      /* FPU state register */
    uint32_t T2;
    uint32_t cwp;      /* index of current register window (extracted
                          from PSR) */
    uint32_t wim;      /* window invalid mask */
+    uint32_t tbr;      /* trap base register */
+    int      psrs;     /* supervisor mode (extracted from PSR) */
+    int      psrps;    /* previous supervisor mode */
+    int      psret;    /* enable traps */
    jmp_buf  jmp_env;
    int user_mode_only;
    int exception_index;
    int interrupt_index;
    int interrupt_request;
+    uint32_t exception_next_pc;
    struct TranslationBlock *current_tb;
    void *opaque;
    /* NOTE: we allow 8 more registers to handle wrapping */
@@ -51,6 +122,22 @@
                                   written */
    unsigned long mem_write_vaddr; /* target virtual addr at which the
                                      memory was written */
+    /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
+    CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
+    CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
+    int error_code;
+    int access_type;
+    /* MMU regs */
+    uint32_t mmuregs[16];
+    /* temporary float registers */
+    float ft0, ft1, ft2;
+    double dt0, dt1, dt2;
+
+    /* ice debug support */
+    uint32_t breakpoints[MAX_BREAKPOINTS];
+    int nb_breakpoints;
+ int singlestep_enabled; /* XXX: should use CPU single step mode instead */
+
} CPUSPARCState;

CPUSPARCState *cpu_sparc_init(void);
@@ -61,7 +148,7 @@
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
void cpu_sparc_dump_state(CPUSPARCState *env, FILE *f, int flags);

-#define TARGET_PAGE_BITS 13
+#define TARGET_PAGE_BITS 12 /* 4k */
#include "cpu-all.h"

#endif
diff -ruN qemu-0.6.0.orig/target-sparc/exec.h qemu-0.6.0/target-sparc/exec.h
--- qemu-0.6.0.orig/target-sparc/exec.h 2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/target-sparc/exec.h      2004-09-11 18:52:32.000000000 +0200
@@ -6,6 +6,12 @@
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
+#define FT0 (env->ft0)
+#define FT1 (env->ft1)
+#define FT2 (env->ft2)
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define DT2 (env->dt2)

#include "cpu.h"
#include "exec-all.h"
@@ -14,4 +20,88 @@
void cpu_unlock(void);
void cpu_loop_exit(void);
void helper_flush(target_ulong addr);
+void helper_ld_asi(int asi);
+void helper_st_asi(int asi);
+void helper_rett(void);
+void helper_stfsr(void);
+void set_cwp(int new_cwp);
+void do_fabss(void);
+void do_fsqrts(void);
+void do_fsqrtd(void);
+void do_fcmps(void);
+void do_fcmpd(void);
+void do_interrupt(int intno, int is_int, int error_code,
+                  unsigned int next_eip, int is_hw);
+void raise_exception_err(int exception_index, int error_code);
+void raise_exception(int tt);
+void memcpy32(uint32_t *dst, const uint32_t *src);
+
+/* XXX: move that to a generic header */
+#if !defined(CONFIG_USER_ONLY)
+
+#define ldul_user ldl_user
+#define ldul_kernel ldl_kernel
+
+#define ACCESS_TYPE 0
+#define MEMSUFFIX _kernel
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+
+#define ACCESS_TYPE 1
+#define MEMSUFFIX _user
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+
+/* these access are slower, they must be as rare as possible */
+#define ACCESS_TYPE 2
+#define MEMSUFFIX _data
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+
+#define ldub(p) ldub_data(p)
+#define ldsb(p) ldsb_data(p)
+#define lduw(p) lduw_data(p)
+#define ldsw(p) ldsw_data(p)
+#define ldl(p) ldl_data(p)
+#define ldq(p) ldq_data(p)
+
+#define stb(p, v) stb_data(p, v)
+#define stw(p, v) stw_data(p, v)
+#define stl(p, v) stl_data(p, v)
+#define stq(p, v) stq_data(p, v)
+
+#endif /* !defined(CONFIG_USER_ONLY) */
#endif
diff -ruN qemu-0.6.0.orig/target-sparc/fop_template.h qemu-0.6.0/target-sparc/fop_template.h --- qemu-0.6.0.orig/target-sparc/fop_template.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.6.0/target-sparc/fop_template.h 2004-09-11 18:35:03.000000000 +0200
@@ -0,0 +1,121 @@
+/*
+ *  SPARC micro operations (templates for various register related
+ *  operations)
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* floating point registers moves */
+void OPPROTO glue(op_load_fpr_FT0_fpr, REGNAME)(void)
+{
+    FT0 = REG;
+}
+
+void OPPROTO glue(op_store_FT0_fpr_fpr, REGNAME)(void)
+{
+    REG = FT0;
+}
+
+void OPPROTO glue(op_load_fpr_FT1_fpr, REGNAME)(void)
+{
+    FT1 = REG;
+}
+
+void OPPROTO glue(op_store_FT1_fpr_fpr, REGNAME)(void)
+{
+    REG = FT1;
+}
+
+void OPPROTO glue(op_load_fpr_FT2_fpr, REGNAME)(void)
+{
+    FT2 = REG;
+}
+
+void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void)
+{
+    REG = FT2;
+}
+
+/* double floating point registers moves */
+#if 0
+#define CPU_DOUBLE_U_DEF
+typedef union {
+    double d;
+    struct {
+        uint32_t lower;
+        uint32_t upper;
+    } l;
+    uint64_t ll;
+} CPU_DoubleU;
+#endif /* CPU_DOUBLE_U_DEF */
+
+void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void)
+{
+    CPU_DoubleU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.l.lower = *(p +1);
+    u.l.upper = *p;
+    DT0 = u.d;
+}
+
+void OPPROTO glue(op_store_DT0_fpr_fpr, REGNAME)(void)
+{
+    CPU_DoubleU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.d = DT0;
+    *(p +1) = u.l.lower;
+    *p = u.l.upper;
+}
+
+void OPPROTO glue(op_load_fpr_DT1_fpr, REGNAME)(void)
+{
+    CPU_DoubleU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.l.lower = *(p +1);
+    u.l.upper = *p;
+    DT1 = u.d;
+}
+
+void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void)
+{
+    CPU_DoubleU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.d = DT1;
+    *(p +1) = u.l.lower;
+    *p = u.l.upper;
+}
+
+void OPPROTO glue(op_load_fpr_DT2_fpr, REGNAME)(void)
+{
+    CPU_DoubleU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.l.lower = *(p +1);
+    u.l.upper = *p;
+    DT2 = u.d;
+}
+
+void OPPROTO glue(op_store_DT2_fpr_fpr, REGNAME)(void)
+{
+    CPU_DoubleU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.d = DT2;
+    *(p +1) = u.l.lower;
+    *p = u.l.upper;
+}
+
+#undef REG
+#undef REGNAME
diff -ruN qemu-0.6.0.orig/target-sparc/helper.c qemu-0.6.0/target-sparc/helper.c --- qemu-0.6.0.orig/target-sparc/helper.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-0.6.0/target-sparc/helper.c    2004-09-12 18:48:20.000000000 +0200
@@ -0,0 +1,341 @@
+/*
+ *  sparc helpers
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "exec.h"
+
+#define DEBUG_PCALL
+
+#if 0
+#define raise_exception_err(a, b)\
+do {\
+    fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
+    (raise_exception_err)(a, b);\
+} while (0)
+#endif
+
+/* Sparc MMU emulation */
+int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+                              int is_user, int is_softmmu);
+
+
+/* thread support */
+
+spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+
+void cpu_lock(void)
+{
+    spin_lock(&global_cpu_lock);
+}
+
+void cpu_unlock(void)
+{
+    spin_unlock(&global_cpu_lock);
+}
+
+#if 0
+void cpu_loop_exit(void)
+{
+    /* NOTE: the register at this point must be saved by hand because
+       longjmp restore them */
+    longjmp(env->jmp_env, 1);
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+#define GETPC() (__builtin_return_address(0))
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
+{
+    TranslationBlock *tb;
+    int ret;
+    unsigned long pc;
+    CPUState *saved_env;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+
+    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1);
+    if (ret) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+ /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc, NULL);
+            }
+        }
+        raise_exception_err(ret, env->error_code);
+    }
+    env = saved_env;
+}
+#endif
+
+static int access_table[8][8] = {
+    { 0, 0, 0, 0, 2, 0, 3, 3 },
+    { 0, 0, 0, 0, 2, 0, 0, 0 },
+    { 2, 2, 0, 0, 0, 2, 3, 3 },
+    { 2, 2, 0, 0, 0, 2, 0, 0 },
+    { 2, 0, 2, 0, 2, 2, 3, 3 },
+    { 2, 0, 2, 0, 2, 0, 2, 0 },
+    { 2, 2, 2, 0, 2, 2, 3, 3 },
+    { 2, 2, 2, 0, 2, 2, 2, 0 }
+};
+
+/* 1 = write OK */
+static int rw_table[2][8] = {
+    { 0, 1, 0, 1, 0, 1, 0, 1 },
+    { 0, 1, 0, 1, 0, 0, 0, 0 }
+};
+
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+                              int is_user, int is_softmmu)
+{
+    int exception = 0;
+    int access_type, access_perms = 0, access_index = 0;
+    uint8_t *pde_ptr;
+    uint32_t pde, virt_addr;
+    int error_code = 0, is_dirty, prot, ret = 0;
+    unsigned long paddr, vaddr, page_offset;
+
+
+//    printf("%s 0\n", __func__);
+    access_type = env->access_type;
+    if (env->user_mode_only) {
+        /* user mode only emulation */
+        ret = -2;
+        goto do_fault;
+    }
+
+    virt_addr = address & TARGET_PAGE_MASK;
+    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
+       paddr = address;
+       page_offset = address & (TARGET_PAGE_SIZE - 1);
+        prot = PAGE_READ | PAGE_WRITE;
+        goto do_mapping;
+    }
+
+    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
+    /* Context base + context number */
+ pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
+    pde = ldl_raw(pde_ptr);
+
+    /* Ctx pde */
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    case 0: /* Invalid */
+        error_code = 1;
+        goto do_fault;
+    case 2: /* PTE, maybe should not happen? */
+    case 3: /* Reserved */
+        error_code = 0;
+        goto do_fault;
+    case 1: /* L1 PDE */
+       pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4);
+       pde = ldl_raw(pde_ptr);
+
+       switch (pde & PTE_ENTRYTYPE_MASK) {
+       case 0: /* Invalid */
+           error_code = 1;
+           goto do_fault;
+       case 3: /* Reserved */
+           error_code = 0;
+           goto do_fault;
+       case 1: /* L2 PDE */
+ pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+           pde = ldl_raw(pde_ptr);
+
+           switch (pde & PTE_ENTRYTYPE_MASK) {
+           case 0: /* Invalid */
+               error_code = 1;
+               goto do_fault;
+           case 3: /* Reserved */
+               error_code = 0;
+               goto do_fault;
+           case 1: /* L3 PDE */
+ pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+               pde = ldl_raw(pde_ptr);
+
+               switch (pde & PTE_ENTRYTYPE_MASK) {
+               case 0: /* Invalid */
+                   error_code = 1;
+                   goto do_fault;
+               case 1: /* PDE, should not happen */
+                   error_code = 4;
+                   goto do_fault;
+               case 3: /* Reserved */
+                   error_code = 0;
+                   goto do_fault;
+               case 2: /* L3 PTE */
+                   virt_addr = address & TARGET_PAGE_MASK;
+                   page_offset = (address & TARGET_PAGE_MASK) & 
(TARGET_PAGE_SIZE - 1);
+               }
+               break;
+           case 2: /* L2 PTE */
+               virt_addr = address & ~0x3ffff;
+               page_offset = address & 0x3ffff;
+           }
+           break;
+       case 2: /* L1 PTE */
+           virt_addr = address & ~0xffffff;
+           page_offset = address & 0xffffff;
+       }
+    }
+
+    /* update page modified and dirty bits */
+    is_dirty = rw && !(pde & PG_MODIFIED_MASK);
+    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+       pde |= PG_ACCESSED_MASK;
+       if (is_dirty)
+           pde |= PG_MODIFIED_MASK;
+       stl_raw(pde_ptr, pde);
+    }
+
+    /* check access */
+ access_index = (rw << 2) | (is_user? 0 : 1); /* XXX bit 1 should be instruction vs. data access */
+    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
+    error_code = access_table[access_index][access_perms];
+    if (error_code)
+       goto do_fault;
+
+    /* the page can be put in the TLB */
+    prot = PAGE_READ;
+    if (pde & PG_MODIFIED_MASK) {
+        /* only set write access if already dirty... otherwise wait
+           for dirty access */
+       if (rw_table[is_user][access_perms])
+               prot |= PAGE_WRITE;
+    }
+
+    /* Even if large ptes, we map only one 4KB page in the cache to
+       avoid filling it too fast */
+    virt_addr = address & TARGET_PAGE_MASK;
+    paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
+
+ do_mapping:
+ vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
+
+    ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
+    return ret;
+
+ do_fault:
+    if (env->mmuregs[3]) /* Fault status register */
+       env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+    env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2;
+    env->mmuregs[4] = address; /* Fault address register */
+
+    if (env->mmuregs[0] & MMU_NF) // No fault
+       return 0;
+
+    env->exception_index = exception;
+    env->error_code = error_code;
+    return error_code;
+}
+
+/* XXX Copy from op.c */
+void set_cwp(int new_cwp)
+{
+    /* put the modified wrap registers at their proper location */
+    if (env->cwp == (NWINDOWS - 1))
+        memcpy32(env->regbase, env->regbase + NWINDOWS * 16);
+    env->cwp = new_cwp;
+    /* put the wrap registers at their temporary location */
+    if (new_cwp == (NWINDOWS - 1))
+        memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
+    env->regwptr = env->regbase + (new_cwp * 16);
+}
+
+/*
+ * Begin execution of an interruption. is_int is TRUE if coming from
+ * the int instruction. next_eip is the EIP value AFTER the interrupt
+ * instruction. It is only relevant if is_int is TRUE.
+ */
+void do_interrupt(int intno, int is_int, int error_code,
+                  unsigned int next_eip, int is_hw)
+{
+    int cwp, trapno;
+
+#ifdef DEBUG_PCALL
+    if (loglevel & CPU_LOG_INT) {
+       static int count;
+       fprintf(logfile, "%6d: v=%02x e=%04x i=%d pc=%08x npc=%08x SP=%08x\n",
+                    count, intno, error_code, is_int,
+                    env->pc,
+                    env->npc, env->gregs[7]);
+#if 0
+       cpu_sparc_dump_state(env, logfile, 0);
+       {
+           int i;
+           uint8_t *ptr;
+           fprintf(logfile, "       code=");
+           ptr = env->pc;
+           for(i = 0; i < 16; i++) {
+               fprintf(logfile, " %02x", ldub(ptr + i));
+           }
+           fprintf(logfile, "\n");
+       }
+#endif
+       count++;
+    }
+#endif
+    env->psret = 0;
+    cwp = (env->cwp - 1) & (NWINDOWS - 1);
+    set_cwp(cwp);
+    env->regwptr[9] = env->pc;
+    env->regwptr[10] = env->npc;
+    env->psrps = env->psrs;
+    env->psrs = 1;
+
+    if (is_int)
+       trapno = intno | 0x80;
+    else
+       trapno = env->interrupt_index | 0x10;
+
+    env->tbr = (env->tbr & TBR_BASE_MASK) | (trapno << 4);
+    env->pc = env->tbr;
+    env->npc = env->pc + 4;
+}
+
+void raise_exception_err(int exception_index, int error_code)
+{
+    raise_exception(exception_index);
+}
diff -ruN qemu-0.6.0.orig/target-sparc/op.c qemu-0.6.0/target-sparc/op.c
--- qemu-0.6.0.orig/target-sparc/op.c   2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/target-sparc/op.c        2004-09-11 21:50:10.000000000 +0200
@@ -117,9 +117,108 @@
#define REGNAME o7
#define REG (env->regwptr[7])
#include "op_template.h"
+
+#define REGNAME f0
+#define REG (env->fpr[0])
+#include "fop_template.h"
+#define REGNAME f1
+#define REG (env->fpr[1])
+#include "fop_template.h"
+#define REGNAME f2
+#define REG (env->fpr[2])
+#include "fop_template.h"
+#define REGNAME f3
+#define REG (env->fpr[3])
+#include "fop_template.h"
+#define REGNAME f4
+#define REG (env->fpr[4])
+#include "fop_template.h"
+#define REGNAME f5
+#define REG (env->fpr[5])
+#include "fop_template.h"
+#define REGNAME f6
+#define REG (env->fpr[6])
+#include "fop_template.h"
+#define REGNAME f7
+#define REG (env->fpr[7])
+#include "fop_template.h"
+#define REGNAME f8
+#define REG (env->fpr[8])
+#include "fop_template.h"
+#define REGNAME f9
+#define REG (env->fpr[9])
+#include "fop_template.h"
+#define REGNAME f10
+#define REG (env->fpr[10])
+#include "fop_template.h"
+#define REGNAME f11
+#define REG (env->fpr[11])
+#include "fop_template.h"
+#define REGNAME f12
+#define REG (env->fpr[12])
+#include "fop_template.h"
+#define REGNAME f13
+#define REG (env->fpr[13])
+#include "fop_template.h"
+#define REGNAME f14
+#define REG (env->fpr[14])
+#include "fop_template.h"
+#define REGNAME f15
+#define REG (env->fpr[15])
+#include "fop_template.h"
+#define REGNAME f16
+#define REG (env->fpr[16])
+#include "fop_template.h"
+#define REGNAME f17
+#define REG (env->fpr[17])
+#include "fop_template.h"
+#define REGNAME f18
+#define REG (env->fpr[18])
+#include "fop_template.h"
+#define REGNAME f19
+#define REG (env->fpr[19])
+#include "fop_template.h"
+#define REGNAME f20
+#define REG (env->fpr[20])
+#include "fop_template.h"
+#define REGNAME f21
+#define REG (env->fpr[21])
+#include "fop_template.h"
+#define REGNAME f22
+#define REG (env->fpr[22])
+#include "fop_template.h"
+#define REGNAME f23
+#define REG (env->fpr[23])
+#include "fop_template.h"
+#define REGNAME f24
+#define REG (env->fpr[24])
+#include "fop_template.h"
+#define REGNAME f25
+#define REG (env->fpr[25])
+#include "fop_template.h"
+#define REGNAME f26
+#define REG (env->fpr[26])
+#include "fop_template.h"
+#define REGNAME f27
+#define REG (env->fpr[27])
+#include "fop_template.h"
+#define REGNAME f28
+#define REG (env->fpr[28])
+#include "fop_template.h"
+#define REGNAME f29
+#define REG (env->fpr[29])
+#include "fop_template.h"
+#define REGNAME f30
+#define REG (env->fpr[30])
+#include "fop_template.h"
+#define REGNAME f31
+#define REG (env->fpr[31])
+#include "fop_template.h"
+
#define EIP (env->pc)

#define FLAG_SET(x) (env->psr&x)?1:0
+#define FFLAG_SET(x) ((env->fsr&x)?1:0)

void OPPROTO op_movl_T0_0(void)
{
@@ -259,10 +358,10 @@

void OPPROTO op_mulscc_T1_T0(void)
{
-    unsigned int b1, C, V, b2, src1;
-    C = FLAG_SET(PSR_CARRY);
+    unsigned int b1, N, V, b2, src1;
+    N = FLAG_SET(PSR_NEG);
    V = FLAG_SET(PSR_OVF);
-    b1 = C ^ V;
+    b1 = N ^ V;
    b2 = T0 & 1;
    T0 = (b1 << 31) | (T0 >> 1);
    if (!(env->y & 1))
@@ -375,6 +474,7 @@
    T0 = ((int32_t) T0) >> T1;
}

+#if 0
void OPPROTO op_st(void)
{
    stl((void *) T0, T1);
@@ -440,6 +540,51 @@
    T0 = ldl((void *) (T0 + 4));
}

+void OPPROTO op_stf(void)
+{
+    stfl((void *) T0, FT0);
+}
+
+void OPPROTO op_stdf(void)
+{
+    stfq((void *) T0, DT0);
+}
+
+void OPPROTO op_ldf(void)
+{
+    FT0 = ldfl((void *) T0);
+}
+
+void OPPROTO op_lddf(void)
+{
+    DT0 = ldfq((void *) T0);
+}
+#else
+/* Load and store */
+#define MEMSUFFIX _raw
+#include "op_mem.h"
+#if !defined(CONFIG_USER_ONLY)
+#define MEMSUFFIX _user
+#include "op_mem.h"
+
+#define MEMSUFFIX _kernel
+#include "op_mem.h"
+#endif
+#endif
+
+void OPPROTO op_ldfsr(void)
+{
+    env->fsr = *((uint32_t *) &FT0);
+    FORCE_RET();
+}
+
+void OPPROTO op_stfsr(void)
+{
+    *((uint32_t *) &FT0) = env->fsr;
+    helper_stfsr();
+    FORCE_RET();
+}
+
void OPPROTO op_wry(void)
{
    env->y = T0;
@@ -450,6 +595,51 @@
    T0 = env->y;
}

+void OPPROTO op_rdwim(void)
+{
+    T0 = env->wim;
+}
+
+void OPPROTO op_wrwim(void)
+{
+    env->wim = T0;
+    FORCE_RET();
+}
+
+void OPPROTO op_rdpsr(void)
+{
+    /* Fake impl 0, version 4 */
+ T0 = (0<<28) | (4<<24) | env->psr | (env->psrs? PSR_S : 0) | (env->psrs? PSR_PS : 0) |(env->psret? PSR_ET : 0) | env->cwp;
+    FORCE_RET();
+}
+
+void OPPROTO op_wrpsr(void)
+{
+    env->psr = T0 & ~PSR_ICC;
+    env->psrs = (T0 & PSR_S)? 1 : 0;
+    env->psrps = (T0 & PSR_PS)? 1 : 0;
+    env->psret = (T0 & PSR_ET)? 1 : 0;
+    env->cwp = (T0 & PSR_CWP);
+    FORCE_RET();
+}
+
+void OPPROTO op_rdtbr(void)
+{
+    T0 = env->tbr;
+}
+
+void OPPROTO op_wrtbr(void)
+{
+    env->tbr = T0;
+    FORCE_RET();
+}
+
+void OPPROTO op_rett(void)
+{
+    helper_rett();
+    FORCE_RET();
+}
+
void raise_exception(int tt)
{
    env->exception_index = tt;
@@ -468,6 +658,7 @@
    dst[7] = src[7];
}

+#if 0
static inline void set_cwp(int new_cwp)
{
    /* put the modified wrap registers at their proper location */
@@ -479,6 +670,7 @@
        memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
    env->regwptr = env->regbase + (new_cwp * 16);
}
+#endif

/* XXX: use another pointer for %iN registers to avoid slow wrapping
   handling ? */
@@ -525,6 +717,12 @@
    FORCE_RET();
}

+void OPPROTO op_debug(void)
+{
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit();
+}
+
void OPPROTO op_exit_tb(void)
{
    EXIT_TB();
@@ -612,6 +810,92 @@
    T2 = !(env->psr & PSR_OVF);
}

+/* FCC1:FCC0: 0 =, 1 <, 2 >, 3 u */
+
+void OPPROTO op_eval_fbne(void)
+{
+// !0
+    T2 = (env->fsr & (FSR_FCC1 | FSR_FCC0)); /* L or G or U */
+}
+
+void OPPROTO op_eval_fblg(void)
+{
+// 1 or 2
+    T2 = FFLAG_SET(FSR_FCC0) ^ FFLAG_SET(FSR_FCC1);
+}
+
+void OPPROTO op_eval_fbul(void)
+{
+// 1 or 3
+    T2 = FFLAG_SET(FSR_FCC0);
+}
+
+void OPPROTO op_eval_fbl(void)
+{
+// 1
+    T2 = FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1);
+}
+
+void OPPROTO op_eval_fbug(void)
+{
+// 2 or 3
+    T2 = FFLAG_SET(FSR_FCC1);
+}
+
+void OPPROTO op_eval_fbg(void)
+{
+// 2
+    T2 = !FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1);
+}
+
+void OPPROTO op_eval_fbu(void)
+{
+// 3
+    T2 = FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1);
+}
+
+void OPPROTO op_eval_fbe(void)
+{
+// 0
+    T2 = !FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1);
+}
+
+void OPPROTO op_eval_fbue(void)
+{
+// 0 or 3
+    T2 = !(FFLAG_SET(FSR_FCC1) ^ FFLAG_SET(FSR_FCC0));
+}
+
+void OPPROTO op_eval_fbge(void)
+{
+// 0 or 2
+    T2 = !FFLAG_SET(FSR_FCC0);
+}
+
+void OPPROTO op_eval_fbuge(void)
+{
+// !1
+    T2 = !(FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1));
+}
+
+void OPPROTO op_eval_fble(void)
+{
+// 0 or 1
+    T2 = !FFLAG_SET(FSR_FCC1);
+}
+
+void OPPROTO op_eval_fbule(void)
+{
+// !2
+    T2 = !(!FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1));
+}
+
+void OPPROTO op_eval_fbo(void)
+{
+// !3
+    T2 = !(FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1));
+}
+
void OPPROTO op_movl_T2_0(void)
{
    T2 = 0;
@@ -687,3 +971,119 @@
{
    helper_flush(T0);
}
+
+void OPPROTO op_fnegs(void)
+{
+    FT0 = -FT1;
+}
+
+void OPPROTO op_fabss(void)
+{
+    do_fabss();
+}
+
+void OPPROTO op_fsqrts(void)
+{
+    do_fsqrts();
+}
+
+void OPPROTO op_fsqrtd(void)
+{
+    do_fsqrtd();
+}
+
+void OPPROTO op_fmuls(void)
+{
+    FT0 *= FT1;
+}
+
+void OPPROTO op_fmuld(void)
+{
+    DT0 *= DT1;
+}
+
+void OPPROTO op_fsmuld(void)
+{
+    DT0 = FT0 * FT1;
+}
+
+void OPPROTO op_fadds(void)
+{
+    FT0 += FT1;
+}
+
+void OPPROTO op_faddd(void)
+{
+    DT0 += DT1;
+}
+
+void OPPROTO op_fsubs(void)
+{
+    FT0 -= FT1;
+}
+
+void OPPROTO op_fsubd(void)
+{
+    DT0 -= DT1;
+}
+
+void OPPROTO op_fdivs(void)
+{
+    FT0 /= FT1;
+}
+
+void OPPROTO op_fdivd(void)
+{
+    DT0 /= DT1;
+}
+
+void OPPROTO op_fcmps(void)
+{
+    do_fcmps();
+}
+
+void OPPROTO op_fcmpd(void)
+{
+    do_fcmpd();
+}
+
+void OPPROTO op_fitos(void)
+{
+    FT0 = (float) *((int32_t *)&FT1);
+}
+
+void OPPROTO op_fdtos(void)
+{
+    FT0 = (float) DT1;
+}
+
+void OPPROTO op_fitod(void)
+{
+    DT0 = (double) *((int32_t *)&FT1);
+}
+
+void OPPROTO op_fstod(void)
+{
+    DT0 = (double) FT1;
+}
+
+void OPPROTO op_fstoi(void)
+{
+    *((int32_t *)&FT0) = (int32_t) FT1;
+}
+
+void OPPROTO op_fdtoi(void)
+{
+    *((int32_t *)&FT0) = (int32_t) DT1;
+}
+
+void OPPROTO op_ld_asi()
+{
+    helper_ld_asi(PARAM1);
+}
+
+void OPPROTO op_st_asi()
+{
+    helper_st_asi(PARAM1);
+}
+
diff -ruN qemu-0.6.0.orig/target-sparc/op_helper.c qemu-0.6.0/target-sparc/op_helper.c --- qemu-0.6.0.orig/target-sparc/op_helper.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-0.6.0/target-sparc/op_helper.c 2004-09-11 18:47:24.000000000 +0200
@@ -0,0 +1,128 @@
+#include <math.h>
+#include <fenv.h>
+#include "exec.h"
+
+void OPPROTO do_fabss(void)
+{
+    FT0 = fabsf(FT1);
+}
+
+void OPPROTO do_fsqrts(void)
+{
+    FT0 = sqrtf(FT1);
+}
+
+void OPPROTO do_fsqrtd(void)
+{
+    DT0 = sqrt(DT1);
+}
+
+void OPPROTO do_fcmps (void)
+{
+    if (isnan(FT0) || isnan(FT1)) {
+        T0 = FSR_FCC1 | FSR_FCC0;
+    } else if (FT0 < FT1) {
+        T0 = FSR_FCC0;
+    } else if (FT0 > FT1) {
+        T0 = FSR_FCC1;
+    } else {
+        T0 = 0;
+    }
+    env->fsr = T0;
+}
+
+void OPPROTO do_fcmpd (void)
+{
+    if (isnan(DT0) || isnan(DT1)) {
+        T0 = FSR_FCC1 | FSR_FCC0;
+    } else if (DT0 < DT1) {
+        T0 = FSR_FCC0;
+    } else if (DT0 > DT1) {
+        T0 = FSR_FCC1;
+    } else {
+        T0 = 0;
+    }
+    env->fsr = T0;
+}
+
+void OPPROTO helper_ld_asi(int asi)
+{
+    switch(asi) {
+    case 3: /* MMU probe */
+       T1 = 0;
+       return;
+    case 4: /* read MMU regs */
+       {
+           int temp, reg = (T0 >> 8) & 0xf;
+
+           temp = env->mmuregs[reg];
+           if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/
+               env->mmuregs[reg] = 0;
+           T1 = temp;
+       }
+       return;
+    case 0x20 ... 0x2f: /* MMU passthrough */
+       {
+           int temp;
+
+           cpu_physical_memory_rw(T0, (void *) &temp, 4, 0);
+           bswap32s(&temp);
+           T1 = temp;
+       }
+       return;
+    default:
+       T1 = 0;
+       return;
+    }
+}
+
+void OPPROTO helper_st_asi(int asi)
+{
+    switch(asi) {
+    case 3: /* MMU flush */
+       return;
+    case 4: /* write MMU regs */
+       env->mmuregs[(T0 >> 8) & 0xf] = T1;
+       return;
+    case 0x20 ... 0x2f: /* MMU passthrough */
+       {
+           int temp = T1;
+
+           bswap32s(&temp);
+           cpu_physical_memory_rw(T0, (void *) &temp, 4, 1);
+       }
+       return;
+    default:
+       return;
+    }
+}
+
+void OPPROTO helper_rett()
+{
+    int cwp;
+    env->psret = 1;
+    cwp = (env->cwp + 1) & (NWINDOWS - 1);
+    if (env->wim & (1 << cwp)) {
+        raise_exception(TT_WIN_UNF);
+    }
+    set_cwp(cwp);
+    env->psrs = env->psrps;
+}
+
+void helper_stfsr(void)
+{
+    switch (env->fsr & FSR_RD_MASK) {
+    case FSR_RD_NEAREST:
+       fesetround(FE_TONEAREST);
+       break;
+    case FSR_RD_ZERO:
+       fesetround(FE_TOWARDZERO);
+       break;
+    case FSR_RD_POS:
+       fesetround(FE_UPWARD);
+       break;
+    case FSR_RD_NEG:
+       fesetround(FE_DOWNWARD);
+       break;
+    }
+}
diff -ruN qemu-0.6.0.orig/target-sparc/op_mem.h qemu-0.6.0/target-sparc/op_mem.h --- qemu-0.6.0.orig/target-sparc/op_mem.h 1970-01-01 01:00:00.000000000 +0100
+++ qemu-0.6.0/target-sparc/op_mem.h    2004-08-22 12:29:03.000000000 +0200
@@ -0,0 +1,71 @@
+/*** Integer load ***/ +#define SPARC_LD_OP(name, qp) \ +void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ +{ \ + T1 = glue(qp, MEMSUFFIX)((void *)T0); \
+}
+
+#define SPARC_ST_OP(name, op) \ +void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ +{ \ + glue(op, MEMSUFFIX)((void *)T0, T1); \
+}
+
+SPARC_LD_OP(ld, ldl);
+SPARC_LD_OP(ldub, ldub);
+SPARC_LD_OP(lduh, lduw);
+SPARC_LD_OP(ldsb, ldsb);
+SPARC_LD_OP(ldsh, ldsw);
+
+/*** Integer store ***/
+SPARC_ST_OP(st, stl);
+SPARC_ST_OP(stb, stb);
+SPARC_ST_OP(sth, stw);
+
+void OPPROTO glue(op_std, MEMSUFFIX)(void)
+{
+    glue(stl, MEMSUFFIX)((void *) T0, T1);
+    glue(stl, MEMSUFFIX)((void *) (T0 + 4), T2);
+}
+
+void OPPROTO glue(op_ldstub, MEMSUFFIX)(void)
+{
+    T1 = glue(ldub, MEMSUFFIX)((void *) T0);
+ glue(stb, MEMSUFFIX)((void *) T0, 0xff); /* XXX: Should be Atomically */
+}
+
+void OPPROTO glue(op_swap, MEMSUFFIX)(void)
+{
+    unsigned int tmp = glue(ldl, MEMSUFFIX)((void *) T0);
+ glue(stl, MEMSUFFIX)((void *) T0, T1); /* XXX: Should be Atomically */
+    T1 = tmp;
+}
+
+void OPPROTO glue(op_ldd, MEMSUFFIX)(void)
+{
+    T1 = glue(ldl, MEMSUFFIX)((void *) T0);
+    T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4));
+}
+
+/*** Floating-point store ***/
+void OPPROTO glue(op_stf, MEMSUFFIX) (void)
+{
+    glue(stfl, MEMSUFFIX)((void *) T0, FT0);
+}
+
+void OPPROTO glue(op_stdf, MEMSUFFIX) (void)
+{
+    glue(stfq, MEMSUFFIX)((void *) T0, DT0);
+}
+
+/*** Floating-point load ***/
+void OPPROTO glue(op_ldf, MEMSUFFIX) (void)
+{
+    FT0 = glue(ldfl, MEMSUFFIX)((void *) T0);
+}
+
+void OPPROTO glue(op_lddf, MEMSUFFIX) (void)
+{
+    DT0 = glue(ldfq, MEMSUFFIX)((void *) T0);
+}
+#undef MEMSUFFIX
diff -ruN qemu-0.6.0.orig/target-sparc/translate.c qemu-0.6.0/target-sparc/translate.c --- qemu-0.6.0.orig/target-sparc/translate.c 2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/target-sparc/translate.c 2004-09-15 19:37:54.000000000 +0200
@@ -51,6 +51,7 @@
    target_ulong npc;   /* next PC: integer or DYNAMIC_PC or JUMP_PC */
    target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */
    int is_br;
+    int mem_idx;
    struct TranslationBlock *tb;
} DisasContext;

@@ -257,6 +258,96 @@
    gen_op_movl_T2_im
};

+#define GEN32(func, NAME) \
+static GenOpFunc *NAME ## _table [32] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \
+}
+
+/* floating point registers moves */
+GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fprf);
+GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fprf);
+GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fprf);
+GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fprf);
+GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fprf);
+GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fprf);
+
+GEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fprf);
+GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf);
+GEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fprf);
+GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf);
+GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf);
+GEN32(gen_op_store_DT2_fpr, gen_op_store_DT2_fpr_fprf);
+
+#if defined(CONFIG_USER_ONLY)
+#define gen_op_ldst(name)        gen_op_##name##_raw()
+#define OP_LD_TABLE(width)
+#define supervisor(dc) 0
+#else
+#define gen_op_ldst(name)        (*gen_op_##name[dc->mem_idx])()
+#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_##width[] = { \ + &gen_op_##width##_user, \ + &gen_op_##width##_kernel, \ +}; \ + \
+static void gen_op_##width##a(int insn, int is_ld)                           \
+{ \ + int asi; \ + \ + asi = GET_FIELD(insn, 19, 26); \ + switch (asi) { \
+       case 10: /* User data access */                                       \
+           gen_op_##width##_user();                                          \
+           break;                                                            \
+       case 11: /* Supervisor data access */                                 \
+           gen_op_##width##_kernel();                                        \
+           break;                                                            \
+        case 0x20 ... 0x2f: /* MMU passthrough */                            \
+           if (is_ld)                                                        \
+               gen_op_ld_asi(asi);                                           \
+           else                                                              \
+               gen_op_st_asi(asi);                                           \
+           break;                                                            \
+       default:                                                              \
+           if (is_ld)                                                        \
+               gen_op_ld_asi(asi);                                           \
+           else                                                              \
+               gen_op_st_asi(asi);                                           \
+ break; \ + } \
+}
+
+#define supervisor(dc) (dc->mem_idx == 1)
+#endif
+
+OP_LD_TABLE(ld);
+OP_LD_TABLE(st);
+OP_LD_TABLE(ldub);
+OP_LD_TABLE(lduh);
+OP_LD_TABLE(ldsb);
+OP_LD_TABLE(ldsh);
+OP_LD_TABLE(stb);
+OP_LD_TABLE(sth);
+OP_LD_TABLE(std);
+OP_LD_TABLE(ldstub);
+OP_LD_TABLE(swap);
+OP_LD_TABLE(ldd);
+OP_LD_TABLE(stf);
+OP_LD_TABLE(stdf);
+OP_LD_TABLE(ldf);
+OP_LD_TABLE(lddf);
+
static inline void gen_movl_imm_TN(int reg, int imm)
{
    gen_op_movl_TN_im[reg] (imm);
@@ -391,6 +482,60 @@
        }
}

+static void gen_fcond(int cond)
+{
+       switch (cond) {
+        case 0x0:
+            gen_op_movl_T2_0();
+            break;
+       case 0x1:
+           gen_op_eval_fbne();
+           break;
+       case 0x2:
+           gen_op_eval_fblg();
+           break;
+       case 0x3:
+           gen_op_eval_fbul();
+           break;
+       case 0x4:
+           gen_op_eval_fbl();
+           break;
+       case 0x5:
+           gen_op_eval_fbug();
+           break;
+       case 0x6:
+           gen_op_eval_fbg();
+           break;
+       case 0x7:
+           gen_op_eval_fbu();
+           break;
+        case 0x8:
+            gen_op_movl_T2_1();
+            break;
+       case 0x9:
+           gen_op_eval_fbe();
+           break;
+       case 0xa:
+           gen_op_eval_fbue();
+           break;
+       case 0xb:
+           gen_op_eval_fbge();
+           break;
+       case 0xc:
+           gen_op_eval_fbuge();
+           break;
+       case 0xd:
+           gen_op_eval_fble();
+           break;
+       case 0xe:
+           gen_op_eval_fbule();
+           break;
+        default:
+       case 0xf:
+           gen_op_eval_fbo();
+           break;
+       }
+}

static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn)
{
@@ -429,6 +574,50 @@
    }
}

+static void do_fbranch(DisasContext * dc, uint32_t target, uint32_t insn)
+{
+    unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29));
+    target += (uint32_t) dc->pc;
+    if (cond == 0x0) {
+       /* unconditional not taken */
+       if (a) {
+           dc->pc = dc->npc + 4;
+           dc->npc = dc->pc + 4;
+       } else {
+           dc->pc = dc->npc;
+           dc->npc = dc->pc + 4;
+       }
+    } else if (cond == 0x8) {
+       /* unconditional taken */
+       if (a) {
+           dc->pc = target;
+           dc->npc = dc->pc + 4;
+       } else {
+           dc->pc = dc->npc;
+           dc->npc = target;
+       }
+    } else {
+        flush_T2(dc);
+        gen_fcond(cond);
+       if (a) {
+           gen_op_branch_a((long)dc->tb, target, dc->npc);
+            dc->is_br = 1;
+       } else {
+            dc->pc = dc->npc;
+            dc->jump_pc[0] = target;
+            dc->jump_pc[1] = dc->npc + 4;
+            dc->npc = JUMP_PC;
+       }
+    }
+}
+
+static void gen_debug(DisasContext *s, uint32_t pc)
+{
+    gen_op_jmp_im(pc);
+    gen_op_debug();
+    s->is_br = 1;
+}
+
#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)

static int sign_extend(int x, int len)
@@ -454,6 +643,7 @@
            switch (xop) {
            case 0x0:
            case 0x1:           /* UNIMPL */
+           default:
                goto illegal_insn;
            case 0x2:           /* BN+x */
                {
@@ -462,8 +652,13 @@
                    do_branch(dc, target, insn);
                    goto jmp_insn;
                }
-           case 0x3:           /* FBN+x */
-               break;
+           case 0x6:           /* FBN+x */
+               {
+                   target <<= 2;
+                   target = sign_extend(target, 22);
+                   do_fbranch(dc, target, insn);
+                   goto jmp_insn;
+               }
            case 0x4:           /* SETHI */
                gen_movl_imm_T0(target << 10);
                gen_movl_T0_reg(rd);
@@ -492,12 +687,16 @@
                rs1 = GET_FIELD(insn, 13, 17);
                gen_movl_reg_T0(rs1);
                if (IS_IMM) {
-                    gen_movl_imm_T1(GET_FIELD(insn, 25, 31));
+                   rs2 = GET_FIELD(insn, 25, 31);
+                   if (rs2 != 0) {
+                        gen_movl_imm_T1(rs2);
+                        gen_op_add_T1_T0();
+                   }
                } else {
                    rs2 = GET_FIELD(insn, 27, 31);
                    gen_movl_reg_T1(rs2);
+                    gen_op_add_T1_T0();
                }
-                gen_op_add_T1_T0();
                save_state(dc);
                cond = GET_FIELD(insn, 3, 6);
                if (cond == 0x8) {
@@ -514,11 +713,167 @@
                    gen_op_rdy();
                    gen_movl_T0_reg(rd);
                    break;
+                case 15: /* stbar */
+                   break; /* no effect? */
                default:
                    goto illegal_insn;
                }
+#if !defined(CONFIG_USER_ONLY)
+            } else if (xop == 0x29) {
+               if (!supervisor(dc))
+                   goto priv_insn;
+                gen_op_rdpsr();
+                gen_movl_T0_reg(rd);
+                break;
+            } else if (xop == 0x2a) {
+               if (!supervisor(dc))
+                   goto priv_insn;
+                gen_op_rdwim();
+                gen_movl_T0_reg(rd);
+                break;
+            } else if (xop == 0x2b) {
+               if (!supervisor(dc))
+                   goto priv_insn;
+                gen_op_rdtbr();
+                gen_movl_T0_reg(rd);
+                break;
+#endif
            } else if (xop == 0x34 || xop == 0x35) {    /* FPU Operations */
-                goto illegal_insn;
+                rs1 = GET_FIELD(insn, 13, 17);
+               rs2 = GET_FIELD(insn, 27, 31);
+               xop = GET_FIELD(insn, 18, 26);
+               switch (xop) {
+                   case 0x1: /* fmovs */
+                       gen_op_load_fpr_FT0(rs2);
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0x5: /* fnegs */
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fnegs();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0x9: /* fabss */
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fabss();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0x29: /* fsqrts */
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fsqrts();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0x2a: /* fsqrtd */
+                       gen_op_load_fpr_DT1(rs2);
+                       gen_op_fsqrtd();
+                       gen_op_store_DT0_fpr(rd);
+                       break;
+                   case 0x41:
+                       gen_op_load_fpr_FT0(rs1);
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fadds();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0x42:
+                       gen_op_load_fpr_DT0(rs1);
+                       gen_op_load_fpr_DT1(rs2);
+                       gen_op_faddd();
+                       gen_op_store_DT0_fpr(rd);
+                       break;
+                   case 0x45:
+                       gen_op_load_fpr_FT0(rs1);
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fsubs();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0x46:
+                       gen_op_load_fpr_DT0(rs1);
+                       gen_op_load_fpr_DT1(rs2);
+                       gen_op_fsubd();
+                       gen_op_store_DT0_fpr(rd);
+                       break;
+                   case 0x49:
+                       gen_op_load_fpr_FT0(rs1);
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fmuls();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0x4a:
+                       gen_op_load_fpr_DT0(rs1);
+                       gen_op_load_fpr_DT1(rs2);
+                       gen_op_fmuld();
+                       gen_op_store_DT0_fpr(rd);
+                       break;
+                   case 0x4d:
+                       gen_op_load_fpr_FT0(rs1);
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fdivs();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0x4e:
+                       gen_op_load_fpr_DT0(rs1);
+                       gen_op_load_fpr_DT1(rs2);
+                       gen_op_fdivd();
+                       gen_op_store_DT0_fpr(rd);
+                       break;
+                   case 0x51:
+                       gen_op_load_fpr_FT0(rs1);
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fcmps();
+                       break;
+                   case 0x52:
+                       gen_op_load_fpr_DT0(rs1);
+                       gen_op_load_fpr_DT1(rs2);
+                       gen_op_fcmpd();
+                       break;
+                   case 0x55: /* fcmpes */
+                       gen_op_load_fpr_FT0(rs1);
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fcmps(); /* XXX */
+                       break;
+                   case 0x56: /* fcmped */
+                       gen_op_load_fpr_DT0(rs1);
+                       gen_op_load_fpr_DT1(rs2);
+                       gen_op_fcmpd(); /* XXX */
+                       break;
+                   case 0x69:
+                       gen_op_load_fpr_FT0(rs1);
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fsmuld();
+                       gen_op_store_DT0_fpr(rd);
+                       break;
+                   case 0xc4:
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fitos();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0xc6:
+                       gen_op_load_fpr_DT1(rs2);
+                       gen_op_fdtos();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0xc8:
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fitod();
+                       gen_op_store_DT0_fpr(rd);
+                       break;
+                   case 0xc9:
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fstod();
+                       gen_op_store_DT0_fpr(rd);
+                       break;
+                   case 0xd1:
+                       gen_op_load_fpr_FT1(rs2);
+                       gen_op_fstoi();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   case 0xd2:
+                       gen_op_load_fpr_DT1(rs2);
+                       gen_op_fdtoi();
+                       gen_op_store_FT0_fpr(rd);
+                       break;
+                   default:
+                       goto illegal_insn;
+               }
            } else {
                rs1 = GET_FIELD(insn, 13, 17);
                gen_movl_reg_T0(rs1);
@@ -637,6 +992,32 @@
                            }
                        }
                        break;
+#if !defined(CONFIG_USER_ONLY)
+                    case 0x31:
+                        {
+                           if (!supervisor(dc))
+                               goto priv_insn;
+                            gen_op_xor_T1_T0();
+                            gen_op_wrpsr();
+                        }
+                        break;
+                    case 0x32:
+                        {
+                           if (!supervisor(dc))
+                               goto priv_insn;
+                            gen_op_xor_T1_T0();
+                            gen_op_wrwim();
+                        }
+                        break;
+                    case 0x33:
+                        {
+                           if (!supervisor(dc))
+                               goto priv_insn;
+                            gen_op_xor_T1_T0();
+                            gen_op_wrtbr();
+                        }
+                        break;
+#endif
                    case 0x38:  /* jmpl */
                        {
                            gen_op_add_T1_T0();
@@ -649,6 +1030,24 @@
                            dc->npc = DYNAMIC_PC;
                        }
                        goto jmp_insn;
+#if !defined(CONFIG_USER_ONLY)
+                    case 0x39: /* rett */
+                        {
+                           if (!supervisor(dc))
+                               goto priv_insn;
+                            gen_op_add_T1_T0();
+                            gen_op_movl_npc_T0();
+                            gen_op_rett();
+#if 0
+                           dc->pc = dc->npc;
+                           dc->npc = DYNAMIC_PC;
+#endif
+                        }
+#if 0
+                        goto jmp_insn;
+#endif
+                       break;
+#endif
                    case 0x3b: /* flush */
                        gen_op_add_T1_T0();
                        gen_op_flush_T0();
@@ -679,60 +1078,157 @@
            gen_movl_reg_T0(rs1);
            if (IS_IMM) {       /* immediate */
                rs2 = GET_FIELDs(insn, 19, 31);
-               gen_movl_imm_T1(rs2);
+               if (rs2 != 0) {
+                   gen_movl_imm_T1(rs2);
+                   gen_op_add_T1_T0();
+               }
            } else {            /* register */
                rs2 = GET_FIELD(insn, 27, 31);
                gen_movl_reg_T1(rs2);
+               gen_op_add_T1_T0();
            }
-           gen_op_add_T1_T0();
-           if (xop < 4 || xop > 7) {
+           if (xop < 4 || (xop > 7 && xop < 0x14) || \
+                   (xop > 0x17 && xop < 0x20)) {
                switch (xop) {
                case 0x0:       /* load word */
-                   gen_op_ld();
+                   gen_op_ldst(ld);
                    break;
                case 0x1:       /* load unsigned byte */
-                   gen_op_ldub();
+                   gen_op_ldst(ldub);
                    break;
                case 0x2:       /* load unsigned halfword */
-                   gen_op_lduh();
+                   gen_op_ldst(lduh);
                    break;
                case 0x3:       /* load double word */
-                   gen_op_ldd();
+                   gen_op_ldst(ldd);
                    gen_movl_T0_reg(rd + 1);
                    break;
                case 0x9:       /* load signed byte */
-                   gen_op_ldsb();
+                   gen_op_ldst(ldsb);
                    break;
                case 0xa:       /* load signed halfword */
-                   gen_op_ldsh();
+                   gen_op_ldst(ldsh);
                    break;
                case 0xd:       /* ldstub -- XXX: should be atomically */
-                   gen_op_ldstub();
+                   gen_op_ldst(ldstub);
                    break;
                case 0x0f:      /* swap register with memory. Also atomically */
-                   gen_op_swap();
+                   gen_op_ldst(swap);
+                   break;
+               case 0x10:      /* load word alternate */
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_lda(insn, 1);
+                   break;
+               case 0x11:      /* load unsigned byte alternate */
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_lduba(insn, 1);
+                   break;
+               case 0x12:      /* load unsigned halfword alternate */
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_lduha(insn, 1);
+                   break;
+               case 0x13:      /* load double word alternate */
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_ldda(insn, 1);
+                   gen_movl_T0_reg(rd + 1);
+                   break;
+               case 0x19:      /* load signed byte alternate */
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_ldsba(insn, 1);
+                   break;
+               case 0x1a:      /* load signed halfword alternate */
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_ldsha(insn, 1);
+                   break;
+               case 0x1d:      /* ldstuba -- XXX: should be atomically */
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_ldstuba(insn, 1);
+                   break;
+               case 0x1f:      /* swap reg with alt. memory. Also atomically */
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_swapa(insn, 1);
                    break;
                }
                gen_movl_T1_reg(rd);
-           } else if (xop < 8) {
+           } else if (xop >= 0x20 && xop < 0x24) {
+               switch (xop) {
+               case 0x20:      /* load fpreg */
+                   gen_op_ldst(ldf);
+                   gen_op_store_FT0_fpr(rd);
+                   break;
+               case 0x21:      /* load fsr */
+                   gen_op_ldfsr();
+                   break;
+               case 0x23:      /* load double fpreg */
+                   gen_op_ldst(lddf);
+                   gen_op_store_DT0_fpr(rd);
+                   break;
+               }
+           } else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) {
                gen_movl_reg_T1(rd);
                switch (xop) {
                case 0x4:
-                   gen_op_st();
+                   gen_op_ldst(st);
                    break;
                case 0x5:
-                   gen_op_stb();
+                   gen_op_ldst(stb);
                    break;
                case 0x6:
-                   gen_op_sth();
+                   gen_op_ldst(sth);
                    break;
                case 0x7:
                    flush_T2(dc);
                    gen_movl_reg_T2(rd + 1);
-                   gen_op_std();
+                   gen_op_ldst(std);
+                   break;
+               case 0x14:
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_sta(insn, 0);
+                   break;
+               case 0x15:
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_stba(insn, 0);
+                   break;
+               case 0x16:
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                   gen_op_stha(insn, 0);
+                   break;
+               case 0x17:
+                   if (!supervisor(dc))
+                       goto priv_insn;
+                    flush_T2(dc);
+                   gen_movl_reg_T2(rd + 1);
+                   gen_op_stda(insn, 0);
                    break;
                }
-           }
+           } else if (xop > 0x23 && xop < 0x28) {
+               switch (xop) {
+               case 0x24:
+                    gen_op_load_fpr_FT0(rd);
+                   gen_op_ldst(stf);
+                   break;
+               case 0x25:
+                   gen_op_stfsr();
+                   break;
+               case 0x27:
+                    gen_op_load_fpr_DT0(rd);
+                   gen_op_ldst(stdf);
+                   break;
+               }
+           } else if (xop > 0x33 && xop < 0x38) {
+               /* Co-processor */
+            }
        }
    }
    /* default case for non jump instructions */
@@ -753,30 +1249,58 @@
    save_state(dc);
    gen_op_exception(TT_ILL_INSN);
    dc->is_br = 1;
+    return;
+ priv_insn:
+    save_state(dc);
+    gen_op_exception(TT_PRIV_INSN);
+    dc->is_br = 1;
}

static inline int gen_intermediate_code_internal(TranslationBlock * tb,
-                                                int spc)
+                                                int spc, CPUSPARCState *env)
{
    target_ulong pc_start, last_pc;
    uint16_t *gen_opc_end;
    DisasContext dc1, *dc = &dc1;
+    int j, lj = -1;

    memset(dc, 0, sizeof(DisasContext));
-    if (spc) {
-       printf("SearchPC not yet supported\n");
-       exit(0);
-    }
    dc->tb = tb;
    pc_start = tb->pc;
    dc->pc = pc_start;
    dc->npc = (target_ulong) tb->cs_base;
+#if defined(CONFIG_USER_ONLY)
+    dc->mem_idx = 0;
+#else
+    dc->mem_idx = ((env->psrs) != 0);
+#endif

    gen_opc_ptr = gen_opc_buf;
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
    gen_opparam_ptr = gen_opparam_buf;

    do {
+        if (env->nb_breakpoints > 0) {
+            for(j = 0; j < env->nb_breakpoints; j++) {
+                if (env->breakpoints[j] == dc->pc) {
+                    gen_debug(dc, dc->pc);
+                    break;
+                }
+            }
+        }
+        if (spc) {
+            if (loglevel > 0)
+                fprintf(logfile, "Search PC...\n");
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+                gen_opc_pc[lj] = dc->pc;
+                gen_opc_npc[lj] = dc->npc;
+                gen_opc_instr_start[lj] = 1;
+            }
+        }
        last_pc = dc->pc;
        disas_sparc_insn(dc);
        if (dc->is_br)
@@ -800,6 +1324,20 @@
        }
    }
    *gen_opc_ptr = INDEX_op_end;
+    if (spc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+        tb->size = 0;
+#if 0
+        if (loglevel > 0) {
+            page_dump(logfile);
+        }
+#endif
+    } else {
+        tb->size = dc->npc - pc_start;
+    }
#ifdef DEBUG_DISAS
    if (loglevel & CPU_LOG_TB_IN_ASM) {
        fprintf(logfile, "--------------\n");
@@ -819,12 +1357,12 @@

int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
{
-    return gen_intermediate_code_internal(tb, 0);
+    return gen_intermediate_code_internal(tb, 0, env);
}

int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
{
-    return gen_intermediate_code_internal(tb, 1);
+    return gen_intermediate_code_internal(tb, 1, env);
}

CPUSPARCState *cpu_sparc_init(void)
@@ -839,7 +1377,16 @@
    env->cwp = 0;
    env->wim = 1;
    env->regwptr = env->regbase + (env->cwp * 16);
+#if defined(CONFIG_USER_ONLY)
    env->user_mode_only = 1;
+#else
+    /* Emulate Prom */
+    env->psrs = 1;
+    env->pc = 0x4000;
+    env->npc = env->pc + 4;
+    env->mmuregs[0] = MMU_E; /* MMU Enabled */
+    env->mmuregs[1] = 0x3000 >> 4; /* MMU Context table */
+#endif
    cpu_single_env = env;
    return (env);
}
@@ -870,10 +1417,19 @@
                    env->regwptr[i + x * 8]);
        fprintf(f, "\n");
    }
+    fprintf(f, "\nFloating Point Registers:\n");
+    for (i = 0; i < 32; i++) {
+        if ((i & 3) == 0)
+            fprintf(f, "%%f%02d:", i);
+        fprintf(f, " %016lf", env->fpr[i]);
+        if ((i & 3) == 3)
+            fprintf(f, "\n");
+    }
fprintf(f, "psr: 0x%08x -> %c%c%c%c wim: 0x%08x\n", env->psr | env->cwp,
            GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
            GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'),
            env->wim);
+    fprintf(f, "fsr: 0x%08x\n", env->fsr);
}

target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
diff -ruN qemu-0.6.0.orig/translate-all.c qemu-0.6.0/translate-all.c
--- qemu-0.6.0.orig/translate-all.c     2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/translate-all.c  2004-09-08 18:16:56.000000000 +0200
@@ -46,6 +46,8 @@
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
#if defined(TARGET_I386)
uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
+#elif defined(TARGET_SPARC)
+uint32_t gen_opc_npc[OPC_BUF_SIZE];
#endif

int code_copy_enabled = 1;
@@ -208,6 +210,7 @@
#elif defined(TARGET_SPARC)
    /* XXX: restore npc too */
    env->pc = gen_opc_pc[j];
+    env->npc = gen_opc_npc[j];
#elif defined(TARGET_PPC)
    {
        int type;
diff -ruN qemu-0.6.0.orig/vl.c qemu-0.6.0/vl.c
--- qemu-0.6.0.orig/vl.c        2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/vl.c     2004-09-15 19:42:36.000000000 +0200
@@ -702,7 +702,7 @@

    for(;;) {
        ts = *ptimer_head;
-        if (ts->expire_time > current_time)
+        if (!ts || ts->expire_time > current_time)
            break;
        /* remove timer from the list before calling the callback */
        *ptimer_head = ts->next;
@@ -1758,6 +1758,15 @@
{
    return 0;
}
+#elif defined(TARGET_SPARC)
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return 0;
+}
#else

#warning No CPU save/restore functions
@@ -2803,6 +2812,10 @@
    ppc_init(ram_size, vga_ram_size, boot_device,
             ds, fd_filename, snapshot,
             kernel_filename, kernel_cmdline, initrd_filename);
+#elif defined(TARGET_SPARC)
+    sun4m_init(ram_size, vga_ram_size, boot_device,
+            ds, fd_filename, snapshot,
+            kernel_filename, kernel_cmdline, initrd_filename);
#endif

    /* launched after the device init so that it can display or not a
diff -ruN qemu-0.6.0.orig/vl.h qemu-0.6.0/vl.h
--- qemu-0.6.0.orig/vl.h        2004-07-10 20:20:09.000000000 +0200
+++ qemu-0.6.0/vl.h     2004-09-12 21:00:24.000000000 +0200
@@ -699,6 +699,25 @@
extern CPUReadMemoryFunc *PPC_io_read[];
extern int prep_enabled;

+/* sun4m.c */
+void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
+             DisplayState *ds, const char **fd_filename, int snapshot,
+             const char *kernel_filename, const char *kernel_cmdline,
+             const char *initrd_filename);
+
+/* iommu.c */
+void iommu_init();
+uint32_t iommu_translate(uint32_t addr);
+
+/* lance.c */
+void lance_init(NetDriverState *nd, int irq);
+
+/* tcx.c */
+void tcx_init(DisplayState *ds);
+
+/* sched.c */
+void sched_init();
+
/* NVRAM helpers */
#include "hw/m48t59.h"

_________________________________________________________________
STOP MORE SPAM with the new MSN 8 and get 2 months FREE* http://join.msn.com/?page=features/junkmail





reply via email to

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