diff options
author | blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-09-21 19:10:53 +0000 |
---|---|---|
committer | blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-09-21 19:10:53 +0000 |
commit | 81ad8ba242815e27f990e18778c7cdca2e7e7522 (patch) | |
tree | 40a4c750eb33901b9eee8fc53459ae0e88c32a66 /target-sparc/op_helper.c | |
parent | 43febf49523552ca678eacc2677d3bac58cda4c0 (diff) |
Rework ASI instructions (Aurelien Jarno)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3205 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-sparc/op_helper.c')
-rw-r--r-- | target-sparc/op_helper.c | 403 |
1 files changed, 376 insertions, 27 deletions
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() |