Preliminiary MIPS64 support, disabled by default due to performance impact.
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 21 Dec 2006 01:19:56 +0000 (01:19 +0000)
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 21 Dec 2006 01:19:56 +0000 (01:19 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2250 c046a42c-6fe2-441c-8c8c-71466251a162

12 files changed:
hw/mips_r4k.c
target-mips/cpu.h
target-mips/exec.h
target-mips/fop_template.c
target-mips/helper.c
target-mips/mips-defs.h
target-mips/op.c
target-mips/op_helper.c
target-mips/op_helper_mem.c
target-mips/op_mem.c
target-mips/op_template.c
target-mips/translate.c

index 61db814..ca3a4ff 100644 (file)
 
 #define BIOS_FILENAME "mips_bios.bin"
 //#define BIOS_FILENAME "system.bin"
-#define KERNEL_LOAD_ADDR 0x80010000
-#define INITRD_LOAD_ADDR 0x80800000
+#define KERNEL_LOAD_ADDR SIGN_EXTEND32(0x80010000)
+#define INITRD_LOAD_ADDR SIGN_EXTEND32(0x80800000)
 
-#define VIRT_TO_PHYS_ADDEND (-0x80000000LL)
+#define VIRT_TO_PHYS_ADDEND (-SIGN_EXTEND32(0x80000000LL))
 
 static const int ide_iobase[2] = { 0x1f0, 0x170 };
 static const int ide_iobase2[2] = { 0x3f6, 0x376 };
@@ -74,9 +74,11 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
     long kernel_size, initrd_size;
 
     kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
-    if (kernel_size >= 0)
+    if (kernel_size >= 0) {
+        if ((entry & ~0x7fffffffULL) == 0x80000000)
+            entry = SIGN_EXTEND32(entry);
         env->PC = entry;
-    else {
+    } else {
         kernel_size = load_image(kernel_filename,
                                  phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
         if (kernel_size < 0) {
@@ -103,7 +105,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
     if (initrd_size > 0) {
         int ret;
         ret = sprintf(phys_ram_base + (16 << 20) - 256,
-                      "rd_start=0x%08x rd_size=%li ",
+                      "rd_start=0x" TLSZ " rd_size=%li ",
                       INITRD_LOAD_ADDR,
                       initrd_size);
         strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline);
index 46436cd..710748c 100644 (file)
@@ -15,6 +15,16 @@ typedef unsigned char           uint_fast8_t;
 typedef unsigned int            uint_fast16_t;
 #endif
 
+#ifdef MIPS_HAS_MIPS64
+#define SIGN_EXTEND32(val) (((((uint64_t)(val)) & 0xFFFFFFFF) ^ 0x80000000) - 0x80000000)
+/* target_ulong size spec */
+#define TLSZ "%016llx"
+#else
+#define SIGN_EXTEND32(val) (val)
+/* target_ulong size spec */
+#define TLSZ "%08x"
+#endif
+
 typedef union fpr_t fpr_t;
 union fpr_t {
     float64  fd;   /* ieee double precision */
@@ -55,7 +65,12 @@ struct CPUMIPSState {
     target_ulong gpr[32];
     /* Special registers */
     target_ulong PC;
-    uint32_t HI, LO;
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+    target_ulong t0;
+    target_ulong t1;
+    target_ulong t2;
+#endif
+    target_ulong HI, LO;
     uint32_t DCR; /* ? */
 #if defined(MIPS_USES_FPU)
     /* Floating point registers */
@@ -106,7 +121,7 @@ struct CPUMIPSState {
     uint32_t CP0_PageGrain;
     uint32_t CP0_Wired;
     uint32_t CP0_HWREna;
-    uint32_t CP0_BadVAddr;
+    target_ulong CP0_BadVAddr;
     uint32_t CP0_Count;
     uint64_t CP0_EntryHi;
     uint32_t CP0_Compare;
@@ -145,9 +160,9 @@ struct CPUMIPSState {
 #define CP0Ca_WP   22
 #define CP0Ca_IP    8
 #define CP0Ca_EC    2
-    uint32_t CP0_EPC;
+    target_ulong CP0_EPC;
     uint32_t CP0_PRid;
-    uint32_t CP0_EBase;
+    target_ulong CP0_EBase;
     uint32_t CP0_Config0;
 #define CP0C0_M    31
 #define CP0C0_K23  28
@@ -197,7 +212,7 @@ struct CPUMIPSState {
 #define CP0C3_MT   2
 #define CP0C3_SM   1
 #define CP0C3_TL   0
-    uint32_t CP0_LLAddr;
+    target_ulong CP0_LLAddr;
     uint32_t CP0_WatchLo;
     uint32_t CP0_WatchHi;
     uint32_t CP0_XContext;
@@ -221,13 +236,13 @@ struct CPUMIPSState {
 #define CP0DB_DDBL 2
 #define CP0DB_DBp  1
 #define CP0DB_DSS  0
-    uint32_t CP0_DEPC;
+    target_ulong CP0_DEPC;
     uint32_t CP0_Performance0;
     uint32_t CP0_TagLo;
     uint32_t CP0_DataLo;
     uint32_t CP0_TagHi;
     uint32_t CP0_DataHi;
-    uint32_t CP0_ErrorEPC;
+    target_ulong CP0_ErrorEPC;
     uint32_t CP0_DESAVE;
     /* Qemu */
     int interrupt_request;
index 817ef03..9e1fcdc 100644 (file)
@@ -3,6 +3,7 @@
 
 //#define DEBUG_OP
 
+#include "config.h"
 #include "mips-defs.h"
 #include "dyngen-exec.h"
 
@@ -16,9 +17,15 @@ typedef int32_t host_int_t;
 typedef uint32_t host_uint_t;
 #endif
 
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+#define T0 (env->t0)
+#define T1 (env->t1)
+#define T2 (env->t2)
+#else
 register host_uint_t T0 asm(AREG1);
 register host_uint_t T1 asm(AREG2);
 register host_uint_t T2 asm(AREG3);
+#endif
 
 #if defined (USE_HOST_FLOAT_REGS)
 #error "implement me."
@@ -58,13 +65,36 @@ static inline void regs_to_env(void)
 {
 }
 
-#if (HOST_LONG_BITS == 32)
+#ifdef MIPS_HAS_MIPS64
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+void do_dsll (void);
+void do_dsll32 (void);
+void do_dsra (void);
+void do_dsra32 (void);
+void do_dsrl (void);
+void do_dsrl32 (void);
+void do_drotr (void);
+void do_drotr32 (void);
+void do_dsllv (void);
+void do_dsrav (void);
+void do_dsrlv (void);
+void do_drotrv (void);
+#endif
+#endif
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
 void do_mult (void);
 void do_multu (void);
 void do_madd (void);
 void do_maddu (void);
 void do_msub (void);
 void do_msubu (void);
+void do_ddiv (void);
+void do_ddivu (void);
+#endif
+#ifdef MIPS_HAS_MIPS64
+void do_dmult (void);
+void do_dmultu (void);
 #endif
 void do_mfc0_random(void);
 void do_mfc0_count(void);
@@ -86,6 +116,12 @@ void do_lwl_raw (uint32_t);
 void do_lwr_raw (uint32_t);
 uint32_t do_swl_raw (uint32_t);
 uint32_t do_swr_raw (uint32_t);
+#ifdef MIPS_HAS_MIPS64
+void do_ldl_raw (uint64_t);
+void do_ldr_raw (uint64_t);
+uint64_t do_sdl_raw (uint64_t);
+uint64_t do_sdr_raw (uint64_t);
+#endif
 #if !defined(CONFIG_USER_ONLY)
 void do_lwl_user (uint32_t);
 void do_lwl_kernel (uint32_t);
@@ -95,6 +131,16 @@ uint32_t do_swl_user (uint32_t);
 uint32_t do_swl_kernel (uint32_t);
 uint32_t do_swr_user (uint32_t);
 uint32_t do_swr_kernel (uint32_t);
+#ifdef MIPS_HAS_MIPS64
+void do_ldl_user (uint64_t);
+void do_ldl_kernel (uint64_t);
+void do_ldr_user (uint64_t);
+void do_ldr_kernel (uint64_t);
+uint64_t do_sdl_user (uint64_t);
+uint64_t do_sdl_kernel (uint64_t);
+uint64_t do_sdr_user (uint64_t);
+uint64_t do_sdr_kernel (uint64_t);
+#endif
 #endif
 void do_pmon (int function);
 
index bc0a6e0..4ebb46b 100644 (file)
@@ -96,4 +96,5 @@ SET_RESET(DT0, _DT0)
 SET_RESET(DT1, _DT1)
 SET_RESET(DT2, _DT2)
 
+#undef SET_RESET
 #endif
index a0a56d8..0e3eb6c 100644 (file)
@@ -86,7 +86,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
 #endif
     if (user_mode && address > 0x7FFFFFFFUL)
         return TLBRET_BADADDR;
-    if (address < 0x80000000UL) {
+    if (address < SIGN_EXTEND32(0x80000000UL)) {
         if (!(env->hflags & MIPS_HFLAG_ERL)) {
 #ifdef MIPS_USES_R4K_TLB
             ret = map_address(env, physical, prot, address, rw, access_type);
@@ -98,17 +98,17 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
             *physical = address;
             *prot = PAGE_READ | PAGE_WRITE;
         }
-    } else if (address < 0xA0000000UL) {
+    } else if (address < SIGN_EXTEND32(0xA0000000UL)) {
         /* kseg0 */
         /* XXX: check supervisor mode */
-        *physical = address - 0x80000000UL;
+        *physical = address - SIGN_EXTEND32(0x80000000UL);
         *prot = PAGE_READ | PAGE_WRITE;
-    } else if (address < 0xC0000000UL) {
+    } else if (address < SIGN_EXTEND32(0xC0000000UL)) {
         /* kseg1 */
         /* XXX: check supervisor mode */
-        *physical = address - 0xA0000000UL;
+        *physical = address - SIGN_EXTEND32(0xA0000000UL);
         *prot = PAGE_READ | PAGE_WRITE;
-    } else if (address < 0xE0000000UL) {
+    } else if (address < SIGN_EXTEND32(0xE0000000UL)) {
         /* kseg2 */
 #ifdef MIPS_USES_R4K_TLB
         ret = map_address(env, physical, prot, address, rw, access_type);
@@ -129,8 +129,8 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
     }
 #if 0
     if (logfile) {
-        fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw,
-                access_type, *physical, *prot, ret);
+        fprintf(logfile, TLSZ " %d %d => " TLSZ " %d (%d)\n",
+               address, rw, access_type, *physical, *prot, ret);
     }
 #endif
 
@@ -171,7 +171,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 #if 0
         cpu_dump_state(env, logfile, fprintf, 0);
 #endif
-        fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
+        fprintf(logfile, "%s pc " TLSZ " ad " TLSZ " rw %d is_user %d smmu %d\n",
                 __func__, env->PC, address, rw, is_user, is_softmmu);
     }
 
@@ -189,7 +189,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
     ret = get_physical_address(env, &physical, &prot,
                                address, rw, access_type);
     if (logfile) {
-        fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
+        fprintf(logfile, "%s address=" TLSZ " ret %d physical " TLSZ " prot %d\n",
                 __func__, address, ret, physical, prot);
     }
     if (ret == TLBRET_MATCH) {
@@ -255,7 +255,7 @@ void do_interrupt (CPUState *env)
     int cause = -1;
 
     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
-        fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n",
+        fprintf(logfile, "%s enter: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n",
                 __func__, env->PC, env->CP0_EPC, cause, env->exception_index);
     }
     if (env->exception_index == EXCP_EXT_INTERRUPT &&
@@ -299,7 +299,7 @@ void do_interrupt (CPUState *env)
     enter_debug_mode:
         env->hflags |= MIPS_HFLAG_DM;
         /* EJTAG probe trap enable is not implemented... */
-        env->PC = 0xBFC00480;
+        env->PC = SIGN_EXTEND32(0xBFC00480);
         break;
     case EXCP_RESET:
         cpu_reset(env);
@@ -321,7 +321,7 @@ void do_interrupt (CPUState *env)
         }
         env->hflags |= MIPS_HFLAG_ERL;
        env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
-        env->PC = 0xBFC00000;
+        env->PC = SIGN_EXTEND32(0xBFC00000);
         break;
     case EXCP_MCHECK:
         cause = 24;
@@ -389,9 +389,9 @@ void do_interrupt (CPUState *env)
             env->CP0_Cause &= ~0x80000000;
         }
         if (env->CP0_Status & (1 << CP0St_BEV)) {
-            env->PC = 0xBFC00200;
+            env->PC = SIGN_EXTEND32(0xBFC00200);
         } else {
-            env->PC = 0x80000000;
+            env->PC = SIGN_EXTEND32(0x80000000);
         }
         env->hflags |= MIPS_HFLAG_EXL;
         env->CP0_Status |= (1 << CP0St_EXL);
@@ -407,8 +407,8 @@ void do_interrupt (CPUState *env)
         exit(1);
     }
     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
-        fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n"
-                "    S %08x C %08x A %08x D %08x\n",
+        fprintf(logfile, "%s: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n"
+                "    S %08x C %08x A " TLSZ " D " TLSZ "\n",
                 __func__, env->PC, env->CP0_EPC, cause, env->exception_index,
                 env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
                 env->CP0_DEPC);
index 14d1438..83480c6 100644 (file)
@@ -14,7 +14,8 @@
 
 #if (MIPS_CPU == MIPS_R4Kc)
 /* 32 bits target */
-#define TARGET_LONG_BITS 32
+#undef MIPS_HAS_MIPS64
+//#define MIPS_HAS_MIPS64 1
 /* real pages are variable size... */
 #define TARGET_PAGE_BITS 12
 /* Uses MIPS R4Kx enhancements to MIPS32 architecture */
@@ -69,7 +70,7 @@
  (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL))
 #elif (MIPS_CPU == MIPS_R4Kp)
 /* 32 bits target */
-#define TARGET_LONG_BITS 32
+#undef MIPS_HAS_MIPS64
 /* real pages are variable size... */
 #define TARGET_PAGE_BITS 12
 /* Uses MIPS R4Kx enhancements to MIPS32 architecture */
 #else
 #error "MIPS CPU not defined"
 /* Reminder for other flags */
-//#define TARGET_MIPS64
+//#undef MIPS_HAS_MIPS64
 //#define MIPS_USES_FPU
 #endif
 
+#ifdef MIPS_HAS_MIPS64
+#define TARGET_LONG_BITS 64
+#else
+#define TARGET_LONG_BITS 32
+#endif
+
 #endif /* !defined (__QEMU_MIPS_DEFS_H__) */
index 35a1365..4b6c20c 100644 (file)
@@ -140,13 +140,7 @@ CALL_FROM_TB2(func, arg0, arg1);
 #include "op_template.c"
 #undef REG
 
-#define TN T0
-#include "op_template.c"
-#undef TN
-#define TN T1
-#include "op_template.c"
-#undef TN
-#define TN T2
+#define TN
 #include "op_template.c"
 #undef TN
 
@@ -334,7 +328,7 @@ void op_store_LO (void)
 /* Arithmetic */
 void op_add (void)
 {
-    T0 += T1;
+    T0 = SIGN_EXTEND32((int32_t)T0 + (int32_t)T1);
     RETURN();
 }
 
@@ -342,18 +336,19 @@ void op_addo (void)
 {
     target_ulong tmp;
 
-    tmp = T0;
-    T0 += T1;
+    tmp = (int32_t)T0;
+    T0 = (int32_t)T0 + (int32_t)T1;
     if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) {
-       /* operands of same sign, result different sign */
+        /* operands of same sign, result different sign */
         CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
     }
+    T0 = SIGN_EXTEND32(T0);
     RETURN();
 }
 
 void op_sub (void)
 {
-    T0 -= T1;
+    T0 = SIGN_EXTEND32((int32_t)T0 - (int32_t)T1);
     RETURN();
 }
 
@@ -361,26 +356,27 @@ void op_subo (void)
 {
     target_ulong tmp;
 
-    tmp = T0;
+    tmp = (int32_t)T0;
     T0 = (int32_t)T0 - (int32_t)T1;
     if (((tmp ^ T1) & (tmp ^ T0)) >> 31) {
-       /* operands of different sign, first operand and result different sign */
+        /* operands of different sign, first operand and result different sign */
         CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
     }
+    T0 = SIGN_EXTEND32(T0);
     RETURN();
 }
 
 void op_mul (void)
 {
-    T0 = (int32_t)T0 * (int32_t)T1;
+    T0 = SIGN_EXTEND32((int32_t)T0 * (int32_t)T1);
     RETURN();
 }
 
 void op_div (void)
 {
     if (T1 != 0) {
-        env->LO = (int32_t)T0 / (int32_t)T1;
-        env->HI = (int32_t)T0 % (int32_t)T1;
+        env->LO = SIGN_EXTEND32((int32_t)T0 / (int32_t)T1);
+        env->HI = SIGN_EXTEND32((int32_t)T0 % (int32_t)T1);
     }
     RETURN();
 }
@@ -388,11 +384,91 @@ void op_div (void)
 void op_divu (void)
 {
     if (T1 != 0) {
+        env->LO = SIGN_EXTEND32((uint32_t)T0 / (uint32_t)T1);
+        env->HI = SIGN_EXTEND32((uint32_t)T0 % (uint32_t)T1);
+    }
+    RETURN();
+}
+
+#ifdef MIPS_HAS_MIPS64
+/* Arithmetic */
+void op_dadd (void)
+{
+    T0 += T1;
+    RETURN();
+}
+
+void op_daddo (void)
+{
+    target_long tmp;
+
+    tmp = T0;
+    T0 += T1;
+    if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 63) {
+        /* operands of same sign, result different sign */
+        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+    }
+    RETURN();
+}
+
+void op_dsub (void)
+{
+    T0 -= T1;
+    RETURN();
+}
+
+void op_dsubo (void)
+{
+    target_long tmp;
+
+    tmp = T0;
+    T0 = (int64_t)T0 - (int64_t)T1;
+    if (((tmp ^ T1) & (tmp ^ T0)) >> 63) {
+        /* operands of different sign, first operand and result different sign */
+        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+    }
+    RETURN();
+}
+
+void op_dmul (void)
+{
+    T0 = (int64_t)T0 * (int64_t)T1;
+    RETURN();
+}
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+/* Those might call libgcc functions.  */
+void op_ddiv (void)
+{
+    do_ddiv();
+    RETURN();
+}
+
+void op_ddivu (void)
+{
+    do_ddivu();
+    RETURN();
+}
+#else
+void op_ddiv (void)
+{
+    if (T1 != 0) {
+        env->LO = (int64_t)T0 / (int64_t)T1;
+        env->HI = (int64_t)T0 % (int64_t)T1;
+    }
+    RETURN();
+}
+
+void op_ddivu (void)
+{
+    if (T1 != 0) {
         env->LO = T0 / T1;
         env->HI = T0 % T1;
     }
     RETURN();
 }
+#endif
+#endif /* MIPS_HAS_MIPS64 */
 
 /* Logical */
 void op_and (void)
@@ -421,19 +497,19 @@ void op_xor (void)
 
 void op_sll (void)
 {
-    T0 = T0 << T1;
+    T0 = SIGN_EXTEND32((uint32_t)T0 << (uint32_t)T1);
     RETURN();
 }
 
 void op_sra (void)
 {
-    T0 = (int32_t)T0 >> T1;
+    T0 = SIGN_EXTEND32((int32_t)T0 >> (uint32_t)T1);
     RETURN();
 }
 
 void op_srl (void)
 {
-    T0 = T0 >> T1;
+    T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1);
     RETURN();
 }
 
@@ -442,8 +518,8 @@ void op_rotr (void)
     target_ulong tmp;
 
     if (T1) {
-       tmp = T0 << (0x20 - T1);
-       T0 = (T0 >> T1) | tmp;
+       tmp = SIGN_EXTEND32((uint32_t)T0 << (0x20 - (uint32_t)T1));
+       T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1) | tmp;
     } else
        T0 = T1;
     RETURN();
@@ -451,19 +527,19 @@ void op_rotr (void)
 
 void op_sllv (void)
 {
-    T0 = T1 << (T0 & 0x1F);
+    T0 = SIGN_EXTEND32((uint32_t)T1 << ((uint32_t)T0 & 0x1F));
     RETURN();
 }
 
 void op_srav (void)
 {
-    T0 = (int32_t)T1 >> (T0 & 0x1F);
+    T0 = SIGN_EXTEND32((int32_t)T1 >> (T0 & 0x1F));
     RETURN();
 }
 
 void op_srlv (void)
 {
-    T0 = T1 >> (T0 & 0x1F);
+    T0 = SIGN_EXTEND32((uint32_t)T1 >> (T0 & 0x1F));
     RETURN();
 }
 
@@ -473,8 +549,8 @@ void op_rotrv (void)
 
     T0 &= 0x1F;
     if (T0) {
-       tmp = T1 << (0x20 - T0);
-       T0 = (T1 >> T0) | tmp;
+       tmp = SIGN_EXTEND32((uint32_t)T1 << (0x20 - T0));
+       T0 = SIGN_EXTEND32((uint32_t)T1 >> T0) | tmp;
     } else
        T0 = T1;
     RETURN();
@@ -484,7 +560,7 @@ void op_clo (void)
 {
     int n;
 
-    if (T0 == (target_ulong)-1) {
+    if (T0 == ~((target_ulong)0)) {
         T0 = 32;
     } else {
         for (n = 0; n < 32; n++) {
@@ -514,67 +590,213 @@ void op_clz (void)
     RETURN();
 }
 
-/* 64 bits arithmetic */
-#if (HOST_LONG_BITS == 64)
-static inline uint64_t get_HILO (void)
+#ifdef MIPS_HAS_MIPS64
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+/* Those might call libgcc functions.  */
+void op_dsll (void)
 {
-    return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
+    CALL_FROM_TB0(do_dsll);
+    RETURN();
 }
 
-static inline void set_HILO (uint64_t HILO)
+void op_dsll32 (void)
 {
-    env->LO = HILO & 0xFFFFFFFF;
-    env->HI = HILO >> 32;
+    CALL_FROM_TB0(do_dsll32);
+    RETURN();
 }
 
-void op_mult (void)
+void op_dsra (void)
 {
-    set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    CALL_FROM_TB0(do_dsra);
     RETURN();
 }
 
-void op_multu (void)
+void op_dsra32 (void)
 {
-    set_HILO((uint64_t)T0 * (uint64_t)T1);
+    CALL_FROM_TB0(do_dsra32);
     RETURN();
 }
 
-void op_madd (void)
+void op_dsrl (void)
 {
-    int64_t tmp;
+    CALL_FROM_TB0(do_dsrl);
+    RETURN();
+}
 
-    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
-    set_HILO((int64_t)get_HILO() + tmp);
+void op_dsrl32 (void)
+{
+    CALL_FROM_TB0(do_dsrl32);
     RETURN();
 }
 
-void op_maddu (void)
+void op_drotr (void)
 {
-    uint64_t tmp;
+    CALL_FROM_TB0(do_drotr);
+    RETURN();
+}
 
-    tmp = ((uint64_t)T0 * (uint64_t)T1);
-    set_HILO(get_HILO() + tmp);
+void op_drotr32 (void)
+{
+    CALL_FROM_TB0(do_drotr32);
     RETURN();
 }
 
-void op_msub (void)
+void op_dsllv (void)
 {
-    int64_t tmp;
+    CALL_FROM_TB0(do_dsllv);
+    RETURN();
+}
 
-    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
-    set_HILO((int64_t)get_HILO() - tmp);
+void op_dsrav (void)
+{
+    CALL_FROM_TB0(do_dsrav);
     RETURN();
 }
 
-void op_msubu (void)
+void op_dsrlv (void)
 {
-    uint64_t tmp;
+    CALL_FROM_TB0(do_dsrlv);
+    RETURN();
+}
 
-    tmp = ((uint64_t)T0 * (uint64_t)T1);
-    set_HILO(get_HILO() - tmp);
+void op_drotrv (void)
+{
+    CALL_FROM_TB0(do_drotrv);
     RETURN();
 }
-#else
+
+#else /* TARGET_LONG_BITS > HOST_LONG_BITS */
+
+void op_dsll (void)
+{
+    T0 = T0 << T1;
+    RETURN();
+}
+
+void op_dsll32 (void)
+{
+    T0 = T0 << (T1 + 32);
+    RETURN();
+}
+
+void op_dsra (void)
+{
+    T0 = (int64_t)T0 >> T1;
+    RETURN();
+}
+
+void op_dsra32 (void)
+{
+    T0 = (int64_t)T0 >> (T1 + 32);
+    RETURN();
+}
+
+void op_dsrl (void)
+{
+    T0 = T0 >> T1;
+    RETURN();
+}
+
+void op_dsrl32 (void)
+{
+    T0 = T0 >> (T1 + 32);
+    RETURN();
+}
+
+void op_drotr (void)
+{
+    target_ulong tmp;
+
+    if (T1) {
+       tmp = T0 << (0x40 - T1);
+       T0 = (T0 >> T1) | tmp;
+    } else
+       T0 = T1;
+    RETURN();
+}
+
+void op_drotr32 (void)
+{
+    target_ulong tmp;
+
+    if (T1) {
+       tmp = T0 << (0x40 - (32 + T1));
+       T0 = (T0 >> (32 + T1)) | tmp;
+    } else
+       T0 = T1;
+    RETURN();
+}
+
+void op_dsllv (void)
+{
+    T0 = T1 << (T0 & 0x3F);
+    RETURN();
+}
+
+void op_dsrav (void)
+{
+    T0 = (int64_t)T1 >> (T0 & 0x3F);
+    RETURN();
+}
+
+void op_dsrlv (void)
+{
+    T0 = T1 >> (T0 & 0x3F);
+    RETURN();
+}
+
+void op_drotrv (void)
+{
+    target_ulong tmp;
+
+    T0 &= 0x3F;
+    if (T0) {
+       tmp = T1 << (0x40 - T0);
+       T0 = (T1 >> T0) | tmp;
+    } else
+       T0 = T1;
+    RETURN();
+}
+#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
+
+void op_dclo (void)
+{
+    int n;
+
+    if (T0 == ~((target_ulong)0)) {
+        T0 = 64;
+    } else {
+        for (n = 0; n < 64; n++) {
+            if (!(T0 & (1ULL << 63)))
+                break;
+            T0 = T0 << 1;
+        }
+        T0 = n;
+    }
+    RETURN();
+}
+
+void op_dclz (void)
+{
+    int n;
+
+    if (T0 == 0) {
+        T0 = 64;
+    } else {
+        for (n = 0; n < 64; n++) {
+            if (T0 & (1ULL << 63))
+                break;
+            T0 = T0 << 1;
+        }
+        T0 = n;
+    }
+    RETURN();
+}
+#endif
+
+/* 64 bits arithmetic */
+#if TARGET_LONG_BITS > HOST_LONG_BITS
 void op_mult (void)
 {
     CALL_FROM_TB0(do_mult);
@@ -610,6 +832,81 @@ void op_msubu (void)
     CALL_FROM_TB0(do_msubu);
     RETURN();
 }
+
+#else /* TARGET_LONG_BITS > HOST_LONG_BITS */
+
+static inline uint64_t get_HILO (void)
+{
+    return ((uint64_t)env->HI << 32) | ((uint64_t)(uint32_t)env->LO);
+}
+
+static inline void set_HILO (uint64_t HILO)
+{
+    env->LO = SIGN_EXTEND32(HILO & 0xFFFFFFFF);
+    env->HI = SIGN_EXTEND32(HILO >> 32);
+}
+
+void op_mult (void)
+{
+    set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    RETURN();
+}
+
+void op_multu (void)
+{
+    set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    RETURN();
+}
+
+void op_madd (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    set_HILO((int64_t)get_HILO() + tmp);
+    RETURN();
+}
+
+void op_maddu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    set_HILO(get_HILO() + tmp);
+    RETURN();
+}
+
+void op_msub (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    set_HILO((int64_t)get_HILO() - tmp);
+    RETURN();
+}
+
+void op_msubu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    set_HILO(get_HILO() - tmp);
+    RETURN();
+}
+#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
+
+#ifdef MIPS_HAS_MIPS64
+void op_dmult (void)
+{
+    CALL_FROM_TB0(do_dmult);
+    RETURN();
+}
+
+void op_dmultu (void)
+{
+    CALL_FROM_TB0(do_dmultu);
+    RETURN();
+}
 #endif
 
 /* Conditional moves */
@@ -735,7 +1032,7 @@ void op_jnz_T2 (void)
 /* CP0 functions */
 void op_mfc0_index (void)
 {
-    T0 = env->CP0_index;
+    T0 = SIGN_EXTEND32(env->CP0_index);
     RETURN();
 }
 
@@ -765,25 +1062,25 @@ void op_mfc0_context (void)
 
 void op_mfc0_pagemask (void)
 {
-    T0 = env->CP0_PageMask;
+    T0 = SIGN_EXTEND32(env->CP0_PageMask);
     RETURN();
 }
 
 void op_mfc0_pagegrain (void)
 {
-    T0 = env->CP0_PageGrain;
+    T0 = SIGN_EXTEND32(env->CP0_PageGrain);
     RETURN();
 }
 
 void op_mfc0_wired (void)
 {
-    T0 = env->CP0_Wired;
+    T0 = SIGN_EXTEND32(env->CP0_Wired);
     RETURN();
 }
 
 void op_mfc0_hwrena (void)
 {
-    T0 = env->CP0_HWREna;
+    T0 = SIGN_EXTEND32(env->CP0_HWREna);
     RETURN();
 }
 
@@ -807,13 +1104,13 @@ void op_mfc0_entryhi (void)
 
 void op_mfc0_compare (void)
 {
-    T0 = env->CP0_Compare;
+    T0 = SIGN_EXTEND32(env->CP0_Compare);
     RETURN();
 }
 
 void op_mfc0_status (void)
 {
-    T0 = env->CP0_Status;
+    T0 = SIGN_EXTEND32(env->CP0_Status);
     if (env->hflags & MIPS_HFLAG_UM)
         T0 |= (1 << CP0St_UM);
     if (env->hflags & MIPS_HFLAG_ERL)
@@ -825,19 +1122,19 @@ void op_mfc0_status (void)
 
 void op_mfc0_intctl (void)
 {
-    T0 = env->CP0_IntCtl;
+    T0 = SIGN_EXTEND32(env->CP0_IntCtl);
     RETURN();
 }
 
 void op_mfc0_srsctl (void)
 {
-    T0 = env->CP0_SRSCtl;
+    T0 = SIGN_EXTEND32(env->CP0_SRSCtl);
     RETURN();
 }
 
 void op_mfc0_cause (void)
 {
-    T0 = env->CP0_Cause;
+    T0 = SIGN_EXTEND32(env->CP0_Cause);
     RETURN();
 }
 
@@ -849,7 +1146,7 @@ void op_mfc0_epc (void)
 
 void op_mfc0_prid (void)
 {
-    T0 = env->CP0_PRid;
+    T0 = SIGN_EXTEND32(env->CP0_PRid);
     RETURN();
 }
 
@@ -861,25 +1158,25 @@ void op_mfc0_ebase (void)
 
 void op_mfc0_config0 (void)
 {
-    T0 = env->CP0_Config0;
+    T0 = SIGN_EXTEND32(env->CP0_Config0);
     RETURN();
 }
 
 void op_mfc0_config1 (void)
 {
-    T0 = env->CP0_Config1;
+    T0 = SIGN_EXTEND32(env->CP0_Config1);
     RETURN();
 }
 
 void op_mfc0_config2 (void)
 {
-    T0 = env->CP0_Config2;
+    T0 = SIGN_EXTEND32(env->CP0_Config2);
     RETURN();
 }
 
 void op_mfc0_config3 (void)
 {
-    T0 = env->CP0_Config3;
+    T0 = SIGN_EXTEND32(env->CP0_Config3);
     RETURN();
 }
 
@@ -891,13 +1188,13 @@ void op_mfc0_lladdr (void)
 
 void op_mfc0_watchlo0 (void)
 {
-    T0 = env->CP0_WatchLo;
+    T0 = SIGN_EXTEND32(env->CP0_WatchLo);
     RETURN();
 }
 
 void op_mfc0_watchhi0 (void)
 {
-    T0 = env->CP0_WatchHi;
+    T0 = SIGN_EXTEND32(env->CP0_WatchHi);
     RETURN();
 }
 
@@ -915,7 +1212,7 @@ void op_mfc0_framemask (void)
 
 void op_mfc0_debug (void)
 {
-    T0 = env->CP0_Debug;
+    T0 = SIGN_EXTEND32(env->CP0_Debug);
     if (env->hflags & MIPS_HFLAG_DM)
         T0 |= 1 << CP0DB_DM;
     RETURN();
@@ -929,31 +1226,31 @@ void op_mfc0_depc (void)
 
 void op_mfc0_performance0 (void)
 {
-    T0 = env->CP0_Performance0;
+    T0 = SIGN_EXTEND32(env->CP0_Performance0);
     RETURN();
 }
 
 void op_mfc0_taglo (void)
 {
-    T0 = env->CP0_TagLo;
+    T0 = SIGN_EXTEND32(env->CP0_TagLo);
     RETURN();
 }
 
 void op_mfc0_datalo (void)
 {
-    T0 = env->CP0_DataLo;
+    T0 = SIGN_EXTEND32(env->CP0_DataLo);
     RETURN();
 }
 
 void op_mfc0_taghi (void)
 {
-    T0 = env->CP0_TagHi;
+    T0 = SIGN_EXTEND32(env->CP0_TagHi);
     RETURN();
 }
 
 void op_mfc0_datahi (void)
 {
-    T0 = env->CP0_DataHi;
+    T0 = SIGN_EXTEND32(env->CP0_DataHi);
     RETURN();
 }
 
@@ -965,7 +1262,7 @@ void op_mfc0_errorepc (void)
 
 void op_mfc0_desave (void)
 {
-    T0 = env->CP0_DESAVE;
+    T0 = SIGN_EXTEND32(env->CP0_DESAVE);
     RETURN();
 }
 
@@ -979,7 +1276,7 @@ void op_mtc0_entrylo0 (void)
 {
     /* Large physaddr not implemented */
     /* 1k pages not implemented */
-    env->CP0_EntryLo0 = T0 & 0x3FFFFFFFUL;
+    env->CP0_EntryLo0 = T0 & SIGN_EXTEND32(0x3FFFFFFFUL);
     RETURN();
 }
 
@@ -987,7 +1284,7 @@ void op_mtc0_entrylo1 (void)
 {
     /* Large physaddr not implemented */
     /* 1k pages not implemented */
-    env->CP0_EntryLo1 = T0 & 0x3FFFFFFFUL;
+    env->CP0_EntryLo1 = T0 & SIGN_EXTEND32(0x3FFFFFFFUL);
     RETURN();
 }
 
@@ -1037,7 +1334,7 @@ void op_mtc0_entryhi (void)
 
     /* 1k pages not implemented */
     /* Ignore MIPS64 TLB for now */
-    val = T0 & 0xFFFFE0FF;
+    val = T0 & SIGN_EXTEND32(0xFFFFE0FF);
     old = env->CP0_EntryHi;
     env->CP0_EntryHi = val;
     /* If the ASID changes, flush qemu's TLB.  */
@@ -1056,7 +1353,7 @@ void op_mtc0_status (void)
 {
     uint32_t val, old, mask;
 
-    val = T0 & 0xFA78FF01;
+    val = T0 & SIGN_EXTEND32(0xFA78FF01);
     old = env->CP0_Status;
     if (T0 & (1 << CP0St_UM))
         env->hflags |= MIPS_HFLAG_UM;
@@ -1107,7 +1404,7 @@ void op_mtc0_cause (void)
 {
     uint32_t val, old;
 
-    val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
+    val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300);
     old = env->CP0_Cause;
     env->CP0_Cause = val;
 #if 0
@@ -1134,7 +1431,7 @@ void op_mtc0_ebase (void)
 {
     /* vectored interrupts not implemented */
     /* Multi-CPU not implemented */
-    env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000);
+    env->CP0_EBase = SIGN_EXTEND32(0x80000000) | (T0 & 0x3FFFF000);
     RETURN();
 }
 
@@ -1204,7 +1501,7 @@ void op_mtc0_performance0 (void)
 
 void op_mtc0_taglo (void)
 {
-    env->CP0_TagLo = T0 & 0xFFFFFCF6;
+    env->CP0_TagLo = T0 & SIGN_EXTEND32(0xFFFFFCF6);
     RETURN();
 }
 
@@ -1787,7 +2084,7 @@ void op_ext(void)
     unsigned int pos = PARAM1;
     unsigned int size = PARAM2;
 
-    T0 = (T1 >> pos) & ((1 << size) - 1);
+    T0 = ((uint32_t)T1 >> pos) & ((1 << size) - 1);
     RETURN();
 }
 
@@ -1797,7 +2094,7 @@ void op_ins(void)
     unsigned int size = PARAM2;
     target_ulong mask = ((1 << size) - 1) << pos;
 
-    T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+    T0 = (T2 & ~mask) | (((uint32_t)T1 << pos) & mask);
     RETURN();
 }
 
@@ -1807,6 +2104,26 @@ void op_wsbh(void)
     RETURN();
 }
 
+#ifdef MIPS_HAS_MIPS64
+void op_dext(void)
+{
+    unsigned int pos = PARAM1;
+    unsigned int size = PARAM2;
+
+    T0 = (T1 >> pos) & ((1 << size) - 1);
+    RETURN();
+}
+
+void op_dins(void)
+{
+    unsigned int pos = PARAM1;
+    unsigned int size = PARAM2;
+    target_ulong mask = ((1 << size) - 1) << pos;
+
+    T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+    RETURN();
+}
+
 void op_dsbh(void)
 {
     T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 0x00FF00FF00FF00FFULL);
@@ -1818,6 +2135,7 @@ void op_dshd(void)
     T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL);
     RETURN();
 }
+#endif
 
 void op_seb(void)
 {
index 87a043d..b719f03 100644 (file)
@@ -74,8 +74,92 @@ void do_raise_exception_direct (uint32_t exception)
 #undef MEMSUFFIX
 #endif
 
+#ifdef MIPS_HAS_MIPS64
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+/* Those might call libgcc functions.  */
+void do_dsll (void)
+{
+    T0 = T0 << T1;
+}
+
+void do_dsll32 (void)
+{
+    T0 = T0 << (T1 + 32);
+}
+
+void do_dsra (void)
+{
+    T0 = (int64_t)T0 >> T1;
+}
+
+void do_dsra32 (void)
+{
+    T0 = (int64_t)T0 >> (T1 + 32);
+}
+
+void do_dsrl (void)
+{
+    T0 = T0 >> T1;
+}
+
+void do_dsrl32 (void)
+{
+    T0 = T0 >> (T1 + 32);
+}
+
+void do_drotr (void)
+{
+    target_ulong tmp;
+
+    if (T1) {
+       tmp = T0 << (0x40 - T1);
+       T0 = (T0 >> T1) | tmp;
+    } else
+       T0 = T1;
+}
+
+void do_drotr32 (void)
+{
+    target_ulong tmp;
+
+    if (T1) {
+       tmp = T0 << (0x40 - (32 + T1));
+       T0 = (T0 >> (32 + T1)) | tmp;
+    } else
+       T0 = T1;
+}
+
+void do_dsllv (void)
+{
+    T0 = T1 << (T0 & 0x3F);
+}
+
+void do_dsrav (void)
+{
+    T0 = (int64_t)T1 >> (T0 & 0x3F);
+}
+
+void do_dsrlv (void)
+{
+    T0 = T1 >> (T0 & 0x3F);
+}
+
+void do_drotrv (void)
+{
+    target_ulong tmp;
+
+    T0 &= 0x3F;
+    if (T0) {
+       tmp = T1 << (0x40 - T0);
+       T0 = (T1 >> T0) | tmp;
+    } else
+       T0 = T1;
+}
+#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
+#endif /* MIPS_HAS_MIPS64 */
+
 /* 64 bits arithmetic for 32 bits hosts */
-#if (HOST_LONG_BITS == 32)
+#if TARGET_LONG_BITS > HOST_LONG_BITS
 static inline uint64_t get_HILO (void)
 {
     return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
@@ -83,8 +167,8 @@ static inline uint64_t get_HILO (void)
 
 static inline void set_HILO (uint64_t HILO)
 {
-    env->LO = HILO & 0xFFFFFFFF;
-    env->HI = HILO >> 32;
+    env->LO = SIGN_EXTEND32(HILO & 0xFFFFFFFF);
+    env->HI = SIGN_EXTEND32(HILO >> 32);
 }
 
 void do_mult (void)
@@ -94,7 +178,7 @@ void do_mult (void)
 
 void do_multu (void)
 {
-    set_HILO((uint64_t)T0 * (uint64_t)T1);
+    set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
 }
 
 void do_madd (void)
@@ -109,7 +193,7 @@ void do_maddu (void)
 {
     uint64_t tmp;
 
-    tmp = ((uint64_t)T0 * (uint64_t)T1);
+    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
     set_HILO(get_HILO() + tmp);
 }
 
@@ -125,11 +209,41 @@ void do_msubu (void)
 {
     uint64_t tmp;
 
-    tmp = ((uint64_t)T0 * (uint64_t)T1);
+    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
     set_HILO(get_HILO() - tmp);
 }
 #endif
 
+#ifdef MIPS_HAS_MIPS64
+void do_dmult (void)
+{
+    /* XXX */
+    set_HILO((int64_t)T0 * (int64_t)T1);
+}
+
+void do_dmultu (void)
+{
+    /* XXX */
+    set_HILO((uint64_t)T0 * (uint64_t)T1);
+}
+
+void do_ddiv (void)
+{
+    if (T1 != 0) {
+        env->LO = (int64_t)T0 / (int64_t)T1;
+        env->HI = (int64_t)T0 % (int64_t)T1;
+    }
+}
+
+void do_ddivu (void)
+{
+    if (T1 != 0) {
+        env->LO = T0 / T1;
+        env->HI = T0 % T1;
+    }
+}
+#endif
+
 #if defined(CONFIG_USER_ONLY) 
 void do_mfc0_random (void)
 {
@@ -191,12 +305,12 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global)
 /* CP0 helpers */
 void do_mfc0_random (void)
 {
-    T0 = cpu_mips_get_random(env);
+    T0 = SIGN_EXTEND32(cpu_mips_get_random(env));
 }
 
 void do_mfc0_count (void)
 {
-    T0 = cpu_mips_get_count(env);
+    T0 = SIGN_EXTEND32(cpu_mips_get_count(env));
 }
 
 void do_mtc0_status_debug(uint32_t old, uint32_t val)
@@ -319,7 +433,7 @@ static void fill_tlb (int idx)
 
     /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
     tlb = &env->tlb[idx];
-    tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
+    tlb->VPN = env->CP0_EntryHi & SIGN_EXTEND32(0xFFFFE000);
     tlb->ASID = env->CP0_EntryHi & 0xFF;
     size = env->CP0_PageMask >> 13;
     size = 4 * (size + 1);
@@ -364,7 +478,7 @@ void do_tlbp (void)
     uint8_t ASID;
     int i;
 
-    tag = env->CP0_EntryHi & 0xFFFFE000;
+    tag = env->CP0_EntryHi & SIGN_EXTEND32(0xFFFFE000);
     ASID = env->CP0_EntryHi & 0xFF;
     for (i = 0; i < MIPS_TLB_NB; i++) {
         tlb = &env->tlb[i];
@@ -418,16 +532,16 @@ void do_tlbr (void)
 
 #endif /* !CONFIG_USER_ONLY */
 
-void op_dump_ldst (const unsigned char *func)
+void dump_ldst (const unsigned char *func)
 {
     if (loglevel)
-        fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
+        fprintf(logfile, "%s => " TLSZ " " TLSZ "\n", __func__, T0, T1);
 }
 
 void dump_sc (void)
 {
     if (loglevel) {
-        fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
+        fprintf(logfile, "%s " TLSZ " at " TLSZ " (" TLSZ ")\n", __func__,
                 T1, T0, env->CP0_LLAddr);
     }
 }
@@ -435,7 +549,7 @@ void dump_sc (void)
 void debug_eret (void)
 {
     if (loglevel) {
-        fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
+        fprintf(logfile, "ERET: pc " TLSZ " EPC " TLSZ " ErrorEPC " TLSZ " (%d)\n",
                 env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
                 env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
     }
@@ -454,13 +568,13 @@ void do_pmon (int function)
         break;
     case 3:
     case 12:
-        printf("%c", env->gpr[4] & 0xFF);
+        printf("%c", (char)(env->gpr[4] & 0xFF));
         break;
     case 17:
         break;
     case 158:
         {
-            unsigned char *fmt = (void *)env->gpr[4];
+            unsigned char *fmt = (void *)(unsigned long)env->gpr[4];
             printf("%s", fmt);
         }
         break;
index 4711f7a..e8ec22b 100644 (file)
@@ -10,9 +10,6 @@ void glue(do_lwl, MEMSUFFIX) (uint32_t tmp)
     target_ulong sav = T0;
 #endif
 
-    /* XXX: this is valid only in big-endian mode
-     *      should be reverted for little-endian...
-     */
     switch (GET_LMASK(T0)) {
     case 0:
         T0 = tmp;
@@ -42,9 +39,6 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp)
     target_ulong sav = T0;
 #endif
 
-    /* XXX: this is valid only in big-endian mode
-     *      should be reverted for little-endian...
-     */
     switch (GET_LMASK(T0)) {
     case 0:
         T0 = (tmp >> 24) | (T1 & 0xFFFFFF00);
@@ -71,15 +65,9 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp)
 uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp)
 {
 #if defined (DEBUG_OP)
-    target_ulong sav;
+    target_ulong sav = tmp;
 #endif
 
-#if defined (DEBUG_OP)
-    sav = tmp;
-#endif
-    /* XXX: this is valid only in big-endian mode
-     *      should be reverted for little-endian...
-     */
     switch (GET_LMASK(T0)) {
     case 0:
         tmp = T1;
@@ -107,15 +95,9 @@ uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp)
 uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp)
 {
 #if defined (DEBUG_OP)
-    target_ulong sav;
+    target_ulong sav = tmp;
 #endif
 
-#if defined (DEBUG_OP)
-    sav = tmp;
-#endif
-    /* XXX: this is valid only in big-endian mode
-     *      should be reverted for little-endian...
-     */
     switch (GET_LMASK(T0)) {
     case 0:
         tmp = (tmp & 0x00FFFFFF) | (T1 << 24);
@@ -139,3 +121,179 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp)
     RETURN();
     return tmp;
 }
+
+#ifdef MIPS_HAS_MIPS64
+
+# ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK64(v) ((v) & 4)
+#else
+#define GET_LMASK64(v) (((v) & 4) ^ 4)
+#endif
+
+void glue(do_ldl, MEMSUFFIX) (uint64_t tmp)
+{
+#if defined (DEBUG_OP)
+    target_ulong sav = T0;
+#endif
+
+    switch (GET_LMASK64(T0)) {
+    case 0:
+        T0 = tmp;
+        break;
+    case 1:
+        T0 = (tmp << 8) | (T1 & 0x00000000000000FFULL);
+        break;
+    case 2:
+        T0 = (tmp << 16) | (T1 & 0x000000000000FFFFULL);
+        break;
+    case 3:
+        T0 = (tmp << 24) | (T1 & 0x0000000000FFFFFFULL);
+        break;
+    case 4:
+        T0 = (tmp << 32) | (T1 & 0x00000000FFFFFFFFULL);
+        break;
+    case 5:
+        T0 = (tmp << 40) | (T1 & 0x000000FFFFFFFFFFULL);
+        break;
+    case 6:
+        T0 = (tmp << 48) | (T1 & 0x0000FFFFFFFFFFFFULL);
+        break;
+    case 7:
+        T0 = (tmp << 56) | (T1 & 0x00FFFFFFFFFFFFFFULL);
+        break;
+    }
+#if defined (DEBUG_OP)
+    if (logfile) {
+        fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
+                __func__, sav, tmp, T1, T0);
+    }
+#endif
+    RETURN();
+}
+
+void glue(do_ldr, MEMSUFFIX) (uint64_t tmp)
+{
+#if defined (DEBUG_OP)
+    target_ulong sav = T0;
+#endif
+
+    switch (GET_LMASK64(T0)) {
+    case 0:
+        T0 = (tmp >> 56) | (T1 & 0xFFFFFFFFFFFFFF00ULL);
+        break;
+    case 1:
+        T0 = (tmp >> 48) | (T1 & 0xFFFFFFFFFFFF0000ULL);
+        break;
+    case 2:
+        T0 = (tmp >> 40) | (T1 & 0xFFFFFFFFFF000000ULL);
+        break;
+    case 3:
+        T0 = (tmp >> 32) | (T1 & 0xFFFFFFFF00000000ULL);
+        break;
+    case 4:
+        T0 = (tmp >> 24) | (T1 & 0xFFFFFF0000000000ULL);
+        break;
+    case 5:
+        T0 = (tmp >> 16) | (T1 & 0xFFFF000000000000ULL);
+        break;
+    case 6:
+        T0 = (tmp >> 8) | (T1 & 0xFF00000000000000ULL);
+        break;
+    case 7:
+        T0 = tmp;
+        break;
+    }
+#if defined (DEBUG_OP)
+    if (logfile) {
+        fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
+                __func__, sav, tmp, T1, T0);
+    }
+#endif
+    RETURN();
+}
+
+uint64_t glue(do_sdl, MEMSUFFIX) (uint64_t tmp)
+{
+#if defined (DEBUG_OP)
+    target_ulong sav = tmp;
+#endif
+
+    switch (GET_LMASK64(T0)) {
+    case 0:
+        tmp = T1;
+        break;
+    case 1:
+        tmp = (tmp & 0xFF00000000000000ULL) | (T1 >> 8);
+        break;
+    case 2:
+        tmp = (tmp & 0xFFFF000000000000ULL) | (T1 >> 16);
+        break;
+    case 3:
+        tmp = (tmp & 0xFFFFFF0000000000ULL) | (T1 >> 24);
+        break;
+    case 4:
+        tmp = (tmp & 0xFFFFFFFF00000000ULL) | (T1 >> 32);
+        break;
+    case 5:
+        tmp = (tmp & 0xFFFFFFFFFF000000ULL) | (T1 >> 40);
+        break;
+    case 6:
+        tmp = (tmp & 0xFFFFFFFFFFFF0000ULL) | (T1 >> 48);
+        break;
+    case 7:
+        tmp = (tmp & 0xFFFFFFFFFFFFFF00ULL) | (T1 >> 56);
+        break;
+    }
+#if defined (DEBUG_OP)
+    if (logfile) {
+        fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
+                __func__, T0, sav, T1, tmp);
+    }
+#endif
+    RETURN();
+    return tmp;
+}
+
+uint64_t glue(do_sdr, MEMSUFFIX) (uint64_t tmp)
+{
+#if defined (DEBUG_OP)
+    target_ulong sav = tmp;
+#endif
+
+    switch (GET_LMASK64(T0)) {
+    case 0:
+        tmp = (tmp & 0x00FFFFFFFFFFFFFFULL) | (T1 << 56);
+        break;
+    case 1:
+        tmp = (tmp & 0x0000FFFFFFFFFFFFULL) | (T1 << 48);
+        break;
+    case 2:
+        tmp = (tmp & 0x000000FFFFFFFFFFULL) | (T1 << 40);
+        break;
+    case 3:
+        tmp = (tmp & 0x00000000FFFFFFFFULL) | (T1 << 32);
+        break;
+    case 4:
+        tmp = (tmp & 0x0000000000FFFFFFULL) | (T1 << 24);
+        break;
+    case 5:
+        tmp = (tmp & 0x000000000000FFFFULL) | (T1 << 16);
+        break;
+    case 6:
+        tmp = (tmp & 0x00000000000000FFULL) | (T1 << 8);
+        break;
+    case 7:
+        tmp = T1;
+        break;
+    }
+#if defined (DEBUG_OP)
+    if (logfile) {
+        fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
+                __func__, T0, sav, T1, tmp);
+    }
+#endif
+    RETURN();
+    return tmp;
+}
+
+#endif /* MIPS_HAS_MIPS64 */
index 35ccd44..a328979 100644 (file)
@@ -75,6 +75,7 @@ void glue(op_sw, MEMSUFFIX) (void)
 
 /* "half" load and stores.  We must do the memory access inline,
    or fault handling won't work.  */
+/* XXX: This is broken, CP0_BADVADDR has the wrong (aligned) value. */
 void glue(op_lwl, MEMSUFFIX) (void)
 {
     uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
@@ -125,6 +126,72 @@ void glue(op_sc, MEMSUFFIX) (void)
     RETURN();
 }
 
+#ifdef MIPS_HAS_MIPS64
+void glue(op_ld, MEMSUFFIX) (void)
+{
+    T0 = glue(ldq, MEMSUFFIX)(T0);
+    RETURN();
+}
+
+void glue(op_sd, MEMSUFFIX) (void)
+{
+    glue(stq, MEMSUFFIX)(T0, T1);
+    RETURN();
+}
+
+/* "half" load and stores.  We must do the memory access inline,
+   or fault handling won't work.  */
+void glue(op_ldl, MEMSUFFIX) (void)
+{
+    target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7);
+    CALL_FROM_TB1(glue(do_ldl, MEMSUFFIX), tmp);
+    RETURN();
+}
+
+void glue(op_ldr, MEMSUFFIX) (void)
+{
+    target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7);
+    CALL_FROM_TB1(glue(do_ldr, MEMSUFFIX), tmp);
+    RETURN();
+}
+
+void glue(op_sdl, MEMSUFFIX) (void)
+{
+    target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7);
+    tmp = CALL_FROM_TB1(glue(do_sdl, MEMSUFFIX), tmp);
+    glue(stq, MEMSUFFIX)(T0 & ~7, tmp);
+    RETURN();
+}
+
+void glue(op_sdr, MEMSUFFIX) (void)
+{
+    target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7);
+    tmp = CALL_FROM_TB1(glue(do_sdr, MEMSUFFIX), tmp);
+    glue(stq, MEMSUFFIX)(T0 & ~7, tmp);
+    RETURN();
+}
+
+void glue(op_lld, MEMSUFFIX) (void)
+{
+    T1 = T0;
+    T0 = glue(ldq, MEMSUFFIX)(T0);
+    env->CP0_LLAddr = T1;
+    RETURN();
+}
+
+void glue(op_scd, MEMSUFFIX) (void)
+{
+    CALL_FROM_TB0(dump_sc);
+    if (T0 == env->CP0_LLAddr) {
+        glue(stq, MEMSUFFIX)(T0, T1);
+        T0 = 1;
+    } else {
+        T0 = 0;
+    }
+    RETURN();
+}
+#endif /* MIPS_HAS_MIPS64 */
+
 #ifdef MIPS_USES_FPU
 void glue(op_lwc1, MEMSUFFIX) (void)
 {
index 9314c95..8d4c4e4 100644 (file)
@@ -51,15 +51,21 @@ void glue(op_load_gpr_T2_gpr, REG) (void)
 #endif
 
 #if defined (TN)
-void glue(op_set_, TN) (void)
-{
-    TN = PARAM1;
-    RETURN();
-}
+#define SET_RESET(treg, tregname)        \
+    void glue(op_set, tregname)(void)    \
+    {                                    \
+        treg = PARAM1;                   \
+        RETURN();                        \
+    }                                    \
+    void glue(op_reset, tregname)(void)  \
+    {                                    \
+        treg = 0;                        \
+        RETURN();                        \
+    }                                    \
 
-void glue (op_reset_, TN) (void)
-{
-    TN = 0;
-    RETURN();
-}
+SET_RESET(T0, _T0)
+SET_RESET(T1, _T1)
+SET_RESET(T2, _T2)
+
+#undef SET_RESET
 #endif
index c9cbc9d..1252e81 100644 (file)
@@ -31,6 +31,7 @@
 #include "disas.h"
 
 //#define MIPS_DEBUG_DISAS
+//#define MIPS_DEBUG_SIGN_EXTENSIONS
 //#define MIPS_SINGLE_STEP
 
 #ifdef USE_DIRECT_JUMP
@@ -502,7 +503,7 @@ enum {
 #define MIPS_DEBUG(fmt, args...)                                              \
 do {                                                                          \
     if (loglevel & CPU_LOG_TB_IN_ASM) {                                       \
-        fprintf(logfile, "%08x: %08x " fmt "\n",                              \
+        fprintf(logfile, TLSZ ": %08x " fmt "\n",                             \
                 ctx->pc, ctx->opcode , ##args);                               \
     }                                                                         \
 } while (0)
@@ -621,6 +622,8 @@ OP_LD_TABLE(dr);
 OP_ST_TABLE(d);
 OP_ST_TABLE(dl);
 OP_ST_TABLE(dr);
+OP_LD_TABLE(ld);
+OP_ST_TABLE(cd);
 #endif
 OP_LD_TABLE(w);
 OP_LD_TABLE(wu);
@@ -1417,7 +1420,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
     case OPC_J:
     case OPC_JAL:
         /* Jump to immediate */
-        btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
+        btarget = ((ctx->pc + 4) & SIGN_EXTEND32(0xF0000000)) | offset;
         break;
     case OPC_JR:
     case OPC_JALR:
@@ -2927,21 +2930,21 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
     switch (op) {
     case OPC_BC1F:
         gen_op_bc1f();
-        MIPS_DEBUG("bc1f %08x", btarget);
+        MIPS_DEBUG("bc1f " TLSZ, btarget);
         goto not_likely;
     case OPC_BC1FL:
         gen_op_bc1f();
-        MIPS_DEBUG("bc1fl %08x", btarget);
+        MIPS_DEBUG("bc1fl " TLSZ, btarget);
         goto likely;
     case OPC_BC1T:
         gen_op_bc1t();
-        MIPS_DEBUG("bc1t %08x", btarget);
+        MIPS_DEBUG("bc1t " TLSZ, btarget);
     not_likely:
         ctx->hflags |= MIPS_HFLAG_BC;
         break;
     case OPC_BC1TL:
         gen_op_bc1t();
-        MIPS_DEBUG("bc1tl %08x", btarget);
+        MIPS_DEBUG("bc1tl " TLSZ, btarget);
     likely:
         ctx->hflags |= MIPS_HFLAG_BL;
         break;
@@ -2952,7 +2955,7 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
     }
     gen_op_set_bcond();
 
-    MIPS_DEBUG("enter ds: cond %02x target %08x",
+    MIPS_DEBUG("enter ds: cond %02x target " TLSZ,
                ctx->hflags, btarget);
     ctx->btarget = btarget;
 
@@ -3351,30 +3354,6 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
 /* SmartMIPS extension to MIPS32 */
 
 #ifdef MIPS_HAS_MIPS64
-static void gen_arith64 (DisasContext *ctx, uint32_t opc)
-{
-    if (func == 0x02 && rd == 0) {
-        /* NOP */
-        return;
-    }
-    if (rs == 0 || rt == 0) {
-        gen_op_reset_T0();
-        gen_op_save64();
-    } else {
-        gen_op_load_gpr_T0(rs);
-        gen_op_load_gpr_T1(rt);
-        gen_op_save64();
-        if (func & 0x01)
-            gen_op_mul64u();
-        else
-            gen_op_mul64s();
-    }
-    if (func & 0x02)
-        gen_op_add64();
-    else
-        gen_op_sub64();
-}
-
 /* Coprocessor 3 (FPU) */
 
 /* MDMX extension to MIPS64 */
@@ -3407,7 +3386,7 @@ static void decode_opc (DisasContext *ctx)
 
     if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
         /* Handle blikely not taken case */
-        MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
+        MIPS_DEBUG("blikely condition (" TLSZ ")", ctx->pc + 4);
         gen_blikely(ctx);
     }
     op = MASK_OP_MAJOR(ctx->opcode);
@@ -4011,7 +3990,7 @@ void fpu_dump_state(CPUState *env, FILE *f,
 void dump_fpu (CPUState *env)
 {
     if (loglevel) { 
-       fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
+       fprintf(logfile, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n",
                env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
        fpu_dump_state(env, logfile, fprintf, 0);
     }
@@ -4019,6 +3998,39 @@ void dump_fpu (CPUState *env)
 
 #endif /* MIPS_USES_FPU */
 
+#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
+/* Debug help: The architecture requires 32bit code to maintain proper
+   sign-extened values on 64bit machines.  */
+
+#define SIGN_EXT_P(val) ((((val) & ~0x7fffffff) == 0) || (((val) & ~0x7fffffff) == ~0x7fffffff))
+
+void cpu_mips_check_sign_extensions (CPUState *env, FILE *f,
+                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                     int flags)
+{
+    int i;
+
+    if (!SIGN_EXT_P(env->PC))
+        cpu_fprintf(f, "BROKEN: pc=0x" TLSZ "\n", env->PC);
+    if (!SIGN_EXT_P(env->HI))
+        cpu_fprintf(f, "BROKEN: HI=0x" TLSZ "\n", env->HI);
+    if (!SIGN_EXT_P(env->LO))
+        cpu_fprintf(f, "BROKEN: LO=0x" TLSZ "\n", env->LO);
+    if (!SIGN_EXT_P(env->btarget))
+        cpu_fprintf(f, "BROKEN: btarget=0x" TLSZ "\n", env->btarget);
+
+    for (i = 0; i < 32; i++) {
+        if (!SIGN_EXT_P(env->gpr[i]))
+            cpu_fprintf(f, "BROKEN: %s=0x" TLSZ "\n", regnames[i], env->gpr[i]);
+    }
+
+    if (!SIGN_EXT_P(env->CP0_EPC))
+        cpu_fprintf(f, "BROKEN: EPC=0x" TLSZ "\n", env->CP0_EPC);
+    if (!SIGN_EXT_P(env->CP0_LLAddr))
+        cpu_fprintf(f, "BROKEN: LLAddr=0x" TLSZ "\n", env->CP0_LLAddr);
+}
+#endif
+
 void cpu_dump_state (CPUState *env, FILE *f, 
                      int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                      int flags)
@@ -4026,12 +4038,12 @@ void cpu_dump_state (CPUState *env, FILE *f,
     uint32_t c0_status;
     int i;
     
-    cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
+    cpu_fprintf(f, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n",
                 env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
     for (i = 0; i < 32; i++) {
         if ((i & 3) == 0)
             cpu_fprintf(f, "GPR%02d:", i);
-        cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
+        cpu_fprintf(f, " %s " TLSZ, regnames[i], env->gpr[i]);
         if ((i & 3) == 3)
             cpu_fprintf(f, "\n");
     }
@@ -4044,14 +4056,17 @@ void cpu_dump_state (CPUState *env, FILE *f,
     if (env->hflags & MIPS_HFLAG_EXL)
         c0_status |= (1 << CP0St_EXL);
 
-    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x%08x\n",
+    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x" TLSZ "\n",
                 c0_status, env->CP0_Cause, env->CP0_EPC);
-    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
+    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x" TLSZ "\n",
                 env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
 #ifdef MIPS_USES_FPU
     if (c0_status & (1 << CP0St_CU1))
         fpu_dump_state(env, f, cpu_fprintf, flags);
 #endif
+#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
+    cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags);
+#endif
 }
 
 CPUMIPSState *cpu_mips_init (void)
@@ -4082,14 +4097,14 @@ void cpu_reset (CPUMIPSState *env)
     } else {
         env->CP0_ErrorEPC = env->PC;
     }
-    env->PC = 0xBFC00000;
+    env->PC = SIGN_EXTEND32(0xBFC00000);
 #if defined (MIPS_USES_R4K_TLB)
     env->CP0_random = MIPS_TLB_NB - 1;
     env->tlb_in_use = MIPS_TLB_NB;
 #endif
     env->CP0_Wired = 0;
     /* SMP not implemented */
-    env->CP0_EBase = 0x80000000;
+    env->CP0_EBase = SIGN_EXTEND32(0x80000000);
     env->CP0_Config0 = MIPS_CONFIG0;
     env->CP0_Config1 = MIPS_CONFIG1;
     env->CP0_Config2 = MIPS_CONFIG2;