]> git.proxmox.com Git - qemu.git/blobdiff - target-microblaze/translate.c
slirp: Replace m_freem with m_free
[qemu.git] / target-microblaze / translate.c
index b180d24b0e1a590a551132be412198e03d28e39e..31e8306ef30cf7b972b0ea3fd8d414d2a6dcee4d 100644 (file)
@@ -25,7 +25,6 @@
 #include <assert.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 #include "helper.h"
@@ -63,8 +62,7 @@ static TCGv env_iflags;
 /* This is the state at translation time.  */
 typedef struct DisasContext {
     CPUState *env;
-    target_ulong pc, ppc;
-    target_ulong cache_pc;
+    target_ulong pc;
 
     /* Decoder.  */
     int type_b;
@@ -79,9 +77,10 @@ typedef struct DisasContext {
     unsigned int clear_imm;
     int is_jmp;
 
-#define JMP_NOJMP    0
-#define JMP_DIRECT   1
-#define JMP_INDIRECT 2
+#define JMP_NOJMP     0
+#define JMP_DIRECT    1
+#define JMP_DIRECT_CC 2
+#define JMP_INDIRECT  3
     unsigned int jmp;
     uint32_t jmp_pc;
 
@@ -91,7 +90,7 @@ typedef struct DisasContext {
     int singlestep_enabled;
 } DisasContext;
 
-const static char *regnames[] =
+static const char *regnames[] =
 {
     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
     "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
@@ -99,7 +98,7 @@ const static char *regnames[] =
     "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
 };
 
-const static char *special_regnames[] =
+static const char *special_regnames[] =
 {
     "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7",
     "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
@@ -146,13 +145,38 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
     if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
         tcg_gen_goto_tb(n);
         tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
-        tcg_gen_exit_tb((long)tb + n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
     } else {
         tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
         tcg_gen_exit_tb(0);
     }
 }
 
+static void read_carry(DisasContext *dc, TCGv d)
+{
+    tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
+}
+
+static void write_carry(DisasContext *dc, TCGv v)
+{
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_shli_tl(t0, v, 31);
+    tcg_gen_sari_tl(t0, t0, 31);
+    tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC));
+    tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR],
+                    ~(MSR_C | MSR_CC));
+    tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0);
+    tcg_temp_free(t0);
+}
+
+/* True if ALU operand b is a small immediate that may deserve
+   faster treatment.  */
+static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
+{
+    /* Immediate insn without the imm prefix ?  */
+    return dc->type_b && !(dc->tb_flags & IMM_FLAG);
+}
+
 static inline TCGv *dec_alu_op_b(DisasContext *dc)
 {
     if (dc->type_b) {
@@ -168,6 +192,7 @@ static inline TCGv *dec_alu_op_b(DisasContext *dc)
 static void dec_add(DisasContext *dc)
 {
     unsigned int k, c;
+    TCGv cf;
 
     k = dc->opcode & 4;
     c = dc->opcode & 2;
@@ -176,22 +201,52 @@ static void dec_add(DisasContext *dc)
             dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "",
             dc->rd, dc->ra, dc->rb);
 
-    if (k && !c && dc->rd)
+    /* Take care of the easy cases first.  */
+    if (k) {
+        /* k - keep carry, no need to update MSR.  */
+        /* If rd == r0, it's a nop.  */
+        if (dc->rd) {
+            tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+
+            if (c) {
+                /* c - Add carry into the result.  */
+                cf = tcg_temp_new();
+
+                read_carry(dc, cf);
+                tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+                tcg_temp_free(cf);
+            }
+        }
+        return;
+    }
+
+    /* From now on, we can assume k is zero.  So we need to update MSR.  */
+    /* Extract carry.  */
+    cf = tcg_temp_new();
+    if (c) {
+        read_carry(dc, cf);
+    } else {
+        tcg_gen_movi_tl(cf, 0);
+    }
+
+    if (dc->rd) {
+        TCGv ncf = tcg_temp_new();
+        gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
         tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
-    else if (dc->rd)
-        gen_helper_addkc(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)),
-                         tcg_const_tl(k), tcg_const_tl(c));
-    else {
-        TCGv d = tcg_temp_new();
-        gen_helper_addkc(d, cpu_R[dc->ra], *(dec_alu_op_b(dc)),
-                         tcg_const_tl(k), tcg_const_tl(c));
-        tcg_temp_free(d);
+        tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+        write_carry(dc, ncf);
+        tcg_temp_free(ncf);
+    } else {
+        gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
+        write_carry(dc, cf);
     }
+    tcg_temp_free(cf);
 }
 
 static void dec_sub(DisasContext *dc)
 {
     unsigned int u, cmp, k, c;
+    TCGv cf, na;
 
     u = dc->imm & 2;
     k = dc->opcode & 4;
@@ -206,24 +261,57 @@ static void dec_sub(DisasContext *dc)
             else
                 gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
         }
-    } else {
-        LOG_DIS("sub%s%s r%d, r%d r%d\n",
-                 k ? "k" : "",  c ? "c" : "", dc->rd, dc->ra, dc->rb);
+        return;
+    }
 
-        if (!k || c) {
-            TCGv t;
-            t = tcg_temp_new();
-            if (dc->rd)
-                gen_helper_subkc(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)),
-                                 tcg_const_tl(k), tcg_const_tl(c));
-            else
-                gen_helper_subkc(t, cpu_R[dc->ra], *(dec_alu_op_b(dc)),
-                                 tcg_const_tl(k), tcg_const_tl(c));
-            tcg_temp_free(t);
-        }
-        else if (dc->rd)
+    LOG_DIS("sub%s%s r%d, r%d r%d\n",
+             k ? "k" : "",  c ? "c" : "", dc->rd, dc->ra, dc->rb);
+
+    /* Take care of the easy cases first.  */
+    if (k) {
+        /* k - keep carry, no need to update MSR.  */
+        /* If rd == r0, it's a nop.  */
+        if (dc->rd) {
             tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+
+            if (c) {
+                /* c - Add carry into the result.  */
+                cf = tcg_temp_new();
+
+                read_carry(dc, cf);
+                tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+                tcg_temp_free(cf);
+            }
+        }
+        return;
     }
+
+    /* From now on, we can assume k is zero.  So we need to update MSR.  */
+    /* Extract carry. And complement a into na.  */
+    cf = tcg_temp_new();
+    na = tcg_temp_new();
+    if (c) {
+        read_carry(dc, cf);
+    } else {
+        tcg_gen_movi_tl(cf, 1);
+    }
+
+    /* d = b + ~a + c. carry defaults to 1.  */
+    tcg_gen_not_tl(na, cpu_R[dc->ra]);
+
+    if (dc->rd) {
+        TCGv ncf = tcg_temp_new();
+        gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf);
+        tcg_gen_add_tl(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
+        tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+        write_carry(dc, ncf);
+        tcg_temp_free(ncf);
+    } else {
+        gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf);
+        write_carry(dc, cf);
+    }
+    tcg_temp_free(cf);
+    tcg_temp_free(na);
 }
 
 static void dec_pattern(DisasContext *dc)
@@ -232,7 +320,7 @@ static void dec_pattern(DisasContext *dc)
     int l1;
 
     if ((dc->tb_flags & MSR_EE_FLAG)
-          && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
           && !((dc->env->pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
@@ -329,25 +417,6 @@ static void dec_xor(DisasContext *dc)
         tcg_gen_xor_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
 }
 
-static void read_carry(DisasContext *dc, TCGv d)
-{
-    tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
-}
-
-static void write_carry(DisasContext *dc, TCGv v)
-{
-    TCGv t0 = tcg_temp_new();
-    tcg_gen_shli_tl(t0, v, 31);
-    tcg_gen_sari_tl(t0, t0, 31);
-    tcg_gen_mov_tl(env_debug, t0);
-    tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC));
-    tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR],
-                    ~(MSR_C | MSR_CC));
-    tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0);
-    tcg_temp_free(t0);
-}
-
-
 static inline void msr_read(DisasContext *dc, TCGv d)
 {
     tcg_gen_mov_tl(d, cpu_SR[SR_MSR]);
@@ -450,7 +519,7 @@ static void dec_msr(DisasContext *dc)
                 tcg_gen_mov_tl(cpu_SR[SR_ESR], cpu_R[dc->ra]);
                 break;
             case 0x7:
-                /* Ignored at the moment.  */
+                tcg_gen_andi_tl(cpu_SR[SR_FSR], cpu_R[dc->ra], 31);
                 break;
             default:
                 cpu_abort(dc->env, "unknown mts reg %x\n", sr);
@@ -473,7 +542,7 @@ static void dec_msr(DisasContext *dc)
                 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_ESR]);
                 break;
              case 0x7:
-                tcg_gen_movi_tl(cpu_R[dc->rd], 0);
+                tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_FSR]);
                 break;
             case 0xb:
                 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_BTR]);
@@ -553,7 +622,7 @@ static void dec_mul(DisasContext *dc)
     unsigned int subcode;
 
     if ((dc->tb_flags & MSR_EE_FLAG)
-         && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+         && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
          && !(dc->env->pvr.regs[0] & PVR0_USE_HW_MUL_MASK)) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
@@ -610,7 +679,7 @@ static void dec_div(DisasContext *dc)
     u = dc->imm & 2; 
     LOG_DIS("div\n");
 
-    if (!(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+    if ((dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
           && !((dc->env->pvr.regs[0] & PVR0_USE_DIV_MASK))) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
@@ -630,7 +699,7 @@ static void dec_barrel(DisasContext *dc)
     unsigned int s, t;
 
     if ((dc->tb_flags & MSR_EE_FLAG)
-          && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
           && !(dc->env->pvr.regs[0] & PVR0_USE_BARREL_MASK)) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
@@ -713,6 +782,9 @@ static void dec_bit(DisasContext *dc)
             tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
             break;
         case 0x64:
+        case 0x66:
+        case 0x74:
+        case 0x76:
             /* wdc.  */
             LOG_DIS("wdc r%d\n", dc->ra);
             if ((dc->tb_flags & MSR_EE_FLAG)
@@ -741,10 +813,12 @@ static void dec_bit(DisasContext *dc)
 
 static inline void sync_jmpstate(DisasContext *dc)
 {
-    if (dc->jmp == JMP_DIRECT) {
-            dc->jmp = JMP_INDIRECT;
+    if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
+        if (dc->jmp == JMP_DIRECT) {
             tcg_gen_movi_tl(env_btaken, 1);
-            tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
+        }
+        dc->jmp = JMP_INDIRECT;
+        tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
     }
 }
 
@@ -775,8 +849,15 @@ static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
 {
     unsigned int extimm = dc->tb_flags & IMM_FLAG;
 
-    /* Treat the fast cases first.  */
+    /* Treat the common cases first.  */
     if (!dc->type_b) {
+        /* If any of the regs is r0, return a ptr to the other.  */
+        if (dc->ra == 0) {
+            return &cpu_R[dc->rb];
+        } else if (dc->rb == 0) {
+            return &cpu_R[dc->ra];
+        }
+
         *t = tcg_temp_new();
         tcg_gen_add_tl(*t, cpu_R[dc->ra], cpu_R[dc->rb]);
         return t;
@@ -797,30 +878,134 @@ static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
     return t;
 }
 
+static inline void dec_byteswap(DisasContext *dc, TCGv dst, TCGv src, int size)
+{
+    if (size == 4) {
+        tcg_gen_bswap32_tl(dst, src);
+    } else if (size == 2) {
+        TCGv t = tcg_temp_new();
+
+        /* bswap16 assumes the high bits are zero.  */
+        tcg_gen_andi_tl(t, src, 0xffff);
+        tcg_gen_bswap16_tl(dst, t);
+        tcg_temp_free(t);
+    } else {
+        /* Ignore.
+        cpu_abort(dc->env, "Invalid ldst byteswap size %d\n", size);
+        */
+    }
+}
+
 static void dec_load(DisasContext *dc)
 {
     TCGv t, *addr;
-    unsigned int size;
+    unsigned int size, rev = 0;
 
     size = 1 << (dc->opcode & 3);
 
-    LOG_DIS("l %x %d\n", dc->opcode, size);
+    if (!dc->type_b) {
+        rev = (dc->ir >> 9) & 1;
+    }
+
+    if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    LOG_DIS("l%d%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "");
+
     t_sync_flags(dc);
     addr = compute_ldst_addr(dc, &t);
 
+    /*
+     * When doing reverse accesses we need to do two things.
+     *
+     * 1. Reverse the address wrt endianness.
+     * 2. Byteswap the data lanes on the way back into the CPU core.
+     */
+    if (rev && size != 4) {
+        /* Endian reverse the address. t is addr.  */
+        switch (size) {
+            case 1:
+            {
+                /* 00 -> 11
+                   01 -> 10
+                   10 -> 10
+                   11 -> 00 */
+                TCGv low = tcg_temp_new();
+
+                /* Force addr into the temp.  */
+                if (addr != &t) {
+                    t = tcg_temp_new();
+                    tcg_gen_mov_tl(t, *addr);
+                    addr = &t;
+                }
+
+                tcg_gen_andi_tl(low, t, 3);
+                tcg_gen_sub_tl(low, tcg_const_tl(3), low);
+                tcg_gen_andi_tl(t, t, ~3);
+                tcg_gen_or_tl(t, t, low);
+                tcg_gen_mov_tl(env_imm, t);
+                tcg_temp_free(low);
+                break;
+            }
+
+            case 2:
+                /* 00 -> 10
+                   10 -> 00.  */
+                /* Force addr into the temp.  */
+                if (addr != &t) {
+                    t = tcg_temp_new();
+                    tcg_gen_xori_tl(t, *addr, 2);
+                    addr = &t;
+                } else {
+                    tcg_gen_xori_tl(t, t, 2);
+                }
+                break;
+            default:
+                cpu_abort(dc->env, "Invalid reverse size\n");
+                break;
+        }
+    }
+
     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
     sync_jmpstate(dc);
 
     /* Verify alignment if needed.  */
     if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
+        TCGv v = tcg_temp_new();
+
+        /*
+         * Microblaze gives MMU faults priority over faults due to
+         * unaligned addresses. That's why we speculatively do the load
+         * into v. If the load succeeds, we verify alignment of the
+         * address and if that succeeds we write into the destination reg.
+         */
+        gen_load(dc, v, *addr, size);
+
+        tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
         gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
                             tcg_const_tl(0), tcg_const_tl(size - 1));
-    }
-
-    if (dc->rd) {
-        gen_load(dc, cpu_R[dc->rd], *addr, size);
+        if (dc->rd) {
+            if (rev) {
+                dec_byteswap(dc, cpu_R[dc->rd], v, size);
+            } else {
+                tcg_gen_mov_tl(cpu_R[dc->rd], v);
+            }
+        }
+        tcg_temp_free(v);
     } else {
-        gen_load(dc, env_imm, *addr, size);
+        if (dc->rd) {
+            gen_load(dc, cpu_R[dc->rd], *addr, size);
+            if (rev) {
+                dec_byteswap(dc, cpu_R[dc->rd], cpu_R[dc->rd], size);
+            }
+        } else {
+            /* We are loading into r0, no need to reverse.  */
+            gen_load(dc, env_imm, *addr, size);
+        }
     }
 
     if (addr == &t)
@@ -845,23 +1030,102 @@ static void gen_store(DisasContext *dc, TCGv addr, TCGv val,
 static void dec_store(DisasContext *dc)
 {
     TCGv t, *addr;
-    unsigned int size;
+    unsigned int size, rev = 0;
 
     size = 1 << (dc->opcode & 3);
+    if (!dc->type_b) {
+        rev = (dc->ir >> 9) & 1;
+    }
 
-    LOG_DIS("s%d%s\n", size, dc->type_b ? "i" : "");
+    if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    LOG_DIS("s%d%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "");
     t_sync_flags(dc);
     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
     sync_jmpstate(dc);
     addr = compute_ldst_addr(dc, &t);
 
+    if (rev && size != 4) {
+        /* Endian reverse the address. t is addr.  */
+        switch (size) {
+            case 1:
+            {
+                /* 00 -> 11
+                   01 -> 10
+                   10 -> 10
+                   11 -> 00 */
+                TCGv low = tcg_temp_new();
+
+                /* Force addr into the temp.  */
+                if (addr != &t) {
+                    t = tcg_temp_new();
+                    tcg_gen_mov_tl(t, *addr);
+                    addr = &t;
+                }
+
+                tcg_gen_andi_tl(low, t, 3);
+                tcg_gen_sub_tl(low, tcg_const_tl(3), low);
+                tcg_gen_andi_tl(t, t, ~3);
+                tcg_gen_or_tl(t, t, low);
+                tcg_gen_mov_tl(env_imm, t);
+                tcg_temp_free(low);
+                break;
+            }
+
+            case 2:
+                /* 00 -> 10
+                   10 -> 00.  */
+                /* Force addr into the temp.  */
+                if (addr != &t) {
+                    t = tcg_temp_new();
+                    tcg_gen_xori_tl(t, *addr, 2);
+                    addr = &t;
+                } else {
+                    tcg_gen_xori_tl(t, t, 2);
+                }
+                break;
+            default:
+                cpu_abort(dc->env, "Invalid reverse size\n");
+                break;
+        }
+
+        if (size != 1) {
+            TCGv bs_data = tcg_temp_new();
+            dec_byteswap(dc, bs_data, cpu_R[dc->rd], size);
+            gen_store(dc, *addr, bs_data, size);
+            tcg_temp_free(bs_data);
+        } else {
+            gen_store(dc, *addr, cpu_R[dc->rd], size);
+        }
+    } else {
+        if (rev) {
+            TCGv bs_data = tcg_temp_new();
+            dec_byteswap(dc, bs_data, cpu_R[dc->rd], size);
+            gen_store(dc, *addr, bs_data, size);
+            tcg_temp_free(bs_data);
+        } else {
+            gen_store(dc, *addr, cpu_R[dc->rd], size);
+        }
+    }
+
     /* Verify alignment if needed.  */
     if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
+        tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+        /* FIXME: if the alignment is wrong, we should restore the value
+         *        in memory. One possible way to acheive this is to probe
+         *        the MMU prior to the memaccess, thay way we could put
+         *        the alignment checks in between the probe and the mem
+         *        access.
+         */
         gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
                             tcg_const_tl(1), tcg_const_tl(size - 1));
     }
 
-    gen_store(dc, *addr, cpu_R[dc->rd], size);
     if (addr == &t)
         tcg_temp_free(t);
 }
@@ -869,50 +1133,24 @@ static void dec_store(DisasContext *dc)
 static inline void eval_cc(DisasContext *dc, unsigned int cc,
                            TCGv d, TCGv a, TCGv b)
 {
-    int l1;
-
     switch (cc) {
         case CC_EQ:
-            l1 = gen_new_label();
-            tcg_gen_movi_tl(env_btaken, 1);
-            tcg_gen_brcond_tl(TCG_COND_EQ, a, b, l1);
-            tcg_gen_movi_tl(env_btaken, 0);
-            gen_set_label(l1);
+            tcg_gen_setcond_tl(TCG_COND_EQ, d, a, b);
             break;
         case CC_NE:
-            l1 = gen_new_label();
-            tcg_gen_movi_tl(env_btaken, 1);
-            tcg_gen_brcond_tl(TCG_COND_NE, a, b, l1);
-            tcg_gen_movi_tl(env_btaken, 0);
-            gen_set_label(l1);
+            tcg_gen_setcond_tl(TCG_COND_NE, d, a, b);
             break;
         case CC_LT:
-            l1 = gen_new_label();
-            tcg_gen_movi_tl(env_btaken, 1);
-            tcg_gen_brcond_tl(TCG_COND_LT, a, b, l1);
-            tcg_gen_movi_tl(env_btaken, 0);
-            gen_set_label(l1);
+            tcg_gen_setcond_tl(TCG_COND_LT, d, a, b);
             break;
         case CC_LE:
-            l1 = gen_new_label();
-            tcg_gen_movi_tl(env_btaken, 1);
-            tcg_gen_brcond_tl(TCG_COND_LE, a, b, l1);
-            tcg_gen_movi_tl(env_btaken, 0);
-            gen_set_label(l1);
+            tcg_gen_setcond_tl(TCG_COND_LE, d, a, b);
             break;
         case CC_GE:
-            l1 = gen_new_label();
-            tcg_gen_movi_tl(env_btaken, 1);
-            tcg_gen_brcond_tl(TCG_COND_GE, a, b, l1);
-            tcg_gen_movi_tl(env_btaken, 0);
-            gen_set_label(l1);
+            tcg_gen_setcond_tl(TCG_COND_GE, d, a, b);
             break;
         case CC_GT:
-            l1 = gen_new_label();
-            tcg_gen_movi_tl(env_btaken, 1);
-            tcg_gen_brcond_tl(TCG_COND_GT, a, b, l1);
-            tcg_gen_movi_tl(env_btaken, 0);
-            gen_set_label(l1);
+            tcg_gen_setcond_tl(TCG_COND_GT, d, a, b);
             break;
         default:
             cpu_abort(dc->env, "Unknown condition code %x.\n", cc);
@@ -949,15 +1187,24 @@ static void dec_bcc(DisasContext *dc)
                       cpu_env, offsetof(CPUState, bimm));
     }
 
-    tcg_gen_movi_tl(env_btarget, dc->pc);
-    tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
+    if (dec_alu_op_b_is_small_imm(dc)) {
+        int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend.  */
+
+        tcg_gen_movi_tl(env_btarget, dc->pc + offset);
+        dc->jmp = JMP_DIRECT_CC;
+        dc->jmp_pc = dc->pc + offset;
+    } else {
+        dc->jmp = JMP_INDIRECT;
+        tcg_gen_movi_tl(env_btarget, dc->pc);
+        tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
+    }
     eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0));
-    dc->jmp = JMP_INDIRECT;
 }
 
 static void dec_br(DisasContext *dc)
 {
     unsigned int dslot, link, abs;
+    int mem_index = cpu_mmu_index(dc->env);
 
     dslot = dc->ir & (1 << 20);
     abs = dc->ir & (1 << 19);
@@ -981,19 +1228,27 @@ static void dec_br(DisasContext *dc)
     if (abs) {
         tcg_gen_movi_tl(env_btaken, 1);
         tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc)));
-        if (link && !(dc->tb_flags & IMM_FLAG)
-            && (dc->imm == 8 || dc->imm == 0x18))
-            t_gen_raise_exception(dc, EXCP_BREAK);
-        if (dc->imm == 0)
-            t_gen_raise_exception(dc, EXCP_DEBUG);
+        if (link && !dslot) {
+            if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18))
+                t_gen_raise_exception(dc, EXCP_BREAK);
+            if (dc->imm == 0) {
+                if ((dc->tb_flags & MSR_EE_FLAG) && mem_index == MMU_USER_IDX) {
+                    tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+                    t_gen_raise_exception(dc, EXCP_HW_EXCP);
+                    return;
+                }
+
+                t_gen_raise_exception(dc, EXCP_DEBUG);
+            }
+        }
     } else {
-        if (dc->tb_flags & IMM_FLAG) {
+        if (dec_alu_op_b_is_small_imm(dc)) {
+            dc->jmp = JMP_DIRECT;
+            dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
+        } else {
             tcg_gen_movi_tl(env_btaken, 1);
             tcg_gen_movi_tl(env_btarget, dc->pc);
             tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
-        } else {
-            dc->jmp = JMP_DIRECT;
-            dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
         }
     }
 }
@@ -1092,30 +1347,170 @@ static void dec_rts(DisasContext *dc)
     } else
         LOG_DIS("rts ir=%x\n", dc->ir);
 
+    dc->jmp = JMP_INDIRECT;
     tcg_gen_movi_tl(env_btaken, 1);
     tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
 }
 
+static int dec_check_fpuv2(DisasContext *dc)
+{
+    int r;
+
+    r = dc->env->pvr.regs[2] & PVR2_USE_FPU2_MASK;
+
+    if (!r && (dc->tb_flags & MSR_EE_FLAG)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_FPU);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+    }
+    return r;
+}
+
 static void dec_fpu(DisasContext *dc)
 {
+    unsigned int fpu_insn;
+
     if ((dc->tb_flags & MSR_EE_FLAG)
-          && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
           && !((dc->env->pvr.regs[2] & PVR2_USE_FPU_MASK))) {
         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
         t_gen_raise_exception(dc, EXCP_HW_EXCP);
         return;
     }
 
-    qemu_log ("unimplemented FPU insn pc=%x opc=%x\n", dc->pc, dc->opcode);
-    dc->abort_at_next_insn = 1;
+    fpu_insn = (dc->ir >> 7) & 7;
+
+    switch (fpu_insn) {
+        case 0:
+            gen_helper_fadd(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+
+        case 1:
+            gen_helper_frsub(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+
+        case 2:
+            gen_helper_fmul(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+
+        case 3:
+            gen_helper_fdiv(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+
+        case 4:
+            switch ((dc->ir >> 4) & 7) {
+                case 0:
+                    gen_helper_fcmp_un(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 1:
+                    gen_helper_fcmp_lt(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 2:
+                    gen_helper_fcmp_eq(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 3:
+                    gen_helper_fcmp_le(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 4:
+                    gen_helper_fcmp_gt(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 5:
+                    gen_helper_fcmp_ne(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 6:
+                    gen_helper_fcmp_ge(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                default:
+                    qemu_log ("unimplemented fcmp fpu_insn=%x pc=%x opc=%x\n",
+                              fpu_insn, dc->pc, dc->opcode);
+                    dc->abort_at_next_insn = 1;
+                    break;
+            }
+            break;
+
+        case 5:
+            if (!dec_check_fpuv2(dc)) {
+                return;
+            }
+            gen_helper_flt(cpu_R[dc->rd], cpu_R[dc->ra]);
+            break;
+
+        case 6:
+            if (!dec_check_fpuv2(dc)) {
+                return;
+            }
+            gen_helper_fint(cpu_R[dc->rd], cpu_R[dc->ra]);
+            break;
+
+        case 7:
+            if (!dec_check_fpuv2(dc)) {
+                return;
+            }
+            gen_helper_fsqrt(cpu_R[dc->rd], cpu_R[dc->ra]);
+            break;
+
+        default:
+            qemu_log ("unimplemented FPU insn fpu_insn=%x pc=%x opc=%x\n",
+                      fpu_insn, dc->pc, dc->opcode);
+            dc->abort_at_next_insn = 1;
+            break;
+    }
 }
 
 static void dec_null(DisasContext *dc)
 {
+    if ((dc->tb_flags & MSR_EE_FLAG)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
     qemu_log ("unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
     dc->abort_at_next_insn = 1;
 }
 
+/* Insns connected to FSL or AXI stream attached devices.  */
+static void dec_stream(DisasContext *dc)
+{
+    int mem_index = cpu_mmu_index(dc->env);
+    TCGv_i32 t_id, t_ctrl;
+    int ctrl;
+
+    LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put",
+            dc->type_b ? "" : "d", dc->imm);
+
+    if ((dc->tb_flags & MSR_EE_FLAG) && (mem_index == MMU_USER_IDX)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    t_id = tcg_temp_new();
+    if (dc->type_b) {
+        tcg_gen_movi_tl(t_id, dc->imm & 0xf);
+        ctrl = dc->imm >> 10;
+    } else {
+        tcg_gen_andi_tl(t_id, cpu_R[dc->rb], 0xf);
+        ctrl = dc->imm >> 5;
+    }
+
+    t_ctrl = tcg_const_tl(ctrl);
+
+    if (dc->rd == 0) {
+        gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
+    } else {
+        gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
+    }
+    tcg_temp_free(t_id);
+    tcg_temp_free(t_ctrl);
+}
+
 static struct decoder_info {
     struct {
         uint32_t bits;
@@ -1140,6 +1535,7 @@ static struct decoder_info {
     {DEC_MUL, dec_mul},
     {DEC_DIV, dec_div},
     {DEC_MSR, dec_msr},
+    {DEC_STREAM, dec_stream},
     {{0, 0}, dec_null}
 };
 
@@ -1158,8 +1554,8 @@ static inline void decode(DisasContext *dc)
         dc->nr_nops = 0;
     else {
         if ((dc->tb_flags & MSR_EE_FLAG)
-              && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
-              && !(dc->env->pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
+              && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+              && (dc->env->pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
             tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
             t_gen_raise_exception(dc, EXCP_HW_EXCP);
             return;
@@ -1192,8 +1588,8 @@ static void check_breakpoint(CPUState *env, DisasContext *dc)
 {
     CPUBreakpoint *bp;
 
-    if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
-        TAILQ_FOREACH(bp, &env->breakpoints, entry) {
+    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
             if (bp->pc == dc->pc) {
                 t_gen_raise_exception(dc, EXCP_DEBUG);
                 dc->is_jmp = DISAS_UPDATE;
@@ -1229,9 +1625,10 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
     dc->is_jmp = DISAS_NEXT;
     dc->jmp = 0;
     dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
-    dc->ppc = pc_start;
+    if (dc->delayed_branch) {
+        dc->jmp = JMP_INDIRECT;
+    }
     dc->pc = pc_start;
-    dc->cache_pc = -1;
     dc->singlestep_enabled = env->singlestep_enabled;
     dc->cpustate_changed = 0;
     dc->abort_at_next_insn = 0;
@@ -1287,7 +1684,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
        decode(dc);
         if (dc->clear_imm)
             dc->tb_flags &= ~IMM_FLAG;
-        dc->ppc = dc->pc;
         dc->pc += 4;
         num_insns++;
 
@@ -1303,9 +1699,25 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
                 /* Clear the delay slot flag.  */
                 dc->tb_flags &= ~D_FLAG;
                 /* If it is a direct jump, try direct chaining.  */
-                if (dc->jmp != JMP_DIRECT) {
+                if (dc->jmp == JMP_INDIRECT) {
                     eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
                     dc->is_jmp = DISAS_JUMP;
+                } else if (dc->jmp == JMP_DIRECT) {
+                    t_sync_flags(dc);
+                    gen_goto_tb(dc, 0, dc->jmp_pc);
+                    dc->is_jmp = DISAS_TB_JUMP;
+                } else if (dc->jmp == JMP_DIRECT_CC) {
+                    int l1;
+
+                    t_sync_flags(dc);
+                    l1 = gen_new_label();
+                    /* Conditional jmp.  */
+                    tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1);
+                    gen_goto_tb(dc, 1, dc->pc);
+                    gen_set_label(l1);
+                    gen_goto_tb(dc, 0, dc->jmp_pc);
+
+                    dc->is_jmp = DISAS_TB_JUMP;
                 }
                 break;
             }
@@ -1319,7 +1731,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
                  && num_insns < max_insns);
 
     npc = dc->pc;
-    if (dc->jmp == JMP_DIRECT) {
+    if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
         if (dc->tb_flags & D_FLAG) {
             dc->is_jmp = DISAS_UPDATE;
             tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
@@ -1339,9 +1751,13 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
     t_sync_flags(dc);
 
     if (unlikely(env->singlestep_enabled)) {
-        t_gen_raise_exception(dc, EXCP_DEBUG);
-        if (dc->is_jmp == DISAS_NEXT)
+        TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
+
+        if (dc->is_jmp != DISAS_JUMP) {
             tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+        }
+        gen_helper_raise_exception(tmp);
+        tcg_temp_free_i32(tmp);
     } else {
         switch(dc->is_jmp) {
             case DISAS_NEXT:
@@ -1378,7 +1794,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
 #if DISAS_GNU
         log_target_disas(pc_start, dc->pc - pc_start, 0);
 #endif
-        qemu_log("\nisize=%d osize=%zd\n",
+        qemu_log("\nisize=%d osize=%td\n",
             dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
     }
 #endif
@@ -1396,8 +1812,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
     gen_intermediate_code_internal(env, tb, 1);
 }
 
-void cpu_dump_state (CPUState *env, FILE *f,
-                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                      int flags)
 {
     int i;
@@ -1407,13 +1822,16 @@ void cpu_dump_state (CPUState *env, FILE *f,
 
     cpu_fprintf(f, "IN: PC=%x %s\n",
                 env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC]));
-    cpu_fprintf(f, "rmsr=%x resr=%x debug[%x] imm=%x iflags=%x\n",
-             env->sregs[SR_MSR], env->sregs[SR_ESR],
-             env->debug, env->imm, env->iflags);
-    cpu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s)\n",
+    cpu_fprintf(f, "rmsr=%x resr=%x rear=%x debug=%x imm=%x iflags=%x fsr=%x\n",
+             env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
+             env->debug, env->imm, env->iflags, env->sregs[SR_FSR]);
+    cpu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
              env->btaken, env->btarget,
              (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
-             (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel");
+             (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
+             (env->sregs[SR_MSR] & MSR_EIP),
+             (env->sregs[SR_MSR] & MSR_IE));
+
     for (i = 0; i < 32; i++) {
         cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
         if ((i + 1) % 4 == 0)
@@ -1432,34 +1850,7 @@ CPUState *cpu_mb_init (const char *cpu_model)
 
     cpu_exec_init(env);
     cpu_reset(env);
-
-    env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
-                       | PVR0_USE_BARREL_MASK \
-                       | PVR0_USE_DIV_MASK \
-                       | PVR0_USE_HW_MUL_MASK \
-                       | PVR0_USE_EXC_MASK \
-                       | PVR0_USE_ICACHE_MASK \
-                       | PVR0_USE_DCACHE_MASK \
-                       | PVR0_USE_MMU \
-                       | (0xb << 8);
-    env->pvr.regs[2] = PVR2_D_OPB_MASK \
-                        | PVR2_D_LMB_MASK \
-                        | PVR2_I_OPB_MASK \
-                        | PVR2_I_LMB_MASK \
-                        | PVR2_USE_MSR_INSTR \
-                        | PVR2_USE_PCMP_INSTR \
-                        | PVR2_USE_BARREL_MASK \
-                        | PVR2_USE_DIV_MASK \
-                        | PVR2_USE_HW_MUL_MASK \
-                        | PVR2_USE_MUL64_MASK \
-                        | 0;
-    env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family.  */
-    env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
-#if !defined(CONFIG_USER_ONLY)
-    env->mmu.c_mmu = 3;
-    env->mmu.c_mmu_tlb_access = 3;
-    env->mmu.c_mmu_zones = 16;
-#endif
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
 
     if (tcg_initialized)
         return env;
@@ -1509,17 +1900,46 @@ void cpu_reset (CPUState *env)
     memset(env, 0, offsetof(CPUMBState, breakpoints));
     tlb_flush(env, 1);
 
-    env->sregs[SR_MSR] = 0;
+    env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
+                       | PVR0_USE_BARREL_MASK \
+                       | PVR0_USE_DIV_MASK \
+                       | PVR0_USE_HW_MUL_MASK \
+                       | PVR0_USE_EXC_MASK \
+                       | PVR0_USE_ICACHE_MASK \
+                       | PVR0_USE_DCACHE_MASK \
+                       | PVR0_USE_MMU \
+                       | (0xb << 8);
+    env->pvr.regs[2] = PVR2_D_OPB_MASK \
+                        | PVR2_D_LMB_MASK \
+                        | PVR2_I_OPB_MASK \
+                        | PVR2_I_LMB_MASK \
+                        | PVR2_USE_MSR_INSTR \
+                        | PVR2_USE_PCMP_INSTR \
+                        | PVR2_USE_BARREL_MASK \
+                        | PVR2_USE_DIV_MASK \
+                        | PVR2_USE_HW_MUL_MASK \
+                        | PVR2_USE_MUL64_MASK \
+                        | PVR2_USE_FPU_MASK \
+                        | PVR2_USE_FPU2_MASK \
+                        | PVR2_FPU_EXC_MASK \
+                        | 0;
+    env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family.  */
+    env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
+
 #if defined(CONFIG_USER_ONLY)
     /* start in user mode with interrupts enabled.  */
+    env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
     env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp.  */
 #else
+    env->sregs[SR_MSR] = 0;
     mmu_init(&env->mmu);
+    env->mmu.c_mmu = 3;
+    env->mmu.c_mmu_tlb_access = 3;
+    env->mmu.c_mmu_zones = 16;
 #endif
 }
 
-void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
-                 unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->sregs[SR_PC] = gen_opc_pc[pc_pos];
 }