diff options
Diffstat (limited to 'target-sparc/op_helper.c')
-rw-r--r-- | target-sparc/op_helper.c | 176 |
1 files changed, 133 insertions, 43 deletions
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 3a6de7cfc2..6dead66a8c 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -2,6 +2,8 @@ #include <fenv.h> #include "exec.h" +//#define DEBUG_MMU + #ifdef USE_INT_TO_FLOAT_HELPERS void do_fitos(void) { @@ -33,6 +35,13 @@ void do_fcmps (void) { if (isnan(FT0) || isnan(FT1)) { T0 = FSR_FCC1 | FSR_FCC0; + env->fsr &= ~(FSR_FCC1 | FSR_FCC0); + env->fsr |= T0; + if (env->fsr & FSR_NVM) { + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } } else if (FT0 < FT1) { T0 = FSR_FCC0; } else if (FT0 > FT1) { @@ -47,6 +56,13 @@ void do_fcmpd (void) { if (isnan(DT0) || isnan(DT1)) { T0 = FSR_FCC1 | FSR_FCC0; + env->fsr &= ~(FSR_FCC1 | FSR_FCC0); + env->fsr |= T0; + if (env->fsr & FSR_NVM) { + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } } else if (DT0 < DT1) { T0 = FSR_FCC0; } else if (DT0 > DT1) { @@ -59,55 +75,131 @@ void do_fcmpd (void) void helper_ld_asi(int asi, int size, int sign) { - switch(asi) { + uint32_t ret; + + switch (asi) { case 3: /* MMU probe */ - T1 = 0; - return; + { + int mmulev; + + mmulev = (T0 >> 8) & 15; + if (mmulev > 4) + ret = 0; + else { + ret = mmu_probe(T0, mmulev); + //bswap32s(&ret); + } +#ifdef DEBUG_MMU + printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); +#endif + } + break; case 4: /* read MMU regs */ { - int temp, reg = (T0 >> 8) & 0xf; + int reg = (T0 >> 8) & 0xf; - temp = env->mmuregs[reg]; + ret = env->mmuregs[reg]; if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/ - env->mmuregs[reg] = 0; - T1 = temp; + env->mmuregs[4] = 0; } - return; + break; case 0x20 ... 0x2f: /* MMU passthrough */ - { - int temp; - - cpu_physical_memory_read(T0, (void *) &temp, size); - bswap32s(&temp); - T1 = temp; - } - return; + cpu_physical_memory_read(T0, (void *) &ret, size); + if (size == 4) + bswap32s(&ret); + else if (size == 2) + bswap16s(&ret); + break; default: - T1 = 0; - return; + ret = 0; + break; } + T1 = ret; } void helper_st_asi(int asi, int size, int sign) { switch(asi) { case 3: /* MMU flush */ - return; + { + int mmulev; + + mmulev = (T0 >> 8) & 15; + switch (mmulev) { + case 0: // flush page + tlb_flush_page(cpu_single_env, T0 & 0xfffff000); + break; + case 1: // flush segment (256k) + case 2: // flush region (16M) + case 3: // flush context (4G) + case 4: // flush entire + tlb_flush(cpu_single_env, 1); + break; + default: + break; + } + dump_mmu(); + return; + } case 4: /* write MMU regs */ { - int reg = (T0 >> 8) & 0xf; + int reg = (T0 >> 8) & 0xf, oldreg; + + oldreg = env->mmuregs[reg]; if (reg == 0) { env->mmuregs[reg] &= ~(MMU_E | MMU_NF); env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); } else env->mmuregs[reg] = T1; + if (oldreg != env->mmuregs[reg]) { +#if 0 + // XXX: Only if MMU mapping change, we may need to flush? + tlb_flush(cpu_single_env, 1); + cpu_loop_exit(); + FORCE_RET(); +#endif + } + dump_mmu(); return; } + case 0x17: /* Block copy, sta access */ + { + // value (T1) = src + // address (T0) = dst + // copy 32 bytes + int src = T1, dst = T0; + uint8_t temp[32]; + + bswap32s(&src); + + cpu_physical_memory_read(src, (void *) &temp, 32); + cpu_physical_memory_write(dst, (void *) &temp, 32); + } + return; + case 0x1f: /* Block fill, stda access */ + { + // value (T1, T2) + // address (T0) = dst + // fill 32 bytes + int i, dst = T0; + uint64_t val; + + val = (((uint64_t)T1) << 32) | T2; + bswap64s(&val); + + for (i = 0; i < 32; i += 8, dst += 8) { + cpu_physical_memory_write(dst, (void *) &val, 8); + } + } + return; case 0x20 ... 0x2f: /* MMU passthrough */ { int temp = T1; - - bswap32s(&temp); + if (size == 4) + bswap32s(&temp); + else if (size == 2) + bswap16s(&temp); + cpu_physical_memory_write(T0, (void *) &temp, size); } return; @@ -116,27 +208,6 @@ void helper_st_asi(int asi, int size, int sign) } } -#if 0 -void do_ldd_raw(uint32_t addr) -{ - T1 = ldl_raw((void *) addr); - T0 = ldl_raw((void *) (addr + 4)); -} - -#if !defined(CONFIG_USER_ONLY) -void do_ldd_user(uint32_t addr) -{ - T1 = ldl_user((void *) addr); - T0 = ldl_user((void *) (addr + 4)); -} -void do_ldd_kernel(uint32_t addr) -{ - T1 = ldl_kernel((void *) addr); - T0 = ldl_kernel((void *) (addr + 4)); -} -#endif -#endif - void helper_rett() { int cwp; @@ -166,3 +237,22 @@ void helper_ldfsr(void) break; } } + +void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f) +{ + int exptemp; + + *pmant = ldexp(frexp(f, &exptemp), 53); + *pexp = exptemp; +} + +double cpu_put_fp64(uint64_t mant, uint16_t exp) +{ + return ldexp((double) mant, exp - 53); +} + +void helper_debug() +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} |