diff options
Diffstat (limited to 'target-sparc')
| -rw-r--r-- | target-sparc/cpu.h | 73 | ||||
| -rw-r--r-- | target-sparc/helper.c | 130 | ||||
| -rw-r--r-- | target-sparc/op_helper.c | 250 | ||||
| -rw-r--r-- | target-sparc/translate.c | 286 |
4 files changed, 501 insertions, 238 deletions
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 27b020b541..8f0484b24a 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -92,12 +92,14 @@ #define PSR_CARRY_SHIFT 20 #define PSR_CARRY (1 << PSR_CARRY_SHIFT) #define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY) +#if !defined(TARGET_SPARC64) #define PSR_EF (1<<12) #define PSR_PIL 0xf00 #define PSR_S (1<<7) #define PSR_PS (1<<6) #define PSR_ET (1<<5) #define PSR_CWP 0x1f +#endif #define CC_SRC (env->cc_src) #define CC_SRC2 (env->cc_src2) @@ -341,14 +343,16 @@ typedef struct CPUSPARCState { uint32_t wim; /* window invalid mask */ #endif target_ulong tbr; /* trap base register */ +#if !defined(TARGET_SPARC64) int psrs; /* supervisor mode (extracted from PSR) */ int psrps; /* previous supervisor mode */ -#if !defined(TARGET_SPARC64) int psret; /* enable traps */ #endif uint32_t psrpil; /* interrupt blocking level */ uint32_t pil_in; /* incoming interrupt level bitmap */ +#if !defined(TARGET_SPARC64) int psref; /* enable fpu */ +#endif target_ulong version; int interrupt_index; uint32_t nwindows; @@ -508,21 +512,41 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); #define CPU_SAVE_VERSION 6 /* MMU modes definitions */ +#if defined (TARGET_SPARC64) +#define MMU_USER_IDX 0 #define MMU_MODE0_SUFFIX _user -#define MMU_MODE1_SUFFIX _kernel -#ifdef TARGET_SPARC64 -#define MMU_MODE2_SUFFIX _hypv -#define MMU_MODE3_SUFFIX _nucleus -#define MMU_MODE4_SUFFIX _user_secondary -#define MMU_MODE5_SUFFIX _kernel_secondary -#endif +#define MMU_USER_SECONDARY_IDX 1 +#define MMU_MODE1_SUFFIX _user_secondary +#define MMU_KERNEL_IDX 2 +#define MMU_MODE2_SUFFIX _kernel +#define MMU_KERNEL_SECONDARY_IDX 3 +#define MMU_MODE3_SUFFIX _kernel_secondary +#define MMU_NUCLEUS_IDX 4 +#define MMU_MODE4_SUFFIX _nucleus +#define MMU_HYPV_IDX 5 +#define MMU_MODE5_SUFFIX _hypv +#else #define MMU_USER_IDX 0 +#define MMU_MODE0_SUFFIX _user #define MMU_KERNEL_IDX 1 -#define MMU_HYPV_IDX 2 -#ifdef TARGET_SPARC64 -#define MMU_NUCLEUS_IDX 3 -#define MMU_USER_SECONDARY_IDX 4 -#define MMU_KERNEL_SECONDARY_IDX 5 +#define MMU_MODE1_SUFFIX _kernel +#endif + +#if defined (TARGET_SPARC64) +static inline int cpu_has_hypervisor(CPUState *env1) +{ + return env1->def->features & CPU_FEATURE_HYPV; +} + +static inline int cpu_hypervisor_mode(CPUState *env1) +{ + return cpu_has_hypervisor(env1) && (env1->hpstate & HS_PRIV); +} + +static inline int cpu_supervisor_mode(CPUState *env1) +{ + return env1->pstate & PS_PRIV; +} #endif static inline int cpu_mmu_index(CPUState *env1) @@ -532,12 +556,15 @@ static inline int cpu_mmu_index(CPUState *env1) #elif !defined(TARGET_SPARC64) return env1->psrs; #else - if (!env1->psrs) - return MMU_USER_IDX; - else if ((env1->hpstate & HS_PRIV) == 0) - return MMU_KERNEL_IDX; - else + if (env1->tl > 0) { + return MMU_NUCLEUS_IDX; + } else if (cpu_hypervisor_mode(env1)) { return MMU_HYPV_IDX; + } else if (cpu_supervisor_mode(env1)) { + return MMU_KERNEL_IDX; + } else { + return MMU_USER_IDX; + } #endif } @@ -611,9 +638,13 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, *cs_base = env->npc; #ifdef TARGET_SPARC64 // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled - *flags = ((env->pstate & PS_AM) << 2) - | (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2)) - | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); + *flags = ((env->pstate & PS_AM) << 2) /* 5 */ + | (((env->pstate & PS_PEF) >> 1) /* 3 */ + | ((env->fprs & FPRS_FEF) << 2)) /* 4 */ + | (env->pstate & PS_PRIV) /* 2 */ + | ((env->lsu & (DMMU_E | IMMU_E)) >> 2) /* 1, 0 */ + | ((env->tl & 0xff) << 8) + | (env->dmmu.mmu_primary_context << 16); /* 16... */ #else // FPU enable . Supervisor *flags = (env->psref << 4) | env->psrs; diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 582de1082c..96a22f3475 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -30,6 +30,13 @@ //#define DEBUG_MMU //#define DEBUG_FEATURES +#ifdef DEBUG_MMU +#define DPRINTF_MMU(fmt, ...) \ + do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF_MMU(fmt, ...) do {} while (0) +#endif + static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model); /* Sparc MMU emulation */ @@ -451,42 +458,50 @@ static int get_physical_address_data(CPUState *env, for (i = 0; i < 64; i++) { // ctx match, vaddr match, valid? - if (ultrasparc_tag_match(&env->dtlb[i], - address, context, physical)) { + if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) { + + uint8_t fault_type = 0; + // access ok? - if (((env->dtlb[i].tte & 0x4) && is_user) || - (!(env->dtlb[i].tte & 0x2) && (rw == 1))) { - uint8_t fault_type = 0; + if ((env->dtlb[i].tte & 0x4) && is_user) { + fault_type |= 1; /* privilege violation */ + env->exception_index = TT_DFAULT; - if ((env->dtlb[i].tte & 0x4) && is_user) { - fault_type |= 1; /* privilege violation */ - } + DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64 + " mmu_idx=%d tl=%d\n", + address, context, mmu_idx, env->tl); + } else if (!(env->dtlb[i].tte & 0x2) && (rw == 1)) { + env->exception_index = TT_DPROT; + + DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64 + " mmu_idx=%d tl=%d\n", + address, context, mmu_idx, env->tl); + } else { + *prot = PAGE_READ; + if (env->dtlb[i].tte & 0x2) + *prot |= PAGE_WRITE; - if (env->dmmu.sfsr & 1) /* Fault status register */ - env->dmmu.sfsr = 2; /* overflow (not read before + TTE_SET_USED(env->dtlb[i].tte); + + return 0; + } + + if (env->dmmu.sfsr & 1) /* Fault status register */ + env->dmmu.sfsr = 2; /* overflow (not read before another fault) */ - env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1; + env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1; - env->dmmu.sfsr |= (fault_type << 7); + env->dmmu.sfsr |= (fault_type << 7); - env->dmmu.sfar = address; /* Fault address register */ - env->exception_index = TT_DFAULT; -#ifdef DEBUG_MMU - printf("DFAULT at 0x%" PRIx64 "\n", address); -#endif - return 1; - } - *prot = PAGE_READ; - if (env->dtlb[i].tte & 0x2) - *prot |= PAGE_WRITE; - TTE_SET_USED(env->dtlb[i].tte); - return 0; + env->dmmu.sfar = address; /* Fault address register */ + return 1; } } -#ifdef DEBUG_MMU - printf("DMISS at 0x%" PRIx64 "\n", address); -#endif + + DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n", + address, context); + env->dmmu.tag_access = (address & ~0x1fffULL) | context; env->exception_index = TT_DMISS; return 1; @@ -528,9 +543,10 @@ static int get_physical_address_code(CPUState *env, another fault) */ env->immu.sfsr |= (is_user << 3) | 1; env->exception_index = TT_TFAULT; -#ifdef DEBUG_MMU - printf("TFAULT at 0x%" PRIx64 "\n", address); -#endif + + DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n", + address, context); + return 1; } *prot = PAGE_EXEC; @@ -538,9 +554,10 @@ static int get_physical_address_code(CPUState *env, return 0; } } -#ifdef DEBUG_MMU - printf("TMISS at 0x%" PRIx64 "\n", address); -#endif + + DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n", + address, context); + /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */ env->immu.tag_access = (address & ~0x1fffULL) | context; env->exception_index = TT_TMISS; @@ -555,6 +572,23 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical, /* ??? We treat everything as a small page, then explicitly flush everything when an entry is evicted. */ *page_size = TARGET_PAGE_SIZE; + +#if defined (DEBUG_MMU) + /* safety net to catch wrong softmmu index use from dynamic code */ + if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) { + DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d" + " primary context=%" PRIx64 + " secondary context=%" PRIx64 + " address=%" PRIx64 + "\n", + (rw == 2 ? "CODE" : "DATA"), + env->tl, mmu_idx, + env->dmmu.mmu_primary_context, + env->dmmu.mmu_secondary_context, + address); + } +#endif + if (rw == 2) return get_physical_address_code(env, physical, prot, address, mmu_idx); @@ -578,10 +612,18 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, virt_addr = address & TARGET_PAGE_MASK; vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); -#ifdef DEBUG_MMU - printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 - "\n", address, paddr, vaddr); -#endif + + DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 "," + " vaddr %" PRIx64 + " mmu_idx=%d" + " tl=%d" + " primary context=%" PRIx64 + " secondary context=%" PRIx64 + "\n", + address, paddr, vaddr, mmu_idx, env->tl, + env->dmmu.mmu_primary_context, + env->dmmu.mmu_secondary_context); + tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); return 0; } @@ -628,7 +670,7 @@ void dump_mmu(CPUState *env) env->dtlb[i].tte & 0x2? "RW": "RO", env->dtlb[i].tte & 0x40? "locked": "unlocked", env->dtlb[i].tag & (uint64_t)0x1fffULL, - TTE_IS_GLOBAL(env->dtlb[i].tag)? "global" : "local"); + TTE_IS_GLOBAL(env->dtlb[i].tte)? "global" : "local"); } } } @@ -662,7 +704,7 @@ void dump_mmu(CPUState *env) env->itlb[i].tte & 0x4? "priv": "user", env->itlb[i].tte & 0x40? "locked": "unlocked", env->itlb[i].tag & (uint64_t)0x1fffULL, - TTE_IS_GLOBAL(env->itlb[i].tag)? "global" : "local"); + TTE_IS_GLOBAL(env->itlb[i].tte)? "global" : "local"); } } } @@ -693,7 +735,7 @@ target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr, target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - return cpu_get_phys_page_nofault(env, addr, MMU_KERNEL_IDX); + return cpu_get_phys_page_nofault(env, addr, cpu_mmu_index(env)); } #endif @@ -721,12 +763,12 @@ void cpu_reset(CPUSPARCState *env) #else #if !defined(TARGET_SPARC64) env->psret = 0; -#endif env->psrs = 1; env->psrps = 1; +#endif #ifdef TARGET_SPARC64 env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG; - env->hpstate = HS_PRIV; + env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0; env->tl = env->maxtl; cpu_tsptr(env)->tt = TT_POWER_ON_RESET; env->lsu = 0; @@ -1310,7 +1352,7 @@ static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model) char *featurestr, *name = strtok(s, ","); uint32_t plus_features = 0; uint32_t minus_features = 0; - long long iu_version; + uint64_t iu_version; uint32_t fpu_version, mmu_version, nwindows; for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) { @@ -1342,7 +1384,7 @@ static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model) } cpu_def->iu_version = iu_version; #ifdef DEBUG_FEATURES - fprintf(stderr, "iu_version %llx\n", iu_version); + fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version); #endif } else if (!strcmp(featurestr, "fpu_version")) { char *err; diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index b1451d346f..edeeb4469a 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -901,14 +901,15 @@ static uint32_t compute_C_flags(void) return env->psr & PSR_CARRY; } -static inline uint32_t get_NZ_icc(target_ulong dst) +static inline uint32_t get_NZ_icc(int32_t dst) { uint32_t ret = 0; - if (!(dst & 0xffffffffULL)) - ret |= PSR_ZERO; - if ((int32_t) (dst & 0xffffffffULL) < 0) - ret |= PSR_NEG; + if (dst == 0) { + ret = PSR_ZERO; + } else if (dst < 0) { + ret = PSR_NEG; + } return ret; } @@ -923,14 +924,15 @@ static uint32_t compute_C_flags_xcc(void) return env->xcc & PSR_CARRY; } -static inline uint32_t get_NZ_xcc(target_ulong dst) +static inline uint32_t get_NZ_xcc(target_long dst) { uint32_t ret = 0; - if (!dst) - ret |= PSR_ZERO; - if ((int64_t)dst < 0) - ret |= PSR_NEG; + if (!dst) { + ret = PSR_ZERO; + } else if (dst < 0) { + ret = PSR_NEG; + } return ret; } #endif @@ -939,8 +941,9 @@ static inline uint32_t get_V_div_icc(target_ulong src2) { uint32_t ret = 0; - if (src2 != 0) - ret |= PSR_OVF; + if (src2 != 0) { + ret = PSR_OVF; + } return ret; } @@ -958,26 +961,35 @@ static uint32_t compute_C_div(void) return 0; } -/* carry = (src1[31] & src2[31]) | ( ~dst[31] & (src1[31] | src2[31])) */ -static inline uint32_t get_C_add_icc(target_ulong dst, target_ulong src1, - target_ulong src2) +static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1) { uint32_t ret = 0; - if (((src1 & (1ULL << 31)) & (src2 & (1ULL << 31))) - | ((~(dst & (1ULL << 31))) - & ((src1 & (1ULL << 31)) | (src2 & (1ULL << 31))))) - ret |= PSR_CARRY; + if (dst < src1) { + ret = PSR_CARRY; + } return ret; } -static inline uint32_t get_V_add_icc(target_ulong dst, target_ulong src1, - target_ulong src2) +static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1, + uint32_t src2) +{ + uint32_t ret = 0; + + if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1, + uint32_t src2) { uint32_t ret = 0; - if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 31)) - ret |= PSR_OVF; + if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) { + ret = PSR_OVF; + } return ret; } @@ -986,8 +998,20 @@ static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1) { uint32_t ret = 0; - if (dst < src1) - ret |= PSR_CARRY; + if (dst < src1) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) { + ret = PSR_CARRY; + } return ret; } @@ -996,8 +1020,9 @@ static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1, { uint32_t ret = 0; - if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) - ret |= PSR_OVF; + if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) { + ret = PSR_OVF; + } return ret; } @@ -1022,14 +1047,14 @@ static uint32_t compute_all_add(void) uint32_t ret; ret = get_NZ_icc(CC_DST); - ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_C_add_icc(CC_DST, CC_SRC); ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); return ret; } static uint32_t compute_C_add(void) { - return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2); + return get_C_add_icc(CC_DST, CC_SRC); } #ifdef TARGET_SPARC64 @@ -1038,8 +1063,7 @@ static uint32_t compute_all_addx_xcc(void) uint32_t ret; ret = get_NZ_xcc(CC_DST); - ret |= get_C_add_xcc(CC_DST - CC_SRC2, CC_SRC); - ret |= get_C_add_xcc(CC_DST, CC_SRC); + ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); return ret; } @@ -1048,18 +1072,36 @@ static uint32_t compute_C_addx_xcc(void) { uint32_t ret; - ret = get_C_add_xcc(CC_DST - CC_SRC2, CC_SRC); - ret |= get_C_add_xcc(CC_DST, CC_SRC); + ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); return ret; } #endif +static uint32_t compute_all_addx(void) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_addx(void) +{ + uint32_t ret; + + ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2) { uint32_t ret = 0; - if ((src1 | src2) & 0x3) - ret |= PSR_OVF; + if ((src1 | src2) & 0x3) { + ret = PSR_OVF; + } return ret; } @@ -1068,51 +1110,50 @@ static uint32_t compute_all_tadd(void) uint32_t ret; ret = get_NZ_icc(CC_DST); - ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_C_add_icc(CC_DST, CC_SRC); ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); ret |= get_V_tag_icc(CC_SRC, CC_SRC2); return ret; } -static uint32_t compute_C_tadd(void) -{ - return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2); -} - static uint32_t compute_all_taddtv(void) { uint32_t ret; ret = get_NZ_icc(CC_DST); - ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_C_add_icc(CC_DST, CC_SRC); return ret; } -static uint32_t compute_C_taddtv(void) +static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2) { - return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2); + uint32_t ret = 0; + + if (src1 < src2) { + ret = PSR_CARRY; + } + return ret; } -/* carry = (~src1[31] & src2[31]) | ( dst[31] & (~src1[31] | src2[31])) */ -static inline uint32_t get_C_sub_icc(target_ulong dst, target_ulong src1, - target_ulong src2) +static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1, + uint32_t src2) { uint32_t ret = 0; - if (((~(src1 & (1ULL << 31))) & (src2 & (1ULL << 31))) - | ((dst & (1ULL << 31)) & (( ~(src1 & (1ULL << 31))) - | (src2 & (1ULL << 31))))) - ret |= PSR_CARRY; + if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) { + ret = PSR_CARRY; + } return ret; } -static inline uint32_t get_V_sub_icc(target_ulong dst, target_ulong src1, - target_ulong src2) +static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1, + uint32_t src2) { uint32_t ret = 0; - if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 31)) - ret |= PSR_OVF; + if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) { + ret = PSR_OVF; + } return ret; } @@ -1122,8 +1163,20 @@ static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2) { uint32_t ret = 0; - if (src1 < src2) - ret |= PSR_CARRY; + if (src1 < src2) { + ret = PSR_CARRY; + } + return ret; +} + +static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) { + ret = PSR_CARRY; + } return ret; } @@ -1132,8 +1185,9 @@ static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1, { uint32_t ret = 0; - if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) - ret |= PSR_OVF; + if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) { + ret = PSR_OVF; + } return ret; } @@ -1158,14 +1212,14 @@ static uint32_t compute_all_sub(void) uint32_t ret; ret = get_NZ_icc(CC_DST); - ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_C_sub_icc(CC_SRC, CC_SRC2); ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); return ret; } static uint32_t compute_C_sub(void) { - return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2); + return get_C_sub_icc(CC_SRC, CC_SRC2); } #ifdef TARGET_SPARC64 @@ -1174,8 +1228,7 @@ static uint32_t compute_all_subx_xcc(void) uint32_t ret; ret = get_NZ_xcc(CC_DST); - ret |= get_C_sub_xcc(CC_DST - CC_SRC2, CC_SRC); - ret |= get_C_sub_xcc(CC_DST, CC_SRC2); + ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); return ret; } @@ -1184,40 +1237,47 @@ static uint32_t compute_C_subx_xcc(void) { uint32_t ret; - ret = get_C_sub_xcc(CC_DST - CC_SRC2, CC_SRC); - ret |= get_C_sub_xcc(CC_DST, CC_SRC2); + ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); return ret; } #endif -static uint32_t compute_all_tsub(void) +static uint32_t compute_all_subx(void) { uint32_t ret; ret = get_NZ_icc(CC_DST); - ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); - ret |= get_V_tag_icc(CC_SRC, CC_SRC2); return ret; } -static uint32_t compute_C_tsub(void) +static uint32_t compute_C_subx(void) { - return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2); + uint32_t ret; + + ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; } -static uint32_t compute_all_tsubtv(void) +static uint32_t compute_all_tsub(void) { uint32_t ret; ret = get_NZ_icc(CC_DST); - ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_C_sub_icc(CC_SRC, CC_SRC2); + ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); + ret |= get_V_tag_icc(CC_SRC, CC_SRC2); return ret; } -static uint32_t compute_C_tsubtv(void) +static uint32_t compute_all_tsubtv(void) { - return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2); + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_sub_icc(CC_SRC, CC_SRC2); + return ret; } static uint32_t compute_all_logic(void) @@ -1247,13 +1307,13 @@ static const CCTable icc_table[CC_OP_NB] = { [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags }, [CC_OP_DIV] = { compute_all_div, compute_C_div }, [CC_OP_ADD] = { compute_all_add, compute_C_add }, - [CC_OP_ADDX] = { compute_all_add, compute_C_add }, - [CC_OP_TADD] = { compute_all_tadd, compute_C_tadd }, - [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_taddtv }, + [CC_OP_ADDX] = { compute_all_addx, compute_C_addx }, + [CC_OP_TADD] = { compute_all_tadd, compute_C_add }, + [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add }, [CC_OP_SUB] = { compute_all_sub, compute_C_sub }, - [CC_OP_SUBX] = { compute_all_sub, compute_C_sub }, - [CC_OP_TSUB] = { compute_all_tsub, compute_C_tsub }, - [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_tsubtv }, + [CC_OP_SUBX] = { compute_all_subx, compute_C_subx }, + [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub }, + [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub }, [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic }, }; @@ -1344,11 +1404,7 @@ static target_ulong get_psr(void) (env->psrps? PSR_PS : 0) | (env->psret? PSR_ET : 0) | env->cwp; #else - return env->version | (env->psr & PSR_ICC) | - (env->psref? PSR_EF : 0) | - (env->psrpil << 8) | - (env->psrs? PSR_S : 0) | - (env->psrps? PSR_PS : 0) | env->cwp; + return env->psr & PSR_ICC; #endif } @@ -1367,17 +1423,19 @@ target_ulong cpu_get_psr(CPUState *env1) static void put_psr(target_ulong val) { env->psr = val & PSR_ICC; +#if !defined (TARGET_SPARC64) env->psref = (val & PSR_EF)? 1 : 0; env->psrpil = (val & PSR_PIL) >> 8; +#endif #if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY)) cpu_check_irqs(env); #endif +#if !defined (TARGET_SPARC64) env->psrs = (val & PSR_S)? 1 : 0; env->psrps = (val & PSR_PS)? 1 : 0; -#if !defined (TARGET_SPARC64) env->psret = (val & PSR_ET)? 1 : 0; -#endif set_cwp(val & PSR_CWP); +#endif env->cc_op = CC_OP_FLAGS; } @@ -2266,7 +2324,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) asi &= 0xff; if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || ((env->def->features & CPU_FEATURE_HYPV) + || (cpu_has_hypervisor(env) && asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) raise_exception(TT_PRIV_ACT); @@ -2301,8 +2359,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0xe2: // UA2007 Primary block init case 0xe3: // UA2007 Secondary block init if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - if ((env->def->features & CPU_FEATURE_HYPV) - && env->hpstate & HS_PRIV) { + if (cpu_hypervisor_mode(env)) { switch(size) { case 1: ret = ldub_hypv(addr); @@ -2618,7 +2675,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) asi &= 0xff; if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || ((env->def->features & CPU_FEATURE_HYPV) + || (cpu_has_hypervisor(env) && asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) raise_exception(TT_PRIV_ACT); @@ -2662,8 +2719,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) case 0xe2: // UA2007 Primary block init case 0xe3: // UA2007 Secondary block init if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - if ((env->def->features & CPU_FEATURE_HYPV) - && env->hpstate & HS_PRIV) { + if (cpu_hypervisor_mode(env)) { switch(size) { case 1: stb_hypv(addr, val); @@ -2903,9 +2959,15 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) break; case 1: // Primary context env->dmmu.mmu_primary_context = val; + /* can be optimized to only flush MMU_USER_IDX + and MMU_KERNEL_IDX entries */ + tlb_flush(env, 1); break; case 2: // Secondary context env->dmmu.mmu_secondary_context = val; + /* can be optimized to only flush MMU_USER_SECONDARY_IDX + and MMU_KERNEL_SECONDARY_IDX entries */ + tlb_flush(env, 1); break; case 5: // TSB access DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016" @@ -2988,7 +3050,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) void helper_ldda_asi(target_ulong addr, int asi, int rd) { if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || ((env->def->features & CPU_FEATURE_HYPV) + || (cpu_has_hypervisor(env) && asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) raise_exception(TT_PRIV_ACT); diff --git a/target-sparc/translate.c b/target-sparc/translate.c index ea7c71b85a..72ca0b4dce 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -183,9 +183,9 @@ static void gen_op_store_QT0_fpr(unsigned int dst) #define hypervisor(dc) 0 #endif #else -#define supervisor(dc) (dc->mem_idx >= 1) +#define supervisor(dc) (dc->mem_idx >= MMU_KERNEL_IDX) #ifdef TARGET_SPARC64 -#define hypervisor(dc) (dc->mem_idx == 2) +#define hypervisor(dc) (dc->mem_idx == MMU_HYPV_IDX) #else #endif #endif @@ -332,24 +332,132 @@ static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2) tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_op_addxi_cc(TCGv dst, TCGv src1, target_long src2) +static TCGv_i32 gen_add32_carry32(void) { - gen_helper_compute_C_icc(cpu_tmp0); - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_movi_tl(cpu_cc_src2, src2); - tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0); - tcg_gen_addi_tl(cpu_cc_dst, cpu_cc_dst, src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); + TCGv_i32 carry_32, cc_src1_32, cc_src2_32; + + /* Carry is computed from a previous add: (dst < src) */ +#if TARGET_LONG_BITS == 64 + cc_src1_32 = tcg_temp_new_i32(); + cc_src2_32 = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(cc_src1_32, cpu_cc_dst); + tcg_gen_trunc_i64_i32(cc_src2_32, cpu_cc_src); +#else + cc_src1_32 = cpu_cc_dst; + cc_src2_32 = cpu_cc_src; +#endif + + carry_32 = tcg_temp_new_i32(); + tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32); + +#if TARGET_LONG_BITS == 64 + tcg_temp_free_i32(cc_src1_32); + tcg_temp_free_i32(cc_src2_32); +#endif + + return carry_32; } -static inline void gen_op_addx_cc(TCGv dst, TCGv src1, TCGv src2) +static TCGv_i32 gen_sub32_carry32(void) { - gen_helper_compute_C_icc(cpu_tmp0); - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0); - tcg_gen_add_tl(cpu_cc_dst, cpu_cc_dst, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); + TCGv_i32 carry_32, cc_src1_32, cc_src2_32; + + /* Carry is computed from a previous borrow: (src1 < src2) */ +#if TARGET_LONG_BITS == 64 + cc_src1_32 = tcg_temp_new_i32(); + cc_src2_32 = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(cc_src1_32, cpu_cc_src); + tcg_gen_trunc_i64_i32(cc_src2_32, cpu_cc_src2); +#else + cc_src1_32 = cpu_cc_src; + cc_src2_32 = cpu_cc_src2; +#endif + + carry_32 = tcg_temp_new_i32(); + tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32); + +#if TARGET_LONG_BITS == 64 + tcg_temp_free_i32(cc_src1_32); + tcg_temp_free_i32(cc_src2_32); +#endif + + return carry_32; +} + +static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1, + TCGv src2, int update_cc) +{ + TCGv_i32 carry_32; + TCGv carry; + + switch (dc->cc_op) { + case CC_OP_DIV: + case CC_OP_LOGIC: + /* Carry is known to be zero. Fall back to plain ADD. */ + if (update_cc) { + gen_op_add_cc(dst, src1, src2); + } else { + tcg_gen_add_tl(dst, src1, src2); + } + return; + + case CC_OP_ADD: + case CC_OP_TADD: + case CC_OP_TADDTV: +#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32 + { + /* For 32-bit hosts, we can re-use the host's hardware carry + generation by using an ADD2 opcode. We discard the low + part of the output. Ideally we'd combine this operation + with the add that generated the carry in the first place. */ + TCGv dst_low = tcg_temp_new(); + tcg_gen_op6_i32(INDEX_op_add2_i32, dst_low, dst, + cpu_cc_src, src1, cpu_cc_src2, src2); + tcg_temp_free(dst_low); + goto add_done; + } +#endif + carry_32 = gen_add32_carry32(); + break; + + case CC_OP_SUB: + case CC_OP_TSUB: + case CC_OP_TSUBTV: + carry_32 = gen_sub32_carry32(); + break; + + default: + /* We need external help to produce the carry. */ + carry_32 = tcg_temp_new_i32(); + gen_helper_compute_C_icc(carry_32); + break; + } + +#if TARGET_LONG_BITS == 64 + carry = tcg_temp_new(); + tcg_gen_extu_i32_i64(carry, carry_32); +#else + carry = carry_32; +#endif + + tcg_gen_add_tl(dst, src1, src2); + tcg_gen_add_tl(dst, dst, carry); + + tcg_temp_free_i32(carry_32); +#if TARGET_LONG_BITS == 64 + tcg_temp_free(carry); +#endif + +#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32 + add_done: +#endif + if (update_cc) { + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + tcg_gen_mov_tl(cpu_cc_dst, dst); + tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADDX); + dc->cc_op = CC_OP_ADDX; + } } static inline void gen_op_tadd_cc(TCGv dst, TCGv src1, TCGv src2) @@ -415,24 +523,80 @@ static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2) tcg_gen_mov_tl(dst, cpu_cc_dst); } -static inline void gen_op_subxi_cc(TCGv dst, TCGv src1, target_long src2) +static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, + TCGv src2, int update_cc) { - gen_helper_compute_C_icc(cpu_tmp0); - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_movi_tl(cpu_cc_src2, src2); - tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0); - tcg_gen_subi_tl(cpu_cc_dst, cpu_cc_dst, src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} + TCGv_i32 carry_32; + TCGv carry; -static inline void gen_op_subx_cc(TCGv dst, TCGv src1, TCGv src2) -{ - gen_helper_compute_C_icc(cpu_tmp0); - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0); - tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_dst, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); + switch (dc->cc_op) { + case CC_OP_DIV: + case CC_OP_LOGIC: + /* Carry is known to be zero. Fall back to plain SUB. */ + if (update_cc) { + gen_op_sub_cc(dst, src1, src2); + } else { + tcg_gen_sub_tl(dst, src1, src2); + } + return; + + case CC_OP_ADD: + case CC_OP_TADD: + case CC_OP_TADDTV: + carry_32 = gen_add32_carry32(); + break; + + case CC_OP_SUB: + case CC_OP_TSUB: + case CC_OP_TSUBTV: +#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32 + { + /* For 32-bit hosts, we can re-use the host's hardware carry + generation by using a SUB2 opcode. We discard the low + part of the output. Ideally we'd combine this operation + with the add that generated the carry in the first place. */ + TCGv dst_low = tcg_temp_new(); + tcg_gen_op6_i32(INDEX_op_sub2_i32, dst_low, dst, + cpu_cc_src, src1, cpu_cc_src2, src2); + tcg_temp_free(dst_low); + goto sub_done; + } +#endif + carry_32 = gen_sub32_carry32(); + break; + + default: + /* We need external help to produce the carry. */ + carry_32 = tcg_temp_new_i32(); + gen_helper_compute_C_icc(carry_32); + break; + } + +#if TARGET_LONG_BITS == 64 + carry = tcg_temp_new(); + tcg_gen_extu_i32_i64(carry, carry_32); +#else + carry = carry_32; +#endif + + tcg_gen_sub_tl(dst, src1, src2); + tcg_gen_sub_tl(dst, dst, carry); + + tcg_temp_free_i32(carry_32); +#if TARGET_LONG_BITS == 64 + tcg_temp_free(carry); +#endif + +#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32 + sub_done: +#endif + if (update_cc) { + tcg_gen_mov_tl(cpu_cc_src, src1); + tcg_gen_mov_tl(cpu_cc_src2, src2); + tcg_gen_mov_tl(cpu_cc_dst, dst); + tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUBX); + dc->cc_op = CC_OP_SUBX; + } } static inline void gen_op_tsub_cc(TCGv dst, TCGv src1, TCGv src2) @@ -2950,28 +3114,8 @@ static void disas_sparc_insn(DisasContext * dc) } break; case 0x8: /* addx, V9 addc */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - if (xop & 0x10) { - gen_op_addxi_cc(cpu_dst, cpu_src1, simm); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADDX); - dc->cc_op = CC_OP_ADDX; - } else { - gen_helper_compute_C_icc(cpu_tmp0); - tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, simm); - tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_tmp0); - } - } else { - if (xop & 0x10) { - gen_op_addx_cc(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADDX); - dc->cc_op = CC_OP_ADDX; - } else { - gen_helper_compute_C_icc(cpu_tmp0); - tcg_gen_add_tl(cpu_tmp0, cpu_src2, cpu_tmp0); - tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_tmp0); - } - } + gen_op_addx_int(dc, cpu_dst, cpu_src1, cpu_src2, + (xop & 0x10)); break; #ifdef TARGET_SPARC64 case 0x9: /* V9 mulx */ @@ -3002,28 +3146,8 @@ static void disas_sparc_insn(DisasContext * dc) } break; case 0xc: /* subx, V9 subc */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - if (xop & 0x10) { - gen_op_subxi_cc(cpu_dst, cpu_src1, simm); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUBX); - dc->cc_op = CC_OP_SUBX; - } else { - gen_helper_compute_C_icc(cpu_tmp0); - tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, simm); - tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_tmp0); - } - } else { - if (xop & 0x10) { - gen_op_subx_cc(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUBX); - dc->cc_op = CC_OP_SUBX; - } else { - gen_helper_compute_C_icc(cpu_tmp0); - tcg_gen_add_tl(cpu_tmp0, cpu_src2, cpu_tmp0); - tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_tmp0); - } - } + gen_op_subx_int(dc, cpu_dst, cpu_src1, cpu_src2, + (xop & 0x10)); break; #ifdef TARGET_SPARC64 case 0xd: /* V9 udivx */ @@ -3360,14 +3484,14 @@ static void disas_sparc_insn(DisasContext * dc) case 6: // pstate save_state(dc, cpu_cond); gen_helper_wrpstate(cpu_tmp0); - gen_op_next_insn(); - tcg_gen_exit_tb(0); - dc->is_br = 1; + dc->npc = DYNAMIC_PC; break; case 7: // tl + save_state(dc, cpu_cond); tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); tcg_gen_st_i32(cpu_tmp32, cpu_env, offsetof(CPUSPARCState, tl)); + dc->npc = DYNAMIC_PC; break; case 8: // pil gen_helper_wrpil(cpu_tmp0); @@ -4426,6 +4550,7 @@ static void disas_sparc_insn(DisasContext * dc) #endif save_state(dc, cpu_cond); gen_st_asi(cpu_val, cpu_addr, insn, 4); + dc->npc = DYNAMIC_PC; break; case 0x15: /* stba, store byte alternate */ #ifndef TARGET_SPARC64 @@ -4436,6 +4561,7 @@ static void disas_sparc_insn(DisasContext * dc) #endif save_state(dc, cpu_cond); gen_st_asi(cpu_val, cpu_addr, insn, 1); + dc->npc = DYNAMIC_PC; break; case 0x16: /* stha, store halfword alternate */ #ifndef TARGET_SPARC64 @@ -4446,6 +4572,7 @@ static void disas_sparc_insn(DisasContext * dc) #endif save_state(dc, cpu_cond); gen_st_asi(cpu_val, cpu_addr, insn, 2); + dc->npc = DYNAMIC_PC; break; case 0x17: /* stda, store double word alternate */ #ifndef TARGET_SPARC64 @@ -4470,6 +4597,7 @@ static void disas_sparc_insn(DisasContext * dc) case 0x1e: /* V9 stxa */ save_state(dc, cpu_cond); gen_st_asi(cpu_val, cpu_addr, insn, 8); + dc->npc = DYNAMIC_PC; break; #endif default: |