X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=qemu%2Ftarget-sparc%2Fop_helper.c;h=468bbb6b43f6329b3a0d3d2a6d40153250004075;hb=f0e029f5ddbd31d87c937004051a18feff54cf9f;hp=143cc164498c723292b5da15c2584e05bfaea994;hpb=4e314c6a1b983419a00d8146bc9234defbfe2e64;p=qemu diff --git a/qemu/target-sparc/op_helper.c b/qemu/target-sparc/op_helper.c index 143cc16..468bbb6 100644 --- a/qemu/target-sparc/op_helper.c +++ b/qemu/target-sparc/op_helper.c @@ -1,5 +1,6 @@ #include "exec.h" +//#define DEBUG_PCALL //#define DEBUG_MMU void raise_exception(int tt) @@ -25,6 +26,13 @@ void do_fabss(void) FT0 = float32_abs(FT1); } +#ifdef TARGET_SPARC64 +void do_fabsd(void) +{ + DT0 = float64_abs(DT1); +} +#endif + void do_fsqrts(void) { FT0 = float32_sqrt(FT1, &env->fp_status); @@ -35,51 +43,188 @@ void do_fsqrtd(void) DT0 = float64_sqrt(DT1, &env->fp_status); } +#define FS 0 void do_fcmps (void) { + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); if (isnan(FT0) || isnan(FT1)) { - T0 = FSR_FCC1 | FSR_FCC0; - env->fsr &= ~(FSR_FCC1 | FSR_FCC0); - env->fsr |= T0; + T0 = (FSR_FCC1 | FSR_FCC0) << FS; if (env->fsr & FSR_NVM) { + env->fsr |= T0; raise_exception(TT_FP_EXCP); } else { env->fsr |= FSR_NVA; } } else if (FT0 < FT1) { - T0 = FSR_FCC0; + T0 = FSR_FCC0 << FS; } else if (FT0 > FT1) { - T0 = FSR_FCC1; + T0 = FSR_FCC1 << FS; } else { T0 = 0; } - env->fsr = T0; + env->fsr |= T0; } void do_fcmpd (void) { + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(DT0) || isnan(DT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (DT0 < DT1) { + T0 = FSR_FCC0 << FS; + } else if (DT0 > DT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +#ifdef TARGET_SPARC64 +#undef FS +#define FS 22 +void do_fcmps_fcc1 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(FT0) || isnan(FT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (FT0 < FT1) { + T0 = FSR_FCC0 << FS; + } else if (FT0 > FT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +void do_fcmpd_fcc1 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(DT0) || isnan(DT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (DT0 < DT1) { + T0 = FSR_FCC0 << FS; + } else if (DT0 > DT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +#undef FS +#define FS 24 +void do_fcmps_fcc2 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(FT0) || isnan(FT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (FT0 < FT1) { + T0 = FSR_FCC0 << FS; + } else if (FT0 > FT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +void do_fcmpd_fcc2 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); if (isnan(DT0) || isnan(DT1)) { - T0 = FSR_FCC1 | FSR_FCC0; - env->fsr &= ~(FSR_FCC1 | FSR_FCC0); - env->fsr |= T0; + T0 = (FSR_FCC1 | FSR_FCC0) << FS; if (env->fsr & FSR_NVM) { + env->fsr |= T0; raise_exception(TT_FP_EXCP); } else { env->fsr |= FSR_NVA; } } else if (DT0 < DT1) { - T0 = FSR_FCC0; + T0 = FSR_FCC0 << FS; } else if (DT0 > DT1) { - T0 = FSR_FCC1; + T0 = FSR_FCC1 << FS; } else { T0 = 0; } - env->fsr = T0; + env->fsr |= T0; } +#undef FS +#define FS 26 +void do_fcmps_fcc3 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(FT0) || isnan(FT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (FT0 < FT1) { + T0 = FSR_FCC0 << FS; + } else if (FT0 > FT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +void do_fcmpd_fcc3 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(DT0) || isnan(DT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (DT0 < DT1) { + T0 = FSR_FCC0 << FS; + } else if (DT0 > DT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} +#undef FS +#endif + +#ifndef TARGET_SPARC64 void helper_ld_asi(int asi, int size, int sign) { - uint32_t ret; + uint32_t ret = 0; switch (asi) { case 3: /* MMU probe */ @@ -90,7 +235,7 @@ void helper_ld_asi(int asi, int size, int sign) if (mmulev > 4) ret = 0; else { - ret = mmu_probe(T0, mmulev); + ret = mmu_probe(env, T0, mmulev); //bswap32s(&ret); } #ifdef DEBUG_MMU @@ -149,13 +294,14 @@ void helper_st_asi(int asi, int size, int sign) break; } #ifdef DEBUG_MMU - dump_mmu(); + dump_mmu(env); #endif return; } case 4: /* write MMU regs */ { - int reg = (T0 >> 8) & 0xf, oldreg; + int reg = (T0 >> 8) & 0xf; + uint32_t oldreg; oldreg = env->mmuregs[reg]; switch(reg) { @@ -186,7 +332,7 @@ void helper_st_asi(int asi, int size, int sign) if (oldreg != env->mmuregs[reg]) { printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]); } - dump_mmu(); + dump_mmu(env); #endif return; } @@ -195,7 +341,7 @@ void helper_st_asi(int asi, int size, int sign) // value (T1) = src // address (T0) = dst // copy 32 bytes - int src = T1, dst = T0; + uint32_t src = T1, dst = T0; uint8_t temp[32]; tswap32s(&src); @@ -209,7 +355,8 @@ void helper_st_asi(int asi, int size, int sign) // value (T1, T2) // address (T0) = dst // fill 32 bytes - int i, dst = T0; + int i; + uint32_t dst = T0; uint64_t val; val = (((uint64_t)T1) << 32) | T2; @@ -222,7 +369,7 @@ void helper_st_asi(int asi, int size, int sign) return; case 0x20 ... 0x2f: /* MMU passthrough */ { - int temp = T1; + uint32_t temp = T1; if (size == 4) tswap32s(&temp); else if (size == 2) @@ -235,6 +382,327 @@ void helper_st_asi(int asi, int size, int sign) } } +#else + +void helper_ld_asi(int asi, int size, int sign) +{ + uint64_t ret = 0; + + if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) + raise_exception(TT_PRIV_ACT); + + switch (asi) { + case 0x14: // Bypass + case 0x15: // Bypass, non-cacheable + { + cpu_physical_memory_read(T0, (void *) &ret, size); + if (size == 8) + tswap64s(&ret); + if (size == 4) + tswap32s((uint32_t *)&ret); + else if (size == 2) + tswap16s((uint16_t *)&ret); + break; + } + case 0x04: // Nucleus + case 0x0c: // Nucleus Little Endian (LE) + case 0x10: // As if user primary + case 0x11: // As if user secondary + case 0x18: // As if user primary LE + case 0x19: // As if user secondary LE + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE + case 0x24: // Nucleus quad LDD 128 bit atomic + case 0x2c: // Nucleus quad LDD 128 bit atomic + case 0x4a: // UPA config + case 0x82: // Primary no-fault + case 0x83: // Secondary no-fault + case 0x88: // Primary LE + case 0x89: // Secondary LE + case 0x8a: // Primary no-fault LE + case 0x8b: // Secondary no-fault LE + // XXX + break; + case 0x45: // LSU + ret = env->lsu; + break; + case 0x50: // I-MMU regs + { + int reg = (T0 >> 3) & 0xf; + + ret = env->immuregs[reg]; + break; + } + case 0x51: // I-MMU 8k TSB pointer + case 0x52: // I-MMU 64k TSB pointer + case 0x55: // I-MMU data access + // XXX + break; + case 0x56: // I-MMU tag read + { + unsigned int i; + + for (i = 0; i < 64; i++) { + // Valid, ctx match, vaddr match + if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 && + env->itlb_tag[i] == T0) { + ret = env->itlb_tag[i]; + break; + } + } + break; + } + case 0x58: // D-MMU regs + { + int reg = (T0 >> 3) & 0xf; + + ret = env->dmmuregs[reg]; + break; + } + case 0x5e: // D-MMU tag read + { + unsigned int i; + + for (i = 0; i < 64; i++) { + // Valid, ctx match, vaddr match + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 && + env->dtlb_tag[i] == T0) { + ret = env->dtlb_tag[i]; + break; + } + } + break; + } + case 0x59: // D-MMU 8k TSB pointer + case 0x5a: // D-MMU 64k TSB pointer + case 0x5b: // D-MMU data pointer + case 0x5d: // D-MMU data access + case 0x48: // Interrupt dispatch, RO + case 0x49: // Interrupt data receive + case 0x7f: // Incoming interrupt vector, RO + // XXX + break; + case 0x54: // I-MMU data in, WO + case 0x57: // I-MMU demap, WO + case 0x5c: // D-MMU data in, WO + case 0x5f: // D-MMU demap, WO + case 0x77: // Interrupt vector, WO + default: + ret = 0; + break; + } + T1 = ret; +} + +void helper_st_asi(int asi, int size, int sign) +{ + if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) + raise_exception(TT_PRIV_ACT); + + switch(asi) { + case 0x14: // Bypass + case 0x15: // Bypass, non-cacheable + { + target_ulong temp = T1; + if (size == 8) + tswap64s(&temp); + else if (size == 4) + tswap32s((uint32_t *)&temp); + else if (size == 2) + tswap16s((uint16_t *)&temp); + cpu_physical_memory_write(T0, (void *) &temp, size); + } + return; + case 0x04: // Nucleus + case 0x0c: // Nucleus Little Endian (LE) + case 0x10: // As if user primary + case 0x11: // As if user secondary + case 0x18: // As if user primary LE + case 0x19: // As if user secondary LE + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE + case 0x24: // Nucleus quad LDD 128 bit atomic + case 0x2c: // Nucleus quad LDD 128 bit atomic + case 0x4a: // UPA config + case 0x88: // Primary LE + case 0x89: // Secondary LE + // XXX + return; + case 0x45: // LSU + { + uint64_t oldreg; + + oldreg = env->lsu; + env->lsu = T1 & (DMMU_E | IMMU_E); + // Mappings generated during D/I MMU disabled mode are + // invalid in normal mode + if (oldreg != env->lsu) { +#ifdef DEBUG_MMU + printf("LSU change: 0x%llx -> 0x%llx\n", oldreg, env->lsu); + dump_mmu(env); +#endif + tlb_flush(env, 1); + } + return; + } + case 0x50: // I-MMU regs + { + int reg = (T0 >> 3) & 0xf; + uint64_t oldreg; + + oldreg = env->immuregs[reg]; + switch(reg) { + case 0: // RO + case 4: + return; + case 1: // Not in I-MMU + case 2: + case 7: + case 8: + return; + case 3: // SFSR + if ((T1 & 1) == 0) + T1 = 0; // Clear SFSR + break; + case 5: // TSB access + case 6: // Tag access + default: + break; + } + env->immuregs[reg] = T1; +#ifdef DEBUG_MMU + if (oldreg != env->immuregs[reg]) { + printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->immuregs[reg]); + } + dump_mmu(env); +#endif + return; + } + case 0x54: // I-MMU data in + { + unsigned int i; + + // Try finding an invalid entry + for (i = 0; i < 64; i++) { + if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) { + env->itlb_tag[i] = env->immuregs[6]; + env->itlb_tte[i] = T1; + return; + } + } + // Try finding an unlocked entry + for (i = 0; i < 64; i++) { + if ((env->itlb_tte[i] & 0x40) == 0) { + env->itlb_tag[i] = env->immuregs[6]; + env->itlb_tte[i] = T1; + return; + } + } + // error state? + return; + } + case 0x55: // I-MMU data access + { + unsigned int i = (T0 >> 3) & 0x3f; + + env->itlb_tag[i] = env->immuregs[6]; + env->itlb_tte[i] = T1; + return; + } + case 0x57: // I-MMU demap + // XXX + return; + case 0x58: // D-MMU regs + { + int reg = (T0 >> 3) & 0xf; + uint64_t oldreg; + + oldreg = env->dmmuregs[reg]; + switch(reg) { + case 0: // RO + case 4: + return; + case 3: // SFSR + if ((T1 & 1) == 0) { + T1 = 0; // Clear SFSR, Fault address + env->dmmuregs[4] = 0; + } + env->dmmuregs[reg] = T1; + break; + case 1: // Primary context + case 2: // Secondary context + case 5: // TSB access + case 6: // Tag access + case 7: // Virtual Watchpoint + case 8: // Physical Watchpoint + default: + break; + } + env->dmmuregs[reg] = T1; +#ifdef DEBUG_MMU + if (oldreg != env->dmmuregs[reg]) { + printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->dmmuregs[reg]); + } + dump_mmu(env); +#endif + return; + } + case 0x5c: // D-MMU data in + { + unsigned int i; + + // Try finding an invalid entry + for (i = 0; i < 64; i++) { + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) { + env->dtlb_tag[i] = env->dmmuregs[6]; + env->dtlb_tte[i] = T1; + return; + } + } + // Try finding an unlocked entry + for (i = 0; i < 64; i++) { + if ((env->dtlb_tte[i] & 0x40) == 0) { + env->dtlb_tag[i] = env->dmmuregs[6]; + env->dtlb_tte[i] = T1; + return; + } + } + // error state? + return; + } + case 0x5d: // D-MMU data access + { + unsigned int i = (T0 >> 3) & 0x3f; + + env->dtlb_tag[i] = env->dmmuregs[6]; + env->dtlb_tte[i] = T1; + return; + } + case 0x5f: // D-MMU demap + case 0x49: // Interrupt data receive + // XXX + return; + case 0x51: // I-MMU 8k TSB pointer, RO + case 0x52: // I-MMU 64k TSB pointer, RO + case 0x56: // I-MMU tag read, RO + case 0x59: // D-MMU 8k TSB pointer, RO + case 0x5a: // D-MMU 64k TSB pointer, RO + case 0x5b: // D-MMU data pointer, RO + case 0x5e: // D-MMU tag read, RO + case 0x48: // Interrupt dispatch, RO + case 0x7f: // Incoming interrupt vector, RO + case 0x82: // Primary no-fault, RO + case 0x83: // Secondary no-fault, RO + case 0x8a: // Primary no-fault LE, RO + case 0x8b: // Secondary no-fault LE, RO + default: + return; + } +} + +#endif + +#ifndef TARGET_SPARC64 void helper_rett() { unsigned int cwp; @@ -247,6 +715,7 @@ void helper_rett() set_cwp(cwp); env->psrs = env->psrps; } +#endif void helper_ldfsr(void) { @@ -288,6 +757,7 @@ void helper_debug() cpu_loop_exit(); } +#ifndef TARGET_SPARC64 void do_wrpsr() { PUT_PSR(env, T0); @@ -297,3 +767,257 @@ void do_rdpsr() { T0 = GET_PSR(env); } + +#else + +void do_popc() +{ + T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL); + T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL); + T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL); + T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL); + T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL); + T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL); +} + +static inline uint64_t *get_gregset(uint64_t pstate) +{ + switch (pstate) { + default: + case 0: + return env->bgregs; + case PS_AG: + return env->agregs; + case PS_MG: + return env->mgregs; + case PS_IG: + return env->igregs; + } +} + +void do_wrpstate() +{ + uint64_t new_pstate, pstate_regs, new_pstate_regs; + uint64_t *src, *dst; + + new_pstate = T0 & 0xf3f; + pstate_regs = env->pstate & 0xc01; + new_pstate_regs = new_pstate & 0xc01; + if (new_pstate_regs != pstate_regs) { + // Switch global register bank + src = get_gregset(new_pstate_regs); + dst = get_gregset(pstate_regs); + memcpy32(dst, env->gregs); + memcpy32(env->gregs, src); + } + env->pstate = new_pstate; +} + +void do_done(void) +{ + env->tl--; + env->pc = env->tnpc[env->tl]; + env->npc = env->tnpc[env->tl] + 4; + PUT_CCR(env, env->tstate[env->tl] >> 32); + env->asi = (env->tstate[env->tl] >> 24) & 0xff; + env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; + set_cwp(env->tstate[env->tl] & 0xff); +} + +void do_retry(void) +{ + env->tl--; + env->pc = env->tpc[env->tl]; + env->npc = env->tnpc[env->tl]; + PUT_CCR(env, env->tstate[env->tl] >> 32); + env->asi = (env->tstate[env->tl] >> 24) & 0xff; + env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; + set_cwp(env->tstate[env->tl] & 0xff); +} +#endif + +void set_cwp(int new_cwp) +{ + /* put the modified wrap registers at their proper location */ + if (env->cwp == (NWINDOWS - 1)) + memcpy32(env->regbase, env->regbase + NWINDOWS * 16); + env->cwp = new_cwp; + /* put the wrap registers at their temporary location */ + if (new_cwp == (NWINDOWS - 1)) + memcpy32(env->regbase + NWINDOWS * 16, env->regbase); + env->regwptr = env->regbase + (new_cwp * 16); + REGWPTR = env->regwptr; +} + +void cpu_set_cwp(CPUState *env1, int new_cwp) +{ + CPUState *saved_env; +#ifdef reg_REGWPTR + target_ulong *saved_regwptr; +#endif + + saved_env = env; +#ifdef reg_REGWPTR + saved_regwptr = REGWPTR; +#endif + env = env1; + set_cwp(new_cwp); + env = saved_env; +#ifdef reg_REGWPTR + REGWPTR = saved_regwptr; +#endif +} + +#ifdef TARGET_SPARC64 +void do_interrupt(int intno) +{ +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_INT) { + static int count; + fprintf(logfile, "%6d: v=%04x pc=%016llx npc=%016llx SP=%016llx\n", + count, intno, + env->pc, + env->npc, env->regwptr[6]); + cpu_dump_state(env, logfile, fprintf, 0); +#if 0 + { + int i; + uint8_t *ptr; + + fprintf(logfile, " code="); + ptr = (uint8_t *)env->pc; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); + } + fprintf(logfile, "\n"); + } +#endif + count++; + } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->tl == MAXTL) { + cpu_abort(cpu_single_env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index); + return; + } +#endif + env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | + ((env->pstate & 0xfff) << 8) | (env->cwp & 0xff); + env->tpc[env->tl] = env->pc; + env->tnpc[env->tl] = env->npc; + env->tt[env->tl] = intno; + env->pstate = PS_PEF | PS_PRIV | PS_AG; + env->tbr &= ~0x7fffULL; + env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); + if (env->tl < MAXTL - 1) { + env->tl++; + } else { + env->pstate |= PS_RED; + if (env->tl != MAXTL) + env->tl++; + } + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = 0; +} +#else +void do_interrupt(int intno) +{ + int cwp; + +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_INT) { + static int count; + fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", + count, intno, + env->pc, + env->npc, env->regwptr[6]); + cpu_dump_state(env, logfile, fprintf, 0); +#if 0 + { + int i; + uint8_t *ptr; + + fprintf(logfile, " code="); + ptr = (uint8_t *)env->pc; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); + } + fprintf(logfile, "\n"); + } +#endif + count++; + } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->psret == 0) { + cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); + return; + } +#endif + env->psret = 0; + cwp = (env->cwp - 1) & (NWINDOWS - 1); + set_cwp(cwp); + env->regwptr[9] = env->pc; + env->regwptr[10] = env->npc; + env->psrps = env->psrs; + env->psrs = 1; + env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = 0; +} +#endif + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + int ret; + unsigned long pc; + CPUState *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + + ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (ret) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + tb = tb_find_pc(pc); + if (tb) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, pc, (void *)T2); + } + } + cpu_loop_exit(); + } + env = saved_env; +} + +#endif