提交 c570fd16 编写于 作者: T ths

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
上级 328a4240
...@@ -11,10 +11,10 @@ ...@@ -11,10 +11,10 @@
#define BIOS_FILENAME "mips_bios.bin" #define BIOS_FILENAME "mips_bios.bin"
//#define BIOS_FILENAME "system.bin" //#define BIOS_FILENAME "system.bin"
#define KERNEL_LOAD_ADDR 0x80010000 #define KERNEL_LOAD_ADDR SIGN_EXTEND32(0x80010000)
#define INITRD_LOAD_ADDR 0x80800000 #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_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 };
...@@ -74,9 +74,11 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, ...@@ -74,9 +74,11 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
long kernel_size, initrd_size; long kernel_size, initrd_size;
kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); 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; env->PC = entry;
else { } else {
kernel_size = load_image(kernel_filename, kernel_size = load_image(kernel_filename,
phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
if (kernel_size < 0) { if (kernel_size < 0) {
...@@ -103,7 +105,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, ...@@ -103,7 +105,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
if (initrd_size > 0) { if (initrd_size > 0) {
int ret; int ret;
ret = sprintf(phys_ram_base + (16 << 20) - 256, 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_LOAD_ADDR,
initrd_size); initrd_size);
strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline); strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline);
......
...@@ -15,6 +15,16 @@ typedef unsigned char uint_fast8_t; ...@@ -15,6 +15,16 @@ typedef unsigned char uint_fast8_t;
typedef unsigned int uint_fast16_t; typedef unsigned int uint_fast16_t;
#endif #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; typedef union fpr_t fpr_t;
union fpr_t { union fpr_t {
float64 fd; /* ieee double precision */ float64 fd; /* ieee double precision */
...@@ -55,7 +65,12 @@ struct CPUMIPSState { ...@@ -55,7 +65,12 @@ struct CPUMIPSState {
target_ulong gpr[32]; target_ulong gpr[32];
/* Special registers */ /* Special registers */
target_ulong PC; 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; /* ? */ uint32_t DCR; /* ? */
#if defined(MIPS_USES_FPU) #if defined(MIPS_USES_FPU)
/* Floating point registers */ /* Floating point registers */
...@@ -106,7 +121,7 @@ struct CPUMIPSState { ...@@ -106,7 +121,7 @@ struct CPUMIPSState {
uint32_t CP0_PageGrain; uint32_t CP0_PageGrain;
uint32_t CP0_Wired; uint32_t CP0_Wired;
uint32_t CP0_HWREna; uint32_t CP0_HWREna;
uint32_t CP0_BadVAddr; target_ulong CP0_BadVAddr;
uint32_t CP0_Count; uint32_t CP0_Count;
uint64_t CP0_EntryHi; uint64_t CP0_EntryHi;
uint32_t CP0_Compare; uint32_t CP0_Compare;
...@@ -145,9 +160,9 @@ struct CPUMIPSState { ...@@ -145,9 +160,9 @@ struct CPUMIPSState {
#define CP0Ca_WP 22 #define CP0Ca_WP 22
#define CP0Ca_IP 8 #define CP0Ca_IP 8
#define CP0Ca_EC 2 #define CP0Ca_EC 2
uint32_t CP0_EPC; target_ulong CP0_EPC;
uint32_t CP0_PRid; uint32_t CP0_PRid;
uint32_t CP0_EBase; target_ulong CP0_EBase;
uint32_t CP0_Config0; uint32_t CP0_Config0;
#define CP0C0_M 31 #define CP0C0_M 31
#define CP0C0_K23 28 #define CP0C0_K23 28
...@@ -197,7 +212,7 @@ struct CPUMIPSState { ...@@ -197,7 +212,7 @@ struct CPUMIPSState {
#define CP0C3_MT 2 #define CP0C3_MT 2
#define CP0C3_SM 1 #define CP0C3_SM 1
#define CP0C3_TL 0 #define CP0C3_TL 0
uint32_t CP0_LLAddr; target_ulong CP0_LLAddr;
uint32_t CP0_WatchLo; uint32_t CP0_WatchLo;
uint32_t CP0_WatchHi; uint32_t CP0_WatchHi;
uint32_t CP0_XContext; uint32_t CP0_XContext;
...@@ -221,13 +236,13 @@ struct CPUMIPSState { ...@@ -221,13 +236,13 @@ struct CPUMIPSState {
#define CP0DB_DDBL 2 #define CP0DB_DDBL 2
#define CP0DB_DBp 1 #define CP0DB_DBp 1
#define CP0DB_DSS 0 #define CP0DB_DSS 0
uint32_t CP0_DEPC; target_ulong CP0_DEPC;
uint32_t CP0_Performance0; uint32_t CP0_Performance0;
uint32_t CP0_TagLo; uint32_t CP0_TagLo;
uint32_t CP0_DataLo; uint32_t CP0_DataLo;
uint32_t CP0_TagHi; uint32_t CP0_TagHi;
uint32_t CP0_DataHi; uint32_t CP0_DataHi;
uint32_t CP0_ErrorEPC; target_ulong CP0_ErrorEPC;
uint32_t CP0_DESAVE; uint32_t CP0_DESAVE;
/* Qemu */ /* Qemu */
int interrupt_request; int interrupt_request;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
//#define DEBUG_OP //#define DEBUG_OP
#include "config.h"
#include "mips-defs.h" #include "mips-defs.h"
#include "dyngen-exec.h" #include "dyngen-exec.h"
...@@ -16,9 +17,15 @@ typedef int32_t host_int_t; ...@@ -16,9 +17,15 @@ typedef int32_t host_int_t;
typedef uint32_t host_uint_t; typedef uint32_t host_uint_t;
#endif #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 T0 asm(AREG1);
register host_uint_t T1 asm(AREG2); register host_uint_t T1 asm(AREG2);
register host_uint_t T2 asm(AREG3); register host_uint_t T2 asm(AREG3);
#endif
#if defined (USE_HOST_FLOAT_REGS) #if defined (USE_HOST_FLOAT_REGS)
#error "implement me." #error "implement me."
...@@ -58,13 +65,36 @@ static inline void regs_to_env(void) ...@@ -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_mult (void);
void do_multu (void); void do_multu (void);
void do_madd (void); void do_madd (void);
void do_maddu (void); void do_maddu (void);
void do_msub (void); void do_msub (void);
void do_msubu (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 #endif
void do_mfc0_random(void); void do_mfc0_random(void);
void do_mfc0_count(void); void do_mfc0_count(void);
...@@ -86,6 +116,12 @@ void do_lwl_raw (uint32_t); ...@@ -86,6 +116,12 @@ void do_lwl_raw (uint32_t);
void do_lwr_raw (uint32_t); void do_lwr_raw (uint32_t);
uint32_t do_swl_raw (uint32_t); uint32_t do_swl_raw (uint32_t);
uint32_t do_swr_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) #if !defined(CONFIG_USER_ONLY)
void do_lwl_user (uint32_t); void do_lwl_user (uint32_t);
void do_lwl_kernel (uint32_t); void do_lwl_kernel (uint32_t);
...@@ -95,6 +131,16 @@ uint32_t do_swl_user (uint32_t); ...@@ -95,6 +131,16 @@ uint32_t do_swl_user (uint32_t);
uint32_t do_swl_kernel (uint32_t); uint32_t do_swl_kernel (uint32_t);
uint32_t do_swr_user (uint32_t); uint32_t do_swr_user (uint32_t);
uint32_t do_swr_kernel (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 #endif
void do_pmon (int function); void do_pmon (int function);
......
...@@ -96,4 +96,5 @@ SET_RESET(DT0, _DT0) ...@@ -96,4 +96,5 @@ SET_RESET(DT0, _DT0)
SET_RESET(DT1, _DT1) SET_RESET(DT1, _DT1)
SET_RESET(DT2, _DT2) SET_RESET(DT2, _DT2)
#undef SET_RESET
#endif #endif
...@@ -86,7 +86,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, ...@@ -86,7 +86,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
#endif #endif
if (user_mode && address > 0x7FFFFFFFUL) if (user_mode && address > 0x7FFFFFFFUL)
return TLBRET_BADADDR; return TLBRET_BADADDR;
if (address < 0x80000000UL) { if (address < SIGN_EXTEND32(0x80000000UL)) {
if (!(env->hflags & MIPS_HFLAG_ERL)) { if (!(env->hflags & MIPS_HFLAG_ERL)) {
#ifdef MIPS_USES_R4K_TLB #ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type); ret = map_address(env, physical, prot, address, rw, access_type);
...@@ -98,17 +98,17 @@ static int get_physical_address (CPUState *env, target_ulong *physical, ...@@ -98,17 +98,17 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
*physical = address; *physical = address;
*prot = PAGE_READ | PAGE_WRITE; *prot = PAGE_READ | PAGE_WRITE;
} }
} else if (address < 0xA0000000UL) { } else if (address < SIGN_EXTEND32(0xA0000000UL)) {
/* kseg0 */ /* kseg0 */
/* XXX: check supervisor mode */ /* XXX: check supervisor mode */
*physical = address - 0x80000000UL; *physical = address - SIGN_EXTEND32(0x80000000UL);
*prot = PAGE_READ | PAGE_WRITE; *prot = PAGE_READ | PAGE_WRITE;
} else if (address < 0xC0000000UL) { } else if (address < SIGN_EXTEND32(0xC0000000UL)) {
/* kseg1 */ /* kseg1 */
/* XXX: check supervisor mode */ /* XXX: check supervisor mode */
*physical = address - 0xA0000000UL; *physical = address - SIGN_EXTEND32(0xA0000000UL);
*prot = PAGE_READ | PAGE_WRITE; *prot = PAGE_READ | PAGE_WRITE;
} else if (address < 0xE0000000UL) { } else if (address < SIGN_EXTEND32(0xE0000000UL)) {
/* kseg2 */ /* kseg2 */
#ifdef MIPS_USES_R4K_TLB #ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type); ret = map_address(env, physical, prot, address, rw, access_type);
...@@ -129,8 +129,8 @@ static int get_physical_address (CPUState *env, target_ulong *physical, ...@@ -129,8 +129,8 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
} }
#if 0 #if 0
if (logfile) { if (logfile) {
fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw, fprintf(logfile, TLSZ " %d %d => " TLSZ " %d (%d)\n",
access_type, *physical, *prot, ret); address, rw, access_type, *physical, *prot, ret);
} }
#endif #endif
...@@ -171,7 +171,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, ...@@ -171,7 +171,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
#if 0 #if 0
cpu_dump_state(env, logfile, fprintf, 0); cpu_dump_state(env, logfile, fprintf, 0);
#endif #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); __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, ...@@ -189,7 +189,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
ret = get_physical_address(env, &physical, &prot, ret = get_physical_address(env, &physical, &prot,
address, rw, access_type); address, rw, access_type);
if (logfile) { 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); __func__, address, ret, physical, prot);
} }
if (ret == TLBRET_MATCH) { if (ret == TLBRET_MATCH) {
...@@ -255,7 +255,7 @@ void do_interrupt (CPUState *env) ...@@ -255,7 +255,7 @@ void do_interrupt (CPUState *env)
int cause = -1; int cause = -1;
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { 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); __func__, env->PC, env->CP0_EPC, cause, env->exception_index);
} }
if (env->exception_index == EXCP_EXT_INTERRUPT && if (env->exception_index == EXCP_EXT_INTERRUPT &&
...@@ -299,7 +299,7 @@ void do_interrupt (CPUState *env) ...@@ -299,7 +299,7 @@ void do_interrupt (CPUState *env)
enter_debug_mode: enter_debug_mode:
env->hflags |= MIPS_HFLAG_DM; env->hflags |= MIPS_HFLAG_DM;
/* EJTAG probe trap enable is not implemented... */ /* EJTAG probe trap enable is not implemented... */
env->PC = 0xBFC00480; env->PC = SIGN_EXTEND32(0xBFC00480);
break; break;
case EXCP_RESET: case EXCP_RESET:
cpu_reset(env); cpu_reset(env);
...@@ -321,7 +321,7 @@ void do_interrupt (CPUState *env) ...@@ -321,7 +321,7 @@ void do_interrupt (CPUState *env)
} }
env->hflags |= MIPS_HFLAG_ERL; env->hflags |= MIPS_HFLAG_ERL;
env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
env->PC = 0xBFC00000; env->PC = SIGN_EXTEND32(0xBFC00000);
break; break;
case EXCP_MCHECK: case EXCP_MCHECK:
cause = 24; cause = 24;
...@@ -389,9 +389,9 @@ void do_interrupt (CPUState *env) ...@@ -389,9 +389,9 @@ void do_interrupt (CPUState *env)
env->CP0_Cause &= ~0x80000000; env->CP0_Cause &= ~0x80000000;
} }
if (env->CP0_Status & (1 << CP0St_BEV)) { if (env->CP0_Status & (1 << CP0St_BEV)) {
env->PC = 0xBFC00200; env->PC = SIGN_EXTEND32(0xBFC00200);
} else { } else {
env->PC = 0x80000000; env->PC = SIGN_EXTEND32(0x80000000);
} }
env->hflags |= MIPS_HFLAG_EXL; env->hflags |= MIPS_HFLAG_EXL;
env->CP0_Status |= (1 << CP0St_EXL); env->CP0_Status |= (1 << CP0St_EXL);
...@@ -407,8 +407,8 @@ void do_interrupt (CPUState *env) ...@@ -407,8 +407,8 @@ void do_interrupt (CPUState *env)
exit(1); exit(1);
} }
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n" fprintf(logfile, "%s: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n"
" S %08x C %08x A %08x D %08x\n", " S %08x C %08x A " TLSZ " D " TLSZ "\n",
__func__, env->PC, env->CP0_EPC, cause, env->exception_index, __func__, env->PC, env->CP0_EPC, cause, env->exception_index,
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
env->CP0_DEPC); env->CP0_DEPC);
......
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
#if (MIPS_CPU == MIPS_R4Kc) #if (MIPS_CPU == MIPS_R4Kc)
/* 32 bits target */ /* 32 bits target */
#define TARGET_LONG_BITS 32 #undef MIPS_HAS_MIPS64
//#define MIPS_HAS_MIPS64 1
/* real pages are variable size... */ /* real pages are variable size... */
#define TARGET_PAGE_BITS 12 #define TARGET_PAGE_BITS 12
/* Uses MIPS R4Kx enhancements to MIPS32 architecture */ /* Uses MIPS R4Kx enhancements to MIPS32 architecture */
...@@ -69,7 +70,7 @@ ...@@ -69,7 +70,7 @@
(0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL)) (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL))
#elif (MIPS_CPU == MIPS_R4Kp) #elif (MIPS_CPU == MIPS_R4Kp)
/* 32 bits target */ /* 32 bits target */
#define TARGET_LONG_BITS 32 #undef MIPS_HAS_MIPS64
/* real pages are variable size... */ /* real pages are variable size... */
#define TARGET_PAGE_BITS 12 #define TARGET_PAGE_BITS 12
/* Uses MIPS R4Kx enhancements to MIPS32 architecture */ /* Uses MIPS R4Kx enhancements to MIPS32 architecture */
...@@ -79,8 +80,14 @@ ...@@ -79,8 +80,14 @@
#else #else
#error "MIPS CPU not defined" #error "MIPS CPU not defined"
/* Reminder for other flags */ /* Reminder for other flags */
//#define TARGET_MIPS64 //#undef MIPS_HAS_MIPS64
//#define MIPS_USES_FPU //#define MIPS_USES_FPU
#endif #endif
#ifdef MIPS_HAS_MIPS64
#define TARGET_LONG_BITS 64
#else
#define TARGET_LONG_BITS 32
#endif
#endif /* !defined (__QEMU_MIPS_DEFS_H__) */ #endif /* !defined (__QEMU_MIPS_DEFS_H__) */
...@@ -140,13 +140,7 @@ CALL_FROM_TB2(func, arg0, arg1); ...@@ -140,13 +140,7 @@ CALL_FROM_TB2(func, arg0, arg1);
#include "op_template.c" #include "op_template.c"
#undef REG #undef REG
#define TN T0 #define TN
#include "op_template.c"
#undef TN
#define TN T1
#include "op_template.c"
#undef TN
#define TN T2
#include "op_template.c" #include "op_template.c"
#undef TN #undef TN
...@@ -334,7 +328,7 @@ void op_store_LO (void) ...@@ -334,7 +328,7 @@ void op_store_LO (void)
/* Arithmetic */ /* Arithmetic */
void op_add (void) void op_add (void)
{ {
T0 += T1; T0 = SIGN_EXTEND32((int32_t)T0 + (int32_t)T1);
RETURN(); RETURN();
} }
...@@ -342,18 +336,19 @@ void op_addo (void) ...@@ -342,18 +336,19 @@ void op_addo (void)
{ {
target_ulong tmp; target_ulong tmp;
tmp = T0; tmp = (int32_t)T0;
T0 += T1; T0 = (int32_t)T0 + (int32_t)T1;
if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) { 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); CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
} }
T0 = SIGN_EXTEND32(T0);
RETURN(); RETURN();
} }
void op_sub (void) void op_sub (void)
{ {
T0 -= T1; T0 = SIGN_EXTEND32((int32_t)T0 - (int32_t)T1);
RETURN(); RETURN();
} }
...@@ -361,31 +356,110 @@ void op_subo (void) ...@@ -361,31 +356,110 @@ void op_subo (void)
{ {
target_ulong tmp; target_ulong tmp;
tmp = T0; tmp = (int32_t)T0;
T0 = (int32_t)T0 - (int32_t)T1; T0 = (int32_t)T0 - (int32_t)T1;
if (((tmp ^ T1) & (tmp ^ T0)) >> 31) { 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); CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
} }
T0 = SIGN_EXTEND32(T0);
RETURN(); RETURN();
} }
void op_mul (void) void op_mul (void)
{ {
T0 = (int32_t)T0 * (int32_t)T1; T0 = SIGN_EXTEND32((int32_t)T0 * (int32_t)T1);
RETURN(); RETURN();
} }
void op_div (void) void op_div (void)
{ {
if (T1 != 0) { if (T1 != 0) {
env->LO = (int32_t)T0 / (int32_t)T1; env->LO = SIGN_EXTEND32((int32_t)T0 / (int32_t)T1);
env->HI = (int32_t)T0 % (int32_t)T1; env->HI = SIGN_EXTEND32((int32_t)T0 % (int32_t)T1);
} }
RETURN(); RETURN();
} }
void op_divu (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) { if (T1 != 0) {
env->LO = T0 / T1; env->LO = T0 / T1;
...@@ -393,6 +467,8 @@ void op_divu (void) ...@@ -393,6 +467,8 @@ void op_divu (void)
} }
RETURN(); RETURN();
} }
#endif
#endif /* MIPS_HAS_MIPS64 */
/* Logical */ /* Logical */
void op_and (void) void op_and (void)
...@@ -421,19 +497,19 @@ void op_xor (void) ...@@ -421,19 +497,19 @@ void op_xor (void)
void op_sll (void) void op_sll (void)
{ {
T0 = T0 << T1; T0 = SIGN_EXTEND32((uint32_t)T0 << (uint32_t)T1);
RETURN(); RETURN();
} }
void op_sra (void) void op_sra (void)
{ {
T0 = (int32_t)T0 >> T1; T0 = SIGN_EXTEND32((int32_t)T0 >> (uint32_t)T1);
RETURN(); RETURN();
} }
void op_srl (void) void op_srl (void)
{ {
T0 = T0 >> T1; T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1);
RETURN(); RETURN();
} }
...@@ -442,8 +518,8 @@ void op_rotr (void) ...@@ -442,8 +518,8 @@ void op_rotr (void)
target_ulong tmp; target_ulong tmp;
if (T1) { if (T1) {
tmp = T0 << (0x20 - T1); tmp = SIGN_EXTEND32((uint32_t)T0 << (0x20 - (uint32_t)T1));
T0 = (T0 >> T1) | tmp; T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1) | tmp;
} else } else
T0 = T1; T0 = T1;
RETURN(); RETURN();
...@@ -451,19 +527,19 @@ void op_rotr (void) ...@@ -451,19 +527,19 @@ void op_rotr (void)
void op_sllv (void) void op_sllv (void)
{ {
T0 = T1 << (T0 & 0x1F); T0 = SIGN_EXTEND32((uint32_t)T1 << ((uint32_t)T0 & 0x1F));
RETURN(); RETURN();
} }
void op_srav (void) void op_srav (void)
{ {
T0 = (int32_t)T1 >> (T0 & 0x1F); T0 = SIGN_EXTEND32((int32_t)T1 >> (T0 & 0x1F));
RETURN(); RETURN();
} }
void op_srlv (void) void op_srlv (void)
{ {
T0 = T1 >> (T0 & 0x1F); T0 = SIGN_EXTEND32((uint32_t)T1 >> (T0 & 0x1F));
RETURN(); RETURN();
} }
...@@ -473,8 +549,8 @@ void op_rotrv (void) ...@@ -473,8 +549,8 @@ void op_rotrv (void)
T0 &= 0x1F; T0 &= 0x1F;
if (T0) { if (T0) {
tmp = T1 << (0x20 - T0); tmp = SIGN_EXTEND32((uint32_t)T1 << (0x20 - T0));
T0 = (T1 >> T0) | tmp; T0 = SIGN_EXTEND32((uint32_t)T1 >> T0) | tmp;
} else } else
T0 = T1; T0 = T1;
RETURN(); RETURN();
...@@ -484,7 +560,7 @@ void op_clo (void) ...@@ -484,7 +560,7 @@ void op_clo (void)
{ {
int n; int n;
if (T0 == (target_ulong)-1) { if (T0 == ~((target_ulong)0)) {
T0 = 32; T0 = 32;
} else { } else {
for (n = 0; n < 32; n++) { for (n = 0; n < 32; n++) {
...@@ -514,67 +590,213 @@ void op_clz (void) ...@@ -514,67 +590,213 @@ void op_clz (void)
RETURN(); RETURN();
} }
/* 64 bits arithmetic */ #ifdef MIPS_HAS_MIPS64
#if (HOST_LONG_BITS == 64)
static inline uint64_t get_HILO (void) #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; CALL_FROM_TB0(do_dsll32);
env->HI = HILO >> 32; 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(); RETURN();
} }
void op_multu (void) void op_dsra32 (void)
{ {
set_HILO((uint64_t)T0 * (uint64_t)T1); CALL_FROM_TB0(do_dsra32);
RETURN(); 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); void op_dsrl32 (void)
set_HILO((int64_t)get_HILO() + tmp); {
CALL_FROM_TB0(do_dsrl32);
RETURN(); 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); void op_drotr32 (void)
set_HILO(get_HILO() + tmp); {
CALL_FROM_TB0(do_drotr32);
RETURN(); 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); void op_dsrav (void)
set_HILO((int64_t)get_HILO() - tmp); {
CALL_FROM_TB0(do_dsrav);
RETURN(); 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); void op_drotrv (void)
set_HILO(get_HILO() - tmp); {
CALL_FROM_TB0(do_drotrv);
RETURN(); 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) void op_mult (void)
{ {
CALL_FROM_TB0(do_mult); CALL_FROM_TB0(do_mult);
...@@ -610,6 +832,81 @@ void op_msubu (void) ...@@ -610,6 +832,81 @@ void op_msubu (void)
CALL_FROM_TB0(do_msubu); CALL_FROM_TB0(do_msubu);
RETURN(); 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 #endif
/* Conditional moves */ /* Conditional moves */
...@@ -735,7 +1032,7 @@ void op_jnz_T2 (void) ...@@ -735,7 +1032,7 @@ void op_jnz_T2 (void)
/* CP0 functions */ /* CP0 functions */
void op_mfc0_index (void) void op_mfc0_index (void)
{ {
T0 = env->CP0_index; T0 = SIGN_EXTEND32(env->CP0_index);
RETURN(); RETURN();
} }
...@@ -765,25 +1062,25 @@ void op_mfc0_context (void) ...@@ -765,25 +1062,25 @@ void op_mfc0_context (void)
void op_mfc0_pagemask (void) void op_mfc0_pagemask (void)
{ {
T0 = env->CP0_PageMask; T0 = SIGN_EXTEND32(env->CP0_PageMask);
RETURN(); RETURN();
} }
void op_mfc0_pagegrain (void) void op_mfc0_pagegrain (void)
{ {
T0 = env->CP0_PageGrain; T0 = SIGN_EXTEND32(env->CP0_PageGrain);
RETURN(); RETURN();
} }
void op_mfc0_wired (void) void op_mfc0_wired (void)
{ {
T0 = env->CP0_Wired; T0 = SIGN_EXTEND32(env->CP0_Wired);
RETURN(); RETURN();
} }
void op_mfc0_hwrena (void) void op_mfc0_hwrena (void)
{ {
T0 = env->CP0_HWREna; T0 = SIGN_EXTEND32(env->CP0_HWREna);
RETURN(); RETURN();
} }
...@@ -807,13 +1104,13 @@ void op_mfc0_entryhi (void) ...@@ -807,13 +1104,13 @@ void op_mfc0_entryhi (void)
void op_mfc0_compare (void) void op_mfc0_compare (void)
{ {
T0 = env->CP0_Compare; T0 = SIGN_EXTEND32(env->CP0_Compare);
RETURN(); RETURN();
} }
void op_mfc0_status (void) void op_mfc0_status (void)
{ {
T0 = env->CP0_Status; T0 = SIGN_EXTEND32(env->CP0_Status);
if (env->hflags & MIPS_HFLAG_UM) if (env->hflags & MIPS_HFLAG_UM)
T0 |= (1 << CP0St_UM); T0 |= (1 << CP0St_UM);
if (env->hflags & MIPS_HFLAG_ERL) if (env->hflags & MIPS_HFLAG_ERL)
...@@ -825,19 +1122,19 @@ void op_mfc0_status (void) ...@@ -825,19 +1122,19 @@ void op_mfc0_status (void)
void op_mfc0_intctl (void) void op_mfc0_intctl (void)
{ {
T0 = env->CP0_IntCtl; T0 = SIGN_EXTEND32(env->CP0_IntCtl);
RETURN(); RETURN();
} }
void op_mfc0_srsctl (void) void op_mfc0_srsctl (void)
{ {
T0 = env->CP0_SRSCtl; T0 = SIGN_EXTEND32(env->CP0_SRSCtl);
RETURN(); RETURN();
} }
void op_mfc0_cause (void) void op_mfc0_cause (void)
{ {
T0 = env->CP0_Cause; T0 = SIGN_EXTEND32(env->CP0_Cause);
RETURN(); RETURN();
} }
...@@ -849,7 +1146,7 @@ void op_mfc0_epc (void) ...@@ -849,7 +1146,7 @@ void op_mfc0_epc (void)
void op_mfc0_prid (void) void op_mfc0_prid (void)
{ {
T0 = env->CP0_PRid; T0 = SIGN_EXTEND32(env->CP0_PRid);
RETURN(); RETURN();
} }
...@@ -861,25 +1158,25 @@ void op_mfc0_ebase (void) ...@@ -861,25 +1158,25 @@ void op_mfc0_ebase (void)
void op_mfc0_config0 (void) void op_mfc0_config0 (void)
{ {
T0 = env->CP0_Config0; T0 = SIGN_EXTEND32(env->CP0_Config0);
RETURN(); RETURN();
} }
void op_mfc0_config1 (void) void op_mfc0_config1 (void)
{ {
T0 = env->CP0_Config1; T0 = SIGN_EXTEND32(env->CP0_Config1);
RETURN(); RETURN();
} }
void op_mfc0_config2 (void) void op_mfc0_config2 (void)
{ {
T0 = env->CP0_Config2; T0 = SIGN_EXTEND32(env->CP0_Config2);
RETURN(); RETURN();
} }
void op_mfc0_config3 (void) void op_mfc0_config3 (void)
{ {
T0 = env->CP0_Config3; T0 = SIGN_EXTEND32(env->CP0_Config3);
RETURN(); RETURN();
} }
...@@ -891,13 +1188,13 @@ void op_mfc0_lladdr (void) ...@@ -891,13 +1188,13 @@ void op_mfc0_lladdr (void)
void op_mfc0_watchlo0 (void) void op_mfc0_watchlo0 (void)
{ {
T0 = env->CP0_WatchLo; T0 = SIGN_EXTEND32(env->CP0_WatchLo);
RETURN(); RETURN();
} }
void op_mfc0_watchhi0 (void) void op_mfc0_watchhi0 (void)
{ {
T0 = env->CP0_WatchHi; T0 = SIGN_EXTEND32(env->CP0_WatchHi);
RETURN(); RETURN();
} }
...@@ -915,7 +1212,7 @@ void op_mfc0_framemask (void) ...@@ -915,7 +1212,7 @@ void op_mfc0_framemask (void)
void op_mfc0_debug (void) void op_mfc0_debug (void)
{ {
T0 = env->CP0_Debug; T0 = SIGN_EXTEND32(env->CP0_Debug);
if (env->hflags & MIPS_HFLAG_DM) if (env->hflags & MIPS_HFLAG_DM)
T0 |= 1 << CP0DB_DM; T0 |= 1 << CP0DB_DM;
RETURN(); RETURN();
...@@ -929,31 +1226,31 @@ void op_mfc0_depc (void) ...@@ -929,31 +1226,31 @@ void op_mfc0_depc (void)
void op_mfc0_performance0 (void) void op_mfc0_performance0 (void)
{ {
T0 = env->CP0_Performance0; T0 = SIGN_EXTEND32(env->CP0_Performance0);
RETURN(); RETURN();
} }
void op_mfc0_taglo (void) void op_mfc0_taglo (void)
{ {
T0 = env->CP0_TagLo; T0 = SIGN_EXTEND32(env->CP0_TagLo);
RETURN(); RETURN();
} }
void op_mfc0_datalo (void) void op_mfc0_datalo (void)
{ {
T0 = env->CP0_DataLo; T0 = SIGN_EXTEND32(env->CP0_DataLo);
RETURN(); RETURN();
} }
void op_mfc0_taghi (void) void op_mfc0_taghi (void)
{ {
T0 = env->CP0_TagHi; T0 = SIGN_EXTEND32(env->CP0_TagHi);
RETURN(); RETURN();
} }
void op_mfc0_datahi (void) void op_mfc0_datahi (void)
{ {
T0 = env->CP0_DataHi; T0 = SIGN_EXTEND32(env->CP0_DataHi);
RETURN(); RETURN();
} }
...@@ -965,7 +1262,7 @@ void op_mfc0_errorepc (void) ...@@ -965,7 +1262,7 @@ void op_mfc0_errorepc (void)
void op_mfc0_desave (void) void op_mfc0_desave (void)
{ {
T0 = env->CP0_DESAVE; T0 = SIGN_EXTEND32(env->CP0_DESAVE);
RETURN(); RETURN();
} }
...@@ -979,7 +1276,7 @@ void op_mtc0_entrylo0 (void) ...@@ -979,7 +1276,7 @@ void op_mtc0_entrylo0 (void)
{ {
/* Large physaddr not implemented */ /* Large physaddr not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
env->CP0_EntryLo0 = T0 & 0x3FFFFFFFUL; env->CP0_EntryLo0 = T0 & SIGN_EXTEND32(0x3FFFFFFFUL);
RETURN(); RETURN();
} }
...@@ -987,7 +1284,7 @@ void op_mtc0_entrylo1 (void) ...@@ -987,7 +1284,7 @@ void op_mtc0_entrylo1 (void)
{ {
/* Large physaddr not implemented */ /* Large physaddr not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
env->CP0_EntryLo1 = T0 & 0x3FFFFFFFUL; env->CP0_EntryLo1 = T0 & SIGN_EXTEND32(0x3FFFFFFFUL);
RETURN(); RETURN();
} }
...@@ -1037,7 +1334,7 @@ void op_mtc0_entryhi (void) ...@@ -1037,7 +1334,7 @@ void op_mtc0_entryhi (void)
/* 1k pages not implemented */ /* 1k pages not implemented */
/* Ignore MIPS64 TLB for now */ /* Ignore MIPS64 TLB for now */
val = T0 & 0xFFFFE0FF; val = T0 & SIGN_EXTEND32(0xFFFFE0FF);
old = env->CP0_EntryHi; old = env->CP0_EntryHi;
env->CP0_EntryHi = val; env->CP0_EntryHi = val;
/* If the ASID changes, flush qemu's TLB. */ /* If the ASID changes, flush qemu's TLB. */
...@@ -1056,7 +1353,7 @@ void op_mtc0_status (void) ...@@ -1056,7 +1353,7 @@ void op_mtc0_status (void)
{ {
uint32_t val, old, mask; uint32_t val, old, mask;
val = T0 & 0xFA78FF01; val = T0 & SIGN_EXTEND32(0xFA78FF01);
old = env->CP0_Status; old = env->CP0_Status;
if (T0 & (1 << CP0St_UM)) if (T0 & (1 << CP0St_UM))
env->hflags |= MIPS_HFLAG_UM; env->hflags |= MIPS_HFLAG_UM;
...@@ -1107,7 +1404,7 @@ void op_mtc0_cause (void) ...@@ -1107,7 +1404,7 @@ void op_mtc0_cause (void)
{ {
uint32_t val, old; uint32_t val, old;
val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300); val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300);
old = env->CP0_Cause; old = env->CP0_Cause;
env->CP0_Cause = val; env->CP0_Cause = val;
#if 0 #if 0
...@@ -1134,7 +1431,7 @@ void op_mtc0_ebase (void) ...@@ -1134,7 +1431,7 @@ void op_mtc0_ebase (void)
{ {
/* vectored interrupts not implemented */ /* vectored interrupts not implemented */
/* Multi-CPU not implemented */ /* Multi-CPU not implemented */
env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000); env->CP0_EBase = SIGN_EXTEND32(0x80000000) | (T0 & 0x3FFFF000);
RETURN(); RETURN();
} }
...@@ -1204,7 +1501,7 @@ void op_mtc0_performance0 (void) ...@@ -1204,7 +1501,7 @@ void op_mtc0_performance0 (void)
void op_mtc0_taglo (void) void op_mtc0_taglo (void)
{ {
env->CP0_TagLo = T0 & 0xFFFFFCF6; env->CP0_TagLo = T0 & SIGN_EXTEND32(0xFFFFFCF6);
RETURN(); RETURN();
} }
...@@ -1787,7 +2084,7 @@ void op_ext(void) ...@@ -1787,7 +2084,7 @@ void op_ext(void)
unsigned int pos = PARAM1; unsigned int pos = PARAM1;
unsigned int size = PARAM2; unsigned int size = PARAM2;
T0 = (T1 >> pos) & ((1 << size) - 1); T0 = ((uint32_t)T1 >> pos) & ((1 << size) - 1);
RETURN(); RETURN();
} }
...@@ -1797,7 +2094,7 @@ void op_ins(void) ...@@ -1797,7 +2094,7 @@ void op_ins(void)
unsigned int size = PARAM2; unsigned int size = PARAM2;
target_ulong mask = ((1 << size) - 1) << pos; target_ulong mask = ((1 << size) - 1) << pos;
T0 = (T2 & ~mask) | ((T1 << pos) & mask); T0 = (T2 & ~mask) | (((uint32_t)T1 << pos) & mask);
RETURN(); RETURN();
} }
...@@ -1807,6 +2104,26 @@ void op_wsbh(void) ...@@ -1807,6 +2104,26 @@ void op_wsbh(void)
RETURN(); 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) void op_dsbh(void)
{ {
T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 0x00FF00FF00FF00FFULL); T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 0x00FF00FF00FF00FFULL);
...@@ -1818,6 +2135,7 @@ void op_dshd(void) ...@@ -1818,6 +2135,7 @@ void op_dshd(void)
T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL); T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL);
RETURN(); RETURN();
} }
#endif
void op_seb(void) void op_seb(void)
{ {
......
...@@ -74,8 +74,92 @@ void do_raise_exception_direct (uint32_t exception) ...@@ -74,8 +74,92 @@ void do_raise_exception_direct (uint32_t exception)
#undef MEMSUFFIX #undef MEMSUFFIX
#endif #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 */ /* 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) static inline uint64_t get_HILO (void)
{ {
return ((uint64_t)env->HI << 32) | (uint64_t)env->LO; return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
...@@ -83,8 +167,8 @@ static inline uint64_t get_HILO (void) ...@@ -83,8 +167,8 @@ static inline uint64_t get_HILO (void)
static inline void set_HILO (uint64_t HILO) static inline void set_HILO (uint64_t HILO)
{ {
env->LO = HILO & 0xFFFFFFFF; env->LO = SIGN_EXTEND32(HILO & 0xFFFFFFFF);
env->HI = HILO >> 32; env->HI = SIGN_EXTEND32(HILO >> 32);
} }
void do_mult (void) void do_mult (void)
...@@ -94,7 +178,7 @@ void do_mult (void) ...@@ -94,7 +178,7 @@ void do_mult (void)
void do_multu (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) void do_madd (void)
...@@ -109,7 +193,7 @@ void do_maddu (void) ...@@ -109,7 +193,7 @@ void do_maddu (void)
{ {
uint64_t tmp; 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); set_HILO(get_HILO() + tmp);
} }
...@@ -125,11 +209,41 @@ void do_msubu (void) ...@@ -125,11 +209,41 @@ void do_msubu (void)
{ {
uint64_t tmp; 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); set_HILO(get_HILO() - tmp);
} }
#endif #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) #if defined(CONFIG_USER_ONLY)
void do_mfc0_random (void) void do_mfc0_random (void)
{ {
...@@ -191,12 +305,12 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) ...@@ -191,12 +305,12 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global)
/* CP0 helpers */ /* CP0 helpers */
void do_mfc0_random (void) void do_mfc0_random (void)
{ {
T0 = cpu_mips_get_random(env); T0 = SIGN_EXTEND32(cpu_mips_get_random(env));
} }
void do_mfc0_count (void) 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) void do_mtc0_status_debug(uint32_t old, uint32_t val)
...@@ -319,7 +433,7 @@ static void fill_tlb (int idx) ...@@ -319,7 +433,7 @@ static void fill_tlb (int idx)
/* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
tlb = &env->tlb[idx]; tlb = &env->tlb[idx];
tlb->VPN = env->CP0_EntryHi & 0xFFFFE000; tlb->VPN = env->CP0_EntryHi & SIGN_EXTEND32(0xFFFFE000);
tlb->ASID = env->CP0_EntryHi & 0xFF; tlb->ASID = env->CP0_EntryHi & 0xFF;
size = env->CP0_PageMask >> 13; size = env->CP0_PageMask >> 13;
size = 4 * (size + 1); size = 4 * (size + 1);
...@@ -364,7 +478,7 @@ void do_tlbp (void) ...@@ -364,7 +478,7 @@ void do_tlbp (void)
uint8_t ASID; uint8_t ASID;
int i; int i;
tag = env->CP0_EntryHi & 0xFFFFE000; tag = env->CP0_EntryHi & SIGN_EXTEND32(0xFFFFE000);
ASID = env->CP0_EntryHi & 0xFF; ASID = env->CP0_EntryHi & 0xFF;
for (i = 0; i < MIPS_TLB_NB; i++) { for (i = 0; i < MIPS_TLB_NB; i++) {
tlb = &env->tlb[i]; tlb = &env->tlb[i];
...@@ -418,16 +532,16 @@ void do_tlbr (void) ...@@ -418,16 +532,16 @@ void do_tlbr (void)
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
void op_dump_ldst (const unsigned char *func) void dump_ldst (const unsigned char *func)
{ {
if (loglevel) if (loglevel)
fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1); fprintf(logfile, "%s => " TLSZ " " TLSZ "\n", __func__, T0, T1);
} }
void dump_sc (void) void dump_sc (void)
{ {
if (loglevel) { 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); T1, T0, env->CP0_LLAddr);
} }
} }
...@@ -435,7 +549,7 @@ void dump_sc (void) ...@@ -435,7 +549,7 @@ void dump_sc (void)
void debug_eret (void) void debug_eret (void)
{ {
if (loglevel) { 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->PC, env->CP0_EPC, env->CP0_ErrorEPC,
env->hflags & MIPS_HFLAG_ERL ? 1 : 0); env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
} }
...@@ -454,13 +568,13 @@ void do_pmon (int function) ...@@ -454,13 +568,13 @@ void do_pmon (int function)
break; break;
case 3: case 3:
case 12: case 12:
printf("%c", env->gpr[4] & 0xFF); printf("%c", (char)(env->gpr[4] & 0xFF));
break; break;
case 17: case 17:
break; break;
case 158: case 158:
{ {
unsigned char *fmt = (void *)env->gpr[4]; unsigned char *fmt = (void *)(unsigned long)env->gpr[4];
printf("%s", fmt); printf("%s", fmt);
} }
break; break;
......
...@@ -10,9 +10,6 @@ void glue(do_lwl, MEMSUFFIX) (uint32_t tmp) ...@@ -10,9 +10,6 @@ void glue(do_lwl, MEMSUFFIX) (uint32_t tmp)
target_ulong sav = T0; target_ulong sav = T0;
#endif #endif
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (GET_LMASK(T0)) { switch (GET_LMASK(T0)) {
case 0: case 0:
T0 = tmp; T0 = tmp;
...@@ -42,9 +39,6 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) ...@@ -42,9 +39,6 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp)
target_ulong sav = T0; target_ulong sav = T0;
#endif #endif
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (GET_LMASK(T0)) { switch (GET_LMASK(T0)) {
case 0: case 0:
T0 = (tmp >> 24) | (T1 & 0xFFFFFF00); T0 = (tmp >> 24) | (T1 & 0xFFFFFF00);
...@@ -71,15 +65,9 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) ...@@ -71,15 +65,9 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp)
uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp)
{ {
#if defined (DEBUG_OP) #if defined (DEBUG_OP)
target_ulong sav; target_ulong sav = tmp;
#endif #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)) { switch (GET_LMASK(T0)) {
case 0: case 0:
tmp = T1; tmp = T1;
...@@ -107,15 +95,9 @@ uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) ...@@ -107,15 +95,9 @@ uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp)
uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp)
{ {
#if defined (DEBUG_OP) #if defined (DEBUG_OP)
target_ulong sav; target_ulong sav = tmp;
#endif #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)) { switch (GET_LMASK(T0)) {
case 0: case 0:
tmp = (tmp & 0x00FFFFFF) | (T1 << 24); tmp = (tmp & 0x00FFFFFF) | (T1 << 24);
...@@ -139,3 +121,179 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) ...@@ -139,3 +121,179 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp)
RETURN(); RETURN();
return tmp; 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 */
...@@ -75,6 +75,7 @@ void glue(op_sw, MEMSUFFIX) (void) ...@@ -75,6 +75,7 @@ void glue(op_sw, MEMSUFFIX) (void)
/* "half" load and stores. We must do the memory access inline, /* "half" load and stores. We must do the memory access inline,
or fault handling won't work. */ or fault handling won't work. */
/* XXX: This is broken, CP0_BADVADDR has the wrong (aligned) value. */
void glue(op_lwl, MEMSUFFIX) (void) void glue(op_lwl, MEMSUFFIX) (void)
{ {
uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
...@@ -125,6 +126,72 @@ void glue(op_sc, MEMSUFFIX) (void) ...@@ -125,6 +126,72 @@ void glue(op_sc, MEMSUFFIX) (void)
RETURN(); 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 #ifdef MIPS_USES_FPU
void glue(op_lwc1, MEMSUFFIX) (void) void glue(op_lwc1, MEMSUFFIX) (void)
{ {
......
...@@ -51,15 +51,21 @@ void glue(op_load_gpr_T2_gpr, REG) (void) ...@@ -51,15 +51,21 @@ void glue(op_load_gpr_T2_gpr, REG) (void)
#endif #endif
#if defined (TN) #if defined (TN)
void glue(op_set_, TN) (void) #define SET_RESET(treg, tregname) \
{ void glue(op_set, tregname)(void) \
TN = PARAM1; { \
RETURN(); treg = PARAM1; \
} RETURN(); \
} \
void glue(op_reset, tregname)(void) \
{ \
treg = 0; \
RETURN(); \
} \
void glue (op_reset_, TN) (void) SET_RESET(T0, _T0)
{ SET_RESET(T1, _T1)
TN = 0; SET_RESET(T2, _T2)
RETURN();
} #undef SET_RESET
#endif #endif
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "disas.h" #include "disas.h"
//#define MIPS_DEBUG_DISAS //#define MIPS_DEBUG_DISAS
//#define MIPS_DEBUG_SIGN_EXTENSIONS
//#define MIPS_SINGLE_STEP //#define MIPS_SINGLE_STEP
#ifdef USE_DIRECT_JUMP #ifdef USE_DIRECT_JUMP
...@@ -502,7 +503,7 @@ enum { ...@@ -502,7 +503,7 @@ enum {
#define MIPS_DEBUG(fmt, args...) \ #define MIPS_DEBUG(fmt, args...) \
do { \ do { \
if (loglevel & CPU_LOG_TB_IN_ASM) { \ if (loglevel & CPU_LOG_TB_IN_ASM) { \
fprintf(logfile, "%08x: %08x " fmt "\n", \ fprintf(logfile, TLSZ ": %08x " fmt "\n", \
ctx->pc, ctx->opcode , ##args); \ ctx->pc, ctx->opcode , ##args); \
} \ } \
} while (0) } while (0)
...@@ -621,6 +622,8 @@ OP_LD_TABLE(dr); ...@@ -621,6 +622,8 @@ OP_LD_TABLE(dr);
OP_ST_TABLE(d); OP_ST_TABLE(d);
OP_ST_TABLE(dl); OP_ST_TABLE(dl);
OP_ST_TABLE(dr); OP_ST_TABLE(dr);
OP_LD_TABLE(ld);
OP_ST_TABLE(cd);
#endif #endif
OP_LD_TABLE(w); OP_LD_TABLE(w);
OP_LD_TABLE(wu); OP_LD_TABLE(wu);
...@@ -1417,7 +1420,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, ...@@ -1417,7 +1420,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
case OPC_J: case OPC_J:
case OPC_JAL: case OPC_JAL:
/* Jump to immediate */ /* Jump to immediate */
btarget = ((ctx->pc + 4) & 0xF0000000) | offset; btarget = ((ctx->pc + 4) & SIGN_EXTEND32(0xF0000000)) | offset;
break; break;
case OPC_JR: case OPC_JR:
case OPC_JALR: case OPC_JALR:
...@@ -2927,21 +2930,21 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, ...@@ -2927,21 +2930,21 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
switch (op) { switch (op) {
case OPC_BC1F: case OPC_BC1F:
gen_op_bc1f(); gen_op_bc1f();
MIPS_DEBUG("bc1f %08x", btarget); MIPS_DEBUG("bc1f " TLSZ, btarget);
goto not_likely; goto not_likely;
case OPC_BC1FL: case OPC_BC1FL:
gen_op_bc1f(); gen_op_bc1f();
MIPS_DEBUG("bc1fl %08x", btarget); MIPS_DEBUG("bc1fl " TLSZ, btarget);
goto likely; goto likely;
case OPC_BC1T: case OPC_BC1T:
gen_op_bc1t(); gen_op_bc1t();
MIPS_DEBUG("bc1t %08x", btarget); MIPS_DEBUG("bc1t " TLSZ, btarget);
not_likely: not_likely:
ctx->hflags |= MIPS_HFLAG_BC; ctx->hflags |= MIPS_HFLAG_BC;
break; break;
case OPC_BC1TL: case OPC_BC1TL:
gen_op_bc1t(); gen_op_bc1t();
MIPS_DEBUG("bc1tl %08x", btarget); MIPS_DEBUG("bc1tl " TLSZ, btarget);
likely: likely:
ctx->hflags |= MIPS_HFLAG_BL; ctx->hflags |= MIPS_HFLAG_BL;
break; break;
...@@ -2952,7 +2955,7 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, ...@@ -2952,7 +2955,7 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
} }
gen_op_set_bcond(); gen_op_set_bcond();
MIPS_DEBUG("enter ds: cond %02x target %08x", MIPS_DEBUG("enter ds: cond %02x target " TLSZ,
ctx->hflags, btarget); ctx->hflags, btarget);
ctx->btarget = btarget; ctx->btarget = btarget;
...@@ -3351,30 +3354,6 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) ...@@ -3351,30 +3354,6 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
/* SmartMIPS extension to MIPS32 */ /* SmartMIPS extension to MIPS32 */
#ifdef MIPS_HAS_MIPS64 #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) */ /* Coprocessor 3 (FPU) */
/* MDMX extension to MIPS64 */ /* MDMX extension to MIPS64 */
...@@ -3407,7 +3386,7 @@ static void decode_opc (DisasContext *ctx) ...@@ -3407,7 +3386,7 @@ static void decode_opc (DisasContext *ctx)
if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
/* Handle blikely not taken case */ /* Handle blikely not taken case */
MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); MIPS_DEBUG("blikely condition (" TLSZ ")", ctx->pc + 4);
gen_blikely(ctx); gen_blikely(ctx);
} }
op = MASK_OP_MAJOR(ctx->opcode); op = MASK_OP_MAJOR(ctx->opcode);
...@@ -4011,7 +3990,7 @@ void fpu_dump_state(CPUState *env, FILE *f, ...@@ -4011,7 +3990,7 @@ void fpu_dump_state(CPUState *env, FILE *f,
void dump_fpu (CPUState *env) void dump_fpu (CPUState *env)
{ {
if (loglevel) { 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); env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
fpu_dump_state(env, logfile, fprintf, 0); fpu_dump_state(env, logfile, fprintf, 0);
} }
...@@ -4019,6 +3998,39 @@ void dump_fpu (CPUState *env) ...@@ -4019,6 +3998,39 @@ void dump_fpu (CPUState *env)
#endif /* MIPS_USES_FPU */ #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, void cpu_dump_state (CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags) int flags)
...@@ -4026,12 +4038,12 @@ void cpu_dump_state (CPUState *env, FILE *f, ...@@ -4026,12 +4038,12 @@ void cpu_dump_state (CPUState *env, FILE *f,
uint32_t c0_status; uint32_t c0_status;
int i; 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); env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
if ((i & 3) == 0) if ((i & 3) == 0)
cpu_fprintf(f, "GPR%02d:", i); 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) if ((i & 3) == 3)
cpu_fprintf(f, "\n"); cpu_fprintf(f, "\n");
} }
...@@ -4044,14 +4056,17 @@ void cpu_dump_state (CPUState *env, FILE *f, ...@@ -4044,14 +4056,17 @@ void cpu_dump_state (CPUState *env, FILE *f,
if (env->hflags & MIPS_HFLAG_EXL) if (env->hflags & MIPS_HFLAG_EXL)
c0_status |= (1 << CP0St_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); 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); env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
#ifdef MIPS_USES_FPU #ifdef MIPS_USES_FPU
if (c0_status & (1 << CP0St_CU1)) if (c0_status & (1 << CP0St_CU1))
fpu_dump_state(env, f, cpu_fprintf, flags); fpu_dump_state(env, f, cpu_fprintf, flags);
#endif #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) CPUMIPSState *cpu_mips_init (void)
...@@ -4082,14 +4097,14 @@ void cpu_reset (CPUMIPSState *env) ...@@ -4082,14 +4097,14 @@ void cpu_reset (CPUMIPSState *env)
} else { } else {
env->CP0_ErrorEPC = env->PC; env->CP0_ErrorEPC = env->PC;
} }
env->PC = 0xBFC00000; env->PC = SIGN_EXTEND32(0xBFC00000);
#if defined (MIPS_USES_R4K_TLB) #if defined (MIPS_USES_R4K_TLB)
env->CP0_random = MIPS_TLB_NB - 1; env->CP0_random = MIPS_TLB_NB - 1;
env->tlb_in_use = MIPS_TLB_NB; env->tlb_in_use = MIPS_TLB_NB;
#endif #endif
env->CP0_Wired = 0; env->CP0_Wired = 0;
/* SMP not implemented */ /* SMP not implemented */
env->CP0_EBase = 0x80000000; env->CP0_EBase = SIGN_EXTEND32(0x80000000);
env->CP0_Config0 = MIPS_CONFIG0; env->CP0_Config0 = MIPS_CONFIG0;
env->CP0_Config1 = MIPS_CONFIG1; env->CP0_Config1 = MIPS_CONFIG1;
env->CP0_Config2 = MIPS_CONFIG2; env->CP0_Config2 = MIPS_CONFIG2;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册