X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=target-sparc%2Fop_helper.c;h=739ed9abd223c4e798c623d3d41ae66c7427a176;hb=636aa70ade7e9b96eb9382ba3a503043e83d876b;hp=84ed6f6c4632ac07827d3e3931273949ca4ad4d2;hpb=714547bbc7db79a1d7e6544bf90c9ee1073d6881;p=mirror_qemu.git diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 84ed6f6c46..739ed9abd2 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -10,26 +10,25 @@ //#define DEBUG_UNALIGNED //#define DEBUG_UNASSIGNED //#define DEBUG_ASI +//#define DEBUG_PCALL #ifdef DEBUG_MMU -#define DPRINTF_MMU(fmt, args...) \ -do { printf("MMU: " fmt , ##args); } while (0) +#define DPRINTF_MMU(fmt, ...) \ + do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0) #else -#define DPRINTF_MMU(fmt, args...) do {} while (0) +#define DPRINTF_MMU(fmt, ...) do {} while (0) #endif #ifdef DEBUG_MXCC -#define DPRINTF_MXCC(fmt, args...) \ -do { printf("MXCC: " fmt , ##args); } while (0) +#define DPRINTF_MXCC(fmt, ...) \ + do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0) #else -#define DPRINTF_MXCC(fmt, args...) do {} while (0) +#define DPRINTF_MXCC(fmt, ...) do {} while (0) #endif #ifdef DEBUG_ASI -#define DPRINTF_ASI(fmt, args...) \ -do { printf("ASI: " fmt , ##args); } while (0) -#else -#define DPRINTF_ASI(fmt, args...) do {} while (0) +#define DPRINTF_ASI(fmt, ...) \ + do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0) #endif #ifdef TARGET_SPARC64 @@ -40,6 +39,56 @@ do { printf("ASI: " fmt , ##args); } while (0) #endif #endif +#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) +// Calculates TSB pointer value for fault page size 8k or 64k +static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register, + uint64_t tag_access_register, + int page_size) +{ + uint64_t tsb_base = tsb_register & ~0x1fffULL; + int tsb_split = (env->dmmuregs[5] & 0x1000ULL) ? 1 : 0; + int tsb_size = env->dmmuregs[5] & 0xf; + + // discard lower 13 bits which hold tag access context + uint64_t tag_access_va = tag_access_register & ~0x1fffULL; + + // now reorder bits + uint64_t tsb_base_mask = ~0x1fffULL; + uint64_t va = tag_access_va; + + // move va bits to correct position + if (page_size == 8*1024) { + va >>= 9; + } else if (page_size == 64*1024) { + va >>= 12; + } + + if (tsb_size) { + tsb_base_mask <<= tsb_size; + } + + // calculate tsb_base mask and adjust va if split is in use + if (tsb_split) { + if (page_size == 8*1024) { + va &= ~(1ULL << (13 + tsb_size)); + } else if (page_size == 64*1024) { + va |= (1ULL << (13 + tsb_size)); + } + tsb_base_mask <<= 1; + } + + return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL; +} + +// Calculates tag target register value by reordering bits +// in tag access register +static uint64_t ultrasparc_tag_target(uint64_t tag_access_register) +{ + return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22); +} + +#endif + static inline void address_mask(CPUState *env1, target_ulong *addr) { #ifdef TARGET_SPARC64 @@ -48,24 +97,15 @@ static inline void address_mask(CPUState *env1, target_ulong *addr) #endif } -void raise_exception(int tt) +static void raise_exception(int tt) { env->exception_index = tt; cpu_loop_exit(); } -void helper_trap(target_ulong nb_trap) +void HELPER(raise_exception)(int tt) { - env->exception_index = TT_TRAP + (nb_trap & 0x7f); - cpu_loop_exit(); -} - -void helper_trapcc(target_ulong nb_trap, target_ulong do_trap) -{ - if (do_trap) { - env->exception_index = TT_TRAP + (nb_trap & 0x7f); - cpu_loop_exit(); - } + raise_exception(tt); } static inline void set_cwp(int new_cwp) @@ -106,10 +146,10 @@ F_BINOP(mul); F_BINOP(div); #undef F_BINOP -void helper_fsmuld(void) +void helper_fsmuld(float32 src1, float32 src2) { - DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status), - float32_to_float64(FT1, &env->fp_status), + DT0 = float64_mul(float32_to_float64(src1, &env->fp_status), + float32_to_float64(src2, &env->fp_status), &env->fp_status); } @@ -143,20 +183,20 @@ float32 helper_fitos(int32_t src) return int32_to_float32(src, &env->fp_status); } -F_HELPER(ito, d) +void helper_fitod(int32_t src) { - DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); + DT0 = int32_to_float64(src, &env->fp_status); } -F_HELPER(ito, q) +void helper_fitoq(int32_t src) { - QT0 = int32_to_float128(*((int32_t *)&FT1), &env->fp_status); + QT0 = int32_to_float128(src, &env->fp_status); } #ifdef TARGET_SPARC64 -F_HELPER(xto, s) +float32 helper_fxtos(void) { - FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status); + return int64_to_float32(*((int64_t *)&DT1), &env->fp_status); } F_HELPER(xto, d) @@ -172,24 +212,24 @@ F_HELPER(xto, q) #undef F_HELPER /* floating point conversion */ -void helper_fdtos(void) +float32 helper_fdtos(void) { - FT0 = float64_to_float32(DT1, &env->fp_status); + return float64_to_float32(DT1, &env->fp_status); } -void helper_fstod(void) +void helper_fstod(float32 src) { - DT0 = float32_to_float64(FT1, &env->fp_status); + DT0 = float32_to_float64(src, &env->fp_status); } -void helper_fqtos(void) +float32 helper_fqtos(void) { - FT0 = float128_to_float32(QT1, &env->fp_status); + return float128_to_float32(QT1, &env->fp_status); } -void helper_fstoq(void) +void helper_fstoq(float32 src) { - QT0 = float32_to_float128(FT1, &env->fp_status); + QT0 = float32_to_float128(src, &env->fp_status); } void helper_fqtod(void) @@ -208,20 +248,20 @@ int32_t helper_fstoi(float32 src) return float32_to_int32_round_to_zero(src, &env->fp_status); } -void helper_fdtoi(void) +int32_t helper_fdtoi(void) { - *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status); + return float64_to_int32_round_to_zero(DT1, &env->fp_status); } -void helper_fqtoi(void) +int32_t helper_fqtoi(void) { - *((int32_t *)&FT0) = float128_to_int32_round_to_zero(QT1, &env->fp_status); + return float128_to_int32_round_to_zero(QT1, &env->fp_status); } #ifdef TARGET_SPARC64 -void helper_fstox(void) +void helper_fstox(float32 src) { - *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status); + *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status); } void helper_fdtox(void) @@ -246,116 +286,6 @@ void helper_faligndata(void) *((uint64_t *)&DT0) = tmp; } -void helper_movl_FT0_0(void) -{ - *((uint32_t *)&FT0) = 0; -} - -void helper_movl_DT0_0(void) -{ - *((uint64_t *)&DT0) = 0; -} - -void helper_movl_FT0_1(void) -{ - *((uint32_t *)&FT0) = 0xffffffff; -} - -void helper_movl_DT0_1(void) -{ - *((uint64_t *)&DT0) = 0xffffffffffffffffULL; -} - -void helper_fnot(void) -{ - *(uint64_t *)&DT0 = ~*(uint64_t *)&DT1; -} - -void helper_fnots(void) -{ - *(uint32_t *)&FT0 = ~*(uint32_t *)&FT1; -} - -void helper_fnor(void) -{ - *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 | *(uint64_t *)&DT1); -} - -void helper_fnors(void) -{ - *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 | *(uint32_t *)&FT1); -} - -void helper_for(void) -{ - *(uint64_t *)&DT0 |= *(uint64_t *)&DT1; -} - -void helper_fors(void) -{ - *(uint32_t *)&FT0 |= *(uint32_t *)&FT1; -} - -void helper_fxor(void) -{ - *(uint64_t *)&DT0 ^= *(uint64_t *)&DT1; -} - -void helper_fxors(void) -{ - *(uint32_t *)&FT0 ^= *(uint32_t *)&FT1; -} - -void helper_fand(void) -{ - *(uint64_t *)&DT0 &= *(uint64_t *)&DT1; -} - -void helper_fands(void) -{ - *(uint32_t *)&FT0 &= *(uint32_t *)&FT1; -} - -void helper_fornot(void) -{ - *(uint64_t *)&DT0 = *(uint64_t *)&DT0 | ~*(uint64_t *)&DT1; -} - -void helper_fornots(void) -{ - *(uint32_t *)&FT0 = *(uint32_t *)&FT0 | ~*(uint32_t *)&FT1; -} - -void helper_fandnot(void) -{ - *(uint64_t *)&DT0 = *(uint64_t *)&DT0 & ~*(uint64_t *)&DT1; -} - -void helper_fandnots(void) -{ - *(uint32_t *)&FT0 = *(uint32_t *)&FT0 & ~*(uint32_t *)&FT1; -} - -void helper_fnand(void) -{ - *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 & *(uint64_t *)&DT1); -} - -void helper_fnands(void) -{ - *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 & *(uint32_t *)&FT1); -} - -void helper_fxnor(void) -{ - *(uint64_t *)&DT0 ^= ~*(uint64_t *)&DT1; -} - -void helper_fxnors(void) -{ - *(uint32_t *)&FT0 ^= ~*(uint32_t *)&FT1; -} - #ifdef WORDS_BIGENDIAN #define VIS_B64(n) b[7 - (n)] #define VIS_W64(n) w[3 - (n)] @@ -573,10 +503,10 @@ void helper_fexpand(void) s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff); d.d = DT1; - d.VIS_L64(0) = s.VIS_W32(0) << 4; - d.VIS_L64(1) = s.VIS_W32(1) << 4; - d.VIS_L64(2) = s.VIS_W32(2) << 4; - d.VIS_L64(3) = s.VIS_W32(3) << 4; + d.VIS_W64(0) = s.VIS_B32(0) << 4; + d.VIS_W64(1) = s.VIS_B32(1) << 4; + d.VIS_W64(2) = s.VIS_B32(2) << 4; + d.VIS_W64(3) = s.VIS_B32(3) << 4; DT0 = d.d; } @@ -597,17 +527,17 @@ void helper_fexpand(void) DT0 = d.d; \ } \ \ - void name##16s(void) \ + uint32_t name##16s(uint32_t src1, uint32_t src2) \ { \ vis32 s, d; \ \ - s.f = FT0; \ - d.f = FT1; \ + s.l = src1; \ + d.l = src2; \ \ d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \ d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \ \ - FT0 = d.f; \ + return d.l; \ } \ \ void name##32(void) \ @@ -623,16 +553,16 @@ void helper_fexpand(void) DT0 = d.d; \ } \ \ - void name##32s(void) \ + uint32_t name##32s(uint32_t src1, uint32_t src2) \ { \ vis32 s, d; \ \ - s.f = FT0; \ - d.f = FT1; \ + s.l = src1; \ + d.l = src2; \ \ d.l = F(d.l, s.l); \ \ - FT0 = d.f; \ + return d.l; \ } #define FADD(a, b) ((a) + (b)) @@ -816,6 +746,441 @@ GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0); GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1); +static uint32_t compute_all_flags(void) +{ + return env->psr & PSR_ICC; +} + +static uint32_t compute_C_flags(void) +{ + return env->psr & PSR_CARRY; +} + +static inline uint32_t get_NZ_icc(target_ulong dst) +{ + uint32_t ret = 0; + + if (!(dst & 0xffffffffULL)) + ret |= PSR_ZERO; + if ((int32_t) (dst & 0xffffffffULL) < 0) + ret |= PSR_NEG; + return ret; +} + +#ifdef TARGET_SPARC64 +static uint32_t compute_all_flags_xcc(void) +{ + return env->xcc & PSR_ICC; +} + +static uint32_t compute_C_flags_xcc(void) +{ + return env->xcc & PSR_CARRY; +} + +static inline uint32_t get_NZ_xcc(target_ulong dst) +{ + uint32_t ret = 0; + + if (!dst) + ret |= PSR_ZERO; + if ((int64_t)dst < 0) + ret |= PSR_NEG; + return ret; +} +#endif + +static inline uint32_t get_V_div_icc(target_ulong src2) +{ + uint32_t ret = 0; + + if (src2 != 0) + ret |= PSR_OVF; + return ret; +} + +static uint32_t compute_all_div(void) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_V_div_icc(CC_SRC2); + return ret; +} + +static uint32_t compute_C_div(void) +{ + return 0; +} + +static inline uint32_t get_C_add_icc(target_ulong dst, target_ulong src1) +{ + uint32_t ret = 0; + + if ((dst & 0xffffffffULL) < (src1 & 0xffffffffULL)) + ret |= PSR_CARRY; + return ret; +} + +static inline uint32_t get_V_add_icc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 31)) + ret |= PSR_OVF; + return ret; +} + +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); + 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); +} + +#ifdef TARGET_SPARC64 +static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1) +{ + uint32_t ret = 0; + + if (dst < src1) + ret |= PSR_CARRY; + return ret; +} + +static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) + ret |= PSR_OVF; + return ret; +} + +static uint32_t compute_all_add_xcc(void) +{ + uint32_t ret; + + ret = get_NZ_xcc(CC_DST); + ret |= get_C_add_xcc(CC_DST, CC_SRC); + ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_add_xcc(void) +{ + return get_C_add_xcc(CC_DST, CC_SRC); +} +#endif + +static uint32_t compute_all_addx(void) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_add_icc(CC_DST - CC_SRC2, CC_SRC); + 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_addx(void) +{ + uint32_t ret; + + ret = get_C_add_icc(CC_DST - CC_SRC2, CC_SRC); + ret |= get_C_add_icc(CC_DST, CC_SRC); + return ret; +} + +#ifdef TARGET_SPARC64 +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_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +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); + return ret; +} +#endif + +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; + return ret; +} + +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); + 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); +} + +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); + return ret; +} + +static uint32_t compute_C_taddtv(void) +{ + return get_C_add_icc(CC_DST, CC_SRC); +} + +static inline uint32_t get_C_sub_icc(target_ulong src1, target_ulong src2) +{ + uint32_t ret = 0; + + if ((src1 & 0xffffffffULL) < (src2 & 0xffffffffULL)) + ret |= PSR_CARRY; + return ret; +} + +static inline uint32_t get_V_sub_icc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 31)) + ret |= PSR_OVF; + return ret; +} + +static uint32_t compute_all_sub(void) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + 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_SRC, CC_SRC2); +} + +#ifdef TARGET_SPARC64 +static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2) +{ + uint32_t ret = 0; + + if (src1 < src2) + ret |= PSR_CARRY; + return ret; +} + +static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + uint32_t ret = 0; + + if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) + ret |= PSR_OVF; + return ret; +} + +static uint32_t compute_all_sub_xcc(void) +{ + uint32_t ret; + + ret = get_NZ_xcc(CC_DST); + ret |= get_C_sub_xcc(CC_SRC, CC_SRC2); + ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_sub_xcc(void) +{ + return get_C_sub_xcc(CC_SRC, CC_SRC2); +} +#endif + +static uint32_t compute_all_subx(void) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_sub_icc(CC_DST - CC_SRC2, CC_SRC); + ret |= get_C_sub_icc(CC_DST, CC_SRC2); + ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +static uint32_t compute_C_subx(void) +{ + uint32_t ret; + + ret = get_C_sub_icc(CC_DST - CC_SRC2, CC_SRC); + ret |= get_C_sub_icc(CC_DST, CC_SRC2); + return ret; +} + +#ifdef TARGET_SPARC64 +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_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); + return ret; +} + +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); + return ret; +} +#endif + +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); + 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) +{ + return get_C_sub_icc(CC_DST, CC_SRC); +} + +static uint32_t compute_all_tsubtv(void) +{ + uint32_t ret; + + ret = get_NZ_icc(CC_DST); + ret |= get_C_sub_icc(CC_DST, CC_SRC); + return ret; +} + +static uint32_t compute_C_tsubtv(void) +{ + return get_C_sub_icc(CC_DST, CC_SRC); +} + +static uint32_t compute_all_logic(void) +{ + return get_NZ_icc(CC_DST); +} + +static uint32_t compute_C_logic(void) +{ + return 0; +} + +#ifdef TARGET_SPARC64 +static uint32_t compute_all_logic_xcc(void) +{ + return get_NZ_xcc(CC_DST); +} +#endif + +typedef struct CCTable { + uint32_t (*compute_all)(void); /* return all the flags */ + uint32_t (*compute_c)(void); /* return the C flag */ +} CCTable; + +static const CCTable icc_table[CC_OP_NB] = { + /* CC_OP_DYNAMIC should never happen */ + [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_addx, compute_C_addx }, + [CC_OP_TADD] = { compute_all_tadd, compute_C_tadd }, + [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_taddtv }, + [CC_OP_SUB] = { compute_all_sub, compute_C_sub }, + [CC_OP_SUBX] = { compute_all_subx, compute_C_subx }, + [CC_OP_TSUB] = { compute_all_tsub, compute_C_tsub }, + [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_tsubtv }, + [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic }, +}; + +#ifdef TARGET_SPARC64 +static const CCTable xcc_table[CC_OP_NB] = { + /* CC_OP_DYNAMIC should never happen */ + [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc }, + [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic }, + [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc }, + [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc }, + [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc }, + [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc }, + [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, + [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc }, + [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, + [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc }, + [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic }, +}; +#endif + +void helper_compute_psr(void) +{ + uint32_t new_psr; + + new_psr = icc_table[CC_OP].compute_all(); + env->psr = new_psr; +#ifdef TARGET_SPARC64 + new_psr = xcc_table[CC_OP].compute_all(); + env->xcc = new_psr; +#endif + CC_OP = CC_OP_FLAGS; +} + +uint32_t helper_compute_C_icc(void) +{ + uint32_t ret; + + ret = icc_table[CC_OP].compute_c() >> PSR_CARRY_SHIFT; + return ret; +} + #ifdef TARGET_SPARC64 GEN_FCMPS(fcmps_fcc1, float32, 22, 0); GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); @@ -847,11 +1212,14 @@ GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1); defined(DEBUG_MXCC) static void dump_mxcc(CPUState *env) { - printf("mxccdata: %016llx %016llx %016llx %016llx\n", + printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 + "\n", env->mxccdata[0], env->mxccdata[1], env->mxccdata[2], env->mxccdata[3]); - printf("mxccregs: %016llx %016llx %016llx %016llx\n" - " %016llx %016llx %016llx %016llx\n", + printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 + "\n" + " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 + "\n", env->mxccregs[0], env->mxccregs[1], env->mxccregs[2], env->mxccregs[3], env->mxccregs[4], env->mxccregs[5], @@ -934,7 +1302,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) break; } DPRINTF_MXCC("asi = %d, size = %d, sign = %d, " - "addr = %08x -> ret = %08x," + "addr = %08x -> ret = %" PRIx64 "," "addr = %08x\n", asi, size, sign, last_addr, ret, addr); #ifdef DEBUG_MXCC dump_mxcc(env); @@ -1071,9 +1439,32 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0x39: /* data cache diagnostic register */ ret = 0; break; + case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */ + { + int reg = (addr >> 8) & 3; + + switch(reg) { + case 0: /* Breakpoint Value (Addr) */ + ret = env->mmubpregs[reg]; + break; + case 1: /* Breakpoint Mask */ + ret = env->mmubpregs[reg]; + break; + case 2: /* Breakpoint Control */ + ret = env->mmubpregs[reg]; + break; + case 3: /* Breakpoint Status */ + ret = env->mmubpregs[reg]; + env->mmubpregs[reg] = 0ULL; + break; + } + DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg, + ret); + } + break; case 8: /* User code access, XXX */ default: - do_unassigned_access(addr, 0, 0, asi); + do_unassigned_access(addr, 0, 0, asi, size); ret = 0; break; } @@ -1171,7 +1562,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) break; case 0x01c00a04: /* MXCC control register */ if (size == 4) - env->mxccregs[3] = (env->mxccregs[0xa] & 0xffffffff00000000ULL) + env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL) | val; else DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, @@ -1197,8 +1588,8 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) size); break; } - DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %08x\n", asi, - size, addr, val); + DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n", + asi, size, addr, val); #ifdef DEBUG_MXCC dump_mxcc(env); #endif @@ -1401,13 +1792,34 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) // descriptor diagnostic case 0x36: /* I-cache flash clear */ case 0x37: /* D-cache flash clear */ - case 0x38: /* breakpoint diagnostics */ case 0x4c: /* breakpoint action */ break; + case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/ + { + int reg = (addr >> 8) & 3; + + switch(reg) { + case 0: /* Breakpoint Value (Addr) */ + env->mmubpregs[reg] = (val & 0xfffffffffULL); + break; + case 1: /* Breakpoint Mask */ + env->mmubpregs[reg] = (val & 0xfffffffffULL); + break; + case 2: /* Breakpoint Control */ + env->mmubpregs[reg] = (val & 0x7fULL); + break; + case 3: /* Breakpoint Status */ + env->mmubpregs[reg] = (val & 0xfULL); + break; + } + DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg, + env->mmuregs[reg]); + } + break; case 8: /* User code access, XXX */ case 9: /* Supervisor code access, XXX */ default: - do_unassigned_access(addr, 1, 0, asi); + do_unassigned_access(addr, 1, 0, asi, size); break; } #ifdef DEBUG_ASI @@ -1541,13 +1953,13 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) case 0x89: // Secondary LE switch(size) { case 2: - addr = bswap16(addr); + val = bswap16(val); break; case 4: - addr = bswap32(addr); + val = bswap32(val); break; case 8: - addr = bswap64(addr); + val = bswap64(val); break; default: break; @@ -1587,7 +1999,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) case 0x8a: // Primary no-fault LE, RO case 0x8b: // Secondary no-fault LE, RO default: - do_unassigned_access(addr, 1, 0, 1); + do_unassigned_access(addr, 1, 0, 1, size); return; } } @@ -1622,6 +2034,8 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0x18: // As if user primary LE case 0x80: // Primary case 0x88: // Primary LE + 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) { @@ -1727,13 +2141,31 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) { int reg = (addr >> 3) & 0xf; - ret = env->immuregs[reg]; + if (reg == 0) { + // I-TSB Tag Target register + ret = ultrasparc_tag_target(env->immuregs[6]); + } else { + ret = env->immuregs[reg]; + } + break; } case 0x51: // I-MMU 8k TSB pointer + { + // env->immuregs[5] holds I-MMU TSB register value + // env->immuregs[6] holds I-MMU Tag Access register value + ret = ultrasparc_tsb_pointer(env->immuregs[5], env->immuregs[6], + 8*1024); + break; + } case 0x52: // I-MMU 64k TSB pointer - // XXX - break; + { + // env->immuregs[5] holds I-MMU TSB register value + // env->immuregs[6] holds I-MMU Tag Access register value + ret = ultrasparc_tsb_pointer(env->immuregs[5], env->immuregs[6], + 64*1024); + break; + } case 0x55: // I-MMU data access { int reg = (addr >> 3) & 0x3f; @@ -1752,7 +2184,28 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) { int reg = (addr >> 3) & 0xf; - ret = env->dmmuregs[reg]; + if (reg == 0) { + // D-TSB Tag Target register + ret = ultrasparc_tag_target(env->dmmuregs[6]); + } else { + ret = env->dmmuregs[reg]; + } + break; + } + case 0x59: // D-MMU 8k TSB pointer + { + // env->dmmuregs[5] holds D-MMU TSB register value + // env->dmmuregs[6] holds D-MMU Tag Access register value + ret = ultrasparc_tsb_pointer(env->dmmuregs[5], env->dmmuregs[6], + 8*1024); + break; + } + case 0x5a: // D-MMU 64k TSB pointer + { + // env->dmmuregs[5] holds D-MMU TSB register value + // env->dmmuregs[6] holds D-MMU Tag Access register value + ret = ultrasparc_tsb_pointer(env->dmmuregs[5], env->dmmuregs[6], + 64*1024); break; } case 0x5d: // D-MMU data access @@ -1782,8 +2235,6 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0x76: // E-cache tag case 0x7e: // E-cache tag break; - case 0x59: // D-MMU 8k TSB pointer - case 0x5a: // D-MMU 64k TSB pointer case 0x5b: // D-MMU data pointer case 0x48: // Interrupt dispatch, RO case 0x49: // Interrupt data receive @@ -1796,7 +2247,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0x5f: // D-MMU demap, WO case 0x77: // Interrupt vector, WO default: - do_unassigned_access(addr, 0, 0, 1); + do_unassigned_access(addr, 0, 0, 1, size); ret = 0; break; } @@ -1874,13 +2325,13 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) case 0x89: // Secondary LE switch(size) { case 2: - addr = bswap16(addr); + val = bswap16(val); break; case 4: - addr = bswap32(addr); + val = bswap32(val); break; case 8: - addr = bswap64(addr); + val = bswap64(val); break; default: break; @@ -1894,6 +2345,8 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) case 0x18: // As if user primary LE case 0x80: // Primary case 0x88: // Primary LE + 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) { @@ -2060,6 +2513,8 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) } case 0x55: // I-MMU data access { + // TODO: auto demap + unsigned int i = (addr >> 3) & 0x3f; env->itlb_tag[i] = env->immuregs[6]; @@ -2067,7 +2522,22 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) return; } case 0x57: // I-MMU demap - // XXX + { + unsigned int i; + + for (i = 0; i < 64; i++) { + if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { + target_ulong mask = 0xffffffffffffe000ULL; + + mask <<= 3 * ((env->itlb_tte[i] >> 61) & 3); + if ((val & mask) == (env->itlb_tag[i] & mask)) { + env->itlb_tag[i] = 0; + env->itlb_tte[i] = 0; + } + return; + } + } + } return; case 0x58: // D-MMU regs { @@ -2137,6 +2607,23 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) return; } case 0x5f: // D-MMU demap + { + unsigned int i; + + for (i = 0; i < 64; i++) { + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { + target_ulong mask = 0xffffffffffffe000ULL; + + mask <<= 3 * ((env->dtlb_tte[i] >> 61) & 3); + if ((val & mask) == (env->dtlb_tag[i] & mask)) { + env->dtlb_tag[i] = 0; + env->dtlb_tte[i] = 0; + } + return; + } + } + } + return; case 0x49: // Interrupt data receive // XXX return; @@ -2167,7 +2654,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) case 0x8a: // Primary no-fault LE, RO case 0x8b: // Secondary no-fault LE, RO default: - do_unassigned_access(addr, 1, 0, 1); + do_unassigned_access(addr, 1, 0, 1, size); return; } } @@ -2269,6 +2756,8 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd) helper_check_align(addr, 3); switch (asi) { + case 0xe0: // UA2007 Block commit store primary (cache flush) + case 0xe1: // UA2007 Block commit store secondary (cache flush) case 0xf0: // Block store primary case 0xf1: // Block store secondary case 0xf8: // Block store primary LE @@ -2309,11 +2798,11 @@ target_ulong helper_cas_asi(target_ulong addr, target_ulong val1, { target_ulong ret; - val1 &= 0xffffffffUL; + val2 &= 0xffffffffUL; ret = helper_ld_asi(addr, asi, 4, 0); ret &= 0xffffffffUL; - if (val1 == ret) - helper_st_asi(addr, val2 & 0xffffffffUL, asi, 4); + if (val2 == ret) + helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4); return ret; } @@ -2323,8 +2812,8 @@ target_ulong helper_casx_asi(target_ulong addr, target_ulong val1, target_ulong ret; ret = helper_ld_asi(addr, asi, 8, 0); - if (val1 == ret) - helper_st_asi(addr, val2, asi, 8); + if (val2 == ret) + helper_st_asi(addr, val1, asi, 8); return ret; } #endif /* TARGET_SPARC64 */ @@ -2391,11 +2880,6 @@ target_ulong helper_sdiv(target_ulong a, target_ulong b) } } -uint64_t helper_pack64(target_ulong high, target_ulong low) -{ - return ((uint64_t)high << 32) | (uint64_t)(low & 0xffffffff); -} - void helper_stdf(target_ulong addr, int mem_idx) { helper_check_align(addr, 7); @@ -2745,8 +3229,14 @@ static inline void change_pstate(uint64_t new_pstate) uint64_t pstate_regs, new_pstate_regs; uint64_t *src, *dst; + if (env->def->features & CPU_FEATURE_GL) { + // PS_AG is not implemented in this case + new_pstate &= ~PS_AG; + } + 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); @@ -2759,8 +3249,7 @@ static inline void change_pstate(uint64_t new_pstate) void helper_wrpstate(target_ulong new_state) { - if (!(env->def->features & CPU_FEATURE_GL)) - change_pstate(new_state & 0xf3f); + change_pstate(new_state & 0xf3f); } void helper_done(void) @@ -2786,6 +3275,21 @@ void helper_retry(void) env->tl--; env->tsptr = &env->ts[env->tl & MAXTL_MASK]; } + +void helper_set_softint(uint64_t value) +{ + env->softint |= (uint32_t)value; +} + +void helper_clear_softint(uint64_t value) +{ + env->softint &= (uint32_t)~value; +} + +void helper_write_softint(uint64_t value) +{ + env->softint = (uint32_t)value; +} #endif void helper_flush(target_ulong addr) @@ -2836,7 +3340,7 @@ void do_interrupt(CPUState *env) int intno = env->exception_index; #ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_INT) { + if (qemu_loglevel_mask(CPU_LOG_INT)) { static int count; const char *name; @@ -2854,23 +3358,23 @@ void do_interrupt(CPUState *env) name = "Unknown"; } - fprintf(logfile, "%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64 + qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n", count, name, intno, env->pc, env->npc, env->regwptr[6]); - cpu_dump_state(env, logfile, fprintf, 0); + log_cpu_state(env, 0); #if 0 { int i; uint8_t *ptr; - fprintf(logfile, " code="); + qemu_log(" code="); ptr = (uint8_t *)env->pc; for(i = 0; i < 16; i++) { - fprintf(logfile, " %02x", ldub(ptr + i)); + qemu_log(" %02x", ldub(ptr + i)); } - fprintf(logfile, "\n"); + qemu_log("\n"); } #endif count++; @@ -2897,23 +3401,23 @@ void do_interrupt(CPUState *env) env->tsptr->tpc = env->pc; env->tsptr->tnpc = env->npc; env->tsptr->tt = intno; - if (!(env->def->features & CPU_FEATURE_GL)) { - switch (intno) { - case TT_IVEC: - change_pstate(PS_PEF | PS_PRIV | PS_IG); - break; - case TT_TFAULT: - case TT_TMISS: - case TT_DFAULT: - case TT_DMISS: - case TT_DPROT: - change_pstate(PS_PEF | PS_PRIV | PS_MG); - break; - default: - change_pstate(PS_PEF | PS_PRIV | PS_AG); - break; - } + + switch (intno) { + case TT_IVEC: + change_pstate(PS_PEF | PS_PRIV | PS_IG); + break; + case TT_TFAULT: + case TT_TMISS: + case TT_DFAULT: + case TT_DMISS: + case TT_DPROT: + change_pstate(PS_PEF | PS_PRIV | PS_MG); + break; + default: + change_pstate(PS_PEF | PS_PRIV | PS_AG); + break; } + if (intno == TT_CLRWIN) cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1)); else if ((intno & 0x1c0) == TT_SPILL) @@ -2967,7 +3471,7 @@ void do_interrupt(CPUState *env) int cwp, intno = env->exception_index; #ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_INT) { + if (qemu_loglevel_mask(CPU_LOG_INT)) { static int count; const char *name; @@ -2981,22 +3485,22 @@ void do_interrupt(CPUState *env) name = "Unknown"; } - fprintf(logfile, "%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n", + qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n", count, name, intno, env->pc, env->npc, env->regwptr[6]); - cpu_dump_state(env, logfile, fprintf, 0); + log_cpu_state(env, 0); #if 0 { int i; uint8_t *ptr; - fprintf(logfile, " code="); + qemu_log(" code="); ptr = (uint8_t *)env->pc; for(i = 0; i < 16; i++) { - fprintf(logfile, " %02x", ldub(ptr + i)); + qemu_log(" %02x", ldub(ptr + i)); } - fprintf(logfile, "\n"); + qemu_log("\n"); } #endif count++; @@ -3098,7 +3602,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) #ifndef TARGET_SPARC64 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int is_asi) + int is_asi, int size) { CPUState *saved_env; @@ -3108,14 +3612,15 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, env = cpu_single_env; #ifdef DEBUG_UNASSIGNED if (is_asi) - printf("Unassigned mem %s access to " TARGET_FMT_plx + printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx " asi 0x%02x from " TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", addr, is_asi, - env->pc); + is_exec ? "exec" : is_write ? "write" : "read", size, + size == 1 ? "" : "s", addr, is_asi, env->pc); else - printf("Unassigned mem %s access to " TARGET_FMT_plx " from " - TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", addr, env->pc); + printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx + " from " TARGET_FMT_lx "\n", + is_exec ? "exec" : is_write ? "write" : "read", size, + size == 1 ? "" : "s", addr, env->pc); #endif if (env->mmuregs[3]) /* Fault status register */ env->mmuregs[3] = 1; /* overflow (not read before another fault) */ @@ -3139,7 +3644,7 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, } #else void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int is_asi) + int is_asi, int size) { #ifdef DEBUG_UNASSIGNED CPUState *saved_env; @@ -3159,3 +3664,27 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, } #endif +#ifdef TARGET_SPARC64 +void helper_tick_set_count(void *opaque, uint64_t count) +{ +#if !defined(CONFIG_USER_ONLY) + cpu_tick_set_count(opaque, count); +#endif +} + +uint64_t helper_tick_get_count(void *opaque) +{ +#if !defined(CONFIG_USER_ONLY) + return cpu_tick_get_count(opaque); +#else + return 0; +#endif +} + +void helper_tick_set_limit(void *opaque, uint64_t limit) +{ +#if !defined(CONFIG_USER_ONLY) + cpu_tick_set_limit(opaque, limit); +#endif +} +#endif