From: ths Date: Thu, 21 Dec 2006 01:19:56 +0000 (+0000) Subject: Preliminiary MIPS64 support, disabled by default due to performance impact. X-Git-Tag: TizenStudio_2.0_p2.3~13970 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c570fd169c16f110781f31e0e963542a15229ee9;p=sdk%2Femulator%2Fqemu.git Preliminiary MIPS64 support, disabled by default due to performance impact. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2250 c046a42c-6fe2-441c-8c8c-71466251a162 --- diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 61db814..ca3a4ff 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -11,10 +11,10 @@ #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); diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 46436cd..710748c 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -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; diff --git a/target-mips/exec.h b/target-mips/exec.h index 817ef03..9e1fcdc 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -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); diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c index bc0a6e0..4ebb46b 100644 --- a/target-mips/fop_template.c +++ b/target-mips/fop_template.c @@ -96,4 +96,5 @@ SET_RESET(DT0, _DT0) SET_RESET(DT1, _DT1) SET_RESET(DT2, _DT2) +#undef SET_RESET #endif diff --git a/target-mips/helper.c b/target-mips/helper.c index a0a56d8..0e3eb6c 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -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); diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 14d1438..83480c6 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -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 */ @@ -79,8 +80,14 @@ #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__) */ diff --git a/target-mips/op.c b/target-mips/op.c index 35a1365..4b6c20c 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -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) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 87a043d..b719f03 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -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; diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index 4711f7a..e8ec22b 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -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 */ diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index 35ccd44..a328979 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -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) { diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 9314c95..8d4c4e4 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -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 diff --git a/target-mips/translate.c b/target-mips/translate.c index c9cbc9d..1252e81 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -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;