diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 0305a0498f..35f4b5fd19 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -50,7 +50,7 @@ void cpu_unlock(void); void cpu_loop_exit(void); void helper_flush(target_ulong addr); void helper_ld_asi(int asi, int size, int sign); -void helper_st_asi(int asi, int size, int sign); +void helper_st_asi(int asi, int size); void helper_rett(void); void helper_ldfsr(void); void set_cwp(int new_cwp); diff --git a/target-sparc/op.c b/target-sparc/op.c index f2168af9ab..bb084ee0db 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1862,10 +1862,126 @@ void OPPROTO op_ld_asi_reg() void OPPROTO op_st_asi_reg() { T0 += PARAM1; - helper_st_asi(env->asi, PARAM2, PARAM3); + helper_st_asi(env->asi, PARAM2); +} + +void OPPROTO op_ldstub_asi_reg() /* XXX: should be atomically */ +{ + target_ulong tmp; + + T0 += PARAM1; + helper_ld_asi(env->asi, 1, 0); + tmp = T1; + T1 = 0xff; + helper_st_asi(env->asi, 1); + T1 = tmp; +} + +void OPPROTO op_swap_asi_reg() /* XXX: should be atomically */ +{ + target_ulong tmp1, tmp2; + + T0 += PARAM1; + tmp1 = T1; + helper_ld_asi(env->asi, 4, 0); + tmp2 = T1; + T1 = tmp1; + helper_st_asi(env->asi, 4); + T1 = tmp2; +} + +void OPPROTO op_ldda_asi() +{ + helper_ld_asi(PARAM1, 8, 0); + T0 = T1 & 0xffffffffUL; + T1 >>= 32; +} + +void OPPROTO op_ldda_asi_reg() +{ + T0 += PARAM1; + helper_ld_asi(env->asi, 8, 0); + T0 = T1 & 0xffffffffUL; + T1 >>= 32; +} + +void OPPROTO op_stda_asi() +{ + T1 <<= 32; + T1 += T2 & 0xffffffffUL; + helper_st_asi(PARAM1, 8); +} + +void OPPROTO op_stda_asi_reg() +{ + T0 += PARAM1; + T1 <<= 32; + T1 += T2 & 0xffffffffUL; + helper_st_asi(env->asi, 8); +} + +void OPPROTO op_cas_asi() /* XXX: should be atomically */ +{ + target_ulong tmp; + + tmp = T1 & 0xffffffffUL; + helper_ld_asi(PARAM1, 4, 0); + if (tmp == T1) { + tmp = T1; + T1 = T2 & 0xffffffffUL; + helper_st_asi(PARAM1, 4); + T1 = tmp; + } + T1 &= 0xffffffffUL; +} + +void OPPROTO op_cas_asi_reg() /* XXX: should be atomically */ +{ + target_ulong tmp; + + T0 += PARAM1; + tmp = T1 & 0xffffffffUL; + helper_ld_asi(env->asi, 4, 0); + if (tmp == T1) { + tmp = T1; + T1 = T2 & 0xffffffffUL; + helper_st_asi(env->asi, 4); + T1 = tmp; + } + T1 &= 0xffffffffUL; +} + +void OPPROTO op_casx_asi() /* XXX: should be atomically */ +{ + target_ulong tmp; + + tmp = T1; + helper_ld_asi(PARAM1, 8, 0); + if (tmp == T1) { + tmp = T1; + T1 = T2; + helper_st_asi(PARAM1, 8); + T1 = tmp; + } +} + +void OPPROTO op_casx_asi_reg() /* XXX: should be atomically */ +{ + target_ulong tmp; + + T0 += PARAM1; + tmp = T1; + helper_ld_asi(env->asi, 8, 0); + if (tmp == T1) { + tmp = T1; + T1 = T2; + helper_st_asi(env->asi, 8); + T1 = tmp; + } } #endif +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) void OPPROTO op_ld_asi() { helper_ld_asi(PARAM1, PARAM2, PARAM3); @@ -1873,9 +1989,33 @@ void OPPROTO op_ld_asi() void OPPROTO op_st_asi() { - helper_st_asi(PARAM1, PARAM2, PARAM3); + helper_st_asi(PARAM1, PARAM2); } +void OPPROTO op_ldstub_asi() /* XXX: should be atomically */ +{ + target_ulong tmp; + + helper_ld_asi(PARAM1, 1, 0); + tmp = T1; + T1 = 0xff; + helper_st_asi(PARAM1, 1); + T1 = tmp; +} + +void OPPROTO op_swap_asi() /* XXX: should be atomically */ +{ + target_ulong tmp1, tmp2; + + tmp1 = T1; + helper_ld_asi(PARAM1, 4, 0); + tmp2 = T1; + T1 = tmp1; + helper_st_asi(PARAM1, 4); + T1 = tmp2; +} +#endif + #ifdef TARGET_SPARC64 // This function uses non-native bit order #define GET_FIELD(X, FROM, TO) \ diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 98c4a1ba42..c168252d1d 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -137,16 +137,8 @@ GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); #endif -#if defined(CONFIG_USER_ONLY) -void helper_ld_asi(int asi, int size, int sign) -{ -} - -void helper_st_asi(int asi, int size, int sign) -{ -} -#else #ifndef TARGET_SPARC64 +#ifndef CONFIG_USER_ONLY void helper_ld_asi(int asi, int size, int sign) { uint32_t ret = 0; @@ -200,6 +192,42 @@ void helper_ld_asi(int asi, int size, int sign) break; } break; + case 0xa: /* User data access */ + switch(size) { + case 1: + ret = ldub_user(T0); + break; + case 2: + ret = lduw_user(T0 & ~1); + break; + default: + case 4: + ret = ldl_user(T0 & ~3); + break; + case 8: + ret = ldl_user(T0 & ~3); + T0 = ldl_user((T0 + 4) & ~3); + break; + } + break; + case 0xb: /* Supervisor data access */ + switch(size) { + case 1: + ret = ldub_kernel(T0); + break; + case 2: + ret = lduw_kernel(T0 & ~1); + break; + default: + case 4: + ret = ldl_kernel(T0 & ~3); + break; + case 8: + ret = ldl_kernel(T0 & ~3); + T0 = ldl_kernel((T0 + 4) & ~3); + break; + } + break; case 0xc: /* I-cache tag */ case 0xd: /* I-cache data */ case 0xe: /* D-cache tag */ @@ -253,10 +281,22 @@ void helper_ld_asi(int asi, int size, int sign) ret = 0; break; } - T1 = ret; + if (sign) { + switch(size) { + case 1: + T1 = (int8_t) ret; + case 2: + T1 = (int16_t) ret; + default: + T1 = ret; + break; + } + } + else + T1 = ret; } -void helper_st_asi(int asi, int size, int sign) +void helper_st_asi(int asi, int size) { switch(asi) { case 2: /* SuperSparc MXCC registers */ @@ -325,6 +365,42 @@ void helper_st_asi(int asi, int size, int sign) #endif return; } + case 0xa: /* User data access */ + switch(size) { + case 1: + stb_user(T0, T1); + break; + case 2: + stw_user(T0 & ~1, T1); + break; + default: + case 4: + stl_user(T0 & ~3, T1); + break; + case 8: + stl_user(T0 & ~3, T1); + stl_user((T0 + 4) & ~3, T2); + break; + } + break; + case 0xb: /* Supervisor data access */ + switch(size) { + case 1: + stb_kernel(T0, T1); + break; + case 2: + stw_kernel(T0 & ~1, T1); + break; + default: + case 4: + stl_kernel(T0 & ~3, T1); + break; + case 8: + stl_kernel(T0 & ~3, T1); + stl_kernel((T0 + 4) & ~3, T2); + break; + } + break; case 0xc: /* I-cache tag */ case 0xd: /* I-cache data */ case 0xe: /* D-cache tag */ @@ -422,7 +498,146 @@ void helper_st_asi(int asi, int size, int sign) } } -#else +#endif /* CONFIG_USER_ONLY */ +#else /* TARGET_SPARC64 */ + +#ifdef CONFIG_USER_ONLY +void helper_ld_asi(int asi, int size, int sign) +{ + uint64_t ret = 0; + + if (asi < 0x80) + raise_exception(TT_PRIV_ACT); + + switch (asi) { + case 0x80: // Primary + case 0x82: // Primary no-fault + case 0x88: // Primary LE + case 0x8a: // Primary no-fault LE + { + switch(size) { + case 1: + ret = ldub_raw(T0); + break; + case 2: + ret = lduw_raw(T0 & ~1); + break; + case 4: + ret = ldl_raw(T0 & ~3); + break; + default: + case 8: + ret = ldq_raw(T0 & ~7); + break; + } + } + break; + case 0x81: // Secondary + case 0x83: // Secondary no-fault + case 0x89: // Secondary LE + case 0x8b: // Secondary no-fault LE + // XXX + break; + default: + break; + } + + /* Convert from little endian */ + switch (asi) { + case 0x88: // Primary LE + case 0x89: // Secondary LE + case 0x8a: // Primary no-fault LE + case 0x8b: // Secondary no-fault LE + switch(size) { + case 2: + ret = bswap16(ret); + case 4: + ret = bswap32(ret); + case 8: + ret = bswap64(ret); + default: + break; + } + default: + break; + } + + /* Convert to signed number */ + if (sign) { + switch(size) { + case 1: + ret = (int8_t) ret; + case 2: + ret = (int16_t) ret; + case 4: + ret = (int32_t) ret; + default: + break; + } + } + T1 = ret; +} + +void helper_st_asi(int asi, int size) +{ + if (asi < 0x80) + raise_exception(TT_PRIV_ACT); + + /* Convert to little endian */ + switch (asi) { + case 0x88: // Primary LE + case 0x89: // Secondary LE + switch(size) { + case 2: + T0 = bswap16(T0); + case 4: + T0 = bswap32(T0); + case 8: + T0 = bswap64(T0); + default: + break; + } + default: + break; + } + + switch(asi) { + case 0x80: // Primary + case 0x88: // Primary LE + { + switch(size) { + case 1: + stb_raw(T0, T1); + break; + case 2: + stw_raw(T0 & ~1, T1); + break; + case 4: + stl_raw(T0 & ~3, T1); + break; + case 8: + default: + stq_raw(T0 & ~7, T1); + break; + } + } + break; + case 0x81: // Secondary + case 0x89: // Secondary LE + // XXX + return; + + 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: + do_unassigned_access(T0, 1, 0, 1); + return; + } +} + +#else /* CONFIG_USER_ONLY */ void helper_ld_asi(int asi, int size, int sign) { @@ -432,8 +647,50 @@ void helper_ld_asi(int asi, int size, int sign) raise_exception(TT_PRIV_ACT); switch (asi) { + case 0x10: // As if user primary + case 0x18: // As if user primary LE + case 0x80: // Primary + case 0x82: // Primary no-fault + case 0x88: // Primary LE + case 0x8a: // Primary no-fault LE + if ((asi & 0x80) && (env->pstate & PS_PRIV)) { + switch(size) { + case 1: + ret = ldub_kernel(T0); + break; + case 2: + ret = lduw_kernel(T0 & ~1); + break; + case 4: + ret = ldl_kernel(T0 & ~3); + break; + default: + case 8: + ret = ldq_kernel(T0 & ~7); + break; + } + } else { + switch(size) { + case 1: + ret = ldub_user(T0); + break; + case 2: + ret = lduw_user(T0 & ~1); + break; + case 4: + ret = ldl_user(T0 & ~3); + break; + default: + case 8: + ret = ldq_user(T0 & ~7); + break; + } + } + break; case 0x14: // Bypass case 0x15: // Bypass, non-cacheable + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE { switch(size) { case 1: @@ -454,20 +711,14 @@ void helper_ld_asi(int asi, int size, int sign) } 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 0x81: // Secondary 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; @@ -540,17 +791,120 @@ void helper_ld_asi(int asi, int size, int sign) ret = 0; break; } + + /* Convert from little endian */ + switch (asi) { + case 0x0c: // Nucleus Little Endian (LE) + 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 0x88: // Primary LE + case 0x89: // Secondary LE + case 0x8a: // Primary no-fault LE + case 0x8b: // Secondary no-fault LE + switch(size) { + case 2: + ret = bswap16(ret); + case 4: + ret = bswap32(ret); + case 8: + ret = bswap64(ret); + default: + break; + } + default: + break; + } + + /* Convert to signed number */ + if (sign) { + switch(size) { + case 1: + ret = (int8_t) ret; + case 2: + ret = (int16_t) ret; + case 4: + ret = (int32_t) ret; + default: + break; + } + } T1 = ret; } -void helper_st_asi(int asi, int size, int sign) +void helper_st_asi(int asi, int size) { if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) raise_exception(TT_PRIV_ACT); + /* Convert to little endian */ + switch (asi) { + case 0x0c: // Nucleus Little Endian (LE) + 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 0x81: // Secondary + case 0x88: // Primary LE + case 0x89: // Secondary LE + switch(size) { + case 2: + T0 = bswap16(T0); + case 4: + T0 = bswap32(T0); + case 8: + T0 = bswap64(T0); + default: + break; + } + default: + break; + } + switch(asi) { + case 0x10: // As if user primary + case 0x18: // As if user primary LE + case 0x80: // Primary + case 0x88: // Primary LE + if ((asi & 0x80) && (env->pstate & PS_PRIV)) { + switch(size) { + case 1: + stb_kernel(T0, T1); + break; + case 2: + stw_kernel(T0 & ~1, T1); + break; + case 4: + stl_kernel(T0 & ~3, T1); + break; + case 8: + default: + stq_kernel(T0 & ~7, T1); + break; + } + } else { + switch(size) { + case 1: + stb_user(T0, T1); + break; + case 2: + stw_user(T0 & ~1, T1); + break; + case 4: + stl_user(T0 & ~3, T1); + break; + case 8: + default: + stq_user(T0 & ~7, T1); + break; + } + } + break; case 0x14: // Bypass case 0x15: // Bypass, non-cacheable + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE { switch(size) { case 1: @@ -571,16 +925,11 @@ void helper_st_asi(int asi, int size, int sign) 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; @@ -756,8 +1105,8 @@ void helper_st_asi(int asi, int size, int sign) return; } } -#endif -#endif /* !CONFIG_USER_ONLY */ +#endif /* CONFIG_USER_ONLY */ +#endif /* TARGET_SPARC64 */ #ifndef TARGET_SPARC64 void helper_rett() diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index ae63181c75..c0cf043b31 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -76,33 +76,6 @@ void OPPROTO glue(op_lddf, MEMSUFFIX) (void) } #ifdef TARGET_SPARC64 -/* XXX: Should be Atomically */ -/* XXX: There are no cas[x] instructions, only cas[x]a */ -void OPPROTO glue(op_cas, MEMSUFFIX)(void) -{ - uint32_t tmp; - - tmp = glue(ldl, MEMSUFFIX)(T0); - T2 &= 0xffffffffULL; - if (tmp == (T1 & 0xffffffffULL)) { - glue(stl, MEMSUFFIX)(T0, T2); - } - T2 = tmp; -} - -void OPPROTO glue(op_casx, MEMSUFFIX)(void) -{ - uint64_t tmp; - - // XXX - tmp = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32; - tmp |= glue(ldl, MEMSUFFIX)(T0); - if (tmp == T1) { - glue(stq, MEMSUFFIX)(T0, T2); - } - T2 = tmp; -} - void OPPROTO glue(op_lduw, MEMSUFFIX)(void) { T1 = (uint64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff); diff --git a/target-sparc/translate.c b/target-sparc/translate.c index a52d6717a3..d617b91e99 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -353,112 +353,27 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); #endif #endif -#ifdef TARGET_SPARC64 -// 'a' versions allowed to user depending on asi -#if defined(CONFIG_USER_ONLY) +/* moves */ +#ifdef CONFIG_USER_ONLY #define supervisor(dc) 0 +#ifdef TARGET_SPARC64 #define hypervisor(dc) 0 +#endif #define gen_op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) \ - static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ - { \ - int asi, offset; \ - \ - if (IS_IMM) { \ - offset = GET_FIELD(insn, 25, 31); \ - if (is_ld) \ - gen_op_ld_asi_reg(offset, size, sign); \ - else \ - gen_op_st_asi_reg(offset, size, sign); \ - return; \ - } \ - asi = GET_FIELD(insn, 19, 26); \ - switch (asi) { \ - case 0x80: /* Primary address space */ \ - gen_op_##width##_raw(); \ - break; \ - case 0x82: /* Primary address space, non-faulting load */ \ - gen_op_##width##_raw(); \ - break; \ - default: \ - break; \ - } \ - } - #else +#define supervisor(dc) (dc->mem_idx == 1) +#ifdef TARGET_SPARC64 +#define hypervisor(dc) (dc->mem_idx == 2) +#endif #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() #define OP_LD_TABLE(width) \ static GenOpFunc * const gen_op_##width[] = { \ &gen_op_##width##_user, \ &gen_op_##width##_kernel, \ - }; \ - \ - static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ - { \ - int asi, offset; \ - \ - if (IS_IMM) { \ - offset = GET_FIELD(insn, 25, 31); \ - if (is_ld) \ - gen_op_ld_asi_reg(offset, size, sign); \ - else \ - gen_op_st_asi_reg(offset, size, sign); \ - return; \ - } \ - asi = GET_FIELD(insn, 19, 26); \ - if (is_ld) \ - gen_op_ld_asi(asi, size, sign); \ - else \ - gen_op_st_asi(asi, size, sign); \ - } - -#define supervisor(dc) (dc->mem_idx == 1) -#define hypervisor(dc) (dc->mem_idx == 2) -#endif -#else -#if defined(CONFIG_USER_ONLY) -#define gen_op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) -#define supervisor(dc) 0 -#else -#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() -#define OP_LD_TABLE(width) \ -static GenOpFunc * const gen_op_##width[] = { \ - &gen_op_##width##_user, \ - &gen_op_##width##_kernel, \ -}; \ - \ -static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ -{ \ - int asi; \ - \ - asi = GET_FIELD(insn, 19, 26); \ - switch (asi) { \ - case 10: /* User data access */ \ - gen_op_##width##_user(); \ - break; \ - case 11: /* Supervisor data access */ \ - gen_op_##width##_kernel(); \ - break; \ - case 0x20 ... 0x2f: /* MMU passthrough */ \ - if (is_ld) \ - gen_op_ld_asi(asi, size, sign); \ - else \ - gen_op_st_asi(asi, size, sign); \ - break; \ - default: \ - if (is_ld) \ - gen_op_ld_asi(asi, size, sign); \ - else \ - gen_op_st_asi(asi, size, sign); \ - break; \ - } \ -} - -#define supervisor(dc) (dc->mem_idx == 1) -#endif + }; #endif +#ifndef CONFIG_USER_ONLY OP_LD_TABLE(ld); OP_LD_TABLE(st); OP_LD_TABLE(ldub); @@ -481,8 +396,164 @@ OP_LD_TABLE(lduw); OP_LD_TABLE(ldsw); OP_LD_TABLE(ldx); OP_LD_TABLE(stx); -OP_LD_TABLE(cas); -OP_LD_TABLE(casx); +#endif +#endif + +/* asi moves */ +#ifdef TARGET_SPARC64 +static inline void gen_ld_asi(int insn, int size, int sign) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_ld_asi_reg(offset, size, sign); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_ld_asi(asi, size, sign); + } +} + +static inline void gen_st_asi(int insn, int size) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_st_asi_reg(offset, size); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_st_asi(asi, size); + } +} + +static inline void gen_swap_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_swap_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_swap_asi(asi); + } +} + +static inline void gen_ldstub_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_ldstub_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_ldstub_asi(asi); + } +} + +static inline void gen_ldda_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_ldda_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_ldda_asi(asi); + } +} + +static inline void gen_stda_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_stda_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_stda_asi(asi); + } +} + +static inline void gen_cas_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_cas_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_cas_asi(asi); + } +} + +static inline void gen_casx_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_casx_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_casx_asi(asi); + } +} + +#elif !defined(CONFIG_USER_ONLY) + +static inline void gen_ld_asi(int insn, int size, int sign) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_ld_asi(asi, size, sign); +} + +static inline void gen_st_asi(int insn, int size) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_st_asi(asi, size); +} + +static inline void gen_ldstub_asi(int insn) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_ldstub_asi(asi); +} + +static inline void gen_swap_asi(int insn) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_swap_asi(asi); +} + +static inline void gen_ldda_asi(int insn) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_ld_asi(asi, 8, 0); +} + +static inline void gen_stda_asi(int insn) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_st_asi(asi, 8); +} #endif static inline void gen_movl_imm_TN(int reg, uint32_t imm) @@ -2796,7 +2867,12 @@ static void disas_sparc_insn(DisasContext * dc) rs1 = GET_FIELD(insn, 13, 17); save_state(dc); gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ + if (xop == 0x3c || xop == 0x3e) + { + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + else if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); #if defined(OPTIM) if (rs2 != 0) { @@ -2873,16 +2949,10 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#ifdef CONFIG_USER_ONLY +#elif CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_lda(insn, 1, 4, 0); -#else -#ifdef CONFIG_USER_ONLY - gen_op_check_align_T0_3(); -#endif - gen_op_lduwa(insn, 1, 4, 0); -#endif + gen_ld_asi(insn, 4, 0); break; case 0x11: /* load unsigned byte alternate */ #ifndef TARGET_SPARC64 @@ -2891,7 +2961,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif - gen_op_lduba(insn, 1, 1, 0); + gen_ld_asi(insn, 1, 0); break; case 0x12: /* load unsigned halfword alternate */ #ifndef TARGET_SPARC64 @@ -2899,11 +2969,10 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#endif -#ifdef CONFIG_USER_ONLY +#elif CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_lduha(insn, 1, 2, 0); + gen_ld_asi(insn, 2, 0); break; case 0x13: /* load double word alternate */ #ifndef TARGET_SPARC64 @@ -2915,7 +2984,7 @@ static void disas_sparc_insn(DisasContext * dc) if (rd & 1) goto illegal_insn; gen_op_check_align_T0_7(); - gen_op_ldda(insn, 1, 8, 0); + gen_ldda_asi(insn); gen_movl_T0_reg(rd + 1); break; case 0x19: /* load signed byte alternate */ @@ -2925,7 +2994,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif - gen_op_ldsba(insn, 1, 1, 1); + gen_ld_asi(insn, 1, 1); break; case 0x1a: /* load signed halfword alternate */ #ifndef TARGET_SPARC64 @@ -2933,11 +3002,10 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#endif -#ifdef CONFIG_USER_ONLY +#elif CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_ldsha(insn, 1, 2 ,1); + gen_ld_asi(insn, 2, 1); break; case 0x1d: /* ldstuba -- XXX: should be atomically */ #ifndef TARGET_SPARC64 @@ -2946,7 +3014,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif - gen_op_ldstuba(insn, 1, 1, 0); + gen_ldstub_asi(insn); break; case 0x1f: /* swap reg with alt. memory. Also atomically */ #ifndef TARGET_SPARC64 @@ -2954,12 +3022,11 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#endif - gen_movl_reg_T1(rd); -#ifdef CONFIG_USER_ONLY +#elif CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_swapa(insn, 1, 4, 0); + gen_movl_reg_T1(rd); + gen_swap_asi(insn); break; #ifndef TARGET_SPARC64 @@ -2967,17 +3034,6 @@ static void disas_sparc_insn(DisasContext * dc) case 0x31: /* ldcsr */ case 0x33: /* lddc */ goto ncp_insn; - /* avoid warnings */ - (void) &gen_op_stfa; - (void) &gen_op_stdfa; - (void) &gen_op_ldfa; - (void) &gen_op_lddfa; -#else - (void) &gen_op_lda; -#if !defined(CONFIG_USER_ONLY) - (void) &gen_op_cas; - (void) &gen_op_casx; -#endif #endif #endif #ifdef TARGET_SPARC64 @@ -2995,11 +3051,11 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldswa(insn, 1, 4, 1); + gen_ld_asi(insn, 4, 1); break; case 0x1b: /* V9 ldxa */ gen_op_check_align_T0_7(); - gen_op_ldxa(insn, 1, 8, 0); + gen_ld_asi(insn, 8, 0); break; case 0x2d: /* V9 prefetch, no effect */ goto skip_move; @@ -3007,13 +3063,12 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldfa(insn, 1, 8, 0); // XXX - break; + gen_ld_asi(insn, 8, 0); // XXX + goto skip_move; case 0x33: /* V9 lddfa */ gen_op_check_align_T0_7(); - gen_op_lddfa(insn, 1, 8, 0); // XXX - - break; + gen_ld_asi(insn, 8, 0); // XXX + goto skip_move; case 0x3d: /* V9 prefetcha, no effect */ goto skip_move; case 0x32: /* V9 ldqfa */ @@ -3092,7 +3147,7 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_sta(insn, 0, 4, 0); + gen_st_asi(insn, 4); break; case 0x15: #ifndef TARGET_SPARC64 @@ -3101,7 +3156,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif - gen_op_stba(insn, 0, 1, 0); + gen_st_asi(insn, 1); break; case 0x16: #ifndef TARGET_SPARC64 @@ -3113,7 +3168,7 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_stha(insn, 0, 2, 0); + gen_st_asi(insn, 2); break; case 0x17: #ifndef TARGET_SPARC64 @@ -3127,7 +3182,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_check_align_T0_7(); flush_T2(dc); gen_movl_reg_T2(rd + 1); - gen_op_stda(insn, 0, 8, 0); + gen_stda_asi(insn); break; #endif #ifdef TARGET_SPARC64 @@ -3137,7 +3192,7 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x1e: /* V9 stxa */ gen_op_check_align_T0_7(); - gen_op_stxa(insn, 0, 8, 0); // XXX + gen_st_asi(insn, 8); break; #endif default: @@ -3184,21 +3239,27 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_stfa(insn, 0, 0, 0); // XXX + gen_st_asi(insn, 0); // XXX break; case 0x37: /* V9 stdfa */ gen_op_check_align_T0_7(); - gen_op_stdfa(insn, 0, 0, 0); // XXX + gen_st_asi(insn, 0); // XXX break; case 0x3c: /* V9 casa */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_casa(insn, 0, 4, 0); // XXX + flush_T2(dc); + gen_movl_reg_T2(rd); + gen_cas_asi(insn); + gen_movl_T1_reg(rd); break; case 0x3e: /* V9 casxa */ gen_op_check_align_T0_7(); - gen_op_casxa(insn, 0, 8, 0); // XXX + flush_T2(dc); + gen_movl_reg_T2(rd); + gen_casx_asi(insn); + gen_movl_T1_reg(rd); break; case 0x36: /* V9 stqfa */ goto nfpu_insn;