target-mips: minor upstream integration.

Change-Id: Ib356a3cb8aa0bda14f857b951e2c357405acaaee
diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c
index 8462c5e..f955461 100644
--- a/hw/mips/cputimer.c
+++ b/hw/mips/cputimer.c
@@ -1,3 +1,25 @@
+/*
+ * QEMU MIPS timer support
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
 #include "hw/hw.h"
 #include "hw/mips/mips.h"
 #include "qemu/timer.h"
@@ -5,7 +27,7 @@
 #define TIMER_FREQ	100 * 1000 * 1000
 
 /* XXX: do not use a global */
-uint32_t cpu_mips_get_random (CPUOldState *env)
+uint32_t cpu_mips_get_random (CPUMIPSState *env)
 {
     static uint32_t lfsr = 1;
     static uint32_t prev_idx = 0;
@@ -20,17 +42,7 @@
 }
 
 /* MIPS R4K timer */
-uint32_t cpu_mips_get_count (CPUOldState *env)
-{
-    if (env->CP0_Cause & (1 << CP0Ca_DC))
-        return env->CP0_Count;
-    else
-        return env->CP0_Count +
-            (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
-                               TIMER_FREQ, get_ticks_per_sec());
-}
-
-static void cpu_mips_timer_update(CPUOldState *env)
+static void cpu_mips_timer_update(CPUMIPSState *env)
 {
     uint64_t now, next;
     uint32_t wait;
@@ -42,7 +54,36 @@
     timer_mod(env->timer, next);
 }
 
-void cpu_mips_store_count (CPUOldState *env, uint32_t count)
+/* Expire the timer.  */
+static void cpu_mips_timer_expire(CPUMIPSState *env)
+{
+    cpu_mips_timer_update(env);
+    if (env->insn_flags & ISA_MIPS32R2) {
+        env->CP0_Cause |= 1 << CP0Ca_TI;
+    }
+    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+uint32_t cpu_mips_get_count (CPUMIPSState *env)
+{
+    if (env->CP0_Cause & (1 << CP0Ca_DC)) {
+        return env->CP0_Count;
+    } else {
+        uint64_t now;
+
+        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        if (timer_pending(env->timer)
+            && timer_expired(env->timer, now)) {
+            /* The timer has already expired.  */
+            cpu_mips_timer_expire(env);
+        }
+
+        return env->CP0_Count +
+            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
+    }
+}
+
+void cpu_mips_store_count (CPUMIPSState *env, uint32_t count)
 {
     if (env->CP0_Cause & (1 << CP0Ca_DC))
         env->CP0_Count = count;
@@ -56,7 +97,7 @@
     }
 }
 
-void cpu_mips_store_compare (CPUOldState *env, uint32_t value)
+void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value)
 {
     env->CP0_Compare = value;
     if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
@@ -66,12 +107,12 @@
     qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
 }
 
-void cpu_mips_start_count(CPUOldState *env)
+void cpu_mips_start_count(CPUMIPSState *env)
 {
     cpu_mips_store_count(env, env->CP0_Count);
 }
 
-void cpu_mips_stop_count(CPUOldState *env)
+void cpu_mips_stop_count(CPUMIPSState *env)
 {
     /* Store the current value */
     env->CP0_Count += (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
@@ -80,7 +121,7 @@
 
 static void mips_timer_cb (void *opaque)
 {
-    CPUOldState *env;
+    CPUMIPSState *env;
 
     env = opaque;
 #if 0
@@ -94,16 +135,13 @@
        the comparator value.  Offset the count by one to avoid immediately
        retriggering the callback before any virtual time has passed.  */
     env->CP0_Count++;
-    cpu_mips_timer_update(env);
+    cpu_mips_timer_expire(env);
     env->CP0_Count--;
-    if (env->insn_flags & ISA_MIPS32R2)
-        env->CP0_Cause |= 1 << CP0Ca_TI;
-    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
 }
 
-void cpu_mips_clock_init (CPUOldState *env)
+void cpu_mips_clock_init (CPUMIPSState *env)
 {
-    env->timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, &mips_timer_cb, env);
+    env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &mips_timer_cb, env);
     env->CP0_Compare = 0;
     cpu_mips_store_count(env, 1);
 }
diff --git a/target-mips/machine.c b/target-mips/machine.c
index 6ae15e3..0a07db8 100644
--- a/target-mips/machine.c
+++ b/target-mips/machine.c
@@ -58,6 +58,7 @@
 
     /* Save TLB */
     qemu_put_be32s(f, &env->tlb->nb_tlb);
+    qemu_put_be32s(f, &env->tlb->tlb_in_use);
     for(i = 0; i < MIPS_TLB_MAX; i++) {
         uint16_t flags = ((env->tlb->mmu.r4k.tlb[i].G << 10) |
                           (env->tlb->mmu.r4k.tlb[i].C0 << 7) |
@@ -209,6 +210,7 @@
 
     /* Load TLB */
     qemu_get_be32s(f, &env->tlb->nb_tlb);
+    qemu_get_be32s(f, &env->tlb->tlb_in_use);
     for(i = 0; i < MIPS_TLB_MAX; i++) {
         uint16_t flags;
         uint8_t asid;
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 29c3c6e..ccce17f 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -281,18 +281,6 @@
                        (uint64_t)(uint32_t)arg2);
 }
 
-#ifdef TARGET_MIPS64
-void helper_dmult (CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
-{
-    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
-}
-
-void helper_dmultu (CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
-{
-    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
-}
-#endif
-
 #ifndef CONFIG_USER_ONLY
 
 static inline hwaddr do_translate_address(CPUMIPSState *env,
@@ -1774,7 +1762,6 @@
 void helper_fork(target_ulong arg1, target_ulong arg2)
 {
     // arg1 = rt, arg2 = rs
-    arg1 = 0;
     // TODO: store to TC register
 }
 
@@ -2196,7 +2183,10 @@
 
 void helper_wait(CPUMIPSState *env)
 {
-    ENV_GET_CPU(env)->halted = 1;
+    CPUState* cs = ENV_GET_CPU(env);
+
+    cs->halted = 1;
+    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
     helper_raise_exception(env, EXCP_HLT);
 }
 
@@ -2247,10 +2237,11 @@
 {
     CPUMIPSState *env = cpu->env_ptr;
 
-    if (is_exec)
+    if (is_exec) {
         helper_raise_exception(env, EXCP_IBE);
-    else
+    } else {
         helper_raise_exception(env, EXCP_DBE);
+    }
 }
 /*
  * The following functions are address translation helper functions
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 2c2e1fa..9505e2c 100755
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1026,36 +1026,6 @@
 
 #include "exec/gen-icount.h"
 
-#define gen_helper_0i(name, arg) do {                             \
-    TCGv_i32 helper_tmp = tcg_const_i32(arg);                     \
-    gen_helper_##name(helper_tmp);                                \
-    tcg_temp_free_i32(helper_tmp);                                \
-    } while(0)
-
-#define gen_helper_1i(name, arg1, arg2) do {                      \
-    TCGv_i32 helper_tmp = tcg_const_i32(arg2);                    \
-    gen_helper_##name(arg1, helper_tmp);                          \
-    tcg_temp_free_i32(helper_tmp);                                \
-    } while(0)
-
-#define gen_helper_2i(name, arg1, arg2, arg3) do {                \
-    TCGv_i32 helper_tmp = tcg_const_i32(arg3);                    \
-    gen_helper_##name(arg1, arg2, helper_tmp);                    \
-    tcg_temp_free_i32(helper_tmp);                                \
-    } while(0)
-
-#define gen_helper_3i(name, arg1, arg2, arg3, arg4) do {          \
-    TCGv_i32 helper_tmp = tcg_const_i32(arg4);                    \
-    gen_helper_##name(arg1, arg2, arg3, helper_tmp);              \
-    tcg_temp_free_i32(helper_tmp);                                \
-    } while(0)
-
-#define gen_helper_4i(name, arg1, arg2, arg3, arg4, arg5) do {    \
-    TCGv_i32 helper_tmp = tcg_const_i32(arg5);                    \
-    gen_helper_##name(arg1, arg2, arg3, arg4, helper_tmp);        \
-    tcg_temp_free_i32(helper_tmp);                                \
-    } while(0)
-
 #define gen_helper_0e0i(name, arg) do {                           \
     TCGv_i32 helper_tmp = tcg_const_i32(arg);                     \
     gen_helper_##name(cpu_env, helper_tmp);                       \
@@ -1471,36 +1441,6 @@
         generate_exception(ctx, EXCP_RI);
 }
 
-/* load/store instructions. */
-#define OP_LD(insn,fname)                                                 \
-static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \
-{                                                                         \
-    tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx);                        \
-}
-OP_LD(lb,ld8s);
-OP_LD(lbu,ld8u);
-OP_LD(lh,ld16s);
-OP_LD(lhu,ld16u);
-OP_LD(lw,ld32s);
-#if defined(TARGET_MIPS64)
-OP_LD(lwu,ld32u);
-OP_LD(ld,ld64);
-#endif
-#undef OP_LD
-
-#define OP_ST(insn,fname)                                                  \
-static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, DisasContext *ctx) \
-{                                                                          \
-    tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx);                        \
-}
-OP_ST(sb,st8);
-OP_ST(sh,st16);
-OP_ST(sw,st32);
-#if defined(TARGET_MIPS64)
-OP_ST(sd,st64);
-#endif
-#undef OP_ST
-
 /* Define small wrappers for gen_load_fpr* so that we have a uniform
    calling interface for 32 and 64-bit FPRs.  No sense in changing
    all callers for gen_load_fpr32 when we need the CTX parameter for
@@ -6186,7 +6126,15 @@
         switch (sel) {
         case 0:
             save_cpu_state(ctx, 1);
+            /* Mark as an IO operation because we may trigger a software
+               interrupt.  */
+            if (use_icount) {
+                gen_io_start();
+            }
             gen_helper_mtc0_cause(cpu_env, arg);
+            if (use_icount) {
+                gen_io_end();
+            }
             /* Stop translation as we may have triggered an intetrupt */
             ctx->bstate = BS_STOP;
             rn = "Cause";
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 8ace034..29dc2ef 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -51,10 +51,6 @@
 #define MIPS_CONFIG5                                              \
 ((0 << CP0C5_M))
 
-/* Define a implementation number of 1.
-   Define a major version 1, minor version 0. */
-#define MIPS_FCR0 ((0 << FCR0_S) | (0x1 << FCR0_PRID) | (0x10 << FCR0_REV))
-
 /* MMU types, the first four entries have the same layout as the
    CP0C0_MT field.  */
 enum mips_mmu_types {