diff options
author | Doug Kwan <dougkwan@google.com> | 2014-05-29 09:12:20 -0500 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2014-06-16 13:24:40 +0200 |
commit | e22c357b3ec01c1141969ae81397d60d52e8c87b (patch) | |
tree | ea4aa04bb90ebfb07fdb0e1d5ad1344871eb3651 /target-ppc/mem_helper.c | |
parent | d90b94cd78af672cdfd52dc3789ab249534c2f40 (diff) |
target-ppc: Allow little-endian user mode.
This allows running PPC64 little-endian in user mode if target is configured
that way. In PPC64 LE user mode we set MSR.LE during initialization.
Signed-off-by: Doug Kwan <dougkwan@google.com>
Signed-off-by: Tom Musta <tommusta@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc/mem_helper.c')
-rw-r--r-- | target-ppc/mem_helper.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index 02b627e47b..50344b81cf 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -25,6 +25,15 @@ //#define DEBUG_OP +static inline bool needs_byteswap(const CPUPPCState *env) +{ +#if defined(TARGET_WORDS_BIGENDIAN) + return msr_le; +#else + return !msr_le; +#endif +} + /*****************************************************************************/ /* Memory load and stores */ @@ -44,7 +53,7 @@ static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr, void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg) { for (; reg < 32; reg++) { - if (msr_le) { + if (needs_byteswap(env)) { env->gpr[reg] = bswap32(cpu_ldl_data(env, addr)); } else { env->gpr[reg] = cpu_ldl_data(env, addr); @@ -56,7 +65,7 @@ void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg) void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg) { for (; reg < 32; reg++) { - if (msr_le) { + if (needs_byteswap(env)) { cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg])); } else { cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]); @@ -199,6 +208,11 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, #define LO_IDX 0 #endif +/* We use msr_le to determine index ordering in a vector. However, + byteswapping is not simply controlled by msr_le. We also need to take + into account endianness of the target. This is done for the little-endian + PPC64 user-mode target. */ + #define LVE(name, access, swap, element) \ void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ target_ulong addr) \ @@ -207,9 +221,11 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, int adjust = HI_IDX*(n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - \ if (msr_le) { \ index = n_elems - index - 1; \ + } \ + \ + if (needs_byteswap(env)) { \ r->element[LO_IDX ? index : (adjust - index)] = \ swap(access(env, addr)); \ } else { \ @@ -232,9 +248,11 @@ LVE(lvewx, cpu_ldl_data, bswap32, u32) int adjust = HI_IDX * (n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - \ if (msr_le) { \ index = n_elems - index - 1; \ + } \ + \ + if (needs_byteswap(env)) { \ access(env, addr, swap(r->element[LO_IDX ? index : \ (adjust - index)])); \ } else { \ |