qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-ppc] [PATCH 2/3] PPC: Allow little-endian user mode.


From: Doug Kwan
Subject: [Qemu-ppc] [PATCH 2/3] PPC: Allow little-endian user mode.
Date: Thu, 8 May 2014 01:26:42 -0700

This all running PPC64 little-endian in user mode if target is configured
that way.  In PPC64 LE user mode we set MSR.LE during initialization.
Byteswapping logic is reversed also when QEMU is running in that mode.

Signed-off-by: Doug Kwan <address@hidden>
---
 target-ppc/mem_helper.c     | 16 ++++++++++++++--
 target-ppc/translate.c      | 45 ++++++++++++++++++++++++++++++---------------
 target-ppc/translate_init.c |  9 +++++++++
 3 files changed, 53 insertions(+), 17 deletions(-)

diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index f35ed03..7bacdab 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -202,6 +202,14 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong 
addr, uint32_t reg,
 #define LO_IDX 0
 #endif
 
+static inline bool element_needs_byteswap(CPUPPCState *env) {
+#if defined(TARGET_WORDS_BIGENDIAN)
+  return msr_le;
+#else
+  return !msr_le;
+#endif
+}
+
 #define LVE(name, access, swap, element)                        \
     void helper_##name(CPUPPCState *env, ppc_avr_t *r,          \
                        target_ulong addr)                       \
@@ -210,9 +218,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 (element_needs_byteswap(env)) {                      \
             r->element[LO_IDX ? index : (adjust - index)] =     \
                 swap(access(env, addr));                        \
         } else {                                                \
@@ -235,9 +245,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 (element_needs_byteswap(env)) {                              \
             access(env, addr, swap(r->element[LO_IDX ? index :          \
                                               (adjust - index)]));      \
         } else {                                                        \
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index e3fcb03..4b11c5a 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -210,6 +210,15 @@ typedef struct DisasContext {
     uint64_t insns_flags2;
 } DisasContext;
 
+/* Return true iff byteswap is needed in a scalar memop */
+static inline bool need_byteswap(const DisasContext *ctx) {
+#if defined(TARGET_WORDS_BIGENDIAN)
+     return ctx->le_mode;
+#else
+     return !ctx->le_mode;
+#endif
+}
+
 /* True when active word size < size of target_long.  */
 #ifdef TARGET_PPC64
 # define NARROW_MODE(C)  (!(C)->sf_mode)
@@ -2653,14 +2662,14 @@ static inline void gen_qemu_ld8s(DisasContext *ctx, 
TCGv arg1, TCGv arg2)
 static inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
     tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
-    if (unlikely(ctx->le_mode)) {
+    if (unlikely(need_byteswap(ctx))) {
         tcg_gen_bswap16_tl(arg1, arg1);
     }
 }
 
 static inline void gen_qemu_ld16s(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
-    if (unlikely(ctx->le_mode)) {
+    if (unlikely(need_byteswap(ctx))) {
         tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
         tcg_gen_bswap16_tl(arg1, arg1);
         tcg_gen_ext16s_tl(arg1, arg1);
@@ -2672,7 +2681,7 @@ static inline void gen_qemu_ld16s(DisasContext *ctx, TCGv 
arg1, TCGv arg2)
 static inline void gen_qemu_ld32u(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
     tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
-    if (unlikely(ctx->le_mode)) {
+    if (unlikely(need_byteswap(ctx))) {
         tcg_gen_bswap32_tl(arg1, arg1);
     }
 }
@@ -2687,7 +2696,7 @@ static void gen_qemu_ld32u_i64(DisasContext *ctx, 
TCGv_i64 val, TCGv addr)
 
 static inline void gen_qemu_ld32s(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
-    if (unlikely(ctx->le_mode)) {
+    if (unlikely(need_byteswap(ctx))) {
         tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
         tcg_gen_bswap32_tl(arg1, arg1);
         tcg_gen_ext32s_tl(arg1, arg1);
@@ -2706,7 +2715,7 @@ static void gen_qemu_ld32s_i64(DisasContext *ctx, 
TCGv_i64 val, TCGv addr)
 static inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
 {
     tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx);
-    if (unlikely(ctx->le_mode)) {
+    if (unlikely(need_byteswap(ctx))) {
         tcg_gen_bswap64_i64(arg1, arg1);
     }
 }
@@ -2718,7 +2727,7 @@ static inline void gen_qemu_st8(DisasContext *ctx, TCGv 
arg1, TCGv arg2)
 
 static inline void gen_qemu_st16(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
-    if (unlikely(ctx->le_mode)) {
+    if (unlikely(need_byteswap(ctx))) {
         TCGv t0 = tcg_temp_new();
         tcg_gen_ext16u_tl(t0, arg1);
         tcg_gen_bswap16_tl(t0, t0);
@@ -2731,7 +2740,7 @@ static inline void gen_qemu_st16(DisasContext *ctx, TCGv 
arg1, TCGv arg2)
 
 static inline void gen_qemu_st32(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
-    if (unlikely(ctx->le_mode)) {
+    if (unlikely(need_byteswap(ctx))) {
         TCGv t0 = tcg_temp_new();
         tcg_gen_ext32u_tl(t0, arg1);
         tcg_gen_bswap32_tl(t0, t0);
@@ -2752,7 +2761,7 @@ static void gen_qemu_st32_i64(DisasContext *ctx, TCGv_i64 
val, TCGv addr)
 
 static inline void gen_qemu_st64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
 {
-    if (unlikely(ctx->le_mode)) {
+    if (unlikely(need_byteswap(ctx))) {
         TCGv_i64 t0 = tcg_temp_new_i64();
         tcg_gen_bswap64_i64(t0, arg1);
         tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx);
@@ -3049,11 +3058,17 @@ static void gen_std(DisasContext *ctx)
 }
 #endif
 /***                Integer load and store with byte reverse               ***/
+
+/* Logic for byteswap test is reversed since these instructions require
+ * a byteswap already.  If we need another byteswap due to endianness of
+ * translation context, the two byteswaps cancel out each other.
+ */
+
 /* lhbrx */
 static inline void gen_qemu_ld16ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
     tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
-    if (likely(!ctx->le_mode)) {
+    if (likely(!need_byteswap(ctx))) {
         tcg_gen_bswap16_tl(arg1, arg1);
     }
 }
@@ -3063,7 +3078,7 @@ GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER);
 static inline void gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
     tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
-    if (likely(!ctx->le_mode)) {
+    if (likely(!need_byteswap(ctx))) {
         tcg_gen_bswap32_tl(arg1, arg1);
     }
 }
@@ -3074,7 +3089,7 @@ GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER);
 static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
     tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx);
-    if (likely(!ctx->le_mode)) {
+    if (likely(!need_byteswap(ctx))) {
         tcg_gen_bswap64_tl(arg1, arg1);
     }
 }
@@ -3084,7 +3099,7 @@ GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX);
 /* sthbrx */
 static inline void gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
-    if (likely(!ctx->le_mode)) {
+    if (likely(!need_byteswap(ctx))) {
         TCGv t0 = tcg_temp_new();
         tcg_gen_ext16u_tl(t0, arg1);
         tcg_gen_bswap16_tl(t0, t0);
@@ -3099,7 +3114,7 @@ GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER);
 /* stwbrx */
 static inline void gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
-    if (likely(!ctx->le_mode)) {
+    if (likely(!need_byteswap(ctx))) {
         TCGv t0 = tcg_temp_new();
         tcg_gen_ext32u_tl(t0, arg1);
         tcg_gen_bswap32_tl(t0, t0);
@@ -3115,7 +3130,7 @@ GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER);
 /* stdbrx */
 static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
-    if (likely(!ctx->le_mode)) {
+    if (likely(!need_byteswap(ctx))) {
         TCGv t0 = tcg_temp_new();
         tcg_gen_bswap64_tl(t0, arg1);
         tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx);
@@ -11401,7 +11416,7 @@ static inline void 
gen_intermediate_code_internal(PowerPCCPU *cpu,
                   ctx.nip, ctx.mem_idx, (int)msr_ir);
         if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
             gen_io_start();
-        if (unlikely(ctx.le_mode)) {
+        if (unlikely(need_byteswap(&ctx))) {
             ctx.opcode = bswap32(cpu_ldl_code(env, ctx.nip));
         } else {
             ctx.opcode = cpu_ldl_code(env, ctx.nip);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 4d94015..84381ae 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8418,6 +8418,9 @@ static void ppc_cpu_reset(CPUState *s)
     msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
     msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
     msr |= (target_ulong)1 << MSR_PR;
+#if !defined(TARGET_WORDS_BIGENDIAN)
+    msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */
+#endif
 #endif
 
 #if defined(TARGET_PPC64)
@@ -8461,6 +8464,12 @@ static void ppc_cpu_reset(CPUState *s)
 
     /* Flush all TLBs */
     tlb_flush(s, 1);
+
+#if defined(CONFIG_USER_ONLY) && !defined(TARGET_WORDS_BIGENDIAN)
+    if (!msr_le) {
+        cpu_abort(CPU(cpu), "Cannot set QEMU to little-endian user mode\n");
+    }
+#endif
 }
 
 static void ppc_cpu_initfn(Object *obj)
-- 
1.9.1.423.g4596e3a




reply via email to

[Prev in Thread] Current Thread [Next in Thread]