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:
blueswir1
2007-09-21 19:10:53 +00:00
parent 43febf4952
commit 81ad8ba242
5 changed files with 727 additions and 204 deletions
+1 -1
View File
@@ -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);
+142 -2
View File
@@ -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) \
+376 -27
View File
@@ -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()
-27
View File
@@ -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);
+208 -147
View File
File diff suppressed because it is too large Load Diff