Rework ASI instructions (Aurelien Jarno)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3205 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
43febf4952
commit
81ad8ba242
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user