summaryrefslogtreecommitdiff
path: root/target-ppc/mem_helper.c
diff options
context:
space:
mode:
authorDoug Kwan <dougkwan@google.com>2014-05-29 09:12:20 -0500
committerAlexander Graf <agraf@suse.de>2014-06-16 13:24:40 +0200
commite22c357b3ec01c1141969ae81397d60d52e8c87b (patch)
treeea4aa04bb90ebfb07fdb0e1d5ad1344871eb3651 /target-ppc/mem_helper.c
parentd90b94cd78af672cdfd52dc3789ab249534c2f40 (diff)
downloadqemu-e22c357b3ec01c1141969ae81397d60d52e8c87b.tar.gz
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.c26
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 { \