#include "exec.h"
#include "host-utils.h"
#include "helper.h"
-#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif /* !defined(CONFIG_USER_ONLY) */
//#define DEBUG_MMU
//#define DEBUG_MXCC
#endif
#endif
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
#if defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
int is_asi, int size);
{
unsigned int i;
target_ulong mask;
+ uint64_t context;
+
+ int is_demap_context = (demap_addr >> 6) & 1;
+
+ // demap context
+ switch ((demap_addr >> 4) & 3) {
+ case 0: // primary
+ context = env1->dmmu.mmu_primary_context;
+ break;
+ case 1: // secondary
+ context = env1->dmmu.mmu_secondary_context;
+ break;
+ case 2: // nucleus
+ context = 0;
+ break;
+ case 3: // reserved
+ default:
+ return;
+ }
for (i = 0; i < 64; i++) {
if (TTE_IS_VALID(tlb[i].tte)) {
- mask = 0xffffffffffffe000ULL;
- mask <<= 3 * ((tlb[i].tte >> 61) & 3);
+ if (is_demap_context) {
+ // will remove non-global entries matching context value
+ if (TTE_IS_GLOBAL(tlb[i].tte) ||
+ !tlb_compare_context(&tlb[i], context)) {
+ continue;
+ }
+ } else {
+ // demap page
+ // will remove any entry matching VA
+ mask = 0xffffffffffffe000ULL;
+ mask <<= 3 * ((tlb[i].tte >> 61) & 3);
+
+ if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
+ continue;
+ }
+
+ // entry should be global or matching context value
+ if (!TTE_IS_GLOBAL(tlb[i].tte) &&
+ !tlb_compare_context(&tlb[i], context)) {
+ continue;
+ }
+ }
- if ((demap_addr & mask) == (tlb[i].tag & mask)) {
- replace_tlb_entry(&tlb[i], 0, 0, env1);
+ replace_tlb_entry(&tlb[i], 0, 0, env1);
#ifdef DEBUG_MMU
- DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
- dump_mmu(env1);
+ DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
+ dump_mmu(env1);
#endif
- }
- //return;
}
}
-
}
static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
#endif
-static inline void address_mask(CPUState *env1, target_ulong *addr)
+static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
{
#ifdef TARGET_SPARC64
if (AM_CHECK(env1))
- *addr &= 0xffffffffULL;
+ addr &= 0xffffffffULL;
#endif
+ return addr;
}
static void raise_exception(int tt)
raise_exception(tt);
}
-static inline void set_cwp(int new_cwp)
-{
- cpu_set_cwp(env, new_cwp);
-}
-
void helper_check_align(target_ulong addr, uint32_t align)
{
if (addr & align) {
return env->psr & PSR_CARRY;
}
-static inline uint32_t get_NZ_icc(target_ulong dst)
+static inline uint32_t get_NZ_icc(int32_t dst)
{
uint32_t ret = 0;
- if (!(dst & 0xffffffffULL))
- ret |= PSR_ZERO;
- if ((int32_t) (dst & 0xffffffffULL) < 0)
- ret |= PSR_NEG;
+ if (dst == 0) {
+ ret = PSR_ZERO;
+ } else if (dst < 0) {
+ ret = PSR_NEG;
+ }
return ret;
}
return env->xcc & PSR_CARRY;
}
-static inline uint32_t get_NZ_xcc(target_ulong dst)
+static inline uint32_t get_NZ_xcc(target_long dst)
{
uint32_t ret = 0;
- if (!dst)
- ret |= PSR_ZERO;
- if ((int64_t)dst < 0)
- ret |= PSR_NEG;
+ if (!dst) {
+ ret = PSR_ZERO;
+ } else if (dst < 0) {
+ ret = PSR_NEG;
+ }
return ret;
}
#endif
{
uint32_t ret = 0;
- if (src2 != 0)
- ret |= PSR_OVF;
+ if (src2 != 0) {
+ ret = PSR_OVF;
+ }
return ret;
}
return 0;
}
-/* carry = (src1[31] & src2[31]) | ( ~dst[31] & (src1[31] | src2[31])) */
-static inline uint32_t get_C_add_icc(target_ulong dst, target_ulong src1,
- target_ulong src2)
+static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
{
uint32_t ret = 0;
- if (((src1 & (1ULL << 31)) & (src2 & (1ULL << 31)))
- | ((~(dst & (1ULL << 31)))
- & ((src1 & (1ULL << 31)) | (src2 & (1ULL << 31)))))
- ret |= PSR_CARRY;
+ if (dst < src1) {
+ ret = PSR_CARRY;
+ }
return ret;
}
-static inline uint32_t get_V_add_icc(target_ulong dst, target_ulong src1,
- target_ulong src2)
+static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
{
uint32_t ret = 0;
- if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 31))
- ret |= PSR_OVF;
+ if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
+ ret = PSR_OVF;
+ }
return ret;
}
{
uint32_t ret = 0;
- if (dst < src1)
- ret |= PSR_CARRY;
+ if (dst < src1) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
+ ret = PSR_CARRY;
+ }
return ret;
}
{
uint32_t ret = 0;
- if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63))
- ret |= PSR_OVF;
+ if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
+ ret = PSR_OVF;
+ }
return ret;
}
uint32_t ret;
ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
+ 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, CC_SRC2);
+ return get_C_add_icc(CC_DST, CC_SRC);
}
#ifdef TARGET_SPARC64
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_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
{
uint32_t ret;
- ret = get_C_add_xcc(CC_DST - CC_SRC2, CC_SRC);
- ret |= get_C_add_xcc(CC_DST, CC_SRC);
+ ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
#endif
+static uint32_t compute_all_addx(void)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+ 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_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
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;
+ if ((src1 | src2) & 0x3) {
+ ret = PSR_OVF;
+ }
return ret;
}
uint32_t ret;
ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
+ 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, CC_SRC2);
-}
-
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, CC_SRC2);
+ ret |= get_C_add_icc(CC_DST, CC_SRC);
return ret;
}
-static uint32_t compute_C_taddtv(void)
+static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
{
- return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
+ uint32_t ret = 0;
+
+ if (src1 < src2) {
+ ret = PSR_CARRY;
+ }
+ return ret;
}
-/* carry = (~src1[31] & src2[31]) | ( dst[31] & (~src1[31] | src2[31])) */
-static inline uint32_t get_C_sub_icc(target_ulong dst, target_ulong src1,
- target_ulong src2)
+static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
{
uint32_t ret = 0;
- if (((~(src1 & (1ULL << 31))) & (src2 & (1ULL << 31)))
- | ((dst & (1ULL << 31)) & (( ~(src1 & (1ULL << 31)))
- | (src2 & (1ULL << 31)))))
- ret |= PSR_CARRY;
+ if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
+ ret = PSR_CARRY;
+ }
return ret;
}
-static inline uint32_t get_V_sub_icc(target_ulong dst, target_ulong src1,
- target_ulong src2)
+static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
{
uint32_t ret = 0;
- if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 31))
- ret |= PSR_OVF;
+ if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
+ ret = PSR_OVF;
+ }
return ret;
}
{
uint32_t ret = 0;
- if (src1 < src2)
- ret |= PSR_CARRY;
+ if (src1 < src2) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
+ ret = PSR_CARRY;
+ }
return ret;
}
{
uint32_t ret = 0;
- if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63))
- ret |= PSR_OVF;
+ if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
+ ret = PSR_OVF;
+ }
return ret;
}
uint32_t ret;
ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ 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_DST, CC_SRC, CC_SRC2);
+ return get_C_sub_icc(CC_SRC, CC_SRC2);
}
#ifdef TARGET_SPARC64
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_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
{
uint32_t ret;
- ret = get_C_sub_xcc(CC_DST - CC_SRC2, CC_SRC);
- ret |= get_C_sub_xcc(CC_DST, CC_SRC2);
+ ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
#endif
-static uint32_t compute_all_tsub(void)
+static uint32_t compute_all_subx(void)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
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)
+static uint32_t compute_C_subx(void)
{
- return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ uint32_t ret;
+
+ ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
}
-static uint32_t compute_all_tsubtv(void)
+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, CC_SRC2);
+ ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+ 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_tsubtv(void)
+static uint32_t compute_all_tsubtv(void)
{
- return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+ return ret;
}
static uint32_t compute_all_logic(void)
[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_add, compute_C_add },
- [CC_OP_TADD] = { compute_all_tadd, compute_C_tadd },
- [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_taddtv },
+ [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
+ [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
+ [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
[CC_OP_SUB] = { compute_all_sub, compute_C_sub },
- [CC_OP_SUBX] = { compute_all_sub, compute_C_sub },
- [CC_OP_TSUB] = { compute_all_tsub, compute_C_tsub },
- [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_tsubtv },
+ [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
+ [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
+ [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
[CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
};
return ret;
}
+static inline void memcpy32(target_ulong *dst, const target_ulong *src)
+{
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+}
+
+static void set_cwp(int new_cwp)
+{
+ /* put the modified wrap registers at their proper location */
+ if (env->cwp == env->nwindows - 1) {
+ memcpy32(env->regbase, env->regbase + env->nwindows * 16);
+ }
+ env->cwp = new_cwp;
+
+ /* put the wrap registers at their temporary location */
+ if (new_cwp == env->nwindows - 1) {
+ memcpy32(env->regbase + env->nwindows * 16, env->regbase);
+ }
+ env->regwptr = env->regbase + (new_cwp * 16);
+}
+
+void cpu_set_cwp(CPUState *env1, int new_cwp)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ set_cwp(new_cwp);
+ env = saved_env;
+}
+
+static target_ulong get_psr(void)
+{
+ helper_compute_psr();
+
+#if !defined (TARGET_SPARC64)
+ return env->version | (env->psr & PSR_ICC) |
+ (env->psref? PSR_EF : 0) |
+ (env->psrpil << 8) |
+ (env->psrs? PSR_S : 0) |
+ (env->psrps? PSR_PS : 0) |
+ (env->psret? PSR_ET : 0) | env->cwp;
+#else
+ return env->psr & PSR_ICC;
+#endif
+}
+
+target_ulong cpu_get_psr(CPUState *env1)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = get_psr();
+ env = saved_env;
+ return ret;
+}
+
+static void put_psr(target_ulong val)
+{
+ env->psr = val & PSR_ICC;
+#if !defined (TARGET_SPARC64)
+ env->psref = (val & PSR_EF)? 1 : 0;
+ env->psrpil = (val & PSR_PIL) >> 8;
+#endif
+#if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
+ cpu_check_irqs(env);
+#endif
+#if !defined (TARGET_SPARC64)
+ env->psrs = (val & PSR_S)? 1 : 0;
+ env->psrps = (val & PSR_PS)? 1 : 0;
+ env->psret = (val & PSR_ET)? 1 : 0;
+ set_cwp(val & PSR_CWP);
+#endif
+ env->cc_op = CC_OP_FLAGS;
+}
+
+void cpu_put_psr(CPUState *env1, target_ulong val)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ put_psr(val);
+ env = saved_env;
+}
+
+static int cwp_inc(int cwp)
+{
+ if (unlikely(cwp >= env->nwindows)) {
+ cwp -= env->nwindows;
+ }
+ return cwp;
+}
+
+int cpu_cwp_inc(CPUState *env1, int cwp)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = cwp_inc(cwp);
+ env = saved_env;
+ return ret;
+}
+
+static int cwp_dec(int cwp)
+{
+ if (unlikely(cwp < 0)) {
+ cwp += env->nwindows;
+ }
+ return cwp;
+}
+
+int cpu_cwp_dec(CPUState *env1, int cwp)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = cwp_dec(cwp);
+ env = saved_env;
+ return ret;
+}
+
#ifdef TARGET_SPARC64
GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
raise_exception(TT_PRIV_ACT);
helper_check_align(addr, size - 1);
- address_mask(env, &addr);
+ addr = address_mask(env, addr);
switch (asi) {
case 0x82: // Primary no-fault
raise_exception(TT_PRIV_ACT);
helper_check_align(addr, size - 1);
- address_mask(env, &addr);
+ addr = address_mask(env, addr);
/* Convert to little endian */
switch (asi) {
asi &= 0xff;
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- || ((env->def->features & CPU_FEATURE_HYPV)
+ || (cpu_has_hypervisor(env)
&& asi >= 0x30 && asi < 0x80
&& !(env->hpstate & HS_PRIV)))
raise_exception(TT_PRIV_ACT);
switch (asi) {
case 0x82: // Primary no-fault
case 0x8a: // Primary no-fault LE
- if (cpu_get_phys_page_debug(env, addr) == -1ULL) {
+ case 0x83: // Secondary no-fault
+ case 0x8b: // Secondary no-fault LE
+ {
+ /* secondary space access has lowest asi bit equal to 1 */
+ int access_mmu_idx = ( asi & 1 ) ? MMU_KERNEL_IDX
+ : MMU_KERNEL_SECONDARY_IDX;
+
+ if (cpu_get_phys_page_nofault(env, addr, access_mmu_idx) == -1ULL) {
#ifdef DEBUG_ASI
- dump_asi("read ", last_addr, asi, size, ret);
+ dump_asi("read ", last_addr, asi, size, ret);
#endif
- return 0;
+ return 0;
+ }
}
// Fall through
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 0x80: // Primary
+ case 0x81: // Secondary
case 0x88: // Primary LE
+ case 0x89: // Secondary 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) {
+ if (cpu_hypervisor_mode(env)) {
switch(size) {
case 1:
ret = ldub_hypv(addr);
break;
}
} else {
+ /* secondary space access has lowest asi bit equal to 1 */
+ if (asi & 1) {
+ switch(size) {
+ case 1:
+ ret = ldub_kernel_secondary(addr);
+ break;
+ case 2:
+ ret = lduw_kernel_secondary(addr);
+ break;
+ case 4:
+ ret = ldl_kernel_secondary(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_kernel_secondary(addr);
+ break;
+ }
+ } else {
+ switch(size) {
+ case 1:
+ ret = ldub_kernel(addr);
+ break;
+ case 2:
+ ret = lduw_kernel(addr);
+ break;
+ case 4:
+ ret = ldl_kernel(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_kernel(addr);
+ break;
+ }
+ }
+ }
+ } else {
+ /* secondary space access has lowest asi bit equal to 1 */
+ if (asi & 1) {
switch(size) {
case 1:
- ret = ldub_kernel(addr);
+ ret = ldub_user_secondary(addr);
break;
case 2:
- ret = lduw_kernel(addr);
+ ret = lduw_user_secondary(addr);
break;
case 4:
- ret = ldl_kernel(addr);
+ ret = ldl_user_secondary(addr);
break;
default:
case 8:
- ret = ldq_kernel(addr);
+ ret = ldq_user_secondary(addr);
+ break;
+ }
+ } else {
+ switch(size) {
+ case 1:
+ ret = ldub_user(addr);
+ break;
+ case 2:
+ ret = lduw_user(addr);
+ break;
+ case 4:
+ ret = ldl_user(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_user(addr);
break;
}
- }
- } else {
- switch(size) {
- case 1:
- ret = ldub_user(addr);
- break;
- case 2:
- ret = lduw_user(addr);
- break;
- case 4:
- ret = ldl_user(addr);
- break;
- default:
- case 8:
- ret = ldq_user(addr);
- break;
}
}
break;
// Only ldda allowed
raise_exception(TT_ILL_INSN);
return 0;
- case 0x83: // Secondary no-fault
- case 0x8b: // Secondary no-fault LE
- if (cpu_get_phys_page_debug(env, addr) == -1ULL) {
-#ifdef DEBUG_ASI
- dump_asi("read ", last_addr, asi, size, ret);
-#endif
- return 0;
- }
- // Fall through
case 0x04: // Nucleus
case 0x0c: // Nucleus Little Endian (LE)
- case 0x11: // As if user secondary
- case 0x19: // As if user secondary LE
+ {
+ switch(size) {
+ case 1:
+ ret = ldub_nucleus(addr);
+ break;
+ case 2:
+ ret = lduw_nucleus(addr);
+ break;
+ case 4:
+ ret = ldl_nucleus(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_nucleus(addr);
+ break;
+ }
+ break;
+ }
case 0x4a: // UPA config
- case 0x81: // Secondary
- case 0x89: // Secondary LE
// XXX
break;
case 0x45: // LSU
asi &= 0xff;
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- || ((env->def->features & CPU_FEATURE_HYPV)
+ || (cpu_has_hypervisor(env)
&& asi >= 0x30 && asi < 0x80
&& !(env->hpstate & HS_PRIV)))
raise_exception(TT_PRIV_ACT);
switch(asi) {
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 0x80: // Primary
+ case 0x81: // Secondary
case 0x88: // Primary LE
+ case 0x89: // Secondary 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) {
+ if (cpu_hypervisor_mode(env)) {
switch(size) {
case 1:
stb_hypv(addr, val);
break;
}
} else {
+ /* secondary space access has lowest asi bit equal to 1 */
+ if (asi & 1) {
+ switch(size) {
+ case 1:
+ stb_kernel_secondary(addr, val);
+ break;
+ case 2:
+ stw_kernel_secondary(addr, val);
+ break;
+ case 4:
+ stl_kernel_secondary(addr, val);
+ break;
+ case 8:
+ default:
+ stq_kernel_secondary(addr, val);
+ break;
+ }
+ } else {
+ switch(size) {
+ case 1:
+ stb_kernel(addr, val);
+ break;
+ case 2:
+ stw_kernel(addr, val);
+ break;
+ case 4:
+ stl_kernel(addr, val);
+ break;
+ case 8:
+ default:
+ stq_kernel(addr, val);
+ break;
+ }
+ }
+ }
+ } else {
+ /* secondary space access has lowest asi bit equal to 1 */
+ if (asi & 1) {
switch(size) {
case 1:
- stb_kernel(addr, val);
+ stb_user_secondary(addr, val);
break;
case 2:
- stw_kernel(addr, val);
+ stw_user_secondary(addr, val);
break;
case 4:
- stl_kernel(addr, val);
+ stl_user_secondary(addr, val);
break;
case 8:
default:
- stq_kernel(addr, val);
+ stq_user_secondary(addr, val);
+ break;
+ }
+ } else {
+ switch(size) {
+ case 1:
+ stb_user(addr, val);
+ break;
+ case 2:
+ stw_user(addr, val);
+ break;
+ case 4:
+ stl_user(addr, val);
+ break;
+ case 8:
+ default:
+ stq_user(addr, val);
break;
}
- }
- } else {
- switch(size) {
- case 1:
- stb_user(addr, val);
- break;
- case 2:
- stw_user(addr, val);
- break;
- case 4:
- stl_user(addr, val);
- break;
- case 8:
- default:
- stq_user(addr, val);
- break;
}
}
break;
return;
case 0x04: // Nucleus
case 0x0c: // Nucleus Little Endian (LE)
- case 0x11: // As if user secondary
- case 0x19: // As if user secondary LE
+ {
+ switch(size) {
+ case 1:
+ stb_nucleus(addr, val);
+ break;
+ case 2:
+ stw_nucleus(addr, val);
+ break;
+ case 4:
+ stl_nucleus(addr, val);
+ break;
+ default:
+ case 8:
+ stq_nucleus(addr, val);
+ break;
+ }
+ break;
+ }
+
case 0x4a: // UPA config
- case 0x81: // Secondary
- case 0x89: // Secondary LE
// XXX
return;
case 0x45: // LSU
return;
}
case 0x57: // I-MMU demap
- demap_tlb(env->itlb, val, "immu", env);
+ demap_tlb(env->itlb, addr, "immu", env);
return;
case 0x58: // D-MMU regs
{
break;
case 1: // Primary context
env->dmmu.mmu_primary_context = val;
+ /* can be optimized to only flush MMU_USER_IDX
+ and MMU_KERNEL_IDX entries */
+ tlb_flush(env, 1);
break;
case 2: // Secondary context
env->dmmu.mmu_secondary_context = val;
+ /* can be optimized to only flush MMU_USER_SECONDARY_IDX
+ and MMU_KERNEL_SECONDARY_IDX entries */
+ tlb_flush(env, 1);
break;
case 5: // TSB access
DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
return;
}
case 0x5f: // D-MMU demap
- demap_tlb(env->dtlb, val, "dmmu", env);
+ demap_tlb(env->dtlb, addr, "dmmu", env);
return;
case 0x49: // Interrupt data receive
// XXX
void helper_ldda_asi(target_ulong addr, int asi, int rd)
{
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- || ((env->def->features & CPU_FEATURE_HYPV)
+ || (cpu_has_hypervisor(env)
&& asi >= 0x30 && asi < 0x80
&& !(env->hpstate & HS_PRIV)))
raise_exception(TT_PRIV_ACT);
case 0x2c: // Nucleus quad LDD 128 bit atomic LE
helper_check_align(addr, 0xf);
if (rd == 0) {
- env->gregs[1] = ldq_kernel(addr + 8);
+ env->gregs[1] = ldq_nucleus(addr + 8);
if (asi == 0x2c)
bswap64s(&env->gregs[1]);
} else if (rd < 8) {
- env->gregs[rd] = ldq_kernel(addr);
- env->gregs[rd + 1] = ldq_kernel(addr + 8);
+ env->gregs[rd] = ldq_nucleus(addr);
+ env->gregs[rd + 1] = ldq_nucleus(addr + 8);
if (asi == 0x2c) {
bswap64s(&env->gregs[rd]);
bswap64s(&env->gregs[rd + 1]);
}
} else {
- env->regwptr[rd] = ldq_kernel(addr);
- env->regwptr[rd + 1] = ldq_kernel(addr + 8);
+ env->regwptr[rd] = ldq_nucleus(addr);
+ env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
if (asi == 0x2c) {
bswap64s(&env->regwptr[rd]);
bswap64s(&env->regwptr[rd + 1]);
raise_exception(TT_ILL_INSN);
env->psret = 1;
- cwp = cpu_cwp_inc(env, env->cwp + 1) ;
+ cwp = cwp_inc(env->cwp + 1) ;
if (env->wim & (1 << cwp)) {
raise_exception(TT_WIN_UNF);
}
break;
}
#else
- address_mask(env, &addr);
- stfq_raw(addr, DT0);
+ stfq_raw(address_mask(env, addr), DT0);
#endif
}
break;
}
#else
- address_mask(env, &addr);
- DT0 = ldfq_raw(addr);
+ DT0 = ldfq_raw(address_mask(env, addr));
#endif
}
break;
}
#else
- address_mask(env, &addr);
- u.ll.upper = ldq_raw(addr);
- u.ll.lower = ldq_raw((addr + 8) & 0xffffffffULL);
+ u.ll.upper = ldq_raw(address_mask(env, addr));
+ u.ll.lower = ldq_raw(address_mask(env, addr + 8));
QT0 = u.q;
#endif
}
}
#else
u.q = QT0;
- address_mask(env, &addr);
- stq_raw(addr, u.ll.upper);
- stq_raw((addr + 8) & 0xffffffffULL, u.ll.lower);
+ stq_raw(address_mask(env, addr), u.ll.upper);
+ stq_raw(address_mask(env, addr + 8), u.ll.lower);
#endif
}
{
uint32_t cwp;
- cwp = cpu_cwp_dec(env, env->cwp - 1);
+ cwp = cwp_dec(env->cwp - 1);
if (env->wim & (1 << cwp)) {
raise_exception(TT_WIN_OVF);
}
{
uint32_t cwp;
- cwp = cpu_cwp_inc(env, env->cwp + 1);
+ cwp = cwp_inc(env->cwp + 1);
if (env->wim & (1 << cwp)) {
raise_exception(TT_WIN_UNF);
}
void helper_wrpsr(target_ulong new_psr)
{
- if ((new_psr & PSR_CWP) >= env->nwindows)
+ if ((new_psr & PSR_CWP) >= env->nwindows) {
raise_exception(TT_ILL_INSN);
- else
- PUT_PSR(env, new_psr);
+ } else {
+ cpu_put_psr(env, new_psr);
+ }
}
target_ulong helper_rdpsr(void)
{
- return GET_PSR(env);
+ return get_psr();
}
#else
{
uint32_t cwp;
- cwp = cpu_cwp_dec(env, env->cwp - 1);
+ cwp = cwp_dec(env->cwp - 1);
if (env->cansave == 0) {
raise_exception(TT_SPILL | (env->otherwin != 0 ?
(TT_WOTHER | ((env->wstate & 0x38) >> 1)):
{
uint32_t cwp;
- cwp = cpu_cwp_inc(env, env->cwp + 1);
+ cwp = cwp_inc(env->cwp + 1);
if (env->canrestore == 0) {
raise_exception(TT_FILL | (env->otherwin != 0 ?
(TT_WOTHER | ((env->wstate & 0x38) >> 1)):
env->otherwin--;
}
+static target_ulong get_ccr(void)
+{
+ target_ulong psr;
+
+ psr = get_psr();
+
+ return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
+}
+
+target_ulong cpu_get_ccr(CPUState *env1)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = get_ccr();
+ env = saved_env;
+ return ret;
+}
+
+static void put_ccr(target_ulong val)
+{
+ target_ulong tmp = val;
+
+ env->xcc = (tmp >> 4) << 20;
+ env->psr = (tmp & 0xf) << 20;
+ CC_OP = CC_OP_FLAGS;
+}
+
+void cpu_put_ccr(CPUState *env1, target_ulong val)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ put_ccr(val);
+ env = saved_env;
+}
+
+static target_ulong get_cwp64(void)
+{
+ return env->nwindows - 1 - env->cwp;
+}
+
+target_ulong cpu_get_cwp64(CPUState *env1)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = get_cwp64();
+ env = saved_env;
+ return ret;
+}
+
+static void put_cwp64(int cwp)
+{
+ if (unlikely(cwp >= env->nwindows || cwp < 0)) {
+ cwp %= env->nwindows;
+ }
+ set_cwp(env->nwindows - 1 - cwp);
+}
+
+void cpu_put_cwp64(CPUState *env1, int cwp)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ put_cwp64(cwp);
+ env = saved_env;
+}
+
target_ulong helper_rdccr(void)
{
- return GET_CCR(env);
+ return get_ccr();
}
void helper_wrccr(target_ulong new_ccr)
{
- PUT_CCR(env, new_ccr);
+ put_ccr(new_ccr);
}
// CWP handling is reversed in V9, but we still use the V8 register
// order.
target_ulong helper_rdcwp(void)
{
- return GET_CWP64(env);
+ return get_cwp64();
}
void helper_wrcwp(target_ulong new_cwp)
{
- PUT_CWP64(env, new_cwp);
+ put_cwp64(new_cwp);
}
// This function uses non-native bit order
env->pc = tsptr->tnpc;
env->npc = tsptr->tnpc + 4;
- PUT_CCR(env, tsptr->tstate >> 32);
+ put_ccr(tsptr->tstate >> 32);
env->asi = (tsptr->tstate >> 24) & 0xff;
change_pstate((tsptr->tstate >> 8) & 0xf3f);
- PUT_CWP64(env, tsptr->tstate & 0xff);
+ put_cwp64(tsptr->tstate & 0xff);
env->tl--;
DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
env->pc = tsptr->tpc;
env->npc = tsptr->tnpc;
- PUT_CCR(env, tsptr->tstate >> 32);
+ put_ccr(tsptr->tstate >> 32);
env->asi = (tsptr->tstate >> 24) & 0xff;
change_pstate((tsptr->tstate >> 8) & 0xf3f);
- PUT_CWP64(env, tsptr->tstate & 0xff);
+ put_cwp64(tsptr->tstate & 0xff);
env->tl--;
DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
}
tsptr = cpu_tsptr(env);
- tsptr->tstate = ((uint64_t)GET_CCR(env) << 32) |
+ tsptr->tstate = (get_ccr() << 32) |
((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
- GET_CWP64(env);
+ get_cwp64();
tsptr->tpc = env->pc;
tsptr->tnpc = env->npc;
tsptr->tt = intno;
break;
}
- if (intno == TT_CLRWIN)
- cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
- else if ((intno & 0x1c0) == TT_SPILL)
- cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
- else if ((intno & 0x1c0) == TT_FILL)
- cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
+ if (intno == TT_CLRWIN) {
+ set_cwp(cwp_dec(env->cwp - 1));
+ } else if ((intno & 0x1c0) == TT_SPILL) {
+ set_cwp(cwp_dec(env->cwp - env->cansave - 2));
+ } else if ((intno & 0x1c0) == TT_FILL) {
+ set_cwp(cwp_inc(env->cwp + 1));
+ }
env->tbr &= ~0x7fffULL;
env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
env->pc = env->tbr;
}
#endif
env->psret = 0;
- cwp = cpu_cwp_dec(env, env->cwp - 1);
- cpu_set_cwp(env, cwp);
+ cwp = cwp_dec(env->cwp - 1);
+ set_cwp(cwp);
env->regwptr[9] = env->pc;
env->regwptr[10] = env->npc;
env->psrps = env->psrs;