SPARC fixes: corrected PC/NPC logic (now slower but can be optimized a lot) - fixed...
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 4 Jan 2004 15:01:44 +0000 (15:01 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 4 Jan 2004 15:01:44 +0000 (15:01 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@484 c046a42c-6fe2-441c-8c8c-71466251a162

linux-user/sparc/syscall_nr.h
target-sparc/cpu.h
target-sparc/op.c
target-sparc/translate.c

index afb364f079992dfd887b6f8e31bd9061b54fa09d..3270a302121b15915c0408d57529d60ce2417156 100644 (file)
 #define TARGET_NR_sysinfo            214 /* Linux Specific                              */
 #define TARGET_NR_ipc                215 /* Linux Specific                              */
 #define TARGET_NR_sigreturn          216 /* Linux Specific                              */
-#define TARGET_NR_clone              217 /* Linux Specific                              */
+#define TARGET_NR_clone              2170 /* Linux Specific                              */
 #define TARGET_NR_adjtimex           219 /* Linux Specific                              */
 #define TARGET_NR_sigprocmask        220 /* Linux Specific                              */
 #define TARGET_NR_create_module      221 /* Linux Specific                              */
index 350d7b719c670f3ff8d16ff85d5944a1fd1dd0fa..67fece712734227b867206c5148f11b26a89f6ad 100644 (file)
@@ -7,29 +7,42 @@
 
 /*#define EXCP_INTERRUPT 0x100*/
 
+/* trap definitions */
+#define TT_ILL_INSN 0x02
+#define TT_WIN_OVF  0x05
+#define TT_WIN_UNF  0x06 
+#define TT_DIV_ZERO 0x2a
+#define TT_TRAP     0x80
 
 #define PSR_NEG   (1<<23)
 #define PSR_ZERO  (1<<22)
 #define PSR_OVF   (1<<21)
 #define PSR_CARRY (1<<20)
 
+#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 */
-       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 T2;
-       jmp_buf  jmp_env;
-       int user_mode_only;
-       int exception_index;
-       int interrupt_index;
-       int interrupt_request;
-       struct TranslationBlock *current_tb;
-       void *opaque;
+    uint32_t gregs[8]; /* general registers */
+    uint32_t *regwptr; /* pointer to current register window */
+    double   *regfptr; /* 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 T2;
+    uint32_t cwp;      /* index of current register window (extracted
+                          from PSR) */
+    uint32_t wim;      /* window invalid mask */
+    jmp_buf  jmp_env;
+    int user_mode_only;
+    int exception_index;
+    int interrupt_index;
+    int interrupt_request;
+    struct TranslationBlock *current_tb;
+    void *opaque;
+    /* NOTE: we allow 8 more registers to handle wrapping */
+    uint32_t regbase[NWINDOWS * 16 + 8];
 } CPUSPARCState;
 
 CPUSPARCState *cpu_sparc_init(void);
index 65922aa77647c282ce4a593c22723cbe4d9110ef..394c2241a7a6976eb1b800b93f282b860a17a334 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "exec.h"
 
-/*XXX*/
+ /*XXX*/
 #define REGNAME g0
 #define REG (env->gregs[0])
 #include "op_template.h"
 #define REGNAME o7
 #define REG (env->regwptr[7])
 #include "op_template.h"
-
 #define EIP (env->pc)
 
+#define FLAG_SET(x) (env->psr&x)?1:0
+#define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY)
+
 void OPPROTO op_movl_T0_0(void)
 {
-       T0 = 0;
+    T0 = 0;
 }
 
 void OPPROTO op_movl_T0_1(void)
 {
-       T0 = 1;
+    T0 = 1;
 }
 
 void OPPROTO op_movl_T0_im(void)
 {
-       T0 = PARAM1;
+    T0 = PARAM1;
 }
 
 void OPPROTO op_movl_T1_im(void)
 {
-       T1 = PARAM1;
+    T1 = PARAM1;
 }
 
 void OPPROTO op_movl_T2_im(void)
 {
-       T2 = PARAM1;
+    T2 = PARAM1;
 }
 
 void OPPROTO op_addl_T1_im(void)
 {
-       T1 += PARAM1;
+    T1 += PARAM1;
 }
 
 void OPPROTO op_addl_T1_T2(void)
 {
-       T1 += T2;
+    T1 += T2;
 }
 
 void OPPROTO op_subl_T1_T2(void)
 {
-       T1 -= T2;
+    T1 -= T2;
 }
 
-void OPPROTO op_add_T1_T0 (void)
+void OPPROTO op_add_T1_T0(void)
 {
-       T0 += T1;
+    T0 += T1;
 }
 
-void OPPROTO op_and_T1_T0 (void)
+void OPPROTO op_add_T1_T0_cc(void)
 {
-       T0 &= T1;
+    unsigned int src1;
+    src1 = T0;
+    T0 += T1;
+    env->psr = 0;
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((int) T0 < 0)
+       env->psr |= PSR_NEG;
+    if (T0 < src1)
+       env->psr |= PSR_CARRY;
+    if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
+       env->psr |= PSR_OVF;
+    FORCE_RET();
 }
 
-void OPPROTO op_or_T1_T0 (void)
+void OPPROTO op_sub_T1_T0(void)
 {
-       T0 |= T1;
+    T0 -= T1;
 }
 
-void OPPROTO op_xor_T1_T0 (void)
+void OPPROTO op_sub_T1_T0_cc(void)
 {
-       T0 ^= T1;
+    unsigned int src1;
+
+    src1 = T0;
+    T0 -= T1;
+    env->psr = 0;
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((int) T0 < 0)
+       env->psr |= PSR_NEG;
+    if (src1 < T1)
+       env->psr |= PSR_CARRY;
+    if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
+       env->psr |= PSR_OVF;
+    FORCE_RET();
 }
 
-void OPPROTO op_sub_T1_T0 (void)
+void OPPROTO op_and_T1_T0(void)
 {
-       T0 -= T1;
+    T0 &= T1;
 }
 
-void OPPROTO op_andn_T1_T0 (void)
+void OPPROTO op_or_T1_T0(void)
 {
-       T0 &= ~T1;
+    T0 |= T1;
 }
 
-void OPPROTO op_orn_T1_T0 (void)
+void OPPROTO op_xor_T1_T0(void)
 {
-       T0 |= ~T1;
+    T0 ^= T1;
 }
 
-void OPPROTO op_xnor_T1_T0 (void)
+void OPPROTO op_andn_T1_T0(void)
 {
-       T0 ^= ~T1;
+    T0 &= ~T1;
 }
 
-void OPPROTO op_addx_T1_T0 (void)
+void OPPROTO op_orn_T1_T0(void)
 {
-       T0 += T1+((env->psr & PSR_CARRY)?1:0);
+    T0 |= ~T1;
 }
 
-void OPPROTO op_umul_T1_T0 (void)
+void OPPROTO op_xnor_T1_T0(void)
 {
-       unsigned long long res = T0*T1;
-       T0 = res & 0xffffffff;
-       env->y = res >> 32;
+    T0 ^= ~T1;
 }
 
-void OPPROTO op_smul_T1_T0 (void)
+void OPPROTO op_addx_T1_T0(void)
 {
-       long long res = T0*T1;
-       T0 = res & 0xffffffff;
-       env->y = res >> 32;
+    T0 += T1 + ((env->psr & PSR_CARRY) ? 1 : 0);
 }
 
-void OPPROTO op_udiv_T1_T0 (void)
+void OPPROTO op_umul_T1_T0(void)
 {
-       unsigned long long x0 = T0 * env->y;
-       unsigned int x1 = T1;
-       T0 = x0 / x1;
+    uint64_t res;
+    res = (uint64_t) T0 *(uint64_t) T1;
+    T0 = res & 0xffffffff;
+    env->y = res >> 32;
 }
 
-void OPPROTO op_sdiv_T1_T0 (void)
+void OPPROTO op_smul_T1_T0(void)
 {
-       long long x0 = T0 * env->y;
-       int x1 = T1;
-       T0 = x0 / x1;
+    uint64_t res;
+    res = (int64_t) ((int32_t) T0) * (int64_t) ((int32_t) T1);
+    T0 = res & 0xffffffff;
+    env->y = res >> 32;
 }
 
-void OPPROTO op_subx_T1_T0 (void)
+void OPPROTO op_mulscc_T1_T0(void)
 {
-       T0 -= T1+((env->psr & PSR_CARRY)?1:0);
+    unsigned int b1, C, V, b2, src1;
+    C = FLAG_SET(PSR_CARRY);
+    V = FLAG_SET(PSR_OVF);
+    b1 = C ^ V;
+    b2 = T0 & 1;
+    T0 = (b1 << 31) | (T0 >> 1);
+    if (!(env->y & 1))
+        T1 = 0;
+    /* do addition and update flags */
+    src1 = T0;
+    T0 += T1;
+    env->psr = 0;
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((int) T0 < 0)
+       env->psr |= PSR_NEG;
+    if (T0 < src1)
+       env->psr |= PSR_CARRY;
+    if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
+       env->psr |= PSR_OVF;
+    env->y = (b2 << 31) | (env->y >> 1);
+    FORCE_RET();
+}
+
+void OPPROTO op_udiv_T1_T0(void)
+{
+    uint64_t x0;
+    uint32_t x1;
+
+    x0 = T0 | ((uint64_t) (env->y) << 32);
+    x1 = T1;
+    x0 = x0 / x1;
+    if (x0 > 0xffffffff) {
+       T0 = 0xffffffff;
+       T1 = 1;
+    } else {
+       T0 = x0;
+       T1 = 0;
+    }
+    FORCE_RET();
 }
 
-void OPPROTO op_set_flags (void)
+void OPPROTO op_sdiv_T1_T0(void)
 {
-       env->psr = 0;
-       if (!T0) env->psr |= PSR_ZERO;
-       if ((unsigned int) T0 < (unsigned int) T1) env->psr |= PSR_CARRY;
-       if ((int) T0 < (int) T1) env->psr |= PSR_OVF;
-       if ((int) T0 < 0) env->psr |= PSR_NEG;
+    int64_t x0;
+    int32_t x1;
+
+    x0 = T0 | ((uint64_t) (env->y) << 32);
+    x1 = T1;
+    x0 = x0 / x1;
+    if ((int32_t) x0 != x0) {
+       T0 = x0 >> 63;
+       T1 = 1;
+    } else {
+       T0 = x0;
+       T1 = 0;
+    }
+    FORCE_RET();
 }
 
-void OPPROTO op_sll (void)
+void OPPROTO op_div_cc(void)
 {
-       T0 <<= T1;
+    env->psr = 0;
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((int) T0 < 0)
+       env->psr |= PSR_NEG;
+    if (T1)
+       env->psr |= PSR_OVF;
+    FORCE_RET();
 }
 
-void OPPROTO op_srl (void)
+void OPPROTO op_subx_T1_T0(void)
 {
-       T0 >>= T1;
+    T0 -= T1 + ((env->psr & PSR_CARRY) ? 1 : 0);
 }
 
-void OPPROTO op_sra (void)
+void OPPROTO op_logic_T0_cc(void)
 {
-       int x = T0 >> T1;
-       T0 = x;
+    env->psr = 0;
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((int) T0 < 0)
+       env->psr |= PSR_NEG;
+    FORCE_RET();
 }
 
-void OPPROTO op_s(void)
+void OPPROTO op_set_flags(void)
 {
-       stl ((void *) T0, T1);
+    env->psr = 0;
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((unsigned int) T0 < (unsigned int) T1)
+       env->psr |= PSR_CARRY;
+    if ((int) T0 < (int) T1)
+       env->psr |= PSR_OVF;
+    if ((int) T0 < 0)
+       env->psr |= PSR_NEG;
+    FORCE_RET();
 }
 
-void OPPROTO op_stb (void)
+void OPPROTO op_sll(void)
 {
-       stb ((void *) T0, T1);
+    T0 <<= T1;
 }
 
-void OPPROTO op_sth (void)
+void OPPROTO op_srl(void)
 {
-       stw ((void *) T0, T1);
+    T0 >>= T1;
 }
 
-void OPPROTO op_ld (void)
+void OPPROTO op_sra(void)
 {
-       T1 = ldl ((void *) T0);
+    T0 = ((int32_t) T0) >> T1;
 }
 
-void OPPROTO op_ldub (void)
+void OPPROTO op_st(void)
 {
-       T1 = ldub ((void *) T0);
+    stl((void *) T0, T1);
 }
 
-void OPPROTO op_lduh (void)
+void OPPROTO op_stb(void)
 {
-       T1 = lduw ((void *) T0);
+    stb((void *) T0, T1);
 }
 
-void OPPROTO op_ldsb (void)
+void OPPROTO op_sth(void)
 {
-       T1 = ldsb ((void *) T0);
+    stw((void *) T0, T1);
 }
 
-void OPPROTO op_ldsh (void)
+void OPPROTO op_std(void)
 {
-       T1 = ldsw ((void *) T0);
+    stl((void *) T0, T1);
+    stl((void *) (T0 + 4), T2);
 }
 
-void OPPROTO op_ldstub (void)
+void OPPROTO op_ld(void)
 {
-       T1 = ldub ((void *) T0);
-       stb ((void *) T0, 0xff); /* XXX: Should be Atomically */
+    T1 = ldl((void *) T0);
 }
 
-void OPPROTO op_swap (void)
+void OPPROTO op_ldub(void)
 {
-       unsigned int tmp = ldl ((void *) T0);
-       stl ((void *) T0, T1);   /* XXX: Should be Atomically */
-       T1 = tmp;
+    T1 = ldub((void *) T0);
 }
 
-void OPPROTO op_ld(void)
+void OPPROTO op_lduh(void)
 {
-       T1 = ldl ((void *) T0);
-       T0 = ldl ((void *) T0+4);
+    T1 = lduw((void *) T0);
 }
 
-void OPPROTO op_wry (void)
+void OPPROTO op_ldsb(void)
 {
-       env->y = T0^T1;
+    T1 = ldsb((void *) T0);
 }
 
-void OPPROTO op_rdy (void)
+void OPPROTO op_ldsh(void)
 {
-       T0 = env->y;
+    T1 = ldsw((void *) T0);
 }
 
-#define regwptr (env->regwptr)
+void OPPROTO op_ldstub(void)
+{
+    T1 = ldub((void *) T0);
+    stb((void *) T0, 0xff);    /* XXX: Should be Atomically */
+}
 
-void OPPROTO op_save (void)
+void OPPROTO op_swap(void)
 {
-       regwptr -= 16;
+    unsigned int tmp = ldl((void *) T0);
+    stl((void *) T0, T1);      /* XXX: Should be Atomically */
+    T1 = tmp;
 }
 
-void OPPROTO op_restore (void)
+void OPPROTO op_ldd(void)
 {
-       regwptr += 16;
+    T1 = ldl((void *) T0);
+    T0 = ldl((void *) (T0 + 4));
 }
 
-void OPPROTO op_trap (void)
+void OPPROTO op_wry(void)
 {
-       env->exception_index = PARAM1;
-       cpu_loop_exit ();
+    env->y = T0;
 }
 
-void OPPROTO op_exit_tb (void)
+void OPPROTO op_rdy(void)
 {
-       EXIT_TB ();
+    T0 = env->y;
 }
 
-void OPPROTO op_eval_be (void)
+void raise_exception(int tt)
+{
+    env->exception_index = tt;
+    cpu_loop_exit();
+}   
+
+void memcpy32(uint32_t *dst, const uint32_t *src)
 {
-       T0 = (env->psr & PSR_ZERO);
+    dst[0] = src[0];
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst[3] = src[3];
+    dst[4] = src[4];
+    dst[5] = src[5];
+    dst[6] = src[6];
+    dst[7] = src[7];
 }
 
-#define FLAG_SET(x) (env->psr&x)?1:0
-#define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY)
+static inline 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);
+}
 
-void OPPROTO op_eval_ble (void)
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+   handling ? */
+void OPPROTO op_save(void)
 {
-       GET_FLAGS;
-       T0 = Z | (N^V);
+    int cwp;
+    cwp = (env->cwp - 1) & (NWINDOWS - 1); 
+    if (env->wim & (1 << cwp)) {
+        raise_exception(TT_WIN_OVF);
+    }
+    set_cwp(cwp);
+    FORCE_RET();
 }
 
-void OPPROTO op_eval_bl (void)
+void OPPROTO op_restore(void)
 {
-       GET_FLAGS;
-       T0 = N^V;
+    int cwp;
+    cwp = (env->cwp + 1) & (NWINDOWS - 1); 
+    if (env->wim & (1 << cwp)) {
+        raise_exception(TT_WIN_UNF);
+    }
+    set_cwp(cwp);
+    FORCE_RET();
 }
 
-void OPPROTO op_eval_bleu (void)
+void OPPROTO op_exception(void)
 {
-       GET_FLAGS;
-       T0 = C|Z;
+    env->exception_index = PARAM1;
+    cpu_loop_exit();
 }
 
-void OPPROTO op_eval_bcs (void)
+void OPPROTO op_trap_T0(void)
 {
-       T0 = (env->psr & PSR_CARRY);
+    env->exception_index = TT_TRAP + (T0 & 0x7f);
+    cpu_loop_exit();
 }
 
-void OPPROTO op_eval_bvs (void)
+void OPPROTO op_trapcc_T0(void)
 {
-       T0 = (env->psr & PSR_OVF);
+    if (T2) {
+        env->exception_index = TT_TRAP + (T0 & 0x7f);
+        cpu_loop_exit();
+    }
+    FORCE_RET();
 }
 
-void OPPROTO op_eval_bneg (void)
+void OPPROTO op_exit_tb(void)
 {
-       T0 = (env->psr & PSR_NEG);
+    EXIT_TB();
 }
 
-void OPPROTO op_eval_bne (void)
+void OPPROTO op_eval_be(void)
 {
-       T0 = !(env->psr & PSR_ZERO);
+    T2 = (env->psr & PSR_ZERO);
 }
 
-void OPPROTO op_eval_b(void)
+void OPPROTO op_eval_ble(void)
 {
-       GET_FLAGS;
-       T0 = !(Z | (N^V));
+    GET_FLAGS;
+    T2 = Z | (N ^ V);
 }
 
-/*XXX: This seems to be documented wrong in the SPARC V8 Manual
-  The manual states: !(N^V)
-  but I assume Z | !(N^V) to be correct */
-void OPPROTO op_eval_bge (void)
+void OPPROTO op_eval_bl(void)
 {
-       GET_FLAGS;
-       T0 = Z | !(N^V);
+    GET_FLAGS;
+    T2 = N ^ V;
 }
 
-void OPPROTO op_eval_bgu (void)
+void OPPROTO op_eval_bleu(void)
 {
-       GET_FLAGS;
-       T0 = !(C | Z);
+    GET_FLAGS;
+    T2 = C | Z;
 }
 
-void OPPROTO op_eval_bc(void)
+void OPPROTO op_eval_bcs(void)
 {
-       T0 = !(env->psr & PSR_CARRY);
+    T2 = (env->psr & PSR_CARRY);
 }
 
-void OPPROTO op_eval_bpos (void)
+void OPPROTO op_eval_bvs(void)
 {
-       T0 = !(env->psr & PSR_NEG);
+    T2 = (env->psr & PSR_OVF);
 }
 
-void OPPROTO op_eval_bvc (void)
+void OPPROTO op_eval_bneg(void)
 {
-       T0 = !(env->psr & PSR_OVF);
+    T2 = (env->psr & PSR_NEG);
 }
 
-void OPPROTO op_jmp_im (void)
+void OPPROTO op_eval_bne(void)
 {
-       env->pc = PARAM1;
+    T2 = !(env->psr & PSR_ZERO);
 }
 
-void OPPROTO op_call (void)
+void OPPROTO op_eval_bg(void)
 {
-       regwptr[7] = PARAM1-4;
-       env->pc = PARAM1+PARAM2;
+    GET_FLAGS;
+    T2 = !(Z | (N ^ V));
 }
 
-void OPPROTO op_jmpl (void)
+void OPPROTO op_eval_bge(void)
 {
-       env->npc = T0;
+    GET_FLAGS;
+    T2 = !(N ^ V);
 }
 
-void OPPROTO op_generic_jmp_1 (void)
+void OPPROTO op_eval_bgu(void)
 {
-       T1 = PARAM1;
-       env->pc = PARAM1+PARAM2;
+    GET_FLAGS;
+    T2 = !(C | Z);
 }
 
-void OPPROTO op_generic_jmp_2 (void)
+void OPPROTO op_eval_bcc(void)
 {
-       T1 = PARAM1;
-       env->pc = env->npc;
+    T2 = !(env->psr & PSR_CARRY);
 }
 
-unsigned long old_T0;
+void OPPROTO op_eval_bpos(void)
+{
+    T2 = !(env->psr & PSR_NEG);
+}
+
+void OPPROTO op_eval_bvc(void)
+{
+    T2 = !(env->psr & PSR_OVF);
+}
+
+void OPPROTO op_movl_T2_0(void)
+{
+    T2 = 0;
+}
+
+void OPPROTO op_movl_T2_1(void)
+{
+    T2 = 1;
+}
+
+void OPPROTO op_jmp_im(void)
+{
+    env->pc = PARAM1;
+}
+
+void OPPROTO op_movl_npc_im(void)
+{
+    env->npc = PARAM1;
+}
 
-void OPPROTO op_save_T0 (void)
+void OPPROTO op_movl_npc_T0(void)
 {
-       old_T0 = T0;
+    env->npc = T0;
 }
 
-void OPPROTO op_restore_T0 (void)
+void OPPROTO op_next_insn(void)
 {
-       T0 = old_T0;
+    env->pc = env->npc;
+    env->npc = env->npc + 4;
 }
 
-void OPPROTO op_generic_branch (void)
+void OPPROTO op_generic_branch(void)
 {
-       if (T0)
-               JUMP_TB (op_generic_branch, PARAM1, 0, PARAM2);
-       else
-               JUMP_TB (op_generic_branch, PARAM1, 1, PARAM3);
-       FORCE_RET ();
+    if (T2) {
+       env->npc = PARAM1;
+    } else {
+       env->npc = PARAM2;
+    }
+    FORCE_RET();
 }
 
-void OPPROTO op_generic_branch_a (void)
+void OPPROTO op_generic_branch_a(void)
 {
-       if (T0)
-               env->npc = PARAM3;
-       else
-               JUMP_TB (op_generic_branch_a, PARAM1, 0, PARAM2);
-       FORCE_RET ();
+    if (T2) {
+       env->pc = PARAM2;
+       env->npc = PARAM1;
+    } else {
+       env->pc = PARAM2 + 4;
+       env->npc = PARAM2 + 8;
+    }
+    FORCE_RET();
 }
index d302c3decc07b52404ea0d54e0c23a61f95091b7..a5c1dbe6f35b08cfe48f980bfb45ae17d7bdbf8a 100644 (file)
    and the 'anull' bit in the branch instruction opcode is set. This is
    currently solved by doing a jump after the delay slot instruction.
 
-   There is also one big (currently unsolved) bug in the branch code:
-   If a delay slot modifies the condition codes then the new condition
-   codes, instead of the old ones will be used.
-
    TODO-list:
 
+   Register window overflow/underflow check
    FPU-Instructions
    Coprocessor-Instructions
-   Fix above bug
    Check signedness issues
    Privileged instructions
-   Register window overflow/underflow check
    Optimize synthetic instructions
    Optional alignment and privileged instruction check
 
 #define DEBUG_DISAS
 
 typedef struct DisasContext {
-       uint8_t *pc;
-       uint8_t *npc;
-       void (*branch) (struct DisasContext *, uint32_t, uint32_t);
-       unsigned int delay_slot:2;
-       uint32_t insn;
-       uint32_t target;
-       int      is_br;
-       struct TranslationBlock *tb;
+    uint8_t *pc;               /* NULL means dynamic value */
+    uint8_t *npc;              /* NULL means dynamic value */
+    int is_br;
+    struct TranslationBlock *tb;
 } DisasContext;
 
 static uint16_t *gen_opc_ptr;
@@ -84,7 +75,7 @@ enum {
 #define DEF(s,n,copy_size) INDEX_op_ ## s,
 #include "opc.h"
 #undef DEF
-       NB_OPS
+    NB_OPS
 };
 
 #include "gen-op.h"
@@ -94,651 +85,781 @@ enum {
 
 #define IS_IMM (insn & (1<<13))
 
-static void disas_sparc_insn (DisasContext *dc);
+static void disas_sparc_insn(DisasContext * dc);
 
-typedef void (GenOpFunc)(void);
-typedef void (GenOpFunc1)(long);
-typedef void (GenOpFunc2)(long, long);
-typedef void (GenOpFunc3)(long, long, long);
+typedef void (GenOpFunc) (void);
+typedef void (GenOpFunc1) (long);
+typedef void (GenOpFunc2) (long, long);
+typedef void (GenOpFunc3) (long, long, long);
 
 static GenOpFunc *gen_op_movl_TN_reg[2][32] = {
-       {
-               gen_op_movl_g0_T0,
-               gen_op_movl_g1_T0,
-               gen_op_movl_g2_T0,
-               gen_op_movl_g3_T0,
-               gen_op_movl_g4_T0,
-               gen_op_movl_g5_T0,
-               gen_op_movl_g6_T0,
-               gen_op_movl_g7_T0,
-               gen_op_movl_o0_T0,
-               gen_op_movl_o1_T0,
-               gen_op_movl_o2_T0,
-               gen_op_movl_o3_T0,
-               gen_op_movl_o4_T0,
-               gen_op_movl_o5_T0,
-               gen_op_movl_o6_T0,
-               gen_op_movl_o7_T0,
-               gen_op_movl_l0_T0,
-               gen_op_movl_l1_T0,
-               gen_op_movl_l2_T0,
-               gen_op_movl_l3_T0,
-               gen_op_movl_l4_T0,
-               gen_op_movl_l5_T0,
-               gen_op_movl_l6_T0,
-               gen_op_movl_l7_T0,
-               gen_op_movl_i0_T0,
-               gen_op_movl_i1_T0,
-               gen_op_movl_i2_T0,
-               gen_op_movl_i3_T0,
-               gen_op_movl_i4_T0,
-               gen_op_movl_i5_T0,
-               gen_op_movl_i6_T0,
-               gen_op_movl_i7_T0,
-       },
-       {
-               gen_op_movl_g0_T1,
-               gen_op_movl_g1_T1,
-               gen_op_movl_g2_T1,
-               gen_op_movl_g3_T1,
-               gen_op_movl_g4_T1,
-               gen_op_movl_g5_T1,
-               gen_op_movl_g6_T1,
-               gen_op_movl_g7_T1,
-               gen_op_movl_o0_T1,
-               gen_op_movl_o1_T1,
-               gen_op_movl_o2_T1,
-               gen_op_movl_o3_T1,
-               gen_op_movl_o4_T1,
-               gen_op_movl_o5_T1,
-               gen_op_movl_o6_T1,
-               gen_op_movl_o7_T1,
-               gen_op_movl_l0_T1,
-               gen_op_movl_l1_T1,
-               gen_op_movl_l2_T1,
-               gen_op_movl_l3_T1,
-               gen_op_movl_l4_T1,
-               gen_op_movl_l5_T1,
-               gen_op_movl_l6_T1,
-               gen_op_movl_l7_T1,
-               gen_op_movl_i0_T1,
-               gen_op_movl_i1_T1,
-               gen_op_movl_i2_T1,
-               gen_op_movl_i3_T1,
-               gen_op_movl_i4_T1,
-               gen_op_movl_i5_T1,
-               gen_op_movl_i6_T1,
-               gen_op_movl_i7_T1,
-       }
+    {
+     gen_op_movl_g0_T0,
+     gen_op_movl_g1_T0,
+     gen_op_movl_g2_T0,
+     gen_op_movl_g3_T0,
+     gen_op_movl_g4_T0,
+     gen_op_movl_g5_T0,
+     gen_op_movl_g6_T0,
+     gen_op_movl_g7_T0,
+     gen_op_movl_o0_T0,
+     gen_op_movl_o1_T0,
+     gen_op_movl_o2_T0,
+     gen_op_movl_o3_T0,
+     gen_op_movl_o4_T0,
+     gen_op_movl_o5_T0,
+     gen_op_movl_o6_T0,
+     gen_op_movl_o7_T0,
+     gen_op_movl_l0_T0,
+     gen_op_movl_l1_T0,
+     gen_op_movl_l2_T0,
+     gen_op_movl_l3_T0,
+     gen_op_movl_l4_T0,
+     gen_op_movl_l5_T0,
+     gen_op_movl_l6_T0,
+     gen_op_movl_l7_T0,
+     gen_op_movl_i0_T0,
+     gen_op_movl_i1_T0,
+     gen_op_movl_i2_T0,
+     gen_op_movl_i3_T0,
+     gen_op_movl_i4_T0,
+     gen_op_movl_i5_T0,
+     gen_op_movl_i6_T0,
+     gen_op_movl_i7_T0,
+     },
+    {
+     gen_op_movl_g0_T1,
+     gen_op_movl_g1_T1,
+     gen_op_movl_g2_T1,
+     gen_op_movl_g3_T1,
+     gen_op_movl_g4_T1,
+     gen_op_movl_g5_T1,
+     gen_op_movl_g6_T1,
+     gen_op_movl_g7_T1,
+     gen_op_movl_o0_T1,
+     gen_op_movl_o1_T1,
+     gen_op_movl_o2_T1,
+     gen_op_movl_o3_T1,
+     gen_op_movl_o4_T1,
+     gen_op_movl_o5_T1,
+     gen_op_movl_o6_T1,
+     gen_op_movl_o7_T1,
+     gen_op_movl_l0_T1,
+     gen_op_movl_l1_T1,
+     gen_op_movl_l2_T1,
+     gen_op_movl_l3_T1,
+     gen_op_movl_l4_T1,
+     gen_op_movl_l5_T1,
+     gen_op_movl_l6_T1,
+     gen_op_movl_l7_T1,
+     gen_op_movl_i0_T1,
+     gen_op_movl_i1_T1,
+     gen_op_movl_i2_T1,
+     gen_op_movl_i3_T1,
+     gen_op_movl_i4_T1,
+     gen_op_movl_i5_T1,
+     gen_op_movl_i6_T1,
+     gen_op_movl_i7_T1,
+     }
 };
 
 static GenOpFunc *gen_op_movl_reg_TN[3][32] = {
-       {
-               gen_op_movl_T0_g0,
-               gen_op_movl_T0_g1,
-               gen_op_movl_T0_g2,
-               gen_op_movl_T0_g3,
-               gen_op_movl_T0_g4,
-               gen_op_movl_T0_g5,
-               gen_op_movl_T0_g6,
-               gen_op_movl_T0_g7,
-               gen_op_movl_T0_o0,
-               gen_op_movl_T0_o1,
-               gen_op_movl_T0_o2,
-               gen_op_movl_T0_o3,
-               gen_op_movl_T0_o4,
-               gen_op_movl_T0_o5,
-               gen_op_movl_T0_o6,
-               gen_op_movl_T0_o7,
-               gen_op_movl_T0_l0,
-               gen_op_movl_T0_l1,
-               gen_op_movl_T0_l2,
-               gen_op_movl_T0_l3,
-               gen_op_movl_T0_l4,
-               gen_op_movl_T0_l5,
-               gen_op_movl_T0_l6,
-               gen_op_movl_T0_l7,
-               gen_op_movl_T0_i0,
-               gen_op_movl_T0_i1,
-               gen_op_movl_T0_i2,
-               gen_op_movl_T0_i3,
-               gen_op_movl_T0_i4,
-               gen_op_movl_T0_i5,
-               gen_op_movl_T0_i6,
-               gen_op_movl_T0_i7,
-       },
-       {
-               gen_op_movl_T1_g0,
-               gen_op_movl_T1_g1,
-               gen_op_movl_T1_g2,
-               gen_op_movl_T1_g3,
-               gen_op_movl_T1_g4,
-               gen_op_movl_T1_g5,
-               gen_op_movl_T1_g6,
-               gen_op_movl_T1_g7,
-               gen_op_movl_T1_o0,
-               gen_op_movl_T1_o1,
-               gen_op_movl_T1_o2,
-               gen_op_movl_T1_o3,
-               gen_op_movl_T1_o4,
-               gen_op_movl_T1_o5,
-               gen_op_movl_T1_o6,
-               gen_op_movl_T1_o7,
-               gen_op_movl_T1_l0,
-               gen_op_movl_T1_l1,
-               gen_op_movl_T1_l2,
-               gen_op_movl_T1_l3,
-               gen_op_movl_T1_l4,
-               gen_op_movl_T1_l5,
-               gen_op_movl_T1_l6,
-               gen_op_movl_T1_l7,
-               gen_op_movl_T1_i0,
-               gen_op_movl_T1_i1,
-               gen_op_movl_T1_i2,
-               gen_op_movl_T1_i3,
-               gen_op_movl_T1_i4,
-               gen_op_movl_T1_i5,
-               gen_op_movl_T1_i6,
-               gen_op_movl_T1_i7,
-       },
-       {
-               gen_op_movl_T2_g0,
-               gen_op_movl_T2_g1,
-               gen_op_movl_T2_g2,
-               gen_op_movl_T2_g3,
-               gen_op_movl_T2_g4,
-               gen_op_movl_T2_g5,
-               gen_op_movl_T2_g6,
-               gen_op_movl_T2_g7,
-               gen_op_movl_T2_o0,
-               gen_op_movl_T2_o1,
-               gen_op_movl_T2_o2,
-               gen_op_movl_T2_o3,
-               gen_op_movl_T2_o4,
-               gen_op_movl_T2_o5,
-               gen_op_movl_T2_o6,
-               gen_op_movl_T2_o7,
-               gen_op_movl_T2_l0,
-               gen_op_movl_T2_l1,
-               gen_op_movl_T2_l2,
-               gen_op_movl_T2_l3,
-               gen_op_movl_T2_l4,
-               gen_op_movl_T2_l5,
-               gen_op_movl_T2_l6,
-               gen_op_movl_T2_l7,
-               gen_op_movl_T2_i0,
-               gen_op_movl_T2_i1,
-               gen_op_movl_T2_i2,
-               gen_op_movl_T2_i3,
-               gen_op_movl_T2_i4,
-               gen_op_movl_T2_i5,
-               gen_op_movl_T2_i6,
-               gen_op_movl_T2_i7,
-       }
+    {
+     gen_op_movl_T0_g0,
+     gen_op_movl_T0_g1,
+     gen_op_movl_T0_g2,
+     gen_op_movl_T0_g3,
+     gen_op_movl_T0_g4,
+     gen_op_movl_T0_g5,
+     gen_op_movl_T0_g6,
+     gen_op_movl_T0_g7,
+     gen_op_movl_T0_o0,
+     gen_op_movl_T0_o1,
+     gen_op_movl_T0_o2,
+     gen_op_movl_T0_o3,
+     gen_op_movl_T0_o4,
+     gen_op_movl_T0_o5,
+     gen_op_movl_T0_o6,
+     gen_op_movl_T0_o7,
+     gen_op_movl_T0_l0,
+     gen_op_movl_T0_l1,
+     gen_op_movl_T0_l2,
+     gen_op_movl_T0_l3,
+     gen_op_movl_T0_l4,
+     gen_op_movl_T0_l5,
+     gen_op_movl_T0_l6,
+     gen_op_movl_T0_l7,
+     gen_op_movl_T0_i0,
+     gen_op_movl_T0_i1,
+     gen_op_movl_T0_i2,
+     gen_op_movl_T0_i3,
+     gen_op_movl_T0_i4,
+     gen_op_movl_T0_i5,
+     gen_op_movl_T0_i6,
+     gen_op_movl_T0_i7,
+     },
+    {
+     gen_op_movl_T1_g0,
+     gen_op_movl_T1_g1,
+     gen_op_movl_T1_g2,
+     gen_op_movl_T1_g3,
+     gen_op_movl_T1_g4,
+     gen_op_movl_T1_g5,
+     gen_op_movl_T1_g6,
+     gen_op_movl_T1_g7,
+     gen_op_movl_T1_o0,
+     gen_op_movl_T1_o1,
+     gen_op_movl_T1_o2,
+     gen_op_movl_T1_o3,
+     gen_op_movl_T1_o4,
+     gen_op_movl_T1_o5,
+     gen_op_movl_T1_o6,
+     gen_op_movl_T1_o7,
+     gen_op_movl_T1_l0,
+     gen_op_movl_T1_l1,
+     gen_op_movl_T1_l2,
+     gen_op_movl_T1_l3,
+     gen_op_movl_T1_l4,
+     gen_op_movl_T1_l5,
+     gen_op_movl_T1_l6,
+     gen_op_movl_T1_l7,
+     gen_op_movl_T1_i0,
+     gen_op_movl_T1_i1,
+     gen_op_movl_T1_i2,
+     gen_op_movl_T1_i3,
+     gen_op_movl_T1_i4,
+     gen_op_movl_T1_i5,
+     gen_op_movl_T1_i6,
+     gen_op_movl_T1_i7,
+     },
+    {
+     gen_op_movl_T2_g0,
+     gen_op_movl_T2_g1,
+     gen_op_movl_T2_g2,
+     gen_op_movl_T2_g3,
+     gen_op_movl_T2_g4,
+     gen_op_movl_T2_g5,
+     gen_op_movl_T2_g6,
+     gen_op_movl_T2_g7,
+     gen_op_movl_T2_o0,
+     gen_op_movl_T2_o1,
+     gen_op_movl_T2_o2,
+     gen_op_movl_T2_o3,
+     gen_op_movl_T2_o4,
+     gen_op_movl_T2_o5,
+     gen_op_movl_T2_o6,
+     gen_op_movl_T2_o7,
+     gen_op_movl_T2_l0,
+     gen_op_movl_T2_l1,
+     gen_op_movl_T2_l2,
+     gen_op_movl_T2_l3,
+     gen_op_movl_T2_l4,
+     gen_op_movl_T2_l5,
+     gen_op_movl_T2_l6,
+     gen_op_movl_T2_l7,
+     gen_op_movl_T2_i0,
+     gen_op_movl_T2_i1,
+     gen_op_movl_T2_i2,
+     gen_op_movl_T2_i3,
+     gen_op_movl_T2_i4,
+     gen_op_movl_T2_i5,
+     gen_op_movl_T2_i6,
+     gen_op_movl_T2_i7,
+     }
 };
 
 static GenOpFunc1 *gen_op_movl_TN_im[3] = {
-       gen_op_movl_T0_im,
-       gen_op_movl_T1_im,
-       gen_op_movl_T2_im
+    gen_op_movl_T0_im,
+    gen_op_movl_T1_im,
+    gen_op_movl_T2_im
 };
 
-static inline void gen_movl_imm_TN (int reg, int imm)
+static inline void gen_movl_imm_TN(int reg, int imm)
 {
-       gen_op_movl_TN_im[reg](imm);
+    gen_op_movl_TN_im[reg] (imm);
 }
 
-static inline void gen_movl_imm_T1 (int val)
+static inline void gen_movl_imm_T1(int val)
 {
-       gen_movl_imm_TN (1, val);
+    gen_movl_imm_TN(1, val);
 }
 
-static inline void gen_movl_imm_T0 (int val)
+static inline void gen_movl_imm_T0(int val)
 {
-       gen_movl_imm_TN (0, val);
+    gen_movl_imm_TN(0, val);
 }
 
-static inline void gen_movl_reg_TN (int reg, int t)
+static inline void gen_movl_reg_TN(int reg, int t)
 {
-       if (reg) gen_op_movl_reg_TN[t][reg]();
-       else gen_movl_imm_TN (t, 0);
+    if (reg)
+       gen_op_movl_reg_TN[t][reg] ();
+    else
+       gen_movl_imm_TN(t, 0);
 }
 
-static inline void gen_movl_reg_T0 (int reg)
+static inline void gen_movl_reg_T0(int reg)
 {
-       gen_movl_reg_TN (reg, 0);
+    gen_movl_reg_TN(reg, 0);
 }
 
-static inline void gen_movl_reg_T1 (int reg)
+static inline void gen_movl_reg_T1(int reg)
 {
-       gen_movl_reg_TN (reg, 1);
+    gen_movl_reg_TN(reg, 1);
 }
 
-static inline void gen_movl_reg_T2 (int reg)
+static inline void gen_movl_reg_T2(int reg)
 {
-       gen_movl_reg_TN (reg, 2);
+    gen_movl_reg_TN(reg, 2);
 }
 
-static inline void gen_movl_TN_reg (int reg, int t)
+static inline void gen_movl_TN_reg(int reg, int t)
 {
-       if (reg) gen_op_movl_TN_reg[t][reg]();
+    if (reg)
+       gen_op_movl_TN_reg[t][reg] ();
 }
 
-static inline void gen_movl_T0_reg (int reg)
+static inline void gen_movl_T0_reg(int reg)
 {
-       gen_movl_TN_reg (reg, 0);
+    gen_movl_TN_reg(reg, 0);
 }
 
-static inline void gen_movl_T1_reg (int reg)
+static inline void gen_movl_T1_reg(int reg)
 {
-       gen_movl_TN_reg (reg, 1);
+    gen_movl_TN_reg(reg, 1);
 }
 
-static void do_branch (DisasContext *dc, uint32_t target, uint32_t insn)
+static void gen_cond(int cond)
 {
-       unsigned int cond = GET_FIELD (insn, 3, 6), a = (insn & (1<<29)), ib = 0;
-       target += (uint32_t) dc->pc-4;
-       if (!a) disas_sparc_insn (dc);
        switch (cond) {
-         case 0x0: gen_op_movl_T0_0 (); break;
-         case 0x1: gen_op_eval_be (); break;
-         case 0x2: gen_op_eval_ble (); break;
-         case 0x3: gen_op_eval_bl (); break;
-         case 0x4: gen_op_eval_bleu (); break;
-         case 0x5: gen_op_eval_bcs (); break;
-         case 0x6: gen_op_eval_bneg (); break;
-         case 0x7: gen_op_eval_bvs (); break;
-         case 0x8: gen_op_movl_T0_1 (); break;
-         case 0x9: gen_op_eval_bne (); break;
-         case 0xa: gen_op_eval_bg (); break;
-         case 0xb: gen_op_eval_bge (); break;
-         case 0xc: gen_op_eval_bgu (); break;
-         case 0xd: gen_op_eval_bcc (); break;
-         case 0xe: gen_op_eval_bpos (); break;
-         case 0xf: gen_op_eval_bvc (); break;
-       }
-       if (a && ((cond|0x8) != 0x8)) {
-               gen_op_generic_branch_a ((uint32_t) dc->tb,
-                               (uint32_t) dc->pc+4, target);
-               disas_sparc_insn (dc);
-               ib = 1;
+        case 0x0:
+            gen_op_movl_T2_0();
+            break;
+       case 0x1:
+           gen_op_eval_be();
+           break;
+       case 0x2:
+           gen_op_eval_ble();
+           break;
+       case 0x3:
+           gen_op_eval_bl();
+           break;
+       case 0x4:
+           gen_op_eval_bleu();
+           break;
+       case 0x5:
+           gen_op_eval_bcs();
+           break;
+       case 0x6:
+           gen_op_eval_bneg();
+           break;
+       case 0x7:
+           gen_op_eval_bvs();
+           break;
+        case 0x8:
+            gen_op_movl_T2_1();
+            break;
+       case 0x9:
+           gen_op_eval_bne();
+           break;
+       case 0xa:
+           gen_op_eval_bg();
+           break;
+       case 0xb:
+           gen_op_eval_bge();
+           break;
+       case 0xc:
+           gen_op_eval_bgu();
+           break;
+       case 0xd:
+           gen_op_eval_bcc();
+           break;
+       case 0xe:
+           gen_op_eval_bpos();
+           break;
+        default:
+       case 0xf:
+           gen_op_eval_bvc();
+           break;
        }
-       else
-       if (cond && !a) {
-               gen_op_generic_branch ((uint32_t) dc->tb, (uint32_t) target,
-                       (uint32_t) dc->pc);
-               ib = 1;
-       }
-       if (ib) dc->is_br = DISAS_JUMP;
 }
 
-/* target == 0x1 means CALL- else JMPL-instruction */
-static void do_jump (DisasContext *dc, uint32_t target, uint32_t rd)
+
+static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn)
 {
-       uint32_t orig_pc = (uint32_t) dc->pc-8;
-       if (target != 0x1)
-        gen_op_generic_jmp_1 (orig_pc, target);
-       else
-        gen_op_generic_jmp_2 (orig_pc);
-       gen_movl_T1_reg (rd);
-       dc->is_br = DISAS_JUMP;
-       gen_op_movl_T0_0 ();
+    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 = (uint8_t *) target;
+           dc->npc = dc->pc + 4;
+       } else {
+           dc->pc = dc->npc;
+           dc->npc = (uint8_t *) target;
+       }
+    } else {
+        gen_cond(cond);
+       if (a) {
+           gen_op_generic_branch_a((uint32_t) target,
+                                   (uint32_t) (dc->npc));
+            dc->is_br = 1;
+            dc->pc = NULL;
+            dc->npc = NULL;
+       } else {
+            dc->pc = dc->npc;
+           gen_op_generic_branch((uint32_t) target,
+                                 (uint32_t) (dc->npc + 4));
+            dc->npc = NULL;
+       }
+    }
 }
 
-#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), b-a)
+#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)
 
-static int
-sign_extend (x, len)
-       int x, len;
+static int sign_extend(int x, int len)
 {
-       int signbit = (1 << (len - 1));
-       int mask = (signbit << 1) - 1;
-       return ((x & mask) ^ signbit) - signbit;
+    len = 32 - len;
+    return (x << len) >> len;
 }
 
-static void disas_sparc_insn (DisasContext *dc)
+static inline void save_state(DisasContext * dc)
 {
-       unsigned int insn, opc, rs1, rs2, rd;
+    gen_op_jmp_im((uint32_t)dc->pc);
+    if (dc->npc != NULL)
+        gen_op_movl_npc_im((long) dc->npc);
+}
 
-       if (dc->delay_slot == 1) {
-               insn = dc->insn;
-       } else {
-               if (dc->delay_slot) dc->delay_slot--;
-               insn = htonl (*(unsigned int *) (dc->pc));
-               dc->pc += 4;
-       }
+static void disas_sparc_insn(DisasContext * dc)
+{
+    unsigned int insn, opc, rs1, rs2, rd;
 
-       opc = GET_FIELD (insn, 0, 1);
+    insn = ldl_code(dc->pc);
+    opc = GET_FIELD(insn, 0, 1);
 
-       rd  = GET_FIELD (insn, 2, 6);
-       switch (opc) {
-         case 0: /* branches/sethi */
-               {
-                       unsigned int xop = GET_FIELD (insn, 7, 9);
-                       int target;
-                       target = GET_FIELD (insn, 10, 31);
-                       switch (xop) {
-                        case 0x0: case 0x1: /* UNIMPL */
-                               printf ("UNIMPLEMENTED: %p\n", dc->pc-4);
-                               exit (23);
-                               break;
-                        case 0x2: /* BN+x */
-                       {
-                               target <<= 2;
-                               target = sign_extend (target, 22);
-                               do_branch (dc, target, insn);
-                               break;
-                       }
-                        case 0x3: /* FBN+x */
-                               break;
-                        case 0x4: /* SETHI */
-                               gen_movl_imm_T0 (target<<10);
-                               gen_movl_T0_reg (rd);
-                               break;
-                        case 0x5: /*CBN+x*/
-                               break;
-                       }
-                       break;
-               }
-         case 1: /*CALL*/
+    rd = GET_FIELD(insn, 2, 6);
+    switch (opc) {
+    case 0:                    /* branches/sethi */
+       {
+           unsigned int xop = GET_FIELD(insn, 7, 9);
+           int target;
+           target = GET_FIELD(insn, 10, 31);
+           switch (xop) {
+           case 0x0:
+           case 0x1:           /* UNIMPL */
+                goto illegal_insn;
+           case 0x2:           /* BN+x */
                {
-                       unsigned int target = GET_FIELDs (insn, 2, 31) << 2;
-                       if (dc->delay_slot) {
-                               do_jump (dc, target, 15);
-                               dc->delay_slot = 0;
-                       } else {
-                               dc->insn = insn;
-                               dc->delay_slot = 2;
-                       }
-                       break;
+                   target <<= 2;
+                   target = sign_extend(target, 22);
+                   do_branch(dc, target, insn);
+                   goto jmp_insn;
                }
-         case 2: /* FPU & Logical Operations */
-               {
-                       unsigned int xop = GET_FIELD (insn, 7, 12);
-                       if (xop == 58) { /* generate trap */
-                               dc->is_br = DISAS_JUMP;
-                               gen_op_jmp_im ((uint32_t) dc->pc);
-                               if (IS_IMM) gen_op_trap (GET_FIELD (insn, 25, 31));
-                               /* else XXX*/
-                               gen_op_movl_T0_0 ();
-                               break;
-                       }
-                       if (xop == 0x34 || xop == 0x35) { /* FPU Operations */
-                               exit (33);
-                       }
-                       rs1 = GET_FIELD (insn, 13, 17);
-                       gen_movl_reg_T0 (rs1);
-                       if (IS_IMM) { /* immediate */
-                               rs2 = GET_FIELDs (insn, 20, 31);
-                               gen_movl_imm_T1 (rs2);
-                       } else {              /* register */
-                               rs2 = GET_FIELD (insn, 27, 31);
-                               gen_movl_reg_T1 (rs2);
-                       }
-                       if (xop < 0x20) {
-                        switch (xop &~ 0x10) {
-                         case 0x0:
-                               gen_op_add_T1_T0 ();
-                               break;
-                         case 0x1:
-                               gen_op_and_T1_T0 ();
-                               break;
-                         case 0x2:
-                               gen_op_or_T1_T0 ();
-                               break;
-                         case 0x3:
-                               gen_op_xor_T1_T0 ();
-                               break;
-                         case 0x4:
-                               gen_op_sub_T1_T0 ();
-                               break;
-                         case 0x5:
-                               gen_op_andn_T1_T0 ();
-                               break;
-                         case 0x6:
-                               gen_op_orn_T1_T0 ();
-                               break;
-                         case 0x7:
-                               gen_op_xnor_T1_T0 ();
-                               break;
-                         case 0x8:
-                               gen_op_addx_T1_T0 ();
-                               break;
-                         case 0xa:
-                               gen_op_umul_T1_T0 ();
-                               break;
-                         case 0xb:
-                               gen_op_smul_T1_T0 ();
-                               break;
-                         case 0xc:
-                               gen_op_subx_T1_T0 ();
-                               break;
-                         case 0xe:
-                               gen_op_udiv_T1_T0 ();
-                               break;
-                         case 0xf:
-                               gen_op_sdiv_T1_T0 ();
-                               break;
-                         default:
-                               exit (17);
-                               break;
-                        }
-                        gen_movl_T0_reg (rd);
-                        if (xop & 0x10) {
-                               gen_op_set_flags ();
-                        }
-                       } else {
-                         switch (xop) {
-                               case 0x25: /* SLL */
-                                       gen_op_sll ();
-                                       break;
-                               case 0x26:
-                                       gen_op_srl ();
-                                       break;
-                               case 0x27:
-                                       gen_op_sra ();
-                                       break;
-                               case 0x28: case 0x30:
-                               {
-                                       unsigned int rdi = GET_FIELD (insn, 13, 17);
-                                       if (!rdi) (xop==0x28?gen_op_rdy ():gen_op_wry());
-                                       /* else gen_op_su_trap (); */
-                                       break;
-                               }
-                               /* Problem with jmpl: if restore is executed in the delay
-                                  slot, then the wrong registers are beeing used */
-                               case 0x38: /* jmpl */
-                               {
-                                       if (dc->delay_slot) {
-                                               gen_op_add_T1_T0 ();
-                                               do_jump (dc, 1, rd);
-                                               dc->delay_slot = 0;
-                                       } else {
-                                               gen_op_add_T1_T0 ();
-                                               gen_op_jmpl ();
-                                               dc->insn = insn;
-                                               dc->delay_slot = 2;
-                                       }
-                                       break;
-                               }
-                               case 0x3c: /* save */
-                                       gen_op_add_T1_T0 ();
-                                       gen_op_save ();
-                                       gen_movl_T0_reg (rd);
-                                       break;
-                               case 0x3d: /* restore */
-                                       gen_op_add_T1_T0 ();
-                                       gen_op_restore ();
-                                       gen_movl_T0_reg (rd);
-                                       break;
-                         }
-                       }
-                       break;
+           case 0x3:           /* FBN+x */
+               break;
+           case 0x4:           /* SETHI */
+               gen_movl_imm_T0(target << 10);
+               gen_movl_T0_reg(rd);
+               break;
+           case 0x5:           /*CBN+x */
+               break;
+           }
+           break;
+       }
+    case 1:
+       /*CALL*/ {
+           unsigned int target = GET_FIELDs(insn, 2, 31) << 2;
+
+           gen_op_movl_T0_im((long) (dc->pc));
+           gen_movl_T0_reg(15);
+           target = (long) dc->pc + target;
+           dc->pc = dc->npc;
+           dc->npc = (uint8_t *) target;
+       }
+       goto jmp_insn;
+    case 2:                    /* FPU & Logical Operations */
+       {
+           unsigned int xop = GET_FIELD(insn, 7, 12);
+           if (xop == 0x3a) {  /* generate trap */
+                int cond;
+                rs1 = GET_FIELD(insn, 13, 17);
+                gen_movl_reg_T0(rs1);
+               if (IS_IMM) {
+                    gen_movl_imm_T1(GET_FIELD(insn, 25, 31));
+                } else {
+                    rs2 = GET_FIELD(insn, 27, 31);
+                    gen_movl_reg_T1(rs2);
+                }
+                gen_op_add_T1_T0();
+                save_state(dc);
+                cond = GET_FIELD(insn, 3, 6);
+                if (cond == 0x8) {
+                    gen_op_trap_T0();
+                    dc->is_br = 1;
+                    goto jmp_insn;
+                } else {
+                    gen_op_trapcc_T0();
+                }
+            } else if (xop == 0x28) {
+                rs1 = GET_FIELD(insn, 13, 17);
+                switch(rs1) {
+                case 0: /* rdy */
+                    gen_op_rdy();
+                    gen_movl_T0_reg(rd);
+                    break;
+                default:
+                    goto illegal_insn;
+                }
+           } else if (xop == 0x34 || xop == 0x35) {    /* FPU Operations */
+                goto illegal_insn;
+           } else {
+                rs1 = GET_FIELD(insn, 13, 17);
+                gen_movl_reg_T0(rs1);
+                if (IS_IMM) {  /* immediate */
+                    rs2 = GET_FIELDs(insn, 19, 31);
+                    gen_movl_imm_T1(rs2);
+                } else {               /* register */
+                    rs2 = GET_FIELD(insn, 27, 31);
+                    gen_movl_reg_T1(rs2);
+                }
+                if (xop < 0x20) {
+                    switch (xop & ~0x10) {
+                    case 0x0:
+                        if (xop & 0x10)
+                            gen_op_add_T1_T0_cc();
+                        else
+                            gen_op_add_T1_T0();
+                        break;
+                    case 0x1:
+                        gen_op_and_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_logic_T0_cc();
+                        break;
+                    case 0x2:
+                        gen_op_or_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_logic_T0_cc();
+                        break;
+                    case 0x3:
+                        gen_op_xor_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_logic_T0_cc();
+                        break;
+                    case 0x4:
+                        if (xop & 0x10)
+                            gen_op_sub_T1_T0_cc();
+                        else
+                            gen_op_sub_T1_T0();
+                        break;
+                    case 0x5:
+                        gen_op_andn_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_logic_T0_cc();
+                        break;
+                    case 0x6:
+                        gen_op_orn_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_logic_T0_cc();
+                        break;
+                    case 0x7:
+                        gen_op_xnor_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_logic_T0_cc();
+                        break;
+                    case 0x8:
+                        gen_op_addx_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_set_flags();
+                        break;
+                    case 0xa:
+                        gen_op_umul_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_logic_T0_cc();
+                        break;
+                    case 0xb:
+                        gen_op_smul_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_logic_T0_cc();
+                        break;
+                    case 0xc:
+                        gen_op_subx_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_set_flags();
+                        break;
+                    case 0xe:
+                        gen_op_udiv_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_div_cc();
+                        break;
+                    case 0xf:
+                        gen_op_sdiv_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_div_cc();
+                        break;
+                    default:
+                        goto illegal_insn;
+                    }
+                    gen_movl_T0_reg(rd);
+                } else {
+                    switch (xop) {
+                    case 0x24: /* mulscc */
+                        gen_op_mulscc_T1_T0();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    case 0x25: /* SLL */
+                        gen_op_sll();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    case 0x26:
+                        gen_op_srl();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    case 0x27:
+                        gen_op_sra();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    case 0x30:
+                        {
+                            gen_op_xor_T1_T0();
+                            switch(rd) {
+                            case 0:
+                                gen_op_wry();
+                                break;
+                            default:
+                                goto illegal_insn;
+                            }
+                        }
+                        break;
+                    case 0x38: /* jmpl */
+                        {
+                            gen_op_add_T1_T0();
+                            gen_op_movl_npc_T0();
+                            if (rd != 0) {
+                                gen_op_movl_T0_im((long) (dc->pc));
+                                gen_movl_T0_reg(rd);
+                            }
+                            dc->pc = dc->npc;
+                            dc->npc = NULL;
+                        }
+                        goto jmp_insn;
+                    case 0x3b: /* flush */
+                        /* nothing to do */
+                        break;
+                    case 0x3c: /* save */
+                        save_state(dc);
+                        gen_op_add_T1_T0();
+                        gen_op_save();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    case 0x3d: /* restore */
+                        save_state(dc);
+                        gen_op_add_T1_T0();
+                        gen_op_restore();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    default:
+                        goto illegal_insn;
+                    }
+                }
+            }
+           break;
+       }
+    case 3:                    /* load/store instructions */
+       {
+           unsigned int xop = GET_FIELD(insn, 7, 12);
+           rs1 = GET_FIELD(insn, 13, 17);
+           gen_movl_reg_T0(rs1);
+           if (IS_IMM) {       /* immediate */
+               rs2 = GET_FIELDs(insn, 19, 31);
+               gen_movl_imm_T1(rs2);
+           } else {            /* register */
+               rs2 = GET_FIELD(insn, 27, 31);
+               gen_movl_reg_T1(rs2);
+           }
+           gen_op_add_T1_T0();
+           if (xop < 4 || xop > 7) {
+               switch (xop) {
+               case 0x0:       /* load word */
+                   gen_op_ld();
+                   break;
+               case 0x1:       /* load unsigned byte */
+                   gen_op_ldub();
+                   break;
+               case 0x2:       /* load unsigned halfword */
+                   gen_op_lduh();
+                   break;
+               case 0x3:       /* load double word */
+                   gen_op_ldd();
+                   gen_movl_T0_reg(rd + 1);
+                   break;
+               case 0x9:       /* load signed byte */
+                   gen_op_ldsb();
+                   break;
+               case 0xa:       /* load signed halfword */
+                   gen_op_ldsh();
+                   break;
+               case 0xd:       /* ldstub -- XXX: should be atomically */
+                   gen_op_ldstub();
+                   break;
+               case 0x0f:      /* swap register with memory. Also atomically */
+                   gen_op_swap();
+                   break;
                }
-         case 3: /* load/store instructions */
-               {
-                       unsigned int xop = GET_FIELD (insn, 7, 12);
-                       rs1 = GET_FIELD (insn, 13, 17);
-                       gen_movl_reg_T0 (rs1);
-                       if (IS_IMM) { /* immediate */
-                               rs2 = GET_FIELDs (insn, 20, 31);
-                               gen_movl_imm_T1 (rs2);
-                       } else {              /* register */
-                               rs2 = GET_FIELD (insn, 27, 31);
-                               gen_movl_reg_T1 (rs2);
-                       }
-                       gen_op_add_T1_T0 ();
-                       if (xop < 4 || xop > 7)  {
-                        switch (xop) {
-                         case 0x0: /* load word */
-                               gen_op_ld ();
-                               break;
-                         case 0x1: /* load unsigned byte */
-                               gen_op_ldub ();
-                               break;
-                         case 0x2: /* load unsigned halfword */
-                               gen_op_lduh ();
-                               break;
-                         case 0x3: /* load double word */
-                               gen_op_ldd ();
-                               gen_movl_T0_reg (rd+1);
-                               break;
-                         case 0x9: /* load signed byte */
-                               gen_op_ldsb ();
-                               break;
-                         case 0xa: /* load signed halfword */
-                               gen_op_ldsh ();
-                               break;
-                         case 0xd: /* ldstub -- XXX: should be atomically */
-                               gen_op_ldstub ();
-                               break;
-                         case 0x0f: /* swap register with memory. Also atomically */
-                               gen_op_swap ();
-                               break;
-                        }
-                        gen_movl_T1_reg (rd);
-                       } else if (xop < 8) {
-                        gen_movl_reg_T1 (rd);
-                        switch (xop) {
-                         case 0x4:
-                               gen_op_st ();
-                               break;
-                         case 0x5:
-                               gen_op_stb ();
-                               break;
-                         case 0x6:
-                               gen_op_sth ();
-                               break;
-                         case 0x7:
-                               gen_op_st ();
-                               gen_movl_reg_T1 (rd+1);
-                               gen_op_st ();
-                               break;
-                        }
-                       }
+               gen_movl_T1_reg(rd);
+           } else if (xop < 8) {
+               gen_movl_reg_T1(rd);
+               switch (xop) {
+               case 0x4:
+                   gen_op_st();
+                   break;
+               case 0x5:
+                   gen_op_stb();
+                   break;
+               case 0x6:
+                   gen_op_sth();
+                   break;
+               case 0x7:
+                   gen_movl_reg_T2(rd + 1);
+                   gen_op_std();
+                   break;
                }
+           }
        }
+    }
+    /* default case for non jump instructions */
+    if (dc->npc != NULL) {
+       dc->pc = dc->npc;
+       dc->npc = dc->npc + 4;
+    } else {
+       dc->pc = NULL;
+       gen_op_next_insn();
+    }
+  jmp_insn:;
+    return;
+ illegal_insn:
+    gen_op_jmp_im((uint32_t)dc->pc);
+    if (dc->npc != NULL)
+        gen_op_movl_npc_im((long) dc->npc);
+    gen_op_exception(TT_ILL_INSN);
+    dc->is_br = 1;
 }
 
-static inline int gen_intermediate_code_internal (TranslationBlock *tb, int spc)
+static inline int gen_intermediate_code_internal(TranslationBlock * tb,
+                                                int spc)
 {
-       uint8_t *pc_start = (uint8_t *) tb->pc;
-       uint16_t *gen_opc_end;
-       DisasContext dc;
-
-       memset (&dc, 0, sizeof (dc));
-       if (spc) {
-               printf ("SearchPC not yet supported\n");
-               exit (0);
-       }
-       dc.tb = tb;
-       dc.pc = pc_start;
-
-       gen_opc_ptr = gen_opc_buf;
-       gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
-       gen_opparam_ptr = gen_opparam_buf;
-
-       do {
-               disas_sparc_insn (&dc);
-       } while (!dc.is_br && (gen_opc_ptr < gen_opc_end) &&
-               (dc.pc - pc_start) < (TARGET_PAGE_SIZE - 32));
-
-       switch (dc.is_br) {
-         case DISAS_JUMP:
-         case DISAS_TB_JUMP:
-               gen_op_exit_tb ();
-               break;
-       }
-
-       *gen_opc_ptr = INDEX_op_end;
+    uint8_t *pc_start, *last_pc;
+    uint16_t *gen_opc_end;
+    DisasContext dc1, *dc = &dc1;
+
+    memset(dc, 0, sizeof(DisasContext));
+    if (spc) {
+       printf("SearchPC not yet supported\n");
+       exit(0);
+    }
+    dc->tb = tb;
+    pc_start = (uint8_t *) tb->pc;
+    dc->pc = pc_start;
+    dc->npc = (uint8_t *) tb->cs_base;
+
+    gen_opc_ptr = gen_opc_buf;
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    gen_opparam_ptr = gen_opparam_buf;
+
+    do {
+       last_pc = dc->pc;
+       disas_sparc_insn(dc);
+       if (dc->is_br)
+           break;
+       /* if the next PC is different, we abort now */
+       if (dc->pc != (last_pc + 4))
+           break;
+    } while ((gen_opc_ptr < gen_opc_end) &&
+            (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
+    if (dc->pc != NULL)
+       gen_op_jmp_im((long) dc->pc);
+    if (dc->npc != NULL)
+       gen_op_movl_npc_im((long) dc->npc);
+    gen_op_movl_T0_0();
+    gen_op_exit_tb();
+
+    *gen_opc_ptr = INDEX_op_end;
 #ifdef DEBUG_DISAS
-       if (loglevel) {
-               fprintf (logfile, "--------------\n");
-               fprintf (logfile, "IN: %s\n", lookup_symbol (pc_start));
-               disas(logfile, pc_start, dc.pc - pc_start, 0, 0);
-               fprintf(logfile, "\n");
-               fprintf(logfile, "OP:\n");
-               dump_ops(gen_opc_buf, gen_opparam_buf);
-               fprintf(logfile, "\n");
-       }
+    if (loglevel) {
+       fprintf(logfile, "--------------\n");
+       fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
+       disas(logfile, pc_start, last_pc + 4 - pc_start, 0, 0);
+       fprintf(logfile, "\n");
+       fprintf(logfile, "OP:\n");
+       dump_ops(gen_opc_buf, gen_opparam_buf);
+       fprintf(logfile, "\n");
+    }
 #endif
 
-       return 0;
+    return 0;
 }
 
-int gen_intermediate_code (CPUSPARCState *env, TranslationBlock *tb)
+int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
 {
-       return gen_intermediate_code_internal(tb, 0);
+    return gen_intermediate_code_internal(tb, 0);
 }
 
-int gen_intermediate_code_pc (CPUSPARCState *env, TranslationBlock *tb)
+int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
 {
-       return gen_intermediate_code_internal(tb, 1);
+    return gen_intermediate_code_internal(tb, 1);
 }
 
-void *mycpu;
-
-CPUSPARCState *cpu_sparc_init (void)
+CPUSPARCState *cpu_sparc_init(void)
 {
-       CPUSPARCState *env;
-
-       cpu_exec_init ();
-
-       if (!(env = malloc (sizeof(CPUSPARCState))))
-               return (NULL);
-       memset (env, 0, sizeof (*env));
-       if (!(env->regwptr = malloc (0x2000)))
-               return (NULL);
-       memset (env->regwptr, 0, 0x2000);
-       env->regwptr += 127;
-       env->user_mode_only = 1;
-       mycpu = env;
-       return (env);
+    CPUSPARCState *env;
+
+    cpu_exec_init();
+
+    if (!(env = malloc(sizeof(CPUSPARCState))))
+       return (NULL);
+    memset(env, 0, sizeof(*env));
+    env->cwp = 0;
+    env->wim = 1;
+    env->regwptr = env->regbase + (env->cwp * 16);
+    env->user_mode_only = 1;
+    return (env);
 }
 
 #define GET_FLAG(a,b) ((env->psr & a)?b:'-')
 
-void cpu_sparc_dump_state (CPUSPARCState *env, FILE *f, int flags)
+void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags)
 {
-       int i, x;
-
-       fprintf (f, "@PC: %p\n", (void *) env->pc);
-       fprintf (f, "General Registers:\n");
-       for (i=0;i<4;i++)
-               fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]);
-       fprintf (f, "\n");
-       for (;i<8;i++)
-               fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]);
-       fprintf (f, "\nCurrent Register Window:\n");
-       for (x=0;x<3;x++) {
-         for (i=0;i<4;i++)
-               fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':(x==1?'l':'i')), i, env->regwptr[i+x*8]);
-         fprintf (f, "\n");
-         for (;i<8;i++)
-               fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':x==1?'l':'i'), i, env->regwptr[i+x*8]);
-         fprintf (f, "\n");
-       }
-       fprintf (f, "PSR: %x -> %c%c%c%c\n", env->psr,
-                       GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
-                       GET_FLAG(PSR_NEG, 'N'),  GET_FLAG(PSR_CARRY, 'C'));
+    int i, x;
+
+    fprintf(f, "pc: 0x%08x  npc: 0x%08x\n", (int) env->pc, (int) env->npc);
+    fprintf(f, "General Registers:\n");
+    for (i = 0; i < 4; i++)
+       fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]);
+    fprintf(f, "\n");
+    for (; i < 8; i++)
+       fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]);
+    fprintf(f, "\nCurrent Register Window:\n");
+    for (x = 0; x < 3; x++) {
+       for (i = 0; i < 4; i++)
+           fprintf(f, "%%%c%d: 0x%08x\t",
+                   (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i,
+                   env->regwptr[i + x * 8]);
+       fprintf(f, "\n");
+       for (; i < 8; i++)
+           fprintf(f, "%%%c%d: 0x%08x\t",
+                   (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i,
+                   env->regwptr[i + x * 8]);
+       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);
 }