diff mbox series

[RFC,06/11] target/ppc: introduce gen_addr_swizzle_le() function

Message ID 20241212151412.570454-7-mark.cave-ayland@ilande.co.uk (mailing list archive)
State New
Headers show
Series target/ppc: implement legacy address-swizzling MSR_LE support | expand

Commit Message

Mark Cave-Ayland Dec. 12, 2024, 3:14 p.m. UTC
This function is used to swizzle the address lines to implement little endian
accesses as used by older CPUs. Add the address line swizzle to the gen_ld_tl()
and gen_st_tl() functions.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 target/ppc/translate.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

Comments

Richard Henderson Dec. 12, 2024, 3:58 p.m. UTC | #1
On 12/12/24 09:14, Mark Cave-Ayland wrote:
> This function is used to swizzle the address lines to implement little endian
> accesses as used by older CPUs. Add the address line swizzle to the gen_ld_tl()
> and gen_st_tl() functions.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>   target/ppc/translate.c | 26 ++++++++++++++++++++++++++
>   1 file changed, 26 insertions(+)

Right.  So, this *can't* be split from patch 5.

> +/*
> + * Swizzle the address lines for little endian accesses as used by older
> + * CPUs. The bottom 3 address lines are exlusive-ORed by a constant to

typo for exclusive, though "xor'ed" is probably just as readable.

> + * generate the correct address for a little endian access. For more
> + * information see https://wiki.preterhuman.net/images/f/fc/Endian.pdf
> + */
> +static inline void gen_addr_swizzle_le(TCGv ret, TCGv addr, MemOp op)

Drop the inline.

> +{
> +    MemOp size = op & MO_SIZE;
> +    TCGv aoff = tcg_temp_new();
> +    static int c_swizzle[MO_SIZE] = { 0x7, 0x6, 0x4, 0x0 };
> +
> +    tcg_gen_andi_tl(aoff, addr, (1 << size) - 1);
> +    tcg_gen_andi_tl(ret, addr, ~((1 << size) - 1));
> +    tcg_gen_xori_tl(ret, ret, c_swizzle[size]);
> +    tcg_gen_sub_tl(ret, ret, aoff);
> +}

I believe this is just

     tcg_gen_xori_tl(ret, addr, 8 - memop_size(op));

> @@ -2586,6 +2604,10 @@ static void gen_ld_tl(DisasContext *ctx, TCGv val, TCGv addr, TCGArg idx,
>   {
>       if (!need_addrswizzle_le(ctx)) {
>           tcg_gen_qemu_ld_tl(val, addr, idx, memop);
> +    } else {
> +        TCGv taddr = tcg_temp_new();
> +        gen_addr_swizzle_le(taddr, addr, memop);
> +        tcg_gen_qemu_ld_tl(val, taddr, idx, memop);
>       }
>   }

     if (need) {
         /* BLRM is only found on old ppc32; the only MO_64 should be for the FPU. */
         assert(size < MO_64);
         addr = gen_addr_swizzle_le(...);
     }
     tcg_gen_qemu_ld_tl(...);

You'll need to handle tcg_qemu_ld_i64 as well, and for that MO_64 needs 
tcg_gen_rotli_i64(val, val, 32) after the load / before the store.


r~
diff mbox series

Patch

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 1211435039..ddc0f85fb7 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -2561,6 +2561,24 @@  static TCGv do_ea_calc(DisasContext *ctx, int ra, TCGv displ)
     return ea;
 }
 
+/*
+ * Swizzle the address lines for little endian accesses as used by older
+ * CPUs. The bottom 3 address lines are exlusive-ORed by a constant to
+ * generate the correct address for a little endian access. For more
+ * information see https://wiki.preterhuman.net/images/f/fc/Endian.pdf
+ */
+static inline void gen_addr_swizzle_le(TCGv ret, TCGv addr, MemOp op)
+{
+    MemOp size = op & MO_SIZE;
+    TCGv aoff = tcg_temp_new();
+    static int c_swizzle[MO_SIZE] = { 0x7, 0x6, 0x4, 0x0 };
+
+    tcg_gen_andi_tl(aoff, addr, (1 << size) - 1);
+    tcg_gen_andi_tl(ret, addr, ~((1 << size) - 1));
+    tcg_gen_xori_tl(ret, ret, c_swizzle[size]);
+    tcg_gen_sub_tl(ret, ret, aoff);
+}
+
 #if defined(TARGET_PPC64)
 /* EA <- (ra == 0) ? 0 : GPR[ra] */
 static TCGv do_ea_calc_ra(DisasContext *ctx, int ra)
@@ -2586,6 +2604,10 @@  static void gen_ld_tl(DisasContext *ctx, TCGv val, TCGv addr, TCGArg idx,
 {
     if (!need_addrswizzle_le(ctx)) {
         tcg_gen_qemu_ld_tl(val, addr, idx, memop);
+    } else {
+        TCGv taddr = tcg_temp_new();
+        gen_addr_swizzle_le(taddr, addr, memop);
+        tcg_gen_qemu_ld_tl(val, taddr, idx, memop);
     }
 }
 
@@ -2629,6 +2651,10 @@  static void gen_st_tl(DisasContext *ctx, TCGv val, TCGv addr, TCGArg idx,
 {
     if (!need_addrswizzle_le(ctx)) {
         tcg_gen_qemu_st_tl(val, addr, idx, memop);
+    } else {
+        TCGv taddr = tcg_temp_new();
+        gen_addr_swizzle_le(taddr, addr, memop);
+        tcg_gen_qemu_st_tl(val, taddr, idx, memop);
     }
 }