diff options
author | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-09-06 00:18:15 +0000 |
---|---|---|
committer | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-09-06 00:18:15 +0000 |
commit | ead9360e2fbcaae10a8ca3d8bfed885422205dca (patch) | |
tree | bbec65c2f895319d4192f9662919f74f51556f9a | |
parent | 606b41e7020db7634fe90d069d2c019770c74b45 (diff) |
Partial support for 34K multithreading, not functional yet.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3156 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | cpu-exec.c | 2 | ||||
-rw-r--r-- | gdbstub.c | 34 | ||||
-rw-r--r-- | hw/mips_r4k.c | 2 | ||||
-rw-r--r-- | hw/mips_timer.c | 2 | ||||
-rw-r--r-- | linux-user/main.c | 24 | ||||
-rw-r--r-- | linux-user/signal.c | 36 | ||||
-rw-r--r-- | linux-user/syscall.c | 7 | ||||
-rw-r--r-- | monitor.c | 4 | ||||
-rw-r--r-- | target-mips/cpu.h | 239 | ||||
-rw-r--r-- | target-mips/exec.h | 39 | ||||
-rw-r--r-- | target-mips/fop_template.c | 20 | ||||
-rw-r--r-- | target-mips/helper.c | 57 | ||||
-rw-r--r-- | target-mips/op.c | 875 | ||||
-rw-r--r-- | target-mips/op_helper.c | 605 | ||||
-rw-r--r-- | target-mips/op_template.c | 23 | ||||
-rw-r--r-- | target-mips/translate.c | 949 | ||||
-rw-r--r-- | target-mips/translate_init.c | 211 | ||||
-rw-r--r-- | translate-all.c | 2 |
18 files changed, 2305 insertions, 826 deletions
diff --git a/cpu-exec.c b/cpu-exec.c index 543ec09ef7..4f1cee616e 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -194,7 +194,7 @@ static inline TranslationBlock *tb_find_fast(void) #elif defined(TARGET_MIPS) flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK); cs_base = 0; - pc = env->PC; + pc = env->PC[env->current_tc]; #elif defined(TARGET_M68K) flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */ | (env->sr & SR_S) /* Bit 13 */ @@ -559,17 +559,17 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) ptr = mem_buf; for (i = 0; i < 32; i++) { - *(target_ulong *)ptr = tswapl(env->gpr[i]); + *(target_ulong *)ptr = tswapl(env->gpr[i][env->current_tc]); ptr += sizeof(target_ulong); } *(target_ulong *)ptr = tswapl(env->CP0_Status); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->LO); + *(target_ulong *)ptr = tswapl(env->LO[0][env->current_tc]); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->HI); + *(target_ulong *)ptr = tswapl(env->HI[0][env->current_tc]); ptr += sizeof(target_ulong); *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr); @@ -578,21 +578,21 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) *(target_ulong *)ptr = tswapl(env->CP0_Cause); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->PC); + *(target_ulong *)ptr = tswapl(env->PC[env->current_tc]); ptr += sizeof(target_ulong); if (env->CP0_Config1 & (1 << CP0C1_FP)) { for (i = 0; i < 32; i++) { - *(target_ulong *)ptr = tswapl(env->fpr[i].fs[FP_ENDIAN_IDX]); + *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].fs[FP_ENDIAN_IDX]); ptr += sizeof(target_ulong); } - *(target_ulong *)ptr = tswapl(env->fcr31); + *(target_ulong *)ptr = tswapl(env->fpu->fcr31); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->fcr0); + *(target_ulong *)ptr = tswapl(env->fpu->fcr0); ptr += sizeof(target_ulong); } @@ -611,7 +611,7 @@ static unsigned int ieee_rm[] = float_round_down }; #define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) + set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status) static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { @@ -621,17 +621,17 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) ptr = mem_buf; for (i = 0; i < 32; i++) { - env->gpr[i] = tswapl(*(target_ulong *)ptr); + env->gpr[i][env->current_tc] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); } env->CP0_Status = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); - env->LO = tswapl(*(target_ulong *)ptr); + env->LO[0][env->current_tc] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); - env->HI = tswapl(*(target_ulong *)ptr); + env->HI[0][env->current_tc] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr); @@ -640,21 +640,21 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->CP0_Cause = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); - env->PC = tswapl(*(target_ulong *)ptr); + env->PC[env->current_tc] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); if (env->CP0_Config1 & (1 << CP0C1_FP)) { for (i = 0; i < 32; i++) { - env->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); + env->fpu->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); } - env->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF; + env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF; ptr += sizeof(target_ulong); - env->fcr0 = tswapl(*(target_ulong *)ptr); + env->fpu->fcr0 = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); /* set rounding mode */ @@ -775,7 +775,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_SH4) env->pc = addr; #elif defined (TARGET_MIPS) - env->PC = addr; + env->PC[env->current_tc] = addr; #endif } #ifdef CONFIG_USER_ONLY @@ -799,7 +799,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_SH4) env->pc = addr; #elif defined (TARGET_MIPS) - env->PC = addr; + env->PC[env->current_tc] = addr; #endif } cpu_single_step(env, 1); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 2208922a75..82782273b5 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -77,7 +77,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) entry = (int32_t)entry; - env->PC = entry; + env->PC[env->current_tc] = entry; } else { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 6a517e1841..2fe5e29c58 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -10,7 +10,7 @@ uint32_t cpu_mips_get_random (CPUState *env) static uint32_t seed = 0; uint32_t idx; seed = seed * 314159 + 1; - idx = (seed >> 16) % (env->nb_tlb - env->CP0_Wired) + env->CP0_Wired; + idx = (seed >> 16) % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired; return idx; } diff --git a/linux-user/main.c b/linux-user/main.c index 32fa43d476..edcb68b8d4 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1374,8 +1374,8 @@ void cpu_loop(CPUMIPSState *env) trapnr = cpu_mips_exec(env); switch(trapnr) { case EXCP_SYSCALL: - syscall_num = env->gpr[2] - 4000; - env->PC += 4; + syscall_num = env->gpr[2][env->current_tc] - 4000; + env->PC[env->current_tc] += 4; if (syscall_num >= sizeof(mips_syscall_args)) { ret = -ENOSYS; } else { @@ -1384,7 +1384,7 @@ void cpu_loop(CPUMIPSState *env) target_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; nb_args = mips_syscall_args[syscall_num]; - sp_reg = env->gpr[29]; + sp_reg = env->gpr[29][env->current_tc]; switch (nb_args) { /* these arguments are taken from the stack */ case 8: arg8 = tgetl(sp_reg + 28); @@ -1394,18 +1394,20 @@ void cpu_loop(CPUMIPSState *env) default: break; } - ret = do_syscall(env, env->gpr[2], - env->gpr[4], env->gpr[5], - env->gpr[6], env->gpr[7], + ret = do_syscall(env, env->gpr[2][env->current_tc], + env->gpr[4][env->current_tc], + env->gpr[5][env->current_tc], + env->gpr[6][env->current_tc], + env->gpr[7][env->current_tc], arg5, arg6/*, arg7, arg8*/); } if ((unsigned int)ret >= (unsigned int)(-1133)) { - env->gpr[7] = 1; /* error flag */ + env->gpr[7][env->current_tc] = 1; /* error flag */ ret = -ret; } else { - env->gpr[7] = 0; /* error flag */ + env->gpr[7][env->current_tc] = 0; /* error flag */ } - env->gpr[2] = ret; + env->gpr[2][env->current_tc] = ret; break; case EXCP_TLBL: case EXCP_TLBS: @@ -2053,9 +2055,9 @@ int main(int argc, char **argv) cpu_mips_register(env, def); for(i = 0; i < 32; i++) { - env->gpr[i] = regs->regs[i]; + env->gpr[i][env->current_tc] = regs->regs[i]; } - env->PC = regs->cp0_epc; + env->PC[env->current_tc] = regs->cp0_epc; } #elif defined(TARGET_SH4) { diff --git a/linux-user/signal.c b/linux-user/signal.c index eea73470fa..f73d50516f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1686,10 +1686,10 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) { int err = 0; - err |= __put_user(regs->PC, &sc->sc_pc); + err |= __put_user(regs->PC[regs->current_tc], &sc->sc_pc); -#define save_gp_reg(i) do { \ - err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \ +#define save_gp_reg(i) do { \ + err |= __put_user(regs->gpr[i][regs->current_tc], &sc->sc_regs[i]); \ } while(0) __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); @@ -1702,8 +1702,8 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) save_gp_reg(31); #undef save_gp_reg - err |= __put_user(regs->HI, &sc->sc_mdhi); - err |= __put_user(regs->LO, &sc->sc_mdlo); + err |= __put_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi); + err |= __put_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo); /* Not used yet, but might be useful if we ever have DSP suppport */ #if 0 @@ -1763,11 +1763,11 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) err |= __get_user(regs->CP0_EPC, &sc->sc_pc); - err |= __get_user(regs->HI, &sc->sc_mdhi); - err |= __get_user(regs->LO, &sc->sc_mdlo); + err |= __get_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi); + err |= __get_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo); -#define restore_gp_reg(i) do { \ - err |= __get_user(regs->gpr[i], &sc->sc_regs[i]); \ +#define restore_gp_reg(i) do { \ + err |= __get_user(regs->gpr[i][regs->current_tc], &sc->sc_regs[i]); \ } while(0) restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); @@ -1833,7 +1833,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) unsigned long sp; /* Default to using normal stack */ - sp = regs->gpr[29]; + sp = regs->gpr[29][regs->current_tc]; /* * FPU emulator may have it's own trampoline active just @@ -1881,15 +1881,15 @@ static void setup_frame(int sig, struct emulated_sigaction * ka, * $25 and PC point to the signal handler, $29 points to the * struct sigframe. */ - regs->gpr[ 4] = sig; - regs->gpr[ 5] = 0; - regs->gpr[ 6] = h2g(&frame->sf_sc); - regs->gpr[29] = h2g(frame); - regs->gpr[31] = h2g(frame->sf_code); + regs->gpr[ 4][regs->current_tc] = sig; + regs->gpr[ 5][regs->current_tc] = 0; + regs->gpr[ 6][regs->current_tc] = h2g(&frame->sf_sc); + regs->gpr[29][regs->current_tc] = h2g(frame); + regs->gpr[31][regs->current_tc] = h2g(frame->sf_code); /* The original kernel code sets CP0_EPC to the handler * since it returns to userland using eret * we cannot do this here, and we must set PC directly */ - regs->PC = regs->gpr[25] = ka->sa._sa_handler; + regs->PC[regs->current_tc] = regs->gpr[25][regs->current_tc] = ka->sa._sa_handler; return; give_sigsegv: @@ -1907,7 +1907,7 @@ long do_sigreturn(CPUState *regs) #if defined(DEBUG_SIGNAL) fprintf(stderr, "do_sigreturn\n"); #endif - frame = (struct sigframe *) regs->gpr[29]; + frame = (struct sigframe *) regs->gpr[29][regs->current_tc]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -1934,7 +1934,7 @@ long do_sigreturn(CPUState *regs) /* Unreached */ #endif - regs->PC = regs->CP0_EPC; + regs->PC[regs->current_tc] = regs->CP0_EPC; /* I am not sure this is right, but it seems to work * maybe a problem with nested signals ? */ regs->CP0_EPC = 0; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e23a684e76..cd956aa1ac 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2189,8 +2189,8 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) /* ??? is this sufficient? */ #elif defined(TARGET_MIPS) if (!newsp) - newsp = env->gpr[29]; - new_env->gpr[29] = newsp; + newsp = env->gpr[29][env->current_tc]; + new_env->gpr[29][env->current_tc] = newsp; #elif defined(TARGET_PPC) if (!newsp) newsp = env->gpr[1]; @@ -2777,7 +2777,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(pipe(host_pipe)); if (!is_error(ret)) { #if defined(TARGET_MIPS) - ((CPUMIPSState*)cpu_env)->gpr[3] = host_pipe[1]; + CPUMIPSState *env = (CPUMIPSState*)cpu_env; + env->gpr[3][env->current_tc] = host_pipe[1]; ret = host_pipe[0]; #else tput32(arg1, host_pipe[0]); @@ -309,6 +309,10 @@ static void do_info_cpus(void) term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc); if (env->halted) term_printf(" (halted)"); +#elif defined(TARGET_MIPS) + term_printf(" PC=0x" TARGET_FMT_lx, env->PC[env->current_tc]); + if (env->halted) + term_printf(" (halted)"); #endif term_printf("\n"); } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f5f35e1223..f8b4b18583 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -17,21 +17,7 @@ typedef unsigned char uint_fast8_t; typedef unsigned int uint_fast16_t; #endif -typedef union fpr_t fpr_t; -union fpr_t { - float64 fd; /* ieee double precision */ - float32 fs[2];/* ieee single precision */ - uint64_t d; /* binary double fixed-point */ - uint32_t w[2]; /* binary single fixed-point */ -}; -/* define FP_ENDIAN_IDX to access the same location - * in the fpr_t union regardless of the host endianess - */ -#if defined(WORDS_BIGENDIAN) -# define FP_ENDIAN_IDX 1 -#else -# define FP_ENDIAN_IDX 0 -#endif +struct CPUMIPSState; typedef struct r4k_tlb_t r4k_tlb_t; struct r4k_tlb_t { @@ -48,20 +34,40 @@ struct r4k_tlb_t { target_ulong PFN[2]; }; -typedef struct mips_def_t mips_def_t; +typedef struct CPUMIPSTLBContext CPUMIPSTLBContext; +struct CPUMIPSTLBContext { + uint32_t nb_tlb; + uint32_t tlb_in_use; + int (*map_address) (struct CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type); + void (*do_tlbwi) (void); + void (*do_tlbwr) (void); + void (*do_tlbp) (void); + void (*do_tlbr) (void); + union { + struct { + r4k_tlb_t tlb[MIPS_TLB_MAX]; + } r4k; + } mmu; +}; -typedef struct CPUMIPSState CPUMIPSState; -struct CPUMIPSState { - /* General integer registers */ - target_ulong gpr[32]; - /* Special registers */ - target_ulong PC; -#if TARGET_LONG_BITS > HOST_LONG_BITS - target_ulong t0; - target_ulong t1; - target_ulong t2; +typedef union fpr_t fpr_t; +union fpr_t { + float64 fd; /* ieee double precision */ + float32 fs[2];/* ieee single precision */ + uint64_t d; /* binary double fixed-point */ + uint32_t w[2]; /* binary single fixed-point */ +}; +/* define FP_ENDIAN_IDX to access the same location + * in the fpr_t union regardless of the host endianess + */ +#if defined(WORDS_BIGENDIAN) +# define FP_ENDIAN_IDX 1 +#else +# define FP_ENDIAN_IDX 0 #endif - target_ulong HI, LO; + +typedef struct CPUMIPSFPUContext CPUMIPSFPUContext; +struct CPUMIPSFPUContext { /* Floating point registers */ fpr_t fpr[32]; #ifndef USE_HOST_FLOAT_REGS @@ -99,30 +105,161 @@ struct CPUMIPSState { #define FP_DIV0 8 #define FP_INVALID 16 #define FP_UNIMPLEMENTED 32 +}; + +typedef struct CPUMIPSMVPContext CPUMIPSMVPContext; +struct CPUMIPSMVPContext { + int32_t CP0_MVPControl; +#define CP0MVPCo_CPA 3 +#define CP0MVPCo_STLB 2 +#define CP0MVPCo_VPC 1 +#define CP0MVPCo_EVP 0 + int32_t CP0_MVPConf0; +#define CP0MVPC0_M 31 +#define CP0MVPC0_TLBS 29 +#define CP0MVPC0_GS 28 +#define CP0MVPC0_PCP 27 +#define CP0MVPC0_PTLBE 16 +#define CP0MVPC0_TCA 15 +#define CP0MVPC0_PVPE 10 +#define CP0MVPC0_PTC 0 + int32_t CP0_MVPConf1; +#define CP0MVPC1_CIM 31 +#define CP0MVPC1_CIF 30 +#define CP0MVPC1_PCX 20 +#define CP0MVPC1_PCP2 10 +#define CP0MVPC1_PCP1 0 +}; + +typedef struct mips_def_t mips_def_t; + +#define MIPS_SHADOW_SET_MAX 16 +#define MIPS_TC_MAX 5 +#define MIPS_DSP_ACC 4 + +typedef struct CPUMIPSState CPUMIPSState; +struct CPUMIPSState { + /* General integer registers */ + target_ulong gpr[32][MIPS_SHADOW_SET_MAX]; + /* Special registers */ + target_ulong PC[MIPS_TC_MAX]; +#if TARGET_LONG_BITS > HOST_LONG_BITS + target_ulong t0; + target_ulong t1; + target_ulong t2; +#endif + target_ulong HI[MIPS_DSP_ACC][MIPS_TC_MAX]; + target_ulong LO[MIPS_DSP_ACC][MIPS_TC_MAX]; + target_ulong ACX[MIPS_DSP_ACC][MIPS_TC_MAX]; + target_ulong DSPControl[MIPS_TC_MAX]; + + CPUMIPSMVPContext *mvp; + CPUMIPSTLBContext *tlb; + CPUMIPSFPUContext *fpu; + uint32_t current_tc; - uint32_t nb_tlb; - uint32_t tlb_in_use; uint32_t SEGBITS; target_ulong SEGMask; - int (*map_address) (CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type); - void (*do_tlbwi) (void); - void (*do_tlbwr) (void); - void (*do_tlbp) (void); - void (*do_tlbr) (void); - union { - struct { - r4k_tlb_t tlb[MIPS_TLB_MAX]; - } r4k; - } mmu; int32_t CP0_Index; + /* CP0_MVP* are per MVP registers. */ int32_t CP0_Random; + int32_t CP0_VPEControl; +#define CP0VPECo_YSI 21 +#define CP0VPECo_GSI 20 +#define CP0VPECo_EXCPT 16 +#define CP0VPECo_TE 15 +#define CP0VPECo_TargTC 0 + int32_t CP0_VPEConf0; +#define CP0VPEC0_M 31 +#define CP0VPEC0_XTC 21 +#define CP0VPEC0_TCS 19 +#define CP0VPEC0_SCS 18 +#define CP0VPEC0_DSC 17 +#define CP0VPEC0_ICS 16 +#define CP0VPEC0_MVP 1 +#define CP0VPEC0_VPA 0 + int32_t CP0_VPEConf1; +#define CP0VPEC1_NCX 20 +#define CP0VPEC1_NCP2 10 +#define CP0VPEC1_NCP1 0 + target_ulong CP0_YQMask; + target_ulong CP0_VPESchedule; + target_ulong CP0_VPEScheFBack; + int32_t CP0_VPEOpt; +#define CP0VPEOpt_IWX7 15 +#define CP0VPEOpt_IWX6 14 +#define CP0VPEOpt_IWX5 13 +#define CP0VPEOpt_IWX4 12 +#define CP0VPEOpt_IWX3 11 +#define CP0VPEOpt_IWX2 10 +#define CP0VPEOpt_IWX1 9 +#define CP0VPEOpt_IWX0 8 +#define CP0VPEOpt_DWX7 7 +#define CP0VPEOpt_DWX6 6 +#define CP0VPEOpt_DWX5 5 +#define CP0VPEOpt_DWX4 4 +#define CP0VPEOpt_DWX3 3 +#define CP0VPEOpt_DWX2 2 +#define CP0VPEOpt_DWX1 1 +#define CP0VPEOpt_DWX0 0 target_ulong CP0_EntryLo0; + int32_t CP0_TCStatus[MIPS_TC_MAX]; +#define CP0TCSt_TCU3 31 +#define CP0TCSt_TCU2 30 +#define CP0TCSt_TCU1 29 +#define CP0TCSt_TCU0 28 +#define CP0TCSt_TMX 27 +#define CP0TCSt_RNST 23 +#define CP0TCSt_TDS 21 +#define CP0TCSt_DT 20 +#define CP0TCSt_DA 15 +#define CP0TCSt_A 13 +#define CP0TCSt_TKSU 11 +#define CP0TCSt_IXMT 10 +#define CP0TCSt_TASID 0 + int32_t CP0_TCBind[MIPS_TC_MAX]; +#define CP0TCBd_CurTC 21 +#define CP0TCBd_TBE 17 +#define CP0TCBd_CurVPE 0 + target_ulong CP0_TCHalt[MIPS_TC_MAX]; + target_ulong CP0_TCContext[MIPS_TC_MAX]; + target_ulong CP0_TCSchedule[MIPS_TC_MAX]; + target_ulong CP0_TCScheFBack[MIPS_TC_MAX]; target_ulong CP0_EntryLo1; target_ulong CP0_Context; int32_t CP0_PageMask; int32_t CP0_PageGrain; int32_t CP0_Wired; + int32_t CP0_SRSConf0_rw_bitmask; + int32_t CP0_SRSConf0; +#define CP0SRSC0_M 31 +#define CP0SRSC0_SRS3 20 +#define CP0SRSC0_SRS2 10 +#define CP0SRSC0_SRS1 0 + int32_t CP0_SRSConf1_rw_bitmask; + int32_t CP0_SRSConf1; +#define CP0SRSC1_M 31 +#define CP0SRSC1_SRS6 20 +#define CP0SRSC1_SRS5 10 +#define CP0SRSC1_SRS4 0 + int32_t CP0_SRSConf2_rw_bitmask; + int32_t CP0_SRSConf2; +#define CP0SRSC2_M 31 +#define CP0SRSC2_SRS9 20 +#define CP0SRSC2_SRS8 10 +#define CP0SRSC2_SRS7 0 + int32_t CP0_SRSConf3_rw_bitmask; + int32_t CP0_SRSConf3; +#define CP0SRSC3_M 31 +#define CP0SRSC3_SRS12 20 +#define CP0SRSC3_SRS11 10 +#define CP0SRSC3_SRS10 0 + int32_t CP0_SRSConf4_rw_bitmask; + int32_t CP0_SRSConf4; +#define CP0SRSC4_SRS15 20 +#define CP0SRSC4_SRS14 10 +#define CP0SRSC4_SRS13 0 int32_t CP0_HWREna; target_ulong CP0_BadVAddr; int32_t CP0_Count; @@ -152,8 +289,24 @@ struct CPUMIPSState { #define CP0St_EXL 1 #define CP0St_IE 0 int32_t CP0_IntCtl; +#define CP0IntCtl_IPTI 29 +#define CP0IntCtl_IPPC1 26 +#define CP0IntCtl_VS 5 int32_t CP0_SRSCtl; +#define CP0SRSCtl_HSS 26 +#define CP0SRSCtl_EICSS 18 +#define CP0SRSCtl_ESS 12 +#define CP0SRSCtl_PSS 6 +#define CP0SRSCtl_CSS 0 int32_t CP0_SRSMap; +#define CP0SRSMap_SSV7 28 +#define CP0SRSMap_SSV6 24 +#define CP0SRSMap_SSV5 20 +#define CP0SRSMap_SSV4 16 +#define CP0SRSMap_SSV3 12 +#define CP0SRSMap_SSV2 8 +#define CP0SRSMap_SSV1 4 +#define CP0SRSMap_SSV0 0 int32_t CP0_Cause; #define CP0Ca_BD 31 #define CP0Ca_TI 30 @@ -219,13 +372,14 @@ struct CPUMIPSState { #define CP0C3_TL 0 int32_t CP0_Config6; int32_t CP0_Config7; + /* XXX: Maybe make LLAddr per-TC? */ target_ulong CP0_LLAddr; target_ulong CP0_WatchLo[8]; int32_t CP0_WatchHi[8]; target_ulong CP0_XContext; int32_t CP0_Framemask; int32_t CP0_Debug; -#define CPDB_DBD 31 +#define CP0DB_DBD 31 #define CP0DB_DM 30 #define CP0DB_LSNM 28 #define CP0DB_Doze 27 @@ -243,6 +397,7 @@ struct CPUMIPSState { #define CP0DB_DDBL 2 #define CP0DB_DBp 1 #define CP0DB_DSS 0 + int32_t CP0_Debug_tcstatus[MIPS_TC_MAX]; target_ulong CP0_DEPC; int32_t CP0_Performance0; int32_t CP0_TagLo; @@ -284,7 +439,8 @@ struct CPUMIPSState { int SYNCI_Step; /* Address step size for SYNCI */ int CCRes; /* Cycle count resolution/divisor */ - int Status_rw_bitmask; /* Read/write bits in CP0_Status */ + uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */ + uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */ #ifdef CONFIG_USER_ONLY target_ulong tls_value; @@ -376,6 +532,7 @@ enum { EXCP_TLBS, EXCP_DBE, EXCP_DDBL, + EXCP_THREAD, EXCP_MTCP0 = 0x104, /* mtmsr instruction: */ /* may change privilege level */ EXCP_BRANCH = 0x108, /* branch instruction */ diff --git a/target-mips/exec.h b/target-mips/exec.h index 5b0c833848..53c4189a51 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -23,24 +23,24 @@ register target_ulong T2 asm(AREG3); #if defined (USE_HOST_FLOAT_REGS) #error "implement me." #else -#define FDT0 (env->ft0.fd) -#define FDT1 (env->ft1.fd) -#define FDT2 (env->ft2.fd) -#define FST0 (env->ft0.fs[FP_ENDIAN_IDX]) -#define FST1 (env->ft1.fs[FP_ENDIAN_IDX]) -#define FST2 (env->ft2.fs[FP_ENDIAN_IDX]) -#define FSTH0 (env->ft0.fs[!FP_ENDIAN_IDX]) -#define FSTH1 (env->ft1.fs[!FP_ENDIAN_IDX]) -#define FSTH2 (env->ft2.fs[!FP_ENDIAN_IDX]) -#define DT0 (env->ft0.d) -#define DT1 (env->ft1.d) -#define DT2 (env->ft2.d) -#define WT0 (env->ft0.w[FP_ENDIAN_IDX]) -#define WT1 (env->ft1.w[FP_ENDIAN_IDX]) -#define WT2 (env->ft2.w[FP_ENDIAN_IDX]) -#define WTH0 (env->ft0.w[!FP_ENDIAN_IDX]) -#define WTH1 (env->ft1.w[!FP_ENDIAN_IDX]) -#define WTH2 (env->ft2.w[!FP_ENDIAN_IDX]) +#define FDT0 (env->fpu->ft0.fd) +#define FDT1 (env->fpu->ft1.fd) +#define FDT2 (env->fpu->ft2.fd) +#define FST0 (env->fpu->ft0.fs[FP_ENDIAN_IDX]) +#define FST1 (env->fpu->ft1.fs[FP_ENDIAN_IDX]) +#define FST2 (env->fpu->ft2.fs[FP_ENDIAN_IDX]) +#define FSTH0 (env->fpu->ft0.fs[!FP_ENDIAN_IDX]) +#define FSTH1 (env->fpu->ft1.fs[!FP_ENDIAN_IDX]) +#define FSTH2 (env->fpu->ft2.fs[!FP_ENDIAN_IDX]) +#define DT0 (env->fpu->ft0.d) +#define DT1 (env->fpu->ft1.d) +#define DT2 (env->fpu->ft2.d) +#define WT0 (env->fpu->ft0.w[FP_ENDIAN_IDX]) +#define WT1 (env->fpu->ft1.w[FP_ENDIAN_IDX]) +#define WT2 (env->fpu->ft2.w[FP_ENDIAN_IDX]) +#define WTH0 (env->fpu->ft0.w[!FP_ENDIAN_IDX]) +#define WTH1 (env->fpu->ft1.w[!FP_ENDIAN_IDX]) +#define WTH2 (env->fpu->ft2.w[!FP_ENDIAN_IDX]) #endif #if defined (DEBUG_OP) @@ -157,7 +157,8 @@ void cpu_mips_update_irq (CPUState *env); void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); -void do_ctc1 (void); +void do_cfc1 (int reg); +void do_ctc1 (int reg); #define FOP_PROTO(op) \ void do_float_ ## op ## _s(void); \ diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c index 0f1595ff87..bbdcb28903 100644 --- a/target-mips/fop_template.c +++ b/target-mips/fop_template.c @@ -24,14 +24,14 @@ #define OP_WLOAD_FREG(treg, tregname, FREG) \ void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ - treg = env->fpr[FREG].fs[FP_ENDIAN_IDX]; \ + treg = env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX]; \ RETURN(); \ } #define OP_WSTORE_FREG(treg, tregname, FREG) \ void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ - env->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \ + env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \ RETURN(); \ } @@ -50,10 +50,10 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ if (env->hflags & MIPS_HFLAG_F64) \ - treg = env->fpr[FREG].fd; \ + treg = env->fpu->fpr[FREG].fd; \ else \ - treg = (uint64_t)(env->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \ - env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \ + treg = (uint64_t)(env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \ + env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \ RETURN(); \ } @@ -61,10 +61,10 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ if (env->hflags & MIPS_HFLAG_F64) \ - env->fpr[FREG].fd = treg; \ + env->fpu->fpr[FREG].fd = treg; \ else { \ - env->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \ - env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \ + env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \ + env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \ } \ RETURN(); \ } @@ -81,14 +81,14 @@ OP_DSTORE_FREG(DT2, DT2_fpr, FREG) #define OP_PSLOAD_FREG(treg, tregname, FREG) \ void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ - treg = env->fpr[FREG].fs[!FP_ENDIAN_IDX]; \ + treg = env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX]; \ RETURN(); \ } #define OP_PSSTORE_FREG(treg, tregname, FREG) \ void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ - env->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \ + env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \ RETURN(); \ } diff --git a/target-mips/helper.c b/target-mips/helper.c index 1c83704705..6d0be10156 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -70,8 +70,8 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, uint8_t ASID = env->CP0_EntryHi & 0xFF; int i; - for (i = 0; i < env->tlb_in_use; i++) { - r4k_tlb_t *tlb = &env->mmu.r4k.tlb[i]; + for (i = 0; i < env->tlb->tlb_in_use; i++) { + r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i]; /* 1k pages are not supported. */ target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); target_ulong tag = address & ~mask; @@ -134,7 +134,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, *physical = address & 0xFFFFFFFF; *prot = PAGE_READ | PAGE_WRITE; } else { - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } #ifdef TARGET_MIPS64 /* @@ -144,14 +144,14 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else if (address < 0x3FFFFFFFFFFFFFFFULL) { /* xuseg */ if (UX && address < (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } } else if (address < 0x7FFFFFFFFFFFFFFFULL) { /* xsseg */ if (SX && address < (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } @@ -169,7 +169,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, /* xkseg */ /* XXX: check supervisor mode */ if (KX && address < (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } @@ -186,12 +186,12 @@ static int get_physical_address (CPUState *env, target_ulong *physical, *prot = PAGE_READ | PAGE_WRITE; } else if (address < (int32_t)0xE0000000UL) { /* kseg2 */ - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { /* kseg3 */ /* XXX: check supervisor mode */ /* XXX: debug segment is not emulated */ - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } #if 0 if (logfile) { @@ -238,7 +238,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, cpu_dump_state(env, logfile, fprintf, 0); #endif fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d is_user %d smmu %d\n", - __func__, env->PC, address, rw, is_user, is_softmmu); + __func__, env->PC[env->current_tc], address, rw, is_user, is_softmmu); } rw &= 1; @@ -328,7 +328,7 @@ void do_interrupt (CPUState *env) if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n", - __func__, env->PC, env->CP0_EPC, cause, env->exception_index); + __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index); } if (env->exception_index == EXCP_EXT_INTERRUPT && (env->hflags & MIPS_HFLAG_DM)) @@ -342,7 +342,7 @@ void do_interrupt (CPUState *env) * (but we assume the pc has always been updated during * code translation). */ - env->CP0_DEPC = env->PC; + env->CP0_DEPC = env->PC[env->current_tc]; goto enter_debug_mode; case EXCP_DINT: env->CP0_Debug |= 1 << CP0DB_DINT; @@ -362,10 +362,10 @@ void do_interrupt (CPUState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ - env->CP0_DEPC = env->PC - 4; + env->CP0_DEPC = env->PC[env->current_tc] - 4; env->hflags &= ~MIPS_HFLAG_BMASK; } else { - env->CP0_DEPC = env->PC; + env->CP0_DEPC = env->PC[env->current_tc]; } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; @@ -375,7 +375,7 @@ void do_interrupt (CPUState *env) /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); - env->PC = (int32_t)0xBFC00480; + env->PC[env->current_tc] = (int32_t)0xBFC00480; break; case EXCP_RESET: cpu_reset(env); @@ -390,10 +390,10 @@ void do_interrupt (CPUState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ - env->CP0_ErrorEPC = env->PC - 4; + env->CP0_ErrorEPC = env->PC[env->current_tc] - 4; env->hflags &= ~MIPS_HFLAG_BMASK; } else { - env->CP0_ErrorEPC = env->PC; + env->CP0_ErrorEPC = env->PC[env->current_tc]; } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) @@ -401,7 +401,7 @@ void do_interrupt (CPUState *env) env->hflags &= ~MIPS_HFLAG_UM; if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); - env->PC = (int32_t)0xBFC00000; + env->PC[env->current_tc] = (int32_t)0xBFC00000; break; case EXCP_MCHECK: cause = 24; @@ -471,6 +471,9 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBS: cause = 3; + goto set_EPC; + case EXCP_THREAD: + cause = 25; if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { #ifdef TARGET_MIPS64 int R = env->CP0_BadVAddr >> 62; @@ -489,10 +492,10 @@ void do_interrupt (CPUState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ - env->CP0_EPC = env->PC - 4; + env->CP0_EPC = env->PC[env->current_tc] - 4; env->CP0_Cause |= (1 << CP0Ca_BD); } else { - env->CP0_EPC = env->PC; + env->CP0_EPC = env->PC[env->current_tc]; env->CP0_Cause &= ~(1 << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); @@ -502,11 +505,11 @@ void do_interrupt (CPUState *env) } env->hflags &= ~MIPS_HFLAG_BMASK; if (env->CP0_Status & (1 << CP0St_BEV)) { - env->PC = (int32_t)0xBFC00200; + env->PC[env->current_tc] = (int32_t)0xBFC00200; } else { - env->PC = (int32_t)(env->CP0_EBase & ~0x3ff); + env->PC[env->current_tc] = (int32_t)(env->CP0_EBase & ~0x3ff); } - env->PC += offset; + env->PC[env->current_tc] += offset; env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); break; default: @@ -520,7 +523,7 @@ void do_interrupt (CPUState *env) if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n" " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n", - __func__, env->PC, env->CP0_EPC, cause, env->exception_index, + __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index, env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, env->CP0_DEPC); } @@ -536,19 +539,19 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) uint8_t ASID = env->CP0_EntryHi & 0xFF; target_ulong mask; - tlb = &env->mmu.r4k.tlb[idx]; + tlb = &env->tlb->mmu.r4k.tlb[idx]; /* The qemu TLB is flushed when the ASID changes, so no need to flush these entries again. */ if (tlb->G == 0 && tlb->ASID != ASID) { return; } - if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) { + if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) { /* For tlbwr, we can shadow the discarded entry into a new (fake) TLB entry, as long as the guest can not tell that it's there. */ - env->mmu.r4k.tlb[env->tlb_in_use] = *tlb; - env->tlb_in_use++; + env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb; + env->tlb->tlb_in_use++; return; } diff --git a/target-mips/op.c b/target-mips/op.c index 12498d0335..3f52f59d34 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -254,25 +254,25 @@ void op_dup_T0 (void) void op_load_HI (void) { - T0 = env->HI; + T0 = env->HI[PARAM1][env->current_tc]; RETURN(); } void op_store_HI (void) { - env->HI = T0; + env->HI[PARAM1][env->current_tc] = T0; RETURN(); } void op_load_LO (void) { - T0 = env->LO; + T0 = env->LO[PARAM1][env->current_tc]; RETURN(); } void op_store_LO (void) { - env->LO = T0; + env->LO[PARAM1][env->current_tc] = T0; RETURN(); } @@ -363,8 +363,8 @@ void op_div (void) void op_div (void) { if (T1 != 0) { - env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); - env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); + env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); + env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); } RETURN(); } @@ -373,8 +373,8 @@ void op_div (void) void op_divu (void) { if (T1 != 0) { - env->LO = (int32_t)((uint32_t)T0 / (uint32_t)T1); - env->HI = (int32_t)((uint32_t)T0 % (uint32_t)T1); + env->LO[0][env->current_tc] = (int32_t)((uint32_t)T0 / (uint32_t)T1); + env->HI[0][env->current_tc] = (int32_t)((uint32_t)T0 % (uint32_t)T1); } RETURN(); } @@ -442,8 +442,8 @@ void op_ddivu (void) void op_ddivu (void) { if (T1 != 0) { - env->LO = T0 / T1; - env->HI = T0 % T1; + env->LO[0][env->current_tc] = T0 / T1; + env->HI[0][env->current_tc] = T0 % T1; } RETURN(); } @@ -814,13 +814,14 @@ void op_msubu (void) static inline uint64_t get_HILO (void) { - return ((uint64_t)env->HI << 32) | ((uint64_t)(uint32_t)env->LO); + return ((uint64_t)env->HI[0][env->current_tc] << 32) | + ((uint64_t)(uint32_t)env->LO[0][env->current_tc]); } static inline void set_HILO (uint64_t HILO) { - env->LO = (int32_t)(HILO & 0xFFFFFFFF); - env->HI = (int32_t)(HILO >> 32); + env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF); + env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); } void op_mult (void) @@ -875,13 +876,13 @@ void op_msubu (void) #ifdef TARGET_MIPS64 void op_dmult (void) { - CALL_FROM_TB4(muls64, &(env->HI), &(env->LO), T0, T1); + CALL_FROM_TB4(muls64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1); RETURN(); } void op_dmultu (void) { - CALL_FROM_TB4(mulu64, &(env->HI), &(env->LO), T0, T1); + CALL_FROM_TB4(mulu64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1); RETURN(); } #endif @@ -890,27 +891,27 @@ void op_dmultu (void) void op_movn (void) { if (T1 != 0) - env->gpr[PARAM1] = T0; + env->gpr[PARAM1][env->current_tc] = T0; RETURN(); } void op_movz (void) { if (T1 == 0) - env->gpr[PARAM1] = T0; + env->gpr[PARAM1][env->current_tc] = T0; RETURN(); } void op_movf (void) { - if (!(env->fcr31 & PARAM1)) + if (!(env->fpu->fcr31 & PARAM1)) T0 = T1; RETURN(); } void op_movt (void) { - if (env->fcr31 & PARAM1) + if (env->fpu->fcr31 & PARAM1) T0 = T1; RETURN(); } @@ -966,7 +967,7 @@ void op_restore_breg_target (void) void op_breg (void) { - env->PC = T2; + env->PC[env->current_tc] = T2; RETURN(); } @@ -1017,18 +1018,176 @@ void op_mfc0_index (void) RETURN(); } +void op_mfc0_mvpcontrol (void) +{ + T0 = env->mvp->CP0_MVPControl; + RETURN(); +} + +void op_mfc0_mvpconf0 (void) +{ + T0 = env->mvp->CP0_MVPConf0; + RETURN(); +} + +void op_mfc0_mvpconf1 (void) +{ + T0 = env->mvp->CP0_MVPConf1; + RETURN(); +} + void op_mfc0_random (void) { CALL_FROM_TB0(do_mfc0_random); RETURN(); } +void op_mfc0_vpecontrol (void) +{ + T0 = env->CP0_VPEControl; + RETURN(); +} + +void op_mfc0_vpeconf0 (void) +{ + T0 = env->CP0_VPEConf0; + RETURN(); +} + +void op_mfc0_vpeconf1 (void) +{ + T0 = env->CP0_VPEConf1; + RETURN(); +} + +void op_mfc0_yqmask (void) +{ + T0 = env->CP0_YQMask; + RETURN(); +} + +void op_mfc0_vpeschedule (void) +{ + T0 = env->CP0_VPESchedule; + RETURN(); +} + +void op_mfc0_vpeschefback (void) +{ + T0 = env->CP0_VPEScheFBack; + RETURN(); +} + +void op_mfc0_vpeopt (void) +{ + T0 = env->CP0_VPEOpt; + RETURN(); +} + void op_mfc0_entrylo0 (void) { T0 = (int32_t)env->CP0_EntryLo0; RETURN(); } +void op_mfc0_tcstatus (void) +{ + T0 = env->CP0_TCStatus[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcstatus(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCStatus[other_tc]; + RETURN(); +} + +void op_mfc0_tcbind (void) +{ + T0 = env->CP0_TCBind[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcbind(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCBind[other_tc]; + RETURN(); +} + +void op_mfc0_tcrestart (void) +{ + T0 = env->PC[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcrestart(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->PC[other_tc]; + RETURN(); +} + +void op_mfc0_tchalt (void) +{ + T0 = env->CP0_TCHalt[env->current_tc]; + RETURN(); +} + +void op_mftc0_tchalt(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCHalt[other_tc]; + RETURN(); +} + +void op_mfc0_tccontext (void) +{ + T0 = env->CP0_TCContext[env->current_tc]; + RETURN(); +} + +void op_mftc0_tccontext(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCContext[other_tc]; + RETURN(); +} + +void op_mfc0_tcschedule (void) +{ + T0 = env->CP0_TCSchedule[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcschedule(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCSchedule[other_tc]; + RETURN(); +} + +void op_mfc0_tcschefback (void) +{ + T0 = env->CP0_TCScheFBack[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcschefback(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCScheFBack[other_tc]; + RETURN(); +} + void op_mfc0_entrylo1 (void) { T0 = (int32_t)env->CP0_EntryLo1; @@ -1059,6 +1218,36 @@ void op_mfc0_wired (void) RETURN(); } +void op_mfc0_srsconf0 (void) +{ + T0 = env->CP0_SRSConf0; + RETURN(); +} + +void op_mfc0_srsconf1 (void) +{ + T0 = env->CP0_SRSConf1; + RETURN(); +} + +void op_mfc0_srsconf2 (void) +{ + T0 = env->CP0_SRSConf2; + RETURN(); +} + +void op_mfc0_srsconf3 (void) +{ + T0 = env->CP0_SRSConf3; + RETURN(); +} + +void op_mfc0_srsconf4 (void) +{ + T0 = env->CP0_SRSConf4; + RETURN(); +} + void op_mfc0_hwrena (void) { T0 = env->CP0_HWREna; @@ -1083,6 +1272,14 @@ void op_mfc0_entryhi (void) RETURN(); } +void op_mftc0_entryhi(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = (env->CP0_EntryHi & ~0xff) | (env->CP0_TCStatus[other_tc] & 0xff); + RETURN(); +} + void op_mfc0_compare (void) { T0 = env->CP0_Compare; @@ -1095,6 +1292,18 @@ void op_mfc0_status (void) RETURN(); } +void op_mftc0_status(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t tcstatus = env->CP0_TCStatus[other_tc]; + + T0 = env->CP0_Status & ~0xf1000018; + T0 |= tcstatus & (0xf << CP0TCSt_TCU0); + T0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); + T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_R0); + RETURN(); +} + void op_mfc0_intctl (void) { T0 = env->CP0_IntCtl; @@ -1211,6 +1420,17 @@ void op_mfc0_debug (void) RETURN(); } +void op_mftc0_debug(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + /* XXX: Might be wrong, check with EJTAG spec. */ + T0 = (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | + (env->CP0_Debug_tcstatus[other_tc] & + ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); + RETURN(); +} + void op_mfc0_depc (void) { T0 = (int32_t)env->CP0_DEPC; @@ -1261,7 +1481,105 @@ void op_mfc0_desave (void) void op_mtc0_index (void) { - env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->nb_tlb); + env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->tlb->nb_tlb); + RETURN(); +} + +void op_mtc0_mvpcontrol (void) +{ + uint32_t mask = 0; + uint32_t newval; + + if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) + mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) | + (1 << CP0MVPCo_EVP); + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0MVPCo_STLB); + newval = (env->mvp->CP0_MVPControl & ~mask) | (T0 & mask); + + // TODO: Enable/disable shared TLB, enable/disable VPEs. + + env->mvp->CP0_MVPControl = newval; + RETURN(); +} + +void op_mtc0_vpecontrol (void) +{ + uint32_t mask; + uint32_t newval; + + mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) | + (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC); + newval = (env->CP0_VPEControl & ~mask) | (T0 & mask); + + /* Yield scheduler intercept not implemented. */ + /* Gating storage scheduler intercept not implemented. */ + + // TODO: Enable/disable TCs. + + env->CP0_VPEControl = newval; + RETURN(); +} + +void op_mtc0_vpeconf0 (void) +{ + uint32_t mask = 0; + uint32_t newval; + + if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) { + if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA)) + mask |= (0xff << CP0VPEC0_XTC); + mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); + } + newval = (env->CP0_VPEConf0 & ~mask) | (T0 & mask); + + // TODO: TC exclusive handling due to ERL/EXL. + + env->CP0_VPEConf0 = newval; + RETURN(); +} + +void op_mtc0_vpeconf1 (void) +{ + uint32_t mask = 0; + uint32_t newval; + + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) | + (0xff << CP0VPEC1_NCP1); + newval = (env->CP0_VPEConf1 & ~mask) | (T0 & mask); + + /* UDI not implemented. */ + /* CP2 not implemented. */ + + // TODO: Handle FPU (CP1) binding. + + env->CP0_VPEConf1 = newval; + RETURN(); +} + +void op_mtc0_yqmask (void) +{ + /* Yield qualifier inputs not implemented. */ + env->CP0_YQMask = 0x00000000; + RETURN(); +} + +void op_mtc0_vpeschedule (void) +{ + env->CP0_VPESchedule = T0; + RETURN(); +} + +void op_mtc0_vpeschefback (void) +{ + env->CP0_VPEScheFBack = T0; + RETURN(); +} + +void op_mtc0_vpeopt (void) +{ + env->CP0_VPEOpt = T0 & 0x0000ffff; RETURN(); } @@ -1273,6 +1591,135 @@ void op_mtc0_entrylo0 (void) RETURN(); } +void op_mtc0_tcstatus (void) +{ + uint32_t mask = env->CP0_TCStatus_rw_bitmask; + uint32_t newval; + + newval = (env->CP0_TCStatus[env->current_tc] & ~mask) | (T0 & mask); + + // TODO: Sync with CP0_Status. + + env->CP0_TCStatus[env->current_tc] = newval; + RETURN(); +} + +void op_mttc0_tcstatus (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + // TODO: Sync with CP0_Status. + + env->CP0_TCStatus[other_tc] = T0; + RETURN(); +} + +void op_mtc0_tcbind (void) +{ + uint32_t mask = (1 << CP0TCBd_TBE); + uint32_t newval; + + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0TCBd_CurVPE); + newval = (env->CP0_TCBind[env->current_tc] & ~mask) | (T0 & mask); + env->CP0_TCBind[env->current_tc] = newval; + RETURN(); +} + +void op_mttc0_tcbind (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t mask = (1 << CP0TCBd_TBE); + uint32_t newval; + + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0TCBd_CurVPE); + newval = (env->CP0_TCBind[other_tc] & ~mask) | (T0 & mask); + env->CP0_TCBind[other_tc] = newval; + RETURN(); +} + +void op_mtc0_tcrestart (void) +{ + env->PC[env->current_tc] = T0; + env->CP0_TCStatus[env->current_tc] &= ~(1 << CP0TCSt_TDS); + env->CP0_LLAddr = 0ULL; + /* MIPS16 not implemented. */ + RETURN(); +} + +void op_mttc0_tcrestart (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->PC[other_tc] = T0; + env->CP0_TCStatus[other_tc] &= ~(1 << CP0TCSt_TDS); + env->CP0_LLAddr = 0ULL; + /* MIPS16 not implemented. */ + RETURN(); +} + +void op_mtc0_tchalt (void) +{ + env->CP0_TCHalt[env->current_tc] = T0 & 0x1; + + // TODO: Halt TC / Restart (if allocated+active) TC. + + RETURN(); +} + +void op_mttc0_tchalt (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + // TODO: Halt TC / Restart (if allocated+active) TC. + + env->CP0_TCHalt[other_tc] = T0; + RETURN(); +} + +void op_mtc0_tccontext (void) +{ + env->CP0_TCContext[env->current_tc] = T0; + RETURN(); +} + +void op_mttc0_tccontext (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->CP0_TCContext[other_tc] = T0; + RETURN(); +} + +void op_mtc0_tcschedule (void) +{ + env->CP0_TCSchedule[env->current_tc] = T0; + RETURN(); +} + +void op_mttc0_tcschedule (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->CP0_TCSchedule[other_tc] = T0; + RETURN(); +} + +void op_mtc0_tcschefback (void) +{ + env->CP0_TCScheFBack[env->current_tc] = T0; + RETURN(); +} + +void op_mttc0_tcschefback (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->CP0_TCScheFBack[other_tc] = T0; + RETURN(); +} + void op_mtc0_entrylo1 (void) { /* Large physaddr not implemented */ @@ -1305,7 +1752,37 @@ void op_mtc0_pagegrain (void) void op_mtc0_wired (void) { - env->CP0_Wired = T0 % env->nb_tlb; + env->CP0_Wired = T0 % env->tlb->nb_tlb; + RETURN(); +} + +void op_mtc0_srsconf0 (void) +{ + env->CP0_SRSConf0 |= T0 & env->CP0_SRSConf0_rw_bitmask; + RETURN(); +} + +void op_mtc0_srsconf1 (void) +{ + env->CP0_SRSConf1 |= T0 & env->CP0_SRSConf1_rw_bitmask; + RETURN(); +} + +void op_mtc0_srsconf2 (void) +{ + env->CP0_SRSConf2 |= T0 & env->CP0_SRSConf2_rw_bitmask; + RETURN(); +} + +void op_mtc0_srsconf3 (void) +{ + env->CP0_SRSConf3 |= T0 & env->CP0_SRSConf3_rw_bitmask; + RETURN(); +} + +void op_mtc0_srsconf4 (void) +{ + env->CP0_SRSConf4 |= T0 & env->CP0_SRSConf4_rw_bitmask; RETURN(); } @@ -1332,12 +1809,25 @@ void op_mtc0_entryhi (void) #endif old = env->CP0_EntryHi; env->CP0_EntryHi = val; + if (env->CP0_Config3 & (1 << CP0C3_MT)) { + uint32_t tcst = env->CP0_TCStatus[env->current_tc] & ~0xff; + env->CP0_TCStatus[env->current_tc] = tcst | (val & 0xff); + } /* If the ASID changes, flush qemu's TLB. */ if ((old & 0xFF) != (val & 0xFF)) CALL_FROM_TB2(cpu_mips_tlb_flush, env, 1); RETURN(); } +void op_mttc0_entryhi(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (T0 & ~0xff); + env->CP0_TCStatus[other_tc] = (env->CP0_TCStatus[other_tc] & ~0xff) | (T0 & 0xff); + RETURN(); +} + void op_mtc0_compare (void) { CALL_FROM_TB2(cpu_mips_store_compare, env, T0); @@ -1347,9 +1837,8 @@ void op_mtc0_compare (void) void op_mtc0_status (void) { uint32_t val, old; - uint32_t mask = env->Status_rw_bitmask; + uint32_t mask = env->CP0_Status_rw_bitmask; - /* No reverse endianness, no MDMX/DSP implemented. */ val = T0 & mask; old = env->CP0_Status; if (!(val & (1 << CP0St_EXL)) && @@ -1379,6 +1868,19 @@ void op_mtc0_status (void) RETURN(); } +void op_mttc0_status(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t tcstatus = env->CP0_TCStatus[other_tc]; + + env->CP0_Status = T0 & ~0xf1000018; + tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (T0 & (0xf << CP0St_CU0)); + tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((T0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); + tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((T0 & (0x3 << CP0St_R0)) << (CP0TCSt_TKSU - CP0St_R0)); + env->CP0_TCStatus[other_tc] = tcstatus; + RETURN(); +} + void op_mtc0_intctl (void) { /* vectored interrupts not implemented, timer on int 7, @@ -1389,15 +1891,14 @@ void op_mtc0_intctl (void) void op_mtc0_srsctl (void) { - /* shadow registers not implemented */ - env->CP0_SRSCtl = 0; + uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS); + env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (T0 & mask); RETURN(); } void op_mtc0_srsmap (void) { - /* shadow registers not implemented */ - env->CP0_SRSMap = 0; + env->CP0_SRSMap = T0; RETURN(); } @@ -1460,6 +1961,13 @@ void op_mtc0_watchhi (void) RETURN(); } +void op_mtc0_xcontext (void) +{ + target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; + env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask); + RETURN(); +} + void op_mtc0_framemask (void) { env->CP0_Framemask = T0; /* XXX */ @@ -1476,6 +1984,17 @@ void op_mtc0_debug (void) RETURN(); } +void op_mttc0_debug(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + /* XXX: Might be wrong, check with EJTAG spec. */ + env->CP0_Debug_tcstatus[other_tc] = T0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)); + env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | + (T0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); + RETURN(); +} + void op_mtc0_depc (void) { env->CP0_DEPC = T0; @@ -1525,10 +2044,21 @@ void op_mtc0_desave (void) } #ifdef TARGET_MIPS64 -void op_mtc0_xcontext (void) +void op_dmfc0_yqmask (void) { - target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; - env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask); + T0 = env->CP0_YQMask; + RETURN(); +} + +void op_dmfc0_vpeschedule (void) +{ + T0 = env->CP0_VPESchedule; + RETURN(); +} + +void op_dmfc0_vpeschefback (void) +{ + T0 = env->CP0_VPEScheFBack; RETURN(); } @@ -1538,6 +2068,36 @@ void op_dmfc0_entrylo0 (void) RETURN(); } +void op_dmfc0_tcrestart (void) +{ + T0 = env->PC[env->current_tc]; + RETURN(); +} + +void op_dmfc0_tchalt (void) +{ + T0 = env->CP0_TCHalt[env->current_tc]; + RETURN(); +} + +void op_dmfc0_tccontext (void) +{ + T0 = env->CP0_TCContext[env->current_tc]; + RETURN(); +} + +void op_dmfc0_tcschedule (void) +{ + T0 = env->CP0_TCSchedule[env->current_tc]; + RETURN(); +} + +void op_dmfc0_tcschefback (void) +{ + T0 = env->CP0_TCScheFBack[env->current_tc]; + RETURN(); +} + void op_dmfc0_entrylo1 (void) { T0 = env->CP0_EntryLo1; @@ -1599,6 +2159,157 @@ void op_dmfc0_errorepc (void) } #endif /* TARGET_MIPS64 */ +/* MIPS MT functions */ +void op_mftgpr(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->gpr[PARAM1][other_tc]; + RETURN(); +} + +void op_mftlo(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->LO[PARAM1][other_tc]; + RETURN(); +} + +void op_mfthi(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->HI[PARAM1][other_tc]; + RETURN(); +} + +void op_mftacx(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->ACX[PARAM1][other_tc]; + RETURN(); +} + +void op_mftdsp(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->DSPControl[other_tc]; + RETURN(); +} + +void op_mttgpr(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->gpr[PARAM1][other_tc]; + RETURN(); +} + +void op_mttlo(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->LO[PARAM1][other_tc]; + RETURN(); +} + +void op_mtthi(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->HI[PARAM1][other_tc]; + RETURN(); +} + +void op_mttacx(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->ACX[PARAM1][other_tc]; + RETURN(); +} + +void op_mttdsp(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->DSPControl[other_tc]; + RETURN(); +} + + +void op_dmt(void) +{ + // TODO + T0 = 0; + // rt = T0 + RETURN(); +} + +void op_emt(void) +{ + // TODO + T0 = 0; + // rt = T0 + RETURN(); +} + +void op_dvpe(void) +{ + // TODO + T0 = 0; + // rt = T0 + RETURN(); +} + +void op_evpe(void) +{ + // TODO + T0 = 0; + // rt = T0 + RETURN(); +} + +void op_fork(void) +{ + // T0 = rt, T1 = rs + T0 = 0; + // TODO: store to TC register + RETURN(); +} + +void op_yield(void) +{ + if (T0 < 0) { + /* No scheduling policy implemented. */ + if (T0 != -2) { + if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) && + env->CP0_TCStatus[env->current_tc] & (1 << CP0TCSt_DT)) { + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; + CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); + } + } + } else if (T0 == 0) { + if (0 /* TODO: TC underflow */) { + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); + } else { + // TODO: Deallocate TC + } + } else if (T0 > 0) { + /* Yield qualifier inputs not implemented. */ + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; + CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); + } + T0 = env->CP0_YQMask; + RETURN(); +} + /* CP1 functions */ #if 0 # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) @@ -1617,30 +2328,14 @@ void op_cp0_enabled(void) void op_cfc1 (void) { - switch (T1) { - case 0: - T0 = (int32_t)env->fcr0; - break; - case 25: - T0 = ((env->fcr31 >> 24) & 0xfe) | ((env->fcr31 >> 23) & 0x1); - break; - case 26: - T0 = env->fcr31 & 0x0003f07c; - break; - case 28: - T0 = (env->fcr31 & 0x00000f83) | ((env->fcr31 >> 22) & 0x4); - break; - default: - T0 = (int32_t)env->fcr31; - break; - } + CALL_FROM_TB1(do_cfc1, PARAM1); DEBUG_FPU_STATE(); RETURN(); } void op_ctc1 (void) { - CALL_FROM_TB0(do_ctc1); + CALL_FROM_TB1(do_ctc1, PARAM1); DEBUG_FPU_STATE(); RETURN(); } @@ -1842,21 +2537,21 @@ FLOAT_ROUNDOP(floor, w, s) FLOAT_OP(movf, d) { - if (!(env->fcr31 & PARAM1)) + if (!(env->fpu->fcr31 & PARAM1)) DT2 = DT0; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(movf, s) { - if (!(env->fcr31 & PARAM1)) + if (!(env->fpu->fcr31 & PARAM1)) WT2 = WT0; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(movf, ps) { - if (!(env->fcr31 & PARAM1)) { + if (!(env->fpu->fcr31 & PARAM1)) { WT2 = WT0; WTH2 = WTH0; } @@ -1865,21 +2560,21 @@ FLOAT_OP(movf, ps) } FLOAT_OP(movt, d) { - if (env->fcr31 & PARAM1) + if (env->fpu->fcr31 & PARAM1) DT2 = DT0; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(movt, s) { - if (env->fcr31 & PARAM1) + if (env->fpu->fcr31 & PARAM1) WT2 = WT0; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(movt, ps) { - if (env->fcr31 & PARAM1) { + if (env->fpu->fcr31 & PARAM1) { WT2 = WT0; WTH2 = WTH0; } @@ -1997,24 +2692,24 @@ FLOAT_HOP(mulr) #define FLOAT_TERNOP(name1, name2) \ FLOAT_OP(name1 ## name2, d) \ { \ - FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status); \ - FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status); \ + FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ + FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name1 ## name2, s) \ { \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name1 ## name2, ps) \ { \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ - FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ - FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ + FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ + FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } @@ -2026,26 +2721,26 @@ FLOAT_TERNOP(mul, sub) #define FLOAT_NTERNOP(name1, name2) \ FLOAT_OP(n ## name1 ## name2, d) \ { \ - FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status); \ - FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status); \ + FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ + FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ FDT2 ^= 1ULL << 63; \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(n ## name1 ## name2, s) \ { \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ FST2 ^= 1 << 31; \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(n ## name1 ## name2, ps) \ { \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ - FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ - FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ + FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ + FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ FST2 ^= 1 << 31; \ FSTH2 ^= 1 << 31; \ DEBUG_FPU_STATE(); \ @@ -2059,13 +2754,13 @@ FLOAT_NTERNOP(mul, sub) #define FLOAT_UNOP(name) \ FLOAT_OP(name, d) \ { \ - FDT2 = float64_ ## name(FDT0, &env->fp_status); \ + FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name, s) \ { \ - FST2 = float32_ ## name(FST0, &env->fp_status); \ + FST2 = float32_ ## name(FST0, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } @@ -2141,9 +2836,9 @@ FLOAT_OP(alnv, ps) #ifdef CONFIG_SOFTFLOAT #define clear_invalid() do { \ - int flags = get_float_exception_flags(&env->fp_status); \ + int flags = get_float_exception_flags(&env->fpu->fp_status); \ flags &= ~float_flag_invalid; \ - set_float_exception_flags(flags, &env->fp_status); \ + set_float_exception_flags(flags, &env->fpu->fp_status); \ } while(0) #else #define clear_invalid() do { } while(0) @@ -2190,63 +2885,63 @@ CMP_OPS(ngt) void op_bc1f (void) { - T0 = !!(~GET_FP_COND(env) & (0x1 << PARAM1)); + T0 = !!(~GET_FP_COND(env->fpu) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1any2f (void) { - T0 = !!(~GET_FP_COND(env) & (0x3 << PARAM1)); + T0 = !!(~GET_FP_COND(env->fpu) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1any4f (void) { - T0 = !!(~GET_FP_COND(env) & (0xf << PARAM1)); + T0 = !!(~GET_FP_COND(env->fpu) & (0xf << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1t (void) { - T0 = !!(GET_FP_COND(env) & (0x1 << PARAM1)); + T0 = !!(GET_FP_COND(env->fpu) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1any2t (void) { - T0 = !!(GET_FP_COND(env) & (0x3 << PARAM1)); + T0 = !!(GET_FP_COND(env->fpu) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1any4t (void) { - T0 = !!(GET_FP_COND(env) & (0xf << PARAM1)); + T0 = !!(GET_FP_COND(env->fpu) & (0xf << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_tlbwi (void) { - CALL_FROM_TB0(env->do_tlbwi); + CALL_FROM_TB0(env->tlb->do_tlbwi); RETURN(); } void op_tlbwr (void) { - CALL_FROM_TB0(env->do_tlbwr); + CALL_FROM_TB0(env->tlb->do_tlbwr); RETURN(); } void op_tlbp (void) { - CALL_FROM_TB0(env->do_tlbp); + CALL_FROM_TB0(env->tlb->do_tlbp); RETURN(); } void op_tlbr (void) { - CALL_FROM_TB0(env->do_tlbr); + CALL_FROM_TB0(env->tlb->do_tlbr); RETURN(); } @@ -2307,10 +3002,10 @@ void op_eret (void) if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_pre_eret); if (env->CP0_Status & (1 << CP0St_ERL)) { - env->PC = env->CP0_ErrorEPC; + env->PC[env->current_tc] = env->CP0_ErrorEPC; env->CP0_Status &= ~(1 << CP0St_ERL); } else { - env->PC = env->CP0_EPC; + env->PC[env->current_tc] = env->CP0_EPC; env->CP0_Status &= ~(1 << CP0St_EXL); } if (!(env->CP0_Status & (1 << CP0St_EXL)) && @@ -2335,7 +3030,7 @@ void op_deret (void) { if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_pre_eret); - env->PC = env->CP0_DEPC; + env->PC[env->current_tc] = env->CP0_DEPC; env->hflags |= MIPS_HFLAG_DM; if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && @@ -2407,14 +3102,14 @@ void op_save_state (void) void op_save_pc (void) { - env->PC = PARAM1; + env->PC[env->current_tc] = PARAM1; RETURN(); } #ifdef TARGET_MIPS64 void op_save_pc64 (void) { - env->PC = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; + env->PC[env->current_tc] = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; RETURN(); } #endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 477b80d516..c87317a44f 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -160,13 +160,13 @@ void do_drotrv (void) #if TARGET_LONG_BITS > HOST_LONG_BITS static inline uint64_t get_HILO (void) { - return (env->HI << 32) | (uint32_t)env->LO; + return (env->HI[0][env->current_tc] << 32) | (uint32_t)env->LO[0][env->current_tc]; } static inline void set_HILO (uint64_t HILO) { - env->LO = (int32_t)HILO; - env->HI = (int32_t)(HILO >> 32); + env->LO[0][env->current_tc] = (int32_t)HILO; + env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); } void do_mult (void) @@ -217,8 +217,8 @@ void do_div (void) { /* 64bit datatypes because we may see overflow/underflow. */ if (T1 != 0) { - env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); - env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); + env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); + env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); } } #endif @@ -228,8 +228,8 @@ void do_ddiv (void) { if (T1 != 0) { lldiv_t res = lldiv((int64_t)T0, (int64_t)T1); - env->LO = res.quot; - env->HI = res.rem; + env->LO[0][env->current_tc] = res.quot; + env->HI[0][env->current_tc] = res.rem; } } @@ -237,8 +237,8 @@ void do_ddiv (void) void do_ddivu (void) { if (T1 != 0) { - env->LO = T0 / T1; - env->HI = T0 % T1; + env->LO[0][env->current_tc] = T0 / T1; + env->HI[0][env->current_tc] = T0 % T1; } } #endif @@ -316,10 +316,10 @@ void do_mtc0_status_irqraise_debug(void) void fpu_handle_exception(void) { #ifdef CONFIG_SOFTFLOAT - int flags = get_float_exception_flags(&env->fp_status); + int flags = get_float_exception_flags(&env->fpu->fp_status); unsigned int cpuflags = 0, enable, cause = 0; - enable = GET_FP_ENABLE(env->fcr31); + enable = GET_FP_ENABLE(env->fpu->fcr31); /* determine current flags */ if (flags & float_flag_invalid) { @@ -342,11 +342,11 @@ void fpu_handle_exception(void) cpuflags |= FP_INEXACT; cause |= FP_INEXACT & enable; } - SET_FP_FLAGS(env->fcr31, cpuflags); - SET_FP_CAUSE(env->fcr31, cause); + SET_FP_FLAGS(env->fpu->fcr31, cpuflags); + SET_FP_CAUSE(env->fpu->fcr31, cause); #else - SET_FP_FLAGS(env->fcr31, 0); - SET_FP_CAUSE(env->fcr31, 0); + SET_FP_FLAGS(env->fpu->fcr31, 0); + SET_FP_CAUSE(env->fpu->fcr31, 0); #endif } @@ -355,14 +355,14 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) { /* Flush qemu's TLB and discard all shadowed entries. */ tlb_flush (env, flush_global); - env->tlb_in_use = env->nb_tlb; + env->tlb->tlb_in_use = env->tlb->nb_tlb; } static void r4k_mips_tlb_flush_extra (CPUState *env, int first) { /* Discard entries from env->tlb[first] onwards. */ - while (env->tlb_in_use > first) { - r4k_invalidate_tlb(env, --env->tlb_in_use, 0); + while (env->tlb->tlb_in_use > first) { + r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0); } } @@ -371,7 +371,7 @@ static void r4k_fill_tlb (int idx) r4k_tlb_t *tlb; /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ - tlb = &env->mmu.r4k.tlb[idx]; + tlb = &env->tlb->mmu.r4k.tlb[idx]; tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); #ifdef TARGET_MIPS64 tlb->VPN &= env->SEGMask; @@ -394,10 +394,10 @@ void r4k_do_tlbwi (void) /* Discard cached TLB entries. We could avoid doing this if the tlbwi is just upgrading access permissions on the current entry; that might be a further win. */ - r4k_mips_tlb_flush_extra (env, env->nb_tlb); + r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb); - r4k_invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0); - r4k_fill_tlb(env->CP0_Index % env->nb_tlb); + r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb, 0); + r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb); } void r4k_do_tlbwr (void) @@ -418,8 +418,8 @@ void r4k_do_tlbp (void) int i; ASID = env->CP0_EntryHi & 0xFF; - for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->mmu.r4k.tlb[i]; + for (i = 0; i < env->tlb->nb_tlb; i++) { + tlb = &env->tlb->mmu.r4k.tlb[i]; /* 1k pages are not supported. */ mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); tag = env->CP0_EntryHi & ~mask; @@ -431,10 +431,10 @@ void r4k_do_tlbp (void) break; } } - if (i == env->nb_tlb) { + if (i == env->tlb->nb_tlb) { /* No match. Discard any shadow entries, if any of them match. */ - for (i = env->nb_tlb; i < env->tlb_in_use; i++) { - tlb = &env->mmu.r4k.tlb[i]; + for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) { + tlb = &env->tlb->mmu.r4k.tlb[i]; /* 1k pages are not supported. */ mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); tag = env->CP0_EntryHi & ~mask; @@ -456,13 +456,13 @@ void r4k_do_tlbr (void) uint8_t ASID; ASID = env->CP0_EntryHi & 0xFF; - tlb = &env->mmu.r4k.tlb[env->CP0_Index % env->nb_tlb]; + tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb]; /* If this will change the current ASID, flush qemu's TLB. */ if (ASID != tlb->ASID) cpu_mips_tlb_flush (env, 1); - r4k_mips_tlb_flush_extra(env, env->nb_tlb); + r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb); env->CP0_EntryHi = tlb->VPN | tlb->ASID; env->CP0_PageMask = tlb->PageMask; @@ -491,7 +491,7 @@ void dump_sc (void) void debug_pre_eret (void) { fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, - env->PC, env->CP0_EPC); + env->PC[env->current_tc], env->CP0_EPC); if (env->CP0_Status & (1 << CP0St_ERL)) fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); if (env->hflags & MIPS_HFLAG_DM) @@ -502,7 +502,7 @@ void debug_pre_eret (void) void debug_post_eret (void) { fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, - env->PC, env->CP0_EPC); + env->PC[env->current_tc], env->CP0_EPC); if (env->CP0_Status & (1 << CP0St_ERL)) fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); if (env->hflags & MIPS_HFLAG_DM) @@ -518,21 +518,21 @@ void do_pmon (int function) function /= 2; switch (function) { case 2: /* TODO: char inbyte(int waitflag); */ - if (env->gpr[4] == 0) - env->gpr[2] = -1; + if (env->gpr[4][env->current_tc] == 0) + env->gpr[2][env->current_tc] = -1; /* Fall through */ case 11: /* TODO: char inbyte (void); */ - env->gpr[2] = -1; + env->gpr[2][env->current_tc] = -1; break; case 3: case 12: - printf("%c", (char)(env->gpr[4] & 0xFF)); + printf("%c", (char)(env->gpr[4][env->current_tc] & 0xFF)); break; case 17: break; case 158: { - unsigned char *fmt = (void *)(unsigned long)env->gpr[4]; + unsigned char *fmt = (void *)(unsigned long)env->gpr[4][env->current_tc]; printf("%s", fmt); } break; @@ -613,40 +613,61 @@ unsigned int ieee_rm[] = { }; #define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) + set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status) -void do_ctc1 (void) +void do_cfc1 (int reg) { - switch(T1) { + switch (reg) { + case 0: + T0 = (int32_t)env->fpu->fcr0; + break; + case 25: + T0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1); + break; + case 26: + T0 = env->fpu->fcr31 & 0x0003f07c; + break; + case 28: + T0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4); + break; + default: + T0 = (int32_t)env->fpu->fcr31; + break; + } +} + +void do_ctc1 (int reg) +{ + switch(reg) { case 25: if (T0 & 0xffffff00) return; - env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | + env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | ((T0 & 0x1) << 23); break; case 26: if (T0 & 0x007c0000) return; - env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); + env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); break; case 28: if (T0 & 0x007c0000) return; - env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | + env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | ((T0 & 0x4) << 22); break; case 31: if (T0 & 0x007c0000) return; - env->fcr31 = T0; + env->fpu->fcr31 = T0; break; default: return; } /* set rounding mode */ RESTORE_ROUNDING_MODE; - set_float_exception_flags(0, &env->fp_status); - if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31)) + set_float_exception_flags(0, &env->fpu->fp_status); + if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->fcr31)) do_raise_exception(EXCP_FPE); } @@ -670,325 +691,325 @@ inline char mips_ex_to_ieee(char xcpt) inline void update_fcr31(void) { - int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status)); + int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status)); - SET_FP_CAUSE(env->fcr31, tmp); - if (GET_FP_ENABLE(env->fcr31) & tmp) + SET_FP_CAUSE(env->fpu->fcr31, tmp); + if (GET_FP_ENABLE(env->fpu->fcr31) & tmp) do_raise_exception(EXCP_FPE); else - UPDATE_FP_FLAGS(env->fcr31, tmp); + UPDATE_FP_FLAGS(env->fpu->fcr31, tmp); } #define FLOAT_OP(name, p) void do_float_##name##_##p(void) FLOAT_OP(cvtd, s) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float32_to_float64(FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float32_to_float64(FST0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvtd, w) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = int32_to_float64(WT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = int32_to_float64(WT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvtd, l) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = int64_to_float64(DT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = int64_to_float64(DT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvtl, d) { - set_float_exception_flags(0, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(cvtl, s) { - set_float_exception_flags(0, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + DT2 = float32_to_int64(FST0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(cvtps, pw) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int32_to_float32(WT0, &env->fp_status); - FSTH2 = int32_to_float32(WTH0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = int32_to_float32(WT0, &env->fpu->fp_status); + FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvtpw, ps) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); - WTH2 = float32_to_int32(FSTH0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); + WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(cvts, d) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float64_to_float32(FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float64_to_float32(FDT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvts, w) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int32_to_float32(WT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = int32_to_float32(WT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvts, l) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int64_to_float32(DT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = int64_to_float32(DT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvts, pl) { - set_float_exception_flags(0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); WT2 = WT0; update_fcr31(); } FLOAT_OP(cvts, pu) { - set_float_exception_flags(0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); WT2 = WTH0; update_fcr31(); } FLOAT_OP(cvtw, s) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(cvtw, d) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(roundl, d) { - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); + DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(roundl, s) { - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); + set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); + DT2 = float32_to_int64(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(roundw, d) { - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); + WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(roundw, s) { - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); + set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(truncl, d) { - DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status); + DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(truncl, s) { - DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status); + DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(truncw, d) { - WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); + WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(truncw, s) { - WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status); + WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(ceill, d) { - set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_up, &env->fpu->fp_status); + DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(ceill, s) { - set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); + set_float_rounding_mode(float_round_up, &env->fpu->fp_status); + DT2 = float32_to_int64(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(ceilw, d) { - set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_up, &env->fpu->fp_status); + WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(ceilw, s) { - set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); + set_float_rounding_mode(float_round_up, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(floorl, d) { - set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_down, &env->fpu->fp_status); + DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(floorl, s) { - set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); + set_float_rounding_mode(float_round_down, &env->fpu->fp_status); + DT2 = float32_to_int64(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(floorw, d) { - set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_down, &env->fpu->fp_status); + WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(floorw, s) { - set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); + set_float_rounding_mode(float_round_down, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } /* MIPS specific unary operations */ FLOAT_OP(recip, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(recip, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_sqrt(FDT0, &env->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_sqrt(FST0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_sqrt(FST0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(recip1, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(recip1, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(recip1, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status); - FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status); + FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt1, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_sqrt(FDT0, &env->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt1, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_sqrt(FST0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_sqrt(FST0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt1, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_sqrt(FST0, &env->fp_status); - FSTH2 = float32_sqrt(FSTH0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status); - FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_sqrt(FST0, &env->fpu->fp_status); + FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status); + FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status); update_fcr31(); } @@ -996,41 +1017,41 @@ FLOAT_OP(rsqrt1, ps) #define FLOAT_BINOP(name) \ FLOAT_OP(name, d) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ - update_fcr31(); \ - if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) \ - FDT2 = 0x7ff7ffffffffffffULL; \ - else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ - if ((env->fcr31 & 0x3) == 0) \ - FDT2 &= FLOAT_SIGN64; \ + set_float_exception_flags(0, &env->fpu->fp_status); \ + FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status); \ + update_fcr31(); \ + if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ + FDT2 = 0x7ff7ffffffffffffULL; \ + else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) { \ + if ((env->fpu->fcr31 & 0x3) == 0) \ + FDT2 &= FLOAT_SIGN64; \ } \ } \ FLOAT_OP(name, s) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ - update_fcr31(); \ - if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) \ - FST2 = 0x7fbfffff; \ - else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ - if ((env->fcr31 & 0x3) == 0) \ - FST2 &= FLOAT_SIGN32; \ + set_float_exception_flags(0, &env->fpu->fp_status); \ + FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \ + update_fcr31(); \ + if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ + FST2 = 0x7fbfffff; \ + else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) { \ + if ((env->fpu->fcr31 & 0x3) == 0) \ + FST2 &= FLOAT_SIGN32; \ } \ } \ FLOAT_OP(name, ps) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ - FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ + set_float_exception_flags(0, &env->fpu->fp_status); \ + FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \ + FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \ update_fcr31(); \ - if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) { \ - FST2 = 0x7fbfffff; \ - FSTH2 = 0x7fbfffff; \ - } else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ - if ((env->fcr31 & 0x3) == 0) { \ - FST2 &= FLOAT_SIGN32; \ - FSTH2 &= FLOAT_SIGN32; \ + if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) { \ + FST2 = 0x7fbfffff; \ + FSTH2 = 0x7fbfffff; \ + } else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) { \ + if ((env->fpu->fcr31 & 0x3) == 0) { \ + FST2 &= FLOAT_SIGN32; \ + FSTH2 &= FLOAT_SIGN32; \ } \ } \ } @@ -1043,69 +1064,69 @@ FLOAT_BINOP(div) /* MIPS specific binary operations */ FLOAT_OP(recip2, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_mul(FDT0, FDT2, &env->fp_status); - FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status) ^ FLOAT_SIGN64; + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status); + FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status) ^ FLOAT_SIGN64; update_fcr31(); } FLOAT_OP(recip2, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32; + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32; update_fcr31(); } FLOAT_OP(recip2, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fp_status); - FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32; - FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32; + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); + FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32; + FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32; update_fcr31(); } FLOAT_OP(rsqrt2, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_mul(FDT0, FDT2, &env->fp_status); - FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status); - FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fp_status) ^ FLOAT_SIGN64; + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status); + FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status); + FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status) ^ FLOAT_SIGN64; update_fcr31(); } FLOAT_OP(rsqrt2, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status); - FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32; + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status); + FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32; update_fcr31(); } FLOAT_OP(rsqrt2, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fp_status); - FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status); - FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status); - FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32; - FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32; + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); + FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status); + FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status); + FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32; + FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32; update_fcr31(); } FLOAT_OP(addr, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_add (FST0, FSTH0, &env->fp_status); - FSTH2 = float32_add (FST1, FSTH1, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status); + FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(mulr, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul (FST0, FSTH0, &env->fp_status); - FSTH2 = float32_mul (FST1, FSTH1, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status); + FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status); update_fcr31(); } @@ -1116,9 +1137,9 @@ void do_cmp_d_ ## op (long cc) \ int c = cond; \ update_fcr31(); \ if (c) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ } \ void do_cmpabs_d_ ## op (long cc) \ { \ @@ -1128,9 +1149,9 @@ void do_cmpabs_d_ ## op (long cc) \ c = cond; \ update_fcr31(); \ if (c) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ } int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) @@ -1149,24 +1170,24 @@ int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0)) -FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)) -FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status), 0)) +FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)) +FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0)) -FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status)) -FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status), 0)) +FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)) +FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status)) #define FOP_COND_S(op, cond) \ void do_cmp_s_ ## op (long cc) \ @@ -1174,9 +1195,9 @@ void do_cmp_s_ ## op (long cc) \ int c = cond; \ update_fcr31(); \ if (c) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ } \ void do_cmpabs_s_ ## op (long cc) \ { \ @@ -1186,9 +1207,9 @@ void do_cmpabs_s_ ## op (long cc) \ c = cond; \ update_fcr31(); \ if (c) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ } flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) @@ -1207,24 +1228,24 @@ flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0)) -FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fp_status)) -FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) -FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0)) +FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)) +FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0)) -FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status)) -FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) -FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0)) +FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)) +FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status)) #define FOP_COND_PS(op, condl, condh) \ void do_cmp_ps_ ## op (long cc) \ @@ -1233,13 +1254,13 @@ void do_cmp_ps_ ## op (long cc) \ int ch = condh; \ update_fcr31(); \ if (cl) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ if (ch) \ - SET_FP_COND(cc + 1, env); \ + SET_FP_COND(cc + 1, env->fpu); \ else \ - CLEAR_FP_COND(cc + 1, env); \ + CLEAR_FP_COND(cc + 1, env->fpu); \ } \ void do_cmpabs_ps_ ## op (long cc) \ { \ @@ -1252,48 +1273,48 @@ void do_cmpabs_ps_ ## op (long cc) \ ch = condh; \ update_fcr31(); \ if (cl) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ if (ch) \ - SET_FP_COND(cc + 1, env); \ + SET_FP_COND(cc + 1, env->fpu); \ else \ - CLEAR_FP_COND(cc + 1, env); \ + CLEAR_FP_COND(cc + 1, env->fpu); \ } /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0), - (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0)) -FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)) -FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0), + (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0)) +FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)) +FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0), - (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0)) -FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)) -FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0), + (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0)) +FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)) +FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 8236acc18e..41d954c1db 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -21,31 +21,44 @@ #if defined(REG) void glue(op_load_gpr_T0_gpr, REG) (void) { - T0 = env->gpr[REG]; + T0 = env->gpr[REG][env->current_tc]; RETURN(); } void glue(op_store_T0_gpr_gpr, REG) (void) { - env->gpr[REG] = T0; + env->gpr[REG][env->current_tc] = T0; RETURN(); } void glue(op_load_gpr_T1_gpr, REG) (void) { - T1 = env->gpr[REG]; + T1 = env->gpr[REG][env->current_tc]; RETURN(); } void glue(op_store_T1_gpr_gpr, REG) (void) { - env->gpr[REG] = T1; + env->gpr[REG][env->current_tc] = T1; RETURN(); } void glue(op_load_gpr_T2_gpr, REG) (void) { - T2 = env->gpr[REG]; + T2 = env->gpr[REG][env->current_tc]; + RETURN(); +} + + +void glue(op_load_srsgpr_T0_gpr, REG) (void) +{ + T0 = env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf]; + RETURN(); +} + +void glue(op_store_T0_srsgpr_gpr, REG) (void) +{ + env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf] = T0; RETURN(); } #endif diff --git a/target-mips/translate.c b/target-mips/translate.c index 07dca14595..c87f2c9874 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -266,6 +266,8 @@ enum { OPC_DINSM = 0x05 | OPC_SPECIAL3, OPC_DINSU = 0x06 | OPC_SPECIAL3, OPC_DINS = 0x07 | OPC_SPECIAL3, + OPC_FORK = 0x08 | OPC_SPECIAL3, + OPC_YIELD = 0x09 | OPC_SPECIAL3, OPC_BSHFL = 0x20 | OPC_SPECIAL3, OPC_DBSHFL = 0x24 | OPC_SPECIAL3, OPC_RDHWR = 0x3B | OPC_SPECIAL3, @@ -296,8 +298,10 @@ enum { OPC_DMFC0 = (0x01 << 21) | OPC_CP0, OPC_MTC0 = (0x04 << 21) | OPC_CP0, OPC_DMTC0 = (0x05 << 21) | OPC_CP0, + OPC_MFTR = (0x08 << 21) | OPC_CP0, OPC_RDPGPR = (0x0A << 21) | OPC_CP0, OPC_MFMC0 = (0x0B << 21) | OPC_CP0, + OPC_MTTR = (0x0C << 21) | OPC_CP0, OPC_WRPGPR = (0x0E << 21) | OPC_CP0, OPC_C0 = (0x10 << 21) | OPC_CP0, OPC_C0_FIRST = (0x10 << 21) | OPC_CP0, @@ -308,6 +312,10 @@ enum { #define MASK_MFMC0(op) MASK_CP0(op) | (op & 0xFFFF) enum { + OPC_DMT = 0x01 | (0 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0, + OPC_EMT = 0x01 | (1 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0, + OPC_DVPE = 0x01 | (0 << 5) | OPC_MFMC0, + OPC_EVPE = 0x01 | (1 << 5) | OPC_MFMC0, OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0, OPC_EI = (1 << 5) | (0x0C << 11) | OPC_MFMC0, }; @@ -441,6 +449,10 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); +/* Moves to/from shadow registers */ +GEN32(gen_op_load_srsgpr_T0, gen_op_load_srsgpr_T0_gpr); +GEN32(gen_op_store_T0_srsgpr, gen_op_store_T0_srsgpr_gpr); + static const char *fregnames[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", @@ -569,6 +581,15 @@ do { \ } \ } while (0) +#define GEN_LOAD_SRSREG_TN(Tn, Rn) \ +do { \ + if (Rn == 0) { \ + glue(gen_op_reset_, Tn)(); \ + } else { \ + glue(gen_op_load_srsgpr_, Tn)(Rn); \ + } \ +} while (0) + #ifdef TARGET_MIPS64 #define GEN_LOAD_IMM_TN(Tn, Imm) \ do { \ @@ -598,6 +619,13 @@ do { \ } \ } while (0) +#define GEN_STORE_TN_SRSREG(Rn, Tn) \ +do { \ + if (Rn != 0) { \ + glue(glue(gen_op_store_, Tn),_srsgpr)(Rn); \ + } \ +} while (0) + #define GEN_LOAD_FREG_FTN(FTn, Fn) \ do { \ glue(gen_op_load_fpr_, FTn)(Fn); \ @@ -740,6 +768,14 @@ static inline void check_mips_r2(CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_RI); } +/* This code generates a "reserved instruction" exception if the + CPU is not MIPS MT capable. */ +static inline void check_mips_mt(CPUState *env, DisasContext *ctx) +{ + if (!(env->CP0_Config3 & (1 << CP0C3_MT))) + generate_exception(ctx, EXCP_RI); +} + #if defined(CONFIG_USER_ONLY) #define op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -806,8 +842,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual - * memory access - */ + memory access. */ switch (opc) { #ifdef TARGET_MIPS64 case OPC_LWU: @@ -958,8 +993,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual - * memory access - */ + memory access. */ switch (opc) { case OPC_LWC1: op_ldst(lwc1); @@ -997,9 +1031,8 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, const char *opn = "imm arith"; if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) { - /* if no destination, treat it as a NOP - * For addi, we must generate the overflow exception when needed. - */ + /* If no destination, treat it as a NOP. + For addi, we must generate the overflow exception when needed. */ MIPS_DEBUG("NOP"); return; } @@ -1175,9 +1208,8 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB && opc != OPC_DADD && opc != OPC_DSUB) { - /* if no destination, treat it as a NOP - * For add & sub, we must generate the overflow exception when needed. - */ + /* If no destination, treat it as a NOP. + For add & sub, we must generate the overflow exception when needed. */ MIPS_DEBUG("NOP"); return; } @@ -1324,29 +1356,29 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) const char *opn = "hilo"; if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { - /* Treat as a NOP */ + /* Treat as NOP. */ MIPS_DEBUG("NOP"); return; } switch (opc) { case OPC_MFHI: - gen_op_load_HI(); + gen_op_load_HI(0); GEN_STORE_TN_REG(reg, T0); opn = "mfhi"; break; case OPC_MFLO: - gen_op_load_LO(); + gen_op_load_LO(0); GEN_STORE_TN_REG(reg, T0); opn = "mflo"; break; case OPC_MTHI: GEN_LOAD_REG_TN(T0, reg); - gen_op_store_HI(); + gen_op_store_HI(0); opn = "mthi"; break; case OPC_MTLO: GEN_LOAD_REG_TN(T0, reg); - gen_op_store_LO(); + gen_op_store_LO(0); opn = "mtlo"; break; default: @@ -1428,7 +1460,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, { const char *opn = "CLx"; if (rd == 0) { - /* Treat as a NOP */ + /* Treat as NOP. */ MIPS_DEBUG("NOP"); return; } @@ -1514,7 +1546,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, case OPC_TLTIU: /* r0 < 0 unsigned */ case OPC_TNE: /* rs != rs */ case OPC_TNEI: /* r0 != 0 */ - /* Never trap: treat as NOP */ + /* Never trap: treat as NOP. */ return; default: MIPS_INVAL("trap"); @@ -1674,7 +1706,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_BNE: /* rx != rx */ case OPC_BGTZ: /* 0 > 0 */ case OPC_BLTZ: /* 0 < 0 */ - /* Treated as NOP */ + /* Treat as NOP. */ MIPS_DEBUG("bnever (NOP)"); return; case OPC_BLTZAL: /* 0 < 0 */ @@ -1886,17 +1918,20 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mfc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_mfc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf0(); rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_mfc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf1(); rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -1908,33 +1943,40 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_mfc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_mfc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_mfc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_mfc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_mfc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_mfc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_mfc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -1946,33 +1988,40 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_mfc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_mfc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_mfc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_mfc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_mfc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_mfc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_mfc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -2023,25 +2072,25 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_mfc0_srsconf0(); /* shadow registers */ + gen_op_mfc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_mfc0_srsconf1(); /* shadow registers */ + gen_op_mfc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_mfc0_srsconf2(); /* shadow registers */ + gen_op_mfc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_mfc0_srsconf3(); /* shadow registers */ + gen_op_mfc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_mfc0_srsconf4(); /* shadow registers */ + gen_op_mfc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -2430,17 +2479,20 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mtc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_mtc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_mtc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -2452,33 +2504,40 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_mtc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_mtc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_mtc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_mtc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_mtc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_mtc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_mtc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -2490,33 +2549,40 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_mtc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_mtc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_mtc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_mtc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_mtc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_mtc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_mtc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -2567,25 +2633,25 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_mtc0_srsconf0(); /* shadow registers */ + gen_op_mtc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_mtc0_srsconf1(); /* shadow registers */ + gen_op_mtc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_mtc0_srsconf2(); /* shadow registers */ + gen_op_mtc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_mtc0_srsconf3(); /* shadow registers */ + gen_op_mtc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_mtc0_srsconf4(); /* shadow registers */ + gen_op_mtc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -3006,17 +3072,20 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_dmfc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_dmfc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf0(); rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_dmfc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf1(); rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -3028,33 +3097,40 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_dmfc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_dmfc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_dmfc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_dmfc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_dmfc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_dmfc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_dmfc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -3066,33 +3142,40 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_dmfc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_dmfc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_dmfc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_dmfc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_dmfc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_dmfc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_dmfc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -3143,25 +3226,25 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_dmfc0_srsconf0(); /* shadow registers */ + gen_op_mfc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_dmfc0_srsconf1(); /* shadow registers */ + gen_op_mfc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_dmfc0_srsconf2(); /* shadow registers */ + gen_op_mfc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_dmfc0_srsconf3(); /* shadow registers */ + gen_op_mfc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_dmfc0_srsconf4(); /* shadow registers */ + gen_op_mfc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -3237,7 +3320,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) break; case 3: check_mips_r2(env, ctx); - gen_op_mfc0_srsmap(); /* shadow registers */ + gen_op_mfc0_srsmap(); rn = "SRSMap"; break; default: @@ -3537,17 +3620,20 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mtc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_mtc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_mtc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -3559,33 +3645,40 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_mtc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_mtc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_mtc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_mtc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_mtc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_mtc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_mtc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -3597,33 +3690,40 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_mtc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_mtc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_mtc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_mtc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_mtc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_mtc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_mtc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -3674,25 +3774,25 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_mtc0_srsconf0(); /* shadow registers */ + gen_op_mtc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_mtc0_srsconf1(); /* shadow registers */ + gen_op_mtc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_mtc0_srsconf2(); /* shadow registers */ + gen_op_mtc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_mtc0_srsconf3(); /* shadow registers */ + gen_op_mtc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_mtc0_srsconf4(); /* shadow registers */ + gen_op_mtc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -4086,6 +4186,334 @@ die: } #endif /* TARGET_MIPS64 */ +static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, + int u, int sel, int h) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && + ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != + (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) + gen_op_set_T0(-1); + else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > + (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) + gen_op_set_T0(-1); + else if (u == 0) { + switch (rt) { + case 2: + switch (sel) { + case 1: + gen_op_mftc0_tcstatus(); + break; + case 2: + gen_op_mftc0_tcbind(); + break; + case 3: + gen_op_mftc0_tcrestart(); + break; + case 4: + gen_op_mftc0_tchalt(); + break; + case 5: + gen_op_mftc0_tccontext(); + break; + case 6: + gen_op_mftc0_tcschedule(); + break; + case 7: + gen_op_mftc0_tcschefback(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + break; + case 10: + switch (sel) { + case 0: + gen_op_mftc0_entryhi(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + case 12: + switch (sel) { + case 0: + gen_op_mftc0_status(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + case 23: + switch (sel) { + case 0: + gen_op_mftc0_debug(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + break; + default: + gen_mfc0(env, ctx, rt, sel); + } + } else switch (sel) { + /* GPR registers. */ + case 0: + gen_op_mftgpr(rt); + break; + /* Auxiliary CPU registers */ + case 1: + switch (rt) { + case 0: + gen_op_mftlo(0); + break; + case 1: + gen_op_mfthi(0); + break; + case 2: + gen_op_mftacx(0); + break; + case 4: + gen_op_mftlo(1); + break; + case 5: + gen_op_mfthi(1); + break; + case 6: + gen_op_mftacx(1); + break; + case 8: + gen_op_mftlo(2); + break; + case 9: + gen_op_mfthi(2); + break; + case 10: + gen_op_mftacx(2); + break; + case 12: + gen_op_mftlo(3); + break; + case 13: + gen_op_mfthi(3); + break; + case 14: + gen_op_mftacx(3); + break; + case 16: + gen_op_mftdsp(); + break; + default: + goto die; + } + break; + /* Floating point (COP1). */ + case 2: + /* XXX: For now we support only a single FPU context. */ + if (h == 0) { + GEN_LOAD_FREG_FTN(WT0, rt); + gen_op_mfc1(); + } else { + GEN_LOAD_FREG_FTN(WTH0, rt); + gen_op_mfhc1(); + } + break; + case 3: + /* XXX: For now we support only a single FPU context. */ + gen_op_cfc1(rt); + break; + /* COP2: Not implemented. */ + case 4: + case 5: + /* fall through */ + default: + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n", + rt, u, sel, h); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n", + rt, u, sel, h); + } +#endif + generate_exception(ctx, EXCP_RI); +} + +static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, + int u, int sel, int h) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && + ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != + (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) + /* NOP */ ; + else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > + (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) + /* NOP */ ; + else if (u == 0) { + switch (rd) { + case 2: + switch (sel) { + case 1: + gen_op_mttc0_tcstatus(); + break; + case 2: + gen_op_mttc0_tcbind(); + break; + case 3: + gen_op_mttc0_tcrestart(); + break; + case 4: + gen_op_mttc0_tchalt(); + break; + case 5: + gen_op_mttc0_tccontext(); + break; + case 6: + gen_op_mttc0_tcschedule(); + break; + case 7: + gen_op_mttc0_tcschefback(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + break; + case 10: + switch (sel) { + case 0: + gen_op_mttc0_entryhi(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + case 12: + switch (sel) { + case 0: + gen_op_mttc0_status(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + case 23: + switch (sel) { + case 0: + gen_op_mttc0_debug(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + break; + default: + gen_mtc0(env, ctx, rd, sel); + } + } else switch (sel) { + /* GPR registers. */ + case 0: + gen_op_mttgpr(rd); + break; + /* Auxiliary CPU registers */ + case 1: + switch (rd) { + case 0: + gen_op_mttlo(0); + break; + case 1: + gen_op_mtthi(0); + break; + case 2: + gen_op_mttacx(0); + break; + case 4: + gen_op_mttlo(1); + break; + case 5: + gen_op_mtthi(1); + break; + case 6: + gen_op_mttacx(1); + break; + case 8: + gen_op_mttlo(2); + break; + case 9: + gen_op_mtthi(2); + break; + case 10: + gen_op_mttacx(2); + break; + case 12: + gen_op_mttlo(3); + break; + case 13: + gen_op_mtthi(3); + break; + case 14: + gen_op_mttacx(3); + break; + case 16: + gen_op_mttdsp(); + break; + default: + goto die; + } + break; + /* Floating point (COP1). */ + case 2: + /* XXX: For now we support only a single FPU context. */ + if (h == 0) { + gen_op_mtc1(); + GEN_STORE_FTN_FREG(rd, WT0); + } else { + gen_op_mthc1(); + GEN_STORE_FTN_FREG(rd, WTH0); + } + break; + case 3: + /* XXX: For now we support only a single FPU context. */ + gen_op_ctc1(rd); + break; + /* COP2: Not implemented. */ + case 4: + case 5: + /* fall through */ + default: + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n", + rd, u, sel, h); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n", + rd, u, sel, h); + } +#endif + generate_exception(ctx, EXCP_RI); +} + static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rd) { const char *opn = "ldst"; @@ -4093,7 +4521,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int switch (opc) { case OPC_MFC0: if (rt == 0) { - /* Treat as NOP */ + /* Treat as NOP. */ return; } gen_mfc0(env, ctx, rd, ctx->opcode & 0x7); @@ -4110,7 +4538,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int if (!(ctx->hflags & MIPS_HFLAG_64)) generate_exception(ctx, EXCP_RI); if (rt == 0) { - /* Treat as NOP */ + /* Treat as NOP. */ return; } gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7); @@ -4121,31 +4549,49 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int if (!(ctx->hflags & MIPS_HFLAG_64)) generate_exception(ctx, EXCP_RI); GEN_LOAD_REG_TN(T0, rt); - gen_dmtc0(env,ctx, rd, ctx->opcode & 0x7); + gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; break; #endif + case OPC_MFTR: + check_mips_mt(env, ctx); + if (rd == 0) { + /* Treat as NOP. */ + return; + } + gen_mftr(env, ctx, rt, (ctx->opcode >> 5) & 1, + ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); + gen_op_store_T0_gpr(rd); + opn = "mftr"; + break; + case OPC_MTTR: + check_mips_mt(env, ctx); + GEN_LOAD_REG_TN(T0, rt); + gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1, + ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); + opn = "mttr"; + break; case OPC_TLBWI: opn = "tlbwi"; - if (!env->do_tlbwi) + if (!env->tlb->do_tlbwi) goto die; gen_op_tlbwi(); break; case OPC_TLBWR: opn = "tlbwr"; - if (!env->do_tlbwr) + if (!env->tlb->do_tlbwr) goto die; gen_op_tlbwr(); break; case OPC_TLBP: opn = "tlbp"; - if (!env->do_tlbp) + if (!env->tlb->do_tlbp) goto die; gen_op_tlbp(); break; case OPC_TLBR: opn = "tlbr"; - if (!env->do_tlbr) + if (!env->tlb->do_tlbr) goto die; gen_op_tlbr(); break; @@ -4263,15 +4709,13 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) opn = "mtc1"; break; case OPC_CFC1: - GEN_LOAD_IMM_TN(T1, fs); - gen_op_cfc1(); + gen_op_cfc1(fs); GEN_STORE_TN_REG(rt, T0); opn = "cfc1"; break; case OPC_CTC1: - GEN_LOAD_IMM_TN(T1, fs); GEN_LOAD_REG_TN(T0, rt); - gen_op_ctc1(); + gen_op_ctc1(fs); opn = "ctc1"; break; case OPC_DMFC1: @@ -5171,8 +5615,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual - * memory access - */ + memory access. */ switch (opc) { case OPC_LWXC1: op_ldst(lwc1); @@ -5456,7 +5899,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) #endif break; case OPC_SYNC: - /* Treat as a noop. */ + /* Treat as NOP. */ break; case OPC_MOVCI: @@ -5521,7 +5964,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } else { generate_exception(ctx, EXCP_DBp); } - /* Treat as a noop */ + /* Treat as NOP. */ break; #ifdef TARGET_MIPS64 case OPC_DCLZ ... OPC_DCLO: @@ -5586,7 +6029,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case 29: #if defined (CONFIG_USER_ONLY) - gen_op_tls_value (); + gen_op_tls_value(); break; #endif default: /* Invalid */ @@ -5596,6 +6039,18 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } GEN_STORE_TN_REG(rt, T0); break; + case OPC_FORK: + check_mips_mt(env, ctx); + GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_TN(T1, rs); + gen_op_fork(); + break; + case OPC_YIELD: + check_mips_mt(env, ctx); + GEN_LOAD_REG_TN(T0, rs); + gen_op_yield(); + GEN_STORE_TN_REG(rd, T0); + break; #ifdef TARGET_MIPS64 case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: @@ -5642,7 +6097,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case OPC_SYNCI: check_mips_r2(env, ctx); - /* treat as noop */ + /* Treat as NOP. */ break; default: /* Invalid */ MIPS_INVAL("regimm"); @@ -5657,6 +6112,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) switch (op1) { case OPC_MFC0: case OPC_MTC0: + case OPC_MFTR: + case OPC_MTTR: #ifdef TARGET_MIPS64 case OPC_DMFC0: case OPC_DMTC0: @@ -5670,6 +6127,22 @@ static void decode_opc (CPUState *env, DisasContext *ctx) check_mips_r2(env, ctx); op2 = MASK_MFMC0(ctx->opcode); switch (op2) { + case OPC_DMT: + check_mips_mt(env, ctx); + gen_op_dmt(); + break; + case OPC_EMT: + check_mips_mt(env, ctx); + gen_op_emt(); + break; + case OPC_DVPE: + check_mips_mt(env, ctx); + gen_op_dvpe(); + break; + case OPC_EVPE: + check_mips_mt(env, ctx); + gen_op_evpe(); + break; case OPC_DI: gen_op_di(); /* Stop translation as we may have switched the execution mode */ @@ -5688,11 +6161,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) GEN_STORE_TN_REG(rt, T0); break; case OPC_RDPGPR: + check_mips_r2(env, ctx); + GEN_LOAD_SRSREG_TN(T0, rt); + GEN_STORE_TN_REG(rd, T0); + break; case OPC_WRPGPR: check_mips_r2(env, ctx); - /* Shadow registers not implemented. */ GEN_LOAD_REG_TN(T0, rt); - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_TN_SRSREG(rd, T0); break; default: MIPS_INVAL("cp0"); @@ -5719,10 +6195,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_ldst(ctx, op, rt, rs, imm); break; case OPC_CACHE: - /* Treat as a noop */ + /* Treat as NOP. */ break; case OPC_PREF: - /* Treat as a noop */ + /* Treat as NOP. */ break; /* Floating point (COP1). */ @@ -5807,7 +6283,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_flt3_ldst(ctx, op1, sa, rd, rs, rt); break; case OPC_PREFX: - /* treat as noop */ + /* Treat as NOP. */ break; case OPC_ALNV_PS: case OPC_MADD_S: @@ -6079,13 +6555,14 @@ void fpu_dump_state(CPUState *env, FILE *f, fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n", - env->fcr0, env->fcr31, is_fpu64, env->fp_status, get_float_exception_flags(&env->fp_status)); - fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); - fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); - fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); + env->fpu->fcr0, env->fpu->fcr31, is_fpu64, env->fpu->fp_status, + get_float_exception_flags(&env->fpu->fp_status)); + fpu_fprintf(f, "FT0: "); printfpr(&env->fpu->ft0); + fpu_fprintf(f, "FT1: "); printfpr(&env->fpu->ft1); + fpu_fprintf(f, "FT2: "); printfpr(&env->fpu->ft2); for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { fpu_fprintf(f, "%3s: ", fregnames[i]); - printfpr(&env->fpr[i]); + printfpr(&env->fpu->fpr[i]); } #undef printfpr @@ -6095,7 +6572,7 @@ void dump_fpu (CPUState *env) { if (loglevel) { fprintf(logfile, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); + env->PC[env->current_tc], env->HI[0][env->current_tc], env->LO[0][env->current_tc], env->hflags, env->btarget, env->bcond); fpu_dump_state(env, logfile, fprintf, 0); } } @@ -6112,18 +6589,18 @@ void cpu_mips_check_sign_extensions (CPUState *env, FILE *f, { int i; - if (!SIGN_EXT_P(env->PC)) - cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC); - if (!SIGN_EXT_P(env->HI)) - cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI); - if (!SIGN_EXT_P(env->LO)) - cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO); + if (!SIGN_EXT_P(env->PC[env->current_tc])) + cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC[env->current_tc]); + if (!SIGN_EXT_P(env->HI[env->current_tc])) + cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI[env->current_tc]); + if (!SIGN_EXT_P(env->LO[env->current_tc])) + cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO[env->current_tc]); if (!SIGN_EXT_P(env->btarget)) cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget); for (i = 0; i < 32; i++) { - if (!SIGN_EXT_P(env->gpr[i])) - cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i]); + if (!SIGN_EXT_P(env->gpr[i][env->current_tc])) + cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i][env->current_tc]); } if (!SIGN_EXT_P(env->CP0_EPC)) @@ -6140,11 +6617,11 @@ void cpu_dump_state (CPUState *env, FILE *f, int i; cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); + env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], 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 " TARGET_FMT_lx, regnames[i], env->gpr[i]); + cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i][env->current_tc]); if ((i & 3) == 3) cpu_fprintf(f, "\n"); } @@ -6183,12 +6660,12 @@ void cpu_reset (CPUMIPSState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump. */ - env->CP0_ErrorEPC = env->PC - 4; + env->CP0_ErrorEPC = env->PC[env->current_tc] - 4; } else { - env->CP0_ErrorEPC = env->PC; + env->CP0_ErrorEPC = env->PC[env->current_tc]; } env->hflags = 0; - env->PC = (int32_t)0xBFC00000; + env->PC[env->current_tc] = (int32_t)0xBFC00000; env->CP0_Wired = 0; /* SMP not implemented */ env->CP0_EBase = 0x80000000; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index d327312e55..a9e9312642 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -43,11 +43,11 @@ /* No config4, no DSP ASE, no large physaddr, no external interrupt controller, no vectored interupts, - no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */ + no 1kb pages, no SmartMIPS ASE, no trace logic */ #define MIPS_CONFIG3 \ ((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \ (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \ - (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL)) + (0 << CP0C3_SM) | (0 << CP0C3_TL)) /* Define a implementation number of 1. Define a major version 1, minor version 0. */ @@ -65,9 +65,21 @@ struct mips_def_t { int32_t CP0_Config7; int32_t SYNCI_Step; int32_t CCRes; - int32_t Status_rw_bitmask; + int32_t CP0_Status_rw_bitmask; + int32_t CP0_TCStatus_rw_bitmask; + int32_t CP0_SRSCtl; int32_t CP1_fcr0; int32_t SEGBITS; + int32_t CP0_SRSConf0_rw_bitmask; + int32_t CP0_SRSConf0; + int32_t CP0_SRSConf1_rw_bitmask; + int32_t CP0_SRSConf1; + int32_t CP0_SRSConf2_rw_bitmask; + int32_t CP0_SRSConf2; + int32_t CP0_SRSConf3_rw_bitmask; + int32_t CP0_SRSConf3; + int32_t CP0_SRSConf4_rw_bitmask; + int32_t CP0_SRSConf4; }; /*****************************************************************************/ @@ -85,7 +97,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3278FF17, + .CP0_Status_rw_bitmask = 0x1278FF17, }, { .name = "4KEcR1", @@ -98,7 +110,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3278FF17, + .CP0_Status_rw_bitmask = 0x1278FF17, }, { .name = "4KEc", @@ -108,10 +120,10 @@ static mips_def_t mips_defs[] = (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3, + .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt), .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3278FF17, + .CP0_Status_rw_bitmask = 0x1278FF17, }, { .name = "24Kc", @@ -121,10 +133,11 @@ static mips_def_t mips_defs[] = (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3, + .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt), .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3278FF17, + /* No DSP implemented. */ + .CP0_Status_rw_bitmask = 0x1278FF17, }, { .name = "24Kf", @@ -134,13 +147,53 @@ static mips_def_t mips_defs[] = (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3, + .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt), .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3678FF17, + /* No DSP implemented. */ + .CP0_Status_rw_bitmask = 0x3678FF17, .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), }, + { + .name = "34Kf", + .CP0_PRid = 0x00019500, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt) | (1 << CP0C3_MT), + .SYNCI_Step = 32, + .CCRes = 2, + /* No DSP implemented. */ + .CP0_Status_rw_bitmask = 0x3678FF17, + /* No DSP implemented. */ + .CP0_TCStatus_rw_bitmask = (0 << CP0TCSt_TCU3) | (0 << CP0TCSt_TCU2) | + (1 << CP0TCSt_TCU1) | (1 << CP0TCSt_TCU0) | + (0 << CP0TCSt_TMX) | (1 << CP0TCSt_DT) | + (1 << CP0TCSt_DA) | (1 << CP0TCSt_A) | + (0x3 << CP0TCSt_TKSU) | (1 << CP0TCSt_IXMT) | + (0xff << CP0TCSt_TASID), + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | + (1 << FCR0_D) | (1 << FCR0_S) | (0x95 << FCR0_PRID), + .CP0_SRSCtl = (0xf << CP0SRSCtl_HSS), + .CP0_SRSConf0_rw_bitmask = 0x3fffffff, + .CP0_SRSConf0 = (1 << CP0SRSC0_M) | (0x3fe << CP0SRSC0_SRS3) | + (0x3fe << CP0SRSC0_SRS2) | (0x3fe << CP0SRSC0_SRS1), + .CP0_SRSConf1_rw_bitmask = 0x3fffffff, + .CP0_SRSConf1 = (1 << CP0SRSC1_M) | (0x3fe << CP0SRSC1_SRS6) | + (0x3fe << CP0SRSC1_SRS5) | (0x3fe << CP0SRSC1_SRS4), + .CP0_SRSConf2_rw_bitmask = 0x3fffffff, + .CP0_SRSConf2 = (1 << CP0SRSC2_M) | (0x3fe << CP0SRSC2_SRS9) | + (0x3fe << CP0SRSC2_SRS8) | (0x3fe << CP0SRSC2_SRS7), + .CP0_SRSConf3_rw_bitmask = 0x3fffffff, + .CP0_SRSConf3 = (1 << CP0SRSC3_M) | (0x3fe << CP0SRSC3_SRS12) | + (0x3fe << CP0SRSC3_SRS11) | (0x3fe << CP0SRSC3_SRS10), + .CP0_SRSConf4_rw_bitmask = 0x3fffffff, + .CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) | + (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13), + }, #ifdef TARGET_MIPS64 { .name = "R4000", @@ -153,7 +206,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 16, .CCRes = 2, - .Status_rw_bitmask = 0x3678FFFF, + .CP0_Status_rw_bitmask = 0x3678FFFF, /* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */ .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), .SEGBITS = 40, @@ -170,7 +223,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x32F8FFFF, + .CP0_Status_rw_bitmask = 0x32F8FFFF, .SEGBITS = 42, }, { @@ -185,7 +238,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x36F8FFFF, + .CP0_Status_rw_bitmask = 0x36F8FFFF, /* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */ .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) | (0x81 << FCR0_PRID) | (0x0 << FCR0_REV), @@ -205,7 +258,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x36FBFFFF, + .CP0_Status_rw_bitmask = 0x36FBFFFF, /* The 20Kc has F64 / L / W but doesn't use the fcr0 bits. */ .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) | (1 << FCR0_D) | (1 << FCR0_S) | @@ -245,27 +298,88 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) #ifndef CONFIG_USER_ONLY static void no_mmu_init (CPUMIPSState *env, mips_def_t *def) { - env->nb_tlb = 1; - env->map_address = &no_mmu_map_address; + env->tlb->nb_tlb = 1; + env->tlb->map_address = &no_mmu_map_address; } static void fixed_mmu_init (CPUMIPSState *env, mips_def_t *def) { - env->nb_tlb = 1; - env->map_address = &fixed_mmu_map_address; + env->tlb->nb_tlb = 1; + env->tlb->map_address = &fixed_mmu_map_address; } static void r4k_mmu_init (CPUMIPSState *env, mips_def_t *def) { - env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); - env->map_address = &r4k_map_address; - env->do_tlbwi = r4k_do_tlbwi; - env->do_tlbwr = r4k_do_tlbwr; - env->do_tlbp = r4k_do_tlbp; - env->do_tlbr = r4k_do_tlbr; + env->tlb->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); + env->tlb->map_address = &r4k_map_address; + env->tlb->do_tlbwi = r4k_do_tlbwi; + env->tlb->do_tlbwr = r4k_do_tlbwr; + env->tlb->do_tlbp = r4k_do_tlbp; + env->tlb->do_tlbr = r4k_do_tlbr; +} + +static void mmu_init (CPUMIPSState *env, mips_def_t *def) +{ + env->tlb = qemu_mallocz(sizeof(CPUMIPSTLBContext)); + + /* There are more full-featured MMU variants in older MIPS CPUs, + R3000, R6000 and R8000 come to mind. If we ever support them, + this check will need to look up a different place than those + newfangled config registers. */ + switch ((env->CP0_Config0 >> CP0C0_MT) & 3) { + case 0: + no_mmu_init(env, def); + break; + case 1: + r4k_mmu_init(env, def); + break; + case 3: + fixed_mmu_init(env, def); + break; + default: + cpu_abort(env, "MMU type not supported\n"); + } + env->CP0_Random = env->tlb->nb_tlb - 1; + env->tlb->tlb_in_use = env->tlb->nb_tlb; } #endif /* CONFIG_USER_ONLY */ +static void fpu_init (CPUMIPSState *env, mips_def_t *def) +{ + env->fpu = qemu_mallocz(sizeof(CPUMIPSFPUContext)); + + env->fpu->fcr0 = def->CP1_fcr0; +#ifdef CONFIG_USER_ONLY + if (env->CP0_Config1 & (1 << CP0C1_FP)) + env->hflags |= MIPS_HFLAG_FPU; + if (env->fpu->fcr0 & (1 << FCR0_F64)) + env->hflags |= MIPS_HFLAG_F64; +#endif +} + +static void mvp_init (CPUMIPSState *env, mips_def_t *def) +{ + env->mvp = qemu_mallocz(sizeof(CPUMIPSMVPContext)); + + /* MVPConf1 implemented, TLB sharable, no gating storage support, + programmable cache partitioning implemented, number of allocatable + and sharable TLB entries, MVP has allocatable TCs, 2 VPEs + implemented, 5 TCs implemented. */ + env->mvp->CP0_MVPConf0 = (1 << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) | + (0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) | + (env->tlb->nb_tlb << CP0MVPC0_PTLBE) | +// TODO: actually do 2 VPEs. +// (1 << CP0MVPC0_TCA) | (0x1 << CP0MVPC0_PVPE) | +// (0x04 << CP0MVPC0_PTC); + (1 << CP0MVPC0_TCA) | (0x0 << CP0MVPC0_PVPE) | + (0x04 << CP0MVPC0_PTC); + /* Allocatable CP1 have media extensions, allocatable CP1 have FP support, + no UDI implemented, no CP2 implemented, 1 CP1 implemented. */ + env->mvp->CP0_MVPConf1 = (1 << CP0MVPC1_CIM) | (1 << CP0MVPC1_CIF) | + (0x0 << CP0MVPC1_PCX) | (0x0 << CP0MVPC1_PCP2) | + (0x1 << CP0MVPC1_PCP1); +} + int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) { if (!def) @@ -285,8 +399,9 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CP0_Config7 = def->CP0_Config7; env->SYNCI_Step = def->SYNCI_Step; env->CCRes = def->CCRes; - env->Status_rw_bitmask = def->Status_rw_bitmask; - env->fcr0 = def->CP1_fcr0; + env->CP0_Status_rw_bitmask = def->CP0_Status_rw_bitmask; + env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask; + env->CP0_SRSCtl = def->CP0_SRSCtl; #ifdef TARGET_MIPS64 if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) { @@ -298,31 +413,21 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->SEGMask = 0xFFFFFFFF; } #endif -#ifdef CONFIG_USER_ONLY - if (env->CP0_Config1 & (1 << CP0C1_FP)) - env->hflags |= MIPS_HFLAG_FPU; - if (env->fcr0 & (1 << FCR0_F64)) - env->hflags |= MIPS_HFLAG_F64; -#else - /* There are more full-featured MMU variants in older MIPS CPUs, - R3000, R6000 and R8000 come to mind. If we ever support them, - this check will need to look up a different place than those - newfangled config registers. */ - switch ((env->CP0_Config0 >> CP0C0_MT) & 3) { - case 0: - no_mmu_init(env, def); - break; - case 1: - r4k_mmu_init(env, def); - break; - case 3: - fixed_mmu_init(env, def); - break; - default: - cpu_abort(env, "MMU type not supported\n"); - } - env->CP0_Random = env->nb_tlb - 1; - env->tlb_in_use = env->nb_tlb; -#endif /* CONFIG_USER_ONLY */ + env->CP0_SRSConf0_rw_bitmask = def->CP0_SRSConf0_rw_bitmask; + env->CP0_SRSConf0 = def->CP0_SRSConf0; + env->CP0_SRSConf1_rw_bitmask = def->CP0_SRSConf1_rw_bitmask; + env->CP0_SRSConf1 = def->CP0_SRSConf1; + env->CP0_SRSConf2_rw_bitmask = def->CP0_SRSConf2_rw_bitmask; + env->CP0_SRSConf2 = def->CP0_SRSConf2; + env->CP0_SRSConf3_rw_bitmask = def->CP0_SRSConf3_rw_bitmask; + env->CP0_SRSConf3 = def->CP0_SRSConf3; + env->CP0_SRSConf4_rw_bitmask = def->CP0_SRSConf4_rw_bitmask; + env->CP0_SRSConf4 = def->CP0_SRSConf4; + +#ifndef CONFIG_USER_ONLY + mmu_init(env, def); +#endif + fpu_init(env, def); + mvp_init(env, def); return 0; } diff --git a/translate-all.c b/translate-all.c index 491b3b3d33..bd5286f2a1 100644 --- a/translate-all.c +++ b/translate-all.c @@ -305,7 +305,7 @@ int cpu_restore_state(TranslationBlock *tb, #elif defined(TARGET_M68K) env->pc = gen_opc_pc[j]; #elif defined(TARGET_MIPS) - env->PC = gen_opc_pc[j]; + env->PC[env->current_tc] = gen_opc_pc[j]; env->hflags &= ~MIPS_HFLAG_BMASK; env->hflags |= gen_opc_hflags[j]; #elif defined(TARGET_ALPHA) |